From bae8e34a3814acc6b64a7f23b5836f9cd1cde1e9 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 10 Jan 2025 15:21:00 -0800 Subject: [PATCH 0001/6055] tests: i2c_emul: Remove unused variable Building with clang warns: tests/drivers/i2c/i2c_emul/src/test_forwarding_pio.cpp:19:32: error: unused variable 'targets' [-Werror,-Wunused-const-variable] constexpr const struct device *targets[FORWARD_COUNT] = { ^ Signed-off-by: Tom Hughes --- tests/drivers/i2c/i2c_emul/src/test_forwarding_pio.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/drivers/i2c/i2c_emul/src/test_forwarding_pio.cpp b/tests/drivers/i2c/i2c_emul/src/test_forwarding_pio.cpp index 1d570af0a7b5d..9c3039efee1ec 100644 --- a/tests/drivers/i2c/i2c_emul/src/test_forwarding_pio.cpp +++ b/tests/drivers/i2c/i2c_emul/src/test_forwarding_pio.cpp @@ -14,8 +14,6 @@ namespace /* Get the devicetree constants */ constexpr const struct device *controller = DEVICE_DT_GET(CONTROLLER_LABEL); -constexpr const struct device *targets[FORWARD_COUNT] = { - DT_FOREACH_PROP_ELEM_SEP(CONTROLLER_LABEL, forwards, DEVICE_DT_GET_BY_IDX, (,))}; ZTEST(i2c_emul_forwarding, test_write_is_forwarded) { From 782152f404b9dfd96f9922f62c466b8e4e06c953 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Mon, 13 Jan 2025 11:53:59 -0800 Subject: [PATCH 0002/6055] tests: i2c_emul: Remove unused variable Building with clang warns: tests/drivers/i2c/i2c_emul/src/test_forwarding_buf.cpp:20:32: error: unused variable 'targets' [-Werror,-Wunused-const-variable] constexpr const struct device *targets[FORWARD_COUNT] = { ^ Signed-off-by: Tom Hughes --- tests/drivers/i2c/i2c_emul/src/test_forwarding_buf.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/drivers/i2c/i2c_emul/src/test_forwarding_buf.cpp b/tests/drivers/i2c/i2c_emul/src/test_forwarding_buf.cpp index 1bcf7942d4502..7bf687a3a479e 100644 --- a/tests/drivers/i2c/i2c_emul/src/test_forwarding_buf.cpp +++ b/tests/drivers/i2c/i2c_emul/src/test_forwarding_buf.cpp @@ -15,8 +15,6 @@ namespace /* Get the devicetree constants */ constexpr const struct device *controller = DEVICE_DT_GET(CONTROLLER_LABEL); -constexpr const struct device *targets[FORWARD_COUNT] = { - DT_FOREACH_PROP_ELEM_SEP(CONTROLLER_LABEL, forwards, DEVICE_DT_GET_BY_IDX, (,))}; ZTEST(i2c_emul_forwarding, test_write_is_forwarded) { From 538b525ef15a5689372cbdffbac86e35df8460e1 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 10 Jan 2025 10:01:52 -0800 Subject: [PATCH 0003/6055] drivers: dma: Remove unused function Building with clang warns: drivers/dma/dma_emul.c:73:20: error: unused function 'dma_emul_xfer_is_error_status' [-Werror,-Wunused-function] static inline bool dma_emul_xfer_is_error_status(int status) ^ Signed-off-by: Tom Hughes --- drivers/dma/dma_emul.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/dma/dma_emul.c b/drivers/dma/dma_emul.c index bdb5245ae4648..6320d1c1620b7 100644 --- a/drivers/dma/dma_emul.c +++ b/drivers/dma/dma_emul.c @@ -70,11 +70,6 @@ static void dma_emul_work_handler(struct k_work *work); LOG_MODULE_REGISTER(dma_emul, CONFIG_DMA_LOG_LEVEL); -static inline bool dma_emul_xfer_is_error_status(int status) -{ - return status < 0; -} - static inline const char *const dma_emul_channel_state_to_string(enum dma_emul_channel_state state) { switch (state) { From 337ca4e4780b9a8aacf081b935c7c15b68f52c13 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 10 Jan 2025 09:45:41 -0800 Subject: [PATCH 0004/6055] drivers: sensor: Remove unused function Building with clang warns: drivers/sensor/st/ism330dhcx/ism330dhcx.c:107:19: error: unused function 'ism330dhcx_reboot' [-Werror,-Wunused-function] static inline int ism330dhcx_reboot(const struct device *dev) Signed-off-by: Tom Hughes --- drivers/sensor/st/ism330dhcx/ism330dhcx.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/sensor/st/ism330dhcx/ism330dhcx.c b/drivers/sensor/st/ism330dhcx/ism330dhcx.c index da1cef97a0475..44b8506664e6d 100644 --- a/drivers/sensor/st/ism330dhcx/ism330dhcx.c +++ b/drivers/sensor/st/ism330dhcx/ism330dhcx.c @@ -104,20 +104,6 @@ static int ism330dhcx_gyro_range_to_fs_val(int32_t range) return -EINVAL; } -static inline int ism330dhcx_reboot(const struct device *dev) -{ - struct ism330dhcx_data *data = dev->data; - - if (ism330dhcx_boot_set(data->ctx, 1) < 0) { - return -EIO; - } - - /* Wait sensor turn-on time as per datasheet */ - k_busy_wait(35 * USEC_PER_MSEC); - - return 0; -} - static int ism330dhcx_accel_set_fs_raw(const struct device *dev, uint8_t fs) { struct ism330dhcx_data *data = dev->data; From a4542edf6d0307649cf2f7759850c604a07627ff Mon Sep 17 00:00:00 2001 From: Sudan Landge Date: Tue, 4 Feb 2025 22:32:08 +0000 Subject: [PATCH 0005/6055] maintainers: Adding @ithinuel as collaborator @ithinuel will be continuing to help with reviews on Arm and Arm64 arch/platform so adding him as collaborator. Also adding me @wearyzen as collaborator for Arm64 to help with reviews. Signed-off-by: Sudan Landge --- MAINTAINERS.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 251006cbafb45..2177e3a6352a0 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -182,6 +182,7 @@ ARM arch: - MaureenHelm - stephanosio - bbolen + - ithinuel files: - arch/arm/ - arch/arm/core/offsets/ @@ -202,6 +203,8 @@ ARM64 arch: - npitre - povergoing - sgrrzhf + - wearyzen + - ithinuel files: - arch/arm64/ - include/zephyr/arch/arm64/ @@ -218,6 +221,8 @@ ARM Platforms: status: maintained maintainers: - wearyzen + collaborators: + - ithinuel files: - boards/arm/mps*/ - boards/arm/v2m_*/ @@ -1642,6 +1647,9 @@ Release Notes: status: maintained maintainers: - carlocaione + collaborators: + - wearyzen + - ithinuel files: - include/zephyr/drivers/mbox.h - drivers/mbox/ @@ -4772,6 +4780,7 @@ West: - wearyzen collaborators: - tomi-font + - ithinuel files: [] labels: - "area: CMSIS_6" @@ -4868,6 +4877,8 @@ West: maintainers: - kristofer-jonsson-arm - wearyzen + collaborators: + - ithinuel files: - drivers/misc/ethos_u/ - modules/hal_ethos_u/ @@ -5200,6 +5211,7 @@ West: - wearyzen - valeriosetti - tomi-font + - ithinuel files: - modules/mbedtls/ - tests/crypto/mbedtls/ @@ -5390,6 +5402,7 @@ West: - wearyzen - valeriosetti - tomi-font + - ithinuel files: - modules/trusted-firmware-m/ - samples/tfm_integration/ @@ -5407,6 +5420,7 @@ West: collaborators: - Vge0rge - wearyzen + - ithinuel files: [] labels: - "area: TF-M" @@ -5419,6 +5433,7 @@ West: collaborators: - carlocaione - wearyzen + - ithinuel files: - modules/trusted-firmware-a/ labels: @@ -5431,6 +5446,7 @@ West: collaborators: - Vge0rge - wearyzen + - ithinuel files: [] labels: - "area: TF-M" From 79130a73bee6e256fe59d8e2a6ba8d662dab26e2 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 7 Feb 2025 08:02:33 +0900 Subject: [PATCH 0006/6055] drivers: gpio: renesas_ra: Add support for `GPIO_GET_CONFIG` option Enable retrieval of pin configuration information. Signed-off-by: TOKITA Hiroshi --- drivers/gpio/gpio_renesas_ra_ioport.c | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/gpio/gpio_renesas_ra_ioport.c b/drivers/gpio/gpio_renesas_ra_ioport.c index 9ea6ab6d9f59c..194ff8ff1f042 100644 --- a/drivers/gpio/gpio_renesas_ra_ioport.c +++ b/drivers/gpio/gpio_renesas_ra_ioport.c @@ -175,6 +175,36 @@ static int gpio_ra_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ return pinctrl_configure_pins(&pincfg, 1, PINCTRL_REG_NONE); } +static int gpio_ra_pin_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *flags) +{ + const struct gpio_ra_config *config = dev->config; + uint32_t pincfg; + + if (pin >= RA_PINCTRL_PIN_NUM) { + return -EINVAL; + } + + memset(flags, 0, sizeof(gpio_flags_t)); + + pincfg = R_PFS->PORT[config->port_num].PIN[pin].PmnPFS; + + if (pincfg & BIT(R_PFS_PORT_PIN_PmnPFS_PDR_Pos)) { + *flags |= GPIO_OUTPUT; + } else { + *flags |= GPIO_INPUT; + } + + if (pincfg & BIT(R_PFS_PORT_PIN_PmnPFS_NCODR_Pos)) { + *flags |= GPIO_LINE_OPEN_DRAIN; + } + + if (pincfg & BIT(R_PFS_PORT_PIN_PmnPFS_PCR_Pos)) { + *flags |= GPIO_PULL_UP; + } + + return 0; +} + static int gpio_ra_port_get_raw(const struct device *dev, uint32_t *value) { const struct gpio_ra_config *config = dev->config; @@ -244,6 +274,9 @@ static int gpio_ra_manage_callback(const struct device *dev, struct gpio_callbac static DEVICE_API(gpio, gpio_ra_drv_api_funcs) = { .pin_configure = gpio_ra_pin_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = gpio_ra_pin_get_config, +#endif .port_get_raw = gpio_ra_port_get_raw, .port_set_masked_raw = gpio_ra_port_set_masked_raw, .port_set_bits_raw = gpio_ra_port_set_bits_raw, From 1db7d3c35ae6881833ed42a002baab25724c69df Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 7 Feb 2025 08:01:16 +0900 Subject: [PATCH 0007/6055] drivers: gpio: renesas_ra: Do not clear pin config in int-configure In the current implementation, when `gpio_ra_pin_interrupt_configure` is executed, the existing settings made by `gpio_ra_pin_configure` are erased. A read-modify-write method will be used to preserve the settings. Signed-off-by: TOKITA Hiroshi --- drivers/gpio/gpio_renesas_ra_ioport.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio_renesas_ra_ioport.c b/drivers/gpio/gpio_renesas_ra_ioport.c index 194ff8ff1f042..fec5f8c43493a 100644 --- a/drivers/gpio/gpio_renesas_ra_ioport.c +++ b/drivers/gpio/gpio_renesas_ra_ioport.c @@ -175,7 +175,8 @@ static int gpio_ra_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ return pinctrl_configure_pins(&pincfg, 1, PINCTRL_REG_NONE); } -static int gpio_ra_pin_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *flags) +__maybe_unused static int gpio_ra_pin_get_config(const struct device *dev, gpio_pin_t pin, + gpio_flags_t *flags) { const struct gpio_ra_config *config = dev->config; uint32_t pincfg; @@ -260,7 +261,15 @@ static int gpio_ra_port_toggle_bits(const struct device *dev, gpio_port_pins_t p static int gpio_ra_pin_interrupt_configure(const struct device *port, gpio_pin_t pin, enum gpio_int_mode mode, enum gpio_int_trig trig) { - return gpio_ra_pin_configure(port, pin, (mode | trig)); + gpio_flags_t flags; + int err; + + err = gpio_ra_pin_get_config(port, pin, &flags); + if (err) { + return err; + } + + return gpio_ra_pin_configure(port, pin, (flags | mode | trig)); } static int gpio_ra_manage_callback(const struct device *dev, struct gpio_callback *callback, From a80f7e40e3f5d21f4fa39e1cb26e71beab73d334 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 10 Feb 2025 21:03:25 -0800 Subject: [PATCH 0008/6055] modules: cmsis-nn: update to v7.0.0 Update manifest to cmsis-nn v7.0.0 Signed-off-by: Ryan McClelland --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 1f7aec693bf22..40cd980370ad1 100644 --- a/west.yml +++ b/west.yml @@ -125,7 +125,7 @@ manifest: revision: d80a49b2bb186317dc1db4ac88da49c0ab77e6e7 path: modules/lib/cmsis-dsp - name: cmsis-nn - revision: ea987c1ca661be723de83bd159aed815d6cbd430 + revision: e9328d612ea3ea7d0d210d3ac16ea8667c01abdd path: modules/lib/cmsis-nn - name: cmsis_6 repo-path: CMSIS_6 From 8f4a4aeb238171c753916a8e9e1222ac8938685d Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 10 Feb 2025 21:20:01 -0800 Subject: [PATCH 0009/6055] tests: cmsis-nn: update tests for v7.0.0 arm_convolve_s8 got an extra arg. Set to NULL to no behavior change. Signed-off-by: Ryan McClelland --- tests/lib/cmsis_nn/src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/lib/cmsis_nn/src/main.c b/tests/lib/cmsis_nn/src/main.c index c7dbe3bc58ed4..efe113b7ac733 100644 --- a/tests/lib/cmsis_nn/src/main.c +++ b/tests/lib/cmsis_nn/src/main.c @@ -203,6 +203,7 @@ ZTEST(cmsis_nn, test_convolve) kernel_data, &bias_dims, bias_data, + NULL, &output_dims, output); From eeaf054a488b854fe7681b1b981199138809b1f5 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 10 Feb 2025 21:29:13 -0800 Subject: [PATCH 0010/6055] modules: cmsis-nn: add transpose Add KConfig for the new cmsis-nn transpose kernels. Signed-off-by: Ryan McClelland --- modules/cmsis-nn/CMakeLists.txt | 5 +++++ modules/cmsis-nn/Kconfig | 5 +++++ modules/tflite-micro/Kconfig | 1 + 3 files changed, 11 insertions(+) diff --git a/modules/cmsis-nn/CMakeLists.txt b/modules/cmsis-nn/CMakeLists.txt index ec55bafbcfa7a..2eacfd0d31a65 100644 --- a/modules/cmsis-nn/CMakeLists.txt +++ b/modules/cmsis-nn/CMakeLists.txt @@ -85,4 +85,9 @@ if(CONFIG_CMSIS_NN) zephyr_library_sources(${SRC}) endif() + if(CONFIG_CMSIS_NN_TRANSPOSE) + file(GLOB SRC "${CMSIS_NN_DIR}/Source/TransposeFunctions/*_s8.c") + zephyr_library_sources(${SRC}) + endif() + endif() diff --git a/modules/cmsis-nn/Kconfig b/modules/cmsis-nn/Kconfig index 53c3aa4987d7d..419d3f3a75d5a 100644 --- a/modules/cmsis-nn/Kconfig +++ b/modules/cmsis-nn/Kconfig @@ -78,4 +78,9 @@ config CMSIS_NN_LSTM help This option enables the NN libraries for Long Short-Term Memory. +config CMSIS_NN_TRANSPOSE + bool "Transpose" + help + This option enables the NN libraries for the transpose layers. + endif #CMSIS_NN diff --git a/modules/tflite-micro/Kconfig b/modules/tflite-micro/Kconfig index 72789bd51de61..887c965759a81 100644 --- a/modules/tflite-micro/Kconfig +++ b/modules/tflite-micro/Kconfig @@ -28,6 +28,7 @@ config TENSORFLOW_LITE_MICRO_CMSIS_NN_KERNELS select CMSIS_NN_SOFTMAX select CMSIS_NN_SVD select CMSIS_NN_LSTM + select CMSIS_NN_TRANSPOSE help This option adds support for CMSIS-NN optimized kernels when using TensorFlow Lite Micro. From a8a9f0c1a91fde589f6d0e4ce3b91619021cecd7 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Mon, 10 Feb 2025 21:32:05 -0800 Subject: [PATCH 0011/6055] modules: cmsis-nn: add pad Add KConfig for the new cmsis-nn pad kernels. Signed-off-by: Ryan McClelland --- modules/cmsis-nn/CMakeLists.txt | 5 +++++ modules/cmsis-nn/Kconfig | 5 +++++ modules/tflite-micro/Kconfig | 1 + 3 files changed, 11 insertions(+) diff --git a/modules/cmsis-nn/CMakeLists.txt b/modules/cmsis-nn/CMakeLists.txt index 2eacfd0d31a65..0fdf3db9675e6 100644 --- a/modules/cmsis-nn/CMakeLists.txt +++ b/modules/cmsis-nn/CMakeLists.txt @@ -90,4 +90,9 @@ if(CONFIG_CMSIS_NN) zephyr_library_sources(${SRC}) endif() + if(CONFIG_CMSIS_NN_PAD) + file(GLOB SRC "${CMSIS_NN_DIR}/Source/PadFunctions/*_s8.c") + zephyr_library_sources(${SRC}) + endif() + endif() diff --git a/modules/cmsis-nn/Kconfig b/modules/cmsis-nn/Kconfig index 419d3f3a75d5a..dd5395f92efaa 100644 --- a/modules/cmsis-nn/Kconfig +++ b/modules/cmsis-nn/Kconfig @@ -78,6 +78,11 @@ config CMSIS_NN_LSTM help This option enables the NN libraries for Long Short-Term Memory. +config CMSIS_NN_PAD + bool "Pad" + help + This option enables the NN libraries for the pad layers. + config CMSIS_NN_TRANSPOSE bool "Transpose" help diff --git a/modules/tflite-micro/Kconfig b/modules/tflite-micro/Kconfig index 887c965759a81..99a49d6a633bf 100644 --- a/modules/tflite-micro/Kconfig +++ b/modules/tflite-micro/Kconfig @@ -29,6 +29,7 @@ config TENSORFLOW_LITE_MICRO_CMSIS_NN_KERNELS select CMSIS_NN_SVD select CMSIS_NN_LSTM select CMSIS_NN_TRANSPOSE + select CMSIS_NN_PAD help This option adds support for CMSIS-NN optimized kernels when using TensorFlow Lite Micro. From 4dda4fc3f939a345f8ce6934f787caa587a6e6d5 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Tue, 11 Feb 2025 09:43:54 -0800 Subject: [PATCH 0012/6055] modules: tflite-micro: update to latest hash Update tflite-micro to latest hash. Signed-off-by: Ryan McClelland --- submanifests/optional.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index d4d67d0ec2bd1..73fd9a1c7e4aa 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -47,7 +47,7 @@ manifest: groups: - optional - name: tflite-micro - revision: 48613f7ba1ffbda46ad771a77a35408f48f922e9 + revision: 8d404de73acf7687831e16d88e86e4f73cfddf8e path: optional/modules/lib/tflite-micro repo-path: tflite-micro remote: upstream From c57e8880e5286bf7cb9b05f58ceec4c647245020 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Tue, 11 Feb 2025 19:59:18 -0800 Subject: [PATCH 0013/6055] modules: tflite-micro: update cmakelists Update cmakelists for the new tflite-micro hash Signed-off-by: Ryan McClelland --- modules/tflite-micro/CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/tflite-micro/CMakeLists.txt b/modules/tflite-micro/CMakeLists.txt index c0893a7d807e0..95301b34c7939 100644 --- a/modules/tflite-micro/CMakeLists.txt +++ b/modules/tflite-micro/CMakeLists.txt @@ -41,9 +41,12 @@ if(CONFIG_TENSORFLOW_LITE_MICRO) ${TENSORFLOW_LITE_MICRO_DIR}/signal/src/kiss_fft_wrappers/kiss_fft_float.cc ${TENSORFLOW_LITE_MICRO_DIR}/signal/src/kiss_fft_wrappers/kiss_fft_int16.cc ${TENSORFLOW_LITE_MICRO_DIR}/signal/src/kiss_fft_wrappers/kiss_fft_int32.cc + ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/compiler/mlir/lite/core/api/error_reporter.cc + ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/compiler/mlir/lite/schema/schema_utils.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/array.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/core/c/common.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/debug_log.cc + ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/hexdump.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/fake_micro_context.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/memory_helpers.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/micro_allocation_info.cc @@ -81,9 +84,7 @@ if(CONFIG_TENSORFLOW_LITE_MICRO) ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/kernels/internal/reference/portable_tensor_utils.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/kernels/kernel_util.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/core/api/flatbuffer_conversions.cc - ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/core/api/error_reporter.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/core/api/tensor_utils.cc - ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/schema/schema_utils.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/activations.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/activations_common.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/${CMSIS_NN_OPTIMIZED_KERNEL_DIR}/add.cc @@ -91,7 +92,7 @@ if(CONFIG_TENSORFLOW_LITE_MICRO) ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/add_n.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/arg_min_max.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/assign_variable.cc - ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/batch_matmul.cc + ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/${CMSIS_NN_OPTIMIZED_KERNEL_DIR}/batch_matmul.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/batch_to_space_nd.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/broadcast_args.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/broadcast_to.cc @@ -105,6 +106,8 @@ if(CONFIG_TENSORFLOW_LITE_MICRO) ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/${CMSIS_NN_OPTIMIZED_KERNEL_DIR}/conv.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/conv_common.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/cumsum.cc + ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/decompress.cc + ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/decompress_common.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/depth_to_space.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/${CMSIS_NN_OPTIMIZED_KERNEL_DIR}/depthwise_conv.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/depthwise_conv_common.cc @@ -142,7 +145,7 @@ if(CONFIG_TENSORFLOW_LITE_MICRO) ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/lstm_eval.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/lstm_eval_common.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/log_softmax.cc - ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/maximum_minimum.cc + ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/${CMSIS_NN_OPTIMIZED_KERNEL_DIR}/maximum_minimum.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/micro_tensor_utils.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/mirror_pad.cc ${TENSORFLOW_LITE_MICRO_DIR}/tensorflow/lite/micro/kernels/${CMSIS_NN_OPTIMIZED_KERNEL_DIR}/mul.cc From b9a4e30d3b5738845b1085ca8e89537430d48a69 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 16 Dec 2024 15:28:03 +0700 Subject: [PATCH 0014/6055] drivers: clock control: Initial support for RZ/G3S Add Clock Control driver support for Renesas RZ/G3S Signed-off-by: Tien Nguyen Signed-off-by: Nhut Nguyen --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.renesas_rz_cpg | 12 ++ .../clock_control_renesas_rz_cpg.c | 134 ++++++++++++++++++ dts/bindings/clock/renesas,rz-cpg.yml | 15 ++ .../dt-bindings/clock/renesas_rzg_clock.h | 93 ++++++++++++ modules/Kconfig.renesas_fsp | 5 + 7 files changed, 262 insertions(+) create mode 100644 drivers/clock_control/Kconfig.renesas_rz_cpg create mode 100644 drivers/clock_control/clock_control_renesas_rz_cpg.c create mode 100644 dts/bindings/clock/renesas,rz-cpg.yml create mode 100644 include/zephyr/dt-bindings/clock/renesas_rzg_clock.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 3a7892ef9ac05..1b8332cdc6f35 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -35,6 +35,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SMARTBOND clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NUMAKER_SCC clock_control_numaker_scc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NXP_S32 clock_control_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RA_CGC clock_control_renesas_ra_cgc.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RZ_CPG clock_control_renesas_rz_cpg.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AMBIQ clock_control_ambiq.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_PWM clock_control_pwm.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RPI_PICO clock_control_rpi_pico.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index a746628d86db9..c4a0f83d6e154 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -88,6 +88,8 @@ source "drivers/clock_control/Kconfig.agilex5" source "drivers/clock_control/Kconfig.renesas_ra_cgc" +source "drivers/clock_control/Kconfig.renesas_rz_cpg" + source "drivers/clock_control/Kconfig.max32" source "drivers/clock_control/Kconfig.ambiq" diff --git a/drivers/clock_control/Kconfig.renesas_rz_cpg b/drivers/clock_control/Kconfig.renesas_rz_cpg new file mode 100644 index 0000000000000..6d8e04cefce57 --- /dev/null +++ b/drivers/clock_control/Kconfig.renesas_rz_cpg @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_RENESAS_RZ_CPG + bool "Renesas RZ/G Clock Control Driver" + default y + depends on DT_HAS_RENESAS_RZ_CPG_ENABLED + select USE_RZ_FSP_CPG + help + Enable support for Renesas RZ CPG Clock Pulse Generator (CPG) driver. + The CPG driver supports only module's clocks. + The PLLs and core clocks are not configured by the CPG driver. diff --git a/drivers/clock_control/clock_control_renesas_rz_cpg.c b/drivers/clock_control/clock_control_renesas_rz_cpg.c new file mode 100644 index 0000000000000..f220cc2e4d0aa --- /dev/null +++ b/drivers/clock_control/clock_control_renesas_rz_cpg.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define DT_DRV_COMPAT renesas_rz_cpg + +static int clock_control_renesas_rz_on(const struct device *dev, clock_control_subsys_t sys) +{ + if (!dev || !sys) { + return -EINVAL; + } + + uint32_t *clock_id = (uint32_t *)sys; + + uint32_t ip = (*clock_id & RZ_IP_MASK) >> RZ_IP_SHIFT; + uint32_t ch = (*clock_id & RZ_IP_CH_MASK) >> RZ_IP_CH_SHIFT; + + switch (ip) { + case RZ_IP_GTM: + R_BSP_MODULE_START(FSP_IP_GTM, ch); + break; + case RZ_IP_GPT: + R_BSP_MODULE_START(FSP_IP_GPT, ch); + break; + case RZ_IP_SCIF: + R_BSP_MODULE_START(FSP_IP_SCIF, ch); + break; + case RZ_IP_RIIC: + R_BSP_MODULE_START(FSP_IP_RIIC, ch); + break; + case RZ_IP_RSPI: + R_BSP_MODULE_START(FSP_IP_RSPI, ch); + break; + case RZ_IP_MHU: + R_BSP_MODULE_START(FSP_IP_MHU, ch); + break; + case RZ_IP_DMAC: + R_BSP_MODULE_START(FSP_IP_DMAC, ch); + break; + case RZ_IP_CANFD: + R_BSP_MODULE_START(FSP_IP_CANFD, ch); + break; + case RZ_IP_ADC: + R_BSP_MODULE_START(FSP_IP_ADC, ch); + break; + default: + return -EINVAL; /* Invalid FSP IP Module */ + } + + return 0; +} + +static int clock_control_renesas_rz_off(const struct device *dev, clock_control_subsys_t sys) +{ + if (!dev || !sys) { + return -EINVAL; + } + + uint32_t *clock_id = (uint32_t *)sys; + + uint32_t ip = (*clock_id & RZ_IP_MASK) >> RZ_IP_SHIFT; + uint32_t ch = (*clock_id & RZ_IP_CH_MASK) >> RZ_IP_CH_SHIFT; + + switch (ip) { + case RZ_IP_GTM: + R_BSP_MODULE_STOP(FSP_IP_GTM, ch); + break; + case RZ_IP_GPT: + R_BSP_MODULE_STOP(FSP_IP_GPT, ch); + break; + case RZ_IP_SCIF: + R_BSP_MODULE_STOP(FSP_IP_SCIF, ch); + break; + case RZ_IP_RIIC: + R_BSP_MODULE_STOP(FSP_IP_RIIC, ch); + break; + case RZ_IP_RSPI: + R_BSP_MODULE_STOP(FSP_IP_RSPI, ch); + break; + case RZ_IP_MHU: + R_BSP_MODULE_STOP(FSP_IP_MHU, ch); + break; + case RZ_IP_DMAC: + R_BSP_MODULE_STOP(FSP_IP_DMAC, ch); + break; + case RZ_IP_CANFD: + R_BSP_MODULE_STOP(FSP_IP_CANFD, ch); + break; + case RZ_IP_ADC: + R_BSP_MODULE_STOP(FSP_IP_ADC, ch); + break; + default: + return -EINVAL; /* Invalid */ + } + return 0; +} + +static int clock_control_renesas_rz_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + if (!dev || !sys || !rate) { + return -EINVAL; + } + + uint32_t *clock_id = (uint32_t *)sys; + + fsp_priv_clock_t clk_src = (*clock_id & RZ_CLOCK_MASK) >> RZ_CLOCK_SHIFT; + uint32_t clk_div = (*clock_id & RZ_CLOCK_DIV_MASK) >> RZ_CLOCK_DIV_SHIFT; + + uint32_t clk_hz = R_FSP_SystemClockHzGet(clk_src); + *rate = clk_hz / clk_div; + return 0; +} + +static DEVICE_API(clock_control, rz_clock_control_driver_api) = { + .on = clock_control_renesas_rz_on, + .off = clock_control_renesas_rz_off, + .get_rate = clock_control_renesas_rz_get_rate, +}; + +static int clock_control_rz_init(const struct device *dev) +{ + ARG_UNUSED(dev); + return 0; +} + +DEVICE_DT_INST_DEFINE(0, clock_control_rz_init, NULL, NULL, NULL, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &rz_clock_control_driver_api); diff --git a/dts/bindings/clock/renesas,rz-cpg.yml b/dts/bindings/clock/renesas,rz-cpg.yml new file mode 100644 index 0000000000000..5124cd3cb12db --- /dev/null +++ b/dts/bindings/clock/renesas,rz-cpg.yml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Renesas Electronics Corporation24 +# SPDX-License-Identifier: Apache-2.0 + +description: RZ Clock Pulse Generator +compatible: "renesas,rz-cpg" + +include: [base.yaml, clock-controller.yaml] + +properties: + + "#clock-cells": + const: 1 + +clock-cells: + - clk-id diff --git a/include/zephyr/dt-bindings/clock/renesas_rzg_clock.h b/include/zephyr/dt-bindings/clock/renesas_rzg_clock.h new file mode 100644 index 0000000000000..af94425e5334f --- /dev/null +++ b/include/zephyr/dt-bindings/clock/renesas_rzg_clock.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_RZG_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_RZG_CLOCK_H_ + +/** RZ clock configuration values */ +#define RZ_IP_MASK 0xFF000000UL +#define RZ_IP_SHIFT 24UL +#define RZ_IP_CH_MASK 0xFF0000UL +#define RZ_IP_CH_SHIFT 16UL +#define RZ_CLOCK_MASK 0xFF00UL +#define RZ_CLOCK_SHIFT 8UL +#define RZ_CLOCK_DIV_MASK 0xFFUL +#define RZ_CLOCK_DIV_SHIFT 0UL + +#define RZ_IP_GTM 0UL /* General Timer */ +#define RZ_IP_GPT 1UL /* General PWM Timer */ +#define RZ_IP_SCIF 2UL /* Serial Communications Interface with FIFO */ +#define RZ_IP_RIIC 3UL /* I2C Bus Interface */ +#define RZ_IP_RSPI 4UL /* Renesas Serial Peripheral Interface */ +#define RZ_IP_MHU 5UL /* Message Handling Unit */ +#define RZ_IP_DMAC 6UL /* Direct Memory Access Controller */ +#define RZ_IP_CANFD 7UL /* CANFD Interface (RS-CANFD) */ +#define RZ_IP_ADC 8UL /* A/D Converter */ + +#define RZ_CLOCK_ICLK 0UL /* Cortex-A55 Clock */ +#define RZ_CLOCK_I2CLK 1UL /* Cortex-M33 Clock */ +#define RZ_CLOCK_I3CLK 2UL /* Cortex-M33 FPU Clock */ +#define RZ_CLOCK_S0CLK 3UL /* DDR-PHY Clock */ +#define RZ_CLOCK_OC0CLK 4UL /* OCTA0 Clock */ +#define RZ_CLOCK_OC1CLK 5UL /* OCTA1 Clock */ +#define RZ_CLOCK_SPI0CLK 6UL /* SPI0 Clock */ +#define RZ_CLOCK_SPI1CLK 7UL /* SPI1 Clock */ +#define RZ_CLOCK_SD0CLK 8UL /* SDH0 Clock */ +#define RZ_CLOCK_SD1CLK 9UL /* SDH1 Clock */ +#define RZ_CLOCK_SD2CLK 10UL /* SDH2 Clock */ +#define RZ_CLOCK_M0CLK 11UL /* VCP LCDC Clock */ +#define RZ_CLOCK_HPCLK 12UL /* Ethernet Clock */ +#define RZ_CLOCK_TSUCLK 13UL /* TSU Clock */ +#define RZ_CLOCK_ZTCLK 14UL /* JAUTH Clock */ +#define RZ_CLOCK_P0CLK 15UL /* APB-BUS Clock */ +#define RZ_CLOCK_P1CLK 16UL /* AXI-BUS Clock */ +#define RZ_CLOCK_P2CLK 17UL /* P2CLK */ +#define RZ_CLOCK_P3CLK 18UL /* P3CLK */ +#define RZ_CLOCK_P4CLK 19UL /* P4CLK */ +#define RZ_CLOCK_P5CLK 20UL /* P5CLK */ +#define RZ_CLOCK_ATCLK 21UL /* ATCLK */ +#define RZ_CLOCK_OSCCLK 22UL /* OSC Clock */ +#define RZ_CLOCK_OSCCLK2 23UL /* OSC2 Clock */ + +#define RZ_CLOCK(IP, ch, clk, div) \ + ((RZ_IP_##IP << RZ_IP_SHIFT) | ((ch) << RZ_IP_CH_SHIFT) | ((clk) << RZ_CLOCK_SHIFT) | \ + ((div) << RZ_CLOCK_DIV_SHIFT)) + +/** + * Pack clock configurations in a 32-bit value + * as expected for the Device Tree `clocks` property on Renesas RZ/G. + * + * @param ch Peripheral channel/unit + */ + +/* SCIF */ +#define RZ_CLOCK_SCIF(ch) RZ_CLOCK(SCIF, ch, RZ_CLOCK_P0CLK, 1) + +/* GPT */ +#define RZ_CLOCK_GPT(ch) RZ_CLOCK(GPT, ch, RZ_CLOCK_P0CLK, 1) + +/* MHU */ +#define RZ_CLOCK_MHU(ch) RZ_CLOCK(MHU, ch, RZ_CLOCK_P1CLK, 2) + +/* ADC */ +#define RZ_CLOCK_ADC(ch) RZ_CLOCK(ADC, ch, RZ_CLOCK_TSUCLK, 1) + +/* RIIC */ +#define RZ_CLOCK_RIIC(ch) RZ_CLOCK(RIIC, ch, RZ_CLOCK_P0CLK, 1) + +/* GTM */ +#define RZ_CLOCK_GTM(ch) RZ_CLOCK(GTM, ch, RZ_CLOCK_P0CLK, 1) + +/* CAN */ +#define RZ_CLOCK_CANFD(ch) RZ_CLOCK(CANFD, ch, RZ_CLOCK_P4CLK, 2) + +/* RSPI */ +#define RZ_CLOCK_RSPI(ch) RZ_CLOCK(RSPI, ch, RZ_CLOCK_P0CLK, 1) + +/* DMAC */ +#define RZ_CLOCK_DMAC(ch) RZ_CLOCK(DMAC, ch, RZ_CLOCK_P3CLK, 1) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_RZG_CLOCK_H_ */ diff --git a/modules/Kconfig.renesas_fsp b/modules/Kconfig.renesas_fsp index 05fc24c9ebf06..6b35466490b3d 100644 --- a/modules/Kconfig.renesas_fsp +++ b/modules/Kconfig.renesas_fsp @@ -183,4 +183,9 @@ config USE_RZ_FSP_EXT_IRQ help Enable RZ FSP External IRQ driver +config USE_RZ_FSP_CPG + bool + help + Enable RZ FSP CLOCK CONTROL driver + endif From a383729653cd5058d1bd2d29952c1105368ebd5c Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 16 Dec 2024 15:30:52 +0700 Subject: [PATCH 0015/6055] dts: renesas: Add Clock Control support for RZ/G3S Add Clock Control nodes to Renesas RZ/G3S devicetree Signed-off-by: Tien Nguyen Signed-off-by: Nhut Nguyen --- dts/arm/renesas/rz/rzg/r9a08g045.dtsi | 159 ++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/dts/arm/renesas/rz/rzg/r9a08g045.dtsi b/dts/arm/renesas/rz/rzg/r9a08g045.dtsi index 1b04204461918..14614b4d22c19 100644 --- a/dts/arm/renesas/rz/rzg/r9a08g045.dtsi +++ b/dts/arm/renesas/rz/rzg/r9a08g045.dtsi @@ -6,6 +6,7 @@ #include #include +#include / { compatible = "renesas,r9a08g045"; @@ -31,7 +32,165 @@ }; }; + osc: osc { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + soc { + cpg: clock-controller@41010000 { + compatible = "renesas,rz-cpg"; + reg = <0x41010000 0x10000>; + clocks = <&osc>; + #clock-cells = <1>; + status = "okay"; + + iclk: iclk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + p0clk: p0clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + p4clk: p4clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + p5clk: p5clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + tsuclk: tsuclk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + sd0clk: sd0clk { + compatible = "fixed-clock"; + clock-frequency = <133333333>; + #clock-cells = <0>; + }; + + sd1clk: sd1clk { + compatible = "fixed-clock"; + clock-frequency = <133333333>; + #clock-cells = <0>; + }; + + sd2clk: sd2clk { + compatible = "fixed-clock"; + clock-frequency = <133333333>; + #clock-cells = <0>; + }; + + m0clk: m0clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + p1clk: p1clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + p2clk: p2clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + p3clk: p3clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + atclk: atclk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + ztclk: ztclk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + oc0clk: oc0clk { + compatible = "fixed-clock"; + clock-frequency = <33333333>; + #clock-cells = <0>; + }; + + oc1clk: oc1clk { + compatible = "fixed-clock"; + clock-frequency = <16666666>; + #clock-cells = <0>; + }; + + spi0clk: spi0clk { + compatible = "fixed-clock"; + clock-frequency = <33333333>; + #clock-cells = <0>; + }; + + spi1clk: spi1clk { + compatible = "fixed-clock"; + clock-frequency = <16666666>; + #clock-cells = <0>; + }; + + s0clk: s0clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + i2clk: i2clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + i3clk: i3clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + hpclk: hpclk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + oscclk: oscclk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + osc2clk: osc2clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + }; + pinctrl: pin-controller@41030000 { compatible = "renesas,rzg-pinctrl"; reg = <0x41030000 DT_SIZE_K(64)>; From 6b945448190780fc9934cdb2e3e9d19a42e73c73 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Wed, 18 Dec 2024 16:21:52 +0700 Subject: [PATCH 0016/6055] boards: renesas: rzg3s_smarc: Add Clock Control support Add Clock Control support for board RZ/G3S-SMARC Signed-off-by: Tien Nguyen Signed-off-by: Nhut Nguyen --- boards/renesas/rzg3s_smarc/doc/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boards/renesas/rzg3s_smarc/doc/index.rst b/boards/renesas/rzg3s_smarc/doc/index.rst index 51323862eb08a..09bcec22e75d6 100644 --- a/boards/renesas/rzg3s_smarc/doc/index.rst +++ b/boards/renesas/rzg3s_smarc/doc/index.rst @@ -73,6 +73,8 @@ and the following hardware features: +-----------+------------+-------------------------------------+ | INTC | on-chip | external interrupt controller | +-----------+------------+-------------------------------------+ +| CLOCK | on-chip | clock control | ++-----------+------------+-------------------------------------+ Other hardware features are currently not supported by the port. From f3703c5c7135d9e826defca1c2b6a08fa1208011 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Thu, 6 Feb 2025 10:08:29 +0700 Subject: [PATCH 0017/6055] dts: arm: renesas: ra: Add support PWM and entropy for RA4M1 Add the PWM and entropy node for r7fa4m1ab3cfp soc Signed-off-by: Khoa Nguyen --- dts/arm/renesas/ra/ra4/r7fa4m1ab3cfp.dtsi | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/dts/arm/renesas/ra/ra4/r7fa4m1ab3cfp.dtsi b/dts/arm/renesas/ra/ra4/r7fa4m1ab3cfp.dtsi index bed5149461bec..4c9c5428c412d 100644 --- a/dts/arm/renesas/ra/ra4/r7fa4m1ab3cfp.dtsi +++ b/dts/arm/renesas/ra/ra4/r7fa4m1ab3cfp.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Renesas Electronics Corporation + * Copyright (c) 2024-2025 Renesas Electronics Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -109,6 +109,31 @@ #port-irq-cells = <0>; status = "disabled"; }; + + trng: trng { + compatible = "renesas,ra-sce5-rng"; + status = "disabled"; + }; + + pwm6: pwm6@40078600 { + compatible = "renesas,ra-pwm"; + divider = ; + channel = ; + clocks = <&pclkd MSTPD 6>; + reg = <0x40078600 0x100>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm7: pwm7@40078700 { + compatible = "renesas,ra-pwm"; + divider = ; + channel = ; + clocks = <&pclkd MSTPD 6>; + reg = <0x40078700 0x100>; + #pwm-cells = <3>; + status = "disabled"; + }; }; clocks: clocks { From fa7132efb08ae97e54e4fe5515c0adea22a6c937 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Thu, 6 Feb 2025 11:09:44 +0700 Subject: [PATCH 0018/6055] boards: renesas: Add config to use entropy, PWM, I2C on ek_ra4m1 Add config and pintrl to use entropy, PWM and I2C on ek_ra4m1 Signed-off-by: Khoa Nguyen --- boards/renesas/ek_ra4m1/doc/index.rst | 6 +++++ boards/renesas/ek_ra4m1/ek_ra4m1-pinctrl.dtsi | 19 +++++++++++++- boards/renesas/ek_ra4m1/ek_ra4m1.dts | 26 ++++++++++++++++++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/boards/renesas/ek_ra4m1/doc/index.rst b/boards/renesas/ek_ra4m1/doc/index.rst index 867dda46652e7..abd0ecd936b81 100644 --- a/boards/renesas/ek_ra4m1/doc/index.rst +++ b/boards/renesas/ek_ra4m1/doc/index.rst @@ -87,6 +87,12 @@ The below features are currently supported on Zephyr for the ``ek_ra4m1`` board: +-----------+------------+----------------------+ | ADC | on-chip | adc | +-----------+------------+----------------------+ +| ENTROPY | on-chip | entropy | ++-----------+------------+----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+----------------------+ +| I2C | on-chip | i2c | ++-----------+------------+----------------------+ Other hardware features are currently not supported by the port. diff --git a/boards/renesas/ek_ra4m1/ek_ra4m1-pinctrl.dtsi b/boards/renesas/ek_ra4m1/ek_ra4m1-pinctrl.dtsi index 49ea76613a0c2..5a701c3bda5eb 100644 --- a/boards/renesas/ek_ra4m1/ek_ra4m1-pinctrl.dtsi +++ b/boards/renesas/ek_ra4m1/ek_ra4m1-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Renesas Electronics Corporation + * Copyright (c) 2024-2025 Renesas Electronics Corporation * SPDX-License-Identifier: Apache-2.0 */ @@ -29,4 +29,21 @@ renesas,analog-enable; }; }; + + pwm1_default: pwm1_default { + group1 { + /* GTIOC1A GTIOC1B */ + psels = , + ; + }; + }; + + iic1_default: iic1_default { + group1 { + /* SCL1 SDA1 */ + psels = , + ; + drive-strength = "medium"; + }; + }; }; diff --git a/boards/renesas/ek_ra4m1/ek_ra4m1.dts b/boards/renesas/ek_ra4m1/ek_ra4m1.dts index d93571828ab35..903f660b1b4c8 100644 --- a/boards/renesas/ek_ra4m1/ek_ra4m1.dts +++ b/boards/renesas/ek_ra4m1/ek_ra4m1.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Renesas Electronics Corporation + * Copyright (c) 2024-2025 Renesas Electronics Corporation * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,7 @@ zephyr,flash = &flash0; zephyr,console = &uart1; zephyr,shell-uart = &uart1; + zephyr,entropy = &trng; }; leds { @@ -104,3 +105,26 @@ interrupts = <27 12>; status = "okay"; }; + +&trng { + status = "okay"; +}; + +&pwm1 { + pinctrl-0 = <&pwm1_default>; + pinctrl-names = "default"; + interrupts = <8 1>, <9 1>; + interrupt-names = "gtioca", "overflow"; + status = "okay"; +}; + +&iic1 { + pinctrl-0 = <&iic1_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + interrupts = <10 1>, <11 1>, <12 1>, <13 1>; + interrupt-names = "rxi", "txi", "tei", "eri"; + status = "okay"; +}; From ddcd752e67d6551d0d2c90d708750a64eaeb6ff8 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Thu, 6 Feb 2025 11:17:31 +0700 Subject: [PATCH 0019/6055] tests: drivers: pwm: Add support pwm_loopback for ek_ra4m1 Add support pwm_loopback to run test app on ek_ra4m1 Signed-off-by: Khoa Nguyen --- .../pwm/pwm_loopback/boards/ek_ra4m1.overlay | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/drivers/pwm/pwm_loopback/boards/ek_ra4m1.overlay diff --git a/tests/drivers/pwm/pwm_loopback/boards/ek_ra4m1.overlay b/tests/drivers/pwm/pwm_loopback/boards/ek_ra4m1.overlay new file mode 100644 index 0000000000000..556410c2aef6a --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/ek_ra4m1.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + pwm_loopback_0 { + compatible = "test-pwm-loopback"; + /* first index must be a 32-Bit timer */ + pwms = <&pwm1 0 0 PWM_POLARITY_NORMAL>, + <&pwm3 0 0 PWM_POLARITY_NORMAL>; + }; +}; + +&pinctrl { + pwm3_default: pwm3_default { + group1 { + /* GTIOC3A */ + psels = ; + }; + }; +}; + +&pwm3 { + pinctrl-0 = <&pwm3_default>; + pinctrl-names = "default"; + interrupts = <30 1>, <31 1>; + interrupt-names = "gtioca", "overflow"; + status = "okay"; +}; From 35d94de056c96bca03d2b84dcd07618accf8ae93 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 7 Feb 2025 11:59:56 +0700 Subject: [PATCH 0020/6055] tests: drivers: adc: add support adc test app for ek_ra4m1 Add support adc_accuracy_test and adc_api test app for ek_ra4m1 board Signed-off-by: Khoa Nguyen --- .../adc_accuracy_test/boards/ek_ra4m1.overlay | 28 +++++++++++++++ .../adc/adc_api/boards/ek_ra4m1.overlay | 36 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/drivers/adc/adc_accuracy_test/boards/ek_ra4m1.overlay create mode 100644 tests/drivers/adc/adc_api/boards/ek_ra4m1.overlay diff --git a/tests/drivers/adc/adc_accuracy_test/boards/ek_ra4m1.overlay b/tests/drivers/adc/adc_accuracy_test/boards/ek_ra4m1.overlay new file mode 100644 index 0000000000000..71c6e206e6146 --- /dev/null +++ b/tests/drivers/adc/adc_accuracy_test/boards/ek_ra4m1.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + io-channels = <&adc0 0>; + reference-mv = <3300>; + expected-accuracy = <32>; + }; +}; + +&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>; + zephyr,vref-mv = <3300>; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/ek_ra4m1.overlay b/tests/drivers/adc/adc_api/boards/ek_ra4m1.overlay new file mode 100644 index 0000000000000..9aab1db0db5d2 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/ek_ra4m1.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +/ { + zephyr,user { + io-channels = <&adc0 0>, <&adc0 2>; + }; +}; + +&adc0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + zephyr,acquisition-time = ; + zephyr,vref-mv = <3300>; + }; + + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + zephyr,acquisition-time = ; + zephyr,vref-mv = <3300>; + }; +}; From 78b55cc97227ac0cd6609ff42e8360efb6842965 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 7 Feb 2025 13:03:20 +0700 Subject: [PATCH 0021/6055] tests: drivers: i2c: Add support i2c test for ek_ra4m1 Add support i2c_target_api test app for ek_ra4m1 board Signed-off-by: Khoa Nguyen --- tests/drivers/i2c/i2c_api/boards/ek_ra4m1.conf | 4 ++++ tests/drivers/i2c/i2c_api/boards/ek_ra4m1.overlay | 12 ++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/drivers/i2c/i2c_api/boards/ek_ra4m1.conf create mode 100644 tests/drivers/i2c/i2c_api/boards/ek_ra4m1.overlay diff --git a/tests/drivers/i2c/i2c_api/boards/ek_ra4m1.conf b/tests/drivers/i2c/i2c_api/boards/ek_ra4m1.conf new file mode 100644 index 0000000000000..3b626dd7fad28 --- /dev/null +++ b/tests/drivers/i2c/i2c_api/boards/ek_ra4m1.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SENSOR_GY271_QMC=y diff --git a/tests/drivers/i2c/i2c_api/boards/ek_ra4m1.overlay b/tests/drivers/i2c/i2c_api/boards/ek_ra4m1.overlay new file mode 100644 index 0000000000000..0dfb29aaae618 --- /dev/null +++ b/tests/drivers/i2c/i2c_api/boards/ek_ra4m1.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2c-0 = &iic1; + gy271 = &iic1; + }; +}; From 0c277e7a3933b48c8822b32236070d510fe1ed9b Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 7 Feb 2025 15:20:48 +0700 Subject: [PATCH 0022/6055] tests: drivers: spi: Add support spi_loopback for ek_ra4m1 Add support spi_loopback to run test app on ek_ra4m1 board Signed-off-by: Khoa Nguyen --- .../spi/spi_loopback/boards/ek_ra4m1.conf | 6 ++++++ .../spi/spi_loopback/boards/ek_ra4m1.overlay | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/drivers/spi/spi_loopback/boards/ek_ra4m1.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/ek_ra4m1.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/ek_ra4m1.conf b/tests/drivers/spi/spi_loopback/boards/ek_ra4m1.conf new file mode 100644 index 0000000000000..a231e084368be --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/ek_ra4m1.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SPI_LOOPBACK_MODE_LOOP=y +CONFIG_SPI_INTERRUPT=y +CONFIG_SPI_RA_DTC=y diff --git a/tests/drivers/spi/spi_loopback/boards/ek_ra4m1.overlay b/tests/drivers/spi/spi_loopback/boards/ek_ra4m1.overlay new file mode 100644 index 0000000000000..0ae7478a32701 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/ek_ra4m1.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&spi1 { + rx-dtc; + tx-dtc; + slow@0 { + compatible = "test-spi-loopback-slow"; + reg = <0>; + spi-max-frequency = <2000000>; + }; + fast@0 { + compatible = "test-spi-loopback-fast"; + reg = <0>; + spi-max-frequency = <3000000>; + }; +}; From fc43629c6f037fbc349af7e58a89a227f3d5d8ca Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 7 Feb 2025 15:22:09 +0700 Subject: [PATCH 0023/6055] tests: drivers: uart: Add support uart_async_api for ek_ra4m1 Add support uart_async_api to run test app on ek_ra4m1 board Signed-off-by: Khoa Nguyen --- .../uart_async_api/boards/ek_ra4m1.overlay | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/drivers/uart/uart_async_api/boards/ek_ra4m1.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/ek_ra4m1.overlay b/tests/drivers/uart/uart_async_api/boards/ek_ra4m1.overlay new file mode 100644 index 0000000000000..6bf3f9ce967d9 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/ek_ra4m1.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + sci9_default: sci9_default { + group1 { + /* tx rx */ + psels = , + ; + }; + }; +}; + +&sci9 { + pinctrl-0 = <&sci9_default>; + pinctrl-names = "default"; + interrupts = <28 1>, <29 1>, <30 1>, <31 1>; + interrupt-names = "rxi", "txi", "tei", "eri"; + status = "okay"; + dut: uart { + current-speed = <115200>; + status = "okay"; + }; +}; From f8d05ea9e99f0f9f19406900b28af7cf99147bd3 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 7 Feb 2025 15:23:00 +0700 Subject: [PATCH 0024/6055] samples: drivers: counter: Add support alarm for ek_ra4m1 Add support counter/alarm to run sample app on ek_ra4m1 Signed-off-by: Khoa Nguyen --- .../drivers/counter/alarm/boards/ek_ra4m1.overlay | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 samples/drivers/counter/alarm/boards/ek_ra4m1.overlay diff --git a/samples/drivers/counter/alarm/boards/ek_ra4m1.overlay b/samples/drivers/counter/alarm/boards/ek_ra4m1.overlay new file mode 100644 index 0000000000000..5b83678c38c07 --- /dev/null +++ b/samples/drivers/counter/alarm/boards/ek_ra4m1.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&agt0 { + status = "okay"; + interrupts = <30 1>, <31 1>; + interrupt-names = "agti", "agtcmai"; + renesas,prescaler = <4>; + counter0: counter { + status = "okay"; + }; +}; From fbd97a198310732682924e1626d4a7dce3d7f60e Mon Sep 17 00:00:00 2001 From: Martin Hoff Date: Mon, 10 Feb 2025 16:31:59 +0100 Subject: [PATCH 0025/6055] soc: silabs: silabs_s2: Activate Zero Latency IRQ with level 2 silabs_s2 uses simplicity_sdk hal library, which already have by default a zero latency IRQs mechanism with a hardcoded value. In order to be aligned with simplicity_sdk, we need to activate Zero Latency IRQ in Zephyr by default. The level (2) depends on the hardcoded value in simplicity_sdk (CORE_ATOMIC_BASE_PRIORITY_LEVEL). Without this fix, if you use an IRQ with a priority of 0 or 1, irq_lock() and irq_unlock() have no effect for this IRQ. Signed-off-by: Martin Hoff --- soc/silabs/silabs_s2/Kconfig.defconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/soc/silabs/silabs_s2/Kconfig.defconfig b/soc/silabs/silabs_s2/Kconfig.defconfig index d7dec5deb3df8..9bea631fe7924 100644 --- a/soc/silabs/silabs_s2/Kconfig.defconfig +++ b/soc/silabs/silabs_s2/Kconfig.defconfig @@ -18,4 +18,17 @@ config SILABS_SLEEPTIMER_TIMER config CORTEX_M_SYSTICK default n if SILABS_SLEEPTIMER_TIMER || GECKO_BURTC_TIMER +# silabs_s2 uses simplicity_sdk hal library, which already have by default a zero latency +# IRQs mechanism with a hardcoded value. In order to be aligned with simplicity_sdk, we +# need to activate Zero Latency IRQ in Zephyr by default. The level (2) depends on the +# hardcoded value in simplicity_sdk (CORE_ATOMIC_BASE_PRIORITY_LEVEL). Without this config, +# if you use an IRQ with a priority of 0 or 1, irq_lock() and irq_unlock() have no effect +# over this IRQ. + +config ZERO_LATENCY_IRQS + default y + +config ZERO_LATENCY_LEVELS + default 2 + endif From e3538a3183654e01b072228cbb83bac1dd05b61f Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Tue, 11 Feb 2025 11:39:20 +0800 Subject: [PATCH 0026/6055] soc: nxp: imxrt: imxrt118x: change trdc permission getting strategy When TRDC permission fails to be obtained, it does not recycle to access ELE core to prevent blocking problems. The current practice only generates a log warning alarm. Signed-off-by: Lucien Zhao --- soc/nxp/imxrt/imxrt118x/soc.c | 37 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/soc/nxp/imxrt/imxrt118x/soc.c b/soc/nxp/imxrt/imxrt118x/soc.c index 169234e1bbf6c..ad73f0525437e 100644 --- a/soc/nxp/imxrt/imxrt118x/soc.c +++ b/soc/nxp/imxrt/imxrt118x/soc.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,8 @@ #include #include +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + /* * Set ELE_STICK_FAILED_STS to 0 when ELE status check is not required, * which is useful when debug reset, where the core has already get the @@ -521,34 +524,36 @@ static ALWAYS_INLINE void trdc_enable_all_access(void) status_t sts; uint8_t i, j; - /* Get ELE FW status */ + /* Get ELE FW status */ do { uint32_t ele_fw_sts; sts = ELE_BaseAPI_GetFwStatus(MU_RT_S3MUA, &ele_fw_sts); } while (sts != kStatus_Success); - do { #if defined(CONFIG_SOC_MIMXRT1189_CM33) - /* Release TRDC A to CM33 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM33_ID); + /* Release TRDC AON to CM33 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM33_ID); #elif defined(CONFIG_SOC_MIMXRT1189_CM7) - /* Release TRDC A to CM7 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM7_ID); + /* Release TRDC AON to CM7 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM7_ID); #endif - } while (ELE_IS_FAILED(sts)); + if (sts != kStatus_Success) { + LOG_WRN("warning: TRDC AON permission get failed. If core don't get TRDC " + "AON permission, AON domain permission can't be configured."); + } - /* Release TRDC W to CM33 core */ - do { #if defined(CONFIG_SOC_MIMXRT1189_CM33) - /* Release TRDC A to CM33 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM33_ID); + /* Release TRDC Wakeup to CM33 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM33_ID); #elif defined(CONFIG_SOC_MIMXRT1189_CM7) - /* Release TRDC A to CM7 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM7_ID); + /* Release TRDC Wakeup to CM7 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM7_ID); #endif - } while (ELE_IS_FAILED(sts)); - + if (sts != kStatus_Success) { + LOG_WRN("warning: TRDC Wakeup permission get failed. If core don't get TRDC " + "Wakeup permission, Wakeup domain permission can't be configured."); + } /* Set the master domain access configuration for eDMA3/eDMA4 */ trdc_non_processor_domain_assignment_t edmaAssignment; From c387fcae17eb8cef274e782acd817bdaa5fe2613 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 11 Feb 2025 08:50:40 +0100 Subject: [PATCH 0027/6055] drivers: flash: stm32h7: fix compilation errors There were some compilation errors caused by unused functions. Add proper #ifdef statements not to include unused functions. Signed-off-by: Dawid Niedzwiecki --- drivers/flash/flash_stm32h7x.c | 51 ++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/drivers/flash/flash_stm32h7x.c b/drivers/flash/flash_stm32h7x.c index 24f5b0b3a7d56..c793e8aca6757 100644 --- a/drivers/flash/flash_stm32h7x.c +++ b/drivers/flash/flash_stm32h7x.c @@ -67,7 +67,9 @@ struct flash_stm32_sector_t { volatile uint32_t *sr; }; -static __unused int commit_optb(const struct device *dev) +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) || defined(CONFIG_FLASH_STM32_WRITE_PROTECT) + +static int commit_optb(const struct device *dev) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); int64_t timeout_time = k_uptime_get() + STM32H7_FLASH_OPT_TIMEOUT_MS; @@ -87,8 +89,8 @@ static __unused int commit_optb(const struct device *dev) } /* Returns negative value on error, 0 if a change was not need, 1 if a change has been made. */ -static __unused int write_opt(const struct device *dev, uint32_t mask, uint32_t value, - uintptr_t cur, bool commit) +static int write_opt(const struct device *dev, uint32_t mask, uint32_t value, uintptr_t cur, + bool commit) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); /* PRG register always follows CUR register. */ @@ -124,7 +126,10 @@ static __unused int write_opt(const struct device *dev, uint32_t mask, uint32_t return 1; } -static __unused int write_optsr(const struct device *dev, uint32_t mask, uint32_t value) +#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT || CONFIG_FLASH_STM32_READOUT_PROTECTION */ + +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) +static int write_optsr(const struct device *dev, uint32_t mask, uint32_t value) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); uintptr_t cur = (uintptr_t)regs + offsetof(FLASH_TypeDef, OPTSR_CUR); @@ -132,26 +137,6 @@ static __unused int write_optsr(const struct device *dev, uint32_t mask, uint32_ return write_opt(dev, mask, value, cur, true); } -static __unused int write_optwp(const struct device *dev, uint32_t mask, uint32_t value, - uint32_t bank) -{ - FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); - uintptr_t cur = (uintptr_t)regs + offsetof(FLASH_TypeDef, WPSN_CUR1); - - if (bank >= NUMBER_OF_BANKS) { - return -EINVAL; - } - -#ifdef DUAL_BANK - if (bank == 1) { - cur = (uintptr_t)regs + offsetof(FLASH_TypeDef, WPSN_CUR2); - } -#endif /* DUAL_BANK */ - - return write_opt(dev, mask, value, cur, false); -} - -#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) uint8_t flash_stm32_get_rdp_level(const struct device *dev) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); @@ -170,6 +155,24 @@ void flash_stm32_set_rdp_level(const struct device *dev, uint8_t level) #define WP_MSK FLASH_WPSN_WRPSN_Msk #define WP_POS FLASH_WPSN_WRPSN_Pos +static int write_optwp(const struct device *dev, uint32_t mask, uint32_t value, uint32_t bank) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + uintptr_t cur = (uintptr_t)regs + offsetof(FLASH_TypeDef, WPSN_CUR1); + + if (bank >= NUMBER_OF_BANKS) { + return -EINVAL; + } + +#ifdef DUAL_BANK + if (bank == 1) { + cur = (uintptr_t)regs + offsetof(FLASH_TypeDef, WPSN_CUR2); + } +#endif /* DUAL_BANK */ + + return write_opt(dev, mask, value, cur, false); +} + int flash_stm32_update_wp_sectors(const struct device *dev, uint64_t changed_sectors, uint64_t protected_sectors) { From 4715a306837f2bc9fe45236597d020ad614908f1 Mon Sep 17 00:00:00 2001 From: Detlev Zundel Date: Thu, 6 Feb 2025 13:41:00 +0100 Subject: [PATCH 0028/6055] samples: modules: lvgl: demos: Increase memory pool to fix crash Due to the added demos, a memory pool of 49 KiB is no longer enough and leads to crashes: https://github.com/lvgl/lvgl/issues/7648 Increasing the memory pool to 57 KiB fixes the problem. Signed-off-by: Detlev Zundel --- samples/modules/lvgl/demos/prj.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/modules/lvgl/demos/prj.conf b/samples/modules/lvgl/demos/prj.conf index aad236d1c362a..4b7ab1bb7dbb3 100644 --- a/samples/modules/lvgl/demos/prj.conf +++ b/samples/modules/lvgl/demos/prj.conf @@ -3,7 +3,7 @@ CONFIG_LOG=y CONFIG_SHELL=y CONFIG_LVGL=y -CONFIG_LV_Z_MEM_POOL_SIZE=49152 +CONFIG_LV_Z_MEM_POOL_SIZE=58368 CONFIG_LV_Z_SHELL=y CONFIG_LV_USE_MONKEY=y From e3e45487dbce48c6d956c6b9f154dd6017956be5 Mon Sep 17 00:00:00 2001 From: Piotr Kosycarz Date: Fri, 7 Feb 2025 08:36:19 +0100 Subject: [PATCH 0029/6055] tests: drivers: pwm: pwm_gpio_loopback: adjust configuration for nrf54h20 Extend CONFIG_SKIP_EDGE_NUM. Signed-off-by: Piotr Kosycarz --- .../pwm/pwm_gpio_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.conf | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/drivers/pwm/pwm_gpio_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.conf diff --git a/tests/drivers/pwm/pwm_gpio_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/tests/drivers/pwm/pwm_gpio_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 0000000000000..795414a504ab4 --- /dev/null +++ b/tests/drivers/pwm/pwm_gpio_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1 @@ +CONFIG_SKIP_EDGE_NUM=4 From 04eba1d392c9294651c6ea2bb65c71720671d9ba Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 7 Feb 2025 22:14:25 +0900 Subject: [PATCH 0030/6055] fb: cfb: Remove unused config CHARACTER_FRAMEBUFFER_SHELL_DRIVER_NAME is not used. Remove it. Signed-off-by: TOKITA Hiroshi --- subsys/fb/Kconfig | 8 -------- 1 file changed, 8 deletions(-) diff --git a/subsys/fb/Kconfig b/subsys/fb/Kconfig index 00be2ab08c088..6e4cf8b668a69 100644 --- a/subsys/fb/Kconfig +++ b/subsys/fb/Kconfig @@ -23,14 +23,6 @@ config CHARACTER_FRAMEBUFFER_SHELL Activate shell module that provides Framebuffer commands to the console. -config CHARACTER_FRAMEBUFFER_SHELL_DRIVER_NAME - string - default "SSD16XX" if SSD16XX - default "SSD1306" if SSD1306 - depends on CHARACTER_FRAMEBUFFER_SHELL - help - Character Framebuffer Display Driver Name - module = CFB module-str = cfb source "subsys/logging/Kconfig.template.log_config" From 6f67555dd7e2f2b473d0d1e83b31c85ece76d3e0 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 4 Feb 2025 15:59:30 +0100 Subject: [PATCH 0031/6055] boards: st: stm32n6: add arduino connector Add Arduino connector for STM32N657X0-DK and Nucleo N657X0 Signed-off-by: Guillaume Gautier --- .../nucleo_n657x0_q/arduino_r3_connector.dtsi | 35 ++++++++++++++++++ .../stm32n6570_dk/arduino_r3_connector.dtsi | 36 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi create mode 100644 boards/st/stm32n6570_dk/arduino_r3_connector.dtsi diff --git a/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi b/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi new file mode 100644 index 0000000000000..1e92e77ed92b9 --- /dev/null +++ b/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioa 8 0>, /* A0 */ + <1 0 &gpioa 9 0>, /* A1 */ + <2 0 &gpioa 10 0>, /* A2 */ + <3 0 &gpioa 12 0>, /* A3 */ + <4 0 &gpiof 3 0>, /* A4 */ + <5 0 &gpiog 15 0>, /* A5 */ + <6 0 &gpiod 9 0>, /* D0 */ + <7 0 &gpiod 8 0>, /* D1 */ + <8 0 &gpiod 0 0>, /* D2 */ + <9 0 &gpioe 9 0>, /* D3 */ + <10 0 &gpioe 0 0>, /* D4 */ + <11 0 &gpioe 10 0>, /* D5 */ + <12 0 &gpiod 5 0>, /* D6 */ + <13 0 &gpioe 11 0>, /* D7 */ + <14 0 &gpiod 12 0>, /* D8 */ + <15 0 &gpiod 7 0>, /* D9 */ + <16 0 &gpioa 3 0>, /* D10 */ + <17 0 &gpiog 2 0>, /* D11 */ + <18 0 &gpiog 1 0>, /* D12 */ + <19 0 &gpioe 15 0>, /* D13 */ + <20 0 &gpioc 1 0>, /* D14 */ + <21 0 &gpioh 9 0>; /* D15 */ + }; +}; diff --git a/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi b/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi new file mode 100644 index 0000000000000..491167d72345a --- /dev/null +++ b/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioa 5 0>, /* A0 */ + <1 0 &gpioa 9 0>, /* A1 */ + <2 0 &gpioa 10 0>, /* A2 */ + <3 0 &gpioa 12 0>, /* A3 */ + <4 0 &gpiof 3 0>, /* A4 */ + <5 0 &gpiob 10 0>, /* A5 */ + <6 0 &gpiof 6 0>, /* D0 */ + <7 0 &gpiod 5 0>, /* D1 */ + <8 0 &gpiod 0 0>, /* D2 */ + <9 0 &gpioe 9 0>, /* D3 */ + <10 0 &gpioh 5 0>, /* D4 */ + <11 0 &gpioe 10 0>, /* D5 */ + <12 0 &gpioe 13 0>, /* D6 */ + <13 0 &gpiod 6 0>, /* D7 */ + <14 0 &gpioe 7 0>, /* D8 */ + <15 0 &gpioe 14 0>, /* D9 */ + <16 0 &gpioa 3 0>, /* D10 */ + <17 0 &gpiog 2 0>, /* D11 */ + <18 0 &gpioh 8 0>, /* D12 */ + <19 0 &gpioe 15 0>, /* D13 */ + <20 0 &gpioc 1 0>, /* D14 */ + <21 0 &gpioh 9 0>; /* D15 */ + }; +}; From b4d799545888e2a8f06b864e6cf13f9bd2c1d295 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 28 Jan 2025 10:02:42 +0100 Subject: [PATCH 0032/6055] boards: st: stm32n6: enable a second uart for stm32n6 boards Enable a second UART for Nucleo N657x0-Q and STM32N6570 DK boards. Signed-off-by: Guillaume Gautier --- boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi | 2 ++ boards/st/nucleo_n657x0_q/doc/index.rst | 2 ++ boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi | 9 +++++++++ boards/st/nucleo_n657x0_q/twister.yaml | 1 + boards/st/stm32n6570_dk/arduino_r3_connector.dtsi | 2 ++ boards/st/stm32n6570_dk/doc/index.rst | 2 ++ boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi | 9 +++++++++ boards/st/stm32n6570_dk/twister.yaml | 1 + 8 files changed, 28 insertions(+) diff --git a/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi b/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi index 1e92e77ed92b9..17ca546f87ec7 100644 --- a/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi +++ b/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi @@ -33,3 +33,5 @@ <21 0 &gpioh 9 0>; /* D15 */ }; }; + +arduino_serial: &usart3 {}; diff --git a/boards/st/nucleo_n657x0_q/doc/index.rst b/boards/st/nucleo_n657x0_q/doc/index.rst index 57e8dd010eac1..c729f1810ab77 100644 --- a/boards/st/nucleo_n657x0_q/doc/index.rst +++ b/boards/st/nucleo_n657x0_q/doc/index.rst @@ -99,6 +99,8 @@ Default Zephyr Peripheral Mapping: - LD2 : PG10 - USART_1_TX : PE5 - USART_1_RX : PE6 +- USART_3_TX : PD8 +- USART_3_RX : PD9 System Clock ------------ diff --git a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi index 3dffbe335e734..db3fd57e2130d 100644 --- a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi +++ b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi @@ -118,3 +118,12 @@ current-speed = <115200>; status = "okay"; }; + +&usart3 { + clocks = <&rcc STM32_CLOCK(APB1, 17)>, + <&rcc STM32_SRC_CKPER USART2_SEL(1)>; + pinctrl-0 = <&usart3_tx_pd8 &usart3_rx_pd9>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; diff --git a/boards/st/nucleo_n657x0_q/twister.yaml b/boards/st/nucleo_n657x0_q/twister.yaml index 1fe32141c7fc9..8ba73fcd9d344 100644 --- a/boards/st/nucleo_n657x0_q/twister.yaml +++ b/boards/st/nucleo_n657x0_q/twister.yaml @@ -4,6 +4,7 @@ arch: arm ram: 1024 flash: 1024 supported: + - arduino_serial - dma - gpio - uart diff --git a/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi b/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi index 491167d72345a..6d887ee41bd6f 100644 --- a/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi +++ b/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi @@ -34,3 +34,5 @@ <21 0 &gpioh 9 0>; /* D15 */ }; }; + +arduino_serial: &usart2 {}; diff --git a/boards/st/stm32n6570_dk/doc/index.rst b/boards/st/stm32n6570_dk/doc/index.rst index 95f2d42f79023..0c1648017ad83 100644 --- a/boards/st/stm32n6570_dk/doc/index.rst +++ b/boards/st/stm32n6570_dk/doc/index.rst @@ -103,6 +103,8 @@ Default Zephyr Peripheral Mapping: - LD2 : PG10 - USART_1_TX : PE5 - USART_1_RX : PE6 +- USART_2_TX : PD5 +- USART_2_RX : PF6 System Clock ------------ diff --git a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi index ba29343eda0ab..834fab39eb935 100644 --- a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi +++ b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi @@ -102,3 +102,12 @@ current-speed = <115200>; status = "okay"; }; + +&usart2 { + clocks = <&rcc STM32_CLOCK(APB1, 17)>, + <&rcc STM32_SRC_CKPER USART2_SEL(1)>; + pinctrl-0 = <&usart2_tx_pd5 &usart2_rx_pf6>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; diff --git a/boards/st/stm32n6570_dk/twister.yaml b/boards/st/stm32n6570_dk/twister.yaml index 5feec454af057..6dfcfaeda28f3 100644 --- a/boards/st/stm32n6570_dk/twister.yaml +++ b/boards/st/stm32n6570_dk/twister.yaml @@ -5,6 +5,7 @@ ram: 1024 flash: 1024 vendor: st supported: + - arduino_serial - dma - gpio - uart From 824bc6cfb51c46366c4e60ae80efb9806094c088 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 31 Jan 2025 10:44:13 +0100 Subject: [PATCH 0033/6055] tests: drivers: uart: async_api: add stm32n6 boards overlays Add UART test overlays for Nucleo N657x0-Q and STM32N6570 DK boards. Remove non serial boot conf file since they are now unnecessary. Signed-off-by: Guillaume Gautier --- .../boards/nucleo_n657x0_q_stm32n657xx_sb.conf | 3 ++- .../boards/nucleo_n657x0_q_stm32n657xx_sb.overlay | 15 +++++++++++++++ .../boards/stm32n6570_dk_stm32n657xx_sb.conf | 3 ++- .../boards/stm32n6570_dk_stm32n657xx_sb.overlay | 15 +++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 tests/drivers/uart/uart_async_api/boards/nucleo_n657x0_q_stm32n657xx_sb.overlay create mode 100644 tests/drivers/uart/uart_async_api/boards/stm32n6570_dk_stm32n657xx_sb.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf b/tests/drivers/uart/uart_async_api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf index 24be02d577c41..3d5e58683e737 100644 --- a/tests/drivers/uart/uart_async_api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf +++ b/tests/drivers/uart/uart_async_api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf @@ -1 +1,2 @@ -CONFIG_DCACHE=n +CONFIG_NOCACHE_MEMORY=y +CONFIG_TEST_USERSPACE=n diff --git a/tests/drivers/uart/uart_async_api/boards/nucleo_n657x0_q_stm32n657xx_sb.overlay b/tests/drivers/uart/uart_async_api/boards/nucleo_n657x0_q_stm32n657xx_sb.overlay new file mode 100644 index 0000000000000..603ecebccb9b6 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/nucleo_n657x0_q_stm32n657xx_sb.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +dut: &usart3 { + dmas = <&gpdma1 0 112 STM32_DMA_PERIPH_TX + &gpdma1 1 111 STM32_DMA_PERIPH_RX>; + dma-names = "tx", "rx"; +}; + +&gpdma1 { + status = "okay"; +}; diff --git a/tests/drivers/uart/uart_async_api/boards/stm32n6570_dk_stm32n657xx_sb.conf b/tests/drivers/uart/uart_async_api/boards/stm32n6570_dk_stm32n657xx_sb.conf index 24be02d577c41..3d5e58683e737 100644 --- a/tests/drivers/uart/uart_async_api/boards/stm32n6570_dk_stm32n657xx_sb.conf +++ b/tests/drivers/uart/uart_async_api/boards/stm32n6570_dk_stm32n657xx_sb.conf @@ -1 +1,2 @@ -CONFIG_DCACHE=n +CONFIG_NOCACHE_MEMORY=y +CONFIG_TEST_USERSPACE=n diff --git a/tests/drivers/uart/uart_async_api/boards/stm32n6570_dk_stm32n657xx_sb.overlay b/tests/drivers/uart/uart_async_api/boards/stm32n6570_dk_stm32n657xx_sb.overlay new file mode 100644 index 0000000000000..7127f08c42c4a --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/stm32n6570_dk_stm32n657xx_sb.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +dut: &usart2 { + dmas = <&gpdma1 0 110 STM32_DMA_PERIPH_TX + &gpdma1 1 109 STM32_DMA_PERIPH_RX>; + dma-names = "tx", "rx"; +}; + +&gpdma1 { + status = "okay"; +}; From c4a817971db94eb65d2a58332ba3136aa13b0dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C5=82=C4=85b?= Date: Tue, 11 Feb 2025 11:34:50 +0100 Subject: [PATCH 0034/6055] tests: drivers: watchodg: Enable wdt_error_cases on nRF5340dk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable wdt_error_cases test on nRF5340dk. Define valid test configuration for that target (reuse from nRF54H/nRF54L). Add target to the platform_allow. Signed-off-by: Sebastian Głąb --- tests/drivers/watchdog/wdt_error_cases/src/main.c | 4 ++-- tests/drivers/watchdog/wdt_error_cases/testcase.yaml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/drivers/watchdog/wdt_error_cases/src/main.c b/tests/drivers/watchdog/wdt_error_cases/src/main.c index 990b2b52c9821..935d8dd95a0fb 100644 --- a/tests/drivers/watchdog/wdt_error_cases/src/main.c +++ b/tests/drivers/watchdog/wdt_error_cases/src/main.c @@ -42,8 +42,8 @@ #define DEFAULT_WINDOW_MIN (0U) /* Align tests to the specific target: */ -#if defined(CONFIG_SOC_SERIES_NRF54LX) || defined(CONFIG_SOC_NRF54H20) || \ - defined(CONFIG_SOC_NRF9280) +#if defined(CONFIG_SOC_SERIES_NRF53X) || defined(CONFIG_SOC_SERIES_NRF54LX) || \ + defined(CONFIG_SOC_NRF54H20) || defined(CONFIG_SOC_NRF9280) #define WDT_TEST_FLAGS \ (WDT_DISABLE_SUPPORTED | WDT_FLAG_RESET_SOC_SUPPORTED | \ WDT_FLAG_ONLY_ONE_TIMEOUT_VALUE_SUPPORTED | WDT_OPT_PAUSE_IN_SLEEP_SUPPORTED | \ diff --git a/tests/drivers/watchdog/wdt_error_cases/testcase.yaml b/tests/drivers/watchdog/wdt_error_cases/testcase.yaml index b585713265442..741b379cacabc 100644 --- a/tests/drivers/watchdog/wdt_error_cases/testcase.yaml +++ b/tests/drivers/watchdog/wdt_error_cases/testcase.yaml @@ -8,6 +8,7 @@ common: tests: drivers.watchdog.wdt_error_cases: platform_allow: + - nrf5340dk/nrf5340/cpuapp - nrf54l09pdk/nrf54l09/cpuapp - nrf54l15dk/nrf54l15/cpuapp - nrf54l20pdk/nrf54l20/cpuapp From 8a10725b5ec85dbee8b329f2162fbc8c8ecf0333 Mon Sep 17 00:00:00 2001 From: Carlo Weidinger Date: Mon, 10 Feb 2025 20:55:44 +0100 Subject: [PATCH 0035/6055] boards: Fixing rak4631 lora RX and TX pins Taking a look at the schematic shows that tx-enable-gpios and dio2-tx-enable were directly connected. This had the effect tx-enable-gpios was trying to pull the line down while SX1262 is pulling the same line high. This increased the power consumption. Now only the SX1262 sets the antenna to tx via dio2-tx-enable. Setting the antenna to rx is still done via the rx-enable-gpios. The antenna defaults to rx if not in use. Signed-off-by: Carlo Weidinger --- boards/rakwireless/rak4631/rak4631_nrf52840.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/boards/rakwireless/rak4631/rak4631_nrf52840.dts b/boards/rakwireless/rak4631/rak4631_nrf52840.dts index c53ea837f010d..5c9b846edf6e6 100644 --- a/boards/rakwireless/rak4631/rak4631_nrf52840.dts +++ b/boards/rakwireless/rak4631/rak4631_nrf52840.dts @@ -119,7 +119,6 @@ reg = <0>; reset-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; busy-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; - tx-enable-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; rx-enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; dio1-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; dio2-tx-enable; From 4632cefc89380e08e08b4c6aed6b697a12f265d4 Mon Sep 17 00:00:00 2001 From: Jonny Gellhaar Date: Tue, 11 Feb 2025 11:48:09 +0100 Subject: [PATCH 0036/6055] fs: api: Fix typo in API documentation Typo in errno reference for mount flag. Signed-off-by: Jonny Gellhaar --- include/zephyr/fs/fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/fs/fs.h b/include/zephyr/fs/fs.h index 57b7c84d6835b..e2cf7dff73b40 100644 --- a/include/zephyr/fs/fs.h +++ b/include/zephyr/fs/fs.h @@ -78,7 +78,7 @@ enum { /** Flag requests file system driver to use Disk Access API. When the flag is * set to the fs_mount_t.flags prior to fs_mount call, a file system * needs to use the Disk Access API, otherwise mount callback for the driver - * should return -ENOSUP; when the flag is not set the file system driver + * should return -ENOTSUP; when the flag is not set the file system driver * should use Flash API by default, unless it only supports Disc Access API. * When file system will use Disk Access API and the flag is not set, the mount * callback for the file system should set the flag on success. From 58b95837d0b50913acc7f6dbe96fd6a61c978415 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 11 Feb 2025 11:49:47 +0100 Subject: [PATCH 0037/6055] manifest: Update nRF hw models to latest Update the HW models module to: 5dc34b26662c6ec91edf1174d775d78590b1a05b Including the following: * 5dc34b2 CLOCK (52-54): Silly bugfix * 4f622b7 CLOCK (52-54): Make TASK_*CLKSTOP instantaneous and clear LFCLK.STAT * 07b1bdb RADIO 54: Correct 2 comments related the CCM trigger Signed-off-by: Alberto Escolar Piedras --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 40cd980370ad1..12200958df531 100644 --- a/west.yml +++ b/west.yml @@ -318,7 +318,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 2570f4a697ce2da860ff39ec34afd91749bd66d3 + revision: 5dc34b26662c6ec91edf1174d775d78590b1a05b path: modules/bsim_hw_models/nrf_hw_models - name: nrf_wifi revision: e35f707a782b7c4c0eb83a3b06ca4e6eb693f29f From f8ebbb3fef12861e9fa94ac9289ced0f09d74670 Mon Sep 17 00:00:00 2001 From: Make Shi Date: Tue, 11 Feb 2025 16:50:40 +0800 Subject: [PATCH 0038/6055] Bluetooth: AVCTP: Implement the functionality of avctp_l2cap_accept - Implement the functionality of avctp_l2cap_accept to accept an L2CAP connection for the AVCTP protocol. Signed-off-by: Make Shi --- subsys/bluetooth/host/classic/avctp.c | 38 ++++++++++++++++++++------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/subsys/bluetooth/host/classic/avctp.c b/subsys/bluetooth/host/classic/avctp.c index 330b22ad9b827..aefe06f555cd8 100644 --- a/subsys/bluetooth/host/classic/avctp.c +++ b/subsys/bluetooth/host/classic/avctp.c @@ -125,15 +125,15 @@ static int avctp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) return session->ops->recv(session, buf); } +static const struct bt_l2cap_chan_ops ops = { + .connected = avctp_l2cap_connected, + .disconnected = avctp_l2cap_disconnected, + .encrypt_change = avctp_l2cap_encrypt_changed, + .recv = avctp_l2cap_recv, +}; + int bt_avctp_connect(struct bt_conn *conn, struct bt_avctp *session) { - static const struct bt_l2cap_chan_ops ops = { - .connected = avctp_l2cap_connected, - .disconnected = avctp_l2cap_disconnected, - .encrypt_change = avctp_l2cap_encrypt_changed, - .recv = avctp_l2cap_recv, - }; - if (!session) { return -EINVAL; } @@ -217,9 +217,29 @@ int bt_avctp_register(const struct bt_avctp_event_cb *cb) static int avctp_l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server, struct bt_l2cap_chan **chan) { - /* TODO */ + struct bt_avctp *session = NULL; + int err; - return -ENOTSUP; + LOG_DBG("conn %p", conn); + + if (!event_cb) { + LOG_WRN("AVCTP server is unsupported"); + return -ENOTSUP; + } + + /* Get the AVCTP session from upper layer */ + err = event_cb->accept(conn, &session); + if (err < 0) { + LOG_ERR("Get the AVCTP session failed %d", err); + return err; + } + + session->br_chan.rx.mtu = BT_L2CAP_RX_MTU; + session->br_chan.psm = BT_L2CAP_PSM_AVCTP; + session->br_chan.chan.ops = &ops; + *chan = &session->br_chan.chan; + + return 0; } int bt_avctp_init(void) From a0fde2e4f8ac953d102a342953882ce10c9c8e9c Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 11 Feb 2025 13:31:00 +0100 Subject: [PATCH 0039/6055] doc: release_notes: Add new BT LE Audio APIs Add list of new functions and APIs for LE Audio. Signed-off-by: Emil Gydesen --- doc/releases/release-notes-4.1.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/releases/release-notes-4.1.rst b/doc/releases/release-notes-4.1.rst index 468f89ef21cbb..da2c2fcb0cf61 100644 --- a/doc/releases/release-notes-4.1.rst +++ b/doc/releases/release-notes-4.1.rst @@ -133,6 +133,15 @@ New APIs and options * Bluetooth + * Audio + + * :c:func:`bt_bap_broadcast_source_register_cb` + * :c:func:`bt_bap_broadcast_source_unregister_cb` + * :c:func:`bt_cap_commander_distribute_broadcast_code` + * ``bt_ccp`` API (in progress) + * :c:func:`bt_pacs_register` + * :c:func:`bt_pacs_unregister` + * Host * :c:func:`bt_conn_is_type` From 7da7818d4f485511ff49698c5d784b3944f28623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Feb 2025 11:07:03 +0100 Subject: [PATCH 0040/6055] Revert "soc: nxp: imxrt: imxrt118x: change trdc permission getting strategy" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e3538a3183654e01b072228cbb83bac1dd05b61f as it's causing CI failures in main. Signed-off-by: Benjamin Cabé --- soc/nxp/imxrt/imxrt118x/soc.c | 37 +++++++++++++++-------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/soc/nxp/imxrt/imxrt118x/soc.c b/soc/nxp/imxrt/imxrt118x/soc.c index ad73f0525437e..169234e1bbf6c 100644 --- a/soc/nxp/imxrt/imxrt118x/soc.c +++ b/soc/nxp/imxrt/imxrt118x/soc.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 NXP + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -24,8 +23,6 @@ #include #include -LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); - /* * Set ELE_STICK_FAILED_STS to 0 when ELE status check is not required, * which is useful when debug reset, where the core has already get the @@ -524,36 +521,34 @@ static ALWAYS_INLINE void trdc_enable_all_access(void) status_t sts; uint8_t i, j; - /* Get ELE FW status */ + /* Get ELE FW status */ do { uint32_t ele_fw_sts; sts = ELE_BaseAPI_GetFwStatus(MU_RT_S3MUA, &ele_fw_sts); } while (sts != kStatus_Success); + do { #if defined(CONFIG_SOC_MIMXRT1189_CM33) - /* Release TRDC AON to CM33 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM33_ID); + /* Release TRDC A to CM33 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM33_ID); #elif defined(CONFIG_SOC_MIMXRT1189_CM7) - /* Release TRDC AON to CM7 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM7_ID); + /* Release TRDC A to CM7 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM7_ID); #endif - if (sts != kStatus_Success) { - LOG_WRN("warning: TRDC AON permission get failed. If core don't get TRDC " - "AON permission, AON domain permission can't be configured."); - } + } while (ELE_IS_FAILED(sts)); + /* Release TRDC W to CM33 core */ + do { #if defined(CONFIG_SOC_MIMXRT1189_CM33) - /* Release TRDC Wakeup to CM33 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM33_ID); + /* Release TRDC A to CM33 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM33_ID); #elif defined(CONFIG_SOC_MIMXRT1189_CM7) - /* Release TRDC Wakeup to CM7 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM7_ID); + /* Release TRDC A to CM7 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM7_ID); #endif - if (sts != kStatus_Success) { - LOG_WRN("warning: TRDC Wakeup permission get failed. If core don't get TRDC " - "Wakeup permission, Wakeup domain permission can't be configured."); - } + } while (ELE_IS_FAILED(sts)); + /* Set the master domain access configuration for eDMA3/eDMA4 */ trdc_non_processor_domain_assignment_t edmaAssignment; From 5ebb04fb561101a231de5567d85df1ff02bd58cf Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Tue, 11 Feb 2025 12:30:01 +0100 Subject: [PATCH 0041/6055] boards/qemu/xtensa: fix `DCACHE_LINE_SIZE` value for `sample_controller32` This commit adds a missing default value for the `DCHACHE_LINE_SIZE` option for the `qemu_xtensa/sample_controller32/mpu` platform. This is required after 8b39d4a6130c28260006a6a35756acd64c7133e9 added a build assert checking this value against `core-isa.h` from Xtensa HAL. Fixes #85591. Signed-off-by: Filip Kokosinski --- boards/qemu/xtensa/Kconfig.defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/qemu/xtensa/Kconfig.defconfig b/boards/qemu/xtensa/Kconfig.defconfig index c94da322385bc..1acc6ce8d4ecf 100644 --- a/boards/qemu/xtensa/Kconfig.defconfig +++ b/boards/qemu/xtensa/Kconfig.defconfig @@ -11,6 +11,7 @@ config IPM_CONSOLE_STACK_SIZE # Must match XCHAL_DCACHE_LINESIZE form core-isa.h config DCACHE_LINE_SIZE + default 4 if BOARD_QEMU_XTENSA_SAMPLE_CONTROLLER32_MPU default 32 endif # BOARD_QEMU_XTENSA From b579a9041344475e5b36d3cc119776b877f1ad9f Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Thu, 17 Oct 2024 11:44:05 -0500 Subject: [PATCH 0042/6055] drivers: power_domain: Add a driver to trigger TURN_ON/TURN_OFF actions This driver triggers the TURN_ON and TURN_OFF actions for certain power states. These power states are specified via device tree. Signed-off-by: Mahesh Mahadevan --- drivers/power_domain/CMakeLists.txt | 1 + drivers/power_domain/Kconfig | 9 ++ .../power_domain_soc_state_change.c | 117 ++++++++++++++++++ .../power-domain-soc-state-change.yaml | 23 ++++ 4 files changed, 150 insertions(+) create mode 100644 drivers/power_domain/power_domain_soc_state_change.c create mode 100644 dts/bindings/power-domain/power-domain-soc-state-change.yaml diff --git a/drivers/power_domain/CMakeLists.txt b/drivers/power_domain/CMakeLists.txt index dedd7a50dffa6..d459e0d88c372 100644 --- a/drivers/power_domain/CMakeLists.txt +++ b/drivers/power_domain/CMakeLists.txt @@ -7,3 +7,4 @@ zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_GPIO power_domain_gpio.c) zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_GPIO_MONITOR power_domain_gpio_monitor.c) zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_INTEL_ADSP power_domain_intel_adsp.c) zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_NXP_SCU power_domain_nxp_scu.c) +zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_SOC_PM_STATE power_domain_soc_state_change.c) diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig index f29057acf5c9d..7bf5fe42470fe 100644 --- a/drivers/power_domain/Kconfig +++ b/drivers/power_domain/Kconfig @@ -90,4 +90,13 @@ config POWER_DOMAIN_NXP_SCU_INIT_PRIORITY endif #POWER_DOMAIN_NXP_SCU +config POWER_DOMAIN_SOC_PM_STATE + bool "SoC PM state power domain" + default y + depends on DT_HAS_POWER_DOMAIN_SOC_STATE_CHANGE_ENABLED + select DEVICE_DEPS + help + Generic power domain control to turn on/off devices when the + PM subsystem transitions in and out certain power states. + endif diff --git a/drivers/power_domain/power_domain_soc_state_change.c b/drivers/power_domain/power_domain_soc_state_change.c new file mode 100644 index 0000000000000..e177c60b4e4be --- /dev/null +++ b/drivers/power_domain/power_domain_soc_state_change.c @@ -0,0 +1,117 @@ +/* + * Copyright 2024-25 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(power_domain_soc_state_change, CONFIG_POWER_DOMAIN_LOG_LEVEL); + +/* Indicates the end of the onoff_power_states array */ +#define POWER_DOMAIN_DEVICE_ONOFF_STATE_MARKER 0xFF + +struct pd_deviceonoff_config { + uint8_t *onoff_power_states; +}; + +struct pd_visitor_context { + const struct device *domain; + enum pm_device_action action; +}; + +static int pd_domain_visitor(const struct device *dev, void *context) +{ + struct pd_visitor_context *visitor_context = context; + + /* Only run action if the device is on the specified domain */ + if (!dev->pm || (dev->pm_base->domain != visitor_context->domain)) { + return 0; + } + + /* In case device is active, first suspend it before turning it off */ + if ((visitor_context->action == PM_DEVICE_ACTION_TURN_OFF) && + (dev->pm_base->state == PM_DEVICE_STATE_ACTIVE)) { + (void)pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND); + } + (void)pm_device_action_run(dev, visitor_context->action); + return 0; +} + +static int pd_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct pd_deviceonoff_config *config = dev->config; + uint8_t i = 0; + /* Get the next power state that will be used */ + enum pm_state state = pm_state_next_get(_current_cpu->id)->state; + struct pd_visitor_context context = {.domain = dev}; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + LOG_DBG("%s: resuming", dev->name); + while (config->onoff_power_states[i] != POWER_DOMAIN_DEVICE_ONOFF_STATE_MARKER) { + /* Check if we need do the turn on action for this state */ + if (state == config->onoff_power_states[i]) { + /* Notify devices on the domain they are now powered */ + context.action = PM_DEVICE_ACTION_TURN_ON; + (void)device_supported_foreach(dev, pd_domain_visitor, &context); + /* No need to go through the rest of the array of states */ + break; + } + i++; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + LOG_DBG("%s: suspending", dev->name); + while (config->onoff_power_states[i] != POWER_DOMAIN_DEVICE_ONOFF_STATE_MARKER) { + /* Check if need to do the turn off action for this state */ + if (state == config->onoff_power_states[i]) { + /* Notify devices on the domain that power is going down */ + context.action = PM_DEVICE_ACTION_TURN_OFF; + (void)device_supported_foreach(dev, pd_domain_visitor, &context); + /* No need to go through the rest of the array of states */ + break; + } + i++; + } + break; + case PM_DEVICE_ACTION_TURN_ON: + break; + case PM_DEVICE_ACTION_TURN_OFF: + break; + default: + return -ENOTSUP; + } + + return 0; +} + +#define DT_DRV_COMPAT power_domain_soc_state_change + +#define PM_STATE_FROM_DT(i, node_id, prop_name) \ + COND_CODE_1(DT_NODE_HAS_STATUS(DT_PHANDLE_BY_IDX(node_id, prop_name, i), okay), \ + (PM_STATE_DT_INIT(DT_PHANDLE_BY_IDX(node_id, prop_name, i)),), ()) + +#define POWER_DOMAIN_DEVICE_ONOFF_STATES(id, node_id) \ + uint8_t onoff_states_##id[] = { \ + LISTIFY(DT_PROP_LEN_OR(node_id, onoff_power_states, 0), \ + PM_STATE_FROM_DT, (), node_id, onoff_power_states) \ + POWER_DOMAIN_DEVICE_ONOFF_STATE_MARKER \ + }; + +#define POWER_DOMAIN_DEVICE(id) \ + POWER_DOMAIN_DEVICE_ONOFF_STATES(id, DT_DRV_INST(id)) \ + \ + static const struct pd_deviceonoff_config pd_deviceonoff_##id##_cfg = { \ + .onoff_power_states = onoff_states_##id, \ + }; \ + PM_DEVICE_DT_INST_DEFINE(id, pd_pm_action); \ + DEVICE_DT_INST_DEFINE(id, NULL, PM_DEVICE_DT_INST_GET(id), \ + NULL, &pd_deviceonoff_##id##_cfg, PRE_KERNEL_1, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); + +DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE) diff --git a/dts/bindings/power-domain/power-domain-soc-state-change.yaml b/dts/bindings/power-domain/power-domain-soc-state-change.yaml new file mode 100644 index 0000000000000..6f5955241d1bc --- /dev/null +++ b/dts/bindings/power-domain/power-domain-soc-state-change.yaml @@ -0,0 +1,23 @@ +# Copyright 2024-25 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + This power domain will Turn On and Off devices when transitioning + in and out a specified Power State. Power States that trigger this + action is specified via the onoff-power-states property. + +compatible: "power-domain-soc-state-change" + +include: power-domain.yaml + +properties: + onoff-power-states: + type: phandles + description: | + List of power management states. + The registered devices will be turned off before the PM subsystem + enters these PM states. The devices will be turned on after the + PM subsystem exits these PM states. + + "#power-domain-cells": + const: 0 From 3b43cb3139f65fa4492cf0235db52904ea979334 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Fri, 7 Feb 2025 13:13:36 -0600 Subject: [PATCH 0043/6055] tests: pm: Test the SoC State Change Power Domain driver The SoC State Change Power Domain driver issues TURN_ON/ TURN_OFF actions to all devices registered with it for certain power states that can be specified via device tree. This test exercises the functionality of this driver. Signed-off-by: Mahesh Mahadevan --- .../CMakeLists.txt | 8 ++ .../pm/power_domain_soc_state_change/Kconfig | 11 +++ .../power_domain_soc_state_change/app.overlay | 46 +++++++++ .../dts/bindings/test-device-pm.yaml | 10 ++ .../pm/power_domain_soc_state_change/prj.conf | 7 ++ .../power_domain_soc_state_change/src/main.c | 93 +++++++++++++++++++ .../testcase.yaml | 10 ++ 7 files changed, 185 insertions(+) create mode 100644 tests/subsys/pm/power_domain_soc_state_change/CMakeLists.txt create mode 100644 tests/subsys/pm/power_domain_soc_state_change/Kconfig create mode 100644 tests/subsys/pm/power_domain_soc_state_change/app.overlay create mode 100644 tests/subsys/pm/power_domain_soc_state_change/dts/bindings/test-device-pm.yaml create mode 100644 tests/subsys/pm/power_domain_soc_state_change/prj.conf create mode 100644 tests/subsys/pm/power_domain_soc_state_change/src/main.c create mode 100644 tests/subsys/pm/power_domain_soc_state_change/testcase.yaml diff --git a/tests/subsys/pm/power_domain_soc_state_change/CMakeLists.txt b/tests/subsys/pm/power_domain_soc_state_change/CMakeLists.txt new file mode 100644 index 0000000000000..538cf3f561214 --- /dev/null +++ b/tests/subsys/pm/power_domain_soc_state_change/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(power_domain_soc_state_change) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/pm/power_domain_soc_state_change/Kconfig b/tests/subsys/pm/power_domain_soc_state_change/Kconfig new file mode 100644 index 0000000000000..6a021dcd9449c --- /dev/null +++ b/tests/subsys/pm/power_domain_soc_state_change/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config TEST_PROVIDE_PM_HOOKS + bool "Provide PM hooks for test purposes" + default y + select HAS_PM diff --git a/tests/subsys/pm/power_domain_soc_state_change/app.overlay b/tests/subsys/pm/power_domain_soc_state_change/app.overlay new file mode 100644 index 0000000000000..330d60daf9d2a --- /dev/null +++ b/tests/subsys/pm/power_domain_soc_state_change/app.overlay @@ -0,0 +1,46 @@ +/* + * Copyright 2025 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + power-states { + state0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <10000>; + exit-latency-us = <100>; + }; + + state1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <50000>; + exit-latency-us = <500>; + }; + + state2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <100000>; + exit-latency-us = <1000>; + }; + }; + + test_soc_state_domain: test_soc_state_domain { + compatible = "power-domain-soc-state-change"; + status = "okay"; + onoff-power-states = <&state1 &state2>; + #power-domain-cells = <0>; + }; + + test_dev_soc_state_change: test_dev_soc_state_change { + compatible = "test-device-pm"; + status = "okay"; + power-domains = <&test_soc_state_domain>; + }; +}; + +&cpu0 { + cpu-power-states = <&state0 &state1 &state2>; +}; diff --git a/tests/subsys/pm/power_domain_soc_state_change/dts/bindings/test-device-pm.yaml b/tests/subsys/pm/power_domain_soc_state_change/dts/bindings/test-device-pm.yaml new file mode 100644 index 0000000000000..2d6c79353e086 --- /dev/null +++ b/tests/subsys/pm/power_domain_soc_state_change/dts/bindings/test-device-pm.yaml @@ -0,0 +1,10 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +include: [base.yaml, pm.yaml] + +description: | + This binding provides resources required to build and run the + tests/subsys/pm/power_domain_soc_state_change test in Zephyr. + +compatible: "test-device-pm" diff --git a/tests/subsys/pm/power_domain_soc_state_change/prj.conf b/tests/subsys/pm/power_domain_soc_state_change/prj.conf new file mode 100644 index 0000000000000..b523d1a9fdf48 --- /dev/null +++ b/tests/subsys/pm/power_domain_soc_state_change/prj.conf @@ -0,0 +1,7 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_PM=y +CONFIG_PM_DEVICE=y +CONFIG_POWER_DOMAIN=y diff --git a/tests/subsys/pm/power_domain_soc_state_change/src/main.c b/tests/subsys/pm/power_domain_soc_state_change/src/main.c new file mode 100644 index 0000000000000..0017b2b2a41c0 --- /dev/null +++ b/tests/subsys/pm/power_domain_soc_state_change/src/main.c @@ -0,0 +1,93 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define TEST_DEV DT_NODELABEL(test_dev_soc_state_change) + +static int testing_domain_on_notitication; +static int testing_domain_off_notitication; + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (testing_domain_off_notitication) { + case 1: + zassert_equal(state, PM_STATE_STANDBY, "Wrong system state %d", state); + break; + case 2: + zassert_true( + ((state == PM_STATE_SUSPEND_TO_IDLE) || (state == PM_STATE_RUNTIME_IDLE)), + "Wrong system state %d", state); + break; + default: + break; + } + + k_cpu_idle(); +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(state); + ARG_UNUSED(substate_id); + + irq_unlock(0); +} + +static int dev_pm_action(const struct device *dev, enum pm_device_action pm_action) +{ + ARG_UNUSED(dev); + + if (pm_action == PM_DEVICE_ACTION_TURN_ON) { + testing_domain_on_notitication++; + } + + if (pm_action == PM_DEVICE_ACTION_TURN_OFF) { + testing_domain_off_notitication++; + } + + return 0; +} + +PM_DEVICE_DT_DEFINE(TEST_DEV, dev_pm_action); +DEVICE_DT_DEFINE(TEST_DEV, NULL, PM_DEVICE_DT_GET(TEST_DEV), NULL, NULL, POST_KERNEL, 20, NULL); + +ZTEST(power_domain_soc_state_change_1cpu, test_power_domain_soc_state_change) +{ + const struct pm_state_info *cpu_states, *state; + + pm_state_cpu_get_all(_current_cpu->id, &cpu_states); + + state = &cpu_states[2]; + /* Sleep to transition to STATE: STANDBY */ + k_usleep(state->min_residency_us + state->exit_latency_us); + + zassert_equal(testing_domain_on_notitication, 1); + zassert_equal(testing_domain_off_notitication, 1); + + state = &cpu_states[1]; + /* Sleep to transition to STATE: SUSPEND-TO-IDLE */ + k_usleep(state->min_residency_us + state->exit_latency_us); + + zassert_equal(testing_domain_on_notitication, 2); + zassert_equal(testing_domain_off_notitication, 2); + + state = &cpu_states[0]; + /* Sleep to transition to STATE: RUNTIME-IDLE */ + k_usleep(state->min_residency_us + state->exit_latency_us); + + /* The domain notification flags should remain the same as RUNTIME-IDLE + * is not listed as an ON/OFF power state in device-tree. + */ + zassert_equal(testing_domain_on_notitication, 2); + zassert_equal(testing_domain_off_notitication, 2); +} + +ZTEST_SUITE(power_domain_soc_state_change_1cpu, NULL, NULL, ztest_simple_1cpu_before, + ztest_simple_1cpu_after, NULL); diff --git a/tests/subsys/pm/power_domain_soc_state_change/testcase.yaml b/tests/subsys/pm/power_domain_soc_state_change/testcase.yaml new file mode 100644 index 0000000000000..5923ecdae5936 --- /dev/null +++ b/tests/subsys/pm/power_domain_soc_state_change/testcase.yaml @@ -0,0 +1,10 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +tests: + pm.power_domain_soc_state_change: + platform_allow: + - native_sim + integration_platforms: + - native_sim + tags: pm From b92c3aa6edbbaccf9958170432773c2c030911f5 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sat, 11 May 2024 17:45:18 -0400 Subject: [PATCH 0044/6055] drivers: flash: spi_nor: Set 4-byte addr mode via write instruction 0x17 Some flash devices enable entering the 4-byte address mode by setting BIT(7) in a special register via a write instruction 0x17. The support for this method is indicated in BIT(3) of Enter 4-Byte Addressing byte in 16th DWORD of the JEDEC Basic Flash Parameter Table. Infineon's S25FL512S is an example flash device with this feature. Signed-off-by: Andriy Gelman --- drivers/flash/spi_nor.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/flash/spi_nor.c b/drivers/flash/spi_nor.c index 9d4823243f11d..9a6ea55cb81b2 100644 --- a/drivers/flash/spi_nor.c +++ b/drivers/flash/spi_nor.c @@ -1139,13 +1139,26 @@ static int spi_nor_set_address_mode(const struct device *dev, /* This currently only supports command 0xB7 (Enter 4-Byte * Address Mode), with or without preceding WREN. + * Or when BIT(3) is set where the 4-byte address mode can be entered + * by setting BIT(7) in a register via a 0x17 write + * instruction. See JEDEC 216F 16th DWORD. */ - if ((enter_4byte_addr & 0x03) == 0) { + if ((enter_4byte_addr & 0x0b) == 0) { return -ENOTSUP; } acquire_device(dev); + if ((enter_4byte_addr & 0x08) != 0) { + /* Enter 4-byte address mode by setting BIT(7) in a register + * via a 0x17 write instruction. + */ + uint8_t sr = BIT(7); + + ret = spi_nor_access(dev, 0x17, NOR_ACCESS_WRITE, 0, &sr, sizeof(sr)); + goto done; + } + if ((enter_4byte_addr & 0x02) != 0) { /* Enter after WREN. */ ret = spi_nor_cmd_write(dev, SPI_NOR_CMD_WREN); @@ -1153,12 +1166,13 @@ static int spi_nor_set_address_mode(const struct device *dev, if (ret == 0) { ret = spi_nor_cmd_write(dev, SPI_NOR_CMD_4BA); + } - if (ret == 0) { - struct spi_nor_data *data = dev->data; +done: + if (ret == 0) { + struct spi_nor_data *data = dev->data; - data->flag_access_32bit = true; - } + data->flag_access_32bit = true; } release_device(dev); From ef4e8dd5c3f8186ab62d28d92bd3f31ddefade61 Mon Sep 17 00:00:00 2001 From: Riadh Ghaddab Date: Tue, 17 Sep 2024 11:16:28 +0200 Subject: [PATCH 0045/6055] settings: ZMS: add a backend for ZMS (Zephyr Memory Storage) This adds the initial backend support for the ZMS storage system. Signed-off-by: Riadh Ghaddab --- subsys/settings/Kconfig | 39 ++ .../settings/include/settings/settings_zms.h | 89 ++++ subsys/settings/src/CMakeLists.txt | 1 + subsys/settings/src/settings_zms.c | 463 ++++++++++++++++++ tests/subsys/settings/zms/CMakeLists.txt | 7 + tests/subsys/settings/zms/prj.conf | 8 + tests/subsys/settings/zms/src/CMakeLists.txt | 12 + tests/subsys/settings/zms/src/settings_test.h | 42 ++ .../settings/zms/src/settings_test_zms.c | 125 +++++ tests/subsys/settings/zms/testcase.yaml | 7 + 10 files changed, 793 insertions(+) create mode 100644 subsys/settings/include/settings/settings_zms.h create mode 100644 subsys/settings/src/settings_zms.c create mode 100644 tests/subsys/settings/zms/CMakeLists.txt create mode 100644 tests/subsys/settings/zms/prj.conf create mode 100644 tests/subsys/settings/zms/src/CMakeLists.txt create mode 100644 tests/subsys/settings/zms/src/settings_test.h create mode 100644 tests/subsys/settings/zms/src/settings_test_zms.c create mode 100644 tests/subsys/settings/zms/testcase.yaml diff --git a/subsys/settings/Kconfig b/subsys/settings/Kconfig index bc015cde9c7d4..a59b618759e04 100644 --- a/subsys/settings/Kconfig +++ b/subsys/settings/Kconfig @@ -32,6 +32,7 @@ config SETTINGS_ENCODE_LEN choice SETTINGS_BACKEND prompt "Storage back-end" + default SETTINGS_ZMS if ZMS default SETTINGS_NVS if NVS default SETTINGS_FCB if FCB default SETTINGS_FILE if FILE_SYSTEM @@ -39,6 +40,13 @@ choice SETTINGS_BACKEND help Storage back-end to be used by the settings subsystem. +config SETTINGS_ZMS + bool "ZMS (Zephyr Memory Storage)" + depends on ZMS + select SYS_HASH_FUNC32 + help + Use ZMS as settings storage backend. + config SETTINGS_FCB bool "FCB" depends on FCB @@ -132,6 +140,37 @@ config SETTINGS_NVS_SECTOR_COUNT help Number of sectors used for the NVS settings area +config SETTINGS_ZMS_SECTOR_SIZE_MULT + int "Sector size of the ZMS settings area" + default 1 + depends on SETTINGS_ZMS + help + The sector size to use for the ZMS settings area as a multiple of + FLASH_ERASE_BLOCK_SIZE. + +config SETTINGS_ZMS_CUSTOM_SECTOR_COUNT + bool "Customize the sector count of the ZMS settings partition" + depends on SETTINGS_ZMS + help + The number of sectors used by default is the maximum value that can + fit in the settings storage partition. + Enabling this config allows to customize the number of used sectors. + +config SETTINGS_ZMS_SECTOR_COUNT + int "Sector count of the ZMS settings area" + default 8 + depends on SETTINGS_ZMS && SETTINGS_ZMS_CUSTOM_SECTOR_COUNT + help + Number of sectors used for the ZMS settings area + +config SETTINGS_ZMS_MAX_COLLISIONS_BITS + int "number of bits reserved to handle collisions between hash numbers" + default 4 + depends on SETTINGS_ZMS + help + The maximum number of hash collisions needs to be well sized depending + on the data that is going to be stored in ZMS and its hash values + config SETTINGS_SHELL bool "Settings shell" depends on SHELL diff --git a/subsys/settings/include/settings/settings_zms.h b/subsys/settings/include/settings/settings_zms.h new file mode 100644 index 0000000000000..5c8db6c8673e1 --- /dev/null +++ b/subsys/settings/include/settings/settings_zms.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2024 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SETTINGS_ZMS_H_ +#define __SETTINGS_ZMS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* In the ZMS backend, each setting is stored in two ZMS entries: + * 1. setting's name + * 2. setting's value + * + * The ZMS entry ID for the setting's value is determined implicitly based on + * the ID of the ZMS entry for the setting's name, once that is found. The + * difference between name and value ID is constant and equal to + * ZMS_NAME_ID_OFFSET. + * + * Setting's name is hashed into 29 bits minus hash_collisions_bits. + * The 2 MSB_bits have always the same value 10, the LL_bit for the name's hash is 0 + * and the hash_collisions_bits is configurable through CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS. + * The resulted 32 bits is the ZMS_ID of the Setting's name. + * If we detect a collision between ZMS_IDs we increment the value within hash_collision_bits + * until we find a free ZMS_ID. + * Separately, we store a linked list using the Setting's name ZMS_ID but setting the lsb to 1. + * + * The linked list is used to maintain a relation between all ZMS_IDs. This is necessary to load + * all settings at initialization. + * The linked list contains at least a header followed by multiple linked list elements that + * we can refer to as LL_x (where x is the order of that element in that list). + * This is a representation of the Linked List that is stored in the storage. + * LL_header <--> LL_0 <--> LL_1 <--> LL_2. + * The "next_hash" pointer of each LL element refers to the next element in the linked list. + * The "previous_hash" pointer is referring the previous element in the linked list. + * + * The bit representation of the 32 bits ZMS_ID is the following: + * -------------------------------------------------------------- + * | MSB_bits | hash (truncated) | hash_collision_bits | LL_bit | + * -------------------------------------------------------------- + * Where: + * MSB_bits (2 bits width) : = 10 for Name IDs + * = 11 for Data IDs + * hash (29 bits - hash_collision_bits) : truncated hash obtained from sys_hash32 + * hash_collision_bits (configurable width) : used to handle hash collisions + * LL_bit : = 0 when this is a name's ZMS_ID + * = 1 when this is the linked list ZMS_ID corresponding to the name + * + * if a settings element is deleted it won't be found. + */ + +#define ZMS_LL_HEAD_HASH_ID 0x80000000 +#define ZMS_DATA_ID_OFFSET 0x40000000 +#define ZMS_HASH_MASK GENMASK(29, CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS + 1) +#define ZMS_COLLISIONS_MASK GENMASK(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS, 1) +#define ZMS_HASH_TOTAL_MASK GENMASK(29, 1) +#define ZMS_MAX_COLLISIONS (BIT(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS) - 1) +#define ZMS_HEADER_HASH 0x80000000 + +/* some useful macros */ +#define ZMS_NAME_HASH_ID(x) (x & ZMS_HASH_TOTAL_MASK) +#define ZMS_UPDATE_COLLISION_NUM(x, y) \ + ((x & ~ZMS_COLLISIONS_MASK) | ((y << 1) & ZMS_COLLISIONS_MASK)) +#define ZMS_COLLISION_NUM(x) ((x & ZMS_COLLISIONS_MASK) >> 1) + +struct settings_zms { + struct settings_store cf_store; + struct zms_fs cf_zms; + const struct device *flash_dev; + uint32_t last_hash_id; + uint32_t second_to_last_hash_id; + uint8_t hash_collision_num; +}; + +struct settings_hash_linked_list { + uint32_t previous_hash; + uint32_t next_hash; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __SETTINGS_ZMS_H_ */ diff --git a/subsys/settings/src/CMakeLists.txt b/subsys/settings/src/CMakeLists.txt index d4ec6e761426f..4aa797fbb3503 100644 --- a/subsys/settings/src/CMakeLists.txt +++ b/subsys/settings/src/CMakeLists.txt @@ -13,3 +13,4 @@ zephyr_sources_ifdef(CONFIG_SETTINGS_FCB settings_fcb.c) zephyr_sources_ifdef(CONFIG_SETTINGS_NVS settings_nvs.c) zephyr_sources_ifdef(CONFIG_SETTINGS_NONE settings_none.c) zephyr_sources_ifdef(CONFIG_SETTINGS_SHELL settings_shell.c) +zephyr_sources_ifdef(CONFIG_SETTINGS_ZMS settings_zms.c) diff --git a/subsys/settings/src/settings_zms.c b/subsys/settings/src/settings_zms.c new file mode 100644 index 0000000000000..abb8989c203c5 --- /dev/null +++ b/subsys/settings/src/settings_zms.c @@ -0,0 +1,463 @@ +/* Copyright (c) 2024 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "settings/settings_zms.h" +#include "settings_priv.h" + +#include +#include +#include +#include +LOG_MODULE_DECLARE(settings, CONFIG_SETTINGS_LOG_LEVEL); + +#if DT_HAS_CHOSEN(zephyr_settings_partition) +#define SETTINGS_PARTITION DT_FIXED_PARTITION_ID(DT_CHOSEN(zephyr_settings_partition)) +#else +#define SETTINGS_PARTITION FIXED_PARTITION_ID(storage_partition) +#endif + +struct settings_zms_read_fn_arg { + struct zms_fs *fs; + uint32_t id; +}; + +static int settings_zms_load(struct settings_store *cs, const struct settings_load_arg *arg); +static int settings_zms_save(struct settings_store *cs, const char *name, const char *value, + size_t val_len); +static void *settings_zms_storage_get(struct settings_store *cs); + +static struct settings_store_itf settings_zms_itf = {.csi_load = settings_zms_load, + .csi_save = settings_zms_save, + .csi_storage_get = settings_zms_storage_get}; + +static ssize_t settings_zms_read_fn(void *back_end, void *data, size_t len) +{ + struct settings_zms_read_fn_arg *rd_fn_arg; + + rd_fn_arg = (struct settings_zms_read_fn_arg *)back_end; + + return zms_read(rd_fn_arg->fs, rd_fn_arg->id, data, len); +} + +static int settings_zms_src(struct settings_zms *cf) +{ + cf->cf_store.cs_itf = &settings_zms_itf; + settings_src_register(&cf->cf_store); + + return 0; +} + +static int settings_zms_dst(struct settings_zms *cf) +{ + cf->cf_store.cs_itf = &settings_zms_itf; + settings_dst_register(&cf->cf_store); + + return 0; +} + +static int settings_zms_unlink_ll_node(struct settings_zms *cf, uint32_t name_hash) +{ + int rc = 0; + struct settings_hash_linked_list settings_element; + struct settings_hash_linked_list settings_update_element; + + /* let's update the linked list */ + rc = zms_read(&cf->cf_zms, name_hash | 1, &settings_element, + sizeof(struct settings_hash_linked_list)); + if (rc < 0) { + return rc; + } + /* update the next element */ + if (settings_element.next_hash) { + rc = zms_read(&cf->cf_zms, settings_element.next_hash, &settings_update_element, + sizeof(struct settings_hash_linked_list)); + if (rc < 0) { + return rc; + } + settings_update_element.previous_hash = settings_element.previous_hash; + rc = zms_write(&cf->cf_zms, settings_element.next_hash, &settings_update_element, + sizeof(struct settings_hash_linked_list)); + if (rc < 0) { + return rc; + } + if (!settings_update_element.next_hash) { + /* update second_to_last_hash_id */ + cf->second_to_last_hash_id = settings_element.previous_hash; + } + } else { + /* we are deleting the last element of the linked list + * let's update the last_hash_id. + */ + cf->last_hash_id = settings_element.previous_hash; + } + /* update the previous element */ + if (settings_element.previous_hash) { + rc = zms_read(&cf->cf_zms, settings_element.previous_hash, &settings_update_element, + sizeof(struct settings_hash_linked_list)); + if (rc < 0) { + return rc; + } + if (!settings_element.next_hash) { + /* we are deleting the last element of the linked list, + * let's update the second_to_last_hash_id + */ + cf->second_to_last_hash_id = settings_update_element.previous_hash; + } + settings_update_element.next_hash = settings_element.next_hash; + rc = zms_write(&cf->cf_zms, settings_element.previous_hash, + &settings_update_element, sizeof(struct settings_hash_linked_list)); + if (rc < 0) { + return rc; + } + } + + return rc; +} + +static int settings_zms_delete(struct settings_zms *cf, uint32_t name_hash) +{ + int rc = 0; + + rc = zms_delete(&cf->cf_zms, name_hash); + if (rc >= 0) { + rc = zms_delete(&cf->cf_zms, name_hash + ZMS_DATA_ID_OFFSET); + } + if (rc < 0) { + return rc; + } + + rc = settings_zms_unlink_ll_node(cf, name_hash); + if (rc < 0) { + return rc; + } + + /* Now delete the current linked list element */ + rc = zms_delete(&cf->cf_zms, name_hash | 1); + if (rc < 0) { + return rc; + } + + return rc; +} + +static int settings_zms_load(struct settings_store *cs, const struct settings_load_arg *arg) +{ + int ret = 0; + struct settings_zms *cf = CONTAINER_OF(cs, struct settings_zms, cf_store); + struct settings_zms_read_fn_arg read_fn_arg; + struct settings_hash_linked_list settings_element; + char name[SETTINGS_MAX_NAME_LEN + SETTINGS_EXTRA_LEN + 1]; + ssize_t rc1; + ssize_t rc2; + uint32_t ll_hash_id; + + ret = zms_read(&cf->cf_zms, ZMS_LL_HEAD_HASH_ID, &settings_element, + sizeof(struct settings_hash_linked_list)); + if (ret < 0) { + return ret; + } + ll_hash_id = settings_element.next_hash; + + while (ll_hash_id) { + + /* In the ZMS backend, each setting item is stored in two ZMS + * entries one for the setting's name and one with the + * setting's value. + */ + rc1 = zms_read(&cf->cf_zms, ZMS_NAME_HASH_ID(ll_hash_id), &name, sizeof(name) - 1); + /* get the length of data and verify that it exists */ + rc2 = zms_get_data_length(&cf->cf_zms, + ZMS_NAME_HASH_ID(ll_hash_id) + ZMS_DATA_ID_OFFSET); + + if ((rc1 <= 0) || (rc2 <= 0)) { + /* Settings item is not stored correctly in the ZMS. + * ZMS entry for its name or value is either missing + * or deleted. Clean dirty entries to make space for + * future settings item. + */ + ret = settings_zms_delete(cf, ZMS_NAME_HASH_ID(ll_hash_id)); + if (ret < 0) { + return ret; + } + continue; + } + + /* Found a name, this might not include a trailing \0 */ + name[rc1] = '\0'; + read_fn_arg.fs = &cf->cf_zms; + read_fn_arg.id = ZMS_NAME_HASH_ID(ll_hash_id) + ZMS_DATA_ID_OFFSET; + + ret = settings_call_set_handler(name, rc2, settings_zms_read_fn, &read_fn_arg, + (void *)arg); + if (ret) { + break; + } + + /* update next ll_hash_id */ + ret = zms_read(&cf->cf_zms, ll_hash_id, &settings_element, + sizeof(struct settings_hash_linked_list)); + if (ret < 0) { + return ret; + } + ll_hash_id = settings_element.next_hash; + } + + return ret; +} + +static int settings_zms_save(struct settings_store *cs, const char *name, const char *value, + size_t val_len) +{ + struct settings_zms *cf = CONTAINER_OF(cs, struct settings_zms, cf_store); + struct settings_hash_linked_list settings_element; + char rdname[SETTINGS_MAX_NAME_LEN + SETTINGS_EXTRA_LEN + 1]; + uint32_t name_hash; + uint32_t collision_num = 0; + bool delete; + bool write_name; + bool hash_collision; + int rc = 0; + int first_available_hash_index = -1; + + if (!name) { + return -EINVAL; + } + + /* Find out if we are doing a delete */ + delete = ((value == NULL) || (val_len == 0)); + + name_hash = sys_hash32(name, strlen(name)) & ZMS_HASH_MASK; + + /* Let's find out if there is no hash collisions in the storage */ + write_name = true; + hash_collision = true; + + for (int i = 0; i <= cf->hash_collision_num; i++) { + rc = zms_read(&cf->cf_zms, name_hash + i * LSB_GET(ZMS_COLLISIONS_MASK), &rdname, + sizeof(rdname)); + if (rc == -ENOENT) { + if (first_available_hash_index < 0) { + first_available_hash_index = i; + } + continue; + } else if (rc < 0) { + /* error while reading */ + return rc; + } + /* Settings entry exist, let's verify if this is the same + * name + */ + rdname[rc] = '\0'; + if (!strcmp(name, rdname)) { + /* Hash exist and the names are equal, we should + * not write the names again. + */ + write_name = false; + name_hash += i * LSB_GET(ZMS_COLLISIONS_MASK); + goto no_hash_collision; + } + /* At this step a Hash collision exists and names are different. + * If we are in the middle of the loop, we should continue checking + * all other possible hash collisions. + * If we reach the end of the loop, either we should select the first + * free hash value otherwise we increment it to the next free value and + * update hash_collision_num + */ + collision_num++; + } + + if (collision_num <= cf->hash_collision_num) { + /* At this step there is a free hash found */ + name_hash = ZMS_UPDATE_COLLISION_NUM(name_hash, first_available_hash_index); + goto no_hash_collision; + } else if (collision_num > cf->hash_collision_num) { + /* We must create a new hash based on incremented collision_num */ + if (collision_num > ZMS_MAX_COLLISIONS) { + /* At this step there is no more space to store hash values */ + LOG_ERR("Maximum hash collisions reached"); + return -ENOSPC; + } + cf->hash_collision_num = collision_num; + name_hash = ZMS_UPDATE_COLLISION_NUM(name_hash, collision_num); + } + +no_hash_collision: + if (delete) { + if (write_name) { + /* hash doesn't exist, do not write anything here */ + return 0; + } + + rc = settings_zms_delete(cf, name_hash); + return rc; + } + + /* write the value */ + rc = zms_write(&cf->cf_zms, name_hash + ZMS_DATA_ID_OFFSET, value, val_len); + if (rc < 0) { + return rc; + } + + /* write the name if required */ + if (write_name) { + rc = zms_write(&cf->cf_zms, name_hash, name, strlen(name)); + if (rc < 0) { + return rc; + } + /* write linked list structure element */ + settings_element.next_hash = 0; + settings_element.previous_hash = cf->last_hash_id; + rc = zms_write(&cf->cf_zms, name_hash | 1, &settings_element, + sizeof(struct settings_hash_linked_list)); + if (rc < 0) { + return rc; + } + /* Now update the previous linked list element */ + settings_element.next_hash = name_hash | 1; + settings_element.previous_hash = cf->second_to_last_hash_id; + rc = zms_write(&cf->cf_zms, cf->last_hash_id, &settings_element, + sizeof(struct settings_hash_linked_list)); + if (rc < 0) { + return rc; + } + cf->second_to_last_hash_id = cf->last_hash_id; + cf->last_hash_id = name_hash | 1; + } + + return 0; +} + +static int settings_zms_get_last_hash_ids(struct settings_zms *cf) +{ + struct settings_hash_linked_list settings_element; + uint32_t ll_last_hash_id = ZMS_LL_HEAD_HASH_ID; + int rc = 0; + + cf->hash_collision_num = 0; + do { + rc = zms_read(&cf->cf_zms, ll_last_hash_id, &settings_element, + sizeof(settings_element)); + if (rc) { + return rc; + } + /* increment hash collision number if necessary */ + if (ZMS_COLLISION_NUM(ll_last_hash_id) > cf->hash_collision_num) { + cf->hash_collision_num = ZMS_COLLISION_NUM(ll_last_hash_id); + } + cf->last_hash_id = ll_last_hash_id; + cf->second_to_last_hash_id = settings_element.previous_hash; + ll_last_hash_id = settings_element.next_hash; + } while (settings_element.next_hash); + + return 0; +} + +/* Initialize the zms backend. */ +static int settings_zms_backend_init(struct settings_zms *cf) +{ + int rc; + + cf->cf_zms.flash_device = cf->flash_dev; + if (cf->cf_zms.flash_device == NULL) { + return -ENODEV; + } + + rc = zms_mount(&cf->cf_zms); + if (rc) { + return rc; + } + + cf->hash_collision_num = 0; + + rc = settings_zms_get_last_hash_ids(cf); + if (rc == -ENOENT) { + /* header doesn't exist or linked list broken, reinitialize the header */ + const struct settings_hash_linked_list settings_element = {.previous_hash = 0, + .next_hash = 0}; + rc = zms_write(&cf->cf_zms, ZMS_LL_HEAD_HASH_ID, &settings_element, + sizeof(struct settings_hash_linked_list)); + if (rc < 0) { + return rc; + } + cf->last_hash_id = ZMS_LL_HEAD_HASH_ID; + cf->second_to_last_hash_id = 0; + } else if (rc < 0) { + return rc; + } + + LOG_DBG("ZMS backend initialized"); + return 0; +} + +int settings_backend_init(void) +{ + static struct settings_zms default_settings_zms; + int rc; + uint32_t cnt = 0; + size_t zms_sector_size; + const struct flash_area *fa; + struct flash_sector hw_flash_sector; + uint32_t sector_cnt = 1; + + rc = flash_area_open(SETTINGS_PARTITION, &fa); + if (rc) { + return rc; + } + + rc = flash_area_get_sectors(SETTINGS_PARTITION, §or_cnt, &hw_flash_sector); + if (rc != 0 && rc != -ENOMEM) { + return rc; + } + + zms_sector_size = CONFIG_SETTINGS_ZMS_SECTOR_SIZE_MULT * hw_flash_sector.fs_size; + + if (zms_sector_size > UINT32_MAX) { + return -EDOM; + } + +#if defined(CONFIG_SETTINGS_ZMS_CUSTOM_SECTOR_COUNT) + size_t zms_size = 0; + + while (cnt < CONFIG_SETTINGS_ZMS_SECTOR_COUNT) { + zms_size += zms_sector_size; + if (zms_size > fa->fa_size) { + break; + } + cnt++; + } +#else + cnt = fa->fa_size / zms_sector_size; +#endif + /* initialize the zms file system structure using the page_info */ + default_settings_zms.cf_zms.sector_size = zms_sector_size; + default_settings_zms.cf_zms.sector_count = cnt; + default_settings_zms.cf_zms.offset = fa->fa_off; + default_settings_zms.flash_dev = fa->fa_dev; + + rc = settings_zms_backend_init(&default_settings_zms); + if (rc) { + return rc; + } + + rc = settings_zms_src(&default_settings_zms); + + if (rc) { + return rc; + } + + rc = settings_zms_dst(&default_settings_zms); + + return rc; +} + +static void *settings_zms_storage_get(struct settings_store *cs) +{ + struct settings_zms *cf = CONTAINER_OF(cs, struct settings_zms, cf_store); + + return &cf->cf_zms; +} diff --git a/tests/subsys/settings/zms/CMakeLists.txt b/tests/subsys/settings/zms/CMakeLists.txt new file mode 100644 index 0000000000000..218451c840edf --- /dev/null +++ b/tests/subsys/settings/zms/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(test_settings_zms_raw) + +add_subdirectory(./src zms_test_bindir) diff --git a/tests/subsys/settings/zms/prj.conf b/tests/subsys/settings/zms/prj.conf new file mode 100644 index 0000000000000..3de961c7c7211 --- /dev/null +++ b/tests/subsys/settings/zms/prj.conf @@ -0,0 +1,8 @@ +CONFIG_ZTEST=y +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_ZMS=y + +CONFIG_SETTINGS=y +CONFIG_SETTINGS_RUNTIME=y +CONFIG_SETTINGS_ZMS=y diff --git a/tests/subsys/settings/zms/src/CMakeLists.txt b/tests/subsys/settings/zms/src/CMakeLists.txt new file mode 100644 index 0000000000000..220a42849a83d --- /dev/null +++ b/tests/subsys/settings/zms/src/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 BayLibre SAS + +zephyr_include_directories( + ${ZEPHYR_BASE}/subsys/settings/include + ${ZEPHYR_BASE}/subsys/settings/src + ${ZEPHYR_BASE}/tests/subsys/settings/zms/src + ) + +target_sources(app PRIVATE settings_test_zms.c) + +add_subdirectory(../../src settings_test_bindir) diff --git a/tests/subsys/settings/zms/src/settings_test.h b/tests/subsys/settings/zms/src/settings_test.h new file mode 100644 index 0000000000000..472ff71f59b60 --- /dev/null +++ b/tests/subsys/settings/zms/src/settings_test.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SETTINGS_TEST_ZMS_H +#define _SETTINGS_TEST_ZMS_H + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint8_t val8; +extern uint8_t val8_un; +extern uint32_t val32; +extern uint64_t val64; + +extern int test_get_called; +extern int test_set_called; +extern int test_commit_called; +extern int test_export_block; + +extern struct settings_handler c_test_handlers[]; + +void ctest_clear_call_state(void); +int ctest_get_call_state(void); + +void config_wipe_srcs(void); +void *settings_config_setup(void); +void settings_config_teardown(void *fixture); + +#ifdef __cplusplus +} +#endif +#endif /* _SETTINGS_TEST_ZMS_H */ diff --git a/tests/subsys/settings/zms/src/settings_test_zms.c b/tests/subsys/settings/zms/src/settings_test_zms.c new file mode 100644 index 0000000000000..17a5ccd56fef3 --- /dev/null +++ b/tests/subsys/settings/zms/src/settings_test_zms.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#include "settings_priv.h" +#include "settings_test.h" + +uint8_t val8; +uint8_t val8_un; +uint32_t val32; +uint64_t val64; + +int test_get_called; +int test_set_called; +int test_commit_called; +int test_export_block; + +int c1_handle_get(const char *name, char *val, int val_len_max); +int c1_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg); +int c1_handle_commit(void); +int c1_handle_export(int (*cb)(const char *name, const void *value, size_t val_len)); + +struct settings_handler c_test_handlers[] = { + {.name = "myfoo", + .h_get = c1_handle_get, + .h_set = c1_handle_set, + .h_commit = c1_handle_commit, + .h_export = c1_handle_export}, +}; + +int c1_handle_get(const char *name, char *val, int val_len_max) +{ + const char *next; + + test_get_called = 1; + + if (settings_name_steq(name, "mybar", &next) && !next) { + val_len_max = MIN(val_len_max, sizeof(val8)); + memcpy(val, &val8, MIN(val_len_max, sizeof(val8))); + return val_len_max; + } + + if (settings_name_steq(name, "mybar64", &next) && !next) { + val_len_max = MIN(val_len_max, sizeof(val64)); + memcpy(val, &val64, MIN(val_len_max, sizeof(val64))); + return val_len_max; + } + + return -ENOENT; +} + +int c1_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) +{ + size_t val_len; + int rc; + const char *next; + + test_set_called = 1; + if (settings_name_steq(name, "mybar", &next) && !next) { + rc = read_cb(cb_arg, &val8, sizeof(val8)); + zassert_true(rc >= 0, "SETTINGS_VALUE_SET callback"); + return 0; + } + + if (settings_name_steq(name, "mybar64", &next) && !next) { + rc = read_cb(cb_arg, &val64, sizeof(val64)); + zassert_true(rc >= 0, "SETTINGS_VALUE_SET callback"); + return 0; + } + + if (settings_name_steq(name, "unaligned", &next) && !next) { + val_len = len; + zassert_equal(val_len, sizeof(val8_un), "value length: %d, ought equal 1", val_len); + rc = read_cb(cb_arg, &val8_un, sizeof(val8_un)); + zassert_true(rc >= 0, "SETTINGS_VALUE_SET callback"); + return 0; + } + + return -ENOENT; +} + +int c1_handle_commit(void) +{ + test_commit_called = 1; + return 0; +} + +int c1_handle_export(int (*cb)(const char *name, const void *value, size_t val_len)) +{ + if (test_export_block) { + return 0; + } + + (void)cb("myfoo/mybar", &val8, sizeof(val8)); + + (void)cb("myfoo/mybar64", &val64, sizeof(val64)); + + (void)cb("myfoo/unaligned", &val8_un, sizeof(val8_un)); + + return 0; +} + +void ctest_clear_call_state(void) +{ + test_get_called = 0; + test_set_called = 0; + test_commit_called = 0; +} + +int ctest_get_call_state(void) +{ + return test_get_called + test_set_called + test_commit_called; +} + +void config_wipe_srcs(void) +{ + sys_slist_init(&settings_load_srcs); + settings_save_dst = NULL; +} + +ZTEST_SUITE(settings_config, NULL, settings_config_setup, NULL, NULL, settings_config_teardown); diff --git a/tests/subsys/settings/zms/testcase.yaml b/tests/subsys/settings/zms/testcase.yaml new file mode 100644 index 0000000000000..2234fd4cd783e --- /dev/null +++ b/tests/subsys/settings/zms/testcase.yaml @@ -0,0 +1,7 @@ +tests: + settings.zms: + depends_on: zms + min_ram: 32 + tags: + - settings + - zms From 97166a5c1115c34544df5c031f4ccaba22a6b403 Mon Sep 17 00:00:00 2001 From: Omkar Kulkarni Date: Wed, 23 Oct 2024 10:50:36 +0200 Subject: [PATCH 0046/6055] tests: settings: Performance test for settings This adds a on target performance test for Settings SS. Using this test performance of the Setting SS + NVS/ZMS backend can be benchmarked. The test repeatedly write 128 settings entries. Each setting entry has a size of 4 bytes, and path length of 16 bytes (excluding the null-terminator). The test has two variants, with and without Bluetooth scan running. This is useful to benchmark performance along with some component of BT subsystem activated. The test could be enhanced in future to include or create combinations of different functionalities running, when agreesive store operations are happening. Signed-off-by: Omkar Kulkarni --- .../settings/performance/CMakeLists.txt | 13 ++ tests/subsys/settings/performance/prj.conf | 7 + .../settings/performance/settings_test_perf.c | 133 ++++++++++++++++++ .../subsys/settings/performance/testcase.yaml | 66 +++++++++ 4 files changed, 219 insertions(+) create mode 100644 tests/subsys/settings/performance/CMakeLists.txt create mode 100644 tests/subsys/settings/performance/prj.conf create mode 100644 tests/subsys/settings/performance/settings_test_perf.c create mode 100644 tests/subsys/settings/performance/testcase.yaml diff --git a/tests/subsys/settings/performance/CMakeLists.txt b/tests/subsys/settings/performance/CMakeLists.txt new file mode 100644 index 0000000000000..b3e4780d3aa59 --- /dev/null +++ b/tests/subsys/settings/performance/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_settings_perf) + +zephyr_include_directories( + ${ZEPHYR_BASE}/subsys/settings/include + ${ZEPHYR_BASE}/subsys/settings/src + ) + +target_sources(app PRIVATE + settings_test_perf.c) diff --git a/tests/subsys/settings/performance/prj.conf b/tests/subsys/settings/performance/prj.conf new file mode 100644 index 0000000000000..27c208baa0bee --- /dev/null +++ b/tests/subsys/settings/performance/prj.conf @@ -0,0 +1,7 @@ +CONFIG_ZTEST=y +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_ZMS=y + +CONFIG_SETTINGS=y +CONFIG_SETTINGS_RUNTIME=y diff --git a/tests/subsys/settings/performance/settings_test_perf.c b/tests/subsys/settings/performance/settings_test_perf.c new file mode 100644 index 0000000000000..a5de17e347503 --- /dev/null +++ b/tests/subsys/settings/performance/settings_test_perf.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include "settings_priv.h" +#include +#include +#include + +/* This is a test suite for performance testing of settings subsystem by writing + * many small setting values repeatedly. Ideally, this should consume as small + * amount of time as possible for best possible UX. + */ + +static struct k_work_q settings_work_q; +static K_THREAD_STACK_DEFINE(settings_work_stack, 2024); +static struct k_work_delayable pending_store; + +#define TEST_SETTINGS_COUNT (128) +#define TEST_STORE_ITR (5) +#define TEST_TIMEOUT_SEC (60) +#define TEST_SETTINGS_WORKQ_PRIO (1) + +static void bt_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, + struct net_buf_simple *buf) +{ + printk("len %u\n", buf->len); +} + +struct test_setting { + uint32_t val; +} test_settings[TEST_SETTINGS_COUNT]; + +K_SEM_DEFINE(waitfor_work, 0, 1); + +static void store_pending(struct k_work *work) +{ + int err; + char path[20]; + struct test_stats { + uint32_t total_calculated; + uint32_t total_measured; + uint32_t single_entry_max; + uint32_t single_entry_min; + } stats = {0, 0, 0, UINT32_MAX}; + + int64_t ts1 = k_uptime_get(); + + /* benchmark storage performance */ + for (int j = 0; j < TEST_STORE_ITR; j++) { + for (int i = 0; i < TEST_SETTINGS_COUNT; i++) { + test_settings[i].val = TEST_SETTINGS_COUNT*j + i; + + int64_t ts2 = k_uptime_get(); + + snprintk(path, sizeof(path), "ab/cdef/ghi/%04x", i); + err = settings_save_one(path, &test_settings[i], + sizeof(struct test_setting)); + zassert_equal(err, 0, "settings_save_one failed %d", err); + + int64_t delta2 = k_uptime_delta(&ts2); + + if (stats.single_entry_max < delta2) { + stats.single_entry_max = delta2; + } + if (stats.single_entry_min > delta2) { + stats.single_entry_min = delta2; + } + stats.total_calculated += delta2; + } + } + + int64_t delta1 = k_uptime_delta(&ts1); + + stats.total_measured = delta1; + + printk("*** storing of %u entries completed ***\n", ARRAY_SIZE(test_settings)); + printk("total calculated: %u, total measured: %u\n", stats.total_calculated, + stats.total_measured); + printk("entry max: %u, entry min: %u\n", stats.single_entry_max, + stats.single_entry_min); + + k_sem_give(&waitfor_work); +} + +ZTEST_SUITE(settings_perf, NULL, NULL, NULL, NULL, NULL); + +ZTEST(settings_perf, test_performance) +{ + int err; + + if (IS_ENABLED(CONFIG_NVS)) { + printk("Testing with NVS\n"); + } else if (IS_ENABLED(CONFIG_ZMS)) { + printk("Testing with ZMS\n"); + } + + k_work_queue_start(&settings_work_q, settings_work_stack, + K_THREAD_STACK_SIZEOF(settings_work_stack), + K_PRIO_COOP(TEST_SETTINGS_WORKQ_PRIO), NULL); + k_thread_name_set(&settings_work_q.thread, "Settings workq"); + k_work_init_delayable(&pending_store, store_pending); + + if (IS_ENABLED(CONFIG_BT)) { + /* enable one of the major subsystems, and start scanning. */ + err = bt_enable(NULL); + zassert_equal(err, 0, "Bluetooth init failed (err %d)\n", err); + + err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, bt_scan_cb); + zassert_equal(err, 0, "Scanning failed to start (err %d)\n", err); + } + + err = settings_subsys_init(); + zassert_equal(err, 0, "settings_backend_init failed %d", err); + + /* fill with values */ + for (int i = 0; i < TEST_SETTINGS_COUNT; i++) { + test_settings[i].val = i; + } + + k_work_reschedule_for_queue(&settings_work_q, &pending_store, K_NO_WAIT); + + err = k_sem_take(&waitfor_work, K_SECONDS(TEST_TIMEOUT_SEC)); + zassert_equal(err, 0, "k_sem_take failed %d", err); + + if (IS_ENABLED(CONFIG_BT)) { + err = bt_le_scan_stop(); + zassert_equal(err, 0, "Scanning failed to stop (err %d)\n", err); + } +} diff --git a/tests/subsys/settings/performance/testcase.yaml b/tests/subsys/settings/performance/testcase.yaml new file mode 100644 index 0000000000000..7ae65c3c55655 --- /dev/null +++ b/tests/subsys/settings/performance/testcase.yaml @@ -0,0 +1,66 @@ +tests: + settings.performance.zms: + extra_configs: + - CONFIG_SETTINGS_ZMS=y + - CONFIG_ZMS_LOOKUP_CACHE=y + - CONFIG_ZMS_LOOKUP_CACHE_SIZE=512 + platform_allow: + - nrf52840dk/nrf52840 + - nrf54l15dk/nrf54l15/cpuapp + min_ram: 32 + tags: + - settings + - zms + + settings.performance.nvs: + extra_configs: + - CONFIG_ZMS=n + - CONFIG_NVS=y + - CONFIG_NVS_LOOKUP_CACHE=y + - CONFIG_NVS_LOOKUP_CACHE_SIZE=512 + - CONFIG_SETTINGS_NVS_NAME_CACHE=y + - CONFIG_SETTINGS_NVS_NAME_CACHE_SIZE=512 + platform_allow: + - nrf52840dk/nrf52840 + - nrf54l15dk/nrf54l15/cpuapp + min_ram: 32 + tags: + - settings + - nvs + + settings.performance.zms_bt: + extra_configs: + - CONFIG_BT=y + - CONFIG_BT_OBSERVER=y + - CONFIG_BT_PERIPHERAL=y + - CONFIG_SETTINGS_ZMS=y + - CONFIG_ZMS_LOOKUP_CACHE=y + - CONFIG_ZMS_LOOKUP_CACHE_SIZE=512 + platform_allow: nrf52840dk/nrf52840 + platform_exclude: + - native_sim + - qemu_x86 + min_ram: 32 + tags: + - settings + - zms + + settings.performance.nvs_bt: + extra_configs: + - CONFIG_BT=y + - CONFIG_BT_OBSERVER=y + - CONFIG_BT_PERIPHERAL=y + - CONFIG_ZMS=n + - CONFIG_NVS=y + - CONFIG_NVS_LOOKUP_CACHE=y + - CONFIG_NVS_LOOKUP_CACHE_SIZE=512 + - CONFIG_SETTINGS_NVS_NAME_CACHE=y + - CONFIG_SETTINGS_NVS_NAME_CACHE_SIZE=512 + platform_allow: nrf52840dk/nrf52840 + platform_exclude: + - native_sim + - qemu_x86 + min_ram: 32 + tags: + - settings + - nvs From ae96ccc3d7d3de82dffe2989e79ba1d8d9cb4ac7 Mon Sep 17 00:00:00 2001 From: Carlo Kirchmeier Date: Wed, 5 Feb 2025 14:40:50 +0100 Subject: [PATCH 0047/6055] fs: enable custom mount points for fatfs Introduce two new kconfig options in order to be able to define custom named fatfs mount points. If activated replace the static FF_VOLUME_STRS approach with the runtime generated VolumeStr array containing those mount points. Signed-off-by: Carlo Kirchmeier --- modules/fatfs/zephyr_fatfs_config.h | 15 +++++++++ modules/fatfs/zfs_diskio.c | 49 +++++++++++++++-------------- subsys/fs/Kconfig.fatfs | 22 +++++++++++++ subsys/fs/fat_fs.c | 23 +++++++++++++- 4 files changed, 84 insertions(+), 25 deletions(-) diff --git a/modules/fatfs/zephyr_fatfs_config.h b/modules/fatfs/zephyr_fatfs_config.h index 396f303ac0f7f..eb33f08f44c78 100644 --- a/modules/fatfs/zephyr_fatfs_config.h +++ b/modules/fatfs/zephyr_fatfs_config.h @@ -117,6 +117,21 @@ #define FF_USE_FIND 1 #endif /* defined(CONFIG_FS_FATFS_EXTRA_NATIVE_API) */ +/* + * When custom mount points are activated FF_VOLUME_STRS needs + * to be undefined in order to be able to provide a custom + * VolumeStr array containing the contents of + * CONFIG_FS_FATFS_CUSTOM_MOUNT_POINTS. Additionally the + * FF_VOLUMES define needs to be set to the correct mount + * point count contained in + * CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT. + */ +#if CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT +#undef FF_VOLUMES +#define FF_VOLUMES CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT +#undef FF_VOLUME_STRS +#endif /* CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT */ + /* * Options provided below have been added to ELM FAT source code to * support Zephyr specific features, and are not part of ffconf.h. diff --git a/modules/fatfs/zfs_diskio.c b/modules/fatfs/zfs_diskio.c index 2b0fa742e711e..d79c5b111bbdc 100644 --- a/modules/fatfs/zfs_diskio.c +++ b/modules/fatfs/zfs_diskio.c @@ -16,14 +16,19 @@ #include /* Zephyr specific FatFS API */ #include -static const char * const pdrv_str[] = {FF_VOLUME_STRS}; +#if CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT +#define PDRV_STR_ARRAY VolumeStr +#else +static const char *const pdrv_str[] = {FF_VOLUME_STRS}; +#define PDRV_STR_ARRAY pdrv_str +#endif /* CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT */ /* Get Drive Status */ DSTATUS disk_status(BYTE pdrv) { - __ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n"); + __ASSERT(pdrv < ARRAY_SIZE(PDRV_STR_ARRAY), "pdrv out-of-range\n"); - if (disk_access_status(pdrv_str[pdrv]) != 0) { + if (disk_access_status(PDRV_STR_ARRAY[pdrv]) != 0) { return STA_NOINIT; } else { return RES_OK; @@ -41,22 +46,21 @@ DSTATUS disk_initialize(BYTE pdrv) /* Read Sector(s) */ DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { - __ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n"); + __ASSERT(pdrv < ARRAY_SIZE(PDRV_STR_ARRAY), "pdrv out-of-range\n"); - if (disk_access_read(pdrv_str[pdrv], buff, sector, count) != 0) { + if (disk_access_read(PDRV_STR_ARRAY[pdrv], buff, sector, count) != 0) { return RES_ERROR; } else { return RES_OK; } - } /* Write Sector(s) */ DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count) { - __ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n"); + __ASSERT(pdrv < ARRAY_SIZE(PDRV_STR_ARRAY), "pdrv out-of-range\n"); - if (disk_access_write(pdrv_str[pdrv], buff, sector, count) != 0) { + if (disk_access_write(PDRV_STR_ARRAY[pdrv], buff, sector, count) != 0) { return RES_ERROR; } else { return RES_OK; @@ -69,19 +73,18 @@ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) int ret = RES_OK; uint32_t sector_size = 0; - __ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n"); + __ASSERT(pdrv < ARRAY_SIZE(PDRV_STR_ARRAY), "pdrv out-of-range\n"); switch (cmd) { case CTRL_SYNC: - if (disk_access_ioctl(pdrv_str[pdrv], - DISK_IOCTL_CTRL_SYNC, buff) != 0) { + if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_CTRL_SYNC, buff) != 0) { ret = RES_ERROR; } break; case GET_SECTOR_COUNT: - if (disk_access_ioctl(pdrv_str[pdrv], - DISK_IOCTL_GET_SECTOR_COUNT, buff) != 0) { + if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_GET_SECTOR_COUNT, buff) != + 0) { ret = RES_ERROR; } break; @@ -91,9 +94,9 @@ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) * 32-bit number while FatFS's GET_SECTOR_SIZE is supposed to * return a 16-bit number. */ - if ((disk_access_ioctl(pdrv_str[pdrv], - DISK_IOCTL_GET_SECTOR_SIZE, §or_size) == 0) && - (sector_size == (uint16_t)sector_size)) { + if ((disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_GET_SECTOR_SIZE, + §or_size) == 0) && + (sector_size == (uint16_t)sector_size)) { *(uint16_t *)buff = (uint16_t)sector_size; } else { ret = RES_ERROR; @@ -101,8 +104,8 @@ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) break; case GET_BLOCK_SIZE: - if (disk_access_ioctl(pdrv_str[pdrv], - DISK_IOCTL_GET_ERASE_BLOCK_SZ, buff) != 0) { + if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_GET_ERASE_BLOCK_SZ, buff) != + 0) { ret = RES_ERROR; } break; @@ -113,16 +116,14 @@ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) case CTRL_POWER: if (((*(uint8_t *)buff)) == DISK_IOCTL_POWER_OFF) { /* Power disk off */ - if (disk_access_ioctl(pdrv_str[pdrv], - DISK_IOCTL_CTRL_DEINIT, - NULL) != 0) { + if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_CTRL_DEINIT, NULL) != + 0) { ret = RES_ERROR; } } else { /* Power disk on */ - if (disk_access_ioctl(pdrv_str[pdrv], - DISK_IOCTL_CTRL_INIT, - NULL) != 0) { + if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_CTRL_INIT, NULL) != + 0) { ret = STA_NOINIT; } } diff --git a/subsys/fs/Kconfig.fatfs b/subsys/fs/Kconfig.fatfs index e91cd71c7dd73..2d3c6b18f03fb 100644 --- a/subsys/fs/Kconfig.fatfs +++ b/subsys/fs/Kconfig.fatfs @@ -277,6 +277,28 @@ config FS_FATFS_MULTI_PARTITION physical drive number and only an FAT volume found on the physical drive will be mounted. +config FS_FATFS_CUSTOM_MOUNT_POINT_COUNT + int "Count of custom mount points" + default 0 + range 0 10 + help + This option has to be used in combination with FS_FATFS_CUSTOM_MOUNT_POINTS. + It specifies how many custom mount points are defined in the custom mount + point string. + +config FS_FATFS_CUSTOM_MOUNT_POINTS + string "Support for custom mountpoints when using fatfs" + help + This option allows to specify custom mount points where fatfs filesystems + can be mounted. The option has to be defined as a comma separated list + with no whitespaces and no trailing commas. + Example: "RAM,SD,SD2,NAND". + It is also necessary to define the count of mount points specified in the + list with the option FS_FATFS_CUSTOM_MOUNT_POINT_COUNT. + If this option is active no mount points not defined within the list can + be used for mounting fatfs filesystems anymore. + depends on FS_FATFS_CUSTOM_MOUNT_POINT_COUNT > 0 + endmenu endif # FAT_FILESYSTEM_ELM diff --git a/subsys/fs/fat_fs.c b/subsys/fs/fat_fs.c index 20367a811a3d0..a0d99c6cf71e0 100644 --- a/subsys/fs/fat_fs.c +++ b/subsys/fs/fat_fs.c @@ -557,9 +557,30 @@ static const struct fs_file_system_t fatfs_fs = { #endif }; +#if CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT +const char *VolumeStr[CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT]; +#endif /* CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT */ + static int fatfs_init(void) { - +#if CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT + static char mount_points[] = CONFIG_FS_FATFS_CUSTOM_MOUNT_POINTS; + int mount_point_count = 0; + + VolumeStr[0] = mount_points; + for (int i = 0; i < ARRAY_SIZE(mount_points) - 1; i++) { + if (mount_points[i] == ',') { + mount_points[i] = 0; + mount_point_count++; + if (mount_point_count >= ARRAY_SIZE(VolumeStr)) { + LOG_ERR("Mount point count not sufficient for defined mount " + "points."); + return -1; + } + VolumeStr[mount_point_count] = &mount_points[i + 1]; + } + } +#endif /* CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT */ return fs_register(FS_FATFS, &fatfs_fs); } From f78742ff752c302da1016c2bfb95d4824ea9460a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Ku=C5=BAnia?= Date: Tue, 4 Feb 2025 12:47:35 +0100 Subject: [PATCH 0048/6055] tests: drivers: adc: add nRF54L20 configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added the test configuration for nRF54L20 for the following tests: - adc_api - adc_error_cases Signed-off-by: Rafał Kuźnia --- drivers/adc/adc_nrfx_saadc.c | 2 +- .../nrf54l20pdk_nrf54l20_cpuapp.overlay | 44 +++++++++++++++++++ .../nrf54l20pdk_nrf54l20_cpuapp.overlay | 15 +++++++ .../drivers/adc/adc_error_cases/testcase.yaml | 1 + 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/drivers/adc/adc_api/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay create mode 100644 tests/drivers/adc/adc_error_cases/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay diff --git a/drivers/adc/adc_nrfx_saadc.c b/drivers/adc/adc_nrfx_saadc.c index e3ea05f124808..0dde7c5bcb03b 100644 --- a/drivers/adc/adc_nrfx_saadc.c +++ b/drivers/adc/adc_nrfx_saadc.c @@ -31,7 +31,7 @@ static const uint8_t saadc_psels[NRF_SAADC_AIN7 + 1] = { [NRF_SAADC_AIN6] = NRF_PIN_PORT_TO_PIN_NUMBER(6U, 1), [NRF_SAADC_AIN7] = NRF_PIN_PORT_TO_PIN_NUMBER(7U, 1), }; -#elif defined(CONFIG_SOC_NRF54L05) || defined(CONFIG_SOC_NRF54L10) || defined(CONFIG_SOC_NRF54L15) +#elif defined(CONFIG_SOC_COMPATIBLE_NRF54LX) static const uint32_t saadc_psels[NRF_SAADC_DVDD + 1] = { [NRF_SAADC_AIN0] = NRF_PIN_PORT_TO_PIN_NUMBER(4U, 1), [NRF_SAADC_AIN1] = NRF_PIN_PORT_TO_PIN_NUMBER(5U, 1), diff --git a/tests/drivers/adc/adc_api/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay b/tests/drivers/adc/adc_api/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay new file mode 100644 index 0000000000000..e1ca1190b33ad --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Nordic Semiconductor ASA + */ + +/ { + zephyr,user { + io-channels = <&adc 0>, <&adc 1> , <&adc 2>; + }; +}; + +&adc { + #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,input-positive = ; + zephyr,resolution = <10>; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1_4"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + zephyr,resolution = <12>; + }; + + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_2_3"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + zephyr,resolution = <10>; + }; +}; diff --git a/tests/drivers/adc/adc_error_cases/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay b/tests/drivers/adc/adc_error_cases/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay new file mode 100644 index 0000000000000..c50279ce8f649 --- /dev/null +++ b/tests/drivers/adc/adc_error_cases/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay @@ -0,0 +1,15 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Nordic Semiconductor ASA + */ + +/ { + aliases { + adc = &adc; + }; +}; + +&adc { + status = "okay"; +}; diff --git a/tests/drivers/adc/adc_error_cases/testcase.yaml b/tests/drivers/adc/adc_error_cases/testcase.yaml index fd3da953eb236..da93a20a1ea6b 100644 --- a/tests/drivers/adc/adc_error_cases/testcase.yaml +++ b/tests/drivers/adc/adc_error_cases/testcase.yaml @@ -9,4 +9,5 @@ tests: platform_allow: - nrf52840dk/nrf52840 - nrf54l15dk/nrf54l15/cpuapp + - nrf54l20pdk/nrf54l20/cpuapp - nrf54h20dk/nrf54h20/cpuapp From 0bb7849aecda172c76330e44ba818c0d776c8ffa Mon Sep 17 00:00:00 2001 From: Jonathon Penix Date: Thu, 6 Feb 2025 16:40:34 -0800 Subject: [PATCH 0049/6055] tests: gen_isr_table: filter *arm_mainline test on *_M_MAINLINE config Since it was added, `arch.interrupt.gen_isr_table_local.arm_mainline` filters on `CONFIG_ARMV6_M_ARMV8_M_BASELINE`. I'm not entirely sure whether this was intentional, but this seems odd to me given a) the naming of the test b) that the `platform_allow` is `qemu_cortex_m3` and c) that the `arch.interrupt.gen_isr_table.arm_mainline` test it inherits part of its config from filters on `CONFIG_ARMV7_M_ARMV8_M_MAINLINE`. The current filtering setup also means that a command like `west twister -c -T tests/kernel/gen_isr_table/` currently filters out all of the `*gen_isr_table_local*` tests which was a surprise to me when testing locally (no tests broke for a change I made as they were all filtered out). Assuming this is undesireable, change the filter to check against `CONFIG_ARMV7_M_ARMV8_M_MAINLINE` to make it possible to run the tests on the expected platform without needing to work around the filter. Signed-off-by: Jonathon Penix --- tests/kernel/gen_isr_table/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/kernel/gen_isr_table/testcase.yaml b/tests/kernel/gen_isr_table/testcase.yaml index a45771919b10f..6b7df17636d4c 100644 --- a/tests/kernel/gen_isr_table/testcase.yaml +++ b/tests/kernel/gen_isr_table/testcase.yaml @@ -56,7 +56,7 @@ tests: - CONFIG_ISR_TABLES_LOCAL_DECLARATION=y arch.interrupt.gen_isr_table_local.arm_mainline: <<: *arm-mainline - filter: CONFIG_GEN_ISR_TABLES and CONFIG_ARMV6_M_ARMV8_M_BASELINE and not CONFIG_USERSPACE + filter: CONFIG_GEN_ISR_TABLES and CONFIG_ARMV7_M_ARMV8_M_MAINLINE and not CONFIG_USERSPACE extra_configs: - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y - CONFIG_ISR_TABLES_LOCAL_DECLARATION=y From cac967db9f2a33215a2046e88b3ca8e902e708da Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Fri, 7 Feb 2025 16:05:21 +0100 Subject: [PATCH 0050/6055] twister: extend reason field in Twister reports Extended the reason field in Twister report to include more detailed information for 'Build failure' and 'CMake build failure' Signed-off-by: Grzegorz Chwierut --- scripts/pylib/twister/twisterlib/reports.py | 58 ++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/reports.py b/scripts/pylib/twister/twisterlib/reports.py index 2131c38a0ddb4..8a11097b3919c 100644 --- a/scripts/pylib/twister/twisterlib/reports.py +++ b/scripts/pylib/twister/twisterlib/reports.py @@ -372,7 +372,6 @@ def json_report(self, filename, version="NA", platform=None, filters=None): suite["available_rom"] = available_rom if instance.status in [TwisterStatus.ERROR, TwisterStatus.FAIL]: suite['status'] = instance.status - suite["reason"] = instance.reason # FIXME if os.path.exists(pytest_log): suite["log"] = self.process_log(pytest_log) @@ -382,6 +381,11 @@ def json_report(self, filename, version="NA", platform=None, filters=None): suite["log"] = self.process_log(device_log) else: suite["log"] = self.process_log(build_log) + + suite["reason"] = self.get_detailed_reason(instance.reason, suite["log"]) + # update the reason to get more details also in other reports (e.g. junit) + # where build log is not available + instance.reason = suite["reason"] elif instance.status == TwisterStatus.FILTER: suite["status"] = TwisterStatus.FILTER suite["reason"] = instance.reason @@ -798,3 +802,55 @@ def target_report(self, json_file, outdir, suffix): self.json_report(json_platform_file + "_footprint.json", version=self.env.version, platform=platform.name, filters=self.json_filters['footprint.json']) + + def get_detailed_reason(self, reason: str, log: str) -> str: + if reason == 'CMake build failure': + if error_key := self._parse_cmake_build_failure(log): + return f"{reason} - {error_key}" + elif reason == 'Build failure': # noqa SIM102 + if error_key := self._parse_build_failure(log): + return f"{reason} - {error_key}" + return reason + + @staticmethod + def _parse_cmake_build_failure(log: str) -> str | None: + last_warning = 'no warning found' + lines = log.splitlines() + for i, line in enumerate(lines): + if "warning: " in line: + last_warning = line + elif "devicetree error: " in line: + return "devicetree error" + elif "fatal error: " in line: + return line[line.index('fatal error: ') :].strip() + elif "error: " in line: # error: Aborting due to Kconfig warnings + if "undefined symbol" in last_warning: + return last_warning[last_warning.index('undefined symbol') :].strip() + return last_warning + elif "CMake Error at" in line: + for next_line in lines[i + 1 :]: + if next_line.strip(): + return line + ' ' + next_line + return line + return None + + @staticmethod + def _parse_build_failure(log: str) -> str | None: + last_warning = '' + lines = log.splitlines() + for i, line in enumerate(lines): + if "undefined reference" in line: + return line[line.index('undefined reference') :].strip() + elif "error: ld returned" in line: + if last_warning: + return last_warning + elif "overflowed by" in lines[i - 1]: + return "ld.bfd: region overflowed" + elif "ld.bfd: warning: " in lines[i - 1]: + return "ld.bfd:" + lines[i - 1].split("ld.bfd:", 1)[-1] + return line + elif "error: " in line: + return line[line.index('error: ') :].strip() + elif ": in function " in line: + last_warning = line[line.index('in function') :].strip() + return None From 33b202e29529c3ee25b7aa0ad62c1117c2c6d879 Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Sat, 8 Feb 2025 23:05:56 +0100 Subject: [PATCH 0051/6055] twister: blackbox: fix test_report_summary after extending reason Updated test_report_summary to match new string with detailed reason of build failure. Signed-off-by: Grzegorz Chwierut --- scripts/tests/twister_blackbox/test_report.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tests/twister_blackbox/test_report.py b/scripts/tests/twister_blackbox/test_report.py index c2ed41f2747de..83d5942c8554c 100644 --- a/scripts/tests/twister_blackbox/test_report.py +++ b/scripts/tests/twister_blackbox/test_report.py @@ -114,8 +114,8 @@ class TestReport: os.path.join(TEST_DATA, 'tests', 'one_fail_two_error_one_pass'), ['qemu_x86/atom'], [r'one_fail_two_error_one_pass.agnostic.group1.subgroup2 on qemu_x86/atom FAILED \(.*\)', - r'one_fail_two_error_one_pass.agnostic.group1.subgroup3 on qemu_x86/atom ERROR \(Build failure\)', - r'one_fail_two_error_one_pass.agnostic.group1.subgroup4 on qemu_x86/atom ERROR \(Build failure\)'], + r'one_fail_two_error_one_pass.agnostic.group1.subgroup3 on qemu_x86/atom ERROR \(Build failure.*\)', + r'one_fail_two_error_one_pass.agnostic.group1.subgroup4 on qemu_x86/atom ERROR \(Build failure.*\)'], ) ] From 145b1b9e64f09e461ba092a846883191fc5779eb Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Mon, 10 Feb 2025 16:49:08 +0100 Subject: [PATCH 0052/6055] ci: twister: Group CMake and Build failures in Twister analysis After adding more detailed information to the reason field in Twister report, update twister_report_analyzer.py to group CMake and Build failures. Signed-off-by: Grzegorz Chwierut --- scripts/ci/twister_report_analyzer.py | 81 +++++++++++++-------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/scripts/ci/twister_report_analyzer.py b/scripts/ci/twister_report_analyzer.py index 74ee9862c110e..3a52c8a2bfe9c 100755 --- a/scripts/ci/twister_report_analyzer.py +++ b/scripts/ci/twister_report_analyzer.py @@ -85,7 +85,7 @@ def add_counter(self, key: str, test: str = '') -> None: def print_counters(self, indent: int = 0): for key, value in self.counters.items(): print(f'{" " * indent}{value.quantity:4} {key}') - if value.subcounters.counters: + if value.has_subcounters(): value.subcounters.print_counters(indent + 4) def sort_by_quantity(self): @@ -93,14 +93,14 @@ def sort_by_quantity(self): sorted(self.counters.items(), key=lambda item: item[1].quantity, reverse=True) ) for value in self.counters.values(): - if value.subcounters.counters: + if value.has_subcounters(): value.subcounters.sort_by_quantity() def get_next_entry(self, depth: int = 0, max_depth: int = 10): for key, value in self.counters.items(): # limit number of test files to 100 to not exceed CSV cell limit yield depth, value.quantity, key, ', '.join(value.tests[0:100]) - if value.subcounters.counters and depth < max_depth: + if value.has_subcounters() and depth < max_depth: yield from value.subcounters.get_next_entry(depth + 1, max_depth) def _flatten(self): @@ -110,7 +110,7 @@ def _flatten(self): do not contain any further nested subcounters. """ for key, value in self.counters.items(): - if value.subcounters.counters: + if value.has_subcounters(): yield from value.subcounters._flatten() else: yield key, value @@ -130,6 +130,9 @@ def append(self, test: str = ''): if test: self.tests.append(test) + def has_subcounters(self): + return bool(self.subcounters.counters) + class TwisterReports: def __init__(self): @@ -161,16 +164,33 @@ def parse_testsuite(self, testsuite): if ts_status not in ('error', 'failed'): return - ts_reason = testsuite.get('reason') or 'Unknown reason' - self.errors.add_counter(ts_reason) ts_platform = testsuite.get('platform') or 'Unknown platform' self.platforms.add_counter(ts_platform) + ts_reason = testsuite.get('reason') or 'Unknown reason' ts_log = testsuite.get('log') test_identifier = f'{testsuite.get("platform")}:{testsuite.get("name")}' - matched = self._parse_ts_error_log( - self.errors.counters[ts_reason].subcounters, ts_reason, ts_log, test_identifier - ) + # CMake and Build failures are treated separately. + # Extract detailed information to group errors. Keep the parsing methods + # to allow for further customization and keep backward compatibility. + if ts_reason.startswith('CMake build failure'): + reason = 'CMake build failure' + self.errors.add_counter(reason) + error_key = ts_reason.split(reason, 1)[-1].lstrip(' -') + if not error_key: + error_key = self._parse_cmake_build_failure(ts_log) + self.errors.counters[reason].subcounters.add_counter(error_key, test_identifier) + ts_reason = reason + elif ts_reason.startswith('Build failure'): + reason = 'Build failure' + self.errors.add_counter(reason) + error_key = ts_reason.split(reason, 1)[-1].lstrip(' -') + if not error_key: + error_key = self._parse_build_failure(ts_log) + self.errors.counters[reason].subcounters.add_counter(error_key, test_identifier) + ts_reason = reason + else: + self.errors.add_counter(ts_reason) # Process testcases for tc in testsuite.get('testcases', []): @@ -178,24 +198,10 @@ def parse_testsuite(self, testsuite): tc_log = tc.get('log') if tc_reason and tc_log: self.errors.counters[ts_reason].subcounters.add_counter(tc_reason, test_identifier) - matched = True - if not matched: + if not self.errors.counters[ts_reason].has_subcounters(): self.errors.counters[ts_reason].tests.append(test_identifier) - def _parse_ts_error_log( - self, counters: Counters, reason: str, log: str, test: str = '' - ) -> bool: - if reason == 'CMake build failure': - if error_key := self._parse_cmake_build_failure(log): - counters.add_counter(error_key, test) - return True - elif reason == 'Build failure': # noqa SIM102 - if error_key := self._parse_build_failure(log): - counters.add_counter(error_key, test) - return True - return False - def _parse_cmake_build_failure(self, log: str) -> str | None: last_warning = 'no warning found' lines = log.splitlines() @@ -263,32 +269,23 @@ def parse_testsuite(self, testsuite): if ts_status not in ('error', 'failed'): return - ts_reason = testsuite.get('reason') or 'Unknown reason' - self.errors.add_counter(ts_reason) ts_log = testsuite.get('log') test_identifier = f'{testsuite.get("platform")}:{testsuite.get("name")}' - self._parse_log_with_error_paterns( - self.errors.counters[ts_reason].subcounters, ts_log, test_identifier - ) + if key := self._parse_log_with_error_paterns(ts_log): + self.errors.add_counter(key, test_identifier) # Process testcases for tc in testsuite.get('testcases', []): - tc_reason = tc.get('reason') tc_log = tc.get('log') - if tc_reason and tc_log: - self.errors.counters[ts_reason].subcounters.add_counter(tc_reason) - self._parse_log_with_error_paterns( - self.errors.counters[ts_reason].subcounters.counters[tc_reason].subcounters, - tc_log, - test_identifier, - ) - - def _parse_log_with_error_paterns(self, counters: Counters, log: str, test: str = ''): + if tc_log and (key := self._parse_log_with_error_paterns(tc_log)): + self.errors.add_counter(key, test_identifier) + + def _parse_log_with_error_paterns(self, log: str) -> str | None: for line in log.splitlines(): for error_pattern in self.error_patterns: if error_pattern in line: logger.debug(f'Matched: {error_pattern} in {line}') - counters.add_counter(error_pattern, test) - return + return error_pattern + return None class EnhancedJSONEncoder(json.JSONEncoder): @@ -363,7 +360,7 @@ def main(): if not reports.errors.counters: return - if args.platforms: + if args.platforms and reports.platforms.counters: print('\nErrors per platform:') reports.platforms.print_counters() From 65b4e594d736258e77770437d66f158eb840d798 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 10 Jan 2025 09:56:40 -0800 Subject: [PATCH 0053/6055] drivers: gpio: pca95xx: Remove unused functions Building with clang warns: drivers/gpio/gpio_pca95xx.c:256:19: error: unused function 'update_input_reg' [-Werror,-Wunused-function] static inline int update_input_reg(const struct device *dev, uint8_t pin, ^ drivers/gpio/gpio_pca95xx.c:120:12: error: unused function 'read_port_reg' [-Werror,-Wunused-function] static int read_port_reg(const struct device *dev, uint8_t reg, ^ uint8_t pin, Signed-off-by: Tom Hughes --- drivers/gpio/gpio_pca95xx.c | 42 ------------------------------------- 1 file changed, 42 deletions(-) diff --git a/drivers/gpio/gpio_pca95xx.c b/drivers/gpio/gpio_pca95xx.c index 662a92465f3bb..c08094c8bb7ae 100644 --- a/drivers/gpio/gpio_pca95xx.c +++ b/drivers/gpio/gpio_pca95xx.c @@ -117,38 +117,6 @@ struct gpio_pca95xx_drv_data { #endif }; -static int read_port_reg(const struct device *dev, uint8_t reg, uint8_t pin, - uint16_t *cache, uint16_t *buf) -{ - const struct gpio_pca95xx_config * const config = dev->config; - uint8_t b_buf; - int ret; - - if (pin >= 8) { - reg++; - } - - ret = i2c_reg_read_byte_dt(&config->bus, reg, &b_buf); - if (ret != 0) { - LOG_ERR("PCA95XX[0x%X]: error reading register 0x%X (%d)", - config->bus.addr, reg, ret); - return ret; - } - - if (pin < 8) { - ((uint8_t *)cache)[LOW_BYTE_LE16_IDX] = b_buf; - } else { - ((uint8_t *)cache)[HIGH_BYTE_LE16_IDX] = b_buf; - } - - *buf = *cache; - - LOG_DBG("PCA95XX[0x%X]: Read: REG[0x%X] = 0x%X", - config->bus.addr, reg, b_buf); - - return 0; -} - /** * @brief Read both port 0 and port 1 registers of certain register function. * @@ -253,16 +221,6 @@ static int write_port_regs(const struct device *dev, uint8_t reg, return ret; } -static inline int update_input_reg(const struct device *dev, uint8_t pin, - uint16_t *buf) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - return read_port_reg(dev, REG_INPUT_PORT0, pin, - &drv_data->reg_cache.input, buf); -} - static inline int update_input_regs(const struct device *dev, uint16_t *buf) { struct gpio_pca95xx_drv_data * const drv_data = From caafe2389101f01181969f651c8d09414662e160 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 4 Feb 2025 19:06:36 +0000 Subject: [PATCH 0054/6055] arch: arm: cortex_m: Apply clang-format on cortex_m related code This commit updates cortex_m related code to align it with the rules from .clang-format. This is done to simplify future changes in these files as we are about to implement use_switch support. Some rules conflict with checkpatch and therefore some small part of the code locally disable clang-format. Signed-off-by: Wilfried Chauveau --- arch/arm/core/cortex_m/cmse/arm_core_cmse.c | 35 +- arch/arm/core/cortex_m/coredump.c | 48 +- arch/arm/core/cortex_m/cpu_idle.c | 38 +- arch/arm/core/cortex_m/debug.c | 33 +- arch/arm/core/cortex_m/fault.c | 133 ++--- arch/arm/core/cortex_m/fpu.c | 18 +- arch/arm/core/cortex_m/irq_manage.c | 15 +- arch/arm/core/cortex_m/prep_c.c | 11 +- arch/arm/core/cortex_m/scb.c | 5 +- arch/arm/core/cortex_m/semihost.c | 9 +- arch/arm/core/cortex_m/thread.c | 202 +++---- arch/arm/core/cortex_m/timing.c | 4 +- arch/arm/include/cortex_m/cmse.h | 38 +- arch/arm/include/cortex_m/dwt.h | 12 +- arch/arm/include/cortex_m/exception.h | 74 ++- arch/arm/include/cortex_m/kernel_arch_func.h | 18 +- arch/arm/include/cortex_m/stack.h | 8 +- arch/arm/include/cortex_m/tz_ns.h | 44 +- include/zephyr/arch/arm/cortex_m/cpu.h | 30 +- include/zephyr/arch/arm/cortex_m/exception.h | 15 +- include/zephyr/arch/arm/cortex_m/memory_map.h | 107 ++-- include/zephyr/arch/arm/mpu/arm_mpu.h | 35 +- include/zephyr/arch/arm/mpu/arm_mpu_v7m.h | 325 ++++++----- include/zephyr/arch/arm/mpu/arm_mpu_v8.h | 353 ++++++------ include/zephyr/arch/arm/mpu/nxp_mpu.h | 243 ++++---- .../src/arm_hardfault.c | 6 +- .../arm/arm_interrupt/src/arm_interrupt.c | 122 ++-- .../src/arm_dynamic_direct_interrupts.c | 12 +- .../src/arm_irq_target_state.c | 36 +- .../src/arm_zero_latency_irqs.c | 9 +- .../src/arm_irq_vector_table.c | 83 ++- .../arch/arm/arm_irq_vector_table/src/main.c | 2 +- .../arm_irq_zero_latency_levels/src/main.c | 34 +- .../arch/arm/arm_no_multithreading/src/main.c | 33 +- .../arm/arm_runtime_nmi/src/arm_runtime_nmi.c | 1 - .../src/arm_sw_vector_relay.c | 27 +- tests/arch/arm/arm_sw_vector_relay/src/main.c | 2 +- .../arm/arm_thread_swap/src/arm_syscalls.c | 97 ++-- .../arm/arm_thread_swap/src/arm_thread_arch.c | 536 +++++++----------- tests/arch/arm/arm_thread_swap_tz/src/main.c | 56 +- tests/arch/arm/arm_tz_wrap_func/src/main.c | 15 +- 41 files changed, 1264 insertions(+), 1660 deletions(-) diff --git a/arch/arm/core/cortex_m/cmse/arm_core_cmse.c b/arch/arm/core/cortex_m/cmse/arm_core_cmse.c index aac96472ecf4f..163a9d0cdd205 100644 --- a/arch/arm/core/cortex_m/cmse/arm_core_cmse.c +++ b/arch/arm/core/cortex_m/cmse/arm_core_cmse.c @@ -9,7 +9,7 @@ int arm_cmse_mpu_region_get(uint32_t addr) { - cmse_address_info_t addr_info = cmse_TT((void *)addr); + cmse_address_info_t addr_info = cmse_TT((void *)addr); if (addr_info.flags.mpu_region_valid) { return addr_info.flags.mpu_region; @@ -40,8 +40,7 @@ int arm_cmse_addr_readwrite_ok(uint32_t addr, int force_npriv) return arm_cmse_addr_read_write_ok(addr, force_npriv, 1); } -static int arm_cmse_addr_range_read_write_ok(uint32_t addr, uint32_t size, - int force_npriv, int rw) +static int arm_cmse_addr_range_read_write_ok(uint32_t addr, uint32_t size, int force_npriv, int rw) { int flags = 0; @@ -74,10 +73,10 @@ int arm_cmse_addr_range_readwrite_ok(uint32_t addr, uint32_t size, int force_npr int arm_cmse_mpu_nonsecure_region_get(uint32_t addr) { - cmse_address_info_t addr_info = cmse_TTA((void *)addr); + cmse_address_info_t addr_info = cmse_TTA((void *)addr); if (addr_info.flags.mpu_region_valid) { - return addr_info.flags.mpu_region; + return addr_info.flags.mpu_region; } return -EINVAL; @@ -85,7 +84,7 @@ int arm_cmse_mpu_nonsecure_region_get(uint32_t addr) int arm_cmse_sau_region_get(uint32_t addr) { - cmse_address_info_t addr_info = cmse_TT((void *)addr); + cmse_address_info_t addr_info = cmse_TT((void *)addr); if (addr_info.flags.sau_region_valid) { return addr_info.flags.sau_region; @@ -96,7 +95,7 @@ int arm_cmse_sau_region_get(uint32_t addr) int arm_cmse_idau_region_get(uint32_t addr) { - cmse_address_info_t addr_info = cmse_TT((void *)addr); + cmse_address_info_t addr_info = cmse_TT((void *)addr); if (addr_info.flags.idau_region_valid) { return addr_info.flags.idau_region; @@ -107,13 +106,12 @@ int arm_cmse_idau_region_get(uint32_t addr) int arm_cmse_addr_is_secure(uint32_t addr) { - cmse_address_info_t addr_info = cmse_TT((void *)addr); + cmse_address_info_t addr_info = cmse_TT((void *)addr); return addr_info.flags.secure; } -static int arm_cmse_addr_nonsecure_read_write_ok(uint32_t addr, - int force_npriv, int rw) +static int arm_cmse_addr_nonsecure_read_write_ok(uint32_t addr, int force_npriv, int rw) { cmse_address_info_t addr_info; if (force_npriv) { @@ -122,8 +120,7 @@ static int arm_cmse_addr_nonsecure_read_write_ok(uint32_t addr, addr_info = cmse_TTA((void *)addr); } - return rw ? addr_info.flags.nonsecure_readwrite_ok : - addr_info.flags.nonsecure_read_ok; + return rw ? addr_info.flags.nonsecure_readwrite_ok : addr_info.flags.nonsecure_read_ok; } int arm_cmse_addr_nonsecure_read_ok(uint32_t addr, int force_npriv) @@ -137,7 +134,7 @@ int arm_cmse_addr_nonsecure_readwrite_ok(uint32_t addr, int force_npriv) } static int arm_cmse_addr_range_nonsecure_read_write_ok(uint32_t addr, uint32_t size, - int force_npriv, int rw) + int force_npriv, int rw) { int flags = CMSE_NONSECURE; @@ -156,18 +153,14 @@ static int arm_cmse_addr_range_nonsecure_read_write_ok(uint32_t addr, uint32_t s } } -int arm_cmse_addr_range_nonsecure_read_ok(uint32_t addr, uint32_t size, - int force_npriv) +int arm_cmse_addr_range_nonsecure_read_ok(uint32_t addr, uint32_t size, int force_npriv) { - return arm_cmse_addr_range_nonsecure_read_write_ok(addr, size, - force_npriv, 0); + return arm_cmse_addr_range_nonsecure_read_write_ok(addr, size, force_npriv, 0); } -int arm_cmse_addr_range_nonsecure_readwrite_ok(uint32_t addr, uint32_t size, - int force_npriv) +int arm_cmse_addr_range_nonsecure_readwrite_ok(uint32_t addr, uint32_t size, int force_npriv) { - return arm_cmse_addr_range_nonsecure_read_write_ok(addr, size, - force_npriv, 1); + return arm_cmse_addr_range_nonsecure_read_write_ok(addr, size, force_npriv, 1); } #endif /* CONFIG_ARM_SECURE_FIRMWARE */ diff --git a/arch/arm/core/cortex_m/coredump.c b/arch/arm/core/cortex_m/coredump.c index c688c91d9819d..ddb539c4e34ef 100644 --- a/arch/arm/core/cortex_m/coredump.c +++ b/arch/arm/core/cortex_m/coredump.c @@ -7,31 +7,31 @@ #include #include -#define ARCH_HDR_VER 2 +#define ARCH_HDR_VER 2 uint32_t z_arm_coredump_fault_sp; struct arm_arch_block { struct { - uint32_t r0; - uint32_t r1; - uint32_t r2; - uint32_t r3; - uint32_t r12; - uint32_t lr; - uint32_t pc; - uint32_t xpsr; - uint32_t sp; + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t xpsr; + uint32_t sp; /* callee registers - optionally collected in V2 */ - uint32_t r4; - uint32_t r5; - uint32_t r6; - uint32_t r7; - uint32_t r8; - uint32_t r9; - uint32_t r10; - uint32_t r11; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; } r; } __packed; @@ -76,12 +76,12 @@ void arch_coredump_info_dump(const struct arch_esf *esf) #if defined(CONFIG_EXTRA_EXCEPTION_INFO) if (esf->extra_info.callee) { - arch_blk.r.r4 = esf->extra_info.callee->v1; - arch_blk.r.r5 = esf->extra_info.callee->v2; - arch_blk.r.r6 = esf->extra_info.callee->v3; - arch_blk.r.r7 = esf->extra_info.callee->v4; - arch_blk.r.r8 = esf->extra_info.callee->v5; - arch_blk.r.r9 = esf->extra_info.callee->v6; + arch_blk.r.r4 = esf->extra_info.callee->v1; + arch_blk.r.r5 = esf->extra_info.callee->v2; + arch_blk.r.r6 = esf->extra_info.callee->v3; + arch_blk.r.r7 = esf->extra_info.callee->v4; + arch_blk.r.r8 = esf->extra_info.callee->v5; + arch_blk.r.r9 = esf->extra_info.callee->v6; arch_blk.r.r10 = esf->extra_info.callee->v7; arch_blk.r.r11 = esf->extra_info.callee->v8; } diff --git a/arch/arm/core/cortex_m/cpu_idle.c b/arch/arm/core/cortex_m/cpu_idle.c index 5f373a88c9d55..8b3c416940f83 100644 --- a/arch/arm/core/cortex_m/cpu_idle.c +++ b/arch/arm/core/cortex_m/cpu_idle.c @@ -30,27 +30,31 @@ void z_arm_cpu_idle_init(void) #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) +#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) +#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) +#define SLEEP_IF_ALLOWED(wait_instr) \ + do { \ + __DSB(); \ + wait_instr(); \ + ON_EXIT_IDLE_HOOK; \ + } while (false) #endif #ifndef CONFIG_ARCH_HAS_CUSTOM_CPU_IDLE diff --git a/arch/arm/core/cortex_m/debug.c b/arch/arm/core/cortex_m/debug.c index 61fb681453507..47141d913dd14 100644 --- a/arch/arm/core/cortex_m/debug.c +++ b/arch/arm/core/cortex_m/debug.c @@ -35,7 +35,7 @@ bool z_arm_debug_monitor_event_error_check(void) printk("Null-pointer exception?\n"); } __ASSERT((DWT->FUNCTION0 & DWT_FUNCTION_MATCHED_Msk) == 0, - "MATCHED flag should have been cleared on read."); + "MATCHED flag should have been cleared on read."); return true; } @@ -55,8 +55,8 @@ bool z_arm_debug_monitor_event_error_check(void) * so we add a build assert that catches it. */ BUILD_ASSERT(!(CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE & - (CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1)), - "the size of the partition must be power of 2"); + (CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1)), + "the size of the partition must be power of 2"); int z_arm_debug_enable_null_pointer_detection(void) { @@ -81,20 +81,12 @@ int z_arm_debug_enable_null_pointer_detection(void) DWT->COMP0 = 0; DWT->COMP1 = CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1; - DWT->FUNCTION0 = - ((0x4 << DWT_FUNCTION_MATCH_Pos) & DWT_FUNCTION_MATCH_Msk) - | - ((0x1 << DWT_FUNCTION_ACTION_Pos) & DWT_FUNCTION_ACTION_Msk) - | - ((0x0 << DWT_FUNCTION_DATAVSIZE_Pos) & DWT_FUNCTION_DATAVSIZE_Msk) - ; - DWT->FUNCTION1 = - ((0x7 << DWT_FUNCTION_MATCH_Pos) & DWT_FUNCTION_MATCH_Msk) - | - ((0x1 << DWT_FUNCTION_ACTION_Pos) & DWT_FUNCTION_ACTION_Msk) - | - ((0x0 << DWT_FUNCTION_DATAVSIZE_Pos) & DWT_FUNCTION_DATAVSIZE_Msk) - ; + DWT->FUNCTION0 = ((0x4 << DWT_FUNCTION_MATCH_Pos) & DWT_FUNCTION_MATCH_Msk) | + ((0x1 << DWT_FUNCTION_ACTION_Pos) & DWT_FUNCTION_ACTION_Msk) | + ((0x0 << DWT_FUNCTION_DATAVSIZE_Pos) & DWT_FUNCTION_DATAVSIZE_Msk); + DWT->FUNCTION1 = ((0x7 << DWT_FUNCTION_MATCH_Pos) & DWT_FUNCTION_MATCH_Msk) | + ((0x1 << DWT_FUNCTION_ACTION_Pos) & DWT_FUNCTION_ACTION_Msk) | + ((0x0 << DWT_FUNCTION_DATAVSIZE_Pos) & DWT_FUNCTION_DATAVSIZE_Msk); #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) /* ASSERT that we have the comparator needed for the implementation */ @@ -106,13 +98,10 @@ int z_arm_debug_enable_null_pointer_detection(void) /* Use comparator 0, R/W access check */ DWT->COMP0 = 0; - DWT->FUNCTION0 = (0x7 << DWT_FUNCTION_FUNCTION_Pos) & - DWT_FUNCTION_FUNCTION_Msk; - + DWT->FUNCTION0 = (0x7 << DWT_FUNCTION_FUNCTION_Pos) & DWT_FUNCTION_FUNCTION_Msk; /* Set mask according to the desired size */ - DWT->MASK0 = 32 - __builtin_clzl( - CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1); + DWT->MASK0 = 32 - __builtin_clzl(CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1); #endif return 0; diff --git a/arch/arm/core/cortex_m/fault.c b/arch/arm/core/cortex_m/fault.c index 56d5be60f4cc0..27ce260dad535 100644 --- a/arch/arm/core/cortex_m/fault.c +++ b/arch/arm/core/cortex_m/fault.c @@ -22,7 +22,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #if defined(CONFIG_PRINTK) || defined(CONFIG_LOG) -#define PR_EXC(...) LOG_ERR(__VA_ARGS__) +#define PR_EXC(...) LOG_ERR(__VA_ARGS__) #define STORE_xFAR(reg_var, reg) uint32_t reg_var = (uint32_t)reg #else #define PR_EXC(...) @@ -36,8 +36,8 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #endif #if defined(CONFIG_ARM_MPU) && defined(CONFIG_CPU_HAS_NXP_SYSMPU) -#define EMN(edr) (((edr) & SYSMPU_EDR_EMN_MASK) >> SYSMPU_EDR_EMN_SHIFT) -#define EACD(edr) (((edr) & SYSMPU_EDR_EACD_MASK) >> SYSMPU_EDR_EACD_SHIFT) +#define EMN(edr) (((edr) & SYSMPU_EDR_EMN_MASK) >> SYSMPU_EDR_EMN_SHIFT) +#define EACD(edr) (((edr) & SYSMPU_EDR_EACD_MASK) >> SYSMPU_EDR_EACD_SHIFT) #endif /* Integrity signature for an ARMv8-M implementation */ @@ -54,15 +54,12 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) /* helpers to access memory/bus/usage faults */ -#define SCB_CFSR_MEMFAULTSR \ - (uint32_t)((SCB->CFSR & SCB_CFSR_MEMFAULTSR_Msk) \ - >> SCB_CFSR_MEMFAULTSR_Pos) -#define SCB_CFSR_BUSFAULTSR \ - (uint32_t)((SCB->CFSR & SCB_CFSR_BUSFAULTSR_Msk) \ - >> SCB_CFSR_BUSFAULTSR_Pos) -#define SCB_CFSR_USGFAULTSR \ - (uint32_t)((SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk) \ - >> SCB_CFSR_USGFAULTSR_Pos) +#define SCB_CFSR_MEMFAULTSR \ + (uint32_t)((SCB->CFSR & SCB_CFSR_MEMFAULTSR_Msk) >> SCB_CFSR_MEMFAULTSR_Pos) +#define SCB_CFSR_BUSFAULTSR \ + (uint32_t)((SCB->CFSR & SCB_CFSR_BUSFAULTSR_Msk) >> SCB_CFSR_BUSFAULTSR_Pos) +#define SCB_CFSR_USGFAULTSR \ + (uint32_t)((SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk) >> SCB_CFSR_USGFAULTSR_Pos) #endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */ /** @@ -103,8 +100,8 @@ static void fault_show(const struct arch_esf *esf, int fault) PR_EXC("Fault! EXC #%d", fault); #if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - PR_EXC("MMFSR: 0x%x, BFSR: 0x%x, UFSR: 0x%x", SCB_CFSR_MEMFAULTSR, - SCB_CFSR_BUSFAULTSR, SCB_CFSR_USGFAULTSR); + PR_EXC("MMFSR: 0x%x, BFSR: 0x%x, UFSR: 0x%x", SCB_CFSR_MEMFAULTSR, SCB_CFSR_BUSFAULTSR, + SCB_CFSR_USGFAULTSR); #if defined(CONFIG_ARM_SECURE_FIRMWARE) PR_EXC("SFSR: 0x%x", SAU->SFSR); #endif /* CONFIG_ARM_SECURE_FIRMWARE */ @@ -127,9 +124,7 @@ static void fault_show(const struct arch_esf *esf, int fault) #ifdef CONFIG_USERSPACE Z_EXC_DECLARE(z_arm_user_string_nlen); -static const struct z_exc_handle exceptions[] = { - Z_EXC_HANDLE(z_arm_user_string_nlen) -}; +static const struct z_exc_handle exceptions[] = {Z_EXC_HANDLE(z_arm_user_string_nlen)}; #endif /* Perform an assessment whether an MPU fault shall be @@ -146,12 +141,12 @@ static bool memory_fault_recoverable(struct arch_esf *esf, bool synchronous) uint32_t end = (uint32_t)exceptions[i].end & ~0x1U; #if defined(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT) - /* Non-synchronous exceptions (e.g. DebugMonitor) may have - * allowed PC to continue to the next instruction. - */ - end += (synchronous) ? 0x0 : 0x4; + /* Non-synchronous exceptions (e.g. DebugMonitor) may have + * allowed PC to continue to the next instruction. + */ + end += (synchronous) ? 0x0 : 0x4; #else - ARG_UNUSED(synchronous); + ARG_UNUSED(synchronous); #endif if (esf->basic.pc >= start && esf->basic.pc < end) { esf->basic.pc = (uint32_t)(exceptions[i].fixup); @@ -168,8 +163,7 @@ static bool memory_fault_recoverable(struct arch_esf *esf, bool synchronous) #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) #if defined(CONFIG_MPU_STACK_GUARD) || defined(CONFIG_USERSPACE) -uint32_t z_check_thread_stack_fail(const uint32_t fault_addr, - const uint32_t psp); +uint32_t z_check_thread_stack_fail(const uint32_t fault_addr, const uint32_t psp); #endif /* CONFIG_MPU_STACK_GUARD || defined(CONFIG_USERSPACE) */ /** @@ -180,8 +174,7 @@ uint32_t z_check_thread_stack_fail(const uint32_t fault_addr, * * @return error code to identify the fatal error reason */ -static uint32_t mem_manage_fault(struct arch_esf *esf, int from_hard_fault, - bool *recoverable) +static uint32_t mem_manage_fault(struct arch_esf *esf, int from_hard_fault, bool *recoverable) { uint32_t reason = K_ERR_ARM_MEM_GENERIC; uint32_t mmfar = -EINVAL; @@ -191,7 +184,7 @@ static uint32_t mem_manage_fault(struct arch_esf *esf, int from_hard_fault, if ((SCB->CFSR & SCB_CFSR_MSTKERR_Msk) != 0) { reason = K_ERR_ARM_MEM_STACKING; PR_FAULT_INFO(" Stacking error (context area might be" - " not valid)"); + " not valid)"); } if ((SCB->CFSR & SCB_CFSR_MUNSTKERR_Msk) != 0) { reason = K_ERR_ARM_MEM_UNSTACKING; @@ -226,8 +219,7 @@ static uint32_t mem_manage_fault(struct arch_esf *esf, int from_hard_fault, #if defined(CONFIG_ARMV7_M_ARMV8_M_FP) if ((SCB->CFSR & SCB_CFSR_MLSPERR_Msk) != 0) { reason = K_ERR_ARM_MEM_FP_LAZY_STATE_PRESERVATION; - PR_FAULT_INFO( - " Floating-point lazy state preservation error"); + PR_FAULT_INFO(" Floating-point lazy state preservation error"); } #endif /* CONFIG_ARMV7_M_ARMV8_M_FP */ @@ -244,8 +236,7 @@ static uint32_t mem_manage_fault(struct arch_esf *esf, int from_hard_fault, * Data Access Violation errors may or may not be caused by * thread stack overflows. */ - if ((SCB->CFSR & SCB_CFSR_MSTKERR_Msk) || - (SCB->CFSR & SCB_CFSR_DACCVIOL_Msk)) { + if ((SCB->CFSR & SCB_CFSR_MSTKERR_Msk) || (SCB->CFSR & SCB_CFSR_DACCVIOL_Msk)) { #if defined(CONFIG_MPU_STACK_GUARD) || defined(CONFIG_USERSPACE) /* MemManage Faults are always banked between security * states. Therefore, we can safely assume the fault @@ -265,8 +256,8 @@ static uint32_t mem_manage_fault(struct arch_esf *esf, int from_hard_fault, * handle the case of 'mmfar' holding the -EINVAL value. */ if (SCB->ICSR & SCB_ICSR_RETTOBASE_Msk) { - uint32_t min_stack_ptr = z_check_thread_stack_fail(mmfar, - ((uint32_t) &esf[0])); + uint32_t min_stack_ptr = + z_check_thread_stack_fail(mmfar, ((uint32_t)&esf[0])); if (min_stack_ptr) { /* When MemManage Stacking Error has occurred, @@ -299,14 +290,14 @@ static uint32_t mem_manage_fault(struct arch_esf *esf, int from_hard_fault, reason = K_ERR_STACK_CHK_FAIL; } else { __ASSERT(!(SCB->CFSR & SCB_CFSR_MSTKERR_Msk), - "Stacking error not a stack fail\n"); + "Stacking error not a stack fail\n"); } } #else - (void)mmfar; - __ASSERT(!(SCB->CFSR & SCB_CFSR_MSTKERR_Msk), - "Stacking or Data Access Violation error " - "without stack guard, user-mode or null-pointer detection\n"); + (void)mmfar; + __ASSERT(!(SCB->CFSR & SCB_CFSR_MSTKERR_Msk), + "Stacking or Data Access Violation error " + "without stack guard, user-mode or null-pointer detection\n"); #endif /* CONFIG_MPU_STACK_GUARD || CONFIG_USERSPACE */ } @@ -408,13 +399,10 @@ static int bus_fault(struct arch_esf *esf, int from_hard_fault, bool *recoverabl PR_FAULT_INFO(" NXP MPU error, port %d", i); PR_FAULT_INFO(" Mode: %s, %s Address: 0x%x", - edr & BIT(2) ? "Supervisor" : "User", - edr & BIT(1) ? "Data" : "Instruction", - ear); - PR_FAULT_INFO( - " Type: %s, Master: %d, Regions: 0x%x", - edr & BIT(0) ? "Write" : "Read", - EMN(edr), EACD(edr)); + edr & BIT(2) ? "Supervisor" : "User", + edr & BIT(1) ? "Data" : "Instruction", ear); + PR_FAULT_INFO(" Type: %s, Master: %d, Regions: 0x%x", + edr & BIT(0) ? "Write" : "Read", EMN(edr), EACD(edr)); /* When stack protection is enabled, we need to assess * if the memory violation error is a stack corruption. @@ -437,8 +425,7 @@ static int bus_fault(struct arch_esf *esf, int from_hard_fault, bool *recoverabl */ if (SCB->ICSR & SCB_ICSR_RETTOBASE_Msk) { uint32_t min_stack_ptr = - z_check_thread_stack_fail(ear, - ((uint32_t) &esf[0])); + z_check_thread_stack_fail(ear, ((uint32_t)&esf[0])); if (min_stack_ptr) { /* When BusFault Stacking Error @@ -468,16 +455,14 @@ static int bus_fault(struct arch_esf *esf, int from_hard_fault, bool *recoverabl */ __set_PSP(min_stack_ptr); - reason = - K_ERR_STACK_CHK_FAIL; + reason = K_ERR_STACK_CHK_FAIL; break; } } #else (void)ear; __ASSERT(0, - "Stacking error without stack guard" - "or User-mode support"); + "Stacking error without stack guard or User-mode support"); #endif /* CONFIG_MPU_STACK_GUARD || CONFIG_USERSPACE */ } } @@ -617,8 +602,7 @@ static void debug_monitor(struct arch_esf *esf, bool *recoverable) { *recoverable = false; - PR_FAULT_INFO( - "***** Debug monitor exception *****"); + PR_FAULT_INFO("***** Debug monitor exception *****"); #if defined(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT) if (!z_arm_debug_monitor_event_error_check()) { @@ -675,7 +659,7 @@ static inline bool z_arm_is_synchronous_svc(struct arch_esf *esf) #endif /* ARMV6_M_ARMV8_M_BASELINE && !ARMV8_M_BASELINE */ if (((fault_insn & 0xff00) == _SVC_OPCODE) && - ((fault_insn & 0x00ff) == _SVC_CALL_RUNTIME_EXCEPT)) { + ((fault_insn & 0x00ff) == _SVC_CALL_RUNTIME_EXCEPT)) { return true; } #undef _SVC_OPCODE @@ -759,13 +743,11 @@ static uint32_t hard_fault(struct arch_esf *esf, bool *recoverable) reason = secure_fault(esf); #endif /* CONFIG_ARM_SECURE_FIRMWARE */ } else { - __ASSERT(0, - "Fault escalation without FSR info"); + __ASSERT(0, "Fault escalation without FSR info"); } } else { - __ASSERT(0, - "HardFault without HFSR info" - " Shall never occur"); + __ASSERT(0, "HardFault without HFSR info" + " Shall never occur"); } #else #error Unknown ARM architecture @@ -786,8 +768,7 @@ static void reserved_exception(const struct arch_esf *esf, int fault) ARG_UNUSED(esf); PR_FAULT_INFO("***** %s %d) *****", - fault < 16 ? "Reserved Exception (" : "Spurious interrupt (IRQ ", - fault - 16); + fault < 16 ? "Reserved Exception (" : "Spurious interrupt (IRQ ", fault - 16); } /* Handler function for ARM fault conditions. */ @@ -802,7 +783,7 @@ static uint32_t fault_handle(struct arch_esf *esf, int fault, bool *recoverable) reason = hard_fault(esf, recoverable); break; #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - /* HardFault is raised for all fault conditions on ARMv6-M. */ + /* HardFault is raised for all fault conditions on ARMv6-M. */ #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) case 4: reason = mem_manage_fault(esf, 0, recoverable); @@ -860,7 +841,7 @@ static void secure_stack_dump(const struct arch_esf *secure_esf) uint32_t sec_ret_addr; #if defined(CONFIG_ARMV7_M_ARMV8_M_FP) if ((*top_of_sec_stack == INTEGRITY_SIGNATURE_STD) || - (*top_of_sec_stack == INTEGRITY_SIGNATURE_EXT)) { + (*top_of_sec_stack == INTEGRITY_SIGNATURE_EXT)) { #else if (*top_of_sec_stack == INTEGRITY_SIGNATURE) { #endif /* CONFIG_ARMV7_M_ARMV8_M_FP */ @@ -879,7 +860,6 @@ static void secure_stack_dump(const struct arch_esf *secure_esf) sec_ret_addr = *top_of_sec_stack; } PR_FAULT_INFO(" S instruction address: 0x%x", sec_ret_addr); - } #define SECURE_STACK_DUMP(esf) secure_stack_dump(esf) #else @@ -900,15 +880,14 @@ static void secure_stack_dump(const struct arch_esf *secure_esf) * @return ESF pointer on success, otherwise return NULL */ static inline struct arch_esf *get_esf(uint32_t msp, uint32_t psp, uint32_t exc_return, - bool *nested_exc) + bool *nested_exc) { bool alternative_state_exc = false; struct arch_esf *ptr_esf = NULL; *nested_exc = false; - if ((exc_return & EXC_RETURN_INDICATOR_PREFIX) != - EXC_RETURN_INDICATOR_PREFIX) { + if ((exc_return & EXC_RETURN_INDICATOR_PREFIX) != EXC_RETURN_INDICATOR_PREFIX) { /* Invalid EXC_RETURN value. This is a fatal error. */ return NULL; } @@ -988,8 +967,7 @@ static inline struct arch_esf *get_esf(uint32_t msp, uint32_t psp, uint32_t exc_ /* The processor has a single execution state. * We verify that the Thread mode is using PSP. */ - if ((exc_return & EXC_RETURN_MODE_THREAD) && - (!(exc_return & EXC_RETURN_SPSEL_PROCESS))) { + if ((exc_return & EXC_RETURN_MODE_THREAD) && (!(exc_return & EXC_RETURN_SPSEL_PROCESS))) { PR_EXC("SPSEL in thread mode does not indicate PSP"); return NULL; } @@ -998,7 +976,7 @@ static inline struct arch_esf *get_esf(uint32_t msp, uint32_t psp, uint32_t exc_ if (!alternative_state_exc) { if (exc_return & EXC_RETURN_MODE_THREAD) { /* Returning to thread mode */ - ptr_esf = (struct arch_esf *)psp; + ptr_esf = (struct arch_esf *)psp; } else { /* Returning to handler mode */ @@ -1041,8 +1019,7 @@ static inline struct arch_esf *get_esf(uint32_t msp, uint32_t psp, uint32_t exc_ * @param callee_regs Callee-saved registers (R4-R11, PSP) * */ -void z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return, - _callee_saved_t *callee_regs) +void z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return, _callee_saved_t *callee_regs) { uint32_t reason = K_ERR_CPU_EXCEPTION; int fault = SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk; @@ -1060,9 +1037,8 @@ void z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return, /* Retrieve the Exception Stack Frame (ESF) to be supplied * as argument to the remainder of the fault handling process. */ - esf = get_esf(msp, psp, exc_return, &nested_exc); - __ASSERT(esf != NULL, - "ESF could not be retrieved successfully. Shall never occur."); + esf = get_esf(msp, psp, exc_return, &nested_exc); + __ASSERT(esf != NULL, "ESF could not be retrieved successfully. Shall never occur."); z_arm_set_fault_sp(esf, exc_return); @@ -1080,11 +1056,8 @@ void z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return, * so we only copy the fields before those. */ memcpy(&esf_copy, esf, offsetof(struct arch_esf, extra_info)); - esf_copy.extra_info = (struct __extra_esf_info) { - .callee = callee_regs, - .exc_return = exc_return, - .msp = msp - }; + esf_copy.extra_info = (struct __extra_esf_info){ + .callee = callee_regs, .exc_return = exc_return, .msp = msp}; #endif /* CONFIG_EXTRA_EXCEPTION_INFO */ /* Overwrite stacked IPSR to mark a nested exception, diff --git a/arch/arm/core/cortex_m/fpu.c b/arch/arm/core/cortex_m/fpu.c index a9c964d14d1a7..b937d725c2834 100644 --- a/arch/arm/core/cortex_m/fpu.c +++ b/arch/arm/core/cortex_m/fpu.c @@ -23,11 +23,10 @@ void z_arm_save_fp_context(struct fpu_ctx_full *buffer) if (CONTROL & CONTROL_FPCA_Msk) { /* Store caller-saved and callee-saved FP registers. */ - __asm__ volatile( - "vstmia %0, {s0-s15}\n" - "vstmia %1, {s16-s31}\n" - :: "r" (buffer->caller_saved), "r" (buffer->callee_saved) : - ); + __asm__ volatile("vstmia %0, {s0-s15}\n" + "vstmia %1, {s16-s31}\n" ::"r"(buffer->caller_saved), + "r"(buffer->callee_saved) + :); buffer->fpscr = __get_FPSCR(); buffer->ctx_saved = true; @@ -55,11 +54,10 @@ void z_arm_restore_fp_context(const struct fpu_ctx_full *buffer) /* Restore FP state. */ __set_FPSCR(buffer->fpscr); - __asm__ volatile( - "vldmia %0, {s0-s15}\n" - "vldmia %1, {s16-s31}\n" - :: "r" (buffer->caller_saved), "r" (buffer->callee_saved) : - ); + __asm__ volatile("vldmia %0, {s0-s15}\n" + "vldmia %1, {s16-s31}\n" ::"r"(buffer->caller_saved), + "r"(buffer->callee_saved) + :); } #endif } diff --git a/arch/arm/core/cortex_m/irq_manage.c b/arch/arm/core/cortex_m/irq_manage.c index cc62386e8acad..522ea4e89dd83 100644 --- a/arch/arm/core/cortex_m/irq_manage.c +++ b/arch/arm/core/cortex_m/irq_manage.c @@ -28,7 +28,7 @@ extern void z_arm_reserved(void); -#define NUM_IRQS_PER_REG 32 +#define NUM_IRQS_PER_REG 32 #define REG_FROM_IRQ(irq) (irq / NUM_IRQS_PER_REG) #define BIT_FROM_IRQ(irq) (irq % NUM_IRQS_PER_REG) @@ -87,8 +87,7 @@ void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) */ __ASSERT(prio <= (BIT(NUM_IRQ_PRIO_BITS) - 1), "invalid priority %d for %d irq! values must be less than %lu\n", - prio - _IRQ_PRIO_OFFSET, irq, - BIT(NUM_IRQ_PRIO_BITS) - (_IRQ_PRIO_OFFSET)); + prio - _IRQ_PRIO_OFFSET, irq, BIT(NUM_IRQ_PRIO_BITS) - (_IRQ_PRIO_OFFSET)); NVIC_SetPriority((IRQn_Type)irq, prio); } @@ -141,7 +140,6 @@ void _arch_isr_direct_pm(void) #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - } #endif @@ -165,8 +163,7 @@ void _arch_isr_direct_pm(void) * * @return The resulting target state of the given IRQ */ -irq_target_state_t irq_target_state_set(unsigned int irq, - irq_target_state_t irq_target_state) +irq_target_state_t irq_target_state_set(unsigned int irq, irq_target_state_t irq_target_state) { uint32_t result; @@ -217,7 +214,7 @@ int irq_target_state_is_secure(unsigned int irq) * - Bits corresponding to un-implemented interrupts are RES0, so writes * will be ignored. * -*/ + */ void irq_target_state_set_all_non_secure(void) { int i; @@ -241,8 +238,8 @@ void irq_target_state_set_all_non_secure(void) #ifdef CONFIG_DYNAMIC_INTERRUPTS #ifdef CONFIG_GEN_ISR_TABLES int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, - void (*routine)(const void *parameter), - const void *parameter, uint32_t flags) + void (*routine)(const void *parameter), const void *parameter, + uint32_t flags) { z_isr_install(irq, routine, parameter); z_arm_irq_priority_set(irq, priority, flags); diff --git a/arch/arm/core/cortex_m/prep_c.c b/arch/arm/core/cortex_m/prep_c.c index ae59960584ce2..f6a22c3f0665f 100644 --- a/arch/arm/core/cortex_m/prep_c.c +++ b/arch/arm/core/cortex_m/prep_c.c @@ -37,8 +37,7 @@ #include #if defined(CONFIG_SW_VECTOR_RELAY) || defined(CONFIG_SW_VECTOR_RELAY_CLIENT) -Z_GENERIC_SECTION(.vt_pointer_section) __attribute__((used)) -void *_vector_table_pointer; +Z_GENERIC_SECTION(.vt_pointer_section) __attribute__((used)) void *_vector_table_pointer; #endif #ifdef CONFIG_CPU_CORTEX_M_HAS_VTOR @@ -64,8 +63,8 @@ static inline void relocate_vector_table(void) void __weak relocate_vector_table(void) { -#if defined(CONFIG_XIP) && (CONFIG_FLASH_BASE_ADDRESS != 0) || \ - !defined(CONFIG_XIP) && (CONFIG_SRAM_BASE_ADDRESS != 0) +#if defined(CONFIG_XIP) && (CONFIG_FLASH_BASE_ADDRESS != 0) || \ + !defined(CONFIG_XIP) && (CONFIG_SRAM_BASE_ADDRESS != 0) size_t vector_size = (size_t)_vector_end - (size_t)_vector_start; (void)memcpy(VECTOR_ADDRESS, _vector_start, vector_size); #elif defined(CONFIG_SW_VECTOR_RELAY) || defined(CONFIG_SW_VECTOR_RELAY_CLIENT) @@ -100,7 +99,7 @@ static inline void z_arm_floating_point_init(void) #else /* Privileged access only */ SCB->CPACR |= CPACR_CP10_PRIV_ACCESS | CPACR_CP11_PRIV_ACCESS; -#endif /* CONFIG_USERSPACE */ +#endif /* CONFIG_USERSPACE */ /* * Upon reset, the FPU Context Control Register is 0xC0000000 * (both Automatic and Lazy state preservation is enabled). @@ -170,7 +169,7 @@ static inline void z_arm_floating_point_init(void) * * If CONFIG_INIT_ARCH_HW_AT_BOOT is set, CONTROL is cleared at reset. */ -#if (!defined(CONFIG_FPU) || !defined(CONFIG_FPU_SHARING)) && \ +#if (!defined(CONFIG_FPU) || !defined(CONFIG_FPU_SHARING)) && \ (!defined(CONFIG_INIT_ARCH_HW_AT_BOOT)) __set_CONTROL(__get_CONTROL() & (~(CONTROL_FPCA_Msk))); diff --git a/arch/arm/core/cortex_m/scb.c b/arch/arm/core/cortex_m/scb.c index a511a8de9b1be..957c66dcc9f50 100644 --- a/arch/arm/core/cortex_m/scb.c +++ b/arch/arm/core/cortex_m/scb.c @@ -55,8 +55,7 @@ void z_arm_clear_arm_mpu_config(void) { int i; - int num_regions = - ((MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos); + int num_regions = ((MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos); for (i = 0; i < num_regions; i++) { ARM_MPU_ClrRegion(i); @@ -90,7 +89,7 @@ void z_arm_clear_arm_mpu_config(void) */ void z_arm_init_arch_hw_at_boot(void) { - /* Disable interrupts */ + /* Disable interrupts */ __disable_irq(); #if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) diff --git a/arch/arm/core/cortex_m/semihost.c b/arch/arm/core/cortex_m/semihost.c index 2a8c6d55a0515..dbf3e7ca94bec 100644 --- a/arch/arm/core/cortex_m/semihost.c +++ b/arch/arm/core/cortex_m/semihost.c @@ -9,11 +9,10 @@ long semihost_exec(enum semihost_instr instr, void *args) { - register unsigned int r0 __asm__ ("r0") = instr; - register void *r1 __asm__ ("r1") = args; - register int ret __asm__ ("r0"); + register unsigned int r0 __asm__("r0") = instr; + register void *r1 __asm__("r1") = args; + register int ret __asm__("r0"); - __asm__ __volatile__ ("bkpt 0xab" - : "=r" (ret) : "r" (r0), "r" (r1) : "memory"); + __asm__ __volatile__("bkpt 0xab" : "=r"(ret) : "r"(r0), "r"(r1) : "memory"); return ret; } diff --git a/arch/arm/core/cortex_m/thread.c b/arch/arm/core/cortex_m/thread.c index c88fd8e41a0fe..f5d93cad1b88d 100644 --- a/arch/arm/core/cortex_m/thread.c +++ b/arch/arm/core/cortex_m/thread.c @@ -22,15 +22,14 @@ #include #if (MPU_GUARD_ALIGN_AND_SIZE_FLOAT > MPU_GUARD_ALIGN_AND_SIZE) -#define FP_GUARD_EXTRA_SIZE (MPU_GUARD_ALIGN_AND_SIZE_FLOAT - \ - MPU_GUARD_ALIGN_AND_SIZE) +#define FP_GUARD_EXTRA_SIZE (MPU_GUARD_ALIGN_AND_SIZE_FLOAT - MPU_GUARD_ALIGN_AND_SIZE) #else -#define FP_GUARD_EXTRA_SIZE 0 +#define FP_GUARD_EXTRA_SIZE 0 #endif #ifndef EXC_RETURN_FTYPE /* bit [4] allocate stack for floating-point context: 0=done 1=skipped */ -#define EXC_RETURN_FTYPE (0x00000010UL) +#define EXC_RETURN_FTYPE (0x00000010UL) #endif /* Default last octet of EXC_RETURN, for threads that have not run yet. @@ -58,9 +57,8 @@ K_THREAD_STACK_DECLARE(z_main_stack, CONFIG_MAIN_STACK_SIZE); * addresses, we have to unset it manually before storing it in the 'pc' field * of the ESF. */ -void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, - char *stack_ptr, k_thread_entry_t entry, - void *p1, void *p2, void *p3) +void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, char *stack_ptr, + k_thread_entry_t entry, void *p1, void *p2, void *p3) { struct __basic_sf *iframe; @@ -105,8 +103,7 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, iframe->a3 = (uint32_t)p2; iframe->a4 = (uint32_t)p3; - iframe->xpsr = - 0x01000000UL; /* clear all, thumb bit is 1, even if RO */ + iframe->xpsr = 0x01000000UL; /* clear all, thumb bit is 1, even if RO */ thread->callee_saved.psp = (uint32_t)iframe; thread->arch.basepri = 0; @@ -131,52 +128,42 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, */ } -#if defined(CONFIG_MPU_STACK_GUARD) && defined(CONFIG_FPU) \ - && defined(CONFIG_FPU_SHARING) +#if defined(CONFIG_MPU_STACK_GUARD) && defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) -static inline void z_arm_thread_stack_info_adjust(struct k_thread *thread, - bool use_large_guard) +static inline void z_arm_thread_stack_info_adjust(struct k_thread *thread, bool use_large_guard) { if (use_large_guard) { /* Switch to use a large MPU guard if not already. */ - if ((thread->arch.mode & - Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) == 0) { + if ((thread->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) == 0) { /* Default guard size is used. Update required. */ thread->arch.mode |= Z_ARM_MODE_MPU_GUARD_FLOAT_Msk; #if defined(CONFIG_USERSPACE) if (thread->arch.priv_stack_start) { /* User thread */ - thread->arch.priv_stack_start += - FP_GUARD_EXTRA_SIZE; + thread->arch.priv_stack_start += FP_GUARD_EXTRA_SIZE; } else #endif /* CONFIG_USERSPACE */ { /* Privileged thread */ - thread->stack_info.start += - FP_GUARD_EXTRA_SIZE; - thread->stack_info.size -= - FP_GUARD_EXTRA_SIZE; + thread->stack_info.start += FP_GUARD_EXTRA_SIZE; + thread->stack_info.size -= FP_GUARD_EXTRA_SIZE; } } } else { /* Switch to use the default MPU guard size if not already. */ - if ((thread->arch.mode & - Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) { + if ((thread->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) { /* Large guard size is used. Update required. */ thread->arch.mode &= ~Z_ARM_MODE_MPU_GUARD_FLOAT_Msk; #if defined(CONFIG_USERSPACE) if (thread->arch.priv_stack_start) { /* User thread */ - thread->arch.priv_stack_start -= - FP_GUARD_EXTRA_SIZE; + thread->arch.priv_stack_start -= FP_GUARD_EXTRA_SIZE; } else #endif /* CONFIG_USERSPACE */ { /* Privileged thread */ - thread->stack_info.start -= - FP_GUARD_EXTRA_SIZE; - thread->stack_info.size += - FP_GUARD_EXTRA_SIZE; + thread->stack_info.start -= FP_GUARD_EXTRA_SIZE; + thread->stack_info.size += FP_GUARD_EXTRA_SIZE; } } } @@ -190,7 +177,7 @@ static inline void z_arm_thread_stack_info_adjust(struct k_thread *thread, uint32_t z_arm_mpu_stack_guard_and_fpu_adjust(struct k_thread *thread) { if (((thread->base.user_options & K_FP_REGS) != 0) || - ((thread->arch.mode_exc_return & EXC_RETURN_FTYPE) == 0)) { + ((thread->arch.mode_exc_return & EXC_RETURN_FTYPE) == 0)) { /* The thread has been pre-tagged (at creation or later) with * K_FP_REGS, i.e. it is expected to be using the FPU registers * (if not already). Activate lazy stacking and program a large @@ -226,13 +213,11 @@ uint32_t z_arm_mpu_stack_guard_and_fpu_adjust(struct k_thread *thread) #endif #ifdef CONFIG_USERSPACE -FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, - void *p1, void *p2, void *p3) +FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, void *p1, void *p2, void *p3) { /* Set up privileged stack before entering user mode */ - _current->arch.priv_stack_start = - (uint32_t)z_priv_stack_find(_current->stack_obj); + _current->arch.priv_stack_start = (uint32_t)z_priv_stack_find(_current->stack_obj); #if defined(CONFIG_MPU_STACK_GUARD) #if defined(CONFIG_THREAD_STACK_INFO) /* We're dropping to user mode which means the guard area is no @@ -256,21 +241,19 @@ FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, */ #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) _current->arch.priv_stack_start += - ((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) ? - MPU_GUARD_ALIGN_AND_SIZE_FLOAT : MPU_GUARD_ALIGN_AND_SIZE; + ((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) + ? MPU_GUARD_ALIGN_AND_SIZE_FLOAT + : MPU_GUARD_ALIGN_AND_SIZE; #else _current->arch.priv_stack_start += MPU_GUARD_ALIGN_AND_SIZE; #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ #endif /* CONFIG_MPU_STACK_GUARD */ - z_arm_userspace_enter(user_entry, p1, p2, p3, - (uint32_t)_current->stack_info.start, - _current->stack_info.size - - _current->stack_info.delta); + z_arm_userspace_enter(user_entry, p1, p2, p3, (uint32_t)_current->stack_info.start, + _current->stack_info.size - _current->stack_info.delta); CODE_UNREACHABLE; } - bool z_arm_thread_is_in_user_mode(void) { uint32_t value; @@ -311,14 +294,12 @@ void configure_builtin_stack_guard(struct k_thread *thread) * than the default thread stack (ensured by design). */ uint32_t guard_start = - ((thread->arch.priv_stack_start) && - (__get_PSP() >= thread->arch.priv_stack_start)) ? - (uint32_t)thread->arch.priv_stack_start : - (uint32_t)thread->stack_obj; + ((thread->arch.priv_stack_start) && (__get_PSP() >= thread->arch.priv_stack_start)) + ? (uint32_t)thread->arch.priv_stack_start + : (uint32_t)thread->stack_obj; __ASSERT(thread->stack_info.start == ((uint32_t)thread->stack_obj), - "stack_info.start does not point to the start of the" - "thread allocated area."); + "stack_info.start does not point to the start of the thread allocated area."); #else uint32_t guard_start = thread->stack_info.start; #endif @@ -332,13 +313,11 @@ void configure_builtin_stack_guard(struct k_thread *thread) #if defined(CONFIG_MPU_STACK_GUARD) || defined(CONFIG_USERSPACE) -#define IS_MPU_GUARD_VIOLATION(guard_start, guard_len, fault_addr, stack_ptr) \ - ((fault_addr != -EINVAL) ? \ - ((fault_addr >= guard_start) && \ - (fault_addr < (guard_start + guard_len)) && \ - (stack_ptr < (guard_start + guard_len))) \ - : \ - (stack_ptr < (guard_start + guard_len))) +#define IS_MPU_GUARD_VIOLATION(guard_start, guard_len, fault_addr, stack_ptr) \ + ((fault_addr != -EINVAL) \ + ? ((fault_addr >= guard_start) && (fault_addr < (guard_start + guard_len)) && \ + (stack_ptr < (guard_start + guard_len))) \ + : (stack_ptr < (guard_start + guard_len))) /** * @brief Assess occurrence of current thread's stack corruption @@ -386,11 +365,10 @@ uint32_t z_check_thread_stack_fail(const uint32_t fault_addr, const uint32_t psp } #endif -#if (defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)) && \ - defined(CONFIG_MPU_STACK_GUARD) - uint32_t guard_len = - ((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) ? - MPU_GUARD_ALIGN_AND_SIZE_FLOAT : MPU_GUARD_ALIGN_AND_SIZE; +#if (defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)) && defined(CONFIG_MPU_STACK_GUARD) + uint32_t guard_len = ((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) + ? MPU_GUARD_ALIGN_AND_SIZE_FLOAT + : MPU_GUARD_ALIGN_AND_SIZE; #else /* If MPU_STACK_GUARD is not enabled, the guard length is * effectively zero. Stack overflows may be detected only @@ -404,10 +382,8 @@ uint32_t z_check_thread_stack_fail(const uint32_t fault_addr, const uint32_t psp /* User thread */ if (z_arm_thread_is_in_user_mode() == false) { /* User thread in privilege mode */ - if (IS_MPU_GUARD_VIOLATION( - thread->arch.priv_stack_start - guard_len, - guard_len, - fault_addr, psp)) { + if (IS_MPU_GUARD_VIOLATION(thread->arch.priv_stack_start - guard_len, + guard_len, fault_addr, psp)) { /* Thread's privilege stack corruption */ return thread->arch.priv_stack_start; } @@ -419,26 +395,21 @@ uint32_t z_check_thread_stack_fail(const uint32_t fault_addr, const uint32_t psp } } else { /* Supervisor thread */ - if (IS_MPU_GUARD_VIOLATION(thread->stack_info.start - - guard_len, - guard_len, - fault_addr, psp)) { + if (IS_MPU_GUARD_VIOLATION(thread->stack_info.start - guard_len, guard_len, + fault_addr, psp)) { /* Supervisor thread stack corruption */ return thread->stack_info.start; } } #else /* CONFIG_USERSPACE */ #if defined(CONFIG_MULTITHREADING) - if (IS_MPU_GUARD_VIOLATION(thread->stack_info.start - guard_len, - guard_len, - fault_addr, psp)) { + if (IS_MPU_GUARD_VIOLATION(thread->stack_info.start - guard_len, guard_len, fault_addr, + psp)) { /* Thread stack corruption */ return thread->stack_info.start; } #else - if (IS_MPU_GUARD_VIOLATION((uint32_t)z_main_stack, - guard_len, - fault_addr, psp)) { + if (IS_MPU_GUARD_VIOLATION((uint32_t)z_main_stack, guard_len, fault_addr, psp)) { /* Thread stack corruption */ return (uint32_t)K_THREAD_STACK_BUFFER(z_main_stack); } @@ -572,23 +543,23 @@ void arch_switch_to_main_thread(struct k_thread *main_thread, char *stack_ptr, * 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 r4, %0\n" /* force _main to be stored in a register */ - "msr PSP, %1\n" /* __set_PSP(stack_ptr) */ - - "movs 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) */ - "movs r1, #0\n" - "movs r2, #0\n" - "movs 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", "ip", "lr", "memory"); + __asm__ volatile("mov r4, %0\n" /* force _main to be stored in a register */ + "msr PSP, %1\n" /* __set_PSP(stack_ptr) */ + + "movs 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) */ + "movs r1, #0\n" + "movs r2, #0\n" + "movs r3, #0\n" + "ldr r4, =z_thread_entry\n" + /* We don’t intend to return, so there is no need to link. */ + "bx r4\n" + : + : "r"(_main), "r"(stack_ptr) + : "r0", "r1", "r2", "r3", "r4", "ip", "lr", "memory"); CODE_UNREACHABLE; } @@ -597,7 +568,7 @@ __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 */ + __enable_irq(); /* alters PRIMASK */ #endif arch_irq_unlock(key); } @@ -609,14 +580,13 @@ __used unsigned int arch_irq_lock_outlined(void) #if !defined(CONFIG_MULTITHREADING) -FUNC_NORETURN void z_arm_switch_to_main_no_multithreading( - k_thread_entry_t main_entry, void *p1, void *p2, void *p3) +FUNC_NORETURN void z_arm_switch_to_main_no_multithreading(k_thread_entry_t main_entry, void *p1, + void *p2, void *p3) { z_arm_prepare_switch_to_main(); /* Set PSP to the highest address of the main stack. */ - char *psp = K_THREAD_STACK_BUFFER(z_main_stack) + - K_THREAD_STACK_SIZEOF(z_main_stack); + char *psp = K_THREAD_STACK_BUFFER(z_main_stack) + K_THREAD_STACK_SIZEOF(z_main_stack); #if defined(CONFIG_BUILTIN_STACK_GUARD) char *psplim = (K_THREAD_STACK_BUFFER(z_main_stack)); @@ -636,31 +606,31 @@ FUNC_NORETURN void z_arm_switch_to_main_no_multithreading( * with the thread entry process. */ - __asm__ volatile ( + __asm__ volatile( #ifdef CONFIG_BUILTIN_STACK_GUARD - "msr PSPLIM, %[_psplim]\n" /* __set_PSPLIM(_psplim) */ + "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); */ - : - : [_p1]"r" (p1), [_p2]"r" (p2), [_p3]"r" (p3), - [_psp]"r" (psp), [_main_entry]"r" (main_entry) + "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); */ + : + : [_p1] "r"(p1), [_p2] "r"(p2), [_p3] "r"(p3), [_psp] "r"(psp), + [_main_entry] "r"(main_entry) #ifdef CONFIG_BUILTIN_STACK_GUARD - , [_psplim]"r" (psplim) + , + [_psplim] "r"(psplim) #endif - : "r0", "r1", "r2", "ip", "lr" - ); + : "r0", "r1", "r2", "ip", "lr"); CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ } diff --git a/arch/arm/core/cortex_m/timing.c b/arch/arm/core/cortex_m/timing.c index 6cb157552ace2..2ce7f64552ba5 100644 --- a/arch/arm/core/cortex_m/timing.c +++ b/arch/arm/core/cortex_m/timing.c @@ -73,7 +73,6 @@ static inline uint64_t z_arm_dwt_freq_get(void) } while ((dcyc == 0) || (ddwt == 0)); dwt_frequency = (cyc_freq * ddwt) / dcyc; - } return dwt_frequency; #endif /* CONFIG_SOC_FAMILY_NORDIC_NRF */ @@ -100,8 +99,7 @@ timing_t arch_timing_counter_get(void) return (timing_t)z_arm_dwt_get_cycles(); } -uint64_t arch_timing_cycles_get(volatile timing_t *const start, - volatile timing_t *const end) +uint64_t arch_timing_cycles_get(volatile timing_t *const start, volatile timing_t *const end) { return ((uint32_t)*end - (uint32_t)*start); } diff --git a/arch/arm/include/cortex_m/cmse.h b/arch/arm/include/cortex_m/cmse.h index ff5e5120d8d39..ca997220dbd16 100644 --- a/arch/arm/include/cortex_m/cmse.h +++ b/arch/arm/include/cortex_m/cmse.h @@ -139,7 +139,7 @@ int arm_cmse_addr_range_readwrite_ok(uint32_t addr, uint32_t size, int force_npr * where typeof is used instead of __typeof__) */ #ifndef typeof -#define typeof __typeof__ +#define typeof __typeof__ #endif /** @@ -157,8 +157,7 @@ int arm_cmse_addr_range_readwrite_ok(uint32_t addr, uint32_t size, int force_npr * * @return p_obj if object is readable, NULL otherwise. */ -#define ARM_CMSE_OBJECT_READ_OK(p_obj) \ - cmse_check_pointed_object(p_obj, CMSE_MPU_READ) +#define ARM_CMSE_OBJECT_READ_OK(p_obj) cmse_check_pointed_object(p_obj, CMSE_MPU_READ) /** * @brief Read accessibility of an object (nPRIV mode) @@ -175,7 +174,7 @@ int arm_cmse_addr_range_readwrite_ok(uint32_t addr, uint32_t size, int force_npr * * @return p_obj if object is readable, NULL otherwise. */ -#define ARM_CMSE_OBJECT_UNPRIV_READ_OK(p_obj) \ +#define ARM_CMSE_OBJECT_UNPRIV_READ_OK(p_obj) \ cmse_check_pointed_object(p_obj, CMSE_MPU_UNPRIV | CMSE_MPU_READ) /** @@ -193,8 +192,7 @@ int arm_cmse_addr_range_readwrite_ok(uint32_t addr, uint32_t size, int force_npr * * @return p_obj if object is Read and Writable, NULL otherwise. */ -#define ARM_CMSE_OBJECT_READWRITE_OK(p_obj) \ - cmse_check_pointed_object(p_obj, CMSE_MPU_READWRITE) +#define ARM_CMSE_OBJECT_READWRITE_OK(p_obj) cmse_check_pointed_object(p_obj, CMSE_MPU_READWRITE) /** * @brief Read and Write accessibility of an object (nPRIV mode) @@ -211,7 +209,7 @@ int arm_cmse_addr_range_readwrite_ok(uint32_t addr, uint32_t size, int force_npr * * @return p_obj if object is Read and Writable, NULL otherwise. */ -#define ARM_CMSE_OBJECT_UNPRIV_READWRITE_OK(p_obj) \ +#define ARM_CMSE_OBJECT_UNPRIV_READWRITE_OK(p_obj) \ cmse_check_pointed_object(p_obj, CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE) #if defined(CONFIG_ARM_SECURE_FIRMWARE) @@ -231,7 +229,7 @@ int arm_cmse_addr_range_readwrite_ok(uint32_t addr, uint32_t size, int force_npr * @param addr The address for which the MPU region is requested * * @return a valid MPU region number or -EINVAL - */ + */ int arm_cmse_mpu_nonsecure_region_get(uint32_t addr); /** @@ -249,7 +247,7 @@ int arm_cmse_mpu_nonsecure_region_get(uint32_t addr); * @param addr The address for which the SAU region is requested * * @return a valid SAU region number or -EINVAL - */ + */ int arm_cmse_sau_region_get(uint32_t addr); /** @@ -267,7 +265,7 @@ int arm_cmse_sau_region_get(uint32_t addr); * @param addr The address for which the IDAU region is requested * * @return a valid IDAU region number or -EINVAL - */ + */ int arm_cmse_idau_region_get(uint32_t addr); /** @@ -342,8 +340,7 @@ int arm_cmse_addr_nonsecure_readwrite_ok(uint32_t addr, int force_npriv); * * @return 1 if address range is readable, 0 otherwise. */ -int arm_cmse_addr_range_nonsecure_read_ok(uint32_t addr, uint32_t size, - int force_npriv); +int arm_cmse_addr_range_nonsecure_read_ok(uint32_t addr, uint32_t size, int force_npriv); /** * @brief Non-Secure Read and Write accessibility of an address range @@ -365,8 +362,7 @@ int arm_cmse_addr_range_nonsecure_read_ok(uint32_t addr, uint32_t size, * * @return 1 if address range is readable, 0 otherwise. */ -int arm_cmse_addr_range_nonsecure_readwrite_ok(uint32_t addr, uint32_t size, - int force_npriv); +int arm_cmse_addr_range_nonsecure_readwrite_ok(uint32_t addr, uint32_t size, int force_npriv); /** * @brief Non-Secure Read accessibility of an object @@ -383,7 +379,7 @@ int arm_cmse_addr_range_nonsecure_readwrite_ok(uint32_t addr, uint32_t size, * * @return p_obj if object is readable from Non-Secure state, NULL otherwise. */ -#define ARM_CMSE_OBJECT_NONSECURE_READ_OK(p_obj) \ +#define ARM_CMSE_OBJECT_NONSECURE_READ_OK(p_obj) \ cmse_check_pointed_object(p_obj, CMSE_NONSECURE | CMSE_MPU_READ) /** @@ -401,9 +397,8 @@ int arm_cmse_addr_range_nonsecure_readwrite_ok(uint32_t addr, uint32_t size, * * @return p_obj if object is readable from Non-Secure state, NULL otherwise. */ -#define ARM_CMSE_OBJECT_NONSECURE_UNPRIV_READ_OK(p_obj) \ - cmse_check_pointed_object(p_obj, \ - CMSE_NONSECURE | CMSE_MPU_UNPRIV | CMSE_MPU_READ) +#define ARM_CMSE_OBJECT_NONSECURE_UNPRIV_READ_OK(p_obj) \ + cmse_check_pointed_object(p_obj, CMSE_NONSECURE | CMSE_MPU_UNPRIV | CMSE_MPU_READ) /** * @brief Non-Secure Read and Write accessibility of an object @@ -420,7 +415,7 @@ int arm_cmse_addr_range_nonsecure_readwrite_ok(uint32_t addr, uint32_t size, * * @return p_obj if object is Non-Secure Read and Writable, NULL otherwise. */ -#define ARM_CMSE_OBJECT_NONSECURE_READWRITE_OK(p_obj) \ +#define ARM_CMSE_OBJECT_NONSECURE_READWRITE_OK(p_obj) \ cmse_check_pointed_object(p_obj, CMSE_NONSECURE | CMSE_MPU_READWRITE) /** @@ -438,9 +433,8 @@ int arm_cmse_addr_range_nonsecure_readwrite_ok(uint32_t addr, uint32_t size, * * @return p_obj if object is Non-Secure Read and Writable, NULL otherwise. */ -#define ARM_CMSE_OBJECT_NON_SECURE_UNPRIV_READWRITE_OK(p_obj) \ - cmse_check_pointed_object(p_obj, \ - CMSE_NONSECURE | CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE) +#define ARM_CMSE_OBJECT_NON_SECURE_UNPRIV_READWRITE_OK(p_obj) \ + cmse_check_pointed_object(p_obj, CMSE_NONSECURE | CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE) #endif /* CONFIG_ARM_SECURE_FIRMWARE */ diff --git a/arch/arm/include/cortex_m/dwt.h b/arch/arm/include/cortex_m/dwt.h index ed0df44dfde56..947b35dca92e8 100644 --- a/arch/arm/include/cortex_m/dwt.h +++ b/arch/arm/include/cortex_m/dwt.h @@ -64,7 +64,7 @@ static inline void dwt_access(bool ena) } } } -#else /* CONFIG_CPU_CORTEX_M7 */ +#else /* CONFIG_CPU_CORTEX_M7 */ ARG_UNUSED(ena); #endif /* CONFIG_CPU_CORTEX_M7 */ } @@ -103,9 +103,8 @@ static inline int z_arm_dwt_init_cycle_counter(void) /* Assert that the cycle counter is indeed implemented. * The field is called NOCYCCNT. So 1 means there is no cycle counter. */ - __ASSERT((DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk) == 0, - "DWT implements no cycle counter. " - "Cannot be used for cycle counting\n"); + __ASSERT((DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk) == 0, "DWT implements no cycle counter. " + "Cannot be used for cycle counting\n"); return 0; } @@ -148,7 +147,7 @@ static inline void z_arm_dwt_enable_debug_monitor(void) * assert that the CPU is in normal mode. */ __ASSERT((CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 0, - "Cannot enable DBM when CPU is in Debug mode\n"); + "Cannot enable DBM when CPU is in Debug mode\n"); #if defined(CONFIG_ARMV8_M_SE) && !defined(CONFIG_ARM_NONSECURE_FIRMWARE) /* @@ -158,8 +157,7 @@ static inline void z_arm_dwt_enable_debug_monitor(void) * when enabling the DebugMonitor exception, assert that * it is not targeting the Non Secure domain. */ - __ASSERT((CoreDebug->DEMCR & DCB_DEMCR_SDME_Msk) != 0, - "DebugMonitor targets Non-Secure\n"); + __ASSERT((CoreDebug->DEMCR & DCB_DEMCR_SDME_Msk) != 0, "DebugMonitor targets Non-Secure\n"); #endif /* The DebugMonitor handler priority is set already diff --git a/arch/arm/include/cortex_m/exception.h b/arch/arm/include/cortex_m/exception.h index c021d59d76411..0800a16436f16 100644 --- a/arch/arm/include/cortex_m/exception.h +++ b/arch/arm/include/cortex_m/exception.h @@ -37,7 +37,7 @@ extern volatile irq_offload_routine_t offload_routine; /* Writes to the AIRCR must be accompanied by a write of the value 0x05FA * to the Vector Key field, otherwise the writes are ignored. */ -#define AIRCR_VECT_KEY_PERMIT_WRITE 0x05FAUL +#define AIRCR_VECT_KEY_PERMIT_WRITE 0x05FAUL /* Exception Return (EXC_RETURN) is provided in LR upon exception entry. * It is used to perform an exception return and to detect possible state @@ -47,45 +47,44 @@ extern volatile irq_offload_routine_t offload_routine; /* Prefix. Indicates that this is an EXC_RETURN value. * This field reads as 0b11111111. */ -#define EXC_RETURN_INDICATOR_PREFIX (0xFF << 24) +#define EXC_RETURN_INDICATOR_PREFIX (0xFF << 24) /* bit[0]: Exception Secure. The security domain the exception was taken to. */ -#define EXC_RETURN_EXCEPTION_SECURE_Pos 0 -#define EXC_RETURN_EXCEPTION_SECURE_Msk \ - BIT(EXC_RETURN_EXCEPTION_SECURE_Pos) +#define EXC_RETURN_EXCEPTION_SECURE_Pos 0 +#define EXC_RETURN_EXCEPTION_SECURE_Msk BIT(EXC_RETURN_EXCEPTION_SECURE_Pos) #define EXC_RETURN_EXCEPTION_SECURE_Non_Secure 0 -#define EXC_RETURN_EXCEPTION_SECURE_Secure EXC_RETURN_EXCEPTION_SECURE_Msk +#define EXC_RETURN_EXCEPTION_SECURE_Secure EXC_RETURN_EXCEPTION_SECURE_Msk /* bit[2]: Stack Pointer selection. */ -#define EXC_RETURN_SPSEL_Pos 2 -#define EXC_RETURN_SPSEL_Msk BIT(EXC_RETURN_SPSEL_Pos) -#define EXC_RETURN_SPSEL_MAIN 0 -#define EXC_RETURN_SPSEL_PROCESS EXC_RETURN_SPSEL_Msk +#define EXC_RETURN_SPSEL_Pos 2 +#define EXC_RETURN_SPSEL_Msk BIT(EXC_RETURN_SPSEL_Pos) +#define EXC_RETURN_SPSEL_MAIN 0 +#define EXC_RETURN_SPSEL_PROCESS EXC_RETURN_SPSEL_Msk /* bit[3]: Mode. Indicates the Mode that was stacked from. */ -#define EXC_RETURN_MODE_Pos 3 -#define EXC_RETURN_MODE_Msk BIT(EXC_RETURN_MODE_Pos) -#define EXC_RETURN_MODE_HANDLER 0 -#define EXC_RETURN_MODE_THREAD EXC_RETURN_MODE_Msk +#define EXC_RETURN_MODE_Pos 3 +#define EXC_RETURN_MODE_Msk BIT(EXC_RETURN_MODE_Pos) +#define EXC_RETURN_MODE_HANDLER 0 +#define EXC_RETURN_MODE_THREAD EXC_RETURN_MODE_Msk /* bit[4]: Stack frame type. Indicates whether the stack frame is a standard * integer only stack frame or an extended floating-point stack frame. */ -#define EXC_RETURN_STACK_FRAME_TYPE_Pos 4 -#define EXC_RETURN_STACK_FRAME_TYPE_Msk BIT(EXC_RETURN_STACK_FRAME_TYPE_Pos) -#define EXC_RETURN_STACK_FRAME_TYPE_EXTENDED 0 -#define EXC_RETURN_STACK_FRAME_TYPE_STANDARD EXC_RETURN_STACK_FRAME_TYPE_Msk +#define EXC_RETURN_STACK_FRAME_TYPE_Pos 4 +#define EXC_RETURN_STACK_FRAME_TYPE_Msk BIT(EXC_RETURN_STACK_FRAME_TYPE_Pos) +#define EXC_RETURN_STACK_FRAME_TYPE_EXTENDED 0 +#define EXC_RETURN_STACK_FRAME_TYPE_STANDARD EXC_RETURN_STACK_FRAME_TYPE_Msk /* bit[5]: Default callee register stacking. Indicates whether the default * stacking rules apply, or whether the callee registers are already on the * stack. */ -#define EXC_RETURN_CALLEE_STACK_Pos 5 -#define EXC_RETURN_CALLEE_STACK_Msk BIT(EXC_RETURN_CALLEE_STACK_Pos) -#define EXC_RETURN_CALLEE_STACK_SKIPPED 0 -#define EXC_RETURN_CALLEE_STACK_DEFAULT EXC_RETURN_CALLEE_STACK_Msk +#define EXC_RETURN_CALLEE_STACK_Pos 5 +#define EXC_RETURN_CALLEE_STACK_Msk BIT(EXC_RETURN_CALLEE_STACK_Pos) +#define EXC_RETURN_CALLEE_STACK_SKIPPED 0 +#define EXC_RETURN_CALLEE_STACK_DEFAULT EXC_RETURN_CALLEE_STACK_Msk /* bit[6]: Secure or Non-secure stack. Indicates whether a Secure or * Non-secure stack is used to restore stack frame on exception return. */ -#define EXC_RETURN_RETURN_STACK_Pos 6 -#define EXC_RETURN_RETURN_STACK_Msk BIT(EXC_RETURN_RETURN_STACK_Pos) -#define EXC_RETURN_RETURN_STACK_Non_Secure 0 -#define EXC_RETURN_RETURN_STACK_Secure EXC_RETURN_RETURN_STACK_Msk +#define EXC_RETURN_RETURN_STACK_Pos 6 +#define EXC_RETURN_RETURN_STACK_Msk BIT(EXC_RETURN_RETURN_STACK_Pos) +#define EXC_RETURN_RETURN_STACK_Non_Secure 0 +#define EXC_RETURN_RETURN_STACK_Secure EXC_RETURN_RETURN_STACK_Msk /* * The current executing vector is found in the IPSR register. All @@ -170,8 +169,8 @@ static ALWAYS_INLINE void z_arm_exc_setup(void) #endif /* CONFIG_ARM_SECURE_FIRMWARE */ /* Enable Usage, Mem, & Bus Faults */ - SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk | - SCB_SHCSR_BUSFAULTENA_Msk; + SCB->SHCSR |= + SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk; #if defined(CONFIG_ARM_SECURE_FIRMWARE) /* Enable Secure Fault */ SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk; @@ -180,25 +179,21 @@ static ALWAYS_INLINE void z_arm_exc_setup(void) #endif /* CONFIG_ARM_SECURE_FIRMWARE */ #endif /* CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS */ -#if defined(CONFIG_ARM_SECURE_FIRMWARE) && \ - !defined(CONFIG_ARM_SECURE_BUSFAULT_HARDFAULT_NMI) +#if defined(CONFIG_ARM_SECURE_FIRMWARE) && !defined(CONFIG_ARM_SECURE_BUSFAULT_HARDFAULT_NMI) /* Set NMI, Hard, and Bus Faults as Non-Secure. * NMI and Bus Faults targeting the Secure state will * escalate to a SecureFault or SecureHardFault. */ SCB->AIRCR = - (SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk))) - | SCB_AIRCR_BFHFNMINS_Msk - | ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) & - SCB_AIRCR_VECTKEY_Msk); + (SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk))) | SCB_AIRCR_BFHFNMINS_Msk | + ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) & SCB_AIRCR_VECTKEY_Msk); /* Note: Fault conditions that would generate a SecureFault * in a PE with the Main Extension instead generate a * SecureHardFault in a PE without the Main Extension. */ #endif /* ARM_SECURE_FIRMWARE && !ARM_SECURE_BUSFAULT_HARDFAULT_NMI */ -#if defined(CONFIG_CPU_CORTEX_M_HAS_SYSTICK) && \ - !defined(CONFIG_CORTEX_M_SYSTICK) +#if defined(CONFIG_CPU_CORTEX_M_HAS_SYSTICK) && !defined(CONFIG_CORTEX_M_SYSTICK) /* SoC implements SysTick, but the system does not use it * as driver for system timing. However, the SysTick IRQ is * always enabled, so we must ensure the interrupt priority @@ -208,7 +203,6 @@ static ALWAYS_INLINE void z_arm_exc_setup(void) */ NVIC_SetPriority(SysTick_IRQn, _EXC_IRQ_DEFAULT_PRIO); #endif /* CPU_CORTEX_M_HAS_SYSTICK && ! CORTEX_M_SYSTICK */ - } /** @@ -221,9 +215,7 @@ static ALWAYS_INLINE void z_arm_clear_faults(void) #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) /* Reset all faults */ - SCB->CFSR = SCB_CFSR_USGFAULTSR_Msk | - SCB_CFSR_MEMFAULTSR_Msk | - SCB_CFSR_BUSFAULTSR_Msk; + SCB->CFSR = SCB_CFSR_USGFAULTSR_Msk | SCB_CFSR_MEMFAULTSR_Msk | SCB_CFSR_BUSFAULTSR_Msk; /* Clear all Hard Faults - HFSR is write-one-to-clear */ SCB->HFSR = 0xffffffff; @@ -253,7 +245,7 @@ static ALWAYS_INLINE void z_arm_set_fault_sp(const struct arch_esf *esf, uint32_ * registers if necessary */ if ((exc_return & EXC_RETURN_STACK_FRAME_TYPE_STANDARD) == - EXC_RETURN_STACK_FRAME_TYPE_EXTENDED) { + EXC_RETURN_STACK_FRAME_TYPE_EXTENDED) { z_arm_coredump_fault_sp += sizeof(esf->fpu); } #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ diff --git a/arch/arm/include/cortex_m/kernel_arch_func.h b/arch/arm/include/cortex_m/kernel_arch_func.h index 2a24103a32de0..5abe5870762cf 100644 --- a/arch/arm/include/cortex_m/kernel_arch_func.h +++ b/arch/arm/include/cortex_m/kernel_arch_func.h @@ -61,26 +61,21 @@ static ALWAYS_INLINE void arch_kernel_init(void) #endif /* CONFIG_SOC_PER_CORE_INIT_HOOK */ } -static ALWAYS_INLINE void -arch_thread_return_value_set(struct k_thread *thread, unsigned int value) +static ALWAYS_INLINE void arch_thread_return_value_set(struct k_thread *thread, unsigned int value) { thread->arch.swap_return_value = value; } #if !defined(CONFIG_MULTITHREADING) -extern FUNC_NORETURN void z_arm_switch_to_main_no_multithreading( - k_thread_entry_t main_func, - void *p1, void *p2, void *p3); +extern FUNC_NORETURN void z_arm_switch_to_main_no_multithreading(k_thread_entry_t main_func, + void *p1, void *p2, void *p3); -#define ARCH_SWITCH_TO_MAIN_NO_MULTITHREADING \ - z_arm_switch_to_main_no_multithreading +#define ARCH_SWITCH_TO_MAIN_NO_MULTITHREADING z_arm_switch_to_main_no_multithreading #endif /* !CONFIG_MULTITHREADING */ -extern FUNC_NORETURN void z_arm_userspace_enter(k_thread_entry_t user_entry, - void *p1, void *p2, void *p3, - uint32_t stack_end, - uint32_t stack_start); +extern FUNC_NORETURN void z_arm_userspace_enter(k_thread_entry_t user_entry, void *p1, void *p2, + void *p3, uint32_t stack_end, uint32_t stack_start); extern void z_arm_fatal_error(unsigned int reason, const struct arch_esf *esf); @@ -102,7 +97,6 @@ static ALWAYS_INLINE int arch_swap(unsigned int key) return _current->arch.swap_return_value; } - #endif /* _ASMLANGUAGE */ #ifdef __cplusplus diff --git a/arch/arm/include/cortex_m/stack.h b/arch/arm/include/cortex_m/stack.h index feeaf719a88e0..6b534a3ea5b1a 100644 --- a/arch/arm/include/cortex_m/stack.h +++ b/arch/arm/include/cortex_m/stack.h @@ -26,8 +26,7 @@ extern "C" { #endif -K_KERNEL_STACK_ARRAY_DECLARE(z_interrupt_stacks, CONFIG_MP_MAX_NUM_CPUS, - CONFIG_ISR_STACK_SIZE); +K_KERNEL_STACK_ARRAY_DECLARE(z_interrupt_stacks, CONFIG_MP_MAX_NUM_CPUS, CONFIG_ISR_STACK_SIZE); /** * @@ -39,9 +38,8 @@ K_KERNEL_STACK_ARRAY_DECLARE(z_interrupt_stacks, CONFIG_MP_MAX_NUM_CPUS, */ static ALWAYS_INLINE void z_arm_interrupt_stack_setup(void) { - uint32_t msp = - (uint32_t)(K_KERNEL_STACK_BUFFER(z_interrupt_stacks[0])) + - K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0]); + uint32_t msp = (uint32_t)(K_KERNEL_STACK_BUFFER(z_interrupt_stacks[0])) + + K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0]); __set_MSP(msp); #if defined(CONFIG_BUILTIN_STACK_GUARD) diff --git a/arch/arm/include/cortex_m/tz_ns.h b/arch/arm/include/cortex_m/tz_ns.h index 51ed5eb1ca9fe..dd6dcb4c22e56 100644 --- a/arch/arm/include/cortex_m/tz_ns.h +++ b/arch/arm/include/cortex_m/tz_ns.h @@ -46,24 +46,18 @@ * the functions have been called. This instruction must leave * r0-r3 unmodified. */ -#define __TZ_WRAP_FUNC_RAW(preface, name, postface, store_lr, load_lr) \ - __asm__ volatile( \ - ".global "#preface"; .type "#preface", %function"); \ - __asm__ volatile( \ - ".global "#name"; .type "#name", %function"); \ - __asm__ volatile( \ - ".global "#postface"; .type "#postface", %function"); \ - __asm__ volatile( \ - store_lr "\n\t" \ - "push {r0-r3}\n\t" \ - "bl " #preface "\n\t" \ - "pop {r0-r3}\n\t" \ - "bl " #name " \n\t" \ - "push {r0-r3}\n\t" \ - "bl " #postface "\n\t" \ - "pop {r0-r3}\n\t" \ - load_lr "\n\t" \ - ::); +#define __TZ_WRAP_FUNC_RAW(preface, name, postface, store_lr, load_lr) \ + __asm__ volatile(".global " #preface "; .type " #preface ", %function"); \ + __asm__ volatile(".global " #name "; .type " #name ", %function"); \ + __asm__ volatile(".global " #postface "; .type " #postface ", %function"); \ + __asm__ volatile(store_lr "\n\t" \ + "push {r0-r3}\n\t" \ + "bl " #preface "\n\t" \ + "pop {r0-r3}\n\t" \ + "bl " #name "\n\t" \ + "push {r0-r3}\n\t" \ + "bl " #postface "\n\t" \ + "pop {r0-r3}\n\t" load_lr "\n\t" ::); /** * @brief Macro for "sandwiching" a function call (@p name) in two other calls @@ -98,10 +92,8 @@ * * See @ref __TZ_WRAP_FUNC_RAW for more information. */ -#define __TZ_WRAP_FUNC(preface, name, postface) \ - __TZ_WRAP_FUNC_RAW(preface, name, postface, "push {r4, lr}", \ - "pop {r4, pc}") - +#define __TZ_WRAP_FUNC(preface, name, postface) \ + __TZ_WRAP_FUNC_RAW(preface, name, postface, "push {r4, lr}", "pop {r4, pc}") #ifdef CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS /** @@ -130,10 +122,10 @@ * @param ... The rest of the signature of the function. This must be the same * signature as the corresponding NS entry function. */ -#define TZ_THREAD_SAFE_NONSECURE_ENTRY_FUNC(name, ret, nsc_name, ...) \ - ret __attribute__((naked)) name(__VA_ARGS__) \ - { \ - __TZ_WRAP_FUNC(k_sched_lock, nsc_name, k_sched_unlock); \ +#define TZ_THREAD_SAFE_NONSECURE_ENTRY_FUNC(name, ret, nsc_name, ...) \ + ret __attribute__((naked)) name(__VA_ARGS__) \ + { \ + __TZ_WRAP_FUNC(k_sched_lock, nsc_name, k_sched_unlock); \ } #endif /* CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS */ diff --git a/include/zephyr/arch/arm/cortex_m/cpu.h b/include/zephyr/arch/arm/cortex_m/cpu.h index 064d8f92d56e2..096f5aabba830 100644 --- a/include/zephyr/arch/arm/cortex_m/cpu.h +++ b/include/zephyr/arch/arm/cortex_m/cpu.h @@ -12,9 +12,9 @@ #define _SCS_BASE_ADDR _PPB_INT_SCS /* ICSR defines */ -#define _SCS_ICSR (_SCS_BASE_ADDR + 0xd04) -#define _SCS_ICSR_PENDSV (1 << 28) -#define _SCS_ICSR_UNPENDSV (1 << 27) +#define _SCS_ICSR (_SCS_BASE_ADDR + 0xd04) +#define _SCS_ICSR_PENDSV (1 << 28) +#define _SCS_ICSR_UNPENDSV (1 << 27) #define _SCS_ICSR_RETTOBASE (1 << 11) #define _SCS_MPU_CTRL (_SCS_BASE_ADDR + 0xd94) @@ -34,20 +34,20 @@ extern "C" { #endif /* CP10 Access Bits */ -#define CPACR_CP10_Pos 20U -#define CPACR_CP10_Msk (3UL << CPACR_CP10_Pos) -#define CPACR_CP10_NO_ACCESS (0UL << CPACR_CP10_Pos) -#define CPACR_CP10_PRIV_ACCESS (1UL << CPACR_CP10_Pos) -#define CPACR_CP10_RESERVED (2UL << CPACR_CP10_Pos) -#define CPACR_CP10_FULL_ACCESS (3UL << CPACR_CP10_Pos) +#define CPACR_CP10_Pos 20U +#define CPACR_CP10_Msk (3UL << CPACR_CP10_Pos) +#define CPACR_CP10_NO_ACCESS (0UL << CPACR_CP10_Pos) +#define CPACR_CP10_PRIV_ACCESS (1UL << CPACR_CP10_Pos) +#define CPACR_CP10_RESERVED (2UL << CPACR_CP10_Pos) +#define CPACR_CP10_FULL_ACCESS (3UL << CPACR_CP10_Pos) /* CP11 Access Bits */ -#define CPACR_CP11_Pos 22U -#define CPACR_CP11_Msk (3UL << CPACR_CP11_Pos) -#define CPACR_CP11_NO_ACCESS (0UL << CPACR_CP11_Pos) -#define CPACR_CP11_PRIV_ACCESS (1UL << CPACR_CP11_Pos) -#define CPACR_CP11_RESERVED (2UL << CPACR_CP11_Pos) -#define CPACR_CP11_FULL_ACCESS (3UL << CPACR_CP11_Pos) +#define CPACR_CP11_Pos 22U +#define CPACR_CP11_Msk (3UL << CPACR_CP11_Pos) +#define CPACR_CP11_NO_ACCESS (0UL << CPACR_CP11_Pos) +#define CPACR_CP11_PRIV_ACCESS (1UL << CPACR_CP11_Pos) +#define CPACR_CP11_RESERVED (2UL << CPACR_CP11_Pos) +#define CPACR_CP11_FULL_ACCESS (3UL << CPACR_CP11_Pos) #ifdef CONFIG_PM_S2RAM diff --git a/include/zephyr/arch/arm/cortex_m/exception.h b/include/zephyr/arch/arm/cortex_m/exception.h index 6f60317891d9a..d675efa1549d0 100644 --- a/include/zephyr/arch/arm/cortex_m/exception.h +++ b/include/zephyr/arch/arm/cortex_m/exception.h @@ -43,17 +43,17 @@ #define _EXCEPTION_RESERVED_PRIO 0 #endif -#define _EXC_FAULT_PRIO 0 +#define _EXC_FAULT_PRIO 0 #define _EXC_ZERO_LATENCY_IRQS_PRIO 0 -#define _EXC_SVC_PRIO COND_CODE_1(CONFIG_ZERO_LATENCY_IRQS, \ +#define _EXC_SVC_PRIO COND_CODE_1(CONFIG_ZERO_LATENCY_IRQS, \ (CONFIG_ZERO_LATENCY_LEVELS), (0)) -#define _IRQ_PRIO_OFFSET (_EXCEPTION_RESERVED_PRIO + _EXC_SVC_PRIO) -#define IRQ_PRIO_LOWEST (BIT(NUM_IRQ_PRIO_BITS) - (_IRQ_PRIO_OFFSET) - 1) +#define _IRQ_PRIO_OFFSET (_EXCEPTION_RESERVED_PRIO + _EXC_SVC_PRIO) +#define IRQ_PRIO_LOWEST (BIT(NUM_IRQ_PRIO_BITS) - (_IRQ_PRIO_OFFSET) - 1) #define _EXC_IRQ_DEFAULT_PRIO Z_EXC_PRIO(_IRQ_PRIO_OFFSET) /* Use lowest possible priority level for PendSV */ -#define _EXC_PENDSV_PRIO 0xff +#define _EXC_PENDSV_PRIO 0xff #define _EXC_PENDSV_PRIO_MASK Z_EXC_PRIO(_EXC_PENDSV_PRIO) #ifdef _ASMLANGUAGE @@ -99,7 +99,10 @@ struct __extra_esf_info { #endif /* CONFIG_EXTRA_EXCEPTION_INFO */ /* ARM GPRs are often designated by two different names */ -#define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; } +#define sys_define_gpr_with_alias(name1, name2) \ + union { \ + uint32_t name1, name2; \ + } struct arch_esf { struct __basic_sf { diff --git a/include/zephyr/arch/arm/cortex_m/memory_map.h b/include/zephyr/arch/arm/cortex_m/memory_map.h index 1fbec9d19d7b8..30e800daf374d 100644 --- a/include/zephyr/arch/arm/cortex_m/memory_map.h +++ b/include/zephyr/arch/arm/cortex_m/memory_map.h @@ -18,8 +18,8 @@ #include /* 0x00000000 -> 0x1fffffff: Code in ROM [0.5 GB] */ -#define _CODE_BASE_ADDR 0x00000000 -#define _CODE_END_ADDR 0x1FFFFFFF +#define _CODE_BASE_ADDR 0x00000000 +#define _CODE_END_ADDR 0x1FFFFFFF /* 0x20000000 -> 0x3fffffff: SRAM [0.5GB] */ #define _SRAM_BASE_ADDR 0x20000000 @@ -38,78 +38,77 @@ #define _PERI_END_ADDR 0x5FFFFFFF /* 0x60000000 -> 0x9fffffff: external RAM [1GB] */ -#define _ERAM_BASE_ADDR 0x60000000 -#define _ERAM_END_ADDR 0x9FFFFFFF +#define _ERAM_BASE_ADDR 0x60000000 +#define _ERAM_END_ADDR 0x9FFFFFFF /* 0xa0000000 -> 0xdfffffff: external devices [1GB] */ -#define _EDEV_BASE_ADDR 0xA0000000 -#define _EDEV_END_ADDR 0xDFFFFFFF +#define _EDEV_BASE_ADDR 0xA0000000 +#define _EDEV_END_ADDR 0xDFFFFFFF /* 0xe0000000 -> 0xffffffff: varies by processor (see below) */ /* 0xe0000000 -> 0xe00fffff: private peripheral bus */ /* 0xe0000000 -> 0xe003ffff: internal [256KB] */ -#define _PPB_INT_BASE_ADDR 0xE0000000 -#if defined(CONFIG_CPU_CORTEX_M0) || defined(CONFIG_CPU_CORTEX_M0PLUS) || \ +#define _PPB_INT_BASE_ADDR 0xE0000000 +#if defined(CONFIG_CPU_CORTEX_M0) || defined(CONFIG_CPU_CORTEX_M0PLUS) || \ defined(CONFIG_CPU_CORTEX_M1) -#define _PPB_INT_RSVD_0 0xE0000000 -#define _PPB_INT_DWT 0xE0001000 -#define _PPB_INT_BPU 0xE0002000 -#define _PPB_INT_RSVD_1 0xE0003000 -#define _PPB_INT_SCS 0xE000E000 -#define _PPB_INT_RSVD_2 0xE000F000 -#elif defined(CONFIG_CPU_CORTEX_M3) || defined(CONFIG_CPU_CORTEX_M4) || defined(CONFIG_CPU_CORTEX_M7) -#define _PPB_INT_ITM 0xE0000000 -#define _PPB_INT_DWT 0xE0001000 -#define _PPB_INT_FPB 0xE0002000 -#define _PPB_INT_RSVD_1 0xE0003000 -#define _PPB_INT_SCS 0xE000E000 -#define _PPB_INT_RSVD_2 0xE000F000 -#elif defined(CONFIG_CPU_CORTEX_M23) || \ - defined(CONFIG_CPU_CORTEX_M33) || \ - defined(CONFIG_CPU_CORTEX_M55) || \ - defined(CONFIG_CPU_CORTEX_M85) -#define _PPB_INT_RSVD_0 0xE0000000 -#define _PPB_INT_SCS 0xE000E000 -#define _PPB_INT_SCB 0xE000ED00 -#define _PPB_INT_RSVD_1 0xE002E000 +#define _PPB_INT_RSVD_0 0xE0000000 +#define _PPB_INT_DWT 0xE0001000 +#define _PPB_INT_BPU 0xE0002000 +#define _PPB_INT_RSVD_1 0xE0003000 +#define _PPB_INT_SCS 0xE000E000 +#define _PPB_INT_RSVD_2 0xE000F000 +#elif defined(CONFIG_CPU_CORTEX_M3) || defined(CONFIG_CPU_CORTEX_M4) || \ + defined(CONFIG_CPU_CORTEX_M7) +#define _PPB_INT_ITM 0xE0000000 +#define _PPB_INT_DWT 0xE0001000 +#define _PPB_INT_FPB 0xE0002000 +#define _PPB_INT_RSVD_1 0xE0003000 +#define _PPB_INT_SCS 0xE000E000 +#define _PPB_INT_RSVD_2 0xE000F000 +#elif defined(CONFIG_CPU_CORTEX_M23) || defined(CONFIG_CPU_CORTEX_M33) || \ + defined(CONFIG_CPU_CORTEX_M55) || defined(CONFIG_CPU_CORTEX_M85) +#define _PPB_INT_RSVD_0 0xE0000000 +#define _PPB_INT_SCS 0xE000E000 +#define _PPB_INT_SCB 0xE000ED00 +#define _PPB_INT_RSVD_1 0xE002E000 #else #error Unknown CPU #endif -#define _PPB_INT_END_ADDR 0xE003FFFF +#define _PPB_INT_END_ADDR 0xE003FFFF /* 0xe0000000 -> 0xe00fffff: private peripheral bus */ /* 0xe0040000 -> 0xe00fffff: external [768K] */ -#define _PPB_EXT_BASE_ADDR 0xE0040000 -#if defined(CONFIG_CPU_CORTEX_M0) || defined(CONFIG_CPU_CORTEX_M0PLUS) \ - || defined(CONFIG_CPU_CORTEX_M1) || defined(CONFIG_CPU_CORTEX_M23) +#define _PPB_EXT_BASE_ADDR 0xE0040000 +#if defined(CONFIG_CPU_CORTEX_M0) || defined(CONFIG_CPU_CORTEX_M0PLUS) || \ + defined(CONFIG_CPU_CORTEX_M1) || defined(CONFIG_CPU_CORTEX_M23) #elif defined(CONFIG_CPU_CORTEX_M3) || defined(CONFIG_CPU_CORTEX_M4) -#define _PPB_EXT_TPIU 0xE0040000 -#define _PPB_EXT_ETM 0xE0041000 -#define _PPB_EXT_PPB 0xE0042000 -#define _PPB_EXT_ROM_TABLE 0xE00FF000 -#define _PPB_EXT_END_ADDR 0xE00FFFFF -#elif defined(CONFIG_CPU_CORTEX_M33) || defined(CONFIG_CPU_CORTEX_M55) \ - || defined(CONFIG_CPU_CORTEX_M85) -#undef _PPB_EXT_BASE_ADDR -#define _PPB_EXT_BASE_ADDR 0xE0044000 -#define _PPB_EXT_ROM_TABLE 0xE00FF000 -#define _PPB_EXT_END_ADDR 0xE00FFFFF +#define _PPB_EXT_TPIU 0xE0040000 +#define _PPB_EXT_ETM 0xE0041000 +#define _PPB_EXT_PPB 0xE0042000 +#define _PPB_EXT_ROM_TABLE 0xE00FF000 +#define _PPB_EXT_END_ADDR 0xE00FFFFF +#elif defined(CONFIG_CPU_CORTEX_M33) || defined(CONFIG_CPU_CORTEX_M55) || \ + defined(CONFIG_CPU_CORTEX_M85) +#undef _PPB_EXT_BASE_ADDR +#define _PPB_EXT_BASE_ADDR 0xE0044000 +#define _PPB_EXT_ROM_TABLE 0xE00FF000 +#define _PPB_EXT_END_ADDR 0xE00FFFFF #elif defined(CONFIG_CPU_CORTEX_M7) -#define _PPB_EXT_BASE_ADDR 0xE0040000 -#define _PPB_EXT_RSVD_TPIU 0xE0040000 -#define _PPB_EXT_ETM 0xE0041000 -#define _PPB_EXT_CTI 0xE0042000 -#define _PPB_EXT_PPB 0xE0043000 -#define _PPB_EXT_PROC_ROM_TABLE 0xE00FE000 -#define _PPB_EXT_PPB_ROM_TABLE 0xE00FF000 +#define _PPB_EXT_BASE_ADDR 0xE0040000 +#define _PPB_EXT_RSVD_TPIU 0xE0040000 +#define _PPB_EXT_ETM 0xE0041000 +#define _PPB_EXT_CTI 0xE0042000 +#define _PPB_EXT_PPB 0xE0043000 +#define _PPB_EXT_PROC_ROM_TABLE 0xE00FE000 +#define _PPB_EXT_PPB_ROM_TABLE 0xE00FF000 #else #error Unknown CPU #endif -#define _PPB_EXT_END_ADDR 0xE00FFFFF +#define _PPB_EXT_END_ADDR 0xE00FFFFF /* 0xe0100000 -> 0xffffffff: vendor-specific [0.5GB-1MB or 511MB] */ -#define _VENDOR_BASE_ADDR 0xE0100000 -#define _VENDOR_END_ADDR 0xFFFFFFFF +#define _VENDOR_BASE_ADDR 0xE0100000 +#define _VENDOR_END_ADDR 0xFFFFFFFF #endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MEMORY_MAP_H_ */ diff --git a/include/zephyr/arch/arm/mpu/arm_mpu.h b/include/zephyr/arch/arm/mpu/arm_mpu.h index e47883f1849a1..2aee4dd7efee5 100644 --- a/include/zephyr/arch/arm/mpu/arm_mpu.h +++ b/include/zephyr/arch/arm/mpu/arm_mpu.h @@ -6,16 +6,11 @@ #ifndef ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ #define ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ -#if defined(CONFIG_CPU_CORTEX_M0PLUS) || \ - defined(CONFIG_CPU_CORTEX_M3) || \ - defined(CONFIG_CPU_CORTEX_M4) || \ - defined(CONFIG_CPU_CORTEX_M7) || \ - defined(CONFIG_ARMV7_R) +#if defined(CONFIG_CPU_CORTEX_M0PLUS) || defined(CONFIG_CPU_CORTEX_M3) || \ + defined(CONFIG_CPU_CORTEX_M4) || defined(CONFIG_CPU_CORTEX_M7) || defined(CONFIG_ARMV7_R) #include -#elif defined(CONFIG_CPU_CORTEX_M23) || \ - defined(CONFIG_CPU_CORTEX_M33) || \ - defined(CONFIG_CPU_CORTEX_M55) || \ - defined(CONFIG_CPU_CORTEX_M85) || \ +#elif defined(CONFIG_CPU_CORTEX_M23) || defined(CONFIG_CPU_CORTEX_M33) || \ + defined(CONFIG_CPU_CORTEX_M55) || defined(CONFIG_CPU_CORTEX_M85) || \ defined(CONFIG_AARCH32_ARMV8_R) #include #else @@ -47,19 +42,19 @@ struct arm_mpu_config { }; #if defined(CONFIG_ARMV7_R) -#define MPU_REGION_ENTRY(_name, _base, _size, _attr) \ - {\ - .name = _name, \ - .base = _base, \ - .size = _size, \ - .attr = _attr, \ +#define MPU_REGION_ENTRY(_name, _base, _size, _attr) \ + { \ + .name = _name, \ + .base = _base, \ + .size = _size, \ + .attr = _attr, \ } #else -#define MPU_REGION_ENTRY(_name, _base, _attr) \ - {\ - .name = _name, \ - .base = _base, \ - .attr = _attr, \ +#define MPU_REGION_ENTRY(_name, _base, _attr) \ + { \ + .name = _name, \ + .base = _base, \ + .attr = _attr, \ } #endif diff --git a/include/zephyr/arch/arm/mpu/arm_mpu_v7m.h b/include/zephyr/arch/arm/mpu/arm_mpu_v7m.h index 1ed8636ec50bd..c1ada0d55e5ed 100644 --- a/include/zephyr/arch/arm/mpu/arm_mpu_v7m.h +++ b/include/zephyr/arch/arm/mpu/arm_mpu_v7m.h @@ -46,73 +46,69 @@ #define NOT_EXEC MPU_RASR_XN_Msk /* The following definitions are for internal use in arm_mpu.h. */ -#define STRONGLY_ORDERED_SHAREABLE MPU_RASR_S_Msk -#define DEVICE_SHAREABLE (MPU_RASR_B_Msk | MPU_RASR_S_Msk) -#define NORMAL_OUTER_INNER_WRITE_THROUGH_SHAREABLE \ - (MPU_RASR_C_Msk | MPU_RASR_S_Msk) -#define NORMAL_OUTER_INNER_WRITE_THROUGH_NON_SHAREABLE MPU_RASR_C_Msk -#define NORMAL_OUTER_INNER_WRITE_BACK_SHAREABLE \ - (MPU_RASR_C_Msk | MPU_RASR_B_Msk | MPU_RASR_S_Msk) -#define NORMAL_OUTER_INNER_WRITE_BACK_NON_SHAREABLE \ - (MPU_RASR_C_Msk | MPU_RASR_B_Msk) -#define NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE \ - ((1 << MPU_RASR_TEX_Pos) | MPU_RASR_S_Msk) -#define NORMAL_OUTER_INNER_NON_CACHEABLE_NON_SHAREABLE \ - (1 << MPU_RASR_TEX_Pos) -#define NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_SHAREABLE \ - ((1 << MPU_RASR_TEX_Pos) |\ - MPU_RASR_C_Msk | MPU_RASR_B_Msk | MPU_RASR_S_Msk) -#define NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE \ +#define STRONGLY_ORDERED_SHAREABLE MPU_RASR_S_Msk +#define DEVICE_SHAREABLE (MPU_RASR_B_Msk | MPU_RASR_S_Msk) +#define NORMAL_OUTER_INNER_WRITE_THROUGH_SHAREABLE (MPU_RASR_C_Msk | MPU_RASR_S_Msk) +#define NORMAL_OUTER_INNER_WRITE_THROUGH_NON_SHAREABLE MPU_RASR_C_Msk +/* clang-format off */ +#define NORMAL_OUTER_INNER_WRITE_BACK_SHAREABLE \ + (MPU_RASR_C_Msk | MPU_RASR_B_Msk | MPU_RASR_S_Msk) +/* clang-format on */ +#define NORMAL_OUTER_INNER_WRITE_BACK_NON_SHAREABLE (MPU_RASR_C_Msk | MPU_RASR_B_Msk) +#define NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE ((1 << MPU_RASR_TEX_Pos) | MPU_RASR_S_Msk) +#define NORMAL_OUTER_INNER_NON_CACHEABLE_NON_SHAREABLE (1 << MPU_RASR_TEX_Pos) +#define NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_SHAREABLE \ + ((1 << MPU_RASR_TEX_Pos) | MPU_RASR_C_Msk | MPU_RASR_B_Msk | MPU_RASR_S_Msk) +#define NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE \ ((1 << MPU_RASR_TEX_Pos) | MPU_RASR_C_Msk | MPU_RASR_B_Msk) -#define DEVICE_NON_SHAREABLE (2 << MPU_RASR_TEX_Pos) +#define DEVICE_NON_SHAREABLE (2 << MPU_RASR_TEX_Pos) /* Bit-masks to disable sub-regions. */ -#define SUB_REGION_0_DISABLED ((0x01 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) -#define SUB_REGION_1_DISABLED ((0x02 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) -#define SUB_REGION_2_DISABLED ((0x04 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) -#define SUB_REGION_3_DISABLED ((0x08 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) -#define SUB_REGION_4_DISABLED ((0x10 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) -#define SUB_REGION_5_DISABLED ((0x20 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) -#define SUB_REGION_6_DISABLED ((0x40 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) -#define SUB_REGION_7_DISABLED ((0x80 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) +#define SUB_REGION_0_DISABLED ((0x01 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) +#define SUB_REGION_1_DISABLED ((0x02 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) +#define SUB_REGION_2_DISABLED ((0x04 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) +#define SUB_REGION_3_DISABLED ((0x08 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) +#define SUB_REGION_4_DISABLED ((0x10 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) +#define SUB_REGION_5_DISABLED ((0x20 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) +#define SUB_REGION_6_DISABLED ((0x40 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) +#define SUB_REGION_7_DISABLED ((0x80 << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) +#define REGION_SIZE(size) ((ARM_MPU_REGION_SIZE_##size << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) -#define REGION_SIZE(size) ((ARM_MPU_REGION_SIZE_ ## size \ - << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) +#define REGION_32B REGION_SIZE(32B) +#define REGION_64B REGION_SIZE(64B) +#define REGION_128B REGION_SIZE(128B) +#define REGION_256B REGION_SIZE(256B) +#define REGION_512B REGION_SIZE(512B) +#define REGION_1K REGION_SIZE(1KB) +#define REGION_2K REGION_SIZE(2KB) +#define REGION_4K REGION_SIZE(4KB) +#define REGION_8K REGION_SIZE(8KB) +#define REGION_16K REGION_SIZE(16KB) +#define REGION_32K REGION_SIZE(32KB) +#define REGION_64K REGION_SIZE(64KB) +#define REGION_128K REGION_SIZE(128KB) +#define REGION_256K REGION_SIZE(256KB) +#define REGION_512K REGION_SIZE(512KB) +#define REGION_1M REGION_SIZE(1MB) +#define REGION_2M REGION_SIZE(2MB) +#define REGION_4M REGION_SIZE(4MB) +#define REGION_8M REGION_SIZE(8MB) +#define REGION_16M REGION_SIZE(16MB) +#define REGION_32M REGION_SIZE(32MB) +#define REGION_64M REGION_SIZE(64MB) +#define REGION_128M REGION_SIZE(128MB) +#define REGION_256M REGION_SIZE(256MB) +#define REGION_512M REGION_SIZE(512MB) +#define REGION_1G REGION_SIZE(1GB) +#define REGION_2G REGION_SIZE(2GB) +#define REGION_4G REGION_SIZE(4GB) -#define REGION_32B REGION_SIZE(32B) -#define REGION_64B REGION_SIZE(64B) -#define REGION_128B REGION_SIZE(128B) -#define REGION_256B REGION_SIZE(256B) -#define REGION_512B REGION_SIZE(512B) -#define REGION_1K REGION_SIZE(1KB) -#define REGION_2K REGION_SIZE(2KB) -#define REGION_4K REGION_SIZE(4KB) -#define REGION_8K REGION_SIZE(8KB) -#define REGION_16K REGION_SIZE(16KB) -#define REGION_32K REGION_SIZE(32KB) -#define REGION_64K REGION_SIZE(64KB) -#define REGION_128K REGION_SIZE(128KB) -#define REGION_256K REGION_SIZE(256KB) -#define REGION_512K REGION_SIZE(512KB) -#define REGION_1M REGION_SIZE(1MB) -#define REGION_2M REGION_SIZE(2MB) -#define REGION_4M REGION_SIZE(4MB) -#define REGION_8M REGION_SIZE(8MB) -#define REGION_16M REGION_SIZE(16MB) -#define REGION_32M REGION_SIZE(32MB) -#define REGION_64M REGION_SIZE(64MB) -#define REGION_128M REGION_SIZE(128MB) -#define REGION_256M REGION_SIZE(256MB) -#define REGION_512M REGION_SIZE(512MB) -#define REGION_1G REGION_SIZE(1GB) -#define REGION_2G REGION_SIZE(2GB) -#define REGION_4G REGION_SIZE(4GB) - -#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \ - { .name = p_name, \ - .base = p_base, \ - .attr = p_attr(size_to_mpu_rasr_size(p_size)), \ +#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \ + { \ + .name = p_name, \ + .base = p_base, \ + .attr = p_attr(size_to_mpu_rasr_size(p_size)), \ } /* Some helper defines for common regions */ @@ -121,33 +117,20 @@ * CONFIG_XIP=n, the entire image will be linked to SRAM, so we need to keep * the SRAM region XN bit clear or the application code will not be executable. */ -#define REGION_RAM_ATTR(size) \ -{ \ - (NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE | \ - IF_ENABLED(CONFIG_XIP, (MPU_RASR_XN_Msk |)) size | P_RW_U_NA_Msk) \ -} -#define REGION_RAM_NOCACHE_ATTR(size) \ -{ \ - (NORMAL_OUTER_INNER_NON_CACHEABLE_NON_SHAREABLE | \ - MPU_RASR_XN_Msk | size | P_RW_U_NA_Msk) \ -} +#define REGION_RAM_ATTR(size) \ + {(NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE | \ + IF_ENABLED(CONFIG_XIP, (MPU_RASR_XN_Msk |)) size | P_RW_U_NA_Msk)} +#define REGION_RAM_NOCACHE_ATTR(size) \ + {(NORMAL_OUTER_INNER_NON_CACHEABLE_NON_SHAREABLE | MPU_RASR_XN_Msk | size | P_RW_U_NA_Msk)} #if defined(CONFIG_MPU_ALLOW_FLASH_WRITE) -#define REGION_FLASH_ATTR(size) \ -{ \ - (NORMAL_OUTER_INNER_WRITE_THROUGH_NON_SHAREABLE | size | \ - P_RW_U_RO_Msk) \ -} +#define REGION_FLASH_ATTR(size) \ + {(NORMAL_OUTER_INNER_WRITE_THROUGH_NON_SHAREABLE | size | P_RW_U_RO_Msk)} #else -#define REGION_FLASH_ATTR(size) \ -{ \ - (NORMAL_OUTER_INNER_WRITE_THROUGH_NON_SHAREABLE | size | RO_Msk) \ -} +#define REGION_FLASH_ATTR(size) {(NORMAL_OUTER_INNER_WRITE_THROUGH_NON_SHAREABLE | size | RO_Msk)} #endif -#define REGION_PPB_ATTR(size) { (STRONGLY_ORDERED_SHAREABLE | size | \ - P_RW_U_NA_Msk) } -#define REGION_IO_ATTR(size) { (DEVICE_NON_SHAREABLE | size | P_RW_U_NA_Msk) } -#define REGION_EXTMEM_ATTR(size) { (STRONGLY_ORDERED_SHAREABLE | size | \ - NO_ACCESS_Msk) } +#define REGION_PPB_ATTR(size) {(STRONGLY_ORDERED_SHAREABLE | size | P_RW_U_NA_Msk)} +#define REGION_IO_ATTR(size) {(DEVICE_NON_SHAREABLE | size | P_RW_U_NA_Msk)} +#define REGION_EXTMEM_ATTR(size) {(STRONGLY_ORDERED_SHAREABLE | size | NO_ACCESS_Msk)} struct arm_mpu_region_attr { /* Attributes belonging to RASR (including the encoded region size) */ @@ -162,12 +145,12 @@ typedef struct { } k_mem_partition_attr_t; /* Read-Write access permission attributes */ -#define _K_MEM_PARTITION_P_NA_U_NA (NO_ACCESS_Msk | NOT_EXEC) -#define _K_MEM_PARTITION_P_RW_U_RW (P_RW_U_RW_Msk | NOT_EXEC) -#define _K_MEM_PARTITION_P_RW_U_RO (P_RW_U_RO_Msk | NOT_EXEC) -#define _K_MEM_PARTITION_P_RW_U_NA (P_RW_U_NA_Msk | NOT_EXEC) -#define _K_MEM_PARTITION_P_RO_U_RO (P_RO_U_RO_Msk | NOT_EXEC) -#define _K_MEM_PARTITION_P_RO_U_NA (P_RO_U_NA_Msk | NOT_EXEC) +#define _K_MEM_PARTITION_P_NA_U_NA (NO_ACCESS_Msk | NOT_EXEC) +#define _K_MEM_PARTITION_P_RW_U_RW (P_RW_U_RW_Msk | NOT_EXEC) +#define _K_MEM_PARTITION_P_RW_U_RO (P_RW_U_RO_Msk | NOT_EXEC) +#define _K_MEM_PARTITION_P_RW_U_NA (P_RW_U_NA_Msk | NOT_EXEC) +#define _K_MEM_PARTITION_P_RO_U_RO (P_RO_U_RO_Msk | NOT_EXEC) +#define _K_MEM_PARTITION_P_RO_U_NA (P_RO_U_NA_Msk | NOT_EXEC) /* Execution-allowed attributes */ #define _K_MEM_PARTITION_P_RWX_U_RWX (P_RW_U_RW_Msk) @@ -184,35 +167,44 @@ typedef struct { */ /* Read-Write access permission attributes (default cache-ability) */ -#define K_MEM_PARTITION_P_NA_U_NA ((k_mem_partition_attr_t) \ - { _K_MEM_PARTITION_P_NA_U_NA | \ - NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) -#define K_MEM_PARTITION_P_RW_U_RW ((k_mem_partition_attr_t) \ - { _K_MEM_PARTITION_P_RW_U_RW | \ - NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) -#define K_MEM_PARTITION_P_RW_U_RO ((k_mem_partition_attr_t) \ - { _K_MEM_PARTITION_P_RW_U_RO | \ - NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) -#define K_MEM_PARTITION_P_RW_U_NA ((k_mem_partition_attr_t) \ - { _K_MEM_PARTITION_P_RW_U_NA | \ - NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) -#define K_MEM_PARTITION_P_RO_U_RO ((k_mem_partition_attr_t) \ - { _K_MEM_PARTITION_P_RO_U_RO | \ - NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) -#define K_MEM_PARTITION_P_RO_U_NA ((k_mem_partition_attr_t) \ - { _K_MEM_PARTITION_P_RO_U_NA | \ - NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) +#define K_MEM_PARTITION_P_NA_U_NA \ + ((k_mem_partition_attr_t){ \ + _K_MEM_PARTITION_P_NA_U_NA | \ + NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) +#define K_MEM_PARTITION_P_RW_U_RW \ + ((k_mem_partition_attr_t){ \ + _K_MEM_PARTITION_P_RW_U_RW | \ + NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) +#define K_MEM_PARTITION_P_RW_U_RO \ + ((k_mem_partition_attr_t){ \ + _K_MEM_PARTITION_P_RW_U_RO | \ + NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) +#define K_MEM_PARTITION_P_RW_U_NA \ + ((k_mem_partition_attr_t){ \ + _K_MEM_PARTITION_P_RW_U_NA | \ + NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) +#define K_MEM_PARTITION_P_RO_U_RO \ + ((k_mem_partition_attr_t){ \ + _K_MEM_PARTITION_P_RO_U_RO | \ + NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) +#define K_MEM_PARTITION_P_RO_U_NA \ + ((k_mem_partition_attr_t){ \ + _K_MEM_PARTITION_P_RO_U_NA | \ + NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) /* Execution-allowed attributes (default-cacheability) */ -#define K_MEM_PARTITION_P_RWX_U_RWX ((k_mem_partition_attr_t) \ - { _K_MEM_PARTITION_P_RWX_U_RWX | \ - NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) -#define K_MEM_PARTITION_P_RWX_U_RX ((k_mem_partition_attr_t) \ - { _K_MEM_PARTITION_P_RWX_U_RX | \ - NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) -#define K_MEM_PARTITION_P_RX_U_RX ((k_mem_partition_attr_t) \ - { _K_MEM_PARTITION_P_RX_U_RX | \ - NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) +#define K_MEM_PARTITION_P_RWX_U_RWX \ + ((k_mem_partition_attr_t){ \ + _K_MEM_PARTITION_P_RWX_U_RWX | \ + NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) +#define K_MEM_PARTITION_P_RWX_U_RX \ + ((k_mem_partition_attr_t){ \ + _K_MEM_PARTITION_P_RWX_U_RX | \ + NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) +#define K_MEM_PARTITION_P_RX_U_RX \ + ((k_mem_partition_attr_t){ \ + _K_MEM_PARTITION_P_RX_U_RX | \ + NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_SHAREABLE}) /* * @brief Evaluate Write-ability @@ -222,19 +214,19 @@ typedef struct { * @param attr The k_mem_partition_attr_t object holding the * MPU attributes to be checked against write-ability. */ -#define K_MEM_PARTITION_IS_WRITABLE(attr) \ - ({ \ - int __is_writable__; \ - switch (attr.rasr_attr & MPU_RASR_AP_Msk) { \ - case P_RW_U_RW_Msk: \ - case P_RW_U_RO_Msk: \ - case P_RW_U_NA_Msk: \ - __is_writable__ = 1; \ - break; \ - default: \ - __is_writable__ = 0; \ - } \ - __is_writable__; \ +#define K_MEM_PARTITION_IS_WRITABLE(attr) \ + ({ \ + int __is_writable__; \ + switch (attr.rasr_attr & MPU_RASR_AP_Msk) { \ + case P_RW_U_RW_Msk: \ + case P_RW_U_RO_Msk: \ + case P_RW_U_NA_Msk: \ + __is_writable__ = 1; \ + break; \ + default: \ + __is_writable__ = 0; \ + } \ + __is_writable__; \ }) /* @@ -246,46 +238,45 @@ typedef struct { * MPU attributes to be checked against execution * allowance. */ -#define K_MEM_PARTITION_IS_EXECUTABLE(attr) \ - (!((attr.rasr_attr) & (NOT_EXEC))) +#define K_MEM_PARTITION_IS_EXECUTABLE(attr) (!((attr.rasr_attr) & (NOT_EXEC))) /* Attributes for no-cache enabling (share-ability is selected by default) */ -#define K_MEM_PARTITION_P_NA_U_NA_NOCACHE ((k_mem_partition_attr_t) \ - {(_K_MEM_PARTITION_P_NA_U_NA \ - | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) -#define K_MEM_PARTITION_P_RW_U_RW_NOCACHE ((k_mem_partition_attr_t) \ - {(_K_MEM_PARTITION_P_RW_U_RW \ - | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) -#define K_MEM_PARTITION_P_RW_U_RO_NOCACHE ((k_mem_partition_attr_t) \ - {(_K_MEM_PARTITION_P_RW_U_RO \ - | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) -#define K_MEM_PARTITION_P_RW_U_NA_NOCACHE ((k_mem_partition_attr_t) \ - {(_K_MEM_PARTITION_P_RW_U_NA \ - | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) -#define K_MEM_PARTITION_P_RO_U_RO_NOCACHE ((k_mem_partition_attr_t) \ - {(_K_MEM_PARTITION_P_RO_U_RO \ - | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) -#define K_MEM_PARTITION_P_RO_U_NA_NOCACHE ((k_mem_partition_attr_t) \ - {(_K_MEM_PARTITION_P_RO_U_NA \ - | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) +#define K_MEM_PARTITION_P_NA_U_NA_NOCACHE \ + ((k_mem_partition_attr_t){ \ + (_K_MEM_PARTITION_P_NA_U_NA | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) +#define K_MEM_PARTITION_P_RW_U_RW_NOCACHE \ + ((k_mem_partition_attr_t){ \ + (_K_MEM_PARTITION_P_RW_U_RW | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) +#define K_MEM_PARTITION_P_RW_U_RO_NOCACHE \ + ((k_mem_partition_attr_t){ \ + (_K_MEM_PARTITION_P_RW_U_RO | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) +#define K_MEM_PARTITION_P_RW_U_NA_NOCACHE \ + ((k_mem_partition_attr_t){ \ + (_K_MEM_PARTITION_P_RW_U_NA | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) +#define K_MEM_PARTITION_P_RO_U_RO_NOCACHE \ + ((k_mem_partition_attr_t){ \ + (_K_MEM_PARTITION_P_RO_U_RO | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) +#define K_MEM_PARTITION_P_RO_U_NA_NOCACHE \ + ((k_mem_partition_attr_t){ \ + (_K_MEM_PARTITION_P_RO_U_NA | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) -#define K_MEM_PARTITION_P_RWX_U_RWX_NOCACHE ((k_mem_partition_attr_t) \ - {(_K_MEM_PARTITION_P_RWX_U_RWX \ - | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) -#define K_MEM_PARTITION_P_RWX_U_RX_NOCACHE ((k_mem_partition_attr_t) \ - {(_K_MEM_PARTITION_P_RWX_U_RX \ - | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) -#define K_MEM_PARTITION_P_RX_U_RX_NOCACHE ((k_mem_partition_attr_t) \ - {(_K_MEM_PARTITION_P_RX_U_RX \ - | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) +#define K_MEM_PARTITION_P_RWX_U_RWX_NOCACHE \ + ((k_mem_partition_attr_t){ \ + (_K_MEM_PARTITION_P_RWX_U_RWX | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) +#define K_MEM_PARTITION_P_RWX_U_RX_NOCACHE \ + ((k_mem_partition_attr_t){ \ + (_K_MEM_PARTITION_P_RWX_U_RX | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) +#define K_MEM_PARTITION_P_RX_U_RX_NOCACHE \ + ((k_mem_partition_attr_t){ \ + (_K_MEM_PARTITION_P_RX_U_RX | NORMAL_OUTER_INNER_NON_CACHEABLE_SHAREABLE)}) #endif /* _ASMLANGUAGE */ -#define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size) \ - BUILD_ASSERT(!(((size) & ((size) - 1))) && \ - (size) >= CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE && \ - !((uint32_t)(start) & ((size) - 1)), \ - "the size of the partition must be power of 2" \ - " and greater than or equal to the minimum MPU region size." \ - "start address of the partition must align with size.") +#define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size) \ + BUILD_ASSERT(!(((size) & ((size) - 1))) && \ + (size) >= CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE && \ + !((uint32_t)(start) & ((size) - 1)), \ + "The size of the partition must be power of 2 and greater than or equal to " \ + "the minimum MPU region size.\n" \ + "The start address of the partition must align with size.") diff --git a/include/zephyr/arch/arm/mpu/arm_mpu_v8.h b/include/zephyr/arch/arm/mpu/arm_mpu_v8.h index 77deb64beed66..0f13bee99be4c 100644 --- a/include/zephyr/arch/arm/mpu/arm_mpu_v8.h +++ b/include/zephyr/arch/arm/mpu/arm_mpu_v8.h @@ -12,25 +12,25 @@ * cache-ability attribution. */ #if defined(CONFIG_AARCH32_ARMV8_R) -#define MPU_IR_REGION_Msk (0xFFU) -#define MPU_IR_REGION_Pos 8U +#define MPU_IR_REGION_Msk (0xFFU) +#define MPU_IR_REGION_Pos 8U /* MPU RBAR Register attribute msk Definitions */ -#define MPU_RBAR_BASE_Pos 6U -#define MPU_RBAR_BASE_Msk (0x3FFFFFFFFFFFFFFUL << MPU_RBAR_BASE_Pos) -#define MPU_RBAR_SH_Pos 3U -#define MPU_RBAR_SH_Msk (0x3UL << MPU_RBAR_SH_Pos) -#define MPU_RBAR_AP_Pos 1U -#define MPU_RBAR_AP_Msk (0x3UL << MPU_RBAR_AP_Pos) +#define MPU_RBAR_BASE_Pos 6U +#define MPU_RBAR_BASE_Msk (0x3FFFFFFFFFFFFFFUL << MPU_RBAR_BASE_Pos) +#define MPU_RBAR_SH_Pos 3U +#define MPU_RBAR_SH_Msk (0x3UL << MPU_RBAR_SH_Pos) +#define MPU_RBAR_AP_Pos 1U +#define MPU_RBAR_AP_Msk (0x3UL << MPU_RBAR_AP_Pos) /* RBAR XN */ -#define MPU_RBAR_XN_Pos 0U -#define MPU_RBAR_XN_Msk (0x1UL << MPU_RBAR_XN_Pos) +#define MPU_RBAR_XN_Pos 0U +#define MPU_RBAR_XN_Msk (0x1UL << MPU_RBAR_XN_Pos) /* MPU PLBAR Register Definitions */ -#define MPU_RLAR_LIMIT_Pos 6U -#define MPU_RLAR_LIMIT_Msk (0x3FFFFFFFFFFFFFFUL << MPU_RLAR_LIMIT_Pos) -#define MPU_RLAR_AttrIndx_Pos 1U -#define MPU_RLAR_AttrIndx_Msk (0x7UL << MPU_RLAR_AttrIndx_Pos) -#define MPU_RLAR_EN_Msk (0x1UL) +#define MPU_RLAR_LIMIT_Pos 6U +#define MPU_RLAR_LIMIT_Msk (0x3FFFFFFFFFFFFFFUL << MPU_RLAR_LIMIT_Pos) +#define MPU_RLAR_AttrIndx_Pos 1U +#define MPU_RLAR_AttrIndx_Msk (0x7UL << MPU_RLAR_AttrIndx_Pos) +#define MPU_RLAR_EN_Msk (0x1UL) #else #include #endif @@ -68,18 +68,14 @@ /* Attribute flags for share-ability */ #define NON_SHAREABLE 0x0 -#define NON_SHAREABLE_Msk \ - ((NON_SHAREABLE << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) -#define OUTER_SHAREABLE 0x2 -#define OUTER_SHAREABLE_Msk \ - ((OUTER_SHAREABLE << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) -#define INNER_SHAREABLE 0x3 -#define INNER_SHAREABLE_Msk \ - ((INNER_SHAREABLE << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) +#define NON_SHAREABLE_Msk ((NON_SHAREABLE << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) +#define OUTER_SHAREABLE 0x2 +#define OUTER_SHAREABLE_Msk ((OUTER_SHAREABLE << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) +#define INNER_SHAREABLE 0x3 +#define INNER_SHAREABLE_Msk ((INNER_SHAREABLE << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) /* Helper define to calculate the region limit address. */ -#define REGION_LIMIT_ADDR(base, size) \ - (((base & MPU_RBAR_BASE_Msk) + size - 1) & MPU_RLAR_LIMIT_Msk) +#define REGION_LIMIT_ADDR(base, size) (((base & MPU_RBAR_BASE_Msk) + size - 1) & MPU_RLAR_LIMIT_Msk) /* Attribute flags for cache-ability */ @@ -101,10 +97,10 @@ * nE: The response should come from the end slave, not buffering in * the interconnect. */ -#define DEVICE_nGnRnE 0x0U -#define DEVICE_nGnRE 0x4U -#define DEVICE_nGRE 0x8U -#define DEVICE_GRE 0xCU +#define DEVICE_nGnRnE 0x0U +#define DEVICE_nGnRE 0x4U +#define DEVICE_nGRE 0x8U +#define DEVICE_GRE 0xCU /* Read/Write Allocation Configurations for Cacheable Memory */ #define R_NON_W_NON 0x0 /* Do not allocate Read/Write */ @@ -113,36 +109,30 @@ #define R_ALLOC_W_ALLOC 0x3 /* Allocate Read/Write */ /* Memory Attributes for Normal Memory */ -#define NORMAL_O_WT_NT 0x80 /* Normal, Outer Write-through non-transient */ -#define NORMAL_O_WB_NT 0xC0 /* Normal, Outer Write-back non-transient */ -#define NORMAL_O_NON_C 0x40 /* Normal, Outer Non-Cacheable */ +#define NORMAL_O_WT_NT 0x80 /* Normal, Outer Write-through non-transient */ +#define NORMAL_O_WB_NT 0xC0 /* Normal, Outer Write-back non-transient */ +#define NORMAL_O_NON_C 0x40 /* Normal, Outer Non-Cacheable */ -#define NORMAL_I_WT_NT 0x08 /* Normal, Inner Write-through non-transient */ -#define NORMAL_I_WB_NT 0x0C /* Normal, Inner Write-back non-transient */ -#define NORMAL_I_NON_C 0x04 /* Normal, Inner Non-Cacheable */ +#define NORMAL_I_WT_NT 0x08 /* Normal, Inner Write-through non-transient */ +#define NORMAL_I_WB_NT 0x0C /* Normal, Inner Write-back non-transient */ +#define NORMAL_I_NON_C 0x04 /* Normal, Inner Non-Cacheable */ -#define NORMAL_OUTER_INNER_WRITE_THROUGH_READ_ALLOCATE_NON_TRANS \ - ((NORMAL_O_WT_NT | (R_ALLOC_W_NON << 4)) \ - | \ - (NORMAL_I_WT_NT | R_ALLOC_W_NON)) \ +#define NORMAL_OUTER_INNER_WRITE_THROUGH_READ_ALLOCATE_NON_TRANS \ + ((NORMAL_O_WT_NT | (R_ALLOC_W_NON << 4)) | (NORMAL_I_WT_NT | R_ALLOC_W_NON)) -#define NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_TRANS \ - ((NORMAL_O_WB_NT | (R_ALLOC_W_ALLOC << 4)) \ - | \ - (NORMAL_I_WB_NT | R_ALLOC_W_ALLOC)) +#define NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_TRANS \ + ((NORMAL_O_WB_NT | (R_ALLOC_W_ALLOC << 4)) | (NORMAL_I_WB_NT | R_ALLOC_W_ALLOC)) -#define NORMAL_OUTER_INNER_NON_CACHEABLE \ - ((NORMAL_O_NON_C | (R_NON_W_NON << 4)) \ - | \ - (NORMAL_I_NON_C | R_NON_W_NON)) +#define NORMAL_OUTER_INNER_NON_CACHEABLE \ + ((NORMAL_O_NON_C | (R_NON_W_NON << 4)) | (NORMAL_I_NON_C | R_NON_W_NON)) /* Common cache-ability configuration for Flash, SRAM regions */ -#define MPU_CACHE_ATTRIBUTES_FLASH \ - NORMAL_OUTER_INNER_WRITE_THROUGH_READ_ALLOCATE_NON_TRANS -#define MPU_CACHE_ATTRIBUTES_SRAM \ +#define MPU_CACHE_ATTRIBUTES_FLASH NORMAL_OUTER_INNER_WRITE_THROUGH_READ_ALLOCATE_NON_TRANS +/* clang-format off */ +#define MPU_CACHE_ATTRIBUTES_SRAM \ NORMAL_OUTER_INNER_WRITE_BACK_WRITE_READ_ALLOCATE_NON_TRANS -#define MPU_CACHE_ATTRIBUTES_SRAM_NOCACHE \ - NORMAL_OUTER_INNER_NON_CACHEABLE +/* clang-format on */ +#define MPU_CACHE_ATTRIBUTES_SRAM_NOCACHE NORMAL_OUTER_INNER_NON_CACHEABLE /* Global MAIR configurations */ #define MPU_MAIR_ATTR_FLASH MPU_CACHE_ATTRIBUTES_FLASH @@ -158,10 +148,10 @@ * SRAM no cache-able regions(s): Attribute-2 * DEVICE no cache-able regions(s): Attribute-3 */ -#define MPU_MAIR_ATTRS \ - ((MPU_MAIR_ATTR_FLASH << (MPU_MAIR_INDEX_FLASH * 8)) | \ - (MPU_MAIR_ATTR_SRAM << (MPU_MAIR_INDEX_SRAM * 8)) | \ - (MPU_MAIR_ATTR_SRAM_NOCACHE << (MPU_MAIR_INDEX_SRAM_NOCACHE * 8)) | \ +#define MPU_MAIR_ATTRS \ + ((MPU_MAIR_ATTR_FLASH << (MPU_MAIR_INDEX_FLASH * 8)) | \ + (MPU_MAIR_ATTR_SRAM << (MPU_MAIR_INDEX_SRAM * 8)) | \ + (MPU_MAIR_ATTR_SRAM_NOCACHE << (MPU_MAIR_INDEX_SRAM_NOCACHE * 8)) | \ (MPU_MAIR_ATTR_DEVICE << (MPU_MAIR_INDEX_DEVICE * 8))) /* Some helper defines for common regions. @@ -175,132 +165,118 @@ */ #if defined(CONFIG_AARCH32_ARMV8_R) -#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \ - { .name = p_name, \ - .base = p_base, \ - .attr = p_attr(p_base + p_size), \ +#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \ + { \ + .name = p_name, \ + .base = p_base, \ + .attr = p_attr(p_base + p_size), \ } -#define REGION_RAM_ATTR(limit) \ - { \ - .rbar = NOT_EXEC | \ - P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_SRAM, \ - .r_limit = limit - 1, /* Region Limit */ \ +#define REGION_RAM_ATTR(limit) \ + { \ + .rbar = NOT_EXEC | P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_SRAM, /* Cache-ability */ \ + .r_limit = limit - 1, /* Region Limit */ \ } -#define REGION_RAM_TEXT_ATTR(limit) \ - { \ - .rbar = P_RO_U_RO_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_SRAM, \ - .r_limit = limit - 1, /* Region Limit */ \ +#define REGION_RAM_TEXT_ATTR(limit) \ + { \ + .rbar = P_RO_U_RO_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_SRAM, /* Cache-ability */ \ + .r_limit = limit - 1, /* Region Limit */ \ } -#define REGION_RAM_RO_ATTR(limit) \ - { \ - .rbar = NOT_EXEC | \ - P_RO_U_RO_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_SRAM, \ - .r_limit = limit - 1, /* Region Limit */ \ +#define REGION_RAM_RO_ATTR(limit) \ + { \ + .rbar = NOT_EXEC | P_RO_U_RO_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_SRAM, /* Cache-ability */ \ + .r_limit = limit - 1, /* Region Limit */ \ } -#define REGION_RAM_NOCACHE_ATTR(limit) \ - { \ - .rbar = NOT_EXEC | \ - P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_SRAM_NOCACHE, \ - .r_limit = limit - 1, /* Region Limit */ \ +#define REGION_RAM_NOCACHE_ATTR(limit) \ + { \ + .rbar = NOT_EXEC | P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_SRAM_NOCACHE, /* Cache-ability */ \ + .r_limit = limit - 1, /* Region Limit */ \ } #if defined(CONFIG_MPU_ALLOW_FLASH_WRITE) /* Note that the access permissions allow for un-privileged writes, contrary * to ARMv7-M where un-privileged code has Read-Only permissions. */ -#define REGION_FLASH_ATTR(limit) \ - { \ - .rbar = P_RW_U_RW_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_FLASH, \ - .r_limit = limit - 1, /* Region Limit */ \ +#define REGION_FLASH_ATTR(limit) \ + { \ + .rbar = P_RW_U_RW_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_FLASH, /* Cache-ability */ \ + .r_limit = limit - 1, /* Region Limit */ \ } #else /* CONFIG_MPU_ALLOW_FLASH_WRITE */ -#define REGION_FLASH_ATTR(limit) \ - { \ - .rbar = RO_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_FLASH, \ - .r_limit = limit - 1, /* Region Limit */ \ +#define REGION_FLASH_ATTR(limit) \ + { \ + .rbar = RO_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_FLASH, /* Cache-ability */ \ + .r_limit = limit - 1, /* Region Limit */ \ } #endif /* CONFIG_MPU_ALLOW_FLASH_WRITE */ -#define REGION_DEVICE_ATTR(limit) \ - { \ - /* AP, XN, SH */ \ - .rbar = NOT_EXEC | P_RW_U_NA_Msk | NON_SHAREABLE_Msk, \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_DEVICE, \ - /* Region Limit */ \ - .r_limit = limit - 1, \ +#define REGION_DEVICE_ATTR(limit) \ + { \ + .rbar = NOT_EXEC | P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_DEVICE, /* Cache-ability */ \ + .r_limit = limit - 1, /* Region Limit */ \ } #else -#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \ - { .name = p_name, \ - .base = p_base, \ - .attr = p_attr(p_base, p_size), \ +#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \ + { \ + .name = p_name, \ + .base = p_base, \ + .attr = p_attr(p_base, p_size), \ } /* On Cortex-M, we can only set the XN bit when CONFIG_XIP=y. When * CONFIG_XIP=n, the entire image will be linked to SRAM, so we need to keep * the SRAM region XN bit clear or the application code will not be executable. */ -#define REGION_RAM_ATTR(base, size) \ - {\ - .rbar = IF_ENABLED(CONFIG_XIP, (NOT_EXEC |)) \ - P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_SRAM, \ - .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ +/* clang-format off */ +#define REGION_RAM_ATTR(base, size) \ + { \ + .rbar = IF_ENABLED(CONFIG_XIP, (NOT_EXEC |)) P_RW_U_NA_Msk | \ + NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_SRAM, /* Cache-ability */ \ + .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ } +/* clang-format on */ -#define REGION_RAM_NOCACHE_ATTR(base, size) \ - {\ - .rbar = NOT_EXEC | \ - P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_SRAM_NOCACHE, \ - .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ +#define REGION_RAM_NOCACHE_ATTR(base, size) \ + { \ + .rbar = NOT_EXEC | P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_SRAM_NOCACHE, /* Cache-ability */ \ + .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ } #if defined(CONFIG_MPU_ALLOW_FLASH_WRITE) /* Note that the access permissions allow for un-privileged writes, contrary * to ARMv7-M where un-privileged code has Read-Only permissions. */ -#define REGION_FLASH_ATTR(base, size) \ - {\ - .rbar = P_RW_U_RW_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_FLASH, \ - .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ +#define REGION_FLASH_ATTR(base, size) \ + { \ + .rbar = P_RW_U_RW_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_FLASH, /* Cache-ability */ \ + .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ } #else /* CONFIG_MPU_ALLOW_FLASH_WRITE */ -#define REGION_FLASH_ATTR(base, size) \ - {\ - .rbar = RO_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ - /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_FLASH, \ - .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ +#define REGION_FLASH_ATTR(base, size) \ + { \ + .rbar = RO_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_FLASH, /* Cache-ability */ \ + .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ } #endif /* CONFIG_MPU_ALLOW_FLASH_WRITE */ #define REGION_DEVICE_ATTR(base, size) \ { \ - /* AP, XN, SH */ \ - .rbar = NOT_EXEC | P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* Cache-ability */ \ - .mair_idx = MPU_MAIR_INDEX_DEVICE, \ - .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ + .rbar = NOT_EXEC | P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + .mair_idx = MPU_MAIR_INDEX_DEVICE, /* Cache-ability */ \ + .r_limit = REGION_LIMIT_ADDR(base, size), /* Region Limit */ \ } #endif @@ -333,20 +309,18 @@ typedef struct { */ /* Read-Write access permission attributes */ -#define K_MEM_PARTITION_P_RW_U_RW ((k_mem_partition_attr_t) \ - {(P_RW_U_RW_Msk | NOT_EXEC), MPU_MAIR_INDEX_SRAM}) -#define K_MEM_PARTITION_P_RW_U_NA ((k_mem_partition_attr_t) \ - {(P_RW_U_NA_Msk | NOT_EXEC), MPU_MAIR_INDEX_SRAM}) -#define K_MEM_PARTITION_P_RO_U_RO ((k_mem_partition_attr_t) \ - {(P_RO_U_RO_Msk | NOT_EXEC), MPU_MAIR_INDEX_SRAM}) -#define K_MEM_PARTITION_P_RO_U_NA ((k_mem_partition_attr_t) \ - {(P_RO_U_NA_Msk | NOT_EXEC), MPU_MAIR_INDEX_SRAM}) +#define K_MEM_PARTITION_P_RW_U_RW \ + ((k_mem_partition_attr_t){(P_RW_U_RW_Msk | NOT_EXEC), MPU_MAIR_INDEX_SRAM}) +#define K_MEM_PARTITION_P_RW_U_NA \ + ((k_mem_partition_attr_t){(P_RW_U_NA_Msk | NOT_EXEC), MPU_MAIR_INDEX_SRAM}) +#define K_MEM_PARTITION_P_RO_U_RO \ + ((k_mem_partition_attr_t){(P_RO_U_RO_Msk | NOT_EXEC), MPU_MAIR_INDEX_SRAM}) +#define K_MEM_PARTITION_P_RO_U_NA \ + ((k_mem_partition_attr_t){(P_RO_U_NA_Msk | NOT_EXEC), MPU_MAIR_INDEX_SRAM}) /* Execution-allowed attributes */ -#define K_MEM_PARTITION_P_RWX_U_RWX ((k_mem_partition_attr_t) \ - {(P_RW_U_RW_Msk), MPU_MAIR_INDEX_SRAM}) -#define K_MEM_PARTITION_P_RX_U_RX ((k_mem_partition_attr_t) \ - {(P_RO_U_RO_Msk), MPU_MAIR_INDEX_SRAM}) +#define K_MEM_PARTITION_P_RWX_U_RWX ((k_mem_partition_attr_t){(P_RW_U_RW_Msk), MPU_MAIR_INDEX_SRAM}) +#define K_MEM_PARTITION_P_RX_U_RX ((k_mem_partition_attr_t){(P_RO_U_RO_Msk), MPU_MAIR_INDEX_SRAM}) /* * @brief Evaluate Write-ability @@ -356,18 +330,18 @@ typedef struct { * @param attr The k_mem_partition_attr_t object holding the * MPU attributes to be checked against write-ability. */ -#define K_MEM_PARTITION_IS_WRITABLE(attr) \ - ({ \ - int __is_writable__; \ - switch (attr.rbar & MPU_RBAR_AP_Msk) { \ - case P_RW_U_RW_Msk: \ - case P_RW_U_NA_Msk: \ - __is_writable__ = 1; \ - break; \ - default: \ - __is_writable__ = 0; \ - } \ - __is_writable__; \ +#define K_MEM_PARTITION_IS_WRITABLE(attr) \ + ({ \ + int __is_writable__; \ + switch (attr.rbar & MPU_RBAR_AP_Msk) { \ + case P_RW_U_RW_Msk: \ + case P_RW_U_NA_Msk: \ + __is_writable__ = 1; \ + break; \ + default: \ + __is_writable__ = 0; \ + } \ + __is_writable__; \ }) /* @@ -379,36 +353,37 @@ typedef struct { * MPU attributes to be checked against execution * allowance. */ -#define K_MEM_PARTITION_IS_EXECUTABLE(attr) \ - (!((attr.rbar) & (NOT_EXEC))) +#define K_MEM_PARTITION_IS_EXECUTABLE(attr) (!((attr.rbar) & (NOT_EXEC))) /* Attributes for no-cache enabling (share-ability is selected by default) */ /* Read-Write access permission attributes */ -#define K_MEM_PARTITION_P_RW_U_RW_NOCACHE ((k_mem_partition_attr_t) \ - {(P_RW_U_RW_Msk | NOT_EXEC | OUTER_SHAREABLE_Msk), \ - MPU_MAIR_INDEX_SRAM_NOCACHE}) -#define K_MEM_PARTITION_P_RW_U_NA_NOCACHE ((k_mem_partition_attr_t) \ - {(P_RW_U_NA_Msk | NOT_EXEC | OUTER_SHAREABLE_Msk), \ - MPU_MAIR_INDEX_SRAM_NOCACHE}) -#define K_MEM_PARTITION_P_RO_U_RO_NOCACHE ((k_mem_partition_attr_t) \ - {(P_RO_U_RO_Msk | NOT_EXEC | OUTER_SHAREABLE_Msk), \ - MPU_MAIR_INDEX_SRAM_NOCACHE}) -#define K_MEM_PARTITION_P_RO_U_NA_NOCACHE ((k_mem_partition_attr_t) \ - {(P_RO_U_NA_Msk | NOT_EXEC | OUTER_SHAREABLE_Msk), \ - MPU_MAIR_INDEX_SRAM_NOCACHE}) +#define K_MEM_PARTITION_P_RW_U_RW_NOCACHE \ + ((k_mem_partition_attr_t){(P_RW_U_RW_Msk | NOT_EXEC | OUTER_SHAREABLE_Msk), \ + MPU_MAIR_INDEX_SRAM_NOCACHE}) +#define K_MEM_PARTITION_P_RW_U_NA_NOCACHE \ + ((k_mem_partition_attr_t){(P_RW_U_NA_Msk | NOT_EXEC | OUTER_SHAREABLE_Msk), \ + MPU_MAIR_INDEX_SRAM_NOCACHE}) +#define K_MEM_PARTITION_P_RO_U_RO_NOCACHE \ + ((k_mem_partition_attr_t){(P_RO_U_RO_Msk | NOT_EXEC | OUTER_SHAREABLE_Msk), \ + MPU_MAIR_INDEX_SRAM_NOCACHE}) +#define K_MEM_PARTITION_P_RO_U_NA_NOCACHE \ + ((k_mem_partition_attr_t){(P_RO_U_NA_Msk | NOT_EXEC | OUTER_SHAREABLE_Msk), \ + MPU_MAIR_INDEX_SRAM_NOCACHE}) /* Execution-allowed attributes */ -#define K_MEM_PARTITION_P_RWX_U_RWX_NOCACHE ((k_mem_partition_attr_t) \ - {(P_RW_U_RW_Msk | OUTER_SHAREABLE_Msk), MPU_MAIR_INDEX_SRAM_NOCACHE}) -#define K_MEM_PARTITION_P_RX_U_RX_NOCACHE ((k_mem_partition_attr_t) \ - {(P_RO_U_RO_Msk | OUTER_SHAREABLE_Msk), MPU_MAIR_INDEX_SRAM_NOCACHE}) +#define K_MEM_PARTITION_P_RWX_U_RWX_NOCACHE \ + ((k_mem_partition_attr_t){(P_RW_U_RW_Msk | OUTER_SHAREABLE_Msk), \ + MPU_MAIR_INDEX_SRAM_NOCACHE}) +#define K_MEM_PARTITION_P_RX_U_RX_NOCACHE \ + ((k_mem_partition_attr_t){(P_RO_U_RO_Msk | OUTER_SHAREABLE_Msk), \ + MPU_MAIR_INDEX_SRAM_NOCACHE}) #endif /* _ASMLANGUAGE */ -#define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size) \ - BUILD_ASSERT((size > 0) && ((uint32_t)start % \ - CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0U) && \ - ((size) % CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0), \ - " the start and size of the partition must align " \ - "with the minimum MPU region size.") +#define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size) \ + BUILD_ASSERT((size > 0) && \ + ((uint32_t)start % CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0U) && \ + ((size) % CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0), \ + "The start and size of the partition must align with the minimum MPU " \ + "region size.") diff --git a/include/zephyr/arch/arm/mpu/nxp_mpu.h b/include/zephyr/arch/arm/mpu/nxp_mpu.h index b95565658027c..b1bc9c2e4510b 100644 --- a/include/zephyr/arch/arm/mpu/nxp_mpu.h +++ b/include/zephyr/arch/arm/mpu/nxp_mpu.h @@ -11,119 +11,102 @@ #define NXP_MPU_REGION_NUMBER 12 /* Bus Master User Mode Access */ -#define UM_READ 4 -#define UM_WRITE 2 -#define UM_EXEC 1 +#define UM_READ 4 +#define UM_WRITE 2 +#define UM_EXEC 1 -#define BM0_UM_SHIFT 0 -#define BM1_UM_SHIFT 6 -#define BM2_UM_SHIFT 12 -#define BM3_UM_SHIFT 18 +#define BM0_UM_SHIFT 0 +#define BM1_UM_SHIFT 6 +#define BM2_UM_SHIFT 12 +#define BM3_UM_SHIFT 18 /* Bus Master Supervisor Mode Access */ -#define SM_RWX_ALLOW 0 -#define SM_RX_ALLOW 1 -#define SM_RW_ALLOW 2 -#define SM_SAME_AS_UM 3 +#define SM_RWX_ALLOW 0 +#define SM_RX_ALLOW 1 +#define SM_RW_ALLOW 2 +#define SM_SAME_AS_UM 3 -#define BM0_SM_SHIFT 3 -#define BM1_SM_SHIFT 9 -#define BM2_SM_SHIFT 15 -#define BM3_SM_SHIFT 21 +#define BM0_SM_SHIFT 3 +#define BM1_SM_SHIFT 9 +#define BM2_SM_SHIFT 15 +#define BM3_SM_SHIFT 21 -#define BM4_WE_SHIFT 24 -#define BM4_RE_SHIFT 25 +#define BM4_WE_SHIFT 24 +#define BM4_RE_SHIFT 25 #if CONFIG_USB_KINETIS || CONFIG_UDC_KINETIS -#define BM4_PERMISSIONS ((1 << BM4_RE_SHIFT) | (1 << BM4_WE_SHIFT)) +#define BM4_PERMISSIONS ((1 << BM4_RE_SHIFT) | (1 << BM4_WE_SHIFT)) #else -#define BM4_PERMISSIONS 0 +#define BM4_PERMISSIONS 0 #endif /* Read Attribute */ -#define MPU_REGION_READ ((UM_READ << BM0_UM_SHIFT) | \ - (UM_READ << BM1_UM_SHIFT) | \ - (UM_READ << BM2_UM_SHIFT) | \ - (UM_READ << BM3_UM_SHIFT)) +#define MPU_REGION_READ \ + ((UM_READ << BM0_UM_SHIFT) | (UM_READ << BM1_UM_SHIFT) | (UM_READ << BM2_UM_SHIFT) | \ + (UM_READ << BM3_UM_SHIFT)) /* Write Attribute */ -#define MPU_REGION_WRITE ((UM_WRITE << BM0_UM_SHIFT) | \ - (UM_WRITE << BM1_UM_SHIFT) | \ - (UM_WRITE << BM2_UM_SHIFT) | \ - (UM_WRITE << BM3_UM_SHIFT)) +#define MPU_REGION_WRITE \ + ((UM_WRITE << BM0_UM_SHIFT) | (UM_WRITE << BM1_UM_SHIFT) | (UM_WRITE << BM2_UM_SHIFT) | \ + (UM_WRITE << BM3_UM_SHIFT)) /* Execute Attribute */ -#define MPU_REGION_EXEC ((UM_EXEC << BM0_UM_SHIFT) | \ - (UM_EXEC << BM1_UM_SHIFT) | \ - (UM_EXEC << BM2_UM_SHIFT) | \ - (UM_EXEC << BM3_UM_SHIFT)) +#define MPU_REGION_EXEC \ + ((UM_EXEC << BM0_UM_SHIFT) | (UM_EXEC << BM1_UM_SHIFT) | (UM_EXEC << BM2_UM_SHIFT) | \ + (UM_EXEC << BM3_UM_SHIFT)) /* Super User Attributes */ -#define MPU_REGION_SU ((SM_SAME_AS_UM << BM0_SM_SHIFT) | \ - (SM_SAME_AS_UM << BM1_SM_SHIFT) | \ - (SM_SAME_AS_UM << BM2_SM_SHIFT) | \ - (SM_SAME_AS_UM << BM3_SM_SHIFT)) - -#define MPU_REGION_SU_RX ((SM_RX_ALLOW << BM0_SM_SHIFT) | \ - (SM_RX_ALLOW << BM1_SM_SHIFT) | \ - (SM_RX_ALLOW << BM2_SM_SHIFT) | \ - (SM_RX_ALLOW << BM3_SM_SHIFT)) - -#define MPU_REGION_SU_RW ((SM_RW_ALLOW << BM0_SM_SHIFT) | \ - (SM_RW_ALLOW << BM1_SM_SHIFT) | \ - (SM_RW_ALLOW << BM2_SM_SHIFT) | \ - (SM_RW_ALLOW << BM3_SM_SHIFT)) - -#define MPU_REGION_SU_RWX ((SM_RWX_ALLOW << BM0_SM_SHIFT) | \ - (SM_RWX_ALLOW << BM1_SM_SHIFT) | \ - (SM_RWX_ALLOW << BM2_SM_SHIFT) | \ - (SM_RWX_ALLOW << BM3_SM_SHIFT)) +#define MPU_REGION_SU \ + ((SM_SAME_AS_UM << BM0_SM_SHIFT) | (SM_SAME_AS_UM << BM1_SM_SHIFT) | \ + (SM_SAME_AS_UM << BM2_SM_SHIFT) | (SM_SAME_AS_UM << BM3_SM_SHIFT)) + +#define MPU_REGION_SU_RX \ + ((SM_RX_ALLOW << BM0_SM_SHIFT) | (SM_RX_ALLOW << BM1_SM_SHIFT) | \ + (SM_RX_ALLOW << BM2_SM_SHIFT) | (SM_RX_ALLOW << BM3_SM_SHIFT)) + +#define MPU_REGION_SU_RW \ + ((SM_RW_ALLOW << BM0_SM_SHIFT) | (SM_RW_ALLOW << BM1_SM_SHIFT) | \ + (SM_RW_ALLOW << BM2_SM_SHIFT) | (SM_RW_ALLOW << BM3_SM_SHIFT)) + +#define MPU_REGION_SU_RWX \ + ((SM_RWX_ALLOW << BM0_SM_SHIFT) | (SM_RWX_ALLOW << BM1_SM_SHIFT) | \ + (SM_RWX_ALLOW << BM2_SM_SHIFT) | (SM_RWX_ALLOW << BM3_SM_SHIFT)) /* The ENDADDR field has the last 5 bit reserved and set to 1 */ #define ENDADDR_ROUND(x) (x - 0x1F) -#define REGION_USER_MODE_ATTR {(MPU_REGION_READ | \ - MPU_REGION_WRITE | \ - MPU_REGION_SU)} +#define REGION_USER_MODE_ATTR {(MPU_REGION_READ | MPU_REGION_WRITE | MPU_REGION_SU)} /* Some helper defines for common regions */ #if defined(CONFIG_MPU_ALLOW_FLASH_WRITE) -#define REGION_RAM_ATTR {((MPU_REGION_SU_RWX) | \ - ((UM_READ | UM_WRITE | UM_EXEC) << BM3_UM_SHIFT) | \ - (BM4_PERMISSIONS))} +#define REGION_RAM_ATTR \ + {((MPU_REGION_SU_RWX) | ((UM_READ | UM_WRITE | UM_EXEC) << BM3_UM_SHIFT) | \ + (BM4_PERMISSIONS))} #define REGION_FLASH_ATTR {(MPU_REGION_SU_RWX)} #else -#define REGION_RAM_ATTR {((MPU_REGION_SU_RW) | \ - ((UM_READ | UM_WRITE) << BM3_UM_SHIFT) | \ - (BM4_PERMISSIONS))} +#define REGION_RAM_ATTR \ + {((MPU_REGION_SU_RW) | ((UM_READ | UM_WRITE) << BM3_UM_SHIFT) | (BM4_PERMISSIONS))} -#define REGION_FLASH_ATTR {(MPU_REGION_READ | \ - MPU_REGION_EXEC | \ - MPU_REGION_SU)} +#define REGION_FLASH_ATTR {(MPU_REGION_READ | MPU_REGION_EXEC | MPU_REGION_SU)} #endif -#define REGION_IO_ATTR {(MPU_REGION_READ | \ - MPU_REGION_WRITE | \ - MPU_REGION_EXEC | \ - MPU_REGION_SU)} +#define REGION_IO_ATTR {(MPU_REGION_READ | MPU_REGION_WRITE | MPU_REGION_EXEC | MPU_REGION_SU)} -#define REGION_RO_ATTR {(MPU_REGION_READ | MPU_REGION_SU)} +#define REGION_RO_ATTR {(MPU_REGION_READ | MPU_REGION_SU)} -#define REGION_USER_RO_ATTR {(MPU_REGION_READ | \ - MPU_REGION_SU)} +#define REGION_USER_RO_ATTR {(MPU_REGION_READ | MPU_REGION_SU)} /* ENET (Master 3) and USB (Master 4) devices will not be able to access RAM when the region is dynamically disabled in NXP MPU. DEBUGGER (Master 1) can't be disabled in Region 0. */ -#define REGION_DEBUGGER_AND_DEVICE_ATTR {((MPU_REGION_SU) | \ - ((UM_READ | UM_WRITE) << BM3_UM_SHIFT) | \ - (BM4_PERMISSIONS))} +#define REGION_DEBUGGER_AND_DEVICE_ATTR \ + {((MPU_REGION_SU) | ((UM_READ | UM_WRITE) << BM3_UM_SHIFT) | (BM4_PERMISSIONS))} -#define REGION_DEBUG_ATTR {MPU_REGION_SU} +#define REGION_DEBUG_ATTR {MPU_REGION_SU} -#define REGION_BACKGROUND_ATTR {MPU_REGION_SU_RW} +#define REGION_BACKGROUND_ATTR {MPU_REGION_SU_RW} struct nxp_mpu_region_attr { /* NXP MPU region access permission attributes */ @@ -145,27 +128,22 @@ typedef struct { */ /* Read-Write access permission attributes */ -#define K_MEM_PARTITION_P_NA_U_NA ((k_mem_partition_attr_t) \ - {(MPU_REGION_SU)}) -#define K_MEM_PARTITION_P_RW_U_RW ((k_mem_partition_attr_t) \ - {(MPU_REGION_READ | MPU_REGION_WRITE | MPU_REGION_SU)}) -#define K_MEM_PARTITION_P_RW_U_RO ((k_mem_partition_attr_t) \ - {(MPU_REGION_READ | MPU_REGION_SU_RW)}) -#define K_MEM_PARTITION_P_RW_U_NA ((k_mem_partition_attr_t) \ - {(MPU_REGION_SU_RW)}) -#define K_MEM_PARTITION_P_RO_U_RO ((k_mem_partition_attr_t) \ - {(MPU_REGION_READ | MPU_REGION_SU)}) -#define K_MEM_PARTITION_P_RO_U_NA ((k_mem_partition_attr_t) \ - {(MPU_REGION_SU_RX)}) +#define K_MEM_PARTITION_P_NA_U_NA ((k_mem_partition_attr_t){(MPU_REGION_SU)}) +#define K_MEM_PARTITION_P_RW_U_RW \ + ((k_mem_partition_attr_t){(MPU_REGION_READ | MPU_REGION_WRITE | MPU_REGION_SU)}) +#define K_MEM_PARTITION_P_RW_U_RO ((k_mem_partition_attr_t){(MPU_REGION_READ | MPU_REGION_SU_RW)}) +#define K_MEM_PARTITION_P_RW_U_NA ((k_mem_partition_attr_t){(MPU_REGION_SU_RW)}) +#define K_MEM_PARTITION_P_RO_U_RO ((k_mem_partition_attr_t){(MPU_REGION_READ | MPU_REGION_SU)}) +#define K_MEM_PARTITION_P_RO_U_NA ((k_mem_partition_attr_t){(MPU_REGION_SU_RX)}) /* Execution-allowed attributes */ -#define K_MEM_PARTITION_P_RWX_U_RWX ((k_mem_partition_attr_t) \ - {(MPU_REGION_READ | MPU_REGION_WRITE | \ - MPU_REGION_EXEC | MPU_REGION_SU)}) -#define K_MEM_PARTITION_P_RWX_U_RX ((k_mem_partition_attr_t) \ - {(MPU_REGION_READ | MPU_REGION_EXEC | MPU_REGION_SU_RWX)}) -#define K_MEM_PARTITION_P_RX_U_RX ((k_mem_partition_attr_t) \ - {(MPU_REGION_READ | MPU_REGION_EXEC | MPU_REGION_SU)}) +#define K_MEM_PARTITION_P_RWX_U_RWX \ + ((k_mem_partition_attr_t){ \ + (MPU_REGION_READ | MPU_REGION_WRITE | MPU_REGION_EXEC | MPU_REGION_SU)}) +#define K_MEM_PARTITION_P_RWX_U_RX \ + ((k_mem_partition_attr_t){(MPU_REGION_READ | MPU_REGION_EXEC | MPU_REGION_SU_RWX)}) +#define K_MEM_PARTITION_P_RX_U_RX \ + ((k_mem_partition_attr_t){(MPU_REGION_READ | MPU_REGION_EXEC | MPU_REGION_SU)}) /* * @brief Evaluate Write-ability @@ -175,18 +153,18 @@ typedef struct { * @param attr The k_mem_partition_attr_t object holding the * MPU attributes to be checked against write-ability. */ -#define K_MEM_PARTITION_IS_WRITABLE(attr) \ - ({ \ - int __is_writable__; \ - switch (attr.ap_attr) { \ - case MPU_REGION_WRITE: \ - case MPU_REGION_SU_RW: \ - __is_writable__ = 1; \ - break; \ - default: \ - __is_writable__ = 0; \ - } \ - __is_writable__; \ +#define K_MEM_PARTITION_IS_WRITABLE(attr) \ + ({ \ + int __is_writable__; \ + switch (attr.ap_attr) { \ + case MPU_REGION_WRITE: \ + case MPU_REGION_SU_RW: \ + __is_writable__ = 1; \ + break; \ + default: \ + __is_writable__ = 0; \ + } \ + __is_writable__; \ }) /* @@ -198,21 +176,20 @@ typedef struct { * MPU attributes to be checked against execution * allowance. */ -#define K_MEM_PARTITION_IS_EXECUTABLE(attr) \ - ({ \ - int __is_executable__; \ - switch (attr.ap_attr) { \ - case MPU_REGION_SU_RX: \ - case MPU_REGION_EXEC: \ - __is_executable__ = 1; \ - break; \ - default: \ - __is_executable__ = 0; \ - } \ - __is_executable__; \ +#define K_MEM_PARTITION_IS_EXECUTABLE(attr) \ + ({ \ + int __is_executable__; \ + switch (attr.ap_attr) { \ + case MPU_REGION_SU_RX: \ + case MPU_REGION_EXEC: \ + __is_executable__ = 1; \ + break; \ + default: \ + __is_executable__ = 0; \ + } \ + __is_executable__; \ }) - /* Region definition data structure */ struct nxp_mpu_region { /* Region Base Address */ @@ -225,12 +202,12 @@ struct nxp_mpu_region { nxp_mpu_region_attr_t attr; }; -#define MPU_REGION_ENTRY(_name, _base, _end, _attr) \ - {\ - .name = _name, \ - .base = _base, \ - .end = _end, \ - .attr = _attr, \ +#define MPU_REGION_ENTRY(_name, _base, _end, _attr) \ + { \ + .name = _name, \ + .base = _base, \ + .end = _end, \ + .attr = _attr, \ } /* MPU configuration data structure */ @@ -255,15 +232,13 @@ extern const struct nxp_mpu_config mpu_config; #endif /* _ASMLANGUAGE */ -#define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size) \ - BUILD_ASSERT((size) % \ - CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0 && \ - (size) >= CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE && \ - (uint32_t)(start) % CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0, \ - "the size of the partition must align with minimum MPU \ - region size" \ - " and greater than or equal to minimum MPU region size." \ - "start address of the partition must align with minimum MPU \ - region size.") +#define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size) \ + BUILD_ASSERT( \ + (size) % CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0 && \ + (size) >= CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE && \ + (uint32_t)(start) % CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0, \ + "The size of the partition must align with minimum MPU region size" \ + " and greater than or equal to minimum MPU region size.\n" \ + "The start address of the partition must align with minimum MPU region size.") #endif /* ZEPHYR_INCLUDE_ARCH_ARM_MPU_NXP_MPU_H_ */ diff --git a/tests/arch/arm/arm_hardfault_validation/src/arm_hardfault.c b/tests/arch/arm/arm_hardfault_validation/src/arm_hardfault.c index d7b4b509f1721..5ad830dabcbd4 100644 --- a/tests/arch/arm/arm_hardfault_validation/src/arm_hardfault.c +++ b/tests/arch/arm/arm_hardfault_validation/src/arm_hardfault.c @@ -25,8 +25,7 @@ void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf) } if (reason != expected_reason) { - printk("Wrong crash type got %d expected %d\n", reason, - expected_reason); + printk("Wrong crash type got %d expected %d\n", reason, expected_reason); k_fatal_halt(reason); } @@ -39,8 +38,7 @@ void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf) * inside the current runtime error */ expected_reason = K_ERR_KERNEL_PANIC; - __ASSERT(0, - "Assert occurring inside kernel panic"); + __ASSERT(0, "Assert occurring inside kernel panic"); } expected_reason = -1; diff --git a/tests/arch/arm/arm_interrupt/src/arm_interrupt.c b/tests/arch/arm/arm_interrupt/src/arm_interrupt.c index 425816c5c9869..dce39ede938ab 100644 --- a/tests/arch/arm/arm_interrupt/src/arm_interrupt.c +++ b/tests/arch/arm/arm_interrupt/src/arm_interrupt.c @@ -19,7 +19,7 @@ static volatile uint32_t expected_msp; static K_THREAD_STACK_DEFINE(esf_collection_stack, 2048); static struct k_thread esf_collection_thread; #define MAIN_PRIORITY 7 -#define PRIORITY 5 +#define PRIORITY 5 /** * Validates that pEsf matches state from set_regs_with_known_pattern() @@ -28,11 +28,8 @@ static int check_esf_matches_expectations(const struct arch_esf *pEsf) { const uint16_t expected_fault_instruction = 0xde5a; /* udf #90 */ const bool caller_regs_match_expected = - (pEsf->basic.r0 == 0) && - (pEsf->basic.r1 == 1) && - (pEsf->basic.r2 == 2) && - (pEsf->basic.r3 == 3) && - (pEsf->basic.lr == 15) && + (pEsf->basic.r0 == 0) && (pEsf->basic.r1 == 1) && (pEsf->basic.r2 == 2) && + (pEsf->basic.r3 == 3) && (pEsf->basic.lr == 15) && (*(uint16_t *)pEsf->basic.pc == expected_fault_instruction); if (!caller_regs_match_expected) { printk("__basic_sf member of ESF is incorrect\n"); @@ -42,14 +39,10 @@ static int check_esf_matches_expectations(const struct arch_esf *pEsf) #if defined(CONFIG_EXTRA_EXCEPTION_INFO) const struct _callee_saved *callee_regs = pEsf->extra_info.callee; const bool callee_regs_match_expected = - (callee_regs->v1 /* r4 */ == 4) && - (callee_regs->v2 /* r5 */ == 5) && - (callee_regs->v3 /* r6 */ == 6) && - (callee_regs->v4 /* r7 */ == 7) && - (callee_regs->v5 /* r8 */ == 8) && - (callee_regs->v6 /* r9 */ == 9) && - (callee_regs->v7 /* r10 */ == 10) && - (callee_regs->v8 /* r11 */ == 11); + (callee_regs->v1 /* r4 */ == 4) && (callee_regs->v2 /* r5 */ == 5) && + (callee_regs->v3 /* r6 */ == 6) && (callee_regs->v4 /* r7 */ == 7) && + (callee_regs->v5 /* r8 */ == 8) && (callee_regs->v6 /* r9 */ == 9) && + (callee_regs->v7 /* r10 */ == 10) && (callee_regs->v8 /* r11 */ == 11); if (!callee_regs_match_expected) { printk("_callee_saved_t member of ESF is incorrect\n"); return -1; @@ -62,10 +55,8 @@ static int check_esf_matches_expectations(const struct arch_esf *pEsf) */ const uint32_t exc_bits_set_mask = 0xff00000C; - if ((pEsf->extra_info.exc_return & exc_bits_set_mask) != - exc_bits_set_mask) { - printk("Incorrect EXC_RETURN of 0x%08x", - pEsf->extra_info.exc_return); + if ((pEsf->extra_info.exc_return & exc_bits_set_mask) != exc_bits_set_mask) { + printk("Incorrect EXC_RETURN of 0x%08x", pEsf->extra_info.exc_return); return -1; } @@ -73,15 +64,13 @@ static int check_esf_matches_expectations(const struct arch_esf *pEsf) * to the xpsr. (the xpsr value in the copy used for pEsf * is overwritten in fault.c) */ - if (memcmp((void *)callee_regs->psp, pEsf, - offsetof(struct arch_esf, basic.xpsr)) != 0) { + if (memcmp((void *)callee_regs->psp, pEsf, offsetof(struct arch_esf, basic.xpsr)) != 0) { printk("psp does not match __basic_sf provided\n"); return -1; } if (pEsf->extra_info.msp != expected_msp) { - printk("MSP is 0x%08x but should be 0x%08x", - pEsf->extra_info.msp, expected_msp); + printk("MSP is 0x%08x but should be 0x%08x", pEsf->extra_info.msp, expected_msp); return -1; } #endif /* CONFIG_EXTRA_EXCEPTION_INFO */ @@ -98,8 +87,7 @@ void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf) } if (reason != expected_reason) { - printk("Wrong crash type got %d expected %d\n", reason, - expected_reason); + printk("Wrong crash type got %d expected %d\n", reason, expected_reason); k_fatal_halt(reason); } @@ -131,29 +119,27 @@ void set_regs_with_known_pattern(void *p1, void *p2, void *p3) ARG_UNUSED(p2); ARG_UNUSED(p3); - __asm__ volatile( - "mov r1, #1\n" - "mov r2, #2\n" - "mov r3, #3\n" - "mov r4, #4\n" - "mov r5, #5\n" - "mov r6, #6\n" - "mov r7, #7\n" - "mov r0, #8\n" - "mov r8, r0\n" - "add r0, r0, #1\n" - "mov r9, r0\n" - "add r0, r0, #1\n" - "mov r10, r0\n" - "add r0, r0, #1\n" - "mov r11, r0\n" - "add r0, r0, #1\n" - "mov r12, r0\n" - "add r0, r0, #3\n" - "mov lr, r0\n" - "mov r0, #0\n" - "udf #90\n" - ); + __asm__ volatile("mov r1, #1\n" + "mov r2, #2\n" + "mov r3, #3\n" + "mov r4, #4\n" + "mov r5, #5\n" + "mov r6, #6\n" + "mov r7, #7\n" + "mov r0, #8\n" + "mov r8, r0\n" + "add r0, r0, #1\n" + "mov r9, r0\n" + "add r0, r0, #1\n" + "mov r10, r0\n" + "add r0, r0, #1\n" + "mov r11, r0\n" + "add r0, r0, #1\n" + "mov r12, r0\n" + "add r0, r0, #3\n" + "mov lr, r0\n" + "mov r0, #0\n" + "udf #90\n"); } ZTEST(arm_interrupt, test_arm_esf_collection) @@ -181,23 +167,19 @@ ZTEST(arm_interrupt, test_arm_esf_collection) TC_PRINT("Testing ESF Reporting\n"); k_thread_create(&esf_collection_thread, esf_collection_stack, - K_THREAD_STACK_SIZEOF(esf_collection_stack), - set_regs_with_known_pattern, - NULL, NULL, NULL, K_PRIO_COOP(PRIORITY), 0, - K_NO_WAIT); + K_THREAD_STACK_SIZEOF(esf_collection_stack), set_regs_with_known_pattern, + NULL, NULL, NULL, K_PRIO_COOP(PRIORITY), 0, K_NO_WAIT); test_validation_rv = esf_validation_rv; - zassert_not_equal(test_validation_rv, TC_FAIL, - "ESF fault collection failed"); + zassert_not_equal(test_validation_rv, TC_FAIL, "ESF fault collection failed"); } void arm_isr_handler(const void *args) { ARG_UNUSED(args); -#if defined(CONFIG_CPU_CORTEX_M) && defined(CONFIG_FPU) && \ - defined(CONFIG_FPU_SHARING) +#if defined(CONFIG_CPU_CORTEX_M) && defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) /* Clear Floating Point Status and Control Register (FPSCR), * to prevent from having the interrupt line set to pending again, * in case FPU IRQ is selected by the test as "Available IRQ line" @@ -235,8 +217,7 @@ void arm_isr_handler(const void *args) */ int reason = expected_reason; - zassert_equal(reason, -1, - "expected_reason has not been reset (%d)\n", reason); + zassert_equal(reason, -1, "expected_reason has not been reset (%d)\n", reason); #endif } } @@ -284,8 +265,7 @@ ZTEST(arm_interrupt, test_arm_interrupt) } } - zassert_true(i >= 0, - "No available IRQ line to use in the test\n"); + zassert_true(i >= 0, "No available IRQ line to use in the test\n"); TC_PRINT("Available IRQ line: %u\n", i); @@ -304,14 +284,10 @@ ZTEST(arm_interrupt, test_arm_interrupt) * expected reason variable is reset. */ reason = expected_reason; - zassert_equal(reason, -1, - "expected_reason has not been reset (%d)\n", reason); + zassert_equal(reason, -1, "expected_reason has not been reset (%d)\n", reason); NVIC_DisableIRQ(i); - arch_irq_connect_dynamic(i, 0 /* highest priority */, - arm_isr_handler, - NULL, - 0); + arch_irq_connect_dynamic(i, 0 /* highest priority */, arm_isr_handler, NULL, 0); NVIC_ClearPendingIRQ(i); NVIC_EnableIRQ(i); @@ -355,17 +331,14 @@ ZTEST(arm_interrupt, test_arm_interrupt) * entry will make PSP descend below the limit and into the MPU guard * section (or beyond the address pointed by PSPLIM in ARMv8-M MCUs). */ -#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) && \ - defined(CONFIG_MPU_STACK_GUARD) +#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) && defined(CONFIG_MPU_STACK_GUARD) #define FPU_STACK_EXTRA_SIZE 0x48 /* If an FP context is present, we should not set the PSP * too close to the end of the stack, because stacking of * the ESF might corrupt kernel memory, making it not * possible to continue the test execution. */ - uint32_t fp_extra_size = - (__get_CONTROL() & CONTROL_FPCA_Msk) ? - FPU_STACK_EXTRA_SIZE : 0; + uint32_t fp_extra_size = (__get_CONTROL() & CONTROL_FPCA_Msk) ? FPU_STACK_EXTRA_SIZE : 0; __set_PSP(_current->stack_info.start + 0x10 + fp_extra_size); #else __set_PSP(_current->stack_info.start + 0x10); @@ -420,8 +393,7 @@ static inline void z_vrfy_test_arm_user_interrupt_syscall(void) ZTEST_USER(arm_interrupt, test_arm_user_interrupt) { /* Test thread executing in user mode */ - zassert_true(arch_is_user_context(), - "Test thread not running in user mode\n"); + zassert_true(arch_is_user_context(), "Test thread not running in user mode\n"); /* Attempt to lock IRQs in user mode */ irq_lock(); @@ -476,12 +448,10 @@ ZTEST(arm_interrupt, test_arm_null_pointer_exception) expected_reason = K_ERR_CPU_EXCEPTION; - printk("Reading a null pointer value: 0x%0x\n", - test_struct_null_pointer->val[1]); + printk("Reading a null pointer value: 0x%0x\n", test_struct_null_pointer->val[1]); reason = expected_reason; - zassert_equal(reason, -1, - "expected_reason has not been reset (%d)\n", reason); + zassert_equal(reason, -1, "expected_reason has not been reset (%d)\n", reason); } #pragma GCC pop_options diff --git a/tests/arch/arm/arm_irq_advanced_features/src/arm_dynamic_direct_interrupts.c b/tests/arch/arm/arm_irq_advanced_features/src/arm_dynamic_direct_interrupts.c index 4d46851faef0b..ce5043d882f48 100644 --- a/tests/arch/arm/arm_irq_advanced_features/src/arm_dynamic_direct_interrupts.c +++ b/tests/arch/arm/arm_irq_advanced_features/src/arm_dynamic_direct_interrupts.c @@ -41,10 +41,8 @@ ZTEST(arm_irq_advanced_features, test_arm_dynamic_direct_interrupts) irq_disable(DIRECT_ISR_OFFSET); /* Attach the ISR handler at run time. */ - irq_connect_dynamic(DIRECT_ISR_OFFSET, 0 /* highest priority */, - arm_direct_isr_handler_0, - NULL, - 0); + irq_connect_dynamic(DIRECT_ISR_OFFSET, 0 /* highest priority */, arm_direct_isr_handler_0, + NULL, 0); /* Enable and pend the interrupt */ irq_enable(DIRECT_ISR_OFFSET); @@ -65,10 +63,8 @@ ZTEST(arm_irq_advanced_features, test_arm_dynamic_direct_interrupts) irq_disable(DIRECT_ISR_OFFSET); /* Attach an alternative ISR handler at run-time. */ - irq_connect_dynamic(DIRECT_ISR_OFFSET, 0 /* highest priority */, - arm_direct_isr_handler_1, - NULL, - 0); + irq_connect_dynamic(DIRECT_ISR_OFFSET, 0 /* highest priority */, arm_direct_isr_handler_1, + NULL, 0); /* Enable and pend the interrupt */ irq_enable(DIRECT_ISR_OFFSET); diff --git a/tests/arch/arm/arm_irq_advanced_features/src/arm_irq_target_state.c b/tests/arch/arm/arm_irq_advanced_features/src/arm_irq_target_state.c index 802385fa0e530..f1d005b47c591 100644 --- a/tests/arch/arm/arm_irq_advanced_features/src/arm_irq_target_state.c +++ b/tests/arch/arm/arm_irq_advanced_features/src/arm_irq_target_state.c @@ -8,11 +8,9 @@ #include #include -#if defined(CONFIG_ARM_SECURE_FIRMWARE) && \ - defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) +#if defined(CONFIG_ARM_SECURE_FIRMWARE) && defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) -extern irq_target_state_t irq_target_state_set(unsigned int irq, - irq_target_state_t target_state); +extern irq_target_state_t irq_target_state_set(unsigned int irq, irq_target_state_t target_state); extern int irq_target_state_is_secure(unsigned int irq); ZTEST(arm_irq_advanced_features, test_arm_irq_target_state) @@ -54,39 +52,29 @@ ZTEST(arm_irq_advanced_features, test_arm_irq_target_state) } } - zassert_true(i >= 0, - "No available IRQ line to configure as zero-latency\n"); + zassert_true(i >= 0, "No available IRQ line to configure as zero-latency\n"); TC_PRINT("Available IRQ line: %u\n", i); /* Set the available IRQ line to Secure and check the result. */ - irq_target_state_t result_state = - irq_target_state_set(i, IRQ_TARGET_STATE_SECURE); + irq_target_state_t result_state = irq_target_state_set(i, IRQ_TARGET_STATE_SECURE); - zassert_equal(result_state, IRQ_TARGET_STATE_SECURE, - "Target state not set to Secure\n"); + zassert_equal(result_state, IRQ_TARGET_STATE_SECURE, "Target state not set to Secure\n"); - zassert_equal(irq_target_state_is_secure(i), 1, - "Target state not set to Secure\n"); + zassert_equal(irq_target_state_is_secure(i), 1, "Target state not set to Secure\n"); /* Set the available IRQ line to Secure and check the result. */ - result_state = - irq_target_state_set(i, IRQ_TARGET_STATE_NON_SECURE); + result_state = irq_target_state_set(i, IRQ_TARGET_STATE_NON_SECURE); zassert_equal(result_state, IRQ_TARGET_STATE_NON_SECURE, - "Target state not set to Secure\n"); - zassert_equal(irq_target_state_is_secure(i), 0, - "Target state not set to Non-Secure\n"); + "Target state not set to Secure\n"); + zassert_equal(irq_target_state_is_secure(i), 0, "Target state not set to Non-Secure\n"); - result_state = - irq_target_state_set(i, IRQ_TARGET_STATE_SECURE); + result_state = irq_target_state_set(i, IRQ_TARGET_STATE_SECURE); - zassert_equal(result_state, IRQ_TARGET_STATE_SECURE, - "Target state not set to Secure\n"); - - zassert_equal(irq_target_state_is_secure(i), 1, - "Target state not set to Secure\n"); + zassert_equal(result_state, IRQ_TARGET_STATE_SECURE, "Target state not set to Secure\n"); + zassert_equal(irq_target_state_is_secure(i), 1, "Target state not set to Secure\n"); } #else ZTEST(arm_irq_advanced_features, test_arm_irq_target_state) diff --git a/tests/arch/arm/arm_irq_advanced_features/src/arm_zero_latency_irqs.c b/tests/arch/arm/arm_irq_advanced_features/src/arm_zero_latency_irqs.c index 67adbc7e9c2a3..c3e8b5f574e40 100644 --- a/tests/arch/arm/arm_irq_advanced_features/src/arm_zero_latency_irqs.c +++ b/tests/arch/arm/arm_irq_advanced_features/src/arm_zero_latency_irqs.c @@ -70,17 +70,14 @@ ZTEST(arm_irq_advanced_features, test_arm_zero_latency_irqs) } } - zassert_true(i >= 0, - "No available IRQ line to configure as zero-latency\n"); + zassert_true(i >= 0, "No available IRQ line to configure as zero-latency\n"); TC_PRINT("Available IRQ line: %u\n", i); /* Configure the available IRQ line as zero-latency. */ - arch_irq_connect_dynamic(i, 0 /* Unused */, - arm_zero_latency_isr_handler, - NULL, - IRQ_ZERO_LATENCY); + arch_irq_connect_dynamic(i, 0 /* Unused */, arm_zero_latency_isr_handler, NULL, + IRQ_ZERO_LATENCY); NVIC_ClearPendingIRQ(i); NVIC_EnableIRQ(i); diff --git a/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c b/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c index fe99dbd4b0f89..5974d13d7d2f7 100644 --- a/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c +++ b/tests/arch/arm/arm_irq_vector_table/src/arm_irq_vector_table.c @@ -9,7 +9,6 @@ #include #include - /* * Offset (starting from the beginning of the vector table) * of the location where the ISRs will be manually installed. @@ -83,7 +82,6 @@ void isr2(void) * @{ */ - /** * @brief Test installation of ISRs directly in the vector table * @@ -106,13 +104,12 @@ ZTEST(vector_table, test_arm_irq_vector_table) k_sem_init(&sem[ii], 0, K_SEM_MAX_LIMIT); } - zassert_true((k_sem_take(&sem[0], K_NO_WAIT) || - k_sem_take(&sem[1], K_NO_WAIT) || - k_sem_take(&sem[2], K_NO_WAIT)), NULL); + zassert_true((k_sem_take(&sem[0], K_NO_WAIT) || k_sem_take(&sem[1], K_NO_WAIT) || + k_sem_take(&sem[2], K_NO_WAIT)), + NULL); for (int ii = 0; ii < 3; ii++) { -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) || \ - defined(CONFIG_SOC_TI_LM3S6965_QEMU) +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) || defined(CONFIG_SOC_TI_LM3S6965_QEMU) /* the QEMU does not simulate the * STIR register: this is a workaround */ @@ -122,10 +119,9 @@ ZTEST(vector_table, test_arm_irq_vector_table) #endif } - zassert_false((k_sem_take(&sem[0], K_NO_WAIT) || - k_sem_take(&sem[1], K_NO_WAIT) || - k_sem_take(&sem[2], K_NO_WAIT)), NULL); - + zassert_false((k_sem_take(&sem[0], K_NO_WAIT) || k_sem_take(&sem[1], K_NO_WAIT) || + k_sem_take(&sem[2], K_NO_WAIT)), + NULL); } typedef void (*vth)(void); /* Vector Table Handler */ @@ -143,26 +139,26 @@ typedef void (*vth)(void); /* Vector Table Handler */ */ void nrfx_power_clock_irq_handler(void); #if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) -#define POWER_CLOCK_IRQ_NUM POWER_CLOCK_IRQn +#define POWER_CLOCK_IRQ_NUM POWER_CLOCK_IRQn #elif defined(CONFIG_SOC_SERIES_NRF54HX) || defined(CONFIG_SOC_SERIES_NRF92X) -#define POWER_CLOCK_IRQ_NUM -1 /* not needed */ +#define POWER_CLOCK_IRQ_NUM -1 /* not needed */ #else -#define POWER_CLOCK_IRQ_NUM CLOCK_POWER_IRQn +#define POWER_CLOCK_IRQ_NUM CLOCK_POWER_IRQn #endif #if defined(CONFIG_BOARD_QEMU_CORTEX_M0) void timer0_nrf_isr(void); -#define TIMER_IRQ_HANDLER timer0_nrf_isr -#define TIMER_IRQ_NUM TIMER0_IRQn -#elif defined(CONFIG_SOC_SERIES_NRF54LX) || defined(CONFIG_SOC_SERIES_NRF54HX) || \ +#define TIMER_IRQ_HANDLER timer0_nrf_isr +#define TIMER_IRQ_NUM TIMER0_IRQn +#elif defined(CONFIG_SOC_SERIES_NRF54LX) || defined(CONFIG_SOC_SERIES_NRF54HX) || \ defined(CONFIG_SOC_SERIES_NRF92X) void nrfx_grtc_irq_handler(void); -#define TIMER_IRQ_HANDLER nrfx_grtc_irq_handler -#define TIMER_IRQ_NUM GRTC_0_IRQn +#define TIMER_IRQ_HANDLER nrfx_grtc_irq_handler +#define TIMER_IRQ_NUM GRTC_0_IRQn #else void rtc_nrf_isr(void); -#define TIMER_IRQ_HANDLER rtc_nrf_isr -#define TIMER_IRQ_NUM RTC1_IRQn +#define TIMER_IRQ_HANDLER rtc_nrf_isr +#define TIMER_IRQ_NUM RTC1_IRQn #endif #define IRQ_VECTOR_TABLE_SIZE (MAX(POWER_CLOCK_IRQ_NUM, MAX(TIMER_IRQ_NUM, _ISR_OFFSET + 2)) + 1) @@ -172,7 +168,9 @@ vth __irq_vector_table _irq_vector_table[IRQ_VECTOR_TABLE_SIZE] = { [POWER_CLOCK_IRQ_NUM] = nrfx_power_clock_irq_handler, #endif [TIMER_IRQ_NUM] = TIMER_IRQ_HANDLER, - [_ISR_OFFSET] = isr0, isr1, isr2, + [_ISR_OFFSET] = isr0, + isr1, + isr2, }; #elif defined(CONFIG_SOC_SERIES_CC13X2_CC26X2) || defined(CONFIG_SOC_SERIES_CC13X2X7_CC26X2X7) /* TI CC13x2/CC26x2 based platforms also employ a Hardware RTC peripheral @@ -181,13 +179,13 @@ vth __irq_vector_table _irq_vector_table[IRQ_VECTOR_TABLE_SIZE] = { * the custom vector table to handle the timer "tick" interrupts. */ extern void rtc_isr(void); -vth __irq_vector_table _irq_vector_table[] = { - isr0, isr1, isr2, 0, - rtc_isr -}; -#elif (defined(CONFIG_SOC_SERIES_IMXRT6XX) || defined(CONFIG_SOC_SERIES_IMXRT5XX) || \ - defined(CONFIG_SOC_SERIES_RW6XX)) && \ - defined(CONFIG_MCUX_OS_TIMER) +vth __irq_vector_table _irq_vector_table[] = {isr0, isr1, isr2, 0, rtc_isr}; + +/* clang-format off */ +#elif (defined(CONFIG_SOC_SERIES_IMXRT6XX) || defined(CONFIG_SOC_SERIES_IMXRT5XX) || \ + defined(CONFIG_SOC_SERIES_RW6XX)) && defined(CONFIG_MCUX_OS_TIMER) +/* clang-format on */ + /* MXRT685 employs a OS Event timer to implement the Kernel system * timer, instead of the ARM Cortex-M SysTick. Therefore, a pointer to * the timer ISR needs to be added in the custom vector table to handle @@ -196,10 +194,8 @@ vth __irq_vector_table _irq_vector_table[] = { extern void mcux_lpc_ostick_isr(void); vth __irq_vector_table _irq_vector_table[] = { isr0, isr1, isr2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - mcux_lpc_ostick_isr -}; -#elif (defined(CONFIG_SOC_SERIES_IMXRT10XX) || defined(CONFIG_SOC_SERIES_IMXRT11XX)) && \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, mcux_lpc_ostick_isr}; +#elif (defined(CONFIG_SOC_SERIES_IMXRT10XX) || defined(CONFIG_SOC_SERIES_IMXRT11XX)) && \ defined(CONFIG_MCUX_GPT_TIMER) /** MXRT parts employ a GPT timer peripheral to implement the Kernel system * timer, instead of the ARM Cortex-M Systick. Thereforce, a pointer to the @@ -208,12 +204,15 @@ vth __irq_vector_table _irq_vector_table[] = { */ extern void mcux_imx_gpt_isr(void); #if defined(CONFIG_SOC_MIMXRT1011) +/* clang-format off */ /* RT1011 GPT timer interrupt is at offset 30 */ vth __irq_vector_table _irq_vector_table[] = { isr0, isr1, isr2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, mcux_imx_gpt_isr }; +/* clang-format on */ #elif defined(CONFIG_SOC_SERIES_IMXRT10XX) +/* clang-format off */ /* RT10xx GPT timer interrupt is at offset 100 */ vth __irq_vector_table _irq_vector_table[] = { isr0, isr1, isr2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -222,23 +221,21 @@ vth __irq_vector_table _irq_vector_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, mcux_imx_gpt_isr }; +/* clang-format on */ #elif defined(CONFIG_SOC_SERIES_IMXRT11XX) /* RT11xx GPT timer interrupt is at offset 119 */ vth __irq_vector_table _irq_vector_table[] = { - isr0, isr1, isr2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - mcux_imx_gpt_isr -}; + isr0, isr1, isr2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, mcux_imx_gpt_isr}; #else #error "GPT timer enabled, but no known SOC selected. ISR table needs rework" #endif #else -vth __irq_vector_table _irq_vector_table[] = { - isr0, isr1, isr2 -}; +vth __irq_vector_table _irq_vector_table[] = {isr0, isr1, isr2}; #endif /* CONFIG_SOC_FAMILY_NORDIC_NRF */ /** diff --git a/tests/arch/arm/arm_irq_vector_table/src/main.c b/tests/arch/arm/arm_irq_vector_table/src/main.c index ccb750f51ccad..9b7d622d3797d 100644 --- a/tests/arch/arm/arm_irq_vector_table/src/main.c +++ b/tests/arch/arm/arm_irq_vector_table/src/main.c @@ -5,7 +5,7 @@ */ #if !defined(CONFIG_CPU_CORTEX_M) - #error project can only run on Cortex-M +#error project can only run on Cortex-M #endif #include diff --git a/tests/arch/arm/arm_irq_zero_latency_levels/src/main.c b/tests/arch/arm/arm_irq_zero_latency_levels/src/main.c index 8a145884b747b..7953635e69f7a 100644 --- a/tests/arch/arm/arm_irq_zero_latency_levels/src/main.c +++ b/tests/arch/arm/arm_irq_zero_latency_levels/src/main.c @@ -9,21 +9,14 @@ #include #include - #define EXECUTION_TRACE_LENGTH 6 -#define IRQ_A_PRIO 1 /* lower priority */ -#define IRQ_B_PRIO 0 /* higher priority */ - - -#define CHECK_STEP(pos, val) zassert_equal( \ - execution_trace[pos], \ - val, \ - "Expected %s for step %d but got %s", \ - execution_step_str(val), \ - pos, \ - execution_step_str(execution_trace[pos])) +#define IRQ_A_PRIO 1 /* lower priority */ +#define IRQ_B_PRIO 0 /* higher priority */ +#define CHECK_STEP(pos, val) \ + zassert_equal(execution_trace[pos], val, "Expected %s for step %d but got %s", \ + execution_step_str(val), pos, execution_step_str(execution_trace[pos])) enum execution_step { STEP_MAIN_BEGIN, @@ -69,17 +62,13 @@ static const char *execution_step_str(enum execution_step s) return res; } - static void execution_trace_add(enum execution_step s) { - __ASSERT(execution_trace_pos < EXECUTION_TRACE_LENGTH, - "Execution trace overflow"); + __ASSERT(execution_trace_pos < EXECUTION_TRACE_LENGTH, "Execution trace overflow"); execution_trace[execution_trace_pos] = s; execution_trace_pos++; } - - void isr_a_handler(const void *args) { ARG_UNUSED(args); @@ -93,7 +82,6 @@ void isr_a_handler(const void *args) execution_trace_add(STEP_ISR_A_END); } - void isr_b_handler(const void *args) { ARG_UNUSED(args); @@ -101,7 +89,6 @@ void isr_b_handler(const void *args) execution_trace_add(STEP_ISR_B_END); } - static int find_unused_irq(int start) { int i; @@ -141,8 +128,7 @@ static int find_unused_irq(int start) } } - zassert_true(i >= 0, - "No available IRQ line to configure as zero-latency\n"); + zassert_true(i >= 0, "No available IRQ line to configure as zero-latency\n"); TC_PRINT("Available IRQ line: %u\n", i); return i; @@ -165,14 +151,12 @@ ZTEST(arm_irq_zero_latency_levels, test_arm_zero_latency_levels) irq_b = find_unused_irq(irq_a); /* Configure IRQ A as zero-latency interrupt with prio 1 */ - arch_irq_connect_dynamic(irq_a, IRQ_A_PRIO, isr_a_handler, - NULL, IRQ_ZERO_LATENCY); + arch_irq_connect_dynamic(irq_a, IRQ_A_PRIO, isr_a_handler, NULL, IRQ_ZERO_LATENCY); NVIC_ClearPendingIRQ(irq_a); NVIC_EnableIRQ(irq_a); /* Configure irq_b as zero-latency interrupt with prio 0 */ - arch_irq_connect_dynamic(irq_b, IRQ_B_PRIO, isr_b_handler, - NULL, IRQ_ZERO_LATENCY); + arch_irq_connect_dynamic(irq_b, IRQ_B_PRIO, isr_b_handler, NULL, IRQ_ZERO_LATENCY); NVIC_ClearPendingIRQ(irq_b); NVIC_EnableIRQ(irq_b); diff --git a/tests/arch/arm/arm_no_multithreading/src/main.c b/tests/arch/arm/arm_no_multithreading/src/main.c index c9e4cdd02f329..ae2bb66d468d0 100644 --- a/tests/arch/arm/arm_no_multithreading/src/main.c +++ b/tests/arch/arm/arm_no_multithreading/src/main.c @@ -11,7 +11,7 @@ #include #if !defined(CONFIG_CPU_CORTEX_M) - #error test can only run on Cortex-M MCUs +#error test can only run on Cortex-M MCUs #endif #if defined(CONFIG_ARMV8_1_M_MAINLINE) @@ -19,9 +19,9 @@ * For ARMv8.1-M, the FPSCR[18:16] LTPSIZE field may always read 0b010 if MVE * is not implemented, so mask it when validating the value of the FPSCR. */ -#define FPSCR_MASK (~FPU_FPDSCR_LTPSIZE_Msk) +#define FPSCR_MASK (~FPU_FPDSCR_LTPSIZE_Msk) #else -#define FPSCR_MASK (0xffffffffU) +#define FPSCR_MASK (0xffffffffU) #endif K_THREAD_STACK_DECLARE(z_main_stack, CONFIG_MAIN_STACK_SIZE); @@ -46,8 +46,7 @@ void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf) } if (reason != expected_reason) { - printk("Wrong crash type got %d expected %d\n", reason, - expected_reason); + printk("Wrong crash type got %d expected %d\n", reason, expected_reason); k_fatal_halt(reason); } @@ -61,29 +60,22 @@ void test_main(void) uint32_t psp = (uint32_t)__get_PSP(); uint32_t main_stack_base = (uint32_t)K_THREAD_STACK_BUFFER(z_main_stack); uint32_t main_stack_top = (uint32_t)(K_THREAD_STACK_BUFFER(z_main_stack) + - K_THREAD_STACK_SIZEOF(z_main_stack)); + K_THREAD_STACK_SIZEOF(z_main_stack)); - __ASSERT( - (psp >= main_stack_base) && (psp <= main_stack_top), - "PSP out of bounds: 0x%x (0x%x - 0x%x)", - psp, main_stack_base, main_stack_top); + __ASSERT((psp >= main_stack_base) && (psp <= main_stack_top), + "PSP out of bounds: 0x%x (0x%x - 0x%x)", psp, main_stack_base, main_stack_top); #if defined(CONFIG_FPU) - __ASSERT((__get_FPSCR() & FPSCR_MASK) == 0, - "FPSCR not zero (0x%x)", __get_FPSCR()); + __ASSERT((__get_FPSCR() & FPSCR_MASK) == 0, "FPSCR not zero (0x%x)", __get_FPSCR()); #endif #if defined(CONFIG_BUILTIN_STACK_GUARD) uint32_t psplim = (uint32_t)__get_PSPLIM(); - __ASSERT( - (psplim == main_stack_base), - "PSPLIM not set to main stack base: (0x%x)", - psplim); + __ASSERT((psplim == main_stack_base), "PSPLIM not set to main stack base: (0x%x)", psplim); #endif int key = arch_irq_lock(); - __ASSERT(arch_irq_unlocked(key), - "IRQs locked in main()"); + __ASSERT(arch_irq_unlocked(key), "IRQs locked in main()"); arch_irq_unlock(key); @@ -136,10 +128,7 @@ void test_main(void) printk("Available IRQ line: %u\n", i); - arch_irq_connect_dynamic(i, 0 /* highest priority */, - arm_isr_handler, - NULL, - 0); + arch_irq_connect_dynamic(i, 0 /* highest priority */, arm_isr_handler, NULL, 0); NVIC_EnableIRQ(i); 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 87e4237d96136..3d9c913dc8b1e 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 @@ -35,7 +35,6 @@ static void nmi_test_isr(void) * @{ */ - /** * @brief test the behavior of CONFIG_RUNTIME_NMI at run time * diff --git a/tests/arch/arm/arm_sw_vector_relay/src/arm_sw_vector_relay.c b/tests/arch/arm/arm_sw_vector_relay/src/arm_sw_vector_relay.c index be400746d92f7..8f5728abee074 100644 --- a/tests/arch/arm/arm_sw_vector_relay/src/arm_sw_vector_relay.c +++ b/tests/arch/arm/arm_sw_vector_relay/src/arm_sw_vector_relay.c @@ -24,15 +24,12 @@ ZTEST(arm_sw_vector_relay, test_arm_sw_vector_relay) * entries for MSP and ResetHandler) point to the relay handling * function. */ - const uint32_t *vector_relay_table_addr_val = - (uint32_t *)(vector_relay_table_addr); + const uint32_t *vector_relay_table_addr_val = (uint32_t *)(vector_relay_table_addr); for (int i = 2; i < 16 + CONFIG_NUM_IRQS; i++) { - zassert_true(vector_relay_table_addr_val[i] == - vector_relay_handler_func, - "vector relay table not pointing to the relay handler: 0x%x, 0x%x\n", - vector_relay_table_addr_val[i], - vector_relay_handler_func); + zassert_true(vector_relay_table_addr_val[i] == vector_relay_handler_func, + "vector relay table not pointing to the relay handler: 0x%x, 0x%x\n", + vector_relay_table_addr_val[i], vector_relay_handler_func); } #if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR) @@ -45,25 +42,23 @@ ZTEST(arm_sw_vector_relay, test_arm_sw_vector_relay) */ uint32_t mask = MAX(128, Z_POW2_CEIL(4 * (16 + CONFIG_NUM_IRQS))) - 1; - zassert_true(((vector_table_addr) & mask) == 0, - "vector table not properly aligned: 0x%x\n", - vector_table_addr); - zassert_true(((vector_relay_table_addr) & mask) == 0, - "vector relay table not properly aligned: 0x%x\n", - vector_relay_table_addr); + zassert_true(((vector_table_addr)&mask) == 0, "vector table not properly aligned: 0x%x\n", + vector_table_addr); + zassert_true(((vector_relay_table_addr)&mask) == 0, + "vector relay table not properly aligned: 0x%x\n", vector_relay_table_addr); /* Verify that the VTOR points to the real vector table, * NOT the table that contains the forwarding function. */ zassert_true(SCB->VTOR == (uint32_t)_vector_start, - "VTOR not pointing to the real vector table\n"); + "VTOR not pointing to the real vector table\n"); #else /* If VTOR is not present then we already need to forward interrupts * before loading any child chain-loadable image. */ zassert_true(_vector_table_pointer == (uint32_t)_vector_start, - "vector table pointer not pointing to vector start, 0x%x, 0x%x\n", - _vector_table_pointer, _vector_start); + "vector table pointer not pointing to vector start, 0x%x, 0x%x\n", + _vector_table_pointer, _vector_start); #endif } /** diff --git a/tests/arch/arm/arm_sw_vector_relay/src/main.c b/tests/arch/arm/arm_sw_vector_relay/src/main.c index 4cbaadb8e71d3..c5adca252df86 100644 --- a/tests/arch/arm/arm_sw_vector_relay/src/main.c +++ b/tests/arch/arm/arm_sw_vector_relay/src/main.c @@ -5,7 +5,7 @@ */ #if !defined(CONFIG_CPU_CORTEX_M) - #error test can only run on Cortex-M MCUs +#error test can only run on Cortex-M MCUs #endif #include diff --git a/tests/arch/arm/arm_thread_swap/src/arm_syscalls.c b/tests/arch/arm/arm_thread_swap/src/arm_syscalls.c index 075b36126a155..42a25f7dc2866 100644 --- a/tests/arch/arm/arm_thread_swap/src/arm_syscalls.c +++ b/tests/arch/arm/arm_thread_swap/src/arm_syscalls.c @@ -12,15 +12,14 @@ #include #include -#if !defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && \ - !defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) +#if !defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && !defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) #error "Unsupported architecture" #endif #if defined(CONFIG_USERSPACE) #define PRIORITY 0 -#define DB_VAL 0xDEADBEEF +#define DB_VAL 0xDEADBEEF static struct k_thread user_thread; static K_THREAD_STACK_DEFINE(user_thread_stack, 1024); @@ -39,22 +38,20 @@ void z_impl_test_arm_user_syscall(void) * - MSPLIM register still guards the interrupt stack */ zassert_true((_current->arch.mode & CONTROL_nPRIV_Msk) == 0, - "mode variable not set to PRIV mode in system call\n"); + "mode variable not set to PRIV mode in system call\n"); - zassert_false(arch_is_user_context(), - "arch_is_user_context() indicates nPRIV\n"); + zassert_false(arch_is_user_context(), "arch_is_user_context() indicates nPRIV\n"); zassert_true( ((__get_PSP() >= _current->arch.priv_stack_start) && - (__get_PSP() < (_current->arch.priv_stack_start + - CONFIG_PRIVILEGED_STACK_SIZE))), - "Process SP outside thread privileged stack limits\n"); + (__get_PSP() < (_current->arch.priv_stack_start + CONFIG_PRIVILEGED_STACK_SIZE))), + "Process SP outside thread privileged stack limits\n"); #if defined(CONFIG_BUILTIN_STACK_GUARD) zassert_true(__get_PSPLIM() == _current->arch.priv_stack_start, - "PSPLIM not guarding the thread's privileged stack\n"); + "PSPLIM not guarding the thread's privileged stack\n"); zassert_true(__get_MSPLIM() == (uint32_t)z_interrupt_stacks, - "MSPLIM not guarding the interrupt stack\n"); + "MSPLIM not guarding the interrupt stack\n"); #endif } @@ -64,7 +61,6 @@ static inline void z_vrfy_test_arm_user_syscall(void) } #include - void arm_isr_handler(const void *args) { ARG_UNUSED(args); @@ -79,16 +75,13 @@ void arm_isr_handler(const void *args) */ zassert_true((_current->arch.mode & CONTROL_nPRIV_Msk) != 0, - "mode variable not set to nPRIV mode for user thread\n"); + "mode variable not set to nPRIV mode for user thread\n"); - zassert_false(arch_is_user_context(), - "arch_is_user_context() indicates nPRIV in ISR\n"); + zassert_false(arch_is_user_context(), "arch_is_user_context() indicates nPRIV in ISR\n"); - zassert_true( - ((__get_PSP() >= _current->stack_info.start) && - (__get_PSP() < (_current->stack_info.start + - _current->stack_info.size))), - "Process SP outside thread stack limits\n"); + zassert_true(((__get_PSP() >= _current->stack_info.start) && + (__get_PSP() < (_current->stack_info.start + _current->stack_info.size))), + "Process SP outside thread stack limits\n"); static int first_call = 1; @@ -106,10 +99,9 @@ void arm_isr_handler(const void *args) /* Second ISR run occurs after thread context-switch. * We expect PSPLIM to be clear at this point. */ - zassert_true(__get_PSPLIM() == 0, - "PSPLIM not clear\n"); + zassert_true(__get_PSPLIM() == 0, "PSPLIM not clear\n"); zassert_true(__get_MSPLIM() == (uint32_t)z_interrupt_stacks, - "MSPLIM not guarding the interrupt stack\n"); + "MSPLIM not guarding the interrupt stack\n"); #endif NVIC_DisableIRQ((uint32_t)args); } @@ -166,22 +158,19 @@ ZTEST(arm_thread_swap, test_arm_syscalls) * - MSPLIM register guards the interrupt stack */ zassert_true((_current->arch.mode & CONTROL_nPRIV_Msk) == 0, - "mode variable not set to PRIV mode for supervisor thread\n"); + "mode variable not set to PRIV mode for supervisor thread\n"); - zassert_false(arch_is_user_context(), - "arch_is_user_context() indicates nPRIV\n"); + zassert_false(arch_is_user_context(), "arch_is_user_context() indicates nPRIV\n"); - zassert_true( - ((__get_PSP() >= _current->stack_info.start) && - (__get_PSP() < (_current->stack_info.start + - _current->stack_info.size))), - "Process SP outside thread stack limits\n"); + zassert_true(((__get_PSP() >= _current->stack_info.start) && + (__get_PSP() < (_current->stack_info.start + _current->stack_info.size))), + "Process SP outside thread stack limits\n"); #if defined(CONFIG_BUILTIN_STACK_GUARD) zassert_true(__get_PSPLIM() == _current->stack_info.start, - "PSPLIM not guarding the default stack\n"); + "PSPLIM not guarding the default stack\n"); zassert_true(__get_MSPLIM() == (uint32_t)z_interrupt_stacks, - "MSPLIM not guarding the interrupt stack\n"); + "MSPLIM not guarding the interrupt stack\n"); #endif #if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) @@ -207,15 +196,11 @@ ZTEST(arm_thread_swap, test_arm_syscalls) } } - zassert_true(i >= 0, - "No available IRQ line to use in the test\n"); + zassert_true(i >= 0, "No available IRQ line to use in the test\n"); TC_PRINT("Available IRQ line: %u\n", i); - arch_irq_connect_dynamic(i, 0 /* highest priority */, - arm_isr_handler, - (uint32_t *)i, - 0); + arch_irq_connect_dynamic(i, 0 /* highest priority */, arm_isr_handler, (uint32_t *)i, 0); NVIC_ClearPendingIRQ(i); NVIC_EnableIRQ(i); @@ -225,19 +210,15 @@ ZTEST(arm_thread_swap, test_arm_syscalls) * i.e. to allow the inspection of the thread state * while running in user mode. */ - SCB->CCR |= SCB_CCR_USERSETMPEND_Msk; + SCB->CCR |= SCB_CCR_USERSETMPEND_Msk; #endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE*/ /* Create and switch to a user thread, passing * as argument the IRQ line to used in the test. */ - k_thread_create(&user_thread, - user_thread_stack, - K_THREAD_STACK_SIZEOF(user_thread_stack), - user_thread_entry, - (uint32_t *)i, NULL, NULL, - K_PRIO_COOP(PRIORITY), K_USER, - K_NO_WAIT); + k_thread_create(&user_thread, user_thread_stack, K_THREAD_STACK_SIZEOF(user_thread_stack), + user_thread_entry, (uint32_t *)i, NULL, NULL, K_PRIO_COOP(PRIORITY), K_USER, + K_NO_WAIT); } void z_impl_test_arm_cpu_write_reg(void) @@ -254,12 +235,10 @@ void z_impl_test_arm_cpu_write_reg(void) * after returning from the system call */ TC_PRINT("Writing 0xDEADBEEF values into registers\n"); - __asm__ volatile ( - "ldr r0, =0xDEADBEEF;\n\t" - "ldr r1, =0xDEADBEEF;\n\t" - "ldr r2, =0xDEADBEEF;\n\t" - "ldr r3, =0xDEADBEEF;\n\t" - ); + __asm__ volatile("ldr r0, =0xDEADBEEF;\n\t" + "ldr r1, =0xDEADBEEF;\n\t" + "ldr r2, =0xDEADBEEF;\n\t" + "ldr r3, =0xDEADBEEF;\n\t"); TC_PRINT("Exit from system call\n"); } @@ -286,15 +265,15 @@ ZTEST_USER(arm_thread_swap, test_syscall_cpu_scrubs_regs) test_arm_cpu_write_reg(); - __asm__ volatile ("mov %0, r0" : "=r"(arm_reg_val[0])); - __asm__ volatile ("mov %0, r1" : "=r"(arm_reg_val[1])); - __asm__ volatile ("mov %0, r2" : "=r"(arm_reg_val[2])); - __asm__ volatile ("mov %0, r3" : "=r"(arm_reg_val[3])); + __asm__ volatile("mov %0, r0" : "=r"(arm_reg_val[0])); + __asm__ volatile("mov %0, r1" : "=r"(arm_reg_val[1])); + __asm__ volatile("mov %0, r2" : "=r"(arm_reg_val[2])); + __asm__ volatile("mov %0, r3" : "=r"(arm_reg_val[3])); for (int i = 0; i < 4; i++) { zassert_not_equal(arm_reg_val[i], DB_VAL, - "register value is 0xDEADBEEF, " - "not scrubbed after system call."); + "register value is 0xDEADBEEF, " + "not scrubbed after system call."); } } #else diff --git a/tests/arch/arm/arm_thread_swap/src/arm_thread_arch.c b/tests/arch/arm/arm_thread_swap/src/arm_thread_arch.c index a617abe06802f..7572982a775e5 100644 --- a/tests/arch/arm/arm_thread_swap/src/arm_thread_arch.c +++ b/tests/arch/arm/arm_thread_swap/src/arm_thread_arch.c @@ -12,19 +12,18 @@ #include #include -#if !defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && \ - !defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) +#if !defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && !defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) #error "Unsupported architecture" #endif -#define PRIORITY 0 +#define PRIORITY 0 #define BASEPRI_MODIFIED_1 0x20 #define BASEPRI_MODIFIED_2 0x40 #define SWAP_RETVAL 0x1234 #ifndef EXC_RETURN_FTYPE /* bit [4] allocate stack for floating-point context: 0=done 1=skipped */ -#define EXC_RETURN_FTYPE (0x00000010UL) +#define EXC_RETURN_FTYPE (0x00000010UL) #endif #if defined(CONFIG_ARMV8_1_M_MAINLINE) @@ -32,9 +31,9 @@ * For ARMv8.1-M, the FPSCR[18:16] LTPSIZE field may always read 0b010 if MVE * is not implemented, so mask it when validating the value of the FPSCR. */ -#define FPSCR_MASK (~FPU_FPDSCR_LTPSIZE_Msk) +#define FPSCR_MASK (~FPU_FPDSCR_LTPSIZE_Msk) #else -#define FPSCR_MASK (0xffffffffU) +#define FPSCR_MASK (0xffffffffU) #endif extern void z_move_thread_to_end_of_prio_q(struct k_thread *thread); @@ -53,75 +52,54 @@ int ztest_swap_return_val; /* Arbitrary values for the callee-saved registers, * enforced in the beginning of the test. */ -const _callee_saved_t ztest_thread_callee_saved_regs_init = { - .v1 = 0x12345678, .v2 = 0x23456789, .v3 = 0x3456789a, .v4 = 0x456789ab, - .v5 = 0x56789abc, .v6 = 0x6789abcd, .v7 = 0x789abcde, .v8 = 0x89abcdef -}; +const _callee_saved_t ztest_thread_callee_saved_regs_init = {.v1 = 0x12345678, + .v2 = 0x23456789, + .v3 = 0x3456789a, + .v4 = 0x456789ab, + .v5 = 0x56789abc, + .v6 = 0x6789abcd, + .v7 = 0x789abcde, + .v8 = 0x89abcdef}; static void load_callee_saved_regs(const _callee_saved_t *regs) { /* Load the callee-saved registers with given values */ #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - __asm__ volatile ( - "mov r1, r7;\n\t" - "mov r0, %0;\n\t" - "add r0, #16;\n\t" - "ldmia r0!, {r4-r7};\n\t" - "mov r8, r4;\n\t" - "mov r9, r5;\n\t" - "mov r10, r6;\n\t" - "mov r11, r7;\n\t" - "sub r0, #32;\n\t" - "ldmia r0!, {r4-r7};\n\t" - "mov r7, r1;\n\t" - : /* no output */ - : "r" (regs) - : "memory", "r1", "r0" - ); + __asm__ volatile("mov r1, r7;\n\t" + "mov r0, %0;\n\t" + "add r0, #16;\n\t" + "ldmia r0!, {r4-r7};\n\t" + "mov r8, r4;\n\t" + "mov r9, r5;\n\t" + "mov r10, r6;\n\t" + "mov r11, r7;\n\t" + "sub r0, #32;\n\t" + "ldmia r0!, {r4-r7};\n\t" + "mov r7, r1;\n\t" + : /* no output */ + : "r"(regs) + : "memory", "r1", "r0"); #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - __asm__ volatile ( - "mov r1, r7;\n\t" - "ldmia %0, {v1-v8};\n\t" - "mov r7, r1;\n\t" - : /* no output */ - : "r" (regs) - : "memory", "r1" - ); + __asm__ volatile("mov r1, r7;\n\t" + "ldmia %0, {v1-v8};\n\t" + "mov r7, r1;\n\t" + : /* no output */ + : "r"(regs) + : "memory", "r1"); #endif barrier_dsync_fence_full(); } -static void verify_callee_saved(const _callee_saved_t *src, - const _callee_saved_t *dst) +static void verify_callee_saved(const _callee_saved_t *src, const _callee_saved_t *dst) { /* Verify callee-saved registers are as expected */ - zassert_true((src->v1 == dst->v1) - && (src->v2 == dst->v2) - && (src->v3 == dst->v3) - && (src->v4 == dst->v4) - && (src->v5 == dst->v5) - && (src->v6 == dst->v6) - && (src->v7 == dst->v7) - && (src->v8 == dst->v8), - " got: 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n" - " expected: 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n", - src->v1, - src->v2, - src->v3, - src->v4, - src->v5, - src->v6, - src->v7, - src->v8, - dst->v1, - dst->v2, - dst->v3, - dst->v4, - dst->v5, - dst->v6, - dst->v7, - dst->v8 - ); + zassert_true((src->v1 == dst->v1) && (src->v2 == dst->v2) && (src->v3 == dst->v3) && + (src->v4 == dst->v4) && (src->v5 == dst->v5) && (src->v6 == dst->v6) && + (src->v7 == dst->v7) && (src->v8 == dst->v8), + " got: 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n" + " expected: 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n", + src->v1, src->v2, src->v3, src->v4, src->v5, src->v6, src->v7, src->v8, + dst->v1, dst->v2, dst->v3, dst->v4, dst->v5, dst->v6, dst->v7, dst->v8); } #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) @@ -131,85 +109,57 @@ static void verify_callee_saved(const _callee_saved_t *src, /* Arbitrary values for the floating-point callee-saved registers */ struct _preempt_float ztest_thread_fp_callee_saved_regs = { - .s16 = 0x11111111, .s17 = 0x22222222, - .s18 = 0x33333333, .s19 = 0x44444444, - .s20 = 0x55555555, .s21 = 0x66666666, - .s22 = 0x77777777, .s23 = 0x88888888, - .s24 = 0x99999999, .s25 = 0xaaaaaaaa, - .s26 = 0xbbbbbbbb, .s27 = 0xcccccccc, - .s28 = 0xdddddddd, .s29 = 0xeeeeeeee, - .s30 = 0xffffffff, .s31 = 0x00000000, + .s16 = 0x11111111, + .s17 = 0x22222222, + .s18 = 0x33333333, + .s19 = 0x44444444, + .s20 = 0x55555555, + .s21 = 0x66666666, + .s22 = 0x77777777, + .s23 = 0x88888888, + .s24 = 0x99999999, + .s25 = 0xaaaaaaaa, + .s26 = 0xbbbbbbbb, + .s27 = 0xcccccccc, + .s28 = 0xdddddddd, + .s29 = 0xeeeeeeee, + .s30 = 0xffffffff, + .s31 = 0x00000000, }; -static void load_fp_callee_saved_regs( - const volatile struct _preempt_float *regs) +static void load_fp_callee_saved_regs(const volatile struct _preempt_float *regs) { - __asm__ volatile ( - "vldmia %0, {s16-s31};\n\t" - : - : "r" (regs) - : "memory" - ); + __asm__ volatile("vldmia %0, {s16-s31};\n\t" : : "r"(regs) : "memory"); barrier_dsync_fence_full(); } static void verify_fp_callee_saved(const struct _preempt_float *src, - const struct _preempt_float *dst) + const struct _preempt_float *dst) { /* Verify FP callee-saved registers are as expected */ - zassert_true((src->s16 == dst->s16) - && (src->s17 == dst->s17) - && (src->s18 == dst->s18) - && (src->s19 == dst->s19) - && (src->s20 == dst->s20) - && (src->s21 == dst->s21) - && (src->s22 == dst->s22) - && (src->s23 == dst->s23) - && (src->s24 == dst->s24) - && (src->s25 == dst->s25) - && (src->s26 == dst->s26) - && (src->s27 == dst->s27) - && (src->s28 == dst->s28) - && (src->s29 == dst->s29) - && (src->s30 == dst->s30) - && (src->s31 == dst->s31), - " got: 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x" - " 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n" - " expected: 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x" - " 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n", - (double)src->s16, - (double)src->s17, - (double)src->s18, - (double)src->s19, - (double)src->s20, - (double)src->s21, - (double)src->s22, - (double)src->s23, - (double)src->s24, - (double)src->s25, - (double)src->s26, - (double)src->s27, - (double)src->s28, - (double)src->s29, - (double)src->s30, - (double)src->s31, - (double)dst->s16, - (double)dst->s17, - (double)dst->s18, - (double)dst->s19, - (double)dst->s20, - (double)dst->s21, - (double)dst->s22, - (double)dst->s23, - (double)dst->s24, - (double)dst->s25, - (double)dst->s26, - (double)dst->s27, - (double)dst->s28, - (double)dst->s29, - (double)dst->s30, - (double)dst->s31 - ); + /* clang-format off */ + zassert_true((src->s16 == dst->s16) && + (src->s17 == dst->s17) && (src->s18 == dst->s18) && + (src->s19 == dst->s19) && (src->s20 == dst->s20) && + (src->s21 == dst->s21) && (src->s22 == dst->s22) && + (src->s23 == dst->s23) && (src->s24 == dst->s24) && + (src->s25 == dst->s25) && (src->s26 == dst->s26) && + (src->s27 == dst->s27) && (src->s28 == dst->s28) && + (src->s29 == dst->s29) && (src->s30 == dst->s30) && + (src->s31 == dst->s31), + " got: 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x" + " 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n" + " expected: 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x" + " 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n", + (double)src->s16, (double)src->s17, (double)src->s18, (double)src->s19, + (double)src->s20, (double)src->s21, (double)src->s22, (double)src->s23, + (double)src->s24, (double)src->s25, (double)src->s26, (double)src->s27, + (double)src->s28, (double)src->s29, (double)src->s30, (double)src->s31, + (double)dst->s16, (double)dst->s17, (double)dst->s18, (double)dst->s19, + (double)dst->s20, (double)dst->s21, (double)dst->s22, (double)dst->s23, + (double)dst->s24, (double)dst->s25, (double)dst->s26, (double)dst->s27, + (double)dst->s28, (double)dst->s29, (double)dst->s30, (double)dst->s31); + /* clang-format on */ } #else @@ -226,91 +176,85 @@ static void alt_thread_entry(void *p1, void *p2, void *p3) int init_flag, post_flag; /* Lock interrupts to make sure we get preempted only when - * it is required by the test */ + * it is required by the test + */ (void)irq_lock(); init_flag = switch_flag; zassert_true(init_flag == false, - "Alternative thread: switch flag not false on thread entry\n"); + "Alternative thread: switch flag not false on thread entry\n"); /* Set switch flag */ switch_flag = true; #if defined(CONFIG_NO_OPTIMIZATIONS) zassert_true(p_ztest_thread->arch.basepri == 0, - "ztest thread basepri not preserved in swap-out\n"); + "ztest thread basepri not preserved in swap-out\n"); #else /* Verify that the main test thread has the correct value * for state variable thread.arch.basepri (set before swap). */ zassert_true(p_ztest_thread->arch.basepri == BASEPRI_MODIFIED_1, - "ztest thread basepri not preserved in swap-out\n"); + "ztest thread basepri not preserved in swap-out\n"); /* Verify original swap return value (set by arch_swap() */ zassert_true(p_ztest_thread->arch.swap_return_value == -EAGAIN, - "ztest thread swap-return-value not preserved in swap-out\n"); + "ztest thread swap-return-value not preserved in swap-out\n"); #endif /* Verify that the main test thread (ztest) has stored the callee-saved * registers properly in its corresponding callee-saved container. */ - verify_callee_saved( - (const _callee_saved_t *)&p_ztest_thread->callee_saved, - &ztest_thread_callee_saved_regs_container); + verify_callee_saved((const _callee_saved_t *)&p_ztest_thread->callee_saved, + &ztest_thread_callee_saved_regs_container); /* Zero the container of the callee-saved registers, to validate, * later, that it is populated properly. */ - memset(&ztest_thread_callee_saved_regs_container, - 0, sizeof(_callee_saved_t)); + memset(&ztest_thread_callee_saved_regs_container, 0, sizeof(_callee_saved_t)); #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) /* Verify that the _current_ (alt) thread is initialized with FPCA cleared. */ zassert_true((__get_CONTROL() & CONTROL_FPCA_Msk) == 0, - "CONTROL.FPCA is not cleared at initialization: 0x%x\n", - __get_CONTROL()); + "CONTROL.FPCA is not cleared at initialization: 0x%x\n", __get_CONTROL()); /* Verify that the _current_ (alt) thread is * initialized with EXC_RETURN.Ftype set */ zassert_true((_current->arch.mode_exc_return & EXC_RETURN_FTYPE) != 0, - "Alt thread FPCA flag not clear at initialization\n"); + "Alt thread FPCA flag not clear at initialization\n"); #if defined(CONFIG_MPU_STACK_GUARD) /* Alt thread is created with K_FP_REGS set, so we * expect lazy stacking and long guard to be enabled. */ - zassert_true((_current->arch.mode & - Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0, - "Alt thread MPU GUAR DFLOAT flag not set at initialization\n"); + zassert_true((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0, + "Alt thread MPU GUAR DFLOAT flag not set at initialization\n"); zassert_true((_current->base.user_options & K_FP_REGS) != 0, - "Alt thread K_FP_REGS not set at initialization\n"); + "Alt thread K_FP_REGS not set at initialization\n"); zassert_true((FPU->FPCCR & FPU_FPCCR_LSPEN_Msk) != 0, - "Lazy FP Stacking not set at initialization\n"); + "Lazy FP Stacking not set at initialization\n"); #endif - /* Verify that the _current_ (alt) thread is initialized with FPSCR cleared. */ zassert_true((__get_FPSCR() & FPSCR_MASK) == 0, - "(Alt thread) FPSCR is not cleared at initialization: 0x%x\n", __get_FPSCR()); + "(Alt thread) FPSCR is not cleared at initialization: 0x%x\n", __get_FPSCR()); zassert_true((p_ztest_thread->arch.mode_exc_return & EXC_RETURN_FTYPE) == 0, - "ztest thread mode Ftype flag not updated at swap-out: 0x%0x\n", - p_ztest_thread->arch.mode); + "ztest thread mode Ftype flag not updated at swap-out: 0x%0x\n", + p_ztest_thread->arch.mode); /* Verify that the main test thread (ztest) has stored the FP * callee-saved registers properly in its corresponding FP * callee-saved container. */ - verify_fp_callee_saved((const struct _preempt_float *) - &p_ztest_thread->arch.preempt_float, - &ztest_thread_fp_callee_saved_regs); + verify_fp_callee_saved((const struct _preempt_float *)&p_ztest_thread->arch.preempt_float, + &ztest_thread_fp_callee_saved_regs); /* Zero the container of the FP callee-saved registers, to validate, * later, that it is populated properly. */ - memset(&ztest_thread_fp_callee_saved_regs, - 0, sizeof(ztest_thread_fp_callee_saved_regs)); + memset(&ztest_thread_fp_callee_saved_regs, 0, sizeof(ztest_thread_fp_callee_saved_regs)); #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ @@ -336,7 +280,7 @@ static void alt_thread_entry(void *p1, void *p2, void *p3) * Note: preserve r7 register (frame pointer). */ #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - __asm__ volatile ( + __asm__ volatile( /* Stash r4-r11 in stack, they will be restored much later in * another inline asm -- that should be reworked since stack * must be balanced when we leave any inline asm. We could @@ -373,21 +317,18 @@ static void alt_thread_entry(void *p1, void *p2, void *p3) "pop {r0, r7};\n\t" : /* no output */ - : "r" (&ztest_thread_callee_saved_regs_container) - : "memory", "r0", "r2", "r3" - ); + : "r"(&ztest_thread_callee_saved_regs_container) + : "memory", "r0", "r2", "r3"); #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - __asm__ volatile ( - "push {v1-v8};\n\t" - "push {r0, r1};\n\t" - "mov r0, r7;\n\t" - "ldmia %0, {v1-v8};\n\t" - "mov r7, r0;\n\t" - "pop {r0, r1};\n\t" - : /* no output */ - : "r" (&ztest_thread_callee_saved_regs_container) - : "memory", "r0" - ); + __asm__ volatile("push {v1-v8};\n\t" + "push {r0, r1};\n\t" + "mov r0, r7;\n\t" + "ldmia %0, {v1-v8};\n\t" + "mov r7, r0;\n\t" + "pop {r0, r1};\n\t" + : /* no output */ + : "r"(&ztest_thread_callee_saved_regs_container) + : "memory", "r0"); #endif /* Manually trigger a context-switch, to swap-out @@ -399,20 +340,17 @@ static void alt_thread_entry(void *p1, void *p2, void *p3) /* Restore stacked callee-saved registers */ #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - __asm__ volatile ( - "pop {r4, r5, r6, r7};\n\t" - "mov r8, r4;\n\t" - "mov r9, r5;\n\t" - "mov r10, r6;\n\t" - "mov r11, r7;\n\t" - "pop {r4, r5, r6, r7};\n\t" - : : : - ); + __asm__ volatile("pop {r4, r5, r6, r7};\n\t" + "mov r8, r4;\n\t" + "mov r9, r5;\n\t" + "mov r10, r6;\n\t" + "mov r11, r7;\n\t" + "pop {r4, r5, r6, r7};\n\t" + : + : + :); #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - __asm__ volatile ( - "pop {v1-v8};\n\t" - : : : - ); + __asm__ volatile("pop {v1-v8};\n\t" : : :); #endif /* Verify that the main test thread has managed to resume, before @@ -422,7 +360,7 @@ static void alt_thread_entry(void *p1, void *p2, void *p3) */ post_flag = switch_flag; zassert_true(post_flag == false, - "Alternative thread: switch flag not false on thread exit\n"); + "Alternative thread: switch flag not false on thread exit\n"); } #if !defined(CONFIG_NO_OPTIMIZATIONS) @@ -462,90 +400,77 @@ ZTEST(arm_thread_swap, test_arm_thread_swap) /* Confirm initial conditions before starting the test. */ test_flag = switch_flag; - zassert_true(test_flag == false, - "Switch flag not initialized properly\n"); + zassert_true(test_flag == false, "Switch flag not initialized properly\n"); zassert_true(_current->arch.basepri == 0, - "Thread BASEPRI flag not clear at thread start\n"); + "Thread BASEPRI flag not clear at thread start\n"); /* Verify, also, that the interrupts are unlocked. */ #if defined(CONFIG_CPU_CORTEX_M_HAS_BASEPRI) - zassert_true(__get_BASEPRI() == 0, - "initial BASEPRI not zero\n"); + zassert_true(__get_BASEPRI() == 0, "initial BASEPRI not zero\n"); #else /* For Cortex-M Baseline architecture, we verify that * the interrupt lock is disabled. */ - zassert_true(__get_PRIMASK() == 0, - "initial PRIMASK not zero\n"); + zassert_true(__get_PRIMASK() == 0, "initial PRIMASK not zero\n"); #endif /* CONFIG_CPU_CORTEX_M_HAS_BASEPRI */ #if defined(CONFIG_USERSPACE) /* The main test thread is set to run in privilege mode */ zassert_false((arch_is_user_context()), - "Main test thread does not start in privilege mode\n"); + "Main test thread does not start in privilege mode\n"); /* Assert that the mode status variable indicates privilege mode */ zassert_true((_current->arch.mode & CONTROL_nPRIV_Msk) == 0, - "Thread nPRIV flag not clear for supervisor thread: 0x%0x\n", - _current->arch.mode); + "Thread nPRIV flag not clear for supervisor thread: 0x%0x\n", + _current->arch.mode); #endif /* CONFIG_USERSPACE */ #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) /* The main test thread is not (yet) actively using the FP registers */ zassert_true((_current->arch.mode_exc_return & EXC_RETURN_FTYPE) != 0, - "Thread Ftype flag not set at initialization 0x%0x\n", - _current->arch.mode); + "Thread Ftype flag not set at initialization 0x%0x\n", _current->arch.mode); /* Verify that the main test thread is initialized with FPCA cleared. */ zassert_true((__get_CONTROL() & CONTROL_FPCA_Msk) == 0, - "CONTROL.FPCA is not cleared at initialization: 0x%x\n", - __get_CONTROL()); + "CONTROL.FPCA is not cleared at initialization: 0x%x\n", __get_CONTROL()); /* Verify that the main test thread is initialized with FPSCR cleared. */ zassert_true((__get_FPSCR() & FPSCR_MASK) == 0, - "FPSCR is not cleared at initialization: 0x%x\n", __get_FPSCR()); + "FPSCR is not cleared at initialization: 0x%x\n", __get_FPSCR()); /* Clear the thread's floating-point callee-saved registers' container. * The container will, later, be populated by the swap mechanism. */ - memset(&_current->arch.preempt_float, 0, - sizeof(struct _preempt_float)); + memset(&_current->arch.preempt_float, 0, sizeof(struct _preempt_float)); /* Randomize the FP callee-saved registers at test initialization */ load_fp_callee_saved_regs(&ztest_thread_fp_callee_saved_regs); /* Modify bit-0 of the FPSCR - will be checked again upon swap-in. */ - zassert_true((__get_FPSCR() & 0x1) == 0, - "FPSCR bit-0 has been set before testing it\n"); + zassert_true((__get_FPSCR() & 0x1) == 0, "FPSCR bit-0 has been set before testing it\n"); __set_FPSCR(__get_FPSCR() | 0x1); /* The main test thread is using the FP registers, but the .mode * flag is not updated until the next context switch. */ zassert_true((_current->arch.mode_exc_return & EXC_RETURN_FTYPE) != 0, - "Thread Ftype flag not set at initialization\n"); + "Thread Ftype flag not set at initialization\n"); #if defined(CONFIG_MPU_STACK_GUARD) - zassert_true((_current->arch.mode & - Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) == 0, - "Thread MPU GUAR DFLOAT flag not clear at initialization\n"); + zassert_true((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) == 0, + "Thread MPU GUAR DFLOAT flag not clear at initialization\n"); zassert_true((_current->base.user_options & K_FP_REGS) == 0, - "Thread K_FP_REGS not clear at initialization\n"); + "Thread K_FP_REGS not clear at initialization\n"); zassert_true((FPU->FPCCR & FPU_FPCCR_LSPEN_Msk) == 0, - "Lazy FP Stacking not clear at initialization\n"); + "Lazy FP Stacking not clear at initialization\n"); #endif #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ /* Create an alternative (supervisor) testing thread */ - k_thread_create(&alt_thread, - alt_thread_stack, - K_THREAD_STACK_SIZEOF(alt_thread_stack), - alt_thread_entry, - NULL, NULL, NULL, - K_PRIO_COOP(PRIORITY), ALT_THREAD_OPTIONS, - K_NO_WAIT); + k_thread_create(&alt_thread, alt_thread_stack, K_THREAD_STACK_SIZEOF(alt_thread_stack), + alt_thread_entry, NULL, NULL, NULL, K_PRIO_COOP(PRIORITY), + ALT_THREAD_OPTIONS, K_NO_WAIT); /* Verify context-switch has not occurred. */ test_flag = switch_flag; - zassert_true(test_flag == false, - "Switch flag incremented when it should not have\n"); + zassert_true(test_flag == false, "Switch flag incremented when it should not have\n"); /* Prepare to force a context switch to the alternative thread, * by manually adding the current thread to the end of the queue, @@ -565,8 +490,7 @@ ZTEST(arm_thread_swap, test_arm_thread_swap) /* Verify context-switch has not occurred yet. */ test_flag = switch_flag; - zassert_true(test_flag == false, - "Switch flag incremented by unexpected context-switch.\n"); + zassert_true(test_flag == false, "Switch flag incremented by unexpected context-switch.\n"); /* Store the callee-saved registers to some global memory * accessible to the alternative testing thread. That @@ -575,27 +499,24 @@ ZTEST(arm_thread_swap, test_arm_thread_swap) * registers' container. */ #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - __asm__ volatile ( - "push {r0, r1, r2, r3};\n\t" - "mov r1, %0;\n\t" - "stmia r1!, {r4-r7};\n\t" - "mov r2, r8;\n\t" - "mov r3, r9;\n\t" - "stmia r1!, {r2-r3};\n\t" - "mov r2, r10;\n\t" - "mov r3, r11;\n\t" - "stmia r1!, {r2-r3};\n\t" - "pop {r0, r1, r2, r3};\n\t" - : : "r" (&ztest_thread_callee_saved_regs_container) - : "memory" - ); - #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - __asm__ volatile ( - "stmia %0, {v1-v8};\n\t" - : - : "r" (&ztest_thread_callee_saved_regs_container) - : "memory" - ); + __asm__ volatile("push {r0, r1, r2, r3};\n\t" + "mov r1, %0;\n\t" + "stmia r1!, {r4-r7};\n\t" + "mov r2, r8;\n\t" + "mov r3, r9;\n\t" + "stmia r1!, {r2-r3};\n\t" + "mov r2, r10;\n\t" + "mov r3, r11;\n\t" + "stmia r1!, {r2-r3};\n\t" + "pop {r0, r1, r2, r3};\n\t" + : + : "r"(&ztest_thread_callee_saved_regs_container) + : "memory"); +#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + __asm__ volatile("stmia %0, {v1-v8};\n\t" + : + : "r"(&ztest_thread_callee_saved_regs_container) + : "memory"); #endif /* Manually trigger a context-switch to swap-out the current thread. @@ -608,7 +529,7 @@ ZTEST(arm_thread_swap, test_arm_thread_swap) irq_unlock(0); /* The thread is now swapped-back in. */ -#else/* CONFIG_NO_OPTIMIZATIONS */ +#else /* CONFIG_NO_OPTIMIZATIONS */ /* Fake a different irq_unlock key when performing swap. * This will be verified by the alternative test thread. @@ -622,27 +543,24 @@ ZTEST(arm_thread_swap, test_arm_thread_swap) /* Dump callee-saved registers to memory. */ #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - __asm__ volatile ( - "push {r0, r1, r2, r3};\n\t" - "mov r1, %0;\n\t" - "stmia r1!, {r4-r7};\n\t" - "mov r2, r8;\n\t" - "mov r3, r9;\n\t" - "stmia r1!, {r2-r3};\n\t" - "mov r2, r10;\n\t" - "mov r3, r11;\n\t" - "stmia r1!, {r2-r3};\n\t" - "pop {r0, r1, r2, r3};\n\t" - : : "r" (&ztest_thread_callee_saved_regs_container) - : "memory" - ); - #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - __asm__ volatile ( - "stmia %0, {v1-v8};\n\t" - : - : "r" (&ztest_thread_callee_saved_regs_container) - : "memory" - ); + __asm__ volatile("push {r0, r1, r2, r3};\n\t" + "mov r1, %0;\n\t" + "stmia r1!, {r4-r7};\n\t" + "mov r2, r8;\n\t" + "mov r3, r9;\n\t" + "stmia r1!, {r2-r3};\n\t" + "mov r2, r10;\n\t" + "mov r3, r11;\n\t" + "stmia r1!, {r2-r3};\n\t" + "pop {r0, r1, r2, r3};\n\t" + : + : "r"(&ztest_thread_callee_saved_regs_container) + : "memory"); +#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + __asm__ volatile("stmia %0, {v1-v8};\n\t" + : + : "r"(&ztest_thread_callee_saved_regs_container) + : "memory"); #endif #if !defined(CONFIG_NO_OPTIMIZATIONS) @@ -652,38 +570,30 @@ ZTEST(arm_thread_swap, test_arm_thread_swap) * used, as base register in the Store Multiple instruction. * We also enforce write-back to suppress assembler warning. */ - __asm__ volatile ( - "push {r0, r1, r2, r3, r4, r5, r6, r7};\n\t" - "stm %0!, {%1};\n\t" - "pop {r0, r1, r2, r3, r4, r5, r6, r7};\n\t" - : - : "r" (&ztest_swap_return_val), "r" (swap_return_val) - : "memory" - ); + __asm__ volatile("push {r0, r1, r2, r3, r4, r5, r6, r7};\n\t" + "stm %0!, {%1};\n\t" + "pop {r0, r1, r2, r3, r4, r5, r6, r7};\n\t" + : + : "r"(&ztest_swap_return_val), "r"(swap_return_val) + : "memory"); #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - __asm__ volatile ( - "stm %0, {%1};\n\t" - : - : "r" (&ztest_swap_return_val), "r" (swap_return_val) - : "memory" - ); + __asm__ volatile("stm %0, {%1};\n\t" + : + : "r"(&ztest_swap_return_val), "r"(swap_return_val) + : "memory"); #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ #endif - /* After swap-back, verify that the callee-saved registers loaded, * look exactly as what is located in the respective callee-saved * container of the thread. */ - verify_callee_saved( - &ztest_thread_callee_saved_regs_container, - &_current->callee_saved); + verify_callee_saved(&ztest_thread_callee_saved_regs_container, &_current->callee_saved); /* Verify context-switch did occur. */ test_flag = switch_flag; - zassert_true(test_flag == true, - "Switch flag not incremented as expected %u\n", - switch_flag); + zassert_true(test_flag == true, "Switch flag not incremented as expected %u\n", + switch_flag); /* Clear the switch flag to signal that the main test thread * has been successfully swapped-in, as expected by the test. */ @@ -694,71 +604,63 @@ ZTEST(arm_thread_swap, test_arm_thread_swap) * is now switched back in. */ zassert_true(_current->arch.basepri == 0, - "arch.basepri value not in accordance with the update\n"); + "arch.basepri value not in accordance with the update\n"); #if defined(CONFIG_CPU_CORTEX_M_HAS_BASEPRI) /* Verify that the BASEPRI register is updated during the last * swap-in of the thread. */ zassert_true(__get_BASEPRI() == BASEPRI_MODIFIED_2, - "BASEPRI not in accordance with the update: 0x%0x\n", - __get_BASEPRI()); + "BASEPRI not in accordance with the update: 0x%0x\n", __get_BASEPRI()); #else /* For Cortex-M Baseline architecture, we verify that * the interrupt lock is enabled. */ - zassert_true(__get_PRIMASK() != 0, - "PRIMASK not in accordance with the update: 0x%0x\n", - __get_PRIMASK()); + zassert_true(__get_PRIMASK() != 0, "PRIMASK not in accordance with the update: 0x%0x\n", + __get_PRIMASK()); #endif /* CONFIG_CPU_CORTEX_M_HAS_BASEPRI */ #if !defined(CONFIG_NO_OPTIMIZATIONS) /* The thread is now swapped-back in. */ zassert_equal(_current->arch.swap_return_value, SWAP_RETVAL, - "Swap value not set as expected: 0x%x (0x%x)\n", - _current->arch.swap_return_value, SWAP_RETVAL); + "Swap value not set as expected: 0x%x (0x%x)\n", + _current->arch.swap_return_value, SWAP_RETVAL); zassert_equal(_current->arch.swap_return_value, ztest_swap_return_val, - "Swap value not returned as expected 0x%x (0x%x)\n", - _current->arch.swap_return_value, ztest_swap_return_val); + "Swap value not returned as expected 0x%x (0x%x)\n", + _current->arch.swap_return_value, ztest_swap_return_val); #endif #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) /* Dump callee-saved registers to memory. */ - __asm__ volatile ( - "vstmia %0, {s16-s31};\n\t" - : - : "r" (&ztest_thread_fp_callee_saved_regs) - : "memory" - ); + __asm__ volatile("vstmia %0, {s16-s31};\n\t" + : + : "r"(&ztest_thread_fp_callee_saved_regs) + : "memory"); /* After swap-back, verify that the FP callee-saved registers loaded, * look exactly as what is located in the respective FP callee-saved * container of the thread. */ - verify_fp_callee_saved( - &ztest_thread_fp_callee_saved_regs, - &_current->arch.preempt_float); + verify_fp_callee_saved(&ztest_thread_fp_callee_saved_regs, &_current->arch.preempt_float); /* Verify that the main test thread restored the FPSCR bit-0. */ - zassert_true((__get_FPSCR() & 0x1) == 0x1, - "FPSCR bit-0 not restored at swap: 0x%x\n", __get_FPSCR()); + zassert_true((__get_FPSCR() & 0x1) == 0x1, "FPSCR bit-0 not restored at swap: 0x%x\n", + __get_FPSCR()); /* The main test thread is using the FP registers, and the .mode * flag and MPU GUARD flag are now updated. */ zassert_true((_current->arch.mode_exc_return & EXC_RETURN_FTYPE) == 0, - "Thread Ftype flag not cleared after main returned back\n"); + "Thread Ftype flag not cleared after main returned back\n"); #if defined(CONFIG_MPU_STACK_GUARD) - zassert_true((_current->arch.mode & - Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0, - "Thread MPU GUARD FLOAT flag not set\n"); + zassert_true((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0, + "Thread MPU GUARD FLOAT flag not set\n"); zassert_true((_current->base.user_options & K_FP_REGS) != 0, - "Thread K_FPREGS not set after main returned back\n"); + "Thread K_FPREGS not set after main returned back\n"); zassert_true((FPU->FPCCR & FPU_FPCCR_LSPEN_Msk) != 0, - "Lazy FP Stacking not set after main returned back\n"); + "Lazy FP Stacking not set after main returned back\n"); #endif #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ - } /** * @} diff --git a/tests/arch/arm/arm_thread_swap_tz/src/main.c b/tests/arch/arm/arm_thread_swap_tz/src/main.c index ebb18fafded61..86cfd5333178b 100644 --- a/tests/arch/arm/arm_thread_swap_tz/src/main.c +++ b/tests/arch/arm/arm_thread_swap_tz/src/main.c @@ -10,7 +10,7 @@ #ifndef EXC_RETURN_S /* bit [6] stack used to push registers: 0=Non-secure 1=Secure */ -#define EXC_RETURN_S (0x00000040UL) +#define EXC_RETURN_S (0x00000040UL) #endif #define HASH_LEN 32 @@ -27,8 +27,8 @@ static void do_hash(char *hash) size_t len; /* Calculate correct hash. */ - psa_status_t status = psa_hash_compute(PSA_ALG_SHA_256, dummy_string, - sizeof(dummy_string), hash, HASH_LEN, &len); + psa_status_t status = psa_hash_compute(PSA_ALG_SHA_256, dummy_string, sizeof(dummy_string), + hash, HASH_LEN, &len); zassert_equal(PSA_SUCCESS, status, "psa_hash_compute_fail: %d\n", status); zassert_equal(HASH_LEN, len, "hash length not correct\n"); @@ -39,12 +39,12 @@ static void work_func(struct k_work *work) #ifdef CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS /* Check that the main thread was executing in secure mode. */ zassert_true(main_thread->arch.mode_exc_return & EXC_RETURN_S, - "EXC_RETURN not secure: 0x%x\n", main_thread->arch.mode_exc_return); + "EXC_RETURN not secure: 0x%x\n", main_thread->arch.mode_exc_return); #else /* Check that the main thread was executing in nonsecure mode. */ zassert_false(main_thread->arch.mode_exc_return & EXC_RETURN_S, - "EXC_RETURN not nonsecure: 0x%x\n", main_thread->arch.mode_exc_return); + "EXC_RETURN not nonsecure: 0x%x\n", main_thread->arch.mode_exc_return); #endif work_done = true; @@ -54,27 +54,23 @@ static void work_func(struct k_work *work) */ #ifdef CONFIG_CPU_HAS_FPU uint32_t clobber_val[16] = { - 0xdeadbee0, 0xdeadbee1, 0xdeadbee2, 0xdeadbee3, - 0xdeadbee4, 0xdeadbee5, 0xdeadbee6, 0xdeadbee7, - 0xdeadbee8, 0xdeadbee9, 0xdeadbeea, 0xdeadbeeb, + 0xdeadbee0, 0xdeadbee1, 0xdeadbee2, 0xdeadbee3, 0xdeadbee4, 0xdeadbee5, + 0xdeadbee6, 0xdeadbee7, 0xdeadbee8, 0xdeadbee9, 0xdeadbeea, 0xdeadbeeb, 0xdeadbeec, 0xdeadbeed, 0xdeadbeee, 0xdeadbeef, }; - __asm__ volatile( - "vldmia %0, {s0-s15}\n" - "vldmia %0, {s16-s31}\n" - :: "r" (clobber_val) : - ); + __asm__ volatile("vldmia %0, {s0-s15}\n" + "vldmia %0, {s16-s31}\n" ::"r"(clobber_val) + :); #endif /* CONFIG_CPU_HAS_FPU */ /* Call a secure service here as well, to test the added complexity of * calling secure services from two threads. */ - psa_status_t status = psa_hash_compare(PSA_ALG_SHA_256, dummy_string, - sizeof(dummy_string), dummy_digest_correct, HASH_LEN); + psa_status_t status = psa_hash_compare(PSA_ALG_SHA_256, dummy_string, sizeof(dummy_string), + dummy_digest_correct, HASH_LEN); zassert_equal(PSA_SUCCESS, status, "psa_hash_compare failed\n"); - } ZTEST(thread_swap_tz, test_thread_swap_tz) @@ -108,25 +104,22 @@ ZTEST(thread_swap_tz, test_thread_swap_tz) */ #ifdef CONFIG_CPU_HAS_FPU uint32_t test_val0[16] = { - 0x1a2b3c40, 0x1a2b3c41, 0x1a2b3c42, 0x1a2b3c43, - 0x1a2b3c44, 0x1a2b3c45, 0x1a2b3c46, 0x1a2b3c47, - 0x1a2b3c48, 0x1a2b3c49, 0x1a2b3c4a, 0x1a2b3c4b, + 0x1a2b3c40, 0x1a2b3c41, 0x1a2b3c42, 0x1a2b3c43, 0x1a2b3c44, 0x1a2b3c45, + 0x1a2b3c46, 0x1a2b3c47, 0x1a2b3c48, 0x1a2b3c49, 0x1a2b3c4a, 0x1a2b3c4b, 0x1a2b3c4c, 0x1a2b3c4d, 0x1a2b3c4e, 0x1a2b3c4f, }; uint32_t test_val1[16] = { - 0x2b3c4d50, 0x2b3c4d51, 0x2b3c4d52, 0x2b3c4d53, - 0x2b3c4d54, 0x2b3c4d55, 0x2b3c4d56, 0x2b3c4d57, - 0x2b3c4d58, 0x2b3c4d59, 0x2b3c4d5a, 0x2b3c4d5b, + 0x2b3c4d50, 0x2b3c4d51, 0x2b3c4d52, 0x2b3c4d53, 0x2b3c4d54, 0x2b3c4d55, + 0x2b3c4d56, 0x2b3c4d57, 0x2b3c4d58, 0x2b3c4d59, 0x2b3c4d5a, 0x2b3c4d5b, 0x2b3c4d5c, 0x2b3c4d5d, 0x2b3c4d5e, 0x2b3c4d5f, }; uint32_t test_val_res0[16]; uint32_t test_val_res1[16]; - __asm__ volatile( - "vldmia %0, {s0-s15}\n" - "vldmia %1, {s16-s31}\n" - :: "r" (test_val0), "r" (test_val1) : - ); + __asm__ volatile("vldmia %0, {s0-s15}\n" + "vldmia %1, {s16-s31}\n" ::"r"(test_val0), + "r"(test_val1) + :); #endif /* CONFIG_CPU_HAS_FPU */ @@ -135,11 +128,10 @@ ZTEST(thread_swap_tz, test_thread_swap_tz) zassert_true(work_done, "Interrupting work never happened\n"); #ifdef CONFIG_CPU_HAS_FPU - __asm__ volatile( - "vstmia %0, {s0-s15}\n" - "vstmia %1, {s16-s31}\n" - :: "r" (test_val_res0), "r" (test_val_res1) : - ); + __asm__ volatile("vstmia %0, {s0-s15}\n" + "vstmia %1, {s16-s31}\n" ::"r"(test_val_res0), + "r"(test_val_res1) + :); zassert_mem_equal(dummy_digest, dummy_digest_correct, HASH_LEN, NULL); zassert_mem_equal(test_val0, test_val_res0, sizeof(test_val0), NULL); diff --git a/tests/arch/arm/arm_tz_wrap_func/src/main.c b/tests/arch/arm/arm_tz_wrap_func/src/main.c index 407873f906b70..c100dfcd2f084 100644 --- a/tests/arch/arm/arm_tz_wrap_func/src/main.c +++ b/tests/arch/arm/arm_tz_wrap_func/src/main.c @@ -33,7 +33,6 @@ void reset_mocks(void) foo1_arg4 = 0; } - void preface(void) { zassert_true(expect_preface, "%s unexpectedly called", __func__); @@ -42,12 +41,10 @@ void preface(void) expect_foo1 = true; } - uint32_t foo1(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) { zassert_true(expect_foo1, "%s unexpectedly called", __func__); - zassert_equal(arg1, foo1_arg1, "Was 0x%"PRIx32", expected 0x%"PRIx32, - arg1, foo1_arg1); + zassert_equal(arg1, foo1_arg1, "Was 0x%" PRIx32 ", expected 0x%" PRIx32, arg1, foo1_arg1); zassert_equal(arg2, foo1_arg2); zassert_equal(arg3, foo1_arg3); zassert_equal(arg4, foo1_arg4); @@ -57,7 +54,6 @@ uint32_t foo1(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) return foo1_retval; } - void postface(void) { zassert_true(expect_postface, "%s unexpectedly called", __func__); @@ -65,14 +61,12 @@ void postface(void) postface_called = true; } - -uint32_t __attribute__((naked)) wrap_foo1(uint32_t arg1, uint32_t arg2, - uint32_t arg3, uint32_t arg4) +uint32_t __attribute__((naked)) wrap_foo1(uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4) { __TZ_WRAP_FUNC(preface, foo1, postface); } - ZTEST(tz_wrap_func, test_tz_wrap_func) { reset_mocks(); @@ -86,8 +80,7 @@ ZTEST(tz_wrap_func, test_tz_wrap_func) msp1 = __get_MSP(); psp1 = __get_PSP(); - zassert_equal(foo1_retval, - wrap_foo1(foo1_arg1, foo1_arg2, foo1_arg3, foo1_arg4), NULL); + zassert_equal(foo1_retval, wrap_foo1(foo1_arg1, foo1_arg2, foo1_arg3, foo1_arg4), NULL); zassert_equal(msp1, __get_MSP()); zassert_equal(psp1, __get_PSP()); From 0f4eeb6380db5734fd234e44dfa2e4d9e8419c8c Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Sat, 8 Feb 2025 10:13:37 -0800 Subject: [PATCH 0055/6055] soc/mediatek/mtk_adsp: Use smaller accesses when find()ing in device memory Recent Python interpreters have started tossing bus errors from this 12-byte string search (the loader is looking for the winstream descriptor in the live firmware image). My guess is that there's a SIMD optimization that's been added that's trying to do e.g. a 16 byte load, and something in the fabric is kicking that out. Note that this is 100% a software change: the same hardware with one version of the host environment works, and an update breaks it. But really I have no idea what's happening here, the memory region in question is documented as system DRAM, the same bus regular process memory is on (it's just not kernel-utilized memory). All I know is that the bus error is introduced with a Python upgrade from 3.8.20 to 3.11.10. Regardless, it's no great hardship to do the search on 64 bit chunks. Signed-off-by: Andy Ross --- soc/mediatek/mt8xxx/mtk_adsp_load.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/soc/mediatek/mt8xxx/mtk_adsp_load.py b/soc/mediatek/mt8xxx/mtk_adsp_load.py index 03efcd2f1cc76..42127b75ec5c8 100755 --- a/soc/mediatek/mt8xxx/mtk_adsp_load.py +++ b/soc/mediatek/mt8xxx/mtk_adsp_load.py @@ -277,7 +277,13 @@ def find_winstream(maps): magic = b'\x74\x5f\x6a\xd0\x79\xe2\x4f\x00\xcd\xb8\xbd\xf9' for m in maps: if "dram" in m: - magoff = maps[m].find(magic) + # Some python versions produce bus errors (!) on the + # hardware when finding a 12 byte substring (maybe a SIMD + # load that the hardware doesn't like?). Do it in two + # chunks. + magoff = maps[m].find(magic[0:8]) + if magoff >= 0: + magoff = maps[m].find(magic[8:], magoff) - 8 if magoff >= 0: addr = le4(maps[m][magoff + 12 : magoff + 16]) return addr From 4b27b5494fb8d9f342c5e7bdd11aa9c2845b471c Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Sat, 8 Feb 2025 12:51:14 -0800 Subject: [PATCH 0056/6055] soc/mediatek/mtk_adsp: Always cache the full SRAM region I think my original idea with this default MPU setup was that the top bits of the (fast) SRAM region might be useful for host DMA that needed better latencies than the (extremely slow) system DRAM mappings. So it should be left uncached for safety. But unfortunately the author[1] of the SOF heap integration for this platform decided to size the heap dynamically to use most of the SRAM block (the vectors and a few other bits live at the bottom, but most of .text is in DRAM). Needless to say, an uncached heap is sort of a performance disaster. It worked OK for default copy-only topologies but fell over the moment we turned on nontrivial processing. [1] Um... Hi. Yeah, that's me too. Signed-off-by: Andy Ross --- soc/mediatek/mt8xxx/soc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/soc/mediatek/mt8xxx/soc.c b/soc/mediatek/mt8xxx/soc.c index 2b375ccf3951f..330a247bbe93d 100644 --- a/soc/mediatek/mt8xxx/soc.c +++ b/soc/mediatek/mt8xxx/soc.c @@ -197,7 +197,6 @@ static void enable_mpu(void) { 0x10000000, 0x06f00 }, /* MMIO registers */ { 0x1d000000, 0x06000 }, /* inaccessible */ { SRAM_START, 0xf7f00 }, /* cached SRAM */ - { (uint32_t)&_mtk_adsp_sram_end, 0x06f00 }, /* uncached SRAM */ { SRAM_END, 0x06000 }, /* inaccessible */ { DRAM_START, 0xf7f00 }, /* cached DRAM */ { (uint32_t)&_mtk_adsp_dram_end, 0x06f00 }, /* uncached DRAM */ From ef232f34d0759917d612fa06aac53cebd5786f26 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sun, 9 Feb 2025 13:31:08 -0800 Subject: [PATCH 0057/6055] arch: arm: fix compile issue if MEM_ATTR=n and ARM_MPU=y It's possible to have MEM_ATTR=n and ARM_MPU=y. This fixes the compile issue with it by compiling out the calls to define the DT mpu regions. Signed-off-by: Ryan McClelland --- arch/arm/core/mpu/arm_mpu.c | 8 ++++---- arch/arm/core/mpu/nxp_mpu.c | 8 ++++---- arch/arm64/core/cortex_r/arm_mpu.c | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/core/mpu/arm_mpu.c b/arch/arm/core/mpu/arm_mpu.c index bec7b18a4f2c2..e66c02ec067fb 100644 --- a/arch/arm/core/mpu/arm_mpu.c +++ b/arch/arm/core/mpu/arm_mpu.c @@ -93,7 +93,7 @@ static int region_allocate_and_init(const uint8_t index, (reg).dt_addr, \ (reg).dt_size, \ _ATTR) - +#ifdef CONFIG_MEM_ATTR /* This internal function programs the MPU regions defined in the DT when using * the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property. */ @@ -158,7 +158,7 @@ static int mpu_configure_regions_from_dt(uint8_t *reg_index) return 0; } - +#endif /* CONFIG_MEM_ATTR */ /* This internal function programs an MPU region * of a given configuration at a given MPU index. */ @@ -459,13 +459,13 @@ int z_arm_mpu_init(void) /* Update the number of programmed MPU regions. */ static_regions_num = mpu_config.num_regions; - +#ifdef CONFIG_MEM_ATTR /* DT-defined MPU regions. */ if (mpu_configure_regions_from_dt(&static_regions_num) == -EINVAL) { __ASSERT(0, "Failed to allocate MPU regions from DT\n"); return -EINVAL; } - +#endif /* CONFIG_MEM_ATTR */ /* Clear all regions before enabling MPU */ for (int i = static_regions_num; i < get_num_regions(); i++) { mpu_clear_region(i); diff --git a/arch/arm/core/mpu/nxp_mpu.c b/arch/arm/core/mpu/nxp_mpu.c index b0fe24c6bf617..ae893086901ce 100644 --- a/arch/arm/core/mpu/nxp_mpu.c +++ b/arch/arm/core/mpu/nxp_mpu.c @@ -151,7 +151,7 @@ static int region_allocate_and_init(const uint8_t index, .end = (reg).dt_addr + (reg).dt_size, \ .attr = _ATTR, \ } - +#ifdef CONFIG_MEM_ATTR /* This internal function programs the MPU regions defined in the DT when using * the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property. */ @@ -198,7 +198,7 @@ static int mpu_configure_regions_from_dt(uint8_t *reg_index) return 0; } - +#endif /* CONFIG_MEM_ATTR */ /** * This internal function is utilized by the MPU driver to combine a given * region attribute configuration and size and fill-in a driver-specific @@ -700,13 +700,13 @@ int z_arm_mpu_init(void) /* Update the number of programmed MPU regions. */ static_regions_num = mpu_config.num_regions; - +#ifdef CONFIG_MEM_ATTR /* DT-defined MPU regions. */ if (mpu_configure_regions_from_dt(&static_regions_num) == -EINVAL) { __ASSERT(0, "Failed to allocate MPU regions from DT\n"); return -EINVAL; } - +#endif /* CONFIG_MEM_ATTR */ arm_core_mpu_enable(); return 0; diff --git a/arch/arm64/core/cortex_r/arm_mpu.c b/arch/arm64/core/cortex_r/arm_mpu.c index 2bd6d265c9a9e..3053d90cb75f6 100644 --- a/arch/arm64/core/cortex_r/arm_mpu.c +++ b/arch/arm64/core/cortex_r/arm_mpu.c @@ -196,7 +196,7 @@ static ALWAYS_INLINE void region_init(const uint32_t index, .limit = (reg).dt_addr + (reg).dt_size, \ .attr = _ATTR, \ } - +#ifdef CONFIG_MEM_ATTR /* This internal function programs the MPU regions defined in the DT when using * the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property. */ @@ -247,7 +247,7 @@ static int mpu_configure_regions_from_dt(uint8_t *reg_index) return 0; } - +#endif /* CONFIG_MEM_ATTR */ /* * @brief MPU default configuration * @@ -303,13 +303,13 @@ FUNC_NO_STACK_PROTECTOR void z_arm64_mm_init(bool is_primary_core) /* Update the number of programmed MPU regions. */ tmp_static_num = mpu_config.num_regions; - +#ifdef CONFIG_MEM_ATTR /* DT-defined MPU regions. */ if (mpu_configure_regions_from_dt(&tmp_static_num) == -EINVAL) { __ASSERT(0, "Failed to allocate MPU regions from DT\n"); return; } - +#endif arm_core_mpu_enable(); if (!is_primary_core) { From 0201683adb512c5a36b530ae919ac092e4a0138f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 10 Feb 2025 09:39:12 +0000 Subject: [PATCH 0058/6055] cmake: snippets: Add snippet help message Adds a help message which gives details on a common issue with snippets where the roots are not known or a snippet is applied to multiple images Signed-off-by: Jamie McCrae --- cmake/modules/snippets.cmake | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cmake/modules/snippets.cmake b/cmake/modules/snippets.cmake index fba7818c65063..b897067667eff 100644 --- a/cmake/modules/snippets.cmake +++ b/cmake/modules/snippets.cmake @@ -94,7 +94,20 @@ function(zephyr_process_snippets) ERROR_VARIABLE output RESULT_VARIABLE ret) if(${ret}) - message(FATAL_ERROR "${output}") + list(JOIN SNIPPET_ROOT "\n " snippet_root_paths) + set(snippet_root_paths "\n ${snippet_root_paths}") + + if(SYSBUILD) + zephyr_get(SYSBUILD_NAME SYSBUILD GLOBAL) + set(extra_output "Snippet roots for image ${SYSBUILD_NAME}:${snippet_root_paths}\n" + "Note that snippets will be applied to all images unless prefixed with the image name " + "e.g. `-D${SYSBUILD_NAME}_SNIPPET=...`, local snippet roots for one image are not set " + "for other images in a build") + else() + set(extra_output "Snippet roots for application:${snippet_root_paths}") + endif() + + message(FATAL_ERROR "${output}" ${extra_output}) endif() include(${snippets_generated}) From 325d6b7d7f99b9d446dc1fcd08f29eb776f82724 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 7 Feb 2025 18:06:26 +0100 Subject: [PATCH 0059/6055] llext: add option to keep section data after llext_load This is required for the functions that inspect the ELF file to work properly. The user must then call llext_free_inspection_data() before calling llext_unload() to free the memory left allocated in the loader and extension memory. Signed-off-by: Luca Burelli --- include/zephyr/llext/llext.h | 24 ++++++++++++++++++++++++ subsys/llext/llext_load.c | 21 +++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index fc9654c408ac5..a77248afda144 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -146,6 +146,7 @@ static inline unsigned int llext_section_count(const struct llext *ext) struct llext_load_param { /** Perform local relocation */ bool relocate_local; + /** * Use the virtual symbol addresses from the ELF, not addresses within * the memory buffer, when calculating relocation targets. It also @@ -154,12 +155,22 @@ struct llext_load_param { * allocation and copying internally. */ bool pre_located; + /** * Extensions can implement custom ELF sections to be loaded in specific * memory regions, detached from other sections of compatible types. * This optional callback checks whether a section should be detached. */ bool (*section_detached)(const elf_shdr_t *shdr); + + /** + * Keep the ELF section data in memory after loading the extension. This + * is needed to use some of the functions in @ref llext_inspect_apis. + * + * @note Related memory must be freed by @ref llext_free_inspection_data + * before the extension can be unloaded via @ref llext_unload. + */ + bool keep_section_info; }; /** Default initializer for @ref llext_load_param */ @@ -211,6 +222,19 @@ int llext_load(struct llext_loader *loader, const char *name, struct llext **ext */ int llext_unload(struct llext **ext); +/** + * @brief Free any inspection-related memory for the specified loader and extension. + * + * This is only required if inspection data was requested at load time by + * setting @ref llext_load_param.keep_section_info; otherwise, this call will + * be a no-op. + * + * @param[in] ldr Extension loader + * @param[in] ext Extension + * @returns 0 on success, or a negative error code. + */ +int llext_free_inspection_data(struct llext_loader *ldr, struct llext *ext); + /** @brief Entry point function signature for an extension. */ typedef void (*llext_entry_fn_t)(void *user_data); diff --git a/subsys/llext/llext_load.c b/subsys/llext/llext_load.c index 68ce4a3f404ab..589b6f2c6b5c3 100644 --- a/subsys/llext/llext_load.c +++ b/subsys/llext/llext_load.c @@ -112,6 +112,7 @@ static int llext_load_elf_data(struct llext_loader *ldr, struct llext *ext) LOG_ERR("Failed to allocate section map, size %zu", sect_map_sz); return -ENOMEM; } + ext->alloc_size += sect_map_sz; for (int i = 0; i < ext->sect_cnt; i++) { ldr->sect_map[i].mem_idx = LLEXT_MEM_COUNT; ldr->sect_map[i].offset = 0; @@ -759,12 +760,13 @@ int do_llext_load(struct llext_loader *ldr, struct llext *ext, out: /* - * Free resources only used during loading. Note that this exploits - * the fact that freeing a NULL pointer has no effect. + * Free resources only used during loading, unless explicitly requested. + * Note that this exploits the fact that freeing a NULL pointer has no effect. */ - llext_free(ldr->sect_map); - ldr->sect_map = NULL; + if (ret != 0 || !ldr_parm || !ldr_parm->keep_section_info) { + llext_free_inspection_data(ldr, ext); + } /* Until proper inter-llext linking is implemented, the symbol table is * not useful outside of the loading process; keep it only if debugging @@ -796,3 +798,14 @@ int do_llext_load(struct llext_loader *ldr, struct llext *ext, return ret; } + +int llext_free_inspection_data(struct llext_loader *ldr, struct llext *ext) +{ + if (ldr->sect_map) { + ext->alloc_size -= ext->sect_cnt * sizeof(ldr->sect_map[0]); + llext_free(ldr->sect_map); + ldr->sect_map = NULL; + } + + return 0; +} From 44c7a1401e489be1ddafc7e906f0c15b23ebce51 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 7 Feb 2025 18:12:18 +0100 Subject: [PATCH 0060/6055] llext: add ELF inspection APIs Add APIs to inspect the contents of an ELF file loaded as an extension. This is useful for applications that need to access the contents of the extension in a more fine-grained way than the existing LLEXT APIs. Use of these APIs requires the 'keep_elf_data' option to be provided via struct llext_load_param to the 'llext_load()' call. Signed-off-by: Luca Burelli --- doc/services/llext/api.rst | 2 + doc/services/llext/load.rst | 4 + include/zephyr/llext/inspect.h | 141 ++++++++++++++++++++++++++ include/zephyr/llext/llext_internal.h | 5 + subsys/llext/llext.c | 37 ++++--- subsys/llext/llext_priv.h | 8 +- 6 files changed, 175 insertions(+), 22 deletions(-) create mode 100644 include/zephyr/llext/inspect.h diff --git a/doc/services/llext/api.rst b/doc/services/llext/api.rst index b3d8d64152b00..c4227ca2d8a42 100644 --- a/doc/services/llext/api.rst +++ b/doc/services/llext/api.rst @@ -6,3 +6,5 @@ API Reference .. doxygengroup:: llext_symbols .. doxygengroup:: llext_loader_apis + +.. doxygengroup:: llext_inspect_apis diff --git a/doc/services/llext/load.rst b/doc/services/llext/load.rst index a72913c0bdec1..939f278185d8c 100644 --- a/doc/services/llext/load.rst +++ b/doc/services/llext/load.rst @@ -60,6 +60,10 @@ The returned ``void *`` can then be cast to the appropriate type and used. A wrapper for calling a function with no arguments is provided in :c:func:`llext_call_fn`. +Advanced users that need direct access to areas of the newly loaded extension +may want to refer to :c:func:`llext_get_section_info` and other LLEXT +inspection APIs. + Cleaning up after use ===================== diff --git a/include/zephyr/llext/inspect.h b/include/zephyr/llext/inspect.h new file mode 100644 index 0000000000000..2cba50158553e --- /dev/null +++ b/include/zephyr/llext/inspect.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LLEXT_INSPECT_H +#define ZEPHYR_LLEXT_INSPECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +/** + * @file + * @brief LLEXT ELF inspection routines. + * + * This file contains routines to inspect the contents of an ELF file. It is + * intended to be used by applications that need advanced access to the ELF + * file structures of a loaded extension. + * + * @defgroup llext_inspect_apis ELF inspection APIs + * @ingroup llext_apis + * @{ + */ + +/** + * @brief Get information about a memory region for the specified extension. + * + * Retrieve information about a region (merged group of similar sections) in + * the extension. Any output parameter can be NULL if that information is not + * needed. + * + * @param[in] ldr Loader + * @param[in] ext Extension + * @param[in] region Region to get information about + * @param[out] hdr Variable storing the pointer to the region header + * @param[out] addr Variable storing the region load address + * @param[out] size Variable storing the region size + * + * @return 0 on success, -EINVAL if the region is invalid + */ +static inline int llext_get_region_info(const struct llext_loader *ldr, + const struct llext *ext, + enum llext_mem region, + const elf_shdr_t **hdr, + const void **addr, size_t *size) +{ + if ((unsigned int)region >= LLEXT_MEM_COUNT) { + return -EINVAL; + } + + if (hdr) { + *hdr = &ldr->sects[region]; + } + if (addr) { + *addr = ext->mem[region]; + } + if (size) { + *size = ext->mem_size[region]; + } + + return 0; +} + +/** + * @brief Get the index of a section with the specified name. + * + * Requires the @ref llext_load_param.keep_section_info flag to be set at + * extension load time. + * + * @param[in] ldr Loader + * @param[in] ext Extension + * @param[in] section_name Name of the section to look for + * + * @return Section index on success, -ENOENT if the section was not found, + * -ENOTSUP if section data is not available. + */ +int llext_section_shndx(const struct llext_loader *ldr, const struct llext *ext, + const char *section_name); + +/** + * @brief Get information about a section for the specified extension. + * + * Retrieve information about an ELF sections in the extension. Any output + * parameter can be @c NULL if that information is not needed. + * + * Requires the @ref llext_load_param.keep_section_info flag to be set at + * extension load time. + * + * @param[in] ldr Loader + * @param[in] ext Extension + * @param[in] shndx Section index + * @param[out] hdr Variable storing the pointer to the section header + * @param[out] region Variable storing the region the section belongs to + * @param[out] offset Variable storing the offset of the section in the region + * + * @return 0 on success, -EINVAL if the section index is invalid, + * -ENOTSUP if section data is not available. + */ +static inline int llext_get_section_info(const struct llext_loader *ldr, + const struct llext *ext, + unsigned int shndx, + const elf_shdr_t **hdr, + enum llext_mem *region, + size_t *offset) +{ + if (shndx < 0 || shndx >= ext->sect_cnt) { + return -EINVAL; + } + if (!ldr->sect_map) { + return -ENOTSUP; + } + + if (hdr) { + *hdr = &ext->sect_hdrs[shndx]; + } + if (region) { + *region = ldr->sect_map[shndx].mem_idx; + } + if (offset) { + *offset = ldr->sect_map[shndx].offset; + } + + return 0; +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LLEXT_INSPECT_H */ diff --git a/include/zephyr/llext/llext_internal.h b/include/zephyr/llext/llext_internal.h index f07dd5efd8655..b5365aa5a751d 100644 --- a/include/zephyr/llext/llext_internal.h +++ b/include/zephyr/llext/llext_internal.h @@ -21,6 +21,11 @@ extern "C" { struct llext_loader; struct llext; +struct llext_elf_sect_map { + enum llext_mem mem_idx; + size_t offset; +}; + const void *llext_loaded_sect_ptr(struct llext_loader *ldr, struct llext *ext, unsigned int sh_ndx); /** @endcond */ diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 020a8b7b8038f..918db5d4ce1ac 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -23,32 +23,37 @@ static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list); static struct k_mutex llext_lock = Z_MUTEX_INITIALIZER(llext_lock); -int llext_get_section_header(struct llext_loader *ldr, struct llext *ext, const char *search_name, - elf_shdr_t *shdr) +int llext_section_shndx(const struct llext_loader *ldr, const struct llext *ext, + const char *sect_name) { - const elf_shdr_t *tmp; unsigned int i; - for (i = 0, tmp = ext->sect_hdrs; - i < ext->sect_cnt; - i++, tmp++) { - const char *name = llext_peek(ldr, - ldr->sects[LLEXT_MEM_SHSTRTAB].sh_offset + - tmp->sh_name); - - if (!name) { - return -ENOTSUP; - } + for (i = 1; i < ext->sect_cnt; i++) { + const char *name = llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, + ext->sect_hdrs[i].sh_name); - if (!strcmp(name, search_name)) { - *shdr = *tmp; - return 0; + if (!strcmp(name, sect_name)) { + return i; } } return -ENOENT; } +int llext_get_section_header(struct llext_loader *ldr, struct llext *ext, const char *search_name, + elf_shdr_t *shdr) +{ + int ret; + + ret = llext_section_shndx(ldr, ext, search_name); + if (ret < 0) { + return ret; + } + + *shdr = ext->sect_hdrs[ret]; + return 0; +} + ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name) { elf_shdr_t *shdr; diff --git a/subsys/llext/llext_priv.h b/subsys/llext/llext_priv.h index cf96da165d2a5..b5b71fa31f674 100644 --- a/subsys/llext/llext_priv.h +++ b/subsys/llext/llext_priv.h @@ -9,11 +9,7 @@ #include #include - -struct llext_elf_sect_map { - enum llext_mem mem_idx; - size_t offset; -}; +#include /* * Memory management (llext_mem.c) @@ -53,7 +49,7 @@ static inline void llext_free(void *ptr) int do_llext_load(struct llext_loader *ldr, struct llext *ext, const struct llext_load_param *ldr_parm); -static inline const char *llext_string(struct llext_loader *ldr, struct llext *ext, +static inline const char *llext_string(const struct llext_loader *ldr, const struct llext *ext, enum llext_mem mem_idx, unsigned int idx) { return (char *)ext->mem[mem_idx] + idx; From fe29c40a9366b5ffdcdd2eac26023ce4502413b1 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Mon, 10 Feb 2025 17:05:36 +0100 Subject: [PATCH 0061/6055] llext: add inspection API test suite This patch adds a test suite for the inspection API. The test checks that the symbols exported by the 'inspect_ext' extension are correctly mapped inside their corresponding regions and sections. Signed-off-by: Luca Burelli --- tests/subsys/llext/CMakeLists.txt | 1 + tests/subsys/llext/src/inspect_ext.c | 28 ++++++++++++ tests/subsys/llext/src/test_llext.c | 67 ++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 tests/subsys/llext/src/inspect_ext.c diff --git a/tests/subsys/llext/CMakeLists.txt b/tests/subsys/llext/CMakeLists.txt index 0c121b2852d67..31730e2a2c7e8 100644 --- a/tests/subsys/llext/CMakeLists.txt +++ b/tests/subsys/llext/CMakeLists.txt @@ -21,6 +21,7 @@ set(ext_names relative_jump object syscalls + inspect threads_kernel_objects export_dependent export_dependency diff --git a/tests/subsys/llext/src/inspect_ext.c b/tests/subsys/llext/src/inspect_ext.c new file mode 100644 index 0000000000000..97d09f99932b0 --- /dev/null +++ b/tests/subsys/llext/src/inspect_ext.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This extension exports a number of symbols to be used by the LLEXT + * inspection APIs. Each symbol is exported within a different section + * and only the addresses are checked in this test. + */ + +#include + +int number_in_bss; +int number_in_data = 1; +const int number_in_rodata = 2; +const int number_in_my_rodata Z_GENERIC_SECTION(.my_rodata) = 3; + +void function_in_text(void) +{ + /* only used for address check */ +} + +EXPORT_SYMBOL(number_in_bss); +EXPORT_SYMBOL(number_in_data); +EXPORT_SYMBOL(number_in_rodata); +EXPORT_SYMBOL(number_in_my_rodata); +EXPORT_SYMBOL(function_in_text); diff --git a/tests/subsys/llext/src/test_llext.c b/tests/subsys/llext/src/test_llext.c index 9ac695311f030..d9bf11ce4334f 100644 --- a/tests/subsys/llext/src/test_llext.c +++ b/tests/subsys/llext/src/test_llext.c @@ -13,6 +13,7 @@ #endif #include #include +#include #include #include #include @@ -316,6 +317,72 @@ LLEXT_LOAD_UNLOAD(threads_kernel_objects, .test_setup = threads_objects_test_setup, ) +static LLEXT_CONST uint8_t inspect_ext[] ELF_ALIGN = { + #include "inspect.inc" +}; + +void do_inspect_checks(struct llext_loader *ldr, struct llext *ext, enum llext_mem reg_idx, + const char *sect_name, const char *sym_name) +{ + const elf_shdr_t *sect_hdr = NULL, *reg_hdr = NULL; + enum llext_mem sect_region = LLEXT_MEM_COUNT; + uintptr_t reg_addr = 0, sym_addr = 0; + size_t reg_size = 0, sect_offset = 0; + int sect_shndx, res; + + res = llext_get_region_info(ldr, ext, reg_idx, + ®_hdr, (const void **)®_addr, ®_size); + zassert_ok(res, "get_region_info() should succeed"); + sect_shndx = llext_section_shndx(ldr, ext, sect_name); + zassert_true(sect_shndx > 0, "section %s should be found", sect_name); + res = llext_get_section_info(ldr, ext, sect_shndx, + §_hdr, §_region, §_offset); + zassert_ok(res, "get_section_info() should succeed"); + sym_addr = (uintptr_t)llext_find_sym(&ext->exp_tab, sym_name); + zassert_true(sym_addr, "symbol %s must be exported", sym_name); + + zassert_equal(reg_idx, sect_region, "region mismatch (expected %d, got %d)", + reg_idx, sect_region); + zassert_true(sect_hdr->sh_offset >= reg_hdr->sh_offset && + (sect_hdr->sh_offset + sect_hdr->sh_size <= + reg_hdr->sh_offset + reg_hdr->sh_size), + "section %s overflows its region %d", sect_name, reg_idx); + zassert_true(sect_offset < reg_size, "section offset outside region"); + zassert_true(sym_addr >= reg_addr && sym_addr < reg_addr + reg_size, + "symbol %s mapped outside region %d", sym_name, reg_idx); + zassert_true(sym_addr >= reg_addr + sect_offset && + sym_addr < reg_addr + sect_offset + sect_hdr->sh_size, + "symbol %s mapped outside section %s", sym_name, sect_name); +} + +ZTEST(llext, test_inspect) +{ + int res; + + struct llext_buf_loader buf_loader = + LLEXT_BUF_LOADER(inspect_ext, sizeof(inspect_ext)); + struct llext_loader *ldr = &buf_loader.loader; + struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT; + struct llext *ext = NULL; + size_t max_alloc_bytes; + + ldr_parm.keep_section_info = true; + res = llext_load(ldr, "inspect", &ext, &ldr_parm); + zassert_ok(res, "load should succeed"); + + do_inspect_checks(ldr, ext, LLEXT_MEM_BSS, ".bss", "number_in_bss"); + do_inspect_checks(ldr, ext, LLEXT_MEM_DATA, ".data", "number_in_data"); + do_inspect_checks(ldr, ext, LLEXT_MEM_RODATA, ".rodata", "number_in_rodata"); + do_inspect_checks(ldr, ext, LLEXT_MEM_RODATA, ".my_rodata", "number_in_my_rodata"); + do_inspect_checks(ldr, ext, LLEXT_MEM_TEXT, ".text", "function_in_text"); + + max_alloc_bytes = ext->alloc_size; + llext_free_inspection_data(ldr, ext); + zassert_true(ext->alloc_size < max_alloc_bytes, "inspection data should be freed"); + + llext_unload(&ext); +} + #ifndef CONFIG_LLEXT_TYPE_ELF_OBJECT static LLEXT_CONST uint8_t multi_file_ext[] ELF_ALIGN = { #include "multi_file.inc" From 95dbbde12ba30541d6e10080f44b8d927a8e7950 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 10 Feb 2025 11:53:51 +0000 Subject: [PATCH 0062/6055] cmake: mcuboot: Set encrypted header flag when key is used Uses the clear imgtool argument to set the encrypted flag in the header of the signed hex output, without encrypting the data. This addresses an issue whereby the first update would swap images and leave the swapped output in the secondary slot without encryption Signed-off-by: Jamie McCrae --- cmake/mcuboot.cmake | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake index 99f6af9e2396e..2767af807c124 100644 --- a/cmake/mcuboot.cmake +++ b/cmake/mcuboot.cmake @@ -183,8 +183,18 @@ function(zephyr_mcuboot_tasks) set(BYPRODUCT_KERNEL_SIGNED_HEX_NAME "${output}.signed.hex" CACHE FILEPATH "Signed kernel hex file" FORCE ) - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND - ${imgtool_sign} ${imgtool_args} ${output}.hex ${output}.signed.hex) + + if(NOT "${keyfile_enc}" STREQUAL "") + # When encryption is enabled, set the encrypted bit when signing the image but do not + # encrypt the data, this means that when the image is moved out of the primary into the + # secondary, it will be encrypted rather than being in unencrypted + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND + ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" --clear + ${output}.hex ${output}.signed.hex) + else() + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND + ${imgtool_sign} ${imgtool_args} ${output}.hex ${output}.signed.hex) + endif() if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) list(APPEND byproducts ${output}.signed.confirmed.hex) From f628add120101d302a09e0fd1a049029262ab675 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 11 Feb 2025 10:19:41 +0000 Subject: [PATCH 0063/6055] doc: release: 4.1: Add note on MCUboot encrypted bit Adds a note about this change Signed-off-by: Jamie McCrae --- doc/releases/release-notes-4.1.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-4.1.rst b/doc/releases/release-notes-4.1.rst index da2c2fcb0cf61..fe7ed8ae800e8 100644 --- a/doc/releases/release-notes-4.1.rst +++ b/doc/releases/release-notes-4.1.rst @@ -177,6 +177,11 @@ New APIs and options * Image management :c:macro:`MGMT_EVT_OP_IMG_MGMT_DFU_CONFIRMED` now has image data field :c:struct:`img_mgmt_image_confirmed`. +* MCUboot + + * Signed hex files where an encryption key Kconfig is set now have the encrypted flag set in + the image header. + * Video * :c:func:`video_set_stream()` driver API has replaced :c:func:`video_stream_start()` and From 53e62cac49e7ade3524c2d386f5b32483cb124c8 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Tue, 11 Feb 2025 10:05:12 -0300 Subject: [PATCH 0064/6055] samples: video: capture: Fix sample for esp32s3_eye Add proper pixel format support for ST7789V display. Signed-off-by: Lucas Tamborrino --- samples/drivers/video/capture/boards/esp32s3_eye_procpu.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/drivers/video/capture/boards/esp32s3_eye_procpu.conf b/samples/drivers/video/capture/boards/esp32s3_eye_procpu.conf index 76321800fa069..24a8455c94ba4 100644 --- a/samples/drivers/video/capture/boards/esp32s3_eye_procpu.conf +++ b/samples/drivers/video/capture/boards/esp32s3_eye_procpu.conf @@ -9,3 +9,4 @@ CONFIG_VIDEO_BUFFER_SMH_ATTRIBUTE=2 CONFIG_VIDEO_FRAME_HEIGHT=240 CONFIG_VIDEO_FRAME_WIDTH=240 CONFIG_VIDEO_PIXEL_FORMAT="RGBP" +CONFIG_ST7789V_BGR565=y From 13ac8fe1f51faf050e0527d2c6e24583cb833a08 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 11 Feb 2025 13:30:23 +0000 Subject: [PATCH 0065/6055] mgmt: mcumgr: smp: Fix custom payload size Fixes an issue when using custom payloads where the size was still using the zcbor buffer instead of the size of the network buffer Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/smp/src/smp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/subsys/mgmt/mcumgr/smp/src/smp.c b/subsys/mgmt/mcumgr/smp/src/smp.c index 693a26f4d1fd6..0da3815907d1d 100644 --- a/subsys/mgmt/mcumgr/smp/src/smp.c +++ b/subsys/mgmt/mcumgr/smp/src/smp.c @@ -310,9 +310,15 @@ static int smp_handle_single_req(struct smp_streamer *streamer, const struct smp } #endif - smp_make_rsp_hdr(req_hdr, &rsp_hdr, - zsp->payload_mut - nbw->nb->data - MGMT_HDR_SIZE); - nbw->nb->len = zsp->payload_mut - nbw->nb->data; +#if defined(CONFIG_MCUMGR_MGMT_CUSTOM_PAYLOAD) + if (!mgmt_find_group(req_hdr->nh_group)->custom_payload) { +#endif + nbw->nb->len = zsp->payload_mut - nbw->nb->data; +#if defined(CONFIG_MCUMGR_MGMT_CUSTOM_PAYLOAD) + } +#endif + + smp_make_rsp_hdr(req_hdr, &rsp_hdr, (nbw->nb->len - MGMT_HDR_SIZE)); smp_write_hdr(streamer, &rsp_hdr); return 0; From c8e93401d0b63e29cfedc9e27e7eb4b821721f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kalle=20Kiet=C3=A4v=C3=A4inen?= Date: Tue, 11 Feb 2025 14:48:37 +0200 Subject: [PATCH 0066/6055] drivers: bluetooth: silabs: Set maximum TX power MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Honor Kconfig option `BT_CTLR_TX_PWR_ANTENNA` for limiting the maximum TX power. The default value for this option is 0 dBm, which means that after this change the actual TX power is likely lower than before, unless increased by this option. Signed-off-by: Kalle Kietäväinen --- drivers/bluetooth/hci/hci_silabs_efr32.c | 15 +++++++++++++++ .../hal_silabs/simplicity_sdk/src/blob_stubs.c | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/drivers/bluetooth/hci/hci_silabs_efr32.c b/drivers/bluetooth/hci/hci_silabs_efr32.c index 5ae602cff9dfd..c528b3b69103b 100644 --- a/drivers/bluetooth/hci/hci_silabs_efr32.c +++ b/drivers/bluetooth/hci/hci_silabs_efr32.c @@ -52,6 +52,7 @@ static struct k_fifo slz_rx_fifo; /* FIXME: these functions should come from the SiSDK headers! */ void BTLE_LL_EventRaise(uint32_t events); void BTLE_LL_Process(uint32_t events); +int16_t BTLE_LL_SetMaxPower(int16_t power); bool sli_pending_btctrl_events(void); RAIL_Handle_t BTLE_LL_GetRadioHandle(void); @@ -256,6 +257,18 @@ static void slz_rx_thread_func(void *p1, void *p2, void *p3) } } +static void slz_set_tx_power(int16_t max_power_dbm) +{ + const int16_t max_power_cbm = max_power_dbm * 10; + const int16_t actual_max_power_cbm = BTLE_LL_SetMaxPower(max_power_cbm); + const int16_t actual_max_power_dbm = DIV_ROUND_CLOSEST(actual_max_power_cbm, 10); + + if (actual_max_power_dbm != max_power_dbm) { + LOG_WRN("Unable to set max TX power to %d dBm, actual max is %d dBm", max_power_dbm, + actual_max_power_dbm); + } +} + static int slz_bt_open(const struct device *dev, bt_hci_recv_t recv) { struct hci_data *hci = dev->data; @@ -303,6 +316,8 @@ static int slz_bt_open(const struct device *dev, bt_hci_recv_t recv) goto deinit; } + slz_set_tx_power(CONFIG_BT_CTLR_TX_PWR_ANTENNA); + sl_btctrl_init_adv(); sl_btctrl_init_scan(); sl_btctrl_init_conn(); diff --git a/modules/hal_silabs/simplicity_sdk/src/blob_stubs.c b/modules/hal_silabs/simplicity_sdk/src/blob_stubs.c index 8a2ff15438606..ad06b11d61ea5 100644 --- a/modules/hal_silabs/simplicity_sdk/src/blob_stubs.c +++ b/modules/hal_silabs/simplicity_sdk/src/blob_stubs.c @@ -31,6 +31,11 @@ void BTLE_LL_Process(uint32_t events) { } +int16_t BTLE_LL_SetMaxPower(int16_t power) +{ + return 0; +} + void sl_btctrl_disable_2m_phy(void) { } From ffbb8f981ad5640627bac6bdfc2e84f154a25370 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Tue, 11 Feb 2025 11:45:21 +0100 Subject: [PATCH 0067/6055] drivers: led: lp50xx: check the number of LED colors The current code assumes (especially in the lp50xx_set_color function) that the number of LED colors defined in DT is not greater than 3. But since this is not checked, then this is not necessarily the case... This patch consolidates the initialization of the lp50xx LED driver by checking the number of colors for each LED found in DT. Signed-off-by: Simon Guinot --- drivers/led/lp50xx.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/led/lp50xx.c b/drivers/led/lp50xx.c index 57ffb1db3b0d8..bd1fd11b529e7 100644 --- a/drivers/led/lp50xx.c +++ b/drivers/led/lp50xx.c @@ -153,7 +153,8 @@ static int lp50xx_set_color(const struct device *dev, uint32_t led, { const struct lp50xx_config *config = dev->config; const struct led_info *led_info = lp50xx_led_to_info(config, led); - uint8_t buf[4]; + uint8_t buf[LP50XX_COLORS_PER_LED + 1]; + uint8_t i; if (!led_info) { return -ENODEV; @@ -170,11 +171,11 @@ static int lp50xx_set_color(const struct device *dev, uint32_t led, buf[0] = LP50XX_OUT0_COLOR(config->num_modules); buf[0] += LP50XX_COLORS_PER_LED * led_info->index; - buf[1] = color[0]; - buf[2] = color[1]; - buf[3] = color[2]; + for (i = 0; i < led_info->num_colors; i++) { + buf[1 + i] = color[i]; + } - return i2c_write_dt(&config->bus, buf, sizeof(buf)); + return i2c_write_dt(&config->bus, buf, led_info->num_colors + 1); } static int lp50xx_write_channels(const struct device *dev, @@ -266,6 +267,7 @@ static int lp50xx_enable(const struct device *dev, bool enable) static int lp50xx_init(const struct device *dev) { const struct lp50xx_config *config = dev->config; + uint8_t led; int err; if (!i2c_is_ready_dt(&config->bus)) { @@ -273,6 +275,7 @@ static int lp50xx_init(const struct device *dev) return -ENODEV; } + /* Check LED configuration found in DT */ if (config->num_leds > config->max_leds) { LOG_ERR("%s: invalid number of LEDs %d (max %d)", dev->name, @@ -280,6 +283,16 @@ static int lp50xx_init(const struct device *dev) config->max_leds); return -EINVAL; } + for (led = 0; led < config->num_leds; led++) { + const struct led_info *led_info = + lp50xx_led_to_info(config, led); + + if (led_info->num_colors > LP50XX_COLORS_PER_LED) { + LOG_ERR("%s: LED %d: invalid number of colors (max %d)", + dev->name, led, LP50XX_COLORS_PER_LED); + return -EINVAL; + } + } /* Configure GPIO if present */ if (config->gpio_enable.port != NULL) { From c356f159b50011ebf6a6379f760b5a21a50350ca Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 21 Mar 2024 12:35:55 -0500 Subject: [PATCH 0068/6055] soc: ti: k3: am6x: m4: Lock resource table location in DRAM Currently the resource table is added to the memory-region labeled DDR. This region can also be extra space for code/data, although this is not yet implemented. This will mean that the linker is free to put the resource table *after* the code/data sections in DDR. The resource table must be at the start of the assigned DRAM area for the remote core to support early-boot/late-attach usecases. To solve this, we carveout the first 4KB of our DRAM area specifically for the resource table. This matches how this issue was solved for the K3 R5F cores. To make this clear we label this memory-region "RSC_TABLE". This is done at the linker file level, which is common for all K3 M4 boards and so we update all 3 such boards in this one patch instead of patch-per-board. Signed-off-by: Andrew Davis --- .../phyboard_electra/phyboard_electra_am6442_m4.dts | 8 +++++++- .../phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts | 10 ++++++++-- boards/ti/sk_am62/sk_am62_am6234_m4.dts | 10 ++++++++-- soc/ti/k3/am6x/m4/linker.ld | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts index d19c5a62c923b..393faa2d5a157 100644 --- a/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts +++ b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts @@ -31,9 +31,15 @@ }; }; - ddr0:memory@a4100000 { + rsc_table: memory@a4100000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0xa4100000 DT_SIZE_K(4)>; + zephyr,memory-region = "RSC_TABLE"; + }; + + ddr0: memory@a4101000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0xa4101000 (DT_SIZE_M(15) - DT_SIZE_K(4))>; zephyr,memory-region = "DDR"; }; diff --git a/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts index 8112aeba41946..c36eb463a6189 100644 --- a/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts +++ b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts @@ -31,9 +31,15 @@ }; }; - ddr0:memory@9CC00000{ + rsc_table: memory@9cc00000 { compatible = "zephyr,memory-region", "mmio-sram"; - reg = <0x9CC00000 DT_SIZE_K(4)>; + reg = <0x9cc00000 DT_SIZE_K(4)>; + zephyr,memory-region = "RSC_TABLE"; + }; + + ddr0: memory@9cc01000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x9cc01000 (DT_SIZE_M(15) - DT_SIZE_K(4))>; zephyr,memory-region = "DDR"; }; diff --git a/boards/ti/sk_am62/sk_am62_am6234_m4.dts b/boards/ti/sk_am62/sk_am62_am6234_m4.dts index 0c3ea26e033e6..59792fc8a449c 100644 --- a/boards/ti/sk_am62/sk_am62_am6234_m4.dts +++ b/boards/ti/sk_am62/sk_am62_am6234_m4.dts @@ -26,9 +26,15 @@ }; }; - ddr0:memory@9CC00000{ + rsc_table: memory@9cc00000 { compatible = "zephyr,memory-region", "mmio-sram"; - reg = <0x9CC00000 DT_SIZE_K(4)>; + reg = <0x9cc00000 DT_SIZE_K(4)>; + zephyr,memory-region = "RSC_TABLE"; + }; + + ddr0: memory@9cc01000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x9cc01000 (DT_SIZE_M(15) - DT_SIZE_K(4))>; zephyr,memory-region = "DDR"; }; }; diff --git a/soc/ti/k3/am6x/m4/linker.ld b/soc/ti/k3/am6x/m4/linker.ld index 5e478a0541ff0..dfe71053cfe6b 100644 --- a/soc/ti/k3/am6x/m4/linker.ld +++ b/soc/ti/k3/am6x/m4/linker.ld @@ -13,6 +13,6 @@ SECTIONS SECTION_PROLOGUE(.resource_table,, SUBALIGN(4)) { KEEP(*(.resource_table*)) - } GROUP_LINK_IN(DDR) + } GROUP_LINK_IN(RSC_TABLE) #endif } From 06202ceab8fd69f5bad593bc43b10bcfffb805fb Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 10 Feb 2025 16:26:35 -0600 Subject: [PATCH 0069/6055] boards: phytec: phyboard_electra: Add VirtIO/Vring DRAM IPC region Add the memory region reserved in DRAM for VirtIO and Vring data for IPC. Add this as the default chosen zephyr,ipc_shm. Signed-off-by: Andrew Davis --- .../phyboard_electra/phyboard_electra_am6442_m4.dts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts index 393faa2d5a157..cc243d6243c55 100644 --- a/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts +++ b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts @@ -17,7 +17,8 @@ zephyr,sram = &sram0; zephyr,console = &uart0; zephyr,shell-uart = &uart0; - zephyr,sram1 = &ddr0; + zephyr,ipc_shm = &ddr0; + zephyr,sram1 = &ddr1; }; aliases { @@ -31,13 +32,18 @@ }; }; + ddr0: memory@a4000000 { + compatible = "mmio-sram"; + reg = <0xa4000000 DT_SIZE_M(1)>; + }; + rsc_table: memory@a4100000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0xa4100000 DT_SIZE_K(4)>; zephyr,memory-region = "RSC_TABLE"; }; - ddr0: memory@a4101000 { + ddr1: memory@a4101000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0xa4101000 (DT_SIZE_M(15) - DT_SIZE_K(4))>; zephyr,memory-region = "DDR"; From 95e4320b2a73f9e3e529b2014665dc251a84e35a Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 10 Feb 2025 16:28:48 -0600 Subject: [PATCH 0070/6055] boards: phytec: phyboard_lyra: Add VirtIO/Vring DRAM IPC region Add the memory region reserved in DRAM for VirtIO and Vring data for IPC. Add this as the default chosen zephyr,ipc_shm. Signed-off-by: Andrew Davis --- .../phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts index c36eb463a6189..403277aea0670 100644 --- a/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts +++ b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts @@ -17,7 +17,8 @@ zephyr,sram = &sram0; zephyr,console = &uart0; zephyr,shell-uart = &uart0; - zephyr,sram1 = &ddr0; + zephyr,ipc_shm = &ddr0; + zephyr,sram1 = &ddr1; }; aliases { @@ -31,13 +32,18 @@ }; }; + ddr0: memory@9cb00000 { + compatible = "mmio-sram"; + reg = <0x9cb00000 DT_SIZE_M(1)>; + }; + rsc_table: memory@9cc00000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x9cc00000 DT_SIZE_K(4)>; zephyr,memory-region = "RSC_TABLE"; }; - ddr0: memory@9cc01000{ + ddr1: memory@9cc01000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x9cc01000 (DT_SIZE_M(15) - DT_SIZE_K(4))>; zephyr,memory-region = "DDR"; From 3a3037d0bcbc3a0087127a2cfa84d9b58dec8a8e Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 10 Feb 2025 16:29:39 -0600 Subject: [PATCH 0071/6055] boards: ti: sk_am62: Add VirtIO/Vring DRAM IPC region Add the memory region reserved in DRAM for VirtIO and Vring data for IPC. Add this as the default chosen zephyr,ipc_shm. Signed-off-by: Andrew Davis --- boards/ti/sk_am62/sk_am62_am6234_m4.dts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/boards/ti/sk_am62/sk_am62_am6234_m4.dts b/boards/ti/sk_am62/sk_am62_am6234_m4.dts index 59792fc8a449c..85688607d5d7a 100644 --- a/boards/ti/sk_am62/sk_am62_am6234_m4.dts +++ b/boards/ti/sk_am62/sk_am62_am6234_m4.dts @@ -16,7 +16,8 @@ zephyr,sram = &sram0; zephyr,console = &uart0; zephyr,shell-uart = &uart0; - zephyr,sram1 = &ddr0; + zephyr,ipc_shm = &ddr0; + zephyr,sram1 = &ddr1; }; cpus { @@ -26,13 +27,18 @@ }; }; + ddr0: memory@9cb00000 { + compatible = "mmio-sram"; + reg = <0x9cb00000 DT_SIZE_M(1)>; + }; + rsc_table: memory@9cc00000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x9cc00000 DT_SIZE_K(4)>; zephyr,memory-region = "RSC_TABLE"; }; - ddr0: memory@9cc01000{ + ddr1: memory@9cc01000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x9cc01000 (DT_SIZE_M(15) - DT_SIZE_K(4))>; zephyr,memory-region = "DDR"; From 7c828bd232a1645f5edd17939db04c591877dea4 Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Tue, 11 Feb 2025 15:16:28 +0100 Subject: [PATCH 0072/6055] bluetooth: dis: add Kconfig for disabling optional characteristics Added new Kconfig option set that allows the user to control the presence of the following optional characteristics: - Manufacturer Name String - Model Number String Depreacted the old configuration that can be deleted in the future Zephyr releases. Signed-off-by: Kamil Piszczek --- drivers/bluetooth/hci/Kconfig.nxp | 5 ++- samples/bluetooth/peripheral_dis/prj.conf | 6 ++- subsys/bluetooth/services/Kconfig.dis | 46 +++++++++++++++++++++-- subsys/bluetooth/services/dis.c | 40 +++++++++++++++++++- 4 files changed, 90 insertions(+), 7 deletions(-) diff --git a/drivers/bluetooth/hci/Kconfig.nxp b/drivers/bluetooth/hci/Kconfig.nxp index 25cffe1f7021b..9eaea2849b033 100644 --- a/drivers/bluetooth/hci/Kconfig.nxp +++ b/drivers/bluetooth/hci/Kconfig.nxp @@ -48,7 +48,10 @@ endif if BT_NXP -config BT_DIS_MANUF +config BT_DIS_MANUF_NAME + default y + +config BT_DIS_MANUF_NAME_STR default "NXP" config BT_HCI_ACL_FLOW_CONTROL diff --git a/samples/bluetooth/peripheral_dis/prj.conf b/samples/bluetooth/peripheral_dis/prj.conf index 4fed0a4e66fe7..cc58337db9c0e 100644 --- a/samples/bluetooth/peripheral_dis/prj.conf +++ b/samples/bluetooth/peripheral_dis/prj.conf @@ -3,12 +3,14 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT_DIS=y CONFIG_BT_DIS_PNP=n -CONFIG_BT_DIS_MODEL="Zephyr Model" -CONFIG_BT_DIS_MANUF="Zephyr" +CONFIG_BT_DIS_MODEL_NUMBER=y +CONFIG_BT_DIS_MANUF_NAME=y CONFIG_BT_DIS_SERIAL_NUMBER=y CONFIG_BT_DIS_FW_REV=y CONFIG_BT_DIS_HW_REV=y CONFIG_BT_DIS_SW_REV=y +CONFIG_BT_DIS_MODEL_NUMBER_STR="Zephyr Model" +CONFIG_BT_DIS_MANUF_NAME_STR="Zephyr" CONFIG_BT_DIS_SERIAL_NUMBER_STR="Zephyr Serial" CONFIG_BT_DIS_FW_REV_STR="Zephyr Firmware" CONFIG_BT_DIS_HW_REV_STR="Zephyr Hardware" diff --git a/subsys/bluetooth/services/Kconfig.dis b/subsys/bluetooth/services/Kconfig.dis index e1056a250d14f..6a15853903dbc 100644 --- a/subsys/bluetooth/services/Kconfig.dis +++ b/subsys/bluetooth/services/Kconfig.dis @@ -23,17 +23,57 @@ config BT_DIS_STR_MAX Bluetooth DIS string storage size. Storage can be up to 248 bytes long (excluding NULL termination). -config BT_DIS_MODEL - string "Model name" +config BT_DIS_MODEL_NUMBER + bool "Model number characteristic" + depends on !BT_DIS_MODEL_DEPRECATED_USED + default y + help + Enable model number characteristic in Device Information Service. + +config BT_DIS_MODEL_NUMBER_STR + string "Model number" + depends on BT_DIS_MODEL_NUMBER default SOC + help + Configure model number string that can be read with the model number characteristic + in Device Information Service. + +config BT_DIS_MODEL + string "Model name [DEPRECATED]" help The device model inside Device Information Service. + This option is deprecated. Use BT_DIS_MODEL_NUMBER and BT_DIS_MODEL_NUMBER_STR instead. -config BT_DIS_MANUF +config BT_DIS_MODEL_DEPRECATED_USED + bool + default y if BT_DIS_MODEL != "" + select DEPRECATED + +config BT_DIS_MANUF_NAME + bool "Manufacturer name characteristic" + depends on !BT_DIS_MANUF_DEPRECATED_USED + default y + help + Enable manufacturer name characteristic in Device Information Service. + +config BT_DIS_MANUF_NAME_STR string "Manufacturer name" + depends on BT_DIS_MANUF_NAME default "Manufacturer" + help + Configure manufacturer name string that can be read with the manufacturer name + characteristic in Device Information Service. + +config BT_DIS_MANUF + string "Manufacturer name [DEPRECATED]" help The device manufacturer inside Device Information Service. + This option is deprecated. Use BT_DIS_MANUF_NAME and BT_DIS_MANUF_NAME_STR instead. + +config BT_DIS_MANUF_DEPRECATED_USED + bool + default y if BT_DIS_MANUF != "" + select DEPRECATED config BT_DIS_PNP bool "PnP_ID characteristic" diff --git a/subsys/bluetooth/services/dis.c b/subsys/bluetooth/services/dis.c index 27676600b1782..c9f429560c319 100644 --- a/subsys/bluetooth/services/dis.c +++ b/subsys/bluetooth/services/dis.c @@ -58,10 +58,20 @@ static uint8_t dis_system_id[8] = {BT_BYTES_LIST_LE40((uint64_t)CONFIG_BT_DIS_SY #endif #if defined(CONFIG_BT_DIS_SETTINGS) +#if defined(CONFIG_BT_DIS_MODEL_NUMBER) +BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MODEL_NUMBER_STR) <= CONFIG_BT_DIS_STR_MAX + 1); +static uint8_t dis_model[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MODEL_NUMBER_STR; +#elif defined(CONFIG_BT_DIS_MODEL_DEPRECATED_USED) BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MODEL) <= CONFIG_BT_DIS_STR_MAX + 1); -BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MANUF) <= CONFIG_BT_DIS_STR_MAX + 1); static uint8_t dis_model[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MODEL; +#endif +#if defined(CONFIG_BT_DIS_MANUF_NAME) +BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MANUF_NAME_STR) <= CONFIG_BT_DIS_STR_MAX + 1); +static uint8_t dis_manuf[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MANUF_NAME_STR; +#elif defined(CONFIG_BT_DIS_MANUF_DEPRECATED_USED) +BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MANUF) <= CONFIG_BT_DIS_STR_MAX + 1); static uint8_t dis_manuf[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MANUF; +#endif #if defined(CONFIG_BT_DIS_SERIAL_NUMBER) BUILD_ASSERT(sizeof(CONFIG_BT_DIS_SERIAL_NUMBER_STR) <= CONFIG_BT_DIS_STR_MAX + 1); static uint8_t dis_serial_number[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_SERIAL_NUMBER_STR; @@ -114,8 +124,16 @@ static uint8_t dis_ieee_rcdl[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_IEEE_RCD #else /* CONFIG_BT_DIS_SETTINGS */ +#if defined(CONFIG_BT_DIS_MODEL_NUMBER) +#define BT_DIS_MODEL_REF CONFIG_BT_DIS_MODEL_NUMBER_STR +#elif defined(CONFIG_BT_DIS_MODEL_DEPRECATED_USED) #define BT_DIS_MODEL_REF CONFIG_BT_DIS_MODEL +#endif +#if defined(CONFIG_BT_DIS_MANUF_NAME) +#define BT_DIS_MANUF_REF CONFIG_BT_DIS_MANUF_NAME_STR +#elif defined(CONFIG_BT_DIS_MANUF_DEPRECATED_USED) #define BT_DIS_MANUF_REF CONFIG_BT_DIS_MANUF +#endif #define BT_DIS_SERIAL_NUMBER_STR_REF CONFIG_BT_DIS_SERIAL_NUMBER_STR #define BT_DIS_FW_REV_STR_REF CONFIG_BT_DIS_FW_REV_STR #define BT_DIS_HW_REV_STR_REF CONFIG_BT_DIS_HW_REV_STR @@ -128,12 +146,20 @@ static uint8_t dis_ieee_rcdl[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_IEEE_RCD #endif /* CONFIG_BT_DIS_SETTINGS */ +#define BT_DIS_READ_STR_USED \ + (CONFIG_BT_DIS_MODEL_NUMBER || CONFIG_BT_DIS_MODEL_DEPRECATED_USED || \ + CONFIG_BT_DIS_MANUF_NAME || CONFIG_BT_DIS_MANUF_DEPRECATED_USED || \ + CONFIG_BT_DIS_SERIAL_NUMBER || CONFIG_BT_DIS_FW_REV || CONFIG_BT_DIS_HW_REV || \ + CONFIG_BT_DIS_SW_REV || CONFIG_BT_DIS_IEEE_RCDL) + +#if BT_DIS_READ_STR_USED static ssize_t read_str(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, strlen(attr->user_data)); } +#endif #if CONFIG_BT_DIS_PNP static ssize_t read_pnp_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, @@ -226,10 +252,16 @@ static ssize_t read_udi(struct bt_conn *conn, const struct bt_gatt_attr *attr, v BT_GATT_SERVICE_DEFINE( dis_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_DIS), +#if defined(CONFIG_BT_DIS_MODEL_NUMBER) || defined(CONFIG_BT_DIS_MODEL_DEPRECATED_USED) BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MODEL_NUMBER, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_str, NULL, BT_DIS_MODEL_REF), +#endif + +#if defined(CONFIG_BT_DIS_MANUF_NAME) || defined(CONFIG_BT_DIS_MANUF_DEPRECATED_USED) BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MANUFACTURER_NAME, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_str, NULL, BT_DIS_MANUF_REF), +#endif + #if CONFIG_BT_DIS_PNP BT_GATT_CHARACTERISTIC(BT_UUID_DIS_PNP_ID, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_pnp_id, NULL, &dis_pnp_id), @@ -309,7 +341,10 @@ static int dis_set(const char *name, size_t len_rd, settings_read_cb read_cb, vo int nlen; const char *next; + ARG_UNUSED(len); + nlen = settings_name_next(name, &next); +#if defined(CONFIG_BT_DIS_MANUF_NAME) || defined(CONFIG_BT_DIS_MANUF_DEPRECATED_USED) if (!strncmp(name, "manuf", nlen)) { len = read_cb(store, &dis_manuf, sizeof(dis_manuf) - 1); if (len < 0) { @@ -321,6 +356,8 @@ static int dis_set(const char *name, size_t len_rd, settings_read_cb read_cb, vo } return 0; } +#endif +#if defined(CONFIG_BT_DIS_MODEL_NUMBER) || defined(CONFIG_BT_DIS_MODEL_DEPRECATED_USED) if (!strncmp(name, "model", nlen)) { len = read_cb(store, &dis_model, sizeof(dis_model) - 1); if (len < 0) { @@ -332,6 +369,7 @@ static int dis_set(const char *name, size_t len_rd, settings_read_cb read_cb, vo } return 0; } +#endif #if defined(CONFIG_BT_DIS_SERIAL_NUMBER) if (!strncmp(name, "serial", nlen)) { len = read_cb(store, &dis_serial_number, sizeof(dis_serial_number) - 1); From 8b80c209446d8bbe9b454b91773ace14ac40d4c2 Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Wed, 12 Feb 2025 12:46:18 +0100 Subject: [PATCH 0073/6055] doc: releases: document the DIS changes in changelog and migration guide Added a changelog entry in the Deprecated and New categories to document the Kconfig changes for the Bluetooth Device Information Service (DIS). Updated the migration guide to provide instructions on how to transition from the old configuration scheme to the new one. Signed-off-by: Kamil Piszczek --- doc/releases/migration-guide-4.1.rst | 10 ++++++++++ doc/releases/release-notes-4.1.rst | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/doc/releases/migration-guide-4.1.rst b/doc/releases/migration-guide-4.1.rst index 9aaf171e41bff..7315df74144e5 100644 --- a/doc/releases/migration-guide-4.1.rst +++ b/doc/releases/migration-guide-4.1.rst @@ -587,6 +587,16 @@ Bluetooth Host Bluetooth Crypto ================ +Bluetooth Services +================== + +* The :kconfig:option:`CONFIG_BT_DIS_MODEL` and :kconfig:option:`CONFIG_BT_DIS_MANUF` have been + deprecated. Application developers should now use the + :kconfig:option:`CONFIG_BT_DIS_MODEL_NUMBER_STR` and + :kconfig:option:`CONFIG_BT_DIS_MANUF_NAME_STR` Kconfig options to set the string values in the + Model Number String and Manufacturer Name String characteristics that are part of the Device + Information Service (DIS). + Networking ********** diff --git a/doc/releases/release-notes-4.1.rst b/doc/releases/release-notes-4.1.rst index fe7ed8ae800e8..ebbac0e320ab7 100644 --- a/doc/releases/release-notes-4.1.rst +++ b/doc/releases/release-notes-4.1.rst @@ -117,6 +117,11 @@ Deprecated APIs and options * The TinyCrypt library has been deprecated as the upstream version is no longer maintained. PSA Crypto API is now the recommended cryptographic library for Zephyr. +* The :kconfig:option:`CONFIG_BT_DIS_MODEL` and :kconfig:option:`CONFIG_BT_DIS_MANUF` have been + deprecated. Application developers can achieve the same configuration by using the new + :kconfig:option:`CONFIG_BT_DIS_MODEL_NUMBER_STR` and + :kconfig:option:`CONFIG_BT_DIS_MANUF_NAME_STR` Kconfig options. + New APIs and options ==================== @@ -151,6 +156,16 @@ New APIs and options * :c:member:`bt_mesh_health_cli::update` callback can be used to periodically update the message published by the Health Client. + * Services + + * The :kconfig:option:`CONFIG_BT_DIS_MODEL_NUMBER` and + :kconfig:option:`CONFIG_BT_DIS_MANUF_NAME` Kconfig options can be used to control the + presence of the Model Number String and Manufacturer Name String characteristics inside + the Device Information Service (DIS). The :kconfig:option:`CONFIG_BT_DIS_MODEL_NUMBER_STR` + and :kconfig:option:`CONFIG_BT_DIS_MANUF_NAME_STR` Kconfig options are now used to set the + string values in these characteristics. They replace the functionality of the deprecated + :kconfig:option:`CONFIG_BT_DIS_MODEL` and :kconfig:option:`CONFIG_BT_DIS_MANUF` Kconfigs. + * Build system * Sysbuild From b0e08c826264aeef098e39a38bb15294bccd8c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Bergman?= Date: Wed, 29 Jan 2025 11:09:54 +0100 Subject: [PATCH 0074/6055] cmake: SHELL: vs zephyr_get_compile_X_for_lang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In zephyr_get_XYZ_for_lang() functions in extensions.cmake we try to mimic what cmake does in generation time to filter out SHELL: tags. However, this filtering was only done for list entries that did not contain generator expressions. This causes broken command lines for e.g. e.g. for the kobject_hash*c if the toolchain puts "SHELL: $<$:some thing>" into the options. Signed-off-by: Björn Bergman --- cmake/modules/extensions.cmake | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 8350b2f397455..6df0ef51f67be 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -336,6 +336,12 @@ function(process_flags lang input output) foreach(flag ${${input}}) set(is_compile_lang_generator_expression 0) + # SHELL is used to avoid de-duplication, but when process flags + # then this tag must be removed to return real compile/linker flags. + if(flag MATCHES "^SHELL:[ ]*(.*)") + separate_arguments(flag UNIX_COMMAND ${CMAKE_MATCH_1}) + endif() + foreach(l ${languages}) if(flag MATCHES ":([^>]+)>") set(updated_flag ${CMAKE_MATCH_1}) @@ -356,11 +362,6 @@ function(process_flags lang input output) endforeach() if(NOT is_compile_lang_generator_expression) - # SHELL is used to avoid de-duplication, but when process flags - # then this tag must be removed to return real compile/linker flags. - if(flag MATCHES "SHELL:[ ]*(.*)") - separate_arguments(flag UNIX_COMMAND ${CMAKE_MATCH_1}) - endif() # Flags may be placed inside generator expression, therefore any flag # which is not already a generator expression must have commas converted. if(NOT flag MATCHES "\\\$<.*>") From ac8c56fcc1ccd5254dc68fc6a91510f59b046378 Mon Sep 17 00:00:00 2001 From: Axel Le Bourhis Date: Thu, 6 Feb 2025 15:02:58 +0100 Subject: [PATCH 0075/6055] manifest: add MCXW72 NBU ble firmware blob Update manifest to add MCXW72 NBU ble firmware blob. Signed-off-by: Axel Le Bourhis --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 12200958df531..0e5e87bec15c5 100644 --- a/west.yml +++ b/west.yml @@ -203,7 +203,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 4afb0ec88a4b0ab65729f308e9c6d910bf9d8698 + revision: 5e1979c7dd94dc84a09f5deb1b59ab83c94d5e83 path: modules/hal/nxp groups: - hal From 2c25211edeea35da76d3d40ad67551d9af2fc4bc Mon Sep 17 00:00:00 2001 From: Axel Le Bourhis Date: Thu, 6 Feb 2025 15:35:47 +0100 Subject: [PATCH 0076/6055] mcxw72_evk: document NBU BLE firmware flashing procedure Document the flashing procedure of the NBU BLE firmware, fetched by west blobs. Signed-off-by: Axel Le Bourhis --- boards/nxp/mcxw72_evk/doc/index.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/boards/nxp/mcxw72_evk/doc/index.rst b/boards/nxp/mcxw72_evk/doc/index.rst index 9bfd25da4e536..d15433e2d5eae 100644 --- a/boards/nxp/mcxw72_evk/doc/index.rst +++ b/boards/nxp/mcxw72_evk/doc/index.rst @@ -56,6 +56,16 @@ The ``mcxw72_evk`` board in Zephyr currently supports the following features: | I2C | on-chip | i2c | +-----------+------------+-------------------------------------+ +Fetch Binary Blobs +****************** + +To support Bluetooth, mcxw72_evk requires fetching binary blobs, which can be +achieved by running the following command: + +.. code-block:: console + + west blobs fetch hal_nxp + Programming and Debugging ************************* @@ -141,6 +151,21 @@ should see the following message in the terminal: *** Booting Zephyr OS build v3.7.0-xxx-xxxx *** Hello World! mcxw72_evk/mcxw727c/cpu0 +Bluetooth +========= + +BLE functionality requires to fetch binary blobs, so make sure to follow +the ``Fetch Binary Blobs`` section first. + +Two images must be written to the board: one for the host (CM33 core0) and one for the NBU (CM33 core1). +- To flash the application (CM33) refer to the ``Flashing`` section above. +- To flash the NBU, follow the instructions below: + +.. code-block:: console + + JLinkExe -device MCXW727C_CORE1 -if SWD -speed 4000 -autoconnect 1 + J-Link>loadbin 0x0 + Troubleshooting =============== From 93b53efbe3f9ba0176fd579cc0e388ba8e9dc9ee Mon Sep 17 00:00:00 2001 From: Jilay Pandya Date: Sun, 9 Feb 2025 19:36:41 +0100 Subject: [PATCH 0077/6055] samples: stepper: add tmc50xx sample Add a minimal tmc50xx sample with spi interface Signed-off-by: Jilay Pandya --- samples/drivers/stepper/index.rst | 5 ++ .../drivers/stepper/tmc50xx/CMakeLists.txt | 10 ++++ samples/drivers/stepper/tmc50xx/Kconfig | 18 ++++++ samples/drivers/stepper/tmc50xx/README.rst | 49 +++++++++++++++++ .../tmc50xx/boards/nucleo_g071rb.overlay | 52 ++++++++++++++++++ samples/drivers/stepper/tmc50xx/prj.conf | 2 + samples/drivers/stepper/tmc50xx/sample.yaml | 8 +++ samples/drivers/stepper/tmc50xx/src/main.c | 55 +++++++++++++++++++ 8 files changed, 199 insertions(+) create mode 100644 samples/drivers/stepper/index.rst create mode 100644 samples/drivers/stepper/tmc50xx/CMakeLists.txt create mode 100644 samples/drivers/stepper/tmc50xx/Kconfig create mode 100644 samples/drivers/stepper/tmc50xx/README.rst create mode 100644 samples/drivers/stepper/tmc50xx/boards/nucleo_g071rb.overlay create mode 100644 samples/drivers/stepper/tmc50xx/prj.conf create mode 100644 samples/drivers/stepper/tmc50xx/sample.yaml create mode 100644 samples/drivers/stepper/tmc50xx/src/main.c diff --git a/samples/drivers/stepper/index.rst b/samples/drivers/stepper/index.rst new file mode 100644 index 0000000000000..7592d15577ca9 --- /dev/null +++ b/samples/drivers/stepper/index.rst @@ -0,0 +1,5 @@ +.. zephyr:code-sample-category:: stepper + :name: Stepper + :show-listing: + + These samples demonstrate how to use the :ref:`stepper ` driver API. diff --git a/samples/drivers/stepper/tmc50xx/CMakeLists.txt b/samples/drivers/stepper/tmc50xx/CMakeLists.txt new file mode 100644 index 0000000000000..7d5a7d600f21b --- /dev/null +++ b/samples/drivers/stepper/tmc50xx/CMakeLists.txt @@ -0,0 +1,10 @@ + # SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya + # SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(tmc50xx) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/drivers/stepper/tmc50xx/Kconfig b/samples/drivers/stepper/tmc50xx/Kconfig new file mode 100644 index 0000000000000..59e2cc9f8d66e --- /dev/null +++ b/samples/drivers/stepper/tmc50xx/Kconfig @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "TMC50XX sample application" + +config STEPS_PER_REV + int "Steps per revolution" + default 200 + +config PING_PONG_N_REV + int "Change direction every N revolutions" + default 1 + +config MAX_VELOCITY_MULTIPLIER + int "Max velocity multiplier" + default 1 + +source "Kconfig.zephyr" diff --git a/samples/drivers/stepper/tmc50xx/README.rst b/samples/drivers/stepper/tmc50xx/README.rst new file mode 100644 index 0000000000000..17191c3f3741e --- /dev/null +++ b/samples/drivers/stepper/tmc50xx/README.rst @@ -0,0 +1,49 @@ +.. zephyr:code-sample:: tmc50xx + :name: TMC50XX stepper + :relevant-api: stepper_interface + + + Rotate a TMC50XX stepper motor and change velocity at runtime. + +Description +*********** + +This sample application periodically spins the stepper clockwise and counterclockwise depending on +the :kconfig:option:`CONFIG_PING_PONG_N_REV` configuration. + +References +********** + + - TMC5041: https://www.analog.com/media/en/technical-documentation/data-sheets/TMC5041_datasheet_rev1.16.pdf + - TMC5072: https://www.analog.com/media/en/technical-documentation/data-sheets/TMC5072_datasheet_rev1.26.pdf + +Wiring +******* + +This sample uses the TMC5072 BOB controlled using the SPI interface. The board's Devicetree must define +a ``stepper`` alias for the stepper motor node. + +Building and Running +******************** + +This project spins the stepper and outputs the events to the console. It requires an TMC50XX stepper +driver. It should work with any platform featuring a SPI peripheral interface. +It does not work on QEMU. + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/stepper/tmc50xx + :board: nucleo_g071rb + :goals: build flash + +Sample Output +============= + +.. code-block:: console + + Starting tmc50xx stepper sample + stepper is 0x8007240, name is tmc_stepper@0 + stepper_callback steps completed changing direction + stepper_callback steps completed changing direction + stepper_callback steps completed changing direction + + diff --git a/samples/drivers/stepper/tmc50xx/boards/nucleo_g071rb.overlay b/samples/drivers/stepper/tmc50xx/boards/nucleo_g071rb.overlay new file mode 100644 index 0000000000000..e3b70a3553140 --- /dev/null +++ b/samples/drivers/stepper/tmc50xx/boards/nucleo_g071rb.overlay @@ -0,0 +1,52 @@ +/ { + aliases { + stepper = &tmc_stepper; + }; +}; + +&spi1 { + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; + pinctrl-names = "default"; + cs-gpios = <&gpiob 0 GPIO_ACTIVE_LOW>; + status = "okay"; + tmc50xx: tmc50xx@0 { + compatible = "adi,tmc50xx"; + reg = <0>; + spi-max-frequency = ; /* Maximum SPI bus frequency */ + + #address-cells = <1>; + #size-cells = <0>; + + clock-frequency = ; /* Internal/External Clock frequency */ + + tmc_stepper: tmc_stepper@0 { + status = "okay"; + reg = <0>; + + /* common stepper controller settings */ + micro-step-res = <256>; + + /* ADI TMC stallguard settings specific to TMC50XX */ + activate-stallguard2; + stallguard-velocity-check-interval-ms=<1000>; + stallguard2-threshold=<30>; + stallguard-threshold-velocity=<200000>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <1000>; + vstop = <10>; + a1 = <10000>; + v1 = <50000>; + d1 = <14000>; + vmax = <900000>; + amax = <50000>; + dmax = <7000>; + tzerowait = <100>; + vhigh = <900000>; + vcoolthrs = <900000>; + ihold = <1>; + irun = <10>; + iholddelay = <1>; + }; + }; +}; diff --git a/samples/drivers/stepper/tmc50xx/prj.conf b/samples/drivers/stepper/tmc50xx/prj.conf new file mode 100644 index 0000000000000..f17d0707cf5d4 --- /dev/null +++ b/samples/drivers/stepper/tmc50xx/prj.conf @@ -0,0 +1,2 @@ +CONFIG_STEPPER=y +CONFIG_LOG=y diff --git a/samples/drivers/stepper/tmc50xx/sample.yaml b/samples/drivers/stepper/tmc50xx/sample.yaml new file mode 100644 index 0000000000000..fd600756c0d58 --- /dev/null +++ b/samples/drivers/stepper/tmc50xx/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: TMC50XX Stepper Sample +tests: + sample.stepper.tmc50xx: + harness: stepper + tags: stepper + platform_allow: nucleo_g071rb + depends_on: spi diff --git a/samples/drivers/stepper/tmc50xx/src/main.c b/samples/drivers/stepper/tmc50xx/src/main.c new file mode 100644 index 0000000000000..b5cb96632a1ab --- /dev/null +++ b/samples/drivers/stepper/tmc50xx/src/main.c @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +const struct device *stepper = DEVICE_DT_GET(DT_ALIAS(stepper)); + +int32_t ping_pong_target_position = CONFIG_STEPS_PER_REV * CONFIG_PING_PONG_N_REV * + DT_PROP(DT_ALIAS(stepper), micro_step_res); + +K_SEM_DEFINE(steps_completed_sem, 0, 1); + +void stepper_callback(const struct device *dev, const enum stepper_event event, void *user_data) +{ + switch (event) { + case STEPPER_EVENT_STEPS_COMPLETED: + k_sem_give(&steps_completed_sem); + break; + default: + break; + } +} + +int main(void) +{ + printf("Starting tmc50xx stepper sample\n"); + if (!device_is_ready(stepper)) { + printf("Device %s is not ready\n", stepper->name); + return -ENODEV; + } + printf("stepper is %p, name is %s\n", stepper, stepper->name); + + stepper_set_event_callback(stepper, stepper_callback, NULL); + stepper_enable(stepper, true); + stepper_set_reference_position(stepper, 0); + stepper_move_by(stepper, ping_pong_target_position); + + /* Change Max Velocity during runtime */ + int32_t tmc_velocity = DT_PROP(DT_ALIAS(stepper), vmax) * CONFIG_MAX_VELOCITY_MULTIPLIER; + (void)tmc50xx_stepper_set_max_velocity(stepper, tmc_velocity); + + for (;;) { + if (k_sem_take(&steps_completed_sem, K_FOREVER) == 0) { + ping_pong_target_position *= -1; + stepper_move_by(stepper, ping_pong_target_position); + } + } + return 0; +} From bfa712c3759a4134ea5d98d3db1c1b202d78dcd5 Mon Sep 17 00:00:00 2001 From: Jilay Pandya Date: Sun, 9 Feb 2025 19:50:11 +0100 Subject: [PATCH 0078/6055] MAINTAINERS: add stepper samples to stepper area Add newly added samples/drivers/stepper folder to Stepper area Signed-off-by: Jilay Pandya --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 2177e3a6352a0..7762faebf0ce5 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2129,6 +2129,7 @@ Release Notes: - include/zephyr/drivers/stepper.h - dts/bindings/stepper/ - doc/hardware/peripherals/stepper.rst + - samples/drivers/stepper/ - tests/drivers/build_all/stepper/ labels: - "area: Stepper" From b3a8de4a6002cd24bff01e61ebc14c373ddc7a41 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Thu, 30 Jan 2025 08:40:05 +0100 Subject: [PATCH 0079/6055] dts: arm: st: n6: add fdcan Add FDCAN support to STM32N6 Signed-off-by: Guillaume Gautier --- dts/arm/st/n6/stm32n6.dtsi | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/dts/arm/st/n6/stm32n6.dtsi b/dts/arm/st/n6/stm32n6.dtsi index 6a269a61a6aa0..d5dfb4e28adaf 100644 --- a/dts/arm/st/n6/stm32n6.dtsi +++ b/dts/arm/st/n6/stm32n6.dtsi @@ -362,6 +362,39 @@ }; }; + fdcan1: can@5000a000 { + compatible = "st,stm32h7-fdcan"; + reg = <0x5000A000 0x400>, <0x5000C000 0xd54>; + reg-names = "m_can", "message_ram"; + clocks = <&rcc STM32_CLOCK(APB1_2, 8)>; + interrupts = <180 0>, <181 0>, <186 0>; + interrupt-names = "int0", "int1", "calib"; + bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; + status = "disabled"; + }; + + fdcan2: can@5000a400 { + compatible = "st,stm32h7-fdcan"; + reg = <0x5000A400 0x400>, <0x5000C000 0x1aa8>; + reg-names = "m_can", "message_ram"; + clocks = <&rcc STM32_CLOCK(APB1_2, 8)>; + interrupts = <182 0>, <183 0>; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0xd54 28 8 3 3 0 3 3>; + status = "disabled"; + }; + + fdcan3: can@5000e800 { + compatible = "st,stm32h7-fdcan"; + reg = <0x5000E800 0x400>, <0x5000C000 0x2800>; + reg-names = "m_can", "message_ram"; + clocks = <&rcc STM32_CLOCK(APB1_2, 8)>; + interrupts = <184 0>, <185 0>; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x1aa8 28 8 3 3 0 3 3>; + status = "disabled"; + }; + usart1: serial@52001000 { compatible = "st,stm32-usart", "st,stm32-uart"; reg = <0x52001000 0x400>; From 05657bc52f7a7b5d9c718e6d990636ae3a2bd1fa Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Thu, 30 Jan 2025 08:48:25 +0100 Subject: [PATCH 0080/6055] boards: st: stm32n6: enable fdcan for stm32n6 boards Enable FDCAN for Nucleo N657x0-Q and STM32N6570 DK boards. Signed-off-by: Guillaume Gautier --- boards/st/nucleo_n657x0_q/doc/index.rst | 4 ++++ boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi | 9 +++++++++ boards/st/nucleo_n657x0_q/twister.yaml | 1 + boards/st/stm32n6570_dk/doc/index.rst | 4 ++++ boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi | 9 +++++++++ boards/st/stm32n6570_dk/twister.yaml | 1 + 6 files changed, 28 insertions(+) diff --git a/boards/st/nucleo_n657x0_q/doc/index.rst b/boards/st/nucleo_n657x0_q/doc/index.rst index c729f1810ab77..d4bd1a05107c2 100644 --- a/boards/st/nucleo_n657x0_q/doc/index.rst +++ b/boards/st/nucleo_n657x0_q/doc/index.rst @@ -67,6 +67,8 @@ The Zephyr ``nucleo_n657x0_q`` board supports the following hardware features: +===========+============+=====================================+ | CLOCK | on-chip | reset and clock control | +-----------+------------+-------------------------------------+ +| CAN/CANFD | on-chip | canbus | ++-----------+------------+-------------------------------------+ | DMA | on-chip | Direct Memory Access Controller | +-----------+------------+-------------------------------------+ | GPIO | on-chip | gpio | @@ -95,6 +97,8 @@ For more details please refer to `NUCLEO-N657X0-Q User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- +- FDCAN1_TX : PH2 +- FDCAN1_RX : PD0 - LD1 : PO1 - LD2 : PG10 - USART_1_TX : PE5 diff --git a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi index db3fd57e2130d..d7c117876b338 100644 --- a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi +++ b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi @@ -13,6 +13,7 @@ zephyr,console = &usart1; zephyr,shell-uart = &usart1; zephyr,sram = &axisram2; + zephyr,canbus = &fdcan1; }; leds: leds { @@ -110,6 +111,14 @@ apb5-prescaler = <1>; }; +&fdcan1 { + clocks = <&rcc STM32_CLOCK(APB1_2, 8)>, + <&rcc STM32_SRC_CKPER FDCAN_SEL(1)>; + pinctrl-0 = <&fdcan1_rx_pd0 &fdcan1_tx_ph2>; + pinctrl-names = "default"; + status = "okay"; +}; + &usart1 { clocks = <&rcc STM32_CLOCK(APB2, 4)>, <&rcc STM32_SRC_CKPER USART1_SEL(1)>; diff --git a/boards/st/nucleo_n657x0_q/twister.yaml b/boards/st/nucleo_n657x0_q/twister.yaml index 8ba73fcd9d344..9a4790009af24 100644 --- a/boards/st/nucleo_n657x0_q/twister.yaml +++ b/boards/st/nucleo_n657x0_q/twister.yaml @@ -5,6 +5,7 @@ ram: 1024 flash: 1024 supported: - arduino_serial + - can - dma - gpio - uart diff --git a/boards/st/stm32n6570_dk/doc/index.rst b/boards/st/stm32n6570_dk/doc/index.rst index 0c1648017ad83..d5b2493f62521 100644 --- a/boards/st/stm32n6570_dk/doc/index.rst +++ b/boards/st/stm32n6570_dk/doc/index.rst @@ -71,6 +71,8 @@ The Zephyr ``stm32n6570_dk`` board supports the following hardware features: +===========+============+=====================================+ | CLOCK | on-chip | reset and clock control | +-----------+------------+-------------------------------------+ +| CAN/CANFD | on-chip | canbus | ++-----------+------------+-------------------------------------+ | DMA | on-chip | Direct Memory Access Controller | +-----------+------------+-------------------------------------+ | GPIO | on-chip | gpio | @@ -99,6 +101,8 @@ For more details please refer to `STM32N6570_DK User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- +- FDCAN1_TX : PH2 +- FDCAN1_RX : PD0 - LD1 : PO1 - LD2 : PG10 - USART_1_TX : PE5 diff --git a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi index 834fab39eb935..1cbf7e60b732c 100644 --- a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi +++ b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi @@ -13,6 +13,7 @@ zephyr,console = &usart1; zephyr,shell-uart = &usart1; zephyr,sram = &axisram2; + zephyr,canbus = &fdcan1; }; aliases { @@ -94,6 +95,14 @@ apb5-prescaler = <1>; }; +&fdcan1 { + clocks = <&rcc STM32_CLOCK(APB1_2, 8)>, + <&rcc STM32_SRC_CKPER FDCAN_SEL(1)>; + pinctrl-0 = <&fdcan1_rx_pd0 &fdcan1_tx_ph2>; + pinctrl-names = "default"; + status = "okay"; +}; + &usart1 { clocks = <&rcc STM32_CLOCK(APB2, 4)>, <&rcc STM32_SRC_CKPER USART1_SEL(1)>; diff --git a/boards/st/stm32n6570_dk/twister.yaml b/boards/st/stm32n6570_dk/twister.yaml index 6dfcfaeda28f3..1ea433c8bbbaa 100644 --- a/boards/st/stm32n6570_dk/twister.yaml +++ b/boards/st/stm32n6570_dk/twister.yaml @@ -6,6 +6,7 @@ flash: 1024 vendor: st supported: - arduino_serial + - can - dma - gpio - uart From 5415e8e4a62c2090dc1418aaa5225919e7df224e Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 31 Jan 2025 08:50:37 +0100 Subject: [PATCH 0081/6055] tests: drivers: can: add stm32n6 boards overlays Add CAN test overlays for Nucleo N657x0-Q and STM32N6570 DK boards. Userspace needs to be disabled for the tests to pass. Signed-off-by: Guillaume Gautier --- .../drivers/can/api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf | 1 + tests/drivers/can/api/boards/stm32n6570_dk_stm32n657xx_sb.conf | 1 + .../can/timing/boards/nucleo_n657x0_q_stm32n657xx_sb.conf | 2 ++ .../drivers/can/timing/boards/stm32n6570_dk_stm32n657xx_sb.conf | 2 ++ 4 files changed, 6 insertions(+) create mode 100644 tests/drivers/can/api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf create mode 100644 tests/drivers/can/api/boards/stm32n6570_dk_stm32n657xx_sb.conf create mode 100644 tests/drivers/can/timing/boards/nucleo_n657x0_q_stm32n657xx_sb.conf create mode 100644 tests/drivers/can/timing/boards/stm32n6570_dk_stm32n657xx_sb.conf diff --git a/tests/drivers/can/api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf b/tests/drivers/can/api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf new file mode 100644 index 0000000000000..9fb2581d7f4a2 --- /dev/null +++ b/tests/drivers/can/api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf @@ -0,0 +1 @@ +CONFIG_TEST_USERSPACE=n diff --git a/tests/drivers/can/api/boards/stm32n6570_dk_stm32n657xx_sb.conf b/tests/drivers/can/api/boards/stm32n6570_dk_stm32n657xx_sb.conf new file mode 100644 index 0000000000000..9fb2581d7f4a2 --- /dev/null +++ b/tests/drivers/can/api/boards/stm32n6570_dk_stm32n657xx_sb.conf @@ -0,0 +1 @@ +CONFIG_TEST_USERSPACE=n diff --git a/tests/drivers/can/timing/boards/nucleo_n657x0_q_stm32n657xx_sb.conf b/tests/drivers/can/timing/boards/nucleo_n657x0_q_stm32n657xx_sb.conf new file mode 100644 index 0000000000000..e0f23afd0cb96 --- /dev/null +++ b/tests/drivers/can/timing/boards/nucleo_n657x0_q_stm32n657xx_sb.conf @@ -0,0 +1,2 @@ +CONFIG_TEST_ALL_BITRATES=y +CONFIG_TEST_USERSPACE=n diff --git a/tests/drivers/can/timing/boards/stm32n6570_dk_stm32n657xx_sb.conf b/tests/drivers/can/timing/boards/stm32n6570_dk_stm32n657xx_sb.conf new file mode 100644 index 0000000000000..e0f23afd0cb96 --- /dev/null +++ b/tests/drivers/can/timing/boards/stm32n6570_dk_stm32n657xx_sb.conf @@ -0,0 +1,2 @@ +CONFIG_TEST_ALL_BITRATES=y +CONFIG_TEST_USERSPACE=n From 1bf536eb1007212264fdececb8a52be22b89bd0d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 11 Feb 2025 11:24:23 +0100 Subject: [PATCH 0082/6055] modules: Update uoscore-uedhoc revision to the latest Pull latest revision of the uoscore-uedhoc module and align corresponding CMake file with the changes. Signed-off-by: Robert Lubos --- modules/uoscore-uedhoc/CMakeLists.txt | 3 ++- west.yml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/uoscore-uedhoc/CMakeLists.txt b/modules/uoscore-uedhoc/CMakeLists.txt index aaf842e392ca6..a7f08928381d5 100644 --- a/modules/uoscore-uedhoc/CMakeLists.txt +++ b/modules/uoscore-uedhoc/CMakeLists.txt @@ -107,7 +107,8 @@ if (CONFIG_UOSCORE OR CONFIG_UEDHOC) ${UOSCORE_UEDHOC_SRC_DIR}/cbor/edhoc_decode_message_1.c ${UOSCORE_UEDHOC_SRC_DIR}/cbor/edhoc_decode_message_2.c ${UOSCORE_UEDHOC_SRC_DIR}/cbor/edhoc_decode_message_3.c - ${UOSCORE_UEDHOC_SRC_DIR}/cbor/edhoc_decode_plaintext.c + ${UOSCORE_UEDHOC_SRC_DIR}/cbor/edhoc_decode_plaintext2.c + ${UOSCORE_UEDHOC_SRC_DIR}/cbor/edhoc_decode_plaintext3.c ${UOSCORE_UEDHOC_SRC_DIR}/cbor/edhoc_encode_bstr_type.c ${UOSCORE_UEDHOC_SRC_DIR}/cbor/edhoc_encode_data_2.c ${UOSCORE_UEDHOC_SRC_DIR}/cbor/edhoc_encode_enc_structure.c diff --git a/west.yml b/west.yml index 0e5e87bec15c5..cbfecc80e61ba 100644 --- a/west.yml +++ b/west.yml @@ -358,7 +358,7 @@ manifest: groups: - tee - name: uoscore-uedhoc - revision: 84ef879a46d7bfd9a423fbfb502b04289861f9ea + revision: 54abc109c9c0adfd53c70077744c14e454f04f4a path: modules/lib/uoscore-uedhoc - name: zcbor revision: 9b07780aca6fb21f82a241ba386ad9b379809337 From 29975452efc3a5aa40d6434ae1553db115a5225d Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 11 Feb 2025 15:24:41 +0100 Subject: [PATCH 0083/6055] modules: liblc3: Bump to 1.1.2 Bump up liblc3 to the 1.1.2 Signed-off-by: Mariusz Skamra --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index cbfecc80e61ba..f446f270996fd 100644 --- a/west.yml +++ b/west.yml @@ -276,7 +276,7 @@ manifest: path: modules/lib/hostap revision: 4957416a01c86579aebb333b43f1c23da0375835 - name: liblc3 - revision: bb85f7dde4195bfc0fca9e9c7c2eed0f8694203c + revision: 48bbd3eacd36e99a57317a0a4867002e0b09e183 path: modules/lib/liblc3 - name: libmctp revision: b97860e78998551af99931ece149eeffc538bdb1 From 774730e06a56692e0b823890cdc7270353ef5463 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Tue, 11 Feb 2025 15:54:51 -0300 Subject: [PATCH 0084/6055] drivers: video: use correct return error Build fails due to wrong variable used in log output. Signed-off-by: Sylvio Alves --- drivers/video/video_esp32_dvp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/video_esp32_dvp.c b/drivers/video/video_esp32_dvp.c index b13c329f96cba..a4e243f46b6e9 100644 --- a/drivers/video/video_esp32_dvp.c +++ b/drivers/video/video_esp32_dvp.c @@ -153,7 +153,7 @@ static int video_esp32_set_stream(const struct device *dev, bool enable) data->is_streaming = false; error = dma_stop(cfg->dma_dev, cfg->rx_dma_channel); if (error) { - LOG_ERR("Unable to stop DMA (%d)", ret); + LOG_ERR("Unable to stop DMA (%d)", error); return error; } From 62a08e79616fa113aba74c3a674425d8ba3b1d2b Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 12 Feb 2025 12:08:52 +0800 Subject: [PATCH 0085/6055] drivers: ethernet: nxp_imx_netc: fix dt parsing of dsa port connection Wrong functions were used for dsa port connection dt parsing. Fixed it. Signed-off-by: Yangbo Lu --- drivers/ethernet/nxp_imx_netc/dsa_nxp_imx_netc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ethernet/nxp_imx_netc/dsa_nxp_imx_netc.c b/drivers/ethernet/nxp_imx_netc/dsa_nxp_imx_netc.c index 9dd68d97865ff..a1cda7cc7c16e 100644 --- a/drivers/ethernet/nxp_imx_netc/dsa_nxp_imx_netc.c +++ b/drivers/ethernet/nxp_imx_netc/dsa_nxp_imx_netc.c @@ -256,8 +256,8 @@ static struct dsa_api dsa_netc_api = { .pseudo_mac = DT_ENUM_HAS_VALUE(slave, phy_connection_type, internal), \ .pincfg = PINCTRL_DT_DEV_CONFIG_GET(slave), \ .port_idx = DT_REG_ADDR_BY_IDX(slave, 0), \ - .ethernet_connection = (COND_CODE_1(DT_INST_NODE_HAS_PROP(slave, ethernet), \ - (DEVICE_DT_GET(DT_INST_PHANDLE(slave, ethernet))), NULL)), \ + .ethernet_connection = (COND_CODE_1(DT_NODE_HAS_PROP(slave, ethernet), \ + (DEVICE_DT_GET(DT_PHANDLE(slave, ethernet))), NULL)), \ }; \ NET_DEVICE_INIT_INSTANCE( \ CONCAT(dsa_slave_port_, slave), \ From b1803eaf8f4b114435ae70b0d379277d48e9603f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Feb 2025 11:59:24 +0100 Subject: [PATCH 0086/6055] boards: Remove 'xtools' toolchain variant references (take 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A follow-up to commit fe87abe0b9549e3cb07194fbf039912dd321f9ed This addresses boards that had pending pull requests at the time the initial clean-up was done. Signed-off-by: Benjamin Cabé --- boards/adi/max78000evkit/max78000evkit_max78000_m4.yaml | 1 - boards/adi/max78000fthr/max78000fthr_max78000_m4.yaml | 1 - boards/arm/mps2/mps2_an383.yaml | 1 - boards/arm/mps2/mps2_an386.yaml | 1 - boards/arm/mps2/mps2_an500.yaml | 1 - boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.yaml | 1 - boards/nxp/frdm_mcxw72/frdm_mcxw72_mcxw727c_cpu0.yaml | 1 - boards/nxp/mcxw72_evk/mcxw72_evk_mcxw727c_cpu0.yaml | 1 - boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi_C.yaml | 1 - boards/rakwireless/rak3172/rak3172.yaml | 1 - boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.yaml | 1 - boards/silabs/radio_boards/xg29_rb4412a/xg29_rb4412a.yaml | 1 - boards/st/nucleo_f072rb/nucleo_f072rb.yaml | 1 - boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml | 1 - 14 files changed, 14 deletions(-) diff --git a/boards/adi/max78000evkit/max78000evkit_max78000_m4.yaml b/boards/adi/max78000evkit/max78000evkit_max78000_m4.yaml index f974a60c9959b..5f7f522504112 100644 --- a/boards/adi/max78000evkit/max78000evkit_max78000_m4.yaml +++ b/boards/adi/max78000evkit/max78000evkit_max78000_m4.yaml @@ -6,7 +6,6 @@ arch: arm toolchain: - zephyr - gnuarmemb - - xtools supported: - adc - counter diff --git a/boards/adi/max78000fthr/max78000fthr_max78000_m4.yaml b/boards/adi/max78000fthr/max78000fthr_max78000_m4.yaml index f649928b1bacf..116fa9051c584 100644 --- a/boards/adi/max78000fthr/max78000fthr_max78000_m4.yaml +++ b/boards/adi/max78000fthr/max78000fthr_max78000_m4.yaml @@ -6,7 +6,6 @@ arch: arm toolchain: - zephyr - gnuarmemb - - xtools supported: - adc - counter diff --git a/boards/arm/mps2/mps2_an383.yaml b/boards/arm/mps2/mps2_an383.yaml index c7e2ae8ba3fb0..249225737754a 100644 --- a/boards/arm/mps2/mps2_an383.yaml +++ b/boards/arm/mps2/mps2_an383.yaml @@ -8,7 +8,6 @@ simulation: toolchain: - zephyr - gnuarmemb - - xtools supported: - counter - netif:serial-net diff --git a/boards/arm/mps2/mps2_an386.yaml b/boards/arm/mps2/mps2_an386.yaml index c241948ce498e..f71e166e683d4 100644 --- a/boards/arm/mps2/mps2_an386.yaml +++ b/boards/arm/mps2/mps2_an386.yaml @@ -8,7 +8,6 @@ simulation: toolchain: - zephyr - gnuarmemb - - xtools supported: - counter - gpio diff --git a/boards/arm/mps2/mps2_an500.yaml b/boards/arm/mps2/mps2_an500.yaml index 243fc64083df2..cc4c713d799f9 100644 --- a/boards/arm/mps2/mps2_an500.yaml +++ b/boards/arm/mps2/mps2_an500.yaml @@ -8,7 +8,6 @@ simulation: toolchain: - zephyr - gnuarmemb - - xtools supported: - counter - gpio diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.yaml b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.yaml index 352e6ebc514e3..62335a40f84ac 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.yaml +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.yaml @@ -13,7 +13,6 @@ flash: 200 toolchain: - zephyr - gnuarmemb - - xtools supported: - dma - gpio diff --git a/boards/nxp/frdm_mcxw72/frdm_mcxw72_mcxw727c_cpu0.yaml b/boards/nxp/frdm_mcxw72/frdm_mcxw72_mcxw727c_cpu0.yaml index 3d881e5cd4f32..b41068a1c998d 100644 --- a/boards/nxp/frdm_mcxw72/frdm_mcxw72_mcxw727c_cpu0.yaml +++ b/boards/nxp/frdm_mcxw72/frdm_mcxw72_mcxw727c_cpu0.yaml @@ -7,7 +7,6 @@ flash: 2048 toolchain: - zephyr - gnuarmemb - - xtools supported: - adc - can diff --git a/boards/nxp/mcxw72_evk/mcxw72_evk_mcxw727c_cpu0.yaml b/boards/nxp/mcxw72_evk/mcxw72_evk_mcxw727c_cpu0.yaml index d3841b6fe308c..f3f9a54cf1da3 100644 --- a/boards/nxp/mcxw72_evk/mcxw72_evk_mcxw727c_cpu0.yaml +++ b/boards/nxp/mcxw72_evk/mcxw72_evk_mcxw727c_cpu0.yaml @@ -7,7 +7,6 @@ flash: 2048 toolchain: - zephyr - gnuarmemb - - xtools supported: - adc - can diff --git a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi_C.yaml b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi_C.yaml index 3f19dd54721f5..2a1c331164722 100644 --- a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi_C.yaml +++ b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi_C.yaml @@ -11,7 +11,6 @@ arch: arm toolchain: - zephyr - gnuarmemb - - xtools ram: 32768 flash: 8192 supported: diff --git a/boards/rakwireless/rak3172/rak3172.yaml b/boards/rakwireless/rak3172/rak3172.yaml index b3d19a8284f37..75017423ed671 100644 --- a/boards/rakwireless/rak3172/rak3172.yaml +++ b/boards/rakwireless/rak3172/rak3172.yaml @@ -5,7 +5,6 @@ arch: arm toolchain: - zephyr - gnuarmemb - - xtools ram: 64 flash: 256 supported: diff --git a/boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.yaml b/boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.yaml index 602906447c2fd..12dd348c93c42 100644 --- a/boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.yaml +++ b/boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.yaml @@ -7,7 +7,6 @@ flash: 1024 toolchain: - zephyr - gnuarmemb - - xtools supported: - bluetooth - dma diff --git a/boards/silabs/radio_boards/xg29_rb4412a/xg29_rb4412a.yaml b/boards/silabs/radio_boards/xg29_rb4412a/xg29_rb4412a.yaml index 989719eda22a8..c829c215fa9b1 100644 --- a/boards/silabs/radio_boards/xg29_rb4412a/xg29_rb4412a.yaml +++ b/boards/silabs/radio_boards/xg29_rb4412a/xg29_rb4412a.yaml @@ -7,7 +7,6 @@ flash: 1024 toolchain: - zephyr - gnuarmemb - - xtools supported: - bluetooth - gpio diff --git a/boards/st/nucleo_f072rb/nucleo_f072rb.yaml b/boards/st/nucleo_f072rb/nucleo_f072rb.yaml index dca1847f4b8ed..0a46f541b9115 100644 --- a/boards/st/nucleo_f072rb/nucleo_f072rb.yaml +++ b/boards/st/nucleo_f072rb/nucleo_f072rb.yaml @@ -7,7 +7,6 @@ flash: 128 toolchain: - zephyr - gnuarmemb - - xtools supported: - adc - arduino_gpio diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml index 705f3cdef20a7..29cda9cc23990 100644 --- a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml @@ -7,7 +7,6 @@ flash: 512 toolchain: - zephyr - gnuarmemb - - xtools supported: - gpio - uart From 2512d3d57e1c6b583ca3fcb15a76349c19f167d7 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 6 Feb 2025 13:55:49 +0100 Subject: [PATCH 0087/6055] boards: nrf9280pdk: remove can enablement CAN is not supported yet, so remove it from the board for now. Signed-off-by: Gerard Marull-Paretas --- .../nordic/nrf9280pdk/nrf9280pdk_nrf9280-pinctrl.dtsi | 7 ------- .../nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts | 11 ----------- .../nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.yaml | 1 - 3 files changed, 19 deletions(-) diff --git a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280-pinctrl.dtsi b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280-pinctrl.dtsi index 48067a7052c33..4cae3ba580ffc 100644 --- a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280-pinctrl.dtsi +++ b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280-pinctrl.dtsi @@ -60,13 +60,6 @@ }; }; - /omit-if-no-ref/ can120_default: can120_default { - group1 { - psels = , - ; - }; - }; - /omit-if-no-ref/ pwm130_default: pwm130_default { group1 { psels = ; diff --git a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts index a380ac7473aad..11760974a11aa 100644 --- a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts +++ b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts @@ -27,7 +27,6 @@ zephyr,ieee802154 = &cpuapp_ieee802154; zephyr,bt-hci = &bt_hci_ipc0; nordic,802154-spinel-ipc = &ipc0; - zephyr,canbus = &can120; }; aliases { @@ -275,16 +274,6 @@ zephyr_udc0: &usbhs { status = "okay"; }; -&canpll { - status = "okay"; -}; - -&can120 { - status = "okay"; - pinctrl-0 = <&can120_default>; - pinctrl-names = "default"; -}; - &pwm130 { status = "okay"; pinctrl-0 = <&pwm130_default>; diff --git a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.yaml b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.yaml index fc718eb1c8ecb..d4bc799100dd2 100644 --- a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.yaml +++ b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.yaml @@ -13,7 +13,6 @@ ram: 512 flash: 1024 supported: - adc - - can - counter - gpio - i2c From 8b851ad990b81593f0789bcbbdc00754077db469 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 6 Feb 2025 13:56:22 +0100 Subject: [PATCH 0088/6055] dts: nordic: nrf9280: drop can120/121 nodes CAN is not ready yet for this platform (clock control drivers). So remove the nodes for now. Signed-off-by: Gerard Marull-Paretas --- dts/common/nordic/nrf9280.dtsi | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/dts/common/nordic/nrf9280.dtsi b/dts/common/nordic/nrf9280.dtsi index e03359a47096b..df5f3c429319b 100644 --- a/dts/common/nordic/nrf9280.dtsi +++ b/dts/common/nordic/nrf9280.dtsi @@ -445,28 +445,6 @@ global-domain-id = <12>; }; - can120: can@8d8000 { - compatible = "nordic,nrf-can"; - reg = <0x8d8000 0x400>, <0x2fbef800 0x800>, <0x2fbe8000 0x7800>; - reg-names = "wrapper", "m_can", "message_ram"; - interrupts = <216 NRF_DEFAULT_IRQ_PRIORITY>; - clocks = <&canpll>, <&hsfll120>; - clock-names = "auxpll", "hsfll"; - bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; - status = "disabled"; - }; - - can121: can@8db000 { - compatible = "nordic,nrf-can"; - reg = <0x8db000 0x400>, <0x2fbf7800 0x800>, <0x2fbf0000 0x7800>; - reg-names = "wrapper", "m_can", "message_ram"; - interrupts = <219 NRF_DEFAULT_IRQ_PRIORITY>; - clocks = <&canpll>, <&hsfll120>; - clock-names = "auxpll", "hsfll"; - bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; - status = "disabled"; - }; - dppic120: dppic@8e1000 { compatible = "nordic,nrf-dppic-global"; reg = <0x8e1000 0x1000>; From 71d663dafcb2de0e140098ad990b03f3e1bf7ed4 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 12 Feb 2025 09:54:40 +0100 Subject: [PATCH 0089/6055] tests: kernel: gen_isr_table: exclude nrf9280pdk/nrf9280/cpuppr First, SoC is not supported, but when I tried to add it, build results in RAM overflow of ~10K. Excluding the platform for now, so CI is happy. Signed-off-by: Gerard Marull-Paretas --- tests/kernel/gen_isr_table/testcase.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/kernel/gen_isr_table/testcase.yaml b/tests/kernel/gen_isr_table/testcase.yaml index 6b7df17636d4c..60662b11d9c13 100644 --- a/tests/kernel/gen_isr_table/testcase.yaml +++ b/tests/kernel/gen_isr_table/testcase.yaml @@ -72,6 +72,8 @@ tests: platform_exclude: - m2gl025_miv - adp_xc7k/ae350 + - nrf9280pdk/nrf9280/cpuppr + - nrf9280pdk/nrf9280/cpuppr/xip filter: CONFIG_RISCV_PRIVILEGED extra_configs: - CONFIG_GEN_IRQ_VECTOR_TABLE=y From 0c368e85b117272df8397d8258da088ebea11f5c Mon Sep 17 00:00:00 2001 From: Tomi Fontanilles Date: Tue, 11 Feb 2025 12:59:46 +0200 Subject: [PATCH 0090/6055] secure_storage: add a global registry header file for PSA key IDs We need to make sure that within Zephyr different users of the PSA APIs don't interfere with each other because of using the same numerical IDs for persistent assets. This takes care of the PSA key IDs when using persistent keys through the PSA Crypto API. See the comments in `` for more information. This removes the recently-introduced Kconfig options that allowed changing the base IDs subsystems were using for their persistent keys. Signed-off-by: Tomi Fontanilles --- MAINTAINERS.yml | 1 + include/zephyr/psa/key_ids.h | 51 +++++++++++++++++++ modules/openthread/Kconfig.thread | 8 --- .../platform/openthread-core-zephyr-config.h | 5 +- samples/psa/persistent_key/src/main.c | 3 +- subsys/bluetooth/mesh/Kconfig | 16 ------ subsys/bluetooth/mesh/crypto_psa.c | 31 +++++------ subsys/net/lib/wifi_credentials/Kconfig | 12 ----- .../wifi_credentials_backend_psa.c | 17 +++---- .../bluetooth/mesh/src/distribute_keyid.c | 32 ++++++------ .../CMakeLists.txt | 1 - .../wifi_credentials_backend_psa/src/main.c | 14 +++-- .../secure_storage/psa/crypto/src/main.c | 3 +- 13 files changed, 103 insertions(+), 91 deletions(-) create mode 100644 include/zephyr/psa/key_ids.h diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 7762faebf0ce5..1eeaacf400761 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4341,6 +4341,7 @@ Secure storage: - tomi-font files: - subsys/secure_storage/ + - include/zephyr/psa/ - samples/psa/ - doc/services/secure_storage.rst - tests/subsys/secure_storage/ diff --git a/include/zephyr/psa/key_ids.h b/include/zephyr/psa/key_ids.h new file mode 100644 index 0000000000000..851d1349812d5 --- /dev/null +++ b/include/zephyr/psa/key_ids.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2025 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_PSA_KEY_IDS_H_ +#define ZEPHYR_PSA_KEY_IDS_H_ + +/** + * @file zephyr/psa/key_ids.h + * + * @brief This file defines the key ID ranges of the existing users of the PSA Crypto API. + * + * In addition to the application, different subsystems store and use persistent keys through the + * PSA Crypto API. Because they are not aware of each other, collisions are avoided by having them + * use different ID ranges. + * This file acts as the registry of all the allocated PSA key ID ranges within Zephyr. + * + * The end-user application also has a dedicated range, `ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_BEGIN`. + * + * Some of the IDs below are based on previously existing and used values, while others + * are chosen to be somewhere in the PSA user key ID range to try to avoid collisions + * (avoiding, for example, the very beginning of the range). + */ + +#include +typedef uint32_t psa_key_id_t; + +/** PSA key ID range to be used by OpenThread. The base ID is equal to the default value upstream: + * https://github.com/openthread/openthread/blob/thread-reference-20230706/src/core/config/platform.h#L138 + */ +#define ZEPHYR_PSA_OPENTHREAD_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20000 +#define ZEPHYR_PSA_OPENTHREAD_KEY_ID_RANGE_SIZE 0x10000 /* 64 Ki */ + +/** PSA key ID range to be used by Matter. The base ID is equal to the default value upstream: + * https://github.com/project-chip/connectedhomeip/blob/v1.4.0.0/src/crypto/CHIPCryptoPALPSA.h#L55 + */ +#define ZEPHYR_PSA_MATTER_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x30000 +#define ZEPHYR_PSA_MATTER_KEY_ID_RANGE_SIZE 0x10000 /* 64 Ki */ + +/** PSA key ID range to be used by Bluetooth Mesh. */ +#define ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20000000 +#define ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_SIZE 0xC000 /* 48 Ki */ + +/** PSA key ID range to be used by Wi-Fi credentials management. */ +#define ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20010000 +#define ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_SIZE 0x100 /* 256 */ + +/** PSA key ID range to be used by the end-user application. */ +#define ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x30000000 +#define ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_SIZE 0x100000 /* 1 Mi */ + +#endif /* ZEPHYR_PSA_KEY_IDS_H_ */ diff --git a/modules/openthread/Kconfig.thread b/modules/openthread/Kconfig.thread index 81c0ab20afc09..2bababd4fee5d 100644 --- a/modules/openthread/Kconfig.thread +++ b/modules/openthread/Kconfig.thread @@ -250,11 +250,3 @@ config OPENTHREAD_MLE_CHILD_TIMEOUT default 240 help The value of MLE child timeout in seconds. - -config OPENTHREAD_PSA_ITS_NVM_OFFSET - hex "NVM offset while using key refs" - default 0x20000 - help - The offset value in the PSA ITS non-volatile space is dedicated to OpenThread - key reference IDs. This offset must not overwrite any other ranges already in - use within the PSA ITS non-volatile space. diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index c495c8ca4eff2..15688bf67a2d9 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -14,6 +14,7 @@ #define OPENTHREAD_CORE_ZEPHYR_CONFIG_H_ #include +#include #include /** @@ -516,8 +517,6 @@ * NVM offset while using key refs. * */ -#ifdef CONFIG_OPENTHREAD_PSA_ITS_NVM_OFFSET -#define OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET CONFIG_OPENTHREAD_PSA_ITS_NVM_OFFSET -#endif +#define OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET ZEPHYR_PSA_OPENTHREAD_KEY_ID_RANGE_BEGIN #endif /* OPENTHREAD_CORE_ZEPHYR_CONFIG_H_ */ diff --git a/samples/psa/persistent_key/src/main.c b/samples/psa/persistent_key/src/main.c index c79d8184f94fe..2f010a012ea08 100644 --- a/samples/psa/persistent_key/src/main.c +++ b/samples/psa/persistent_key/src/main.c @@ -3,10 +3,11 @@ */ #include #include +#include LOG_MODULE_REGISTER(persistent_key); -#define SAMPLE_KEY_ID PSA_KEY_ID_USER_MIN +#define SAMPLE_KEY_ID ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_BEGIN #define SAMPLE_KEY_TYPE PSA_KEY_TYPE_AES #define SAMPLE_ALG PSA_ALG_CTR #define SAMPLE_KEY_BITS 256 diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 49cc16fa7b60d..a3f4b6c4bd10c 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1531,22 +1531,6 @@ config BT_MESH_USES_TFM_PSA endchoice -if BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA - -config BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET - int "Offset of Bluetooth Mesh key id range regarding PSA_KEY_ID_USER_MIN" - default 0 - help - The PSA specification mandates to set key identifiers for keys - with persistent lifetime. The users of the PSA API is responsible - (Bluetooth Mesh is user of PSA API) to provide correct and unique identifiers. - The Bluetooth Mesh identifier range should be between PSA_KEY_ID_USER_MIN and - PSA_KEY_ID_USER_MAX. Bluetooth Mesh requires two ids for each subnetwork, two ids - for each application key, and two ids for the device key and device key candidate. - It should consider the Mesh Configuration Database instances if database enabled. - -endif # BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA - menu "Beacons" config BT_MESH_BEACON_ENABLED diff --git a/subsys/bluetooth/mesh/crypto_psa.c b/subsys/bluetooth/mesh/crypto_psa.c index 7267f064bc8e4..cc43293a3df23 100644 --- a/subsys/bluetooth/mesh/crypto_psa.c +++ b/subsys/bluetooth/mesh/crypto_psa.c @@ -7,6 +7,7 @@ #include #include +#include #include #define LOG_LEVEL CONFIG_BT_MESH_CRYPTO_LOG_LEVEL @@ -26,13 +27,13 @@ LOG_MODULE_REGISTER(bt_mesh_crypto_psa); #else #define BT_MESH_CDB_KEY_ID_RANGE_SIZE 0 #endif -#define BT_MESH_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \ - 2 * CONFIG_BT_MESH_APP_KEY_COUNT + 2 + BT_MESH_CDB_KEY_ID_RANGE_SIZE) -#define BT_MESH_PSA_KEY_ID_USER_MIN (PSA_KEY_ID_USER_MIN + \ - CONFIG_BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET) -BUILD_ASSERT(BT_MESH_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE <= PSA_KEY_ID_USER_MAX, - "Bluetooth Mesh PSA key id range overlaps maximum allowed boundary."); +#define BT_MESH_PSA_KEY_ID_MIN ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_BEGIN + +#define BT_MESH_PSA_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \ + 2 * CONFIG_BT_MESH_APP_KEY_COUNT + 2 + BT_MESH_CDB_KEY_ID_RANGE_SIZE) +BUILD_ASSERT(BT_MESH_PSA_KEY_ID_RANGE_SIZE <= ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_SIZE, + "PSA key ID range exceeds officially allocated range."); BUILD_ASSERT(PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128, PSA_ALG_CMAC) == 16, "MAC length should be 16 bytes for 128-bits key for CMAC-AES"); @@ -46,7 +47,7 @@ static struct { uint8_t public_key_be[PUB_KEY_SIZE + 1]; } dh_pair; -static ATOMIC_DEFINE(pst_keys, BT_MESH_KEY_ID_RANGE_SIZE); +static ATOMIC_DEFINE(pst_keys, BT_MESH_PSA_KEY_ID_RANGE_SIZE); int bt_mesh_crypto_init(void) { @@ -354,10 +355,10 @@ int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, uint8_t * __weak psa_key_id_t bt_mesh_user_keyid_alloc(void) { - for (int i = 0; i < BT_MESH_KEY_ID_RANGE_SIZE; i++) { + for (int i = 0; i < BT_MESH_PSA_KEY_ID_RANGE_SIZE; i++) { if (!atomic_test_bit(pst_keys, i)) { atomic_set_bit(pst_keys, i); - return BT_MESH_PSA_KEY_ID_USER_MIN + i; + return BT_MESH_PSA_KEY_ID_MIN + i; } } @@ -366,9 +367,9 @@ __weak psa_key_id_t bt_mesh_user_keyid_alloc(void) __weak int bt_mesh_user_keyid_free(psa_key_id_t key_id) { - if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_USER_MIN, - BT_MESH_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) { - atomic_clear_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_USER_MIN); + if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_MIN, + BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE - 1)) { + atomic_clear_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_MIN); return 0; } @@ -377,9 +378,9 @@ __weak int bt_mesh_user_keyid_free(psa_key_id_t key_id) __weak void bt_mesh_user_keyid_assign(psa_key_id_t key_id) { - if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_USER_MIN, - BT_MESH_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) { - atomic_set_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_USER_MIN); + if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_MIN, + BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE - 1)) { + atomic_set_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_MIN); } } diff --git a/subsys/net/lib/wifi_credentials/Kconfig b/subsys/net/lib/wifi_credentials/Kconfig index 3cfe87c29f28a..2fc002f00b83a 100644 --- a/subsys/net/lib/wifi_credentials/Kconfig +++ b/subsys/net/lib/wifi_credentials/Kconfig @@ -75,18 +75,6 @@ endif # WIFI_CREDENTIALS_CONNECT_STORED endif # WIFI_CREDENTIALS -if WIFI_CREDENTIALS_BACKEND_PSA - -config WIFI_CREDENTIALS_BACKEND_PSA_OFFSET - int "PSA_KEY_ID range offset" - default 0 - help - The PSA specification mandates to set key identifiers for keys - with persistent lifetime. The users of the PSA API are responsible (WIFI credentials - management is user of PSA API) to provide correct and unique identifiers. - -endif # WIFI_CREDENTIALS_BACKEND_PSA - config WIFI_CREDENTIALS_STATIC bool "Static Wi-Fi network configuration" diff --git a/subsys/net/lib/wifi_credentials/wifi_credentials_backend_psa.c b/subsys/net/lib/wifi_credentials/wifi_credentials_backend_psa.c index bf82ee725775b..7ec3ae1056def 100644 --- a/subsys/net/lib/wifi_credentials/wifi_credentials_backend_psa.c +++ b/subsys/net/lib/wifi_credentials/wifi_credentials_backend_psa.c @@ -6,18 +6,15 @@ #include #include +#include #include "psa/crypto.h" #include "wifi_credentials_internal.h" LOG_MODULE_REGISTER(wifi_credentials_backend, CONFIG_WIFI_CREDENTIALS_LOG_LEVEL); -#define WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN \ - (PSA_KEY_ID_USER_MIN + CONFIG_WIFI_CREDENTIALS_BACKEND_PSA_OFFSET) - -BUILD_ASSERT((WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN + CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES) <= - PSA_KEY_ID_USER_MAX, - "WIFI credentials management PSA key id range exceeds PSA_KEY_ID_USER_MAX."); +BUILD_ASSERT(CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES <= ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_SIZE, + "Wi-Fi credentials management PSA key ID range exceeds officially allocated range."); int wifi_credentials_backend_init(void) { @@ -26,7 +23,7 @@ int wifi_credentials_backend_init(void) for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) { size_t length_read = 0; - size_t key_id = i + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN; + size_t key_id = i + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN; ret = psa_export_key(key_id, buf, ARRAY_SIZE(buf), &length_read); if (ret == PSA_SUCCESS && length_read == ENTRY_MAX_LEN) { @@ -46,7 +43,7 @@ int wifi_credentials_store_entry(size_t idx, const void *buf, size_t buf_len) psa_key_attributes_t key_attributes = {0}; psa_key_id_t key_id; - psa_set_key_id(&key_attributes, idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN); + psa_set_key_id(&key_attributes, idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN); psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_EXPORT); psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); psa_set_key_algorithm(&key_attributes, PSA_ALG_NONE); @@ -67,7 +64,7 @@ int wifi_credentials_store_entry(size_t idx, const void *buf, size_t buf_len) int wifi_credentials_delete_entry(size_t idx) { - psa_status_t ret = psa_destroy_key(idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN); + psa_status_t ret = psa_destroy_key(idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN); if (ret != PSA_SUCCESS) { LOG_ERR("psa_destroy_key failed, err: %d", ret); @@ -80,7 +77,7 @@ int wifi_credentials_delete_entry(size_t idx) int wifi_credentials_load_entry(size_t idx, void *buf, size_t buf_len) { size_t length_read = 0; - size_t key_id = idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN; + size_t key_id = idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN; psa_status_t ret; ret = psa_export_key(key_id, buf, buf_len, &length_read); diff --git a/tests/bsim/bluetooth/mesh/src/distribute_keyid.c b/tests/bsim/bluetooth/mesh/src/distribute_keyid.c index 8bfb0f6ced1d1..54a9a8feae291 100644 --- a/tests/bsim/bluetooth/mesh/src/distribute_keyid.c +++ b/tests/bsim/bluetooth/mesh/src/distribute_keyid.c @@ -6,6 +6,7 @@ #include #include +#include #include "argparse.h" #include "mesh/crypto.h" @@ -22,24 +23,23 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #else #define BT_MESH_CDB_KEY_ID_RANGE_SIZE 0 #endif -#define BT_MESH_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \ - 2 * CONFIG_BT_MESH_APP_KEY_COUNT + 1 + BT_MESH_CDB_KEY_ID_RANGE_SIZE) -#define BT_MESH_PSA_KEY_ID_USER_MIN (PSA_KEY_ID_USER_MIN + \ - CONFIG_BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET) -#define BT_MESH_TEST_PSA_KEY_ID_USER_MIN (BT_MESH_PSA_KEY_ID_USER_MIN + \ - BT_MESH_KEY_ID_RANGE_SIZE * get_device_nbr()) -static ATOMIC_DEFINE(pst_keys, BT_MESH_KEY_ID_RANGE_SIZE); +#define BT_MESH_PSA_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \ + 2 * CONFIG_BT_MESH_APP_KEY_COUNT + 2 + BT_MESH_CDB_KEY_ID_RANGE_SIZE) +#define BT_MESH_TEST_PSA_KEY_ID_MIN (ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_BEGIN + \ + BT_MESH_PSA_KEY_ID_RANGE_SIZE * get_device_nbr()) + +static ATOMIC_DEFINE(pst_keys, BT_MESH_PSA_KEY_ID_RANGE_SIZE); psa_key_id_t bt_mesh_user_keyid_alloc(void) { - for (int i = 0; i < BT_MESH_KEY_ID_RANGE_SIZE; i++) { + for (int i = 0; i < BT_MESH_PSA_KEY_ID_RANGE_SIZE; i++) { if (!atomic_test_bit(pst_keys, i)) { atomic_set_bit(pst_keys, i); - LOG_INF("key id %d is allocated", BT_MESH_TEST_PSA_KEY_ID_USER_MIN + i); + LOG_INF("key id %d is allocated", BT_MESH_TEST_PSA_KEY_ID_MIN + i); - return BT_MESH_TEST_PSA_KEY_ID_USER_MIN + i; + return BT_MESH_TEST_PSA_KEY_ID_MIN + i; } } @@ -48,9 +48,9 @@ psa_key_id_t bt_mesh_user_keyid_alloc(void) int bt_mesh_user_keyid_free(psa_key_id_t key_id) { - if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_USER_MIN, - BT_MESH_TEST_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) { - atomic_clear_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_USER_MIN); + if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_MIN, + BT_MESH_TEST_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE - 1)) { + atomic_clear_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_MIN); LOG_INF("key id %d is freed", key_id); @@ -62,9 +62,9 @@ int bt_mesh_user_keyid_free(psa_key_id_t key_id) void bt_mesh_user_keyid_assign(psa_key_id_t key_id) { - if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_USER_MIN, - BT_MESH_TEST_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) { - atomic_set_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_USER_MIN); + if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_MIN, + BT_MESH_TEST_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE - 1)) { + atomic_set_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_MIN); LOG_INF("key id %d is assigned", key_id); } else { LOG_WRN("key id %d is out of the reserved id range", key_id); diff --git a/tests/net/lib/wifi_credentials_backend_psa/CMakeLists.txt b/tests/net/lib/wifi_credentials_backend_psa/CMakeLists.txt index 6ff95328fff17..15bd547a82d74 100644 --- a/tests/net/lib/wifi_credentials_backend_psa/CMakeLists.txt +++ b/tests/net/lib/wifi_credentials_backend_psa/CMakeLists.txt @@ -27,7 +27,6 @@ target_compile_options(app -DCONFIG_WIFI_CREDENTIALS_MAX_ENTRIES=2 -DCONFIG_WIFI_CREDENTIALS_SAE_PASSWORD_LENGTH=128 -DCONFIG_WIFI_CREDENTIALS_LOG_LEVEL=4 - -DCONFIG_WIFI_CREDENTIALS_BACKEND_PSA_OFFSET=5 ) set_property( diff --git a/tests/net/lib/wifi_credentials_backend_psa/src/main.c b/tests/net/lib/wifi_credentials_backend_psa/src/main.c index f0b2b6804ab06..5e89079e116da 100644 --- a/tests/net/lib/wifi_credentials_backend_psa/src/main.c +++ b/tests/net/lib/wifi_credentials_backend_psa/src/main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -31,9 +32,6 @@ #define BSSID2 NULL #define FLAGS2 0 -#define WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN \ - (PSA_KEY_ID_USER_MIN + CONFIG_WIFI_CREDENTIALS_BACKEND_PSA_OFFSET) - DEFINE_FFF_GLOBALS; K_MUTEX_DEFINE(wifi_credentials_mutex); @@ -83,7 +81,7 @@ psa_status_t custom_psa_export_key(mbedtls_svc_key_id_t key, uint8_t *data, size static void custom_psa_set_key_id(psa_key_attributes_t *attributes, mbedtls_svc_key_id_t key) { - zassert_equal(idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN, key, "Key ID mismatch"); + zassert_equal(idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN, key, "Key ID mismatch"); } void custom_psa_set_key_bits(psa_key_attributes_t *attributes, size_t bits) @@ -175,7 +173,7 @@ ZTEST(wifi_credentials_backend_psa, test_add) ZTEST(wifi_credentials_backend_psa, test_get) { int ret; - psa_key_id_t key_id = idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN; + psa_key_id_t key_id = idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN; uint8_t buf[ENTRY_MAX_LEN]; ret = wifi_credentials_load_entry(idx, buf, ARRAY_SIZE(buf)); @@ -186,7 +184,7 @@ ZTEST(wifi_credentials_backend_psa, test_get) zassert_equal(psa_export_key_fake.arg2_val, ARRAY_SIZE(buf), "Export key arg2 mismatch"); idx++; - key_id = idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN; + key_id = idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN; ret = wifi_credentials_load_entry(idx, buf, ARRAY_SIZE(buf)); @@ -205,7 +203,7 @@ ZTEST(wifi_credentials_backend_psa, test_delete) ret = wifi_credentials_delete_entry(idx); zassert_equal(0, ret, "Delete entry failed"); - zassert_equal(psa_destroy_key_fake.arg0_val, WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN, + zassert_equal(psa_destroy_key_fake.arg0_val, ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN, "Destroy key arg0 mismatch"); idx++; @@ -214,7 +212,7 @@ ZTEST(wifi_credentials_backend_psa, test_delete) zassert_equal(0, ret, "Delete entry failed"); zassert_equal(psa_destroy_key_fake.arg0_val, - idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN, + idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN, "Destroy key arg0 mismatch"); zassert_equal(psa_destroy_key_fake.call_count, 2, "Destroy key call count mismatch"); diff --git a/tests/subsys/secure_storage/psa/crypto/src/main.c b/tests/subsys/secure_storage/psa/crypto/src/main.c index 1a59f0027964a..04a29435cab8b 100644 --- a/tests/subsys/secure_storage/psa/crypto/src/main.c +++ b/tests/subsys/secure_storage/psa/crypto/src/main.c @@ -2,6 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include #include #include @@ -9,7 +10,7 @@ ZTEST_SUITE(secure_storage_psa_crypto, NULL, NULL, NULL, NULL, NULL); -#define ID PSA_KEY_ID_USER_MIN +#define ID ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_BEGIN #define KEY_TYPE PSA_KEY_TYPE_AES #define ALG PSA_ALG_CBC_NO_PADDING #define KEY_BITS 256 From 7b3596faaa8abdd389d3a64da8fe7b2282b4dd94 Mon Sep 17 00:00:00 2001 From: Steven Chang Date: Wed, 25 Dec 2024 10:35:45 +0800 Subject: [PATCH 0091/6055] driver: gpio: ene_kb1200 gpio initial level Change initial level from POST_KERNEL to PRE_LERNEL_1, Config suport voltage and driving flags Signed-off-by: Steven Chang --- drivers/gpio/gpio_ene_kb1200.c | 61 ++++++++++++------- .../zephyr/dt-bindings/gpio/ene-kb1200-gpio.h | 40 ++++++++++++ 2 files changed, 79 insertions(+), 22 deletions(-) create mode 100644 include/zephyr/dt-bindings/gpio/ene-kb1200-gpio.h diff --git a/drivers/gpio/gpio_ene_kb1200.c b/drivers/gpio/gpio_ene_kb1200.c index fb72fd564b099..cc6074374195f 100644 --- a/drivers/gpio/gpio_ene_kb1200.c +++ b/drivers/gpio/gpio_ene_kb1200.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -42,35 +43,51 @@ static int kb1200_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, g const struct gpio_kb1200_config *config = dev->config; WRITE_BIT(config->gpio_regs->GPIOFS, pin, 0); - if ((flags & GPIO_OUTPUT) != 0) { - WRITE_BIT(config->gpio_regs->GPIOIE, pin, 1); - if ((flags & GPIO_SINGLE_ENDED) != 0) { + /* ene specific flags. low voltage mode,input voltage threshold (ViH & ViL) support 1.8V */ + if (flags & KB1200_GPIO_VOLTAGE_POS) { + WRITE_BIT(config->gpio_regs->GPIOLV, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIOLV, pin, 0); + } + /* ene specific flags. max current driving ability, max support 16 mA */ + if (flags & KB1200_GPIO_DRIVING_16MA) { + WRITE_BIT(config->gpio_regs->GPIODC, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIODC, pin, 0); + } + /* pull-up function */ + if (flags & GPIO_PULL_UP) { + WRITE_BIT(config->gpio_regs->GPIOPU, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIOPU, pin, 0); + } + /* output data high/low */ + if (flags & GPIO_OUTPUT_INIT_HIGH) { + WRITE_BIT(config->gpio_regs->GPIOD, pin, 1); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + WRITE_BIT(config->gpio_regs->GPIOD, pin, 0); + } + /* output enable function */ + if (flags & GPIO_OUTPUT) { + /* setting open-drain only when output is enabled */ + /* output type push-pull/open-drain */ + if (flags & GPIO_SINGLE_ENDED) { if (flags & GPIO_LINE_OPEN_DRAIN) { WRITE_BIT(config->gpio_regs->GPIOOD, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIOOD, pin, 0); } } else { WRITE_BIT(config->gpio_regs->GPIOOD, pin, 0); } - if (flags & GPIO_PULL_UP) { - WRITE_BIT(config->gpio_regs->GPIOPU, pin, 1); - } else { - WRITE_BIT(config->gpio_regs->GPIOPU, pin, 0); - } - if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { - WRITE_BIT(config->gpio_regs->GPIOD, pin, 1); - } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { - WRITE_BIT(config->gpio_regs->GPIOD, pin, 0); - } WRITE_BIT(config->gpio_regs->GPIOOE, pin, 1); } else { WRITE_BIT(config->gpio_regs->GPIOOE, pin, 0); - if (flags & GPIO_PULL_UP) { - WRITE_BIT(config->gpio_regs->GPIOPU, pin, 1); - } else { - WRITE_BIT(config->gpio_regs->GPIOPU, pin, 0); - } - WRITE_BIT(config->gpio_regs->GPIOIE, pin, 1); + /* disable open-drain when output is disabled */ + WRITE_BIT(config->gpio_regs->GPIOOD, pin, 0); } + /* input function always enable */ + WRITE_BIT(config->gpio_regs->GPIOIE, pin, 1); return 0; } @@ -203,8 +220,8 @@ static DEVICE_API(gpio, kb1200_gpio_api) = { .gptd_regs = (struct gptd_regs *)DT_INST_REG_ADDR_BY_IDX(n, 1), \ }; \ static struct gpio_kb1200_data gpio_kb1200_##n##_data; \ - DEVICE_DT_INST_DEFINE(n, &kb1200_gpio_##n##_init, NULL, &gpio_kb1200_##n##_data, \ - &port_##n##_kb1200_config, POST_KERNEL, \ - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &kb1200_gpio_api); + DEVICE_DT_INST_DEFINE(n, kb1200_gpio_##n##_init, NULL, &gpio_kb1200_##n##_data, \ + &port_##n##_kb1200_config, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &kb1200_gpio_api); DT_INST_FOREACH_STATUS_OKAY(KB1200_GPIO_INIT) diff --git a/include/zephyr/dt-bindings/gpio/ene-kb1200-gpio.h b/include/zephyr/dt-bindings/gpio/ene-kb1200-gpio.h new file mode 100644 index 0000000000000..f6ca127081fa5 --- /dev/null +++ b/include/zephyr/dt-bindings/gpio/ene-kb1200-gpio.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 ENE Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_ENE_KB1200_GPIO_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_ENE_KB1200_GPIO_H_ + +/** + * @name GPIO pin voltage flags + * + * The voltage and driving flags are a Zephyr specific extension of the standard GPIO flags + * specified by the Linux GPIO binding for use with the ENE KB1200 SoC. + * + * @{ + * Note: Bits 15 down to 8 are reserved for SoC specific flags. + */ + +/** @cond INTERNAL_HIDDEN */ +#define KB1200_GPIO_VOLTAGE_POS 8 +#define KB1200_GPIO_VOLTAGE_MASK (1U << KB1200_GPIO_VOLTAGE_POS) + +#define KB1200_GPIO_DRIVING_POS 9 +#define KB1200_GPIO_DRIVING_MASK (1U << KB1200_GPIO_DRIVING_POS) +/** @endcond */ + +/** Set pin at the default voltage level (3.3V) */ +#define KB1200_GPIO_VOLTAGE_DEFAULT (0U << KB1200_GPIO_VOLTAGE_POS) +/** Set pin voltage level at 1.8 V */ +#define KB1200_GPIO_VOLTAGE_1P8 (1U << KB1200_GPIO_VOLTAGE_POS) + +/** Set pin at the default driving current (4mA) */ +#define KB1200_GPIO_DRIVING_DEFAULT (0U << KB1200_GPIO_DRIVING_POS) +/** Set pin driving current at 16mA */ +#define KB1200_GPIO_DRIVING_16MA (1U << KB1200_GPIO_DRIVING_POS) + + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_ENE_KB1200_GPIO_H_ */ From fff407d2f608af27c97267722fbb157259ed07c1 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Sun, 22 Dec 2024 21:28:38 +0800 Subject: [PATCH 0092/6055] dts: arm: nxp: add adc instances for RT700 RT700 CM33_CPU0/CPU1 both can access the lpadc0 instance Signed-off-by: Lucien Zhao --- dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi | 17 +++++++++++++++++ dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi index b65fbf55e1cea..614c946684161 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -107,6 +108,22 @@ * and secure modes (0x50000000). */ + lpadc0: adc@20c000 { + compatible = "nxp,lpc-lpadc"; + reg = <0x20c000 0x304>; + interrupts = <15 0>; + status = "disabled"; + clk-divider = <1>; + clk-source = <0>; + voltage-ref= <1>; + calibration-average = <128>; + power-level = <0>; + offset-value-a = <10>; + offset-value-b = <10>; + #io-channel-cells = <1>; + clocks = <&clkctl3 MCUX_LPADC1_CLK>; + }; + rstctl0: reset@0 { compatible = "nxp,rstctl"; reg = <0x0 0x1000>; diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi index 2142670365494..1088538099372 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -90,6 +91,22 @@ * and secure modes (0x50000000). */ + lpadc0: adc@20c000 { + compatible = "nxp,lpc-lpadc"; + reg = <0x20c000 0x304>; + interrupts = <15 0>; + status = "disabled"; + clk-divider = <1>; + clk-source = <0>; + voltage-ref= <1>; + calibration-average = <128>; + power-level = <0>; + offset-value-a = <10>; + offset-value-b = <10>; + #io-channel-cells = <1>; + clocks = <&clkctl3 MCUX_LPADC1_CLK>; + }; + rstctl1: reset@40000 { compatible = "nxp,rstctl"; reg = <0x40000 0x1000>; From a2c4f874c5b6c0ef334240d1c21ba1682e1f6738 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Sun, 22 Dec 2024 21:30:14 +0800 Subject: [PATCH 0093/6055] boards: nxp: mimxrt700_evk: add lpadc0 support add lpadc0 channel 0/1 pin configuration set lpadc0 status as ok for cm33_cpu0/1 Signed-off-by: Lucien Zhao --- boards/nxp/mimxrt700_evk/board.c | 6 ++++++ boards/nxp/mimxrt700_evk/doc/index.rst | 2 ++ boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi | 10 ++++++++++ .../mimxrt700_evk_mimxrt798s_cm33_cpu0.dts | 6 ++++++ .../mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml | 1 + .../mimxrt700_evk_mimxrt798s_cm33_cpu1.dts | 6 ++++++ .../mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml | 1 + 7 files changed, 32 insertions(+) diff --git a/boards/nxp/mimxrt700_evk/board.c b/boards/nxp/mimxrt700_evk/board.c index 2e9609dfd6e35..49e49083abb7d 100644 --- a/boards/nxp/mimxrt700_evk/board.c +++ b/boards/nxp/mimxrt700_evk/board.c @@ -394,6 +394,12 @@ void board_early_init_hook(void) #if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer7), okay) SET_UP_CTIMER_CLOCK(7); #endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpadc0), okay) + CLOCK_AttachClk(kFRO1_DIV1_to_SENSE_MAIN); + CLOCK_AttachClk(kSENSE_BASE_to_ADC); + CLOCK_SetClkDiv(kCLOCK_DivAdcClk, 1U); +#endif } static void GlikeyWriteEnable(GLIKEY_Type *base, uint8_t idx) diff --git a/boards/nxp/mimxrt700_evk/doc/index.rst b/boards/nxp/mimxrt700_evk/doc/index.rst index 4d0235df93276..467ff3c87d841 100644 --- a/boards/nxp/mimxrt700_evk/doc/index.rst +++ b/boards/nxp/mimxrt700_evk/doc/index.rst @@ -79,6 +79,8 @@ the hardware features below. +-----------+------------+-------------------------------------+ | MRT | on-chip | counter | +-----------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi b/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi index b056ee4ce0e2d..ccf13860d3d5c 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi @@ -65,4 +65,14 @@ slew-rate = "slow"; }; }; + + pinmux_lpadc0: pinmux_lpadc0 { + group0 { + pinmux = , + ; + slew-rate = "normal"; + drive-strength = "normal"; + nxp,analog-mode; + }; + }; }; diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts index ff01df4cd61f6..cf079cfc343e7 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts @@ -111,6 +111,12 @@ status = "okay"; }; +&lpadc0 { + status = "okay"; + pinctrl-0 = <&pinmux_lpadc0>; + pinctrl-names = "default"; +}; + &blue_led { status = "okay"; }; diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml index bde30fefb28f7..74f4140992ee3 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml @@ -19,4 +19,5 @@ supported: - i2c - uart - spi + - adc vendor: nxp diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts index dba2f9d889ba2..7486247bb0045 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts @@ -50,6 +50,12 @@ status = "okay"; }; +&lpadc0 { + status = "okay"; + pinctrl-0 = <&pinmux_lpadc0>; + pinctrl-names = "default"; +}; + &systick { status = "okay"; }; diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml index cfc78e3a57f7f..38c45ae9027ed 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml @@ -17,4 +17,5 @@ supported: - counter - gpio - uart + - adc vendor: nxp From 7ac0496741a2260d1e84ee8c1d7240af04248d3e Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Sun, 22 Dec 2024 21:31:17 +0800 Subject: [PATCH 0094/6055] tests: driver: adc: support adc_api case for mimxrt700_evk support lpadc0 channel0/1 on cm33_cpu0/1 cores test passed on adc_api case Signed-off-by: Lucien Zhao --- ...mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay | 36 +++++++++++++++++++ ...mimxrt700_evk_mimxrt798s_cm33_cpu1.overlay | 36 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay create mode 100644 tests/drivers/adc/adc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu1.overlay diff --git a/tests/drivers/adc/adc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay b/tests/drivers/adc/adc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay new file mode 100644 index 0000000000000..34514a08b0f00 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2025 NXP + */ + +#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_EXTERNAL0"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu1.overlay b/tests/drivers/adc/adc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu1.overlay new file mode 100644 index 0000000000000..34514a08b0f00 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/mimxrt700_evk_mimxrt798s_cm33_cpu1.overlay @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2025 NXP + */ + +#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_EXTERNAL0"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; From d88575b5f889343a9c0dbfcd348a85bde066642f Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Thu, 30 Jan 2025 06:32:59 +0000 Subject: [PATCH 0095/6055] arch: arm: cortex_a_r: move exit_exc from vector_table.S to exc.S It makes more sense to keep the exit_exc code close to the exc code. Signed-off-by: Wilfried Chauveau --- arch/arm/core/cortex_a_r/exc.S | 22 ++++++++++++++++++++++ arch/arm/core/cortex_a_r/vector_table.S | 24 ------------------------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/arch/arm/core/cortex_a_r/exc.S b/arch/arm/core/cortex_a_r/exc.S index 78414fcd0a193..ecf7bab57f091 100644 --- a/arch/arm/core/cortex_a_r/exc.S +++ b/arch/arm/core/cortex_a_r/exc.S @@ -237,6 +237,28 @@ SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_data_abort) b z_arm_exc_exit #else + +GTEXT(z_arm_cortex_ar_exit_exc) +SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_cortex_ar_exit_exc) + + /* Note: + * This function is expected to be *always* called with + * processor mode set to MODE_SYS. + */ + + /* decrement exception depth */ + get_cpu r2 + ldrb r1, [r2, #_cpu_offset_to_exc_depth] + sub r1, r1, #1 + strb r1, [r2, #_cpu_offset_to_exc_depth] + + /* + * Restore r0-r3, r12, lr, lr_und and spsr_und from the exception stack + * and return to the current thread. + */ + pop {r0-r3, r12, lr} + rfeia sp! + /** * @brief Undefined instruction exception handler * diff --git a/arch/arm/core/cortex_a_r/vector_table.S b/arch/arm/core/cortex_a_r/vector_table.S index e74b6a41c8d6b..d5d95272548fd 100644 --- a/arch/arm/core/cortex_a_r/vector_table.S +++ b/arch/arm/core/cortex_a_r/vector_table.S @@ -35,27 +35,3 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table) #else ldr pc,=z_irq_spurious #endif - - -#ifdef CONFIG_USE_SWITCH -GTEXT(z_arm_cortex_ar_exit_exc) -SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_cortex_ar_exit_exc) - - /* Note: - * This function is expected to be *always* called with - * processor mode set to MODE_SYS. - */ - - /* decrement exception depth */ - get_cpu r2 - ldrb r1, [r2, #_cpu_offset_to_exc_depth] - sub r1, r1, #1 - strb r1, [r2, #_cpu_offset_to_exc_depth] - - /* - * Restore r0-r3, r12, lr, lr_und and spsr_und from the exception stack - * and return to the current thread. - */ - pop {r0-r3, r12, lr} - rfeia sp! -#endif From 95b74e2b977dac647dc902b326425df9445f7687 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Wed, 5 Feb 2025 15:28:04 +0100 Subject: [PATCH 0096/6055] boards: mimxrt1170_evk: switch the default revision to B Switches the default revision of mimxrt1170_evk from A to B. Customers can only purchase MIMXRT1170-EVKB. Revision "A" is obsolete and unavailable. Signed-off-by: Andrej Butok --- boards/nxp/mimxrt1170_evk/board.yml | 2 +- boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm4.yaml | 2 +- boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7.yaml | 2 +- ...1176_cm7_A.overlay => mimxrt1170_evk_mimxrt1176_cm7.overlay} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename tests/drivers/dma/chan_link_transfer/boards/{mimxrt1170_evk_mimxrt1176_cm7_A.overlay => mimxrt1170_evk_mimxrt1176_cm7.overlay} (100%) diff --git a/boards/nxp/mimxrt1170_evk/board.yml b/boards/nxp/mimxrt1170_evk/board.yml index 4a6a25318b01e..fce50aef20b3a 100644 --- a/boards/nxp/mimxrt1170_evk/board.yml +++ b/boards/nxp/mimxrt1170_evk/board.yml @@ -6,7 +6,7 @@ board: - name: mimxrt1176 revision: format: "letter" - default: "A" + default: "B" revisions: - name: "A" - name: "B" diff --git a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm4.yaml b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm4.yaml index 4d9cee2f0d331..dd213e258bfff 100644 --- a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm4.yaml +++ b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm4.yaml @@ -4,7 +4,7 @@ # SPDX-License-Identifier: Apache-2.0 # -identifier: mimxrt1170_evk/mimxrt1176/cm4 +identifier: mimxrt1170_evk@A/mimxrt1176/cm4 name: NXP MIMXRT1170-EVK CM4 type: mcu arch: arm diff --git a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7.yaml b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7.yaml index 409b60732a253..976b0e71f124d 100644 --- a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7.yaml +++ b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7.yaml @@ -4,7 +4,7 @@ # SPDX-License-Identifier: Apache-2.0 # -identifier: mimxrt1170_evk/mimxrt1176/cm7 +identifier: mimxrt1170_evk@A/mimxrt1176/cm7 name: NXP MIMXRT1170-EVK CM7 type: mcu arch: arm diff --git a/tests/drivers/dma/chan_link_transfer/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay b/tests/drivers/dma/chan_link_transfer/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay similarity index 100% rename from tests/drivers/dma/chan_link_transfer/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay rename to tests/drivers/dma/chan_link_transfer/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay From 5c2c354f7357c39ff8aab268ed99d1eef7e86182 Mon Sep 17 00:00:00 2001 From: Emanuele Di Santo Date: Thu, 6 Feb 2025 12:19:22 +0100 Subject: [PATCH 0097/6055] tests: kernel: gen_isr_table: update test for nRF91x1 devices Limit the number of IRQ for all series nRF91 devices, including nRF9161 and nRF9151. Signed-off-by: Emanuele Di Santo --- tests/kernel/gen_isr_table/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/kernel/gen_isr_table/src/main.c b/tests/kernel/gen_isr_table/src/main.c index a7d76b4eafedb..7117ae789fd05 100644 --- a/tests/kernel/gen_isr_table/src/main.c +++ b/tests/kernel/gen_isr_table/src/main.c @@ -76,8 +76,8 @@ extern uint32_t _irq_vector_table[]; * with isr used here, so add a workaround */ #define TEST_NUM_IRQS 105 -#elif defined(CONFIG_SOC_NRF5340_CPUAPP) || defined(CONFIG_SOC_NRF9160) -/* In nRF9160 and application core in nRF5340, not all interrupts with highest +#elif defined(CONFIG_SOC_NRF5340_CPUAPP) || defined(CONFIG_SOC_SERIES_NRF91X) +/* In the application core of nRF5340 and nRF9 series, not all interrupts with highest * numbers are implemented. Thus, limit the number of interrupts reported to * the test, so that it does not try to use some unavailable ones. */ From 85282d604c0ec0988625ed2f3fe7c76473bdbe0b Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Thu, 6 Feb 2025 15:28:10 +0100 Subject: [PATCH 0098/6055] tests: kernel: gen_isr_table: Fix kernel test for nRF FLPR target Fix kernel `gen_isr_table` test for nRF FLPR target similairly to PPR target. Signed-off-by: Adam Kondraciuk --- tests/kernel/gen_isr_table/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/kernel/gen_isr_table/src/main.c b/tests/kernel/gen_isr_table/src/main.c index 7117ae789fd05..f163a9e9c6e64 100644 --- a/tests/kernel/gen_isr_table/src/main.c +++ b/tests/kernel/gen_isr_table/src/main.c @@ -26,7 +26,7 @@ extern uint32_t _irq_vector_table[]; #define ISR3_OFFSET 17 #define ISR5_OFFSET 18 #define TRIG_CHECK_SIZE 19 -#elif defined(CONFIG_SOC_NRF54H20_CPUPPR) +#elif defined(CONFIG_SOC_NRF54H20_CPUPPR) || defined(CONFIG_SOC_NRF54H20_CPUFLPR) #define ISR1_OFFSET 14 #define ISR3_OFFSET 15 #define ISR5_OFFSET 16 From 0399d892e96dbb3f2b7789ae2160ec51c44efec1 Mon Sep 17 00:00:00 2001 From: Furkan Akkiz Date: Thu, 11 Jan 2024 11:05:05 +0300 Subject: [PATCH 0099/6055] tests: drivers: dma: Enable dma driver tests for max32666evkit board Enable dma driver tests for MAX32666EVKIT Signed-off-by: Furkan Akkiz Signed-off-by: Yasin Ustuner Signed-off-by: Maureen Helm --- .../boards/max32666evkit_max32666_cpu0.conf | 4 ++++ .../boards/max32666evkit_max32666_cpu0.overlay | 7 +++++++ .../boards/max32666evkit_max32666_cpu0.overlay | 7 +++++++ 3 files changed, 18 insertions(+) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/max32666evkit_max32666_cpu0.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/max32666evkit_max32666_cpu0.overlay create mode 100644 tests/drivers/dma/loop_transfer/boards/max32666evkit_max32666_cpu0.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/boards/max32666evkit_max32666_cpu0.conf b/tests/drivers/dma/chan_blen_transfer/boards/max32666evkit_max32666_cpu0.conf new file mode 100644 index 0000000000000..a093a1aa63735 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/max32666evkit_max32666_cpu0.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CODE_DATA_RELOCATION=y diff --git a/tests/drivers/dma/chan_blen_transfer/boards/max32666evkit_max32666_cpu0.overlay b/tests/drivers/dma/chan_blen_transfer/boards/max32666evkit_max32666_cpu0.overlay new file mode 100644 index 0000000000000..0e412606f7a07 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/max32666evkit_max32666_cpu0.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &dma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/max32666evkit_max32666_cpu0.overlay b/tests/drivers/dma/loop_transfer/boards/max32666evkit_max32666_cpu0.overlay new file mode 100644 index 0000000000000..0e412606f7a07 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/max32666evkit_max32666_cpu0.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &dma0 { }; From 540b3543f45d31146136dbf1f2f3e25fda268651 Mon Sep 17 00:00:00 2001 From: Mert Ekren Date: Fri, 29 Dec 2023 13:48:00 +0300 Subject: [PATCH 0100/6055] tests: drivers: dma: Add MAX32666FTHR Enable DMA test for MAX32666FTHR board for tests chan_blen_transfer and loop transfer Signed-off-by: Mert Ekren Signed-off-by: Yasin Ustuner Signed-off-by: Maureen Helm --- .../boards/max32666fthr_max32666_cpu0.conf | 4 ++++ .../boards/max32666fthr_max32666_cpu0.overlay | 7 +++++++ .../boards/max32666fthr_max32666_cpu0.overlay | 7 +++++++ 3 files changed, 18 insertions(+) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/max32666fthr_max32666_cpu0.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/max32666fthr_max32666_cpu0.overlay create mode 100644 tests/drivers/dma/loop_transfer/boards/max32666fthr_max32666_cpu0.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/boards/max32666fthr_max32666_cpu0.conf b/tests/drivers/dma/chan_blen_transfer/boards/max32666fthr_max32666_cpu0.conf new file mode 100644 index 0000000000000..a093a1aa63735 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/max32666fthr_max32666_cpu0.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CODE_DATA_RELOCATION=y diff --git a/tests/drivers/dma/chan_blen_transfer/boards/max32666fthr_max32666_cpu0.overlay b/tests/drivers/dma/chan_blen_transfer/boards/max32666fthr_max32666_cpu0.overlay new file mode 100644 index 0000000000000..0e412606f7a07 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/max32666fthr_max32666_cpu0.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &dma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/max32666fthr_max32666_cpu0.overlay b/tests/drivers/dma/loop_transfer/boards/max32666fthr_max32666_cpu0.overlay new file mode 100644 index 0000000000000..0e412606f7a07 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/max32666fthr_max32666_cpu0.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &dma0 { }; From d256a90a549c82ed46f0a818e28ebc622d3b3064 Mon Sep 17 00:00:00 2001 From: Furkan Akkiz Date: Wed, 17 Jan 2024 14:48:43 +0300 Subject: [PATCH 0101/6055] tests: drivers: dma: Enable dma driver tests for max32662evkit board Enable 'chan_blen_transfer' and 'loop_transfer' tests for MAX32662EVKIT. Signed-off-by: Furkan Akkiz --- .../boards/max32662evkit.conf | 4 ++++ .../boards/max32662evkit.overlay | 7 +++++++ .../loop_transfer/boards/max32662evkit.overlay | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/max32662evkit.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/max32662evkit.overlay create mode 100644 tests/drivers/dma/loop_transfer/boards/max32662evkit.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/boards/max32662evkit.conf b/tests/drivers/dma/chan_blen_transfer/boards/max32662evkit.conf new file mode 100644 index 0000000000000..a093a1aa63735 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/max32662evkit.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CODE_DATA_RELOCATION=y diff --git a/tests/drivers/dma/chan_blen_transfer/boards/max32662evkit.overlay b/tests/drivers/dma/chan_blen_transfer/boards/max32662evkit.overlay new file mode 100644 index 0000000000000..0e412606f7a07 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/max32662evkit.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +tst_dma0: &dma0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/max32662evkit.overlay b/tests/drivers/dma/loop_transfer/boards/max32662evkit.overlay new file mode 100644 index 0000000000000..8c711035a3153 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/max32662evkit.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&sram0 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(64)>; +}; + +/ { + chosen { + zephyr,sram = &sram0; + }; +}; + +tst_dma0: &dma0 { }; From 4bd4528adacd983f291605f896c489c04e2c9301 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 30 May 2024 12:12:19 -0500 Subject: [PATCH 0102/6055] soc: ti: k3: am6x: m4: Enable FPU support for M4F cores The M4 cores found in TI AM6x SoCs have FPUs, enable this in the default configuration. Signed-off-by: Andrew Davis --- soc/ti/k3/am6x/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/soc/ti/k3/am6x/Kconfig b/soc/ti/k3/am6x/Kconfig index a28996cc30589..0e8f107697ac0 100644 --- a/soc/ti/k3/am6x/Kconfig +++ b/soc/ti/k3/am6x/Kconfig @@ -9,6 +9,7 @@ config SOC_SERIES_AM6X_A53 config SOC_SERIES_AM6X_M4 select ARM select CPU_CORTEX_M4 + select CPU_HAS_FPU select CPU_CORTEX_M_HAS_SYSTICK select DYNAMIC_INTERRUPTS select CPU_CORTEX_M_HAS_DWT From 846b4687154af5f57ba5a32610ec868d5f4ae61d Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 13 Feb 2025 13:56:59 +0100 Subject: [PATCH 0103/6055] samples: drivers: i2c: rtio_loopback: add fixture Add i2c_bus_short fixture to the rtio_loopback sample to ensure it is only run on boards with the bus shorted. The i2c_bus_short fixture is also used in the i2c_target_api test suite. Signed-off-by: Bjarki Arge Andreasen --- samples/drivers/i2c/rtio_loopback/sample.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/drivers/i2c/rtio_loopback/sample.yaml b/samples/drivers/i2c/rtio_loopback/sample.yaml index e7d5563f5b1b2..4234c090c67e2 100644 --- a/samples/drivers/i2c/rtio_loopback/sample.yaml +++ b/samples/drivers/i2c/rtio_loopback/sample.yaml @@ -5,6 +5,9 @@ tests: tags: - rtio - i2c_target + harness: ztest + harness_config: + fixture: i2c_bus_short platform_allow: - b_u585i_iot02a - nrf5340dk/nrf5340/cpuapp From e9ea97e92d2943655f3f838c313ec7569319ecde Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Thu, 13 Feb 2025 10:27:50 -0800 Subject: [PATCH 0104/6055] drivers: i3c: add synopsys designware i3c driver Add synopsys designware i3c driver Signed-off-by: Ryan McClelland --- drivers/i3c/CMakeLists.txt | 5 + drivers/i3c/Kconfig | 1 + drivers/i3c/Kconfig.dw | 16 + drivers/i3c/i3c_common.c | 18 + drivers/i3c/i3c_dw.c | 2376 +++++++++++++++++++++ dts/bindings/i3c/snps,designware-i3c.yaml | 30 + include/zephyr/drivers/i3c.h | 15 + 7 files changed, 2461 insertions(+) create mode 100644 drivers/i3c/Kconfig.dw create mode 100644 drivers/i3c/i3c_dw.c create mode 100644 dts/bindings/i3c/snps,designware-i3c.yaml diff --git a/drivers/i3c/CMakeLists.txt b/drivers/i3c/CMakeLists.txt index 9a597952dcd6d..4b916a8c48011 100644 --- a/drivers/i3c/CMakeLists.txt +++ b/drivers/i3c/CMakeLists.txt @@ -54,6 +54,11 @@ zephyr_library_sources_ifdef( i3c_stm32.c ) +zephyr_library_sources_ifdef( + CONFIG_I3C_DW + i3c_dw.c +) + zephyr_library_sources_ifdef( CONFIG_I3C_TEST i3c_test.c diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig index 0f84acda8b795..3bf69e2eaa6fc 100644 --- a/drivers/i3c/Kconfig +++ b/drivers/i3c/Kconfig @@ -182,6 +182,7 @@ comment "Device Drivers" rsource "Kconfig.nxp" rsource "Kconfig.cdns" rsource "Kconfig.npcx" +rsource "Kconfig.dw" rsource "Kconfig.test" rsource "Kconfig.stm32" diff --git a/drivers/i3c/Kconfig.dw b/drivers/i3c/Kconfig.dw new file mode 100644 index 0000000000000..6dbfceba16112 --- /dev/null +++ b/drivers/i3c/Kconfig.dw @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Meta Platforms, Inc. and its affiliates. +# +# SPDX-License-Identifier: Apache-2.0 + +module = I3C_DW +module-str = i3c-dw +source "subsys/logging/Kconfig.template.log_config" + +config I3C_DW + bool "DW I3C support" + select I3C_IBI_WORKQUEUE if I3C_USE_IBI + depends on DT_HAS_SNPS_DESIGNWARE_I3C_ENABLED + depends on CLOCK_CONTROL + default y + help + Enable the Synopsys Designware I3C driver diff --git a/drivers/i3c/i3c_common.c b/drivers/i3c/i3c_common.c index 8a5b1234e4ffc..70b7ebdf9d4ff 100644 --- a/drivers/i3c/i3c_common.c +++ b/drivers/i3c/i3c_common.c @@ -216,6 +216,24 @@ struct i3c_device_desc *i3c_dev_list_i3c_addr_find(const struct device *dev, return ret; } +struct i3c_device_desc *i3c_dev_list_i3c_static_addr_find(const struct device *dev, + uint8_t addr) +{ + struct i3c_device_desc *ret = NULL; + struct i3c_device_desc *desc; + + __ASSERT_NO_MSG(dev != NULL); + + I3C_BUS_FOR_EACH_I3CDEV(dev, desc) { + if (desc->static_addr == addr) { + ret = desc; + break; + } + } + + return ret; +} + struct i3c_i2c_device_desc *i3c_dev_list_i2c_addr_find(const struct device *dev, uint16_t addr) { diff --git a/drivers/i3c/i3c_dw.c b/drivers/i3c/i3c_dw.c new file mode 100644 index 0000000000000..25168e9dd4f3b --- /dev/null +++ b/drivers/i3c/i3c_dw.c @@ -0,0 +1,2376 @@ +/* + * Copyright (C) 2020 Samsung Electronics Co., Ltd. + * Copyright (C) 2023 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define NANO_SEC 1000000000ULL +#define BYTES_PER_DWORD 4 + +LOG_MODULE_REGISTER(i3c_dw, CONFIG_I3C_DW_LOG_LEVEL); + +#define DEVICE_CTRL 0x0 +#define DEV_CTRL_ENABLE BIT(31) +#define DEV_CTRL_RESUME BIT(30) +#define DEV_CTRL_HOT_JOIN_NACK BIT(8) +#define DEV_CTRL_I2C_SLAVE_PRESENT BIT(7) +#define DEV_CTRL_IBA_INCLUDE BIT(0) + +#define DEVICE_ADDR 0x4 +#define DEVICE_ADDR_DYNAMIC_ADDR_VALID BIT(31) +#define DEVICE_ADDR_DYNAMIC(x) (((x) << 16) & GENMASK(22, 16)) +#define DEVICE_ADDR_STATIC_ADDR_VALID BIT(15) +#define DEVICE_ADDR_STATIC_MASK GENMASK(6, 0) +#define DEVICE_ADDR_STATIC(x) ((x) & DEVICE_ADDR_STATIC_MASK) + +#define HW_CAPABILITY 0x8 +#define HW_CAPABILITY_SLV_IBI_CAP BIT(19) +#define HW_CAPABILITY_SLV_HJ_CAP BIT(18) +#define HW_CAPABILITY_HDR_TS_EN BIT(4) +#define HW_CAPABILITY_HDR_DDR_EN BIT(3) +#define HW_CAPABILITY_DEVICE_ROLE_CONFIG_MASK GENMASK(2, 0) + +#define COMMAND_QUEUE_PORT 0xc +#define COMMAND_PORT_TOC BIT(30) +#define COMMAND_PORT_READ_TRANSFER BIT(28) +#define COMMAND_PORT_SDAP BIT(27) +#define COMMAND_PORT_ROC BIT(26) +#define COMMAND_PORT_DBP BIT(25) +#define COMMAND_PORT_SPEED(x) (((x) << 21) & GENMASK(23, 21)) +#define COMMAND_PORT_SPEED_I2C_FM 0 +#define COMMAND_PORT_SPEED_I2C_FMP 1 +#define COMMAND_PORT_SPEED_I3C_DDR 6 +#define COMMAND_PORT_SPEED_I3C_TS 7 +#define COMMAND_PORT_DEV_INDEX(x) (((x) << 16) & GENMASK(20, 16)) +#define COMMAND_PORT_CP BIT(15) +#define COMMAND_PORT_CMD(x) (((x) << 7) & GENMASK(14, 7)) +#define COMMAND_PORT_TID(x) (((x) << 3) & GENMASK(6, 3)) + +#define COMMAND_PORT_ARG_DATA_LEN(x) (((x) << 16) & GENMASK(31, 16)) +#define COMMAND_PORT_ARG_DB(x) (((x) << 8) & GENMASK(15, 8)) +#define COMMAND_PORT_ARG_DATA_LEN_MAX 65536 +#define COMMAND_PORT_TRANSFER_ARG 0x01 + +#define COMMAND_PORT_SDA_DATA_BYTE_3(x) (((x) << 24) & GENMASK(31, 24)) +#define COMMAND_PORT_SDA_DATA_BYTE_2(x) (((x) << 16) & GENMASK(23, 16)) +#define COMMAND_PORT_SDA_DATA_BYTE_1(x) (((x) << 8) & GENMASK(15, 8)) +#define COMMAND_PORT_SDA_BYTE_STRB_3 BIT(5) +#define COMMAND_PORT_SDA_BYTE_STRB_2 BIT(4) +#define COMMAND_PORT_SDA_BYTE_STRB_1 BIT(3) +#define COMMAND_PORT_SHORT_DATA_ARG 0x02 + +#define COMMAND_PORT_DEV_COUNT(x) (((x) << 21) & GENMASK(25, 21)) +#define COMMAND_PORT_ADDR_ASSGN_CMD 0x03 + +#define RESPONSE_QUEUE_PORT 0x10 +#define RESPONSE_PORT_ERR_STATUS(x) (((x) & GENMASK(31, 28)) >> 28) +#define RESPONSE_NO_ERROR 0 +#define RESPONSE_ERROR_CRC 1 +#define RESPONSE_ERROR_PARITY 2 +#define RESPONSE_ERROR_FRAME 3 +#define RESPONSE_ERROR_IBA_NACK 4 +#define RESPONSE_ERROR_ADDRESS_NACK 5 +#define RESPONSE_ERROR_OVER_UNDER_FLOW 6 +#define RESPONSE_ERROR_TRANSF_ABORT 8 +#define RESPONSE_ERROR_I2C_W_NACK_ERR 9 +#define RESPONSE_PORT_TID(x) (((x) & GENMASK(27, 24)) >> 24) +#define RESPONSE_PORT_DATA_LEN(x) ((x) & GENMASK(15, 0)) + +#define RX_TX_DATA_PORT 0x14 +#define IBI_QUEUE_STATUS 0x18 +#define IBI_QUEUE_STATUS_IBI_STS(x) (((x) & GENMASK(31, 28)) >> 28) +#define IBI_QUEUE_STATUS_IBI_ID(x) (((x) & GENMASK(15, 8)) >> 8) +#define IBI_QUEUE_STATUS_DATA_LEN(x) ((x) & GENMASK(7, 0)) +#define IBI_QUEUE_IBI_ADDR(x) (IBI_QUEUE_STATUS_IBI_ID(x) >> 1) +#define IBI_QUEUE_IBI_RNW(x) (IBI_QUEUE_STATUS_IBI_ID(x) & BIT(0)) +#define IBI_TYPE_MR(x) \ + ((IBI_QUEUE_IBI_ADDR(x) != I3C_HOT_JOIN_ADDR) && !IBI_QUEUE_IBI_RNW(x)) +#define IBI_TYPE_HJ(x) \ + ((IBI_QUEUE_IBI_ADDR(x) == I3C_HOT_JOIN_ADDR) && !IBI_QUEUE_IBI_RNW(x)) +#define IBI_TYPE_SIRQ(x) \ + ((IBI_QUEUE_IBI_ADDR(x) != I3C_HOT_JOIN_ADDR) && IBI_QUEUE_IBI_RNW(x)) + +#define QUEUE_THLD_CTRL 0x1c +#define QUEUE_THLD_CTRL_IBI_STS_MASK GENMASK(31, 24) +#define QUEUE_THLD_CTRL_RESP_BUF_MASK GENMASK(15, 8) +#define QUEUE_THLD_CTRL_RESP_BUF(x) (((x) - 1) << 8) + +#define DATA_BUFFER_THLD_CTRL 0x20 +#define DATA_BUFFER_THLD_CTRL_RX_BUF GENMASK(11, 8) + +#define IBI_QUEUE_CTRL 0x24 +#define IBI_MR_REQ_REJECT 0x2C +#define IBI_SIR_REQ_REJECT 0x30 +#define IBI_SIR_REQ_ID(x) ((((x) & GENMASK(6, 5)) >> 5) + ((x) & GENMASK(4, 0))) +#define IBI_REQ_REJECT_ALL GENMASK(31, 0) + +#define RESET_CTRL 0x34 +#define RESET_CTRL_IBI_QUEUE BIT(5) +#define RESET_CTRL_RX_FIFO BIT(4) +#define RESET_CTRL_TX_FIFO BIT(3) +#define RESET_CTRL_RESP_QUEUE BIT(2) +#define RESET_CTRL_CMD_QUEUE BIT(1) +#define RESET_CTRL_SOFT BIT(0) +#define RESET_CTRL_ALL \ + (RESET_CTRL_IBI_QUEUE | RESET_CTRL_RX_FIFO | RESET_CTRL_TX_FIFO | RESET_CTRL_RESP_QUEUE | \ + RESET_CTRL_CMD_QUEUE | RESET_CTRL_SOFT) + +#define SLV_EVENT_STATUS 0x38 +#define SLV_EVENT_STATUS_HJ_EN BIT(3) +#define SLV_EVENT_STATUS_MR_EN BIT(1) +#define SLV_EVENT_STATUS_SIR_EN BIT(0) + +#define INTR_STATUS 0x3c +#define INTR_STATUS_EN 0x40 +#define INTR_SIGNAL_EN 0x44 +#define INTR_FORCE 0x48 +#define INTR_BUSOWNER_UPDATE_STAT BIT(13) +#define INTR_IBI_UPDATED_STAT BIT(12) +#define INTR_READ_REQ_RECV_STAT BIT(11) +#define INTR_DEFSLV_STAT BIT(10) +#define INTR_TRANSFER_ERR_STAT BIT(9) +#define INTR_DYN_ADDR_ASSGN_STAT BIT(8) +#define INTR_CCC_UPDATED_STAT BIT(6) +#define INTR_TRANSFER_ABORT_STAT BIT(5) +#define INTR_RESP_READY_STAT BIT(4) +#define INTR_CMD_QUEUE_READY_STAT BIT(3) +#define INTR_IBI_THLD_STAT BIT(2) +#define INTR_RX_THLD_STAT BIT(1) +#define INTR_TX_THLD_STAT BIT(0) +#define INTR_ALL \ + (INTR_BUSOWNER_UPDATE_STAT | INTR_IBI_UPDATED_STAT | INTR_READ_REQ_RECV_STAT | \ + INTR_DEFSLV_STAT | INTR_TRANSFER_ERR_STAT | INTR_DYN_ADDR_ASSGN_STAT | \ + INTR_CCC_UPDATED_STAT | INTR_TRANSFER_ABORT_STAT | INTR_RESP_READY_STAT | \ + INTR_CMD_QUEUE_READY_STAT | INTR_IBI_THLD_STAT | INTR_TX_THLD_STAT | INTR_RX_THLD_STAT) + +#ifdef CONFIG_I3C_USE_IBI +#define INTR_MASTER_MASK (INTR_TRANSFER_ERR_STAT | INTR_RESP_READY_STAT | INTR_IBI_THLD_STAT) +#else +#define INTR_MASTER_MASK (INTR_TRANSFER_ERR_STAT | INTR_RESP_READY_STAT) +#endif +#define INTR_SLAVE_MASK \ + (INTR_TRANSFER_ERR_STAT | INTR_IBI_UPDATED_STAT | INTR_READ_REQ_RECV_STAT | \ + INTR_DYN_ADDR_ASSGN_STAT | INTR_RESP_READY_STAT) + +#define QUEUE_STATUS_LEVEL 0x4c +#define QUEUE_STATUS_IBI_STATUS_CNT(x) (((x) & GENMASK(28, 24)) >> 24) +#define QUEUE_STATUS_IBI_BUF_BLR(x) (((x) & GENMASK(23, 16)) >> 16) +#define QUEUE_STATUS_LEVEL_RESP(x) (((x) & GENMASK(15, 8)) >> 8) +#define QUEUE_STATUS_LEVEL_CMD(x) ((x) & GENMASK(7, 0)) + +#define DATA_BUFFER_STATUS_LEVEL 0x50 +#define DATA_BUFFER_STATUS_LEVEL_RX(x) (((x) & GENMASK(23, 16)) >> 16) +#define DATA_BUFFER_STATUS_LEVEL_TX(x) ((x) & GENMASK(7, 0)) + +#define PRESENT_STATE 0x54 +#define PRESENT_STATE_CURRENT_MASTER BIT(2) + +#define CCC_DEVICE_STATUS 0x58 +#define DEVICE_ADDR_TABLE_POINTER 0x5c +#define DEVICE_ADDR_TABLE_DEPTH(x) (((x) & GENMASK(31, 16)) >> 16) +#define DEVICE_ADDR_TABLE_ADDR(x) ((x) & GENMASK(15, 0)) + +#define DEV_CHAR_TABLE_POINTER 0x60 +#define DEVICE_CHAR_TABLE_ADDR(x) ((x) & GENMASK(11, 0)) +#define VENDOR_SPECIFIC_REG_POINTER 0x6c + +#define SLV_MIPI_ID_VALUE 0x70 +#define SLV_MIPI_ID_VALUE_SLV_MIPI_MFG_ID_MASK GENMASK(15, 1) +#define SLV_MIPI_ID_VALUE_SLV_MIPI_MFG_ID(x) ((x) & SLV_MIPI_ID_VALUE_SLV_MIPI_MFG_ID_MASK) +#define SLV_MIPI_ID_VALUE_SLV_PROV_ID_SEL BIT(0) + +#define SLV_PID_VALUE 0x74 + +#define SLV_CHAR_CTRL 0x78 +#define SLV_CHAR_CTRL_MAX_DATA_SPEED_LIMIT BIT(0) +#define SLV_CHAR_CTRL_IBI_REQUEST_CAPABLE BIT(1) +#define SLV_CHAR_CTRL_IBI_PAYLOAD BIT(2) +#define SLV_CHAR_CTRL_BCR_MASK GENMASK(7, 0) +#define SLV_CHAR_CTRL_BCR(x) ((x) & SLV_CHAR_CTRL_BCR_MASK) +#define SLV_CHAR_CTRL_DCR_MASK GENMASK(15, 8) +#define SLV_CHAR_CTRL_DCR(x) (((x) & SLV_CHAR_CTRL_DCR_MASK) >> 8) +#define SLV_CHAR_CTRL_HDR_CAP_MASK GENMASK(23, 16) +#define SLV_CHAR_CTRL_HDR_CAP(x) (((x) & SLV_CHAR_CTRL_HDR_CAP_MASK) >> 16) + +#define SLV_MAX_LEN 0x7c +#define SLV_MAX_LEN_MRL(x) (((x) & GENMASK(31, 16)) >> 16) +#define SLV_MAX_LEN_MWL(x) ((x) & GENMASK(15, 0)) + +#define MAX_READ_TURNAROUND 0x80 +#define MAX_READ_TURNAROUND_MXDX_MAX_RD_TURN(x) ((x) & GENMASK(23, 0)) + +#define MAX_DATA_SPEED 0x84 +#define SLV_DEBUG_STATUS 0x88 + +#define SLV_INTR_REQ 0x8c +#define SLV_INTR_REQ_SIR_DATA_LENGTH(x) (((x) << 16) & GENMASK(23, 16)) +#define SLV_INTR_REQ_MDB(x) (((x) << 8) & GENMASK(15, 8)) +#define SLV_INTR_REQ_IBI_STS(x) (((x) & GENMASK(9, 8)) >> 8) +#define SLV_INTR_REQ_IBI_STS_IBI_ACCEPT 0x01 +#define SLV_INTR_REQ_IBI_STS_IBI_NO_ATTEMPT 0x03 +#define SLV_INTR_REQ_TS BIT(4) +#define SLV_INTR_REQ_MR BIT(3) +#define SLV_INTR_REQ_SIR_CTRL(x) (((x) & GENMASK(2, 1)) >> 1) +#define SLV_INTR_REQ_SIR BIT(0) + +#define SLV_SIR_DATA 0x94 +#define SLV_SIR_DATA_BYTE3(x) (((x) << 24) & GENMASK(31, 24)) +#define SLV_SIR_DATA_BYTE2(x) (((x) << 16) & GENMASK(23, 16)) +#define SLV_SIR_DATA_BYTE1(x) (((x) << 8) & GENMASK(15, 8)) +#define SLV_SIR_DATA_BYTE0(x) ((x) & GENMASK(7, 0)) + +#define SLV_IBI_RESP 0x98 +#define SLV_IBI_RESP_DATA_LENGTH(x) (((x) & GENMASK(23, 8)) >> 8) +#define SLV_IBI_RESP_IBI_STS(x) ((x) & GENMASK(1, 0)) +#define SLV_IBI_RESP_IBI_STS_ACK 0x01 +#define SLV_IBI_RESP_IBI_STS_EARLY_TERMINATE 0x02 +#define SLV_IBI_RESP_IBI_STS_NACK 0x03 + +#define SLV_NACK_REQ 0x9c +#define SLV_NACK_REQ_NACK_REQ(x) ((x) & GENMASK(1, 0)) +#define SLV_NACK_REQ_NACK_REQ_ACK 0x00 +#define SLV_NACK_REQ_NACK_REQ_NACK 0x01 + +#define DEVICE_CTRL_EXTENDED 0xb0 +#define DEVICE_CTRL_EXTENDED_DEV_OPERATION_MODE(x) ((x) & GENMASK(1, 0)) +#define DEVICE_CTRL_EXTENDED_DEV_OPERATION_MODE_MASTER 0 +#define DEVICE_CTRL_EXTENDED_DEV_OPERATION_MODE_SLAVE 1 + +#define SCL_I3C_OD_TIMING 0xb4 +#define SCL_I3C_PP_TIMING 0xb8 +#define SCL_I3C_TIMING_HCNT(x) (((x) << 16) & GENMASK(23, 16)) +#define SCL_I3C_TIMING_LCNT(x) ((x) & GENMASK(7, 0)) +#define SCL_I3C_TIMING_CNT_MIN 5 +#define SCL_I3C_TIMING_CNT_MAX 255 + +#define SCL_I2C_FM_TIMING 0xbc +#define SCL_I2C_FM_TIMING_HCNT(x) (((x) << 16) & GENMASK(31, 16)) +#define SCL_I2C_FM_TIMING_LCNT(x) ((x) & GENMASK(15, 0)) + +#define SCL_I2C_FMP_TIMING 0xc0 +#define SCL_I2C_FMP_TIMING_HCNT(x) (((x) << 16) & GENMASK(23, 16)) +#define SCL_I2C_FMP_TIMING_LCNT(x) ((x) & GENMASK(15, 0)) + +#define SCL_EXT_LCNT_TIMING 0xc8 +#define SCL_EXT_LCNT_4(x) (((x) << 24) & GENMASK(31, 24)) +#define SCL_EXT_LCNT_3(x) (((x) << 16) & GENMASK(23, 16)) +#define SCL_EXT_LCNT_2(x) (((x) << 8) & GENMASK(15, 8)) +#define SCL_EXT_LCNT_1(x) ((x) & GENMASK(7, 0)) + +#define SCL_EXT_TERMN_LCNT_TIMING 0xcc + +#define SDA_HOLD_SWITCH_DLY_TIMING 0xd0 +#define SDA_HOLD_SWITCH_DLY_TIMING_SDA_TX_HOLD(x) (((x)&GENMASK(18, 16)) >> 16) +#define SDA_HOLD_SWITCH_DLY_TIMING_SDA_PP_OD_SWITCH_DLY(x) (((x)&GENMASK(10, 8)) >> 8) +#define SDA_HOLD_SWITCH_DLY_TIMING_SDA_OD_PP_SWITCH_DLY(x) ((x)&GENMASK(2, 0)) + +#define BUS_FREE_TIMING 0xd4 +/* Bus available time of 1us in ns */ +#define I3C_BUS_AVAILABLE_TIME_NS 1000U +#define BUS_I3C_MST_FREE(x) ((x) & GENMASK(15, 0)) +#define BUS_I3C_AVAIL_TIME(x) ((x << 16) & GENMASK(31, 16)) + +#define BUS_IDLE_TIMING 0xd8 +/* Bus Idle time of 1ms in ns */ +#define I3C_BUS_IDLE_TIME_NS 1000000U +#define BUS_I3C_IDLE_TIME(x) ((x) & GENMASK(19, 0)) + +#define I3C_VER_ID 0xe0 +#define I3C_VER_TYPE 0xe4 +#define EXTENDED_CAPABILITY 0xe8 +#define SLAVE_CONFIG 0xec + +#define QUEUE_SIZE_CAPABILITY 0xe8 +#define QUEUE_SIZE_CAPABILITY_IBI_BUF_DWORD_SIZE(x) (2 << (((x) & GENMASK(19, 16)) >> 16)) +#define QUEUE_SIZE_CAPABILITY_RESP_BUF_DWORD_SIZE(x) (2 << (((x) & GENMASK(15, 12)) >> 12)) +#define QUEUE_SIZE_CAPABILITY_CMD_BUF_DWORD_SIZE(x) (2 << (((x) & GENMASK(11, 8)) >> 8)) +#define QUEUE_SIZE_CAPABILITY_RX_BUF_DWORD_SIZE(x) (2 << (((x) & GENMASK(7, 4)) >> 4)) +#define QUEUE_SIZE_CAPABILITY_TX_BUF_DWORD_SIZE(x) (2 << ((x) & GENMASK(3, 0))) + +#define DEV_ADDR_TABLE_LEGACY_I2C_DEV BIT(31) +#define DEV_ADDR_TABLE_DYNAMIC_ADDR_MASK GENMASK(23, 16) +#define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) (((x) << 16) & GENMASK(23, 16)) +#define DEV_ADDR_TABLE_SIR_REJECT BIT(13) +#define DEV_ADDR_TABLE_IBI_WITH_DATA BIT(12) +#define DEV_ADDR_TABLE_STATIC_ADDR(x) ((x) & GENMASK(6, 0)) +#define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2)) + +#define DEV_CHAR_TABLE_LOC1(start, idx) ((start) + ((idx) << 4)) +#define DEV_CHAR_TABLE_MSB_PID(x) ((x) & GENMASK(31, 16)) +#define DEV_CHAR_TABLE_LSB_PID(x) ((x) & GENMASK(15, 0)) +#define DEV_CHAR_TABLE_LOC2(start, idx) ((DEV_CHAR_TABLE_LOC1(start, idx)) + 4) +#define DEV_CHAR_TABLE_LOC3(start, idx) ((DEV_CHAR_TABLE_LOC1(start, idx)) + 8) +#define DEV_CHAR_TABLE_DCR(x) ((x) & GENMASK(7, 0)) +#define DEV_CHAR_TABLE_BCR(x) (((x) & GENMASK(15, 8)) >> 8) + +#define I3C_BUS_SDR1_SCL_RATE 8000000 +#define I3C_BUS_SDR2_SCL_RATE 6000000 +#define I3C_BUS_SDR3_SCL_RATE 4000000 +#define I3C_BUS_SDR4_SCL_RATE 2000000 +#define I3C_BUS_I2C_FM_TLOW_MIN_NS 1300 +#define I3C_BUS_I2C_FMP_TLOW_MIN_NS 500 +#define I3C_BUS_THIGH_MAX_NS 41 +#define I3C_PERIOD_NS 1000000000ULL + +#define I3C_BUS_MAX_I3C_SCL_RATE 12900000 +#define I3C_BUS_TYP_I3C_SCL_RATE 12500000 +#define I3C_BUS_I2C_FM_PLUS_SCL_RATE 1000000 +#define I3C_BUS_I2C_FM_SCL_RATE 400000 +#define I3C_BUS_TLOW_OD_MIN_NS 200 + +#define I3C_HOT_JOIN_ADDR 0x02 + +#define DW_I3C_MAX_DEVS 32 +#define DW_I3C_MAX_CMD_BUF_SIZE 16 + +/* Snps I3C/I2C Device Private Data */ +struct dw_i3c_i2c_dev_data { + /* Device id within the retaining registers. This is set after bus initialization by the + * controller. + */ + uint8_t id; +}; + +struct dw_i3c_cmd { + uint32_t cmd_lo; + uint32_t cmd_hi; + void *buf; + uint16_t tx_len; + uint16_t rx_len; + uint8_t error; +}; + +struct dw_i3c_xfer { + int32_t ret; + uint32_t ncmds; + struct dw_i3c_cmd cmds[DW_I3C_MAX_CMD_BUF_SIZE]; +}; + +struct dw_i3c_config { + struct i3c_driver_config common; + const struct device *clock; + uint32_t regs; + + /* Initial clk configuration */ + /* Maximum OD high clk pulse length */ + uint32_t od_thigh_max_ns; + /* Minimum OD low clk pulse length */ + uint32_t od_tlow_min_ns; + + void (*irq_config_func)(); +}; + +struct dw_i3c_data { + struct i3c_driver_data common; + uint32_t free_pos; + + uint16_t datstartaddr; + uint16_t dctstartaddr; + uint16_t maxdevs; + + /* fifo depth is in words (32b) */ + uint8_t ibififodepth; + uint8_t respfifodepth; + uint8_t cmdfifodepth; + uint8_t rxfifodepth; + uint8_t txfifodepth; + + enum i3c_bus_mode mode; + + struct i3c_target_config *target_config; + + struct k_sem sem_xfer; + struct k_mutex mt; + +#ifdef CONFIG_I3C_USE_IBI + struct k_sem ibi_sts_sem; + struct k_sem sem_hj; +#endif + + struct dw_i3c_xfer xfer; + + struct dw_i3c_i2c_dev_data dw_i3c_i2c_priv_data[DW_I3C_MAX_DEVS]; +}; + +static uint8_t get_free_pos(uint32_t free_pos) +{ + return find_lsb_set(free_pos) - 1; +} + +/** + * @brief Read data from the Receive FIFO of the I3C device. + * + * This function reads data from the Receive FIFO of the I3C device specified by + * the given device structure and stores it in the provided buffer. + * + * @param dev Pointer to the I3C device structure. + * @param buf Pointer to the buffer where the received data will be stored. + * @param nbytes Number of bytes to read from the Receive FIFO. + */ +static void read_rx_fifo(const struct device *dev, uint8_t *buf, int32_t nbytes) +{ + __ASSERT((buf != NULL), "Rx buffer should not be NULL"); + + const struct dw_i3c_config *config = dev->config; + int32_t i; + uint32_t tmp; + + if (nbytes >= 4) { + for (i = 0; i <= nbytes - 4; i += 4) { + tmp = sys_read32(config->regs + RX_TX_DATA_PORT); + memcpy(buf + i, &tmp, 4); + } + } + if (nbytes & 3) { + tmp = sys_read32(config->regs + RX_TX_DATA_PORT); + memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3); + } +} + +/** + * @brief Write data to the Transmit FIFO of the I3C device. + * + * This function writes data to the Transmit FIFO of the I3C device specified by + * the given device structure from the provided buffer. + * + * @param dev Pointer to the I3C device structure. + * @param buf Pointer to the buffer containing the data to be written. + * @param nbytes Number of bytes to write to the Transmit FIFO. + */ +static void write_tx_fifo(const struct device *dev, const uint8_t *buf, int32_t nbytes) +{ + __ASSERT((buf != NULL), "Tx buffer should not be NULL"); + + const struct dw_i3c_config *config = dev->config; + int32_t i; + uint32_t tmp; + + if (nbytes >= 4) { + for (i = 0; i <= nbytes - 4; i += 4) { + memcpy(&tmp, buf + i, 4); + sys_write32(tmp, config->regs + RX_TX_DATA_PORT); + } + } + + if (nbytes & 3) { + tmp = 0; + memcpy(&tmp, buf + (nbytes & ~3), nbytes & 3); + sys_write32(tmp, config->regs + RX_TX_DATA_PORT); + } +} + +#ifdef CONFIG_I3C_USE_IBI +/** + * @brief Read data from the In-Band Interrupt (IBI) FIFO of the I3C device. + * + * This function reads data from the In-Band Interrupt (IBI) FIFO of the I3C device + * specified by the given device structure and stores it in the provided buffer. + * + * @param dev Pointer to the I3C device structure. + * @param buf Pointer to the buffer where the received IBI data will be stored. + * @param nbytes Number of bytes to read from the IBI FIFO. + */ +static void read_ibi_fifo(const struct device *dev, uint8_t *buf, int32_t nbytes) +{ + __ASSERT((buf != NULL), "Rx IBI buffer should not be NULL"); + + const struct dw_i3c_config *config = dev->config; + int32_t i; + uint32_t tmp; + + if (nbytes >= 4) { + for (i = 0; i <= nbytes - 4; i += 4) { + tmp = sys_read32(config->regs + IBI_QUEUE_STATUS); + memcpy(buf + i, &tmp, 4); + } + } + if (nbytes & 3) { + tmp = sys_read32(config->regs + IBI_QUEUE_STATUS); + memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3); + } +} +#endif + +/** + * @brief End the I3C transfer and process responses. + * + * This function is responsible for ending the I3C transfer on the specified + * I3C device. It processes the responses received from the I3C bus, updating the + * status and error information in the transfer structure. + * + * @param dev Pointer to the I3C device structure. + */ +static void dw_i3c_end_xfer(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_xfer *xfer = &data->xfer; + struct dw_i3c_cmd *cmd; + uint32_t nresp, resp, rx_data; + int32_t i, j, k, ret = 0; + + nresp = QUEUE_STATUS_LEVEL_RESP(sys_read32(config->regs + QUEUE_STATUS_LEVEL)); + for (i = 0; i < nresp; i++) { + uint8_t tid; + + resp = sys_read32(config->regs + RESPONSE_QUEUE_PORT); + tid = RESPONSE_PORT_TID(resp); + if (tid == 0xf) { + /* TODO: handle vendor extension ccc or hdr header in target mode */ + continue; + } + + cmd = &xfer->cmds[tid]; + cmd->rx_len = RESPONSE_PORT_DATA_LEN(resp); + cmd->error = RESPONSE_PORT_ERR_STATUS(resp); + + /* if we are in target mode */ + if (!(sys_read32(config->regs + PRESENT_STATE) & PRESENT_STATE_CURRENT_MASTER)) { + const struct i3c_target_callbacks *target_cb = + data->target_config->callbacks; + + for (j = 0; j < cmd->rx_len; j += 4) { + rx_data = sys_read32(config->regs + RX_TX_DATA_PORT); + /* Call write received cb for each remaining byte */ + for (k = 0; k < MIN(4, cmd->rx_len - j); k++) { + target_cb->write_received_cb(data->target_config, + (rx_data >> (8 * k)) & 0xff); + } + } + + if (target_cb != NULL && target_cb->stop_cb != NULL) { + /* + * TODO: modify API to include status, such as success or aborted + * transfer + */ + target_cb->stop_cb(data->target_config); + } + } + } + + for (i = 0; i < nresp; i++) { + switch (xfer->cmds[i].error) { + case RESPONSE_NO_ERROR: + break; + case RESPONSE_ERROR_PARITY: + case RESPONSE_ERROR_IBA_NACK: + case RESPONSE_ERROR_TRANSF_ABORT: + case RESPONSE_ERROR_CRC: + case RESPONSE_ERROR_FRAME: + ret = -EIO; + break; + case RESPONSE_ERROR_OVER_UNDER_FLOW: + ret = -ENOSPC; + break; + case RESPONSE_ERROR_I2C_W_NACK_ERR: + case RESPONSE_ERROR_ADDRESS_NACK: + ret = -ENXIO; + break; + default: + ret = -EINVAL; + break; + } + } + xfer->ret = ret; + + if (ret < 0) { + sys_write32(RESET_CTRL_RX_FIFO | RESET_CTRL_TX_FIFO | RESET_CTRL_RESP_QUEUE | + RESET_CTRL_CMD_QUEUE, + config->regs + RESET_CTRL); + sys_write32(sys_read32(config->regs + DEVICE_CTRL) | DEV_CTRL_RESUME, + config->regs + DEVICE_CTRL); + } + k_sem_give(&data->sem_xfer); +} + +/** + * @brief Start an I3C transfer on the specified device. + * + * This function initiates an I3C transfer on the specified I3C device by pushing + * data to the Transmit FIFO (TXFIFO) and enqueuing commands to the command queue. + * + * @param dev Pointer to the I3C device structure. + */ +static void start_xfer(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_xfer *xfer = &data->xfer; + struct dw_i3c_cmd *cmd; + uint32_t thld_ctrl, present_state; + int32_t i; + + present_state = sys_read32(config->regs + PRESENT_STATE); + + /* Push data to TXFIFO */ + for (i = 0; i < xfer->ncmds; i++) { + cmd = &xfer->cmds[i]; + /* Not all the commands use write_tx_fifo function */ + if (cmd->buf != NULL) { + write_tx_fifo(dev, cmd->buf, cmd->tx_len); + } + } + + thld_ctrl = sys_read32(config->regs + QUEUE_THLD_CTRL); + thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK; + thld_ctrl |= QUEUE_THLD_CTRL_RESP_BUF(xfer->ncmds); + sys_write32(thld_ctrl, config->regs + QUEUE_THLD_CTRL); + + /* Enqueue CMD */ + for (i = 0; i < xfer->ncmds; i++) { + cmd = &xfer->cmds[i]; + /* Only cmd_lo is used when it is a target */ + if (present_state & PRESENT_STATE_CURRENT_MASTER) { + sys_write32(cmd->cmd_hi, config->regs + COMMAND_QUEUE_PORT); + } + sys_write32(cmd->cmd_lo, config->regs + COMMAND_QUEUE_PORT); + } +} + +/** + * @brief Get the position of an I3C device with the specified address. + * + * This function retrieves the position (ID) of an I3C device with the specified + * address on the I3C bus associated with the provided I3C device structure. This + * utilizes the controller private data for where the id reg is stored. + * + * @param dev Pointer to the I3C device structure. + * @param addr I3C address of the device whose position is to be retrieved. + * @param sa True if looking up by Static Address, False if by Dynamic Address + * + * @return The position (ID) of the device on success, or a negative error code + * if the device with the given address is not found. + */ +static int get_i3c_addr_pos(const struct device *dev, uint8_t addr, bool sa) +{ + struct dw_i3c_i2c_dev_data *dw_i3c_device_data; + struct i3c_device_desc *desc = sa ? i3c_dev_list_i3c_static_addr_find(dev, addr) + : i3c_dev_list_i3c_addr_find(dev, addr); + + if (desc == NULL) { + return -ENODEV; + } + + dw_i3c_device_data = desc->controller_priv; + + return dw_i3c_device_data->id; +} + +/** + * @brief Get the position of an I2C device with the specified address. + * + * This function retrieves the position (ID) of an I2C device with the specified + * address on the I3C bus associated with the provided I3C device structure. This + * utilizes the controller private data for where the id reg is stored. + * + * @param dev Pointer to the I3C device structure. + * @param addr I2C address of the device whose position is to be retrieved. + * + * @return The position (ID) of the device on success, or a negative error code + * if the device with the given address is not found. + */ +static int get_i2c_addr_pos(const struct device *dev, uint16_t addr) +{ + struct dw_i3c_i2c_dev_data *dw_i3c_device_data; + struct i3c_i2c_device_desc *desc = i3c_dev_list_i2c_addr_find(dev, addr); + + if (desc == NULL) { + return -ENODEV; + } + + dw_i3c_device_data = desc->controller_priv; + + return dw_i3c_device_data->id; +} + +/** + * @brief Transfer messages in I3C mode. + * + * @param dev Pointer to device driver instance. + * @param target Pointer to target device descriptor. + * @param msgs Pointer to I3C messages. + * @param num_msgs Number of messages to transfers. + * + * @retval 0 If successful. + * @retval -EIO General input / output error. + * @retval -EINVAL Address not registered + */ +static int dw_i3c_xfers(const struct device *dev, struct i3c_device_desc *target, + struct i3c_msg *msgs, uint8_t num_msgs) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_xfer *xfer = &data->xfer; + int32_t ret, i, pos, nrxwords = 0, ntxwords = 0; + uint32_t present_state; + + present_state = sys_read32(config->regs + PRESENT_STATE); + if (!(present_state & PRESENT_STATE_CURRENT_MASTER)) { + return -EACCES; + } + + if (num_msgs > data->cmdfifodepth) { + return -ENOTSUP; + } + + pos = get_i3c_addr_pos(dev, target->dynamic_addr, false); + if (pos < 0) { + LOG_ERR("%s: Invalid slave device", dev->name); + return -EINVAL; + } + + for (i = 0; i < num_msgs; i++) { + if (msgs[i].flags & I2C_MSG_READ) { + nrxwords += DIV_ROUND_UP(msgs[i].len, 4); + } else { + ntxwords += DIV_ROUND_UP(msgs[i].len, 4); + } + } + + if (ntxwords > data->txfifodepth || nrxwords > data->rxfifodepth) { + return -ENOTSUP; + } + + ret = k_mutex_lock(&data->mt, K_MSEC(1000)); + if (ret) { + LOG_ERR("%s: Mutex err (%d)", dev->name, ret); + return ret; + } + + memset(xfer, 0, sizeof(struct dw_i3c_xfer)); + + xfer->ncmds = num_msgs; + xfer->ret = -1; + + for (i = 0; i < num_msgs; i++) { + struct dw_i3c_cmd *cmd = &xfer->cmds[i]; + + cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(msgs[i].len) | COMMAND_PORT_TRANSFER_ARG; + cmd->cmd_lo = COMMAND_PORT_TID(i) | COMMAND_PORT_DEV_INDEX(pos) | COMMAND_PORT_ROC; + + cmd->buf = msgs[i].buf; + + if (msgs[i].flags & I3C_MSG_NBCH) { + sys_write32(sys_read32(config->regs + DEVICE_CTRL) & ~DEV_CTRL_IBA_INCLUDE, + config->regs + DEVICE_CTRL); + } else { + sys_write32(sys_read32(config->regs + DEVICE_CTRL) | DEV_CTRL_IBA_INCLUDE, + config->regs + DEVICE_CTRL); + } + + if (msgs[i].flags & I3C_MSG_READ) { + uint8_t rd_speed; + + if (msgs[i].flags & I3C_MSG_HDR) { + /* Set read command bit for DDR and TS */ + cmd->cmd_lo |= COMMAND_PORT_CP | + COMMAND_PORT_CMD(BIT(7) | (msgs[i].hdr_cmd_code & + GENMASK(6, 0))); + if (msgs[i].hdr_mode & I3C_MSG_HDR_DDR) { + if (data->common.ctrl_config.supported_hdr & + I3C_MSG_HDR_DDR) { + rd_speed = COMMAND_PORT_SPEED_I3C_DDR; + } else { + /* DDR support not configured with this */ + LOG_ERR("%s: HDR-DDR not supported", dev->name); + ret = -ENOTSUP; + goto error; + } + } else if (msgs[i].hdr_mode & I3C_MSG_HDR_TSP || + msgs[i].hdr_mode & I3C_MSG_HDR_TSL) { + if (data->common.ctrl_config.supported_hdr & + (I3C_MSG_HDR_TSP | I3C_MSG_HDR_TSL)) { + rd_speed = COMMAND_PORT_SPEED_I3C_TS; + } else { + /* TS support not configured with this */ + LOG_ERR("%s: HDR-TS not supported", dev->name); + ret = -ENOTSUP; + goto error; + } + } else { + LOG_ERR("%s: HDR %d not supported", dev->name, + msgs[i].hdr_mode); + ret = -ENOTSUP; + goto error; + } + } else { + rd_speed = I3C_CCC_GETMXDS_MAXRD_MAX_SDR_FSCL( + target->data_speed.maxrd); + } + + cmd->cmd_lo |= (COMMAND_PORT_READ_TRANSFER | COMMAND_PORT_SPEED(rd_speed)); + cmd->rx_len = msgs[i].len; + } else { + uint8_t wr_speed; + + if (msgs[i].flags & I3C_MSG_HDR) { + cmd->cmd_lo |= + COMMAND_PORT_CP | + COMMAND_PORT_CMD(msgs[i].hdr_cmd_code & GENMASK(6, 0)); + if (msgs[i].hdr_mode & I3C_MSG_HDR_DDR) { + if (data->common.ctrl_config.supported_hdr & + I3C_MSG_HDR_DDR) { + wr_speed = COMMAND_PORT_SPEED_I3C_DDR; + } else { + /* DDR support not configured with this */ + LOG_ERR("%s: HDR-DDR not supported", dev->name); + ret = -ENOTSUP; + goto error; + } + } else if (msgs[i].hdr_mode & I3C_MSG_HDR_TSP || + msgs[i].hdr_mode & I3C_MSG_HDR_TSL) { + if (data->common.ctrl_config.supported_hdr & + (I3C_MSG_HDR_TSP | I3C_MSG_HDR_TSL)) { + wr_speed = COMMAND_PORT_SPEED_I3C_TS; + } else { + /* TS support not configured with this */ + LOG_ERR("%s: HDR-TS not supported", dev->name); + ret = -ENOTSUP; + goto error; + } + } else { + LOG_ERR("%s: HDR %d not supported", dev->name, + msgs[i].hdr_mode); + ret = -ENOTSUP; + goto error; + } + } else { + wr_speed = I3C_CCC_GETMXDS_MAXWR_MAX_SDR_FSCL( + target->data_speed.maxwr); + } + + cmd->cmd_lo |= COMMAND_PORT_SPEED(wr_speed); + cmd->tx_len = msgs[i].len; + } + + if (i == (num_msgs - 1)) { + cmd->cmd_lo |= COMMAND_PORT_TOC; + } + } + + start_xfer(dev); + + ret = k_sem_take(&data->sem_xfer, K_MSEC(1000)); + if (ret) { + LOG_ERR("%s: Semaphore err (%d)", dev->name, ret); + goto error; + } + + for (i = 0; i < xfer->ncmds; i++) { + msgs[i].num_xfer = (msgs[i].flags & I3C_MSG_READ) ? xfer->cmds[i].rx_len + : xfer->cmds[i].tx_len; + if (xfer->cmds[i].rx_len && !xfer->cmds[i].error) { + read_rx_fifo(dev, xfer->cmds[i].buf, xfer->cmds[i].rx_len); + } + } + + ret = xfer->ret; + +error: + k_mutex_unlock(&data->mt); + + return ret; +} + +/** + * @brief Transfer messages in I2C mode. + * + * @param dev Pointer to device driver instance. + * @param target Pointer to target device descriptor. + * @param msgs Pointer to I2C messages. + * @param num_msgs Number of messages to transfers. + * + * @retval 0 If successful. + * @retval -EIO General input / output error. + * @retval -EINVAL Address not registered + */ +static int dw_i3c_i2c_transfer(const struct device *dev, struct i3c_i2c_device_desc *target, + struct i2c_msg *msgs, uint8_t num_msgs) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_xfer *xfer = &data->xfer; + int32_t ret, i, pos, nrxwords = 0, ntxwords = 0; + uint32_t present_state; + + present_state = sys_read32(config->regs + PRESENT_STATE); + if (!(present_state & PRESENT_STATE_CURRENT_MASTER)) { + return -EACCES; + } + + if (num_msgs > data->cmdfifodepth) { + return -ENOTSUP; + } + + pos = get_i2c_addr_pos(dev, target->addr); + if (pos < 0) { + LOG_ERR("%s: Invalid slave device", dev->name); + return -EINVAL; + } + + for (i = 0; i < num_msgs; i++) { + if (msgs[i].flags & I2C_MSG_READ) { + nrxwords += DIV_ROUND_UP(msgs[i].len, 4); + } else { + ntxwords += DIV_ROUND_UP(msgs[i].len, 4); + } + } + + if (ntxwords > data->txfifodepth || nrxwords > data->rxfifodepth) { + return -ENOTSUP; + } + + ret = k_mutex_lock(&data->mt, K_MSEC(1000)); + if (ret) { + LOG_ERR("%s: Mutex err (%d)", dev->name, ret); + return ret; + } + + memset(xfer, 0, sizeof(struct dw_i3c_xfer)); + + xfer->ncmds = num_msgs; + xfer->ret = -1; + + for (i = 0; i < num_msgs; i++) { + struct dw_i3c_cmd *cmd = &xfer->cmds[i]; + + cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(msgs[i].len) | COMMAND_PORT_TRANSFER_ARG; + cmd->cmd_lo = COMMAND_PORT_TID(i) | COMMAND_PORT_DEV_INDEX(pos) | COMMAND_PORT_ROC; + + cmd->buf = msgs[i].buf; + + if (msgs[i].flags & I2C_MSG_READ) { + uint8_t rd_speed = I3C_LVR_I2C_MODE(target->lvr) == I3C_LVR_I2C_FM_MODE + ? COMMAND_PORT_SPEED_I2C_FM + : COMMAND_PORT_SPEED_I2C_FMP; + + cmd->cmd_lo |= (COMMAND_PORT_READ_TRANSFER | COMMAND_PORT_SPEED(rd_speed)); + cmd->rx_len = msgs[i].len; + } else { + uint8_t wr_speed = I3C_LVR_I2C_MODE(target->lvr) == I3C_LVR_I2C_FM_MODE + ? COMMAND_PORT_SPEED_I2C_FM + : COMMAND_PORT_SPEED_I2C_FMP; + + cmd->cmd_lo |= COMMAND_PORT_SPEED(wr_speed); + cmd->tx_len = msgs[i].len; + } + + if (i == (num_msgs - 1)) { + cmd->cmd_lo |= COMMAND_PORT_TOC; + } + } + + /* Do not send broadcast address (0x7E) with I2C transfers */ + sys_write32(sys_read32(config->regs + DEVICE_CTRL) & ~DEV_CTRL_IBA_INCLUDE, + config->regs + DEVICE_CTRL); + + start_xfer(dev); + + ret = k_sem_take(&data->sem_xfer, K_MSEC(1000)); + if (ret) { + LOG_ERR("%s: Semaphore err (%d)", dev->name, ret); + goto error; + } + + for (i = 0; i < xfer->ncmds; i++) { + if (xfer->cmds[i].rx_len && !xfer->cmds[i].error) { + read_rx_fifo(dev, xfer->cmds[i].buf, xfer->cmds[i].rx_len); + } + } + + ret = xfer->ret; + +error: + k_mutex_unlock(&data->mt); + + return ret; +} + +/** + * Find a registered I2C target device. + * + * Controller only API. + * + * This returns the I2C device descriptor of the I2C device + * matching the device address @p addr. + * + * @param dev Pointer to controller device driver instance. + * @param id I2C target device address. + * + * @return @see i3c_i2c_device_find. + */ +static struct i3c_i2c_device_desc *dw_i3c_i2c_device_find(const struct device *dev, uint16_t addr) +{ + return i3c_dev_list_i2c_addr_find(dev, addr); +} + +/** + * @brief Transfer messages in I2C mode. + * + * @see i2c_transfer + * + * @param dev Pointer to device driver instance. + * @param target Pointer to target device descriptor. + * @param msgs Pointer to I2C messages. + * @param num_msgs Number of messages to transfers. + * + * @return @see i2c_transfer + */ +static int dw_i3c_i2c_api_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs, + uint16_t addr) +{ + struct i3c_i2c_device_desc *i2c_dev = dw_i3c_i2c_device_find(dev, addr); + int ret; + + if (i2c_dev == NULL) { + ret = -ENODEV; + } else { + ret = dw_i3c_i2c_transfer(dev, i2c_dev, msgs, num_msgs); + } + + return ret; +} + +#ifdef CONFIG_I3C_USE_IBI +static int dw_i3c_controller_ibi_hj_response(const struct device *dev, bool ack) +{ + const struct dw_i3c_config *config = dev->config; + uint32_t ctrl = sys_read32(config->regs + DEVICE_CTRL); + + if (ack) { + ctrl &= ~DEV_CTRL_HOT_JOIN_NACK; + } else { + ctrl |= DEV_CTRL_HOT_JOIN_NACK; + } + + sys_write32(ctrl, config->regs + DEVICE_CTRL); + + return 0; +} + +static int i3c_dw_endis_ibi(const struct device *dev, struct i3c_device_desc *target, bool en) +{ + struct dw_i3c_data *data = dev->data; + const struct dw_i3c_config *config = dev->config; + uint32_t bitpos, sir_con; + struct i3c_ccc_events i3c_events; + int ret; + int pos; + + pos = get_i3c_addr_pos(dev, target->dynamic_addr, false); + if (pos < 0) { + LOG_ERR("%s: Invalid Slave address", dev->name); + return pos; + } + + uint32_t reg = sys_read32(config->regs + DEV_ADDR_TABLE_LOC(data->datstartaddr, pos)); + + if (i3c_ibi_has_payload(target)) { + reg |= DEV_ADDR_TABLE_IBI_WITH_DATA; + } else { + reg &= ~DEV_ADDR_TABLE_IBI_WITH_DATA; + } + if (en) { + reg &= ~DEV_ADDR_TABLE_SIR_REJECT; + } else { + reg |= DEV_ADDR_TABLE_SIR_REJECT; + } + sys_write32(reg, config->regs + DEV_ADDR_TABLE_LOC(data->datstartaddr, pos)); + + sir_con = sys_read32(config->regs + IBI_SIR_REQ_REJECT); + /* TODO: what is this macro doing?? */ + bitpos = IBI_SIR_REQ_ID(target->dynamic_addr); + + if (en) { + sir_con &= ~BIT(bitpos); + } else { + sir_con |= BIT(bitpos); + } + sys_write32(sir_con, config->regs + IBI_SIR_REQ_REJECT); + + /* Tell target to enable IBI */ + i3c_events.events = I3C_CCC_EVT_INTR; + ret = i3c_ccc_do_events_set(target, en, &i3c_events); + if (ret != 0) { + LOG_ERR("%s: Error sending IBI ENEC for 0x%02x (%d)", dev->name, + target->dynamic_addr, ret); + return ret; + } + + return 0; +} + +static int dw_i3c_controller_enable_ibi(const struct device *dev, struct i3c_device_desc *target) +{ + return i3c_dw_endis_ibi(dev, target, true); +} + +static int dw_i3c_controller_disable_ibi(const struct device *dev, struct i3c_device_desc *target) +{ + return i3c_dw_endis_ibi(dev, target, false); +} + +static void dw_i3c_handle_tir(const struct device *dev, uint32_t ibi_status) +{ + uint8_t ibi_data[CONFIG_I3C_IBI_MAX_PAYLOAD_SIZE]; + uint8_t addr, len; + int pos; + + addr = IBI_QUEUE_IBI_ADDR(ibi_status); + len = IBI_QUEUE_STATUS_DATA_LEN(ibi_status); + + pos = get_i3c_addr_pos(dev, addr, false); + if (pos < 0) { + LOG_ERR("%s: Invalid Slave address", dev->name); + return; + } + + struct i3c_device_desc *desc = i3c_dev_list_i3c_addr_find(dev, addr); + + if (desc == NULL) { + return; + } + + if (len > 0) { + read_ibi_fifo(dev, ibi_data, len); + } + + if (i3c_ibi_work_enqueue_target_irq(desc, ibi_data, len) != 0) { + LOG_ERR("%s: Error enqueue IBI IRQ work", dev->name); + } +} + +static void dw_i3c_handle_hj(const struct device *dev, uint32_t ibi_status) +{ + if (IBI_QUEUE_STATUS_IBI_STS(ibi_status) & BIT(3)) { + LOG_DBG("%s: NAK for HJ", dev->name); + return; + } + + if (i3c_ibi_work_enqueue_hotjoin(dev) != 0) { + LOG_ERR("%s: Error enqueue IBI HJ work", dev->name); + } +} + +static void ibis_handle(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + uint32_t nibis, ibi_stat; + int32_t i; + + nibis = sys_read32(config->regs + QUEUE_STATUS_LEVEL); + nibis = QUEUE_STATUS_IBI_BUF_BLR(nibis); + for (i = 0; i < nibis; i++) { + ibi_stat = sys_read32(config->regs + IBI_QUEUE_STATUS); + if (IBI_TYPE_SIRQ(ibi_stat)) { + dw_i3c_handle_tir(dev, ibi_stat); + } else if (IBI_TYPE_HJ(ibi_stat)) { + dw_i3c_handle_hj(dev, ibi_stat); + } else { + LOG_DBG("%s: Secondary Master Request Not implemented", dev->name); + } + } +} + +static int dw_i3c_target_ibi_raise_hj(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + int ret; + + if (!(sys_read32(config->regs + HW_CAPABILITY) & HW_CAPABILITY_SLV_HJ_CAP)) { + LOG_ERR("%s: HJ not supported", dev->name); + return -ENOTSUP; + } + if (sys_read32(config->regs + DEVICE_ADDR) & DEVICE_ADDR_DYNAMIC_ADDR_VALID) { + LOG_ERR("%s: HJ not available, DA already assigned", dev->name); + return -EACCES; + } + /* if this is set, then it is assumed it is already trying */ + if ((sys_read32(config->regs + SLV_EVENT_STATUS) & SLV_EVENT_STATUS_HJ_EN)) { + LOG_ERR("%s: HJ requests are currently disabled by DISEC", dev->name); + return -EAGAIN; + } + + /* + * This is issued auto-magically by the IP when certain conditions are meet. + * These include: + * 1. SLV_EVENT_STATUS[HJ_EN] = 1 (or a controller issues Enables HJ events with + * the CCC ENEC, This can be set to 0 with CCC DISEC from a controller) + * 2. The Dynamic address is invalid. (not assigned yet) + * 3. Bus Idle condition is met (1ms) as programmed in the Bus Timing Register + */ + + /* enable HJ */ + sys_write32(sys_read32(config->regs + SLV_EVENT_STATUS) | SLV_EVENT_STATUS_HJ_EN, + config->regs + SLV_EVENT_STATUS); + + ret = k_sem_take(&data->sem_hj, K_MSEC(1000)); + if (ret) { + return ret; + } + + return 0; +} + +static int dw_i3c_target_ibi_raise_tir(const struct device *dev, struct i3c_ibi *request) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + int status; + uint32_t slv_intr_req, slv_ibi_resp; + + if (!(sys_read32(config->regs + HW_CAPABILITY) & HW_CAPABILITY_SLV_IBI_CAP)) { + LOG_ERR("%s: IBI TIR not supported", dev->name); + return -ENOTSUP; + } + + if (!(sys_read32(config->regs + DEVICE_ADDR) & DEVICE_ADDR_DYNAMIC_ADDR_VALID)) { + LOG_ERR("%s: IBI TIR not available, DA not assigned", dev->name); + return -EACCES; + } + + if (!(sys_read32(config->regs + SLV_EVENT_STATUS) & SLV_EVENT_STATUS_SIR_EN)) { + LOG_ERR("%s: IBI TIR requests are currently disabled by DISEC", dev->name); + return -EAGAIN; + } + + slv_intr_req = sys_read32(config->regs + SLV_INTR_REQ); + if (sys_read32(config->regs + SLV_CHAR_CTRL) & SLV_CHAR_CTRL_IBI_PAYLOAD) { + uint32_t tir_data = 0; + + /* max support length is DA + MDB (1 byte) + 4 data bytes, MDB must be at least + * included + */ + if ((request->payload_len > 5) || (request->payload_len == 0)) { + return -EINVAL; + } + + /* MDB should be the first byte of the payload */ + slv_intr_req |= SLV_INTR_REQ_MDB(request->payload[0]) | + SLV_INTR_REQ_SIR_DATA_LENGTH(request->payload_len - 1); + + /* program the tir data packet */ + tir_data |= + SLV_SIR_DATA_BYTE0((request->payload_len > 1) ? request->payload[1] : 0); + tir_data |= + SLV_SIR_DATA_BYTE1((request->payload_len > 2) ? request->payload[2] : 0); + tir_data |= + SLV_SIR_DATA_BYTE2((request->payload_len > 3) ? request->payload[3] : 0); + tir_data |= + SLV_SIR_DATA_BYTE3((request->payload_len > 4) ? request->payload[4] : 0); + sys_write32(tir_data, config->regs + SLV_SIR_DATA); + } + + /* kick off the ibi tir request */ + slv_intr_req |= SLV_INTR_REQ_SIR; + sys_write32(slv_intr_req, config->regs + SLV_INTR_REQ); + + /* wait for SLV_IBI_RESP update */ + status = k_sem_take(&data->ibi_sts_sem, K_MSEC(100)); + if (status != 0) { + return -ETIMEDOUT; + } + + slv_ibi_resp = sys_read32(config->regs + SLV_INTR_REQ); + switch (SLV_IBI_RESP_IBI_STS(slv_ibi_resp)) { + case SLV_IBI_RESP_IBI_STS_ACK: + LOG_DBG("%s: Controller ACKed IBI TIR", dev->name); + return 0; + case SLV_IBI_RESP_IBI_STS_NACK: + LOG_ERR("%s: Controller NACKed IBI TIR", dev->name); + return -EAGAIN; + case SLV_IBI_RESP_IBI_STS_EARLY_TERMINATE: + LOG_ERR("%s: Controller aborted IBI TIR with %lu remaining", dev->name, + SLV_IBI_RESP_DATA_LENGTH(slv_ibi_resp)); + return -EIO; + default: + return -EIO; + } +} + +static int dw_i3c_target_ibi_raise(const struct device *dev, struct i3c_ibi *request) +{ + if (request == NULL) { + return -EINVAL; + } + + switch (request->ibi_type) { + case I3C_IBI_TARGET_INTR: + return dw_i3c_target_ibi_raise_tir(dev, request); + case I3C_IBI_CONTROLLER_ROLE_REQUEST: + /* TODO: Synopsys I3C can support CR, but not implemented yet */ + return -ENOTSUP; + case I3C_IBI_HOTJOIN: + return dw_i3c_target_ibi_raise_hj(dev); + default: + return -EINVAL; + } +} + +#endif /* CONFIG_I3C_USE_IBI */ + +static int i3c_dw_irq(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + uint32_t status; + uint32_t present_state; + + status = sys_read32(config->regs + INTR_STATUS); + if (status & (INTR_TRANSFER_ERR_STAT | INTR_RESP_READY_STAT)) { + dw_i3c_end_xfer(dev); + + if (status & INTR_TRANSFER_ERR_STAT) { + sys_write32(INTR_TRANSFER_ERR_STAT, config->regs + INTR_STATUS); + } + } + + if (status & INTR_IBI_THLD_STAT) { +#ifdef CONFIG_I3C_USE_IBI + ibis_handle(dev); +#endif /* CONFIG_I3C_USE_IBI */ + } + + /* target mode related interrupts */ + present_state = sys_read32(config->regs + PRESENT_STATE); + if (!(present_state & PRESENT_STATE_CURRENT_MASTER)) { + const struct i3c_target_callbacks *target_cb = + data->target_config ? data->target_config->callbacks : NULL; + + /* Read Requested when the CMDQ is empty*/ + if (status & INTR_READ_REQ_RECV_STAT) { + if (target_cb != NULL && target_cb->read_requested_cb != NULL) { + /* Inform app so that it can send data. */ + target_cb->read_requested_cb(data->target_config, NULL); + } + sys_write32(INTR_READ_REQ_RECV_STAT, config->regs + INTR_STATUS); + } +#ifdef CONFIG_I3C_USE_IBI + /* IBI TIR request register is addressed and status is updated*/ + if (status & INTR_IBI_UPDATED_STAT) { + k_sem_give(&data->ibi_sts_sem); + sys_write32(INTR_IBI_UPDATED_STAT, config->regs + INTR_STATUS); + } + /* DA has been assigned, could happen after a IBI HJ request */ + if (status & INTR_DYN_ADDR_ASSGN_STAT) { + /* TODO: handle IBI HJ with semaphore */ + sys_write32(INTR_DYN_ADDR_ASSGN_STAT, config->regs + INTR_STATUS); + } +#endif /* CONFIG_I3C_USE_IBI */ + } + + return 0; +} + +static int init_scl_timing(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + uint32_t scl_timing, hcnt, lcnt, core_rate; + + if (clock_control_get_rate(config->clock, NULL, &core_rate) != 0) { + LOG_ERR("%s: get clock rate failed", dev->name); + return -EINVAL; + } + + /* I3C_OD */ + hcnt = DIV_ROUND_UP(config->od_thigh_max_ns * (uint64_t)core_rate, I3C_PERIOD_NS) - 1; + hcnt = CLAMP(hcnt, SCL_I3C_TIMING_CNT_MIN, SCL_I3C_TIMING_CNT_MAX); + + lcnt = DIV_ROUND_UP(config->od_tlow_min_ns * (uint64_t)core_rate, I3C_PERIOD_NS); + lcnt = CLAMP(lcnt, SCL_I3C_TIMING_CNT_MIN, SCL_I3C_TIMING_CNT_MAX); + + scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt); + sys_write32(scl_timing, config->regs + SCL_I3C_OD_TIMING); + + /* Set bus free timing to match tlow setting for OD clk config. */ + sys_write32(BUS_I3C_MST_FREE(lcnt), config->regs + BUS_FREE_TIMING); + + /* I3C_PP */ + hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS * (uint64_t)core_rate, I3C_PERIOD_NS) - 1; + hcnt = CLAMP(hcnt, SCL_I3C_TIMING_CNT_MIN, SCL_I3C_TIMING_CNT_MAX); + + lcnt = DIV_ROUND_UP(core_rate, data->common.ctrl_config.scl.i3c) - hcnt; + lcnt = CLAMP(lcnt, SCL_I3C_TIMING_CNT_MIN, SCL_I3C_TIMING_CNT_MAX); + + scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt); + sys_write32(scl_timing, config->regs + SCL_I3C_PP_TIMING); + + /* I3C */ + lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt; + scl_timing = SCL_EXT_LCNT_1(lcnt); + lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt; + scl_timing |= SCL_EXT_LCNT_2(lcnt); + lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt; + scl_timing |= SCL_EXT_LCNT_3(lcnt); + lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt; + scl_timing |= SCL_EXT_LCNT_4(lcnt); + sys_write32(scl_timing, config->regs + SCL_EXT_LCNT_TIMING); + + /* I2C FM+ */ + lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS * (uint64_t)core_rate, I3C_PERIOD_NS); + hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt; + scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) | SCL_I2C_FMP_TIMING_LCNT(lcnt); + sys_write32(scl_timing, config->regs + SCL_I2C_FMP_TIMING); + + /* I2C FM */ + lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS * (uint64_t)core_rate, I3C_PERIOD_NS); + hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt; + scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) | SCL_I2C_FM_TIMING_LCNT(lcnt); + sys_write32(scl_timing, config->regs + SCL_I2C_FM_TIMING); + + if (data->mode != I3C_BUS_MODE_PURE) { + sys_write32(BUS_I3C_MST_FREE(lcnt), config->regs + BUS_FREE_TIMING); + sys_write32(sys_read32(config->regs + DEVICE_CTRL) | DEV_CTRL_I2C_SLAVE_PRESENT, + config->regs + DEVICE_CTRL); + } + /* I3C Bus Available Time */ + scl_timing = DIV_ROUND_UP(I3C_BUS_AVAILABLE_TIME_NS * (uint64_t)core_rate, + I3C_PERIOD_NS); + sys_write32(BUS_I3C_AVAIL_TIME(scl_timing), config->regs + BUS_FREE_TIMING); + + /* I3C Bus Idle Time */ + scl_timing = + DIV_ROUND_UP(I3C_BUS_IDLE_TIME_NS * (uint64_t)core_rate, I3C_PERIOD_NS); + sys_write32(BUS_I3C_IDLE_TIME(scl_timing), config->regs + BUS_IDLE_TIMING); + + return 0; +} + +/** + * Determine I3C bus mode from the i2c devices on the bus + * + * Reads the LVR of all I2C devices and returns the I3C bus + * Mode + * + * @param dev_list Pointer to device list + * + * @return @see enum i3c_bus_mode. + */ +static enum i3c_bus_mode i3c_bus_mode(const struct i3c_dev_list *dev_list) +{ + enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; + + for (int i = 0; i < dev_list->num_i2c; i++) { + switch (I3C_LVR_I2C_DEV_IDX(dev_list->i2c[i].lvr)) { + case I3C_LVR_I2C_DEV_IDX_0: + if (mode < I3C_BUS_MODE_MIXED_FAST) { + mode = I3C_BUS_MODE_MIXED_FAST; + } + break; + case I3C_LVR_I2C_DEV_IDX_1: + if (mode < I3C_BUS_MODE_MIXED_LIMITED) { + mode = I3C_BUS_MODE_MIXED_LIMITED; + } + break; + case I3C_LVR_I2C_DEV_IDX_2: + if (mode < I3C_BUS_MODE_MIXED_SLOW) { + mode = I3C_BUS_MODE_MIXED_SLOW; + } + break; + default: + mode = I3C_BUS_MODE_INVALID; + break; + } + } + return mode; +} + +static int dw_i3c_attach_device(const struct device *dev, struct i3c_device_desc *desc) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + uint8_t pos = get_free_pos(data->free_pos); + uint8_t addr = desc->dynamic_addr ? desc->dynamic_addr : desc->static_addr; + + if (pos < 0) { + LOG_ERR("%s: no space for i3c device: %s", dev->name, desc->dev->name); + return -ENOSPC; + } + + data->dw_i3c_i2c_priv_data[pos].id = pos; + desc->controller_priv = &(data->dw_i3c_i2c_priv_data[pos]); + data->free_pos &= ~BIT(pos); + + LOG_DBG("%s: Attaching %s", dev->name, desc->dev->name); + + sys_write32(DEV_ADDR_TABLE_DYNAMIC_ADDR(addr), + config->regs + DEV_ADDR_TABLE_LOC(data->datstartaddr, pos)); + + return 0; +} + +static int dw_i3c_reattach_device(const struct device *dev, struct i3c_device_desc *desc, + uint8_t old_dyn_addr) +{ + ARG_UNUSED(old_dyn_addr); + + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_i2c_dev_data *dw_i3c_device_data = desc->controller_priv; + uint32_t dat; + + if (dw_i3c_device_data == NULL) { + LOG_ERR("%s: %s: device not attached", dev->name, desc->dev->name); + return -EINVAL; + } + /* TODO: investigate clearing table beforehand */ + + LOG_DBG("Reattaching %s", desc->dev->name); + + dat = sys_read32(config->regs + + DEV_ADDR_TABLE_LOC(data->datstartaddr, dw_i3c_device_data->id)); + dat &= ~DEV_ADDR_TABLE_DYNAMIC_ADDR_MASK; + sys_write32(DEV_ADDR_TABLE_DYNAMIC_ADDR(desc->dynamic_addr) | dat, + config->regs + DEV_ADDR_TABLE_LOC(data->datstartaddr, dw_i3c_device_data->id)); + + return 0; +} + +static int dw_i3c_detach_device(const struct device *dev, struct i3c_device_desc *desc) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_i2c_dev_data *dw_i3c_device_data = desc->controller_priv; + + if (dw_i3c_device_data == NULL) { + LOG_ERR("%s: %s: device not attached", dev->name, desc->dev->name); + return -EINVAL; + } + + LOG_DBG("%s: Detaching %s", dev->name, desc->dev->name); + + sys_write32(0, + config->regs + DEV_ADDR_TABLE_LOC(data->datstartaddr, dw_i3c_device_data->id)); + data->free_pos |= BIT(dw_i3c_device_data->id); + desc->controller_priv = NULL; + + return 0; +} + +static int dw_i3c_i2c_attach_device(const struct device *dev, struct i3c_i2c_device_desc *desc) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + uint8_t pos; + + pos = get_free_pos(data->free_pos); + if (pos < 0) { + return -ENOSPC; + } + + data->dw_i3c_i2c_priv_data[pos].id = pos; + desc->controller_priv = &(data->dw_i3c_i2c_priv_data[pos]); + data->free_pos &= ~BIT(pos); + + sys_write32(DEV_ADDR_TABLE_LEGACY_I2C_DEV | DEV_ADDR_TABLE_STATIC_ADDR(desc->addr), + config->regs + DEV_ADDR_TABLE_LOC(data->datstartaddr, pos)); + + return 0; +} + +static int dw_i3c_i2c_detach_device(const struct device *dev, struct i3c_i2c_device_desc *desc) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_i2c_dev_data *dw_i2c_device_data = desc->controller_priv; + + if (dw_i2c_device_data == NULL) { + LOG_ERR("%s: device not attached", dev->name); + return -EINVAL; + } + + k_mutex_lock(&data->mt, K_FOREVER); + + sys_write32(0, + config->regs + DEV_ADDR_TABLE_LOC(data->datstartaddr, dw_i2c_device_data->id)); + data->free_pos |= BIT(dw_i2c_device_data->id); + desc->controller_priv = NULL; + + k_mutex_unlock(&data->mt); + + return 0; +} + +static int set_controller_info(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + + uint8_t controller_da = + i3c_addr_slots_next_free_find(&data->common.attached_dev.addr_slots, 0); + LOG_DBG("%s: 0x%02x DA selected for controller", dev->name, controller_da); + + sys_write32(DEVICE_ADDR_DYNAMIC_ADDR_VALID | DEVICE_ADDR_DYNAMIC(controller_da), + config->regs + DEVICE_ADDR); + /* Mark the address as I3C device */ + i3c_addr_slots_mark_i3c(&data->common.attached_dev.addr_slots, controller_da); + + return 0; +} + +static void enable_interrupts(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + uint32_t thld_ctrl; + + config->irq_config_func(); + + thld_ctrl = sys_read32(config->regs + QUEUE_THLD_CTRL); + thld_ctrl &= (~QUEUE_THLD_CTRL_RESP_BUF_MASK & ~QUEUE_THLD_CTRL_IBI_STS_MASK); + sys_write32(thld_ctrl, config->regs + QUEUE_THLD_CTRL); + + thld_ctrl = sys_read32(config->regs + DATA_BUFFER_THLD_CTRL); + thld_ctrl &= ~DATA_BUFFER_THLD_CTRL_RX_BUF; + sys_write32(thld_ctrl, config->regs + DATA_BUFFER_THLD_CTRL); + + sys_write32(INTR_ALL, config->regs + INTR_STATUS); + + sys_write32(INTR_SLAVE_MASK | INTR_MASTER_MASK, config->regs + INTR_STATUS_EN); + sys_write32(INTR_SLAVE_MASK | INTR_MASTER_MASK, config->regs + INTR_SIGNAL_EN); +} + +/** + * @brief Calculate the odd parity of a byte. + * + * This function calculates the odd parity of the input byte, returning 1 if the + * number of set bits is odd and 0 otherwise. + * + * @param p The byte for which odd parity is to be calculated. + * + * @return The odd parity result (1 if odd, 0 if even). + */ +static uint8_t odd_parity(uint8_t p) +{ + p ^= p >> 4; + p &= 0xf; + return (0x9669 >> p) & 1; +} + +/** + * @brief Send Common Command Code (CCC). + * + * @see i3c_do_ccc + * + * @param dev Pointer to controller device driver instance. + * @param payload Pointer to CCC payload. + * + * @return @see i3c_do_ccc + */ +static int dw_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *payload) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_xfer *xfer = &data->xfer; + struct dw_i3c_cmd *cmd; + int ret, i, pos; + uint32_t present_state; + + present_state = sys_read32(config->regs + PRESENT_STATE); + if (!(present_state & PRESENT_STATE_CURRENT_MASTER)) { + return -EACCES; + } + + ret = k_mutex_lock(&data->mt, K_MSEC(1000)); + if (ret) { + LOG_DBG("%s: Mutex err (%d)", dev->name, ret); + return ret; + } + + memset(xfer, 0, sizeof(struct dw_i3c_xfer)); + xfer->ret = -1; + + /* in the case of multiple targets in a CCC, each command queue must have the same CCC ID + * loaded along with different dev index fields pointing to the targets + */ + if (i3c_ccc_is_payload_broadcast(payload)) { + xfer->ncmds = 1; + cmd = &xfer->cmds[0]; + cmd->buf = payload->ccc.data; + + cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(payload->ccc.data_len) | + COMMAND_PORT_TRANSFER_ARG; + cmd->cmd_lo = COMMAND_PORT_CP | COMMAND_PORT_TOC | COMMAND_PORT_ROC | + COMMAND_PORT_CMD(payload->ccc.id); + + if ((payload->targets.payloads) && (payload->targets.payloads[0].rnw)) { + cmd->cmd_lo |= COMMAND_PORT_READ_TRANSFER; + cmd->rx_len = payload->ccc.data_len; + } else { + cmd->tx_len = payload->ccc.data_len; + } + } else { + if (!(payload->targets.payloads)) { + LOG_ERR("%s: Direct CCC Payload structure Empty", dev->name); + ret = -EINVAL; + goto error; + } + xfer->ncmds = payload->targets.num_targets; + for (i = 0; i < payload->targets.num_targets; i++) { + cmd = &xfer->cmds[i]; + /* Look up position, SETDASA will perform the look up by static addr */ + pos = get_i3c_addr_pos(dev, payload->targets.payloads[i].addr, + payload->ccc.id == I3C_CCC_SETDASA); + if (pos < 0) { + LOG_ERR("%s: Invalid Slave address with pos %d", dev->name, pos); + ret = -ENOSPC; + goto error; + } + cmd->buf = payload->targets.payloads[i].data; + + cmd->cmd_hi = + COMMAND_PORT_ARG_DATA_LEN(payload->targets.payloads[i].data_len) | + COMMAND_PORT_TRANSFER_ARG; + cmd->cmd_lo = COMMAND_PORT_CP | COMMAND_PORT_DEV_INDEX(pos) | + COMMAND_PORT_ROC | COMMAND_PORT_CMD(payload->ccc.id); + /* last command queue with multiple targets must have TOC set */ + if (i == (payload->targets.num_targets - 1)) { + cmd->cmd_lo |= COMMAND_PORT_TOC; + } + /* If there is a defining byte for direct CCC */ + if (payload->ccc.data_len == 1) { + cmd->cmd_lo |= COMMAND_PORT_DBP; + cmd->cmd_hi |= COMMAND_PORT_ARG_DB(payload->ccc.data[0]); + } else if (payload->ccc.data_len > 1) { + LOG_ERR("%s: direct CCCs defining byte >1", dev->name); + ret = -EINVAL; + goto error; + } + + if (payload->targets.payloads[i].rnw) { + cmd->cmd_lo |= COMMAND_PORT_READ_TRANSFER; + cmd->rx_len = payload->targets.payloads[i].data_len; + } else { + cmd->tx_len = payload->targets.payloads[i].data_len; + } + } + } + + start_xfer(dev); + + ret = k_sem_take(&data->sem_xfer, K_MSEC(1000)); + if (ret) { + LOG_ERR("%s: Semaphore err (%d)", dev->name, ret); + goto error; + } + + /* the only way data_len would not equal num_xfer would be if an abort happened */ + payload->ccc.num_xfer = payload->ccc.data_len; + for (i = 0; i < xfer->ncmds; i++) { + /* if this is a direct ccc, then write back the number of bytes tx or rx */ + if (!i3c_ccc_is_payload_broadcast(payload)) { + payload->targets.payloads[i].num_xfer = payload->targets.payloads[i].rnw + ? xfer->cmds[i].rx_len + : xfer->cmds[i].tx_len; + } + if (xfer->cmds[i].rx_len && !xfer->cmds[i].error) { + read_rx_fifo(dev, xfer->cmds[i].buf, xfer->cmds[i].rx_len); + } + } + + ret = xfer->ret; +error: + k_mutex_unlock(&data->mt); + + return ret; +} + +/** + * @brief Add a slave device from Dynamic Address Assignment (DAA) information. + * + * This function adds a slave device to the I3C controller based on the Dynamic + * Address Assignment (DAA) information at the specified position. It retrieves + * the dynamic address, PID (Provisional ID), and additional device characteristics + * from the corresponding tables and associates the device with a registered device + * descriptor if the PID is known. + * + * @param dev Pointer to the I3C device structure. + * @param pos Position of the device in the DAA and DCT tables. + * + * @return 0 on success, or a negative error code on failure. + */ +static int add_slave_from_daa(const struct device *dev, int32_t pos) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + uint32_t tmp; + uint64_t pid; + uint8_t dyn_addr; + + /* retrieve dynamic address assigned */ + tmp = sys_read32(config->regs + DEV_ADDR_TABLE_LOC(data->datstartaddr, pos)); + dyn_addr = (((tmp) & GENMASK(22, 16)) >> 16); + + /* retrieve pid */ + tmp = sys_read32(config->regs + DEV_CHAR_TABLE_LOC1(data->dctstartaddr, pos)); + pid = ((uint64_t)DEV_CHAR_TABLE_MSB_PID(tmp) << 16) + (DEV_CHAR_TABLE_LSB_PID(tmp) << 16); + tmp = sys_read32(config->regs + DEV_CHAR_TABLE_LOC2(data->dctstartaddr, pos)); + pid |= DEV_CHAR_TABLE_LSB_PID(tmp); + + /* lookup known pids */ + const struct i3c_device_id i3c_id = I3C_DEVICE_ID(pid); + struct i3c_device_desc *target = i3c_device_find(dev, &i3c_id); + + if (target == NULL) { + LOG_INF("%s: PID 0x%012llx is not in registered device " + "list, given DA 0x%02x", + dev->name, pid, dyn_addr); + } else { + target->dynamic_addr = dyn_addr; + tmp = sys_read32(config->regs + DEV_CHAR_TABLE_LOC3(data->dctstartaddr, pos)); + target->bcr = DEV_CHAR_TABLE_BCR(tmp); + target->dcr = DEV_CHAR_TABLE_DCR(tmp); + + LOG_DBG("%s: PID 0x%012llx assigned dynamic address 0x%02x", dev->name, pid, + dyn_addr); + } + i3c_addr_slots_mark_i3c(&data->common.attached_dev.addr_slots, dyn_addr); + + return 0; +} + +/** + * @brief Perform Dynamic Address Assignment. + * + * @see i3c_do_daa + * + * @param dev Pointer to controller device driver instance. + * + * @return @see i3c_do_daa + */ +static int dw_i3c_do_daa(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_xfer *xfer = &data->xfer; + struct dw_i3c_cmd *cmd; + uint32_t olddevs, newdevs; + uint8_t p, idx, last_addr = 0; + int32_t pos, addr, ret; + uint32_t present_state; + + present_state = sys_read32(config->regs + PRESENT_STATE); + if (!(present_state & PRESENT_STATE_CURRENT_MASTER)) { + return -EACCES; + } + + olddevs = ~(data->free_pos); + + /* Prepare DAT before launching DAA. */ + for (pos = 0; pos < data->maxdevs; pos++) { + if (olddevs & BIT(pos)) { + continue; + } + + addr = i3c_addr_slots_next_free_find(&data->common.attached_dev.addr_slots, + last_addr + 1); + if (addr == 0) { + return -ENOSPC; + } + + p = odd_parity(addr); + last_addr = addr; + addr |= (p << 7); + sys_write32(DEV_ADDR_TABLE_DYNAMIC_ADDR(addr), + config->regs + DEV_ADDR_TABLE_LOC(data->datstartaddr, pos)); + } + + pos = get_free_pos(data->free_pos); + if (pos < 0) { + LOG_ERR("%s: find free pos failed", dev->name); + return -ENOSPC; + } + + ret = k_mutex_lock(&data->mt, K_MSEC(1000)); + if (ret) { + LOG_ERR("%s: Mutex err (%d)", dev->name, ret); + return ret; + } + memset(xfer, 0, sizeof(struct dw_i3c_xfer)); + + xfer->ncmds = 1; + xfer->ret = -1; + + cmd = &xfer->cmds[0]; + cmd->cmd_hi = COMMAND_PORT_TRANSFER_ARG; + cmd->cmd_lo = COMMAND_PORT_TOC | COMMAND_PORT_ROC | + COMMAND_PORT_DEV_COUNT(data->maxdevs - pos) | COMMAND_PORT_DEV_INDEX(pos) | + COMMAND_PORT_CMD(I3C_CCC_ENTDAA) | COMMAND_PORT_ADDR_ASSGN_CMD; + + start_xfer(dev); + ret = k_sem_take(&data->sem_xfer, K_MSEC(1000)); + if (ret) { + LOG_ERR("%s: Semaphore err (%d)", dev->name, ret); + k_mutex_unlock(&data->mt); + return ret; + } + + k_mutex_unlock(&data->mt); + + if (data->maxdevs == cmd->rx_len) { + newdevs = 0; + } else { + newdevs = GENMASK(data->maxdevs - cmd->rx_len - 1, 0); + } + newdevs &= ~olddevs; + + for (pos = find_lsb_set(newdevs); pos <= find_msb_set(newdevs); pos++) { + idx = pos - 1; + if (newdevs & BIT(idx)) { + add_slave_from_daa(dev, idx); + } + } + + return 0; +} + +static void dw_i3c_enable_controller(const struct dw_i3c_config *config, bool enable) +{ + uint32_t reg = sys_read32(config->regs + DEVICE_CTRL); + + if (enable) { + reg |= DEV_CTRL_ENABLE; + } else { + reg &= ~DEV_CTRL_ENABLE; + } + + sys_write32(reg, config->regs + DEVICE_CTRL); +} + +/** + * @brief Get configuration of the I3C hardware. + * + * This provides a way to get the current configuration of the I3C hardware. + * + * This can return cached config or probed hardware parameters, but it has to + * be up to date with current configuration. + * + * @param[in] dev Pointer to controller device driver instance. + * @param[in] type Type of configuration parameters being passed + * in @p config. + * @param[in,out] config Pointer to the configuration parameters. + * + * Note that if @p type is @c I3C_CONFIG_CUSTOM, @p config must contain + * the ID of the parameter to be retrieved. + * + * @retval 0 If successful. + * @retval -EIO General Input/Output errors. + * @retval -ENOSYS If not implemented. + */ +static int dw_i3c_config_get(const struct device *dev, enum i3c_config_type type, void *config) +{ + const struct dw_i3c_config *dev_config = dev->config; + struct dw_i3c_data *data = dev->data; + int ret = 0; + + if (type == I3C_CONFIG_CONTROLLER) { + (void)memcpy(config, &data->common.ctrl_config, sizeof(data->common.ctrl_config)); + } else if (type == I3C_CONFIG_TARGET) { + struct i3c_config_target *target_config = config; + uint32_t reg; + + reg = sys_read32(dev_config->regs + SLV_MAX_LEN); + target_config->max_read_len = SLV_MAX_LEN_MRL(reg); + target_config->max_write_len = SLV_MAX_LEN_MWL(reg); + + reg = sys_read32(dev_config->regs + DEVICE_ADDR); + if (reg & DEVICE_ADDR_STATIC_ADDR_VALID) { + target_config->static_addr = DEVICE_ADDR_STATIC(reg); + } else { + target_config->static_addr = 0x00; + } + + reg = sys_read32(dev_config->regs + SLV_CHAR_CTRL); + target_config->bcr = SLV_CHAR_CTRL_BCR(reg); + target_config->dcr = SLV_CHAR_CTRL_DCR(reg); + target_config->supported_hdr = SLV_CHAR_CTRL_HDR_CAP(reg); + + reg = sys_read32(dev_config->regs + SLV_MIPI_ID_VALUE); + target_config->pid = ((uint64_t)reg) << 32; + target_config->pid_random = (bool)!!(reg & SLV_MIPI_ID_VALUE_SLV_PROV_ID_SEL); + reg = sys_read32(dev_config->regs + SLV_PID_VALUE); + target_config->pid |= reg; + + if (!(sys_read32(dev_config->regs + PRESENT_STATE) & + PRESENT_STATE_CURRENT_MASTER)) { + target_config->enable = true; + } else { + target_config->enable = false; + } + } else { + return -EINVAL; + } + + return ret; +} + +/** + * @brief Configure I3C hardware. + * + * @param dev Pointer to controller device driver instance. + * @param type Type of configuration parameters being passed + * in @p config. + * @param config Pointer to the configuration parameters. + * + * @retval 0 If successful. + * @retval -EINVAL If invalid configure parameters. + * @retval -EIO General Input/Output errors. + * @retval -ENOSYS If not implemented. + */ +static int dw_i3c_configure(const struct device *dev, enum i3c_config_type type, void *config) +{ + const struct dw_i3c_config *dev_config = dev->config; + + if (type == I3C_CONFIG_CONTROLLER) { + /* struct i3c_config_controller *ctrl_cfg = config; */ + /* TODO: somehow determine i3c rate? snps is complicated */ + return -ENOTSUP; + } else if (type == I3C_CONFIG_TARGET) { + struct i3c_config_target *target_cfg = config; + uint32_t val; + + /* TODO: some how randomly generate pid */ + if (target_cfg->pid_random) { + return -EINVAL; + } + + val = SLV_MAX_LEN_MWL(target_cfg->max_write_len) | + (SLV_MAX_LEN_MRL(target_cfg->max_read_len) << 16); + sys_write32(val, dev_config->regs + SLV_MAX_LEN); + + /* set static address */ + val = sys_read32(dev_config->regs + DEVICE_ADDR); + /* if static address is set to 0x00, then disable static_addr_en */ + if (target_cfg->static_addr != 0x00) { + val |= DEVICE_ADDR_STATIC_ADDR_VALID; + } else { + val &= ~DEVICE_ADDR_STATIC_ADDR_VALID; + } + val &= ~DEVICE_ADDR_STATIC_MASK; + val |= DEVICE_ADDR_STATIC(target_cfg->static_addr); + sys_write32(val, dev_config->regs + DEVICE_ADDR); + + val = sys_read32(dev_config->regs + SLV_CHAR_CTRL); + val &= ~(SLV_CHAR_CTRL_BCR_MASK | SLV_CHAR_CTRL_DCR_MASK); + /* Bridge identifier, offline capable, ibi_payload, ibi_request_capable can not be + * written to in bcr + */ + val |= SLV_CHAR_CTRL_BCR(target_cfg->bcr); + val |= SLV_CHAR_CTRL_DCR(target_cfg->dcr) << 8; + /* HDR CAPs is not settable */ + sys_write32(val, dev_config->regs + SLV_CHAR_CTRL); + + val = sys_read32(dev_config->regs + SLV_MIPI_ID_VALUE); + val &= ~(SLV_MIPI_ID_VALUE_SLV_MIPI_MFG_ID_MASK | + SLV_MIPI_ID_VALUE_SLV_PROV_ID_SEL); + val |= (uint32_t)(target_cfg->pid >> 16); + sys_write32(val, dev_config->regs + SLV_MIPI_ID_VALUE); + + val = (uint32_t)(target_cfg->pid & 0xFFFFFFFF); + sys_write32(val, dev_config->regs + SLV_PID_VALUE); + } + + return 0; +} + +/** + * @brief Find a registered I3C target device. + * + * This returns the I3C device descriptor of the I3C device + * matching the incoming @p id. + * + * @param dev Pointer to controller device driver instance. + * @param id Pointer to I3C device ID. + * + * @return @see i3c_device_find. + */ +static struct i3c_device_desc *dw_i3c_device_find(const struct device *dev, + const struct i3c_device_id *id) +{ + const struct dw_i3c_config *config = dev->config; + + return i3c_dev_list_find(&config->common.dev_list, id); +} + +/** + * @brief Writes to the Target's TX FIFO + * + * The Synopsys I3C will then ACK read requests to it's TX FIFO from a + * Controller, if there is no tx cmd in cmd Q. Then it will NACK. + * + * @param dev Pointer to the device structure for an I3C controller + * driver configured in target mode. + * @param buf Pointer to the buffer + * @param len Length of the buffer + * + * @retval Total number of bytes written + * @retval -EACCES Not in Target Mode + * @retval -ENOSPC No space in Tx FIFO + */ +static int dw_i3c_target_tx_write(const struct device *dev, uint8_t *buf, uint16_t len, + uint8_t hdr_mode) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct dw_i3c_xfer *xfer = &data->xfer; + uint32_t present_state; + + /* check if we are in target mode */ + present_state = sys_read32(config->regs + PRESENT_STATE); + if (present_state & PRESENT_STATE_CURRENT_MASTER) { + return -EACCES; + } + + /* + * TODO: if len is greater than fifo size, then it will need to be written to based + * on the threshold interrupt + */ + if (len > (data->txfifodepth * BYTES_PER_DWORD)) { + return -ENOSPC; + } + + k_mutex_lock(&data->mt, K_FOREVER); + + if ((hdr_mode == 0) || (hdr_mode & data->common.ctrl_config.supported_hdr)) { + /* Write to CMD */ + memset(xfer, 0, sizeof(struct dw_i3c_xfer)); + xfer->ncmds = 1; + + /* TODO: write_tx_fifo needs to check that the fifo doesn't fill up */ + struct dw_i3c_cmd *cmd = &xfer->cmds[0]; + + cmd->cmd_hi = 0; + cmd->cmd_lo = COMMAND_PORT_TID(0) | COMMAND_PORT_ARG_DATA_LEN(len); + cmd->buf = buf; + cmd->tx_len = len; + + start_xfer(dev); + } else { + k_mutex_unlock(&data->mt); + LOG_ERR("%s: Unsupported HDR Mode %d", dev->name, hdr_mode); + return -ENOTSUP; + } + + k_mutex_unlock(&data->mt); + + /* return total bytes written */ + return (int)len; +} + +/** + * @brief Instructs the I3C Target device to register itself to the I3C Controller + * + * This routine instructs the I3C Target device to register itself to the I3C + * Controller via its parent controller's i3c_target_register() API. + * + * @param dev Pointer to target device driver instance. + * @param cfg Config struct with functions and parameters used by the I3C driver + * to send bus events + * + * @return @see i3c_device_find. + */ +static int dw_i3c_target_register(const struct device *dev, struct i3c_target_config *cfg) +{ + struct dw_i3c_data *data = dev->data; + + data->target_config = cfg; + return 0; +} + +/** + * @brief Unregisters the provided config as Target device + * + * This routine disables I3C target mode for the 'dev' I3C bus driver using + * the provided 'config' struct containing the functions and parameters + * to send bus events. + * + * @param dev Pointer to target device driver instance. + * @param cfg Config struct with functions and parameters used by the I3C driver + * to send bus events + * + * @return @see i3c_device_find. + */ +static int dw_i3c_target_unregister(const struct device *dev, struct i3c_target_config *cfg) +{ + /* no way to disable? maybe write DA to 0? */ + return 0; +} + +static int dw_i3c_init(const struct device *dev) +{ + const struct dw_i3c_config *config = dev->config; + struct dw_i3c_data *data = dev->data; + struct i3c_config_controller *ctrl_config = &data->common.ctrl_config; + int ret; + uint32_t hw_capabilities; + uint32_t queue_capability; + uint32_t device_ctrl_ext; + + if (!device_is_ready(config->clock)) { + return -ENODEV; + } + + ret = clock_control_on(config->clock, NULL); + if (ret < 0) { + return ret; + } + +#ifdef CONFIG_I3C_USE_IBI + k_sem_init(&data->ibi_sts_sem, 0, 1); +#endif + k_sem_init(&data->sem_xfer, 0, 1); + k_mutex_init(&data->mt); + + data->mode = i3c_bus_mode(&config->common.dev_list); + + /* reset all */ + sys_write32(RESET_CTRL_ALL, config->regs + RESET_CTRL); + + /* get DAT, DCT pointer */ + data->datstartaddr = + DEVICE_ADDR_TABLE_ADDR(sys_read32(config->regs + DEVICE_ADDR_TABLE_POINTER)); + data->dctstartaddr = + DEVICE_CHAR_TABLE_ADDR(sys_read32(config->regs + DEV_CHAR_TABLE_POINTER)); + + /* get max devices based on table depth */ + data->maxdevs = + DEVICE_ADDR_TABLE_DEPTH(sys_read32(config->regs + DEVICE_ADDR_TABLE_POINTER)); + data->free_pos = GENMASK(data->maxdevs - 1, 0); + + /* get fifo sizes */ + queue_capability = sys_read32(config->regs + QUEUE_SIZE_CAPABILITY); + data->txfifodepth = QUEUE_SIZE_CAPABILITY_TX_BUF_DWORD_SIZE(queue_capability); + data->rxfifodepth = QUEUE_SIZE_CAPABILITY_RX_BUF_DWORD_SIZE(queue_capability); + data->cmdfifodepth = QUEUE_SIZE_CAPABILITY_CMD_BUF_DWORD_SIZE(queue_capability); + data->respfifodepth = QUEUE_SIZE_CAPABILITY_RESP_BUF_DWORD_SIZE(queue_capability); + data->ibififodepth = QUEUE_SIZE_CAPABILITY_IBI_BUF_DWORD_SIZE(queue_capability); + + /* get HDR capabilities */ + ctrl_config->supported_hdr = 0; + hw_capabilities = sys_read32(config->regs + HW_CAPABILITY); + if (hw_capabilities & HW_CAPABILITY_HDR_TS_EN) { + ctrl_config->supported_hdr |= I3C_MSG_HDR_TSP | I3C_MSG_HDR_TSL; + } + if (hw_capabilities & HW_CAPABILITY_HDR_DDR_EN) { + ctrl_config->supported_hdr |= I3C_MSG_HDR_DDR; + } + + /* if the boot condition starts as a target, then it's a secondary controller */ + device_ctrl_ext = sys_read32(config->regs + DEVICE_CTRL_EXTENDED); + if (DEVICE_CTRL_EXTENDED_DEV_OPERATION_MODE(device_ctrl_ext) & + DEVICE_CTRL_EXTENDED_DEV_OPERATION_MODE_SLAVE) { + ctrl_config->is_secondary = true; + } else { + ctrl_config->is_secondary = false; + } + + ret = init_scl_timing(dev); + if (ret != 0) { + return ret; + } + + enable_interrupts(dev); + + /* disable ibi */ + sys_write32(IBI_REQ_REJECT_ALL, config->regs + IBI_SIR_REQ_REJECT); + sys_write32(IBI_REQ_REJECT_ALL, config->regs + IBI_MR_REQ_REJECT); + + /* disable hot-join */ + sys_write32(sys_read32(config->regs + DEVICE_CTRL) | (DEV_CTRL_HOT_JOIN_NACK), + config->regs + DEVICE_CTRL); + + ret = i3c_addr_slots_init(dev); + if (ret != 0) { + return ret; + } + + dw_i3c_enable_controller(config, true); + + if (!(ctrl_config->is_secondary)) { + ret = set_controller_info(dev); + if (ret) { + return ret; + } + /* Perform bus initialization */ + ret = i3c_bus_init(dev, &config->common.dev_list); + /* Bus Initialization Complete, allow HJ ACKs */ + sys_write32(sys_read32(config->regs + DEVICE_CTRL) & ~(DEV_CTRL_HOT_JOIN_NACK), + config->regs + DEVICE_CTRL); + } + + return 0; +} + +static DEVICE_API(i3c, dw_i3c_api) = { + .i2c_api.transfer = dw_i3c_i2c_api_transfer, + + .configure = dw_i3c_configure, + .config_get = dw_i3c_config_get, + + .attach_i3c_device = dw_i3c_attach_device, + .reattach_i3c_device = dw_i3c_reattach_device, + .detach_i3c_device = dw_i3c_detach_device, + .attach_i2c_device = dw_i3c_i2c_attach_device, + .detach_i2c_device = dw_i3c_i2c_detach_device, + + .do_daa = dw_i3c_do_daa, + .do_ccc = dw_i3c_do_ccc, + + .i3c_device_find = dw_i3c_device_find, + + .i3c_xfers = dw_i3c_xfers, + + .target_tx_write = dw_i3c_target_tx_write, + .target_register = dw_i3c_target_register, + .target_unregister = dw_i3c_target_unregister, + +#ifdef CONFIG_I3C_USE_IBI + .ibi_hj_response = dw_i3c_controller_ibi_hj_response, + .ibi_enable = dw_i3c_controller_enable_ibi, + .ibi_disable = dw_i3c_controller_disable_ibi, + .ibi_raise = dw_i3c_target_ibi_raise, +#endif /* CONFIG_I3C_USE_IBI */ +}; + +#define I3C_DW_IRQ_HANDLER(n) \ + static void i3c_dw_irq_config_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), i3c_dw_irq, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } + +#define DEFINE_DEVICE_FN(n) \ + I3C_DW_IRQ_HANDLER(n) \ + static struct i3c_device_desc dw_i3c_device_array_##n[] = I3C_DEVICE_ARRAY_DT_INST(n); \ + static struct i3c_i2c_device_desc dw_i3c_i2c_device_array_##n[] = \ + I3C_I2C_DEVICE_ARRAY_DT_INST(n); \ + static struct dw_i3c_data dw_i3c_data_##n = { \ + .common.ctrl_config.scl.i3c = \ + DT_INST_PROP_OR(n, i3c_scl_hz, I3C_BUS_TYP_I3C_SCL_RATE), \ + .common.ctrl_config.scl.i2c = DT_INST_PROP_OR(n, i2c_scl_hz, 0), \ + }; \ + static const struct dw_i3c_config dw_i3c_cfg_##n = { \ + .regs = DT_INST_REG_ADDR(n), \ + .clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .od_thigh_max_ns = DT_INST_PROP(n, od_thigh_max_ns), \ + .od_tlow_min_ns = DT_INST_PROP(n, od_tlow_min_ns), \ + .irq_config_func = &i3c_dw_irq_config_##n, \ + .common.dev_list.i3c = dw_i3c_device_array_##n, \ + .common.dev_list.num_i3c = ARRAY_SIZE(dw_i3c_device_array_##n), \ + .common.dev_list.i2c = dw_i3c_i2c_device_array_##n, \ + .common.dev_list.num_i2c = ARRAY_SIZE(dw_i3c_i2c_device_array_##n), \ + }; \ + DEVICE_DT_INST_DEFINE(n, dw_i3c_init, NULL, &dw_i3c_data_##n, &dw_i3c_cfg_##n, \ + POST_KERNEL, CONFIG_I3C_CONTROLLER_INIT_PRIORITY, &dw_i3c_api); + +#define DT_DRV_COMPAT snps_designware_i3c +DT_INST_FOREACH_STATUS_OKAY(DEFINE_DEVICE_FN); diff --git a/dts/bindings/i3c/snps,designware-i3c.yaml b/dts/bindings/i3c/snps,designware-i3c.yaml new file mode 100644 index 0000000000000..b323ebd5e6b9c --- /dev/null +++ b/dts/bindings/i3c/snps,designware-i3c.yaml @@ -0,0 +1,30 @@ +# Copyright (C) 2020 Samsung Electronics Co., Ltd. +# Copyright (C) 2023 Meta Platforms +# SPDX-License-Identifier: Apache-2.0 + +description: > + This is a binding for the Synopsys I3C interface + +compatible: "snps,designware-i3c" + +include: i3c-controller.yaml + +properties: + clocks: + required: true + + od-thigh-max-ns: + type: int + default: 41 + description: | + Maximum high clock pulse length (ns) in Open-Drain mode. + The default is value from Section 6.2 of the I3C + Specifiction. + + od-tlow-min-ns: + type: int + default: 200 + description: | + Minimum low clock pulse length (ns) in Open-Drain mode. + The default is value from Section 6.2 of the I3C + Specifiction. diff --git a/include/zephyr/drivers/i3c.h b/include/zephyr/drivers/i3c.h index 34b43f5a719cd..8ca331f0675a7 100644 --- a/include/zephyr/drivers/i3c.h +++ b/include/zephyr/drivers/i3c.h @@ -1263,6 +1263,21 @@ struct i3c_device_desc *i3c_dev_list_find(const struct i3c_dev_list *dev_list, struct i3c_device_desc *i3c_dev_list_i3c_addr_find(const struct device *dev, uint8_t addr); +/** + * @brief Find a I3C target device descriptor by static address. + * + * This finds the I3C target device descriptor in the attached + * device list matching the static address (@p addr) + * + * @param dev Pointer to controller device driver instance. + * @param addr static address to be matched. + * + * @return Pointer to the I3C target device descriptor, or + * `NULL` if none is found. + */ +struct i3c_device_desc *i3c_dev_list_i3c_static_addr_find(const struct device *dev, + uint8_t addr); + /** * @brief Find a I2C target device descriptor by address. * From 534c4148a9ef3cc260cb7c66a63cbbd4ad21b4bb Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Thu, 9 May 2024 15:06:47 -0700 Subject: [PATCH 0105/6055] drivers: i3c: add snps_designware_i3c to i3c shell add the synopsys designware i3c to the i3c shell. Signed-off-by: Ryan McClelland --- drivers/i3c/i3c_shell.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i3c/i3c_shell.c b/drivers/i3c/i3c_shell.c index d440c5f7eb4ea..95ba3f1c117ff 100644 --- a/drivers/i3c/i3c_shell.c +++ b/drivers/i3c/i3c_shell.c @@ -82,6 +82,7 @@ struct i3c_ctrl { 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) +DT_FOREACH_STATUS_OKAY(snps_designware_i3c, I3C_CTRL_FN) DT_FOREACH_STATUS_OKAY(st_stm32_i3c, I3C_CTRL_FN) /* zephyr-keep-sorted-stop */ @@ -97,6 +98,7 @@ const struct i3c_ctrl i3c_list[] = { 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) + DT_FOREACH_STATUS_OKAY(snps_designware_i3c, I3C_CTRL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(st_stm32_i3c, I3C_CTRL_LIST_ENTRY) /* zephyr-keep-sorted-stop */ }; From ed9c6d84a9e301922720e40809341101c1d3c40c Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Thu, 13 Feb 2025 10:28:14 -0800 Subject: [PATCH 0106/6055] tests: drivers: build_all: add build for i3c_dw The Synopsys I3C has no in-tree board with it to built with. This adds a test build-only for the cadence i3c peripheral attaching with the qemu_cortex_m3 board as that appears to be generic enough. Signed-off-by: Ryan McClelland --- .../i3c/boards/qemu_cortex_m3.overlay | 18 ++++++++++++++++++ tests/drivers/build_all/i3c/prj.conf | 2 ++ tests/drivers/build_all/i3c/testcase.yaml | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/drivers/build_all/i3c/boards/qemu_cortex_m3.overlay b/tests/drivers/build_all/i3c/boards/qemu_cortex_m3.overlay index 43c6d81d4035b..f3508335ec562 100644 --- a/tests/drivers/build_all/i3c/boards/qemu_cortex_m3.overlay +++ b/tests/drivers/build_all/i3c/boards/qemu_cortex_m3.overlay @@ -5,6 +5,12 @@ */ / { + test_fixed_clk: test-fixed-clock { + compatible = "fixed-clock"; + clock-frequency = <200000000>; + #clock-cells = <0>; + }; + i3c0: i3c@88888888 { compatible = "cdns,i3c"; #address-cells = <3>; @@ -16,4 +22,16 @@ i3c-scl-hz = <12500000>; i2c-scl-hz = <400000>; }; + + i3c1: i3c@cccccccc { + compatible = "snps,designware-i3c"; + #address-cells = <3>; + #size-cells = <0>; + reg = <0xcccccccc 0x400>; + interrupt-parent = <&nvic>; + interrupts = <8 1>; + clocks = <&test_fixed_clk>; + i3c-scl-hz = <12500000>; + i2c-scl-hz = <400000>; + }; }; diff --git a/tests/drivers/build_all/i3c/prj.conf b/tests/drivers/build_all/i3c/prj.conf index cf064b0a058d6..0039adf252baf 100644 --- a/tests/drivers/build_all/i3c/prj.conf +++ b/tests/drivers/build_all/i3c/prj.conf @@ -4,3 +4,5 @@ CONFIG_I3C=y CONFIG_SHELL=y CONFIG_I3C_SHELL=y CONFIG_I3C_RTIO=y +CONFIG_CLOCK_CONTROL=y +CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK=y diff --git a/tests/drivers/build_all/i3c/testcase.yaml b/tests/drivers/build_all/i3c/testcase.yaml index 4c4ed78c84046..b4e42b05ce273 100644 --- a/tests/drivers/build_all/i3c/testcase.yaml +++ b/tests/drivers/build_all/i3c/testcase.yaml @@ -7,5 +7,5 @@ tests: drivers.i3c.build: # will cover drivers without in-tree boards platform_allow: qemu_cortex_m3 - tags: i3c_cdns + tags: i3c_cdns i3c_dw extra_args: "CONFIG_I3C=y" From cb8f99ab7ab809548ceba6033690f4ac24ea0c67 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 12 Feb 2025 14:58:43 +0100 Subject: [PATCH 0107/6055] cmake: code relocation setting. With code relocation directives passed to the gen_relocate_app.py script using generated file, then each directive can be place on individual line in the file and thus free up the `|` character as separator. Furthermore, a multi-line file with each directive on separate line is also more user-readable, making debugging easier. Signed-off-by: Torsten Rasmussen --- cmake/modules/extensions.cmake | 4 ++-- scripts/build/gen_relocate_app.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 6df0ef51f67be..22e72ff63560e 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1522,7 +1522,7 @@ function(zephyr_code_relocate) if(CODE_REL_PHDR) set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}") endif() - # We use the "|" character to separate code relocation directives, instead of + # Each code relocation directive is placed on an independent line, instead of # using set_property(APPEND) to produce a ";"-separated CMake list. This way, # each directive can embed multiple CMake lists, representing flags and files, # the latter of which can come from generator expressions. @@ -1530,7 +1530,7 @@ function(zephyr_code_relocate) PROPERTY INTERFACE_SOURCES) set_property(TARGET code_data_relocation_target PROPERTY INTERFACE_SOURCES - "${code_rel_str}|${CODE_REL_LOCATION}:${flag_list}:${file_list}") + "${code_rel_str}\n${CODE_REL_LOCATION}:${flag_list}:${file_list}") endfunction() # Usage: diff --git a/scripts/build/gen_relocate_app.py b/scripts/build/gen_relocate_app.py index f1bcccf1df699..95cb0e557b9d2 100755 --- a/scripts/build/gen_relocate_app.py +++ b/scripts/build/gen_relocate_app.py @@ -526,10 +526,10 @@ def create_dict_wrt_mem(): rel_dict = dict() phdrs = dict() - input_rel_dict = args.input_rel_dict.read() - if input_rel_dict == '': + input_rel_dict = args.input_rel_dict.read().splitlines() + if not input_rel_dict: sys.exit("Disable CONFIG_CODE_DATA_RELOCATION if no file needs relocation") - for line in input_rel_dict.split('|'): + for line in input_rel_dict: if ':' not in line: continue From 4454734d127ad5519c2f8d72e002d5471add4d24 Mon Sep 17 00:00:00 2001 From: Sylvain Chouleur Date: Mon, 17 Jun 2024 12:11:04 +0200 Subject: [PATCH 0108/6055] scripts: code_relocate: support section filter One might want to select the symbols to be relocated inside a file or a library. To do this, one can use the FILTER argument of zephyr_code_relocate which must contain a regular expression of the section names to be selected for relocation. The test_function_in_sram2 test case in `tests/application_development/code_relocation` has been updated to verify that only one function `function_in_sram()` is relocated to ram and that the function `function_not_relocated()` is not being relocated when using relocation filter. Signed-off-by: Sylvain Chouleur Signed-off-by: Torsten Rasmussen --- cmake/modules/extensions.cmake | 4 +- doc/kernel/code-relocation.rst | 34 ++++++++++-- scripts/build/gen_relocate_app.py | 54 ++++++++++++------- .../code_relocation/CMakeLists.txt | 2 +- .../code_relocation/src/test_file1.c | 16 ++++++ .../code_relocation/src/test_file2.c | 11 ++++ 6 files changed, 95 insertions(+), 26 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 22e72ff63560e..51726a3b7ec04 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1453,7 +1453,7 @@ endmacro() # - PHDR [program_header]: add program header. Used on Xtensa platforms. function(zephyr_code_relocate) set(options NOCOPY NOKEEP) - set(single_args LIBRARY LOCATION PHDR) + set(single_args LIBRARY LOCATION PHDR FILTER) set(multi_args FILES) cmake_parse_arguments(CODE_REL "${options}" "${single_args}" "${multi_args}" ${ARGN}) @@ -1530,7 +1530,7 @@ function(zephyr_code_relocate) PROPERTY INTERFACE_SOURCES) set_property(TARGET code_data_relocation_target PROPERTY INTERFACE_SOURCES - "${code_rel_str}\n${CODE_REL_LOCATION}:${flag_list}:${file_list}") + "${code_rel_str}\n${CODE_REL_LOCATION}:${flag_list}:${file_list},${CODE_REL_FILTER}") endfunction() # Usage: diff --git a/doc/kernel/code-relocation.rst b/doc/kernel/code-relocation.rst index aea6e11793d4b..c3b8aced76ecc 100644 --- a/doc/kernel/code-relocation.rst +++ b/doc/kernel/code-relocation.rst @@ -14,15 +14,23 @@ This script provides a robust way to re-order the memory contents without actually having to modify the code. In simple terms this script will do the job of ``__attribute__((section("name")))`` for a bunch of files together. +A regular expression filter can be used to select only the required sections to be relocated. + Details ******* -The memory region and file are given to the :ref:`gen_relocate_app.py` script in the form of a string. +The memory region and file are given to the :ref:`gen_relocate_app.py` script +through a file where each line specifies a list of files to be placed in the +given region. + +An example of such a file is: + + .. code-block:: none -An example of such a string is: -``SRAM2:/home/xyz/zephyr/samples/hello_world/src/main.c,SRAM1:/home/xyz/zephyr/samples/hello_world/src/main2.c`` + SRAM2:/home/xyz/zephyr/samples/hello_world/src/main.c, + SRAM1:/home/xyz/zephyr/samples/hello_world/src/main2.c, This script is invoked with the following parameters: -``python3 gen_relocate_app.py -i input_string -o generated_linker -c generated_code`` +``python3 gen_relocate_app.py -i input_file -o generated_linker -c generated_code`` Kconfig :kconfig:option:`CONFIG_CODE_DATA_RELOCATION` option, when enabled in ``prj.conf``, will invoke the script and do the required relocation. @@ -97,6 +105,24 @@ This section shows additional configuration options that can be set in zephyr_code_relocate(FILES ${sources} LOCATION SRAM) zephyr_code_relocate(FILES $ LOCATION SRAM) +Section Filtering +================= + +By default, all sections of the specified files will be relocated. If +``FILTER`` is used, a regular expression is provided to select only +the sections to be relocated. + +The regular expression applies to sections names which can be used to +select the file's symbols when this one has been built with +``-ffunction-sections`` and ``-fdata-sections`` which is the case by +default. + + .. code-block:: none + + zephyr_code_relocate(FILES src/file1.c FILTER ".*\\.func1|.*\\.func2" LOCATION SRAM2_TEXT) + +The example above will only relocate ``func1()`` and ``func2()`` of file ``src/file1.c`` + NOKEEP flag =========== diff --git a/scripts/build/gen_relocate_app.py b/scripts/build/gen_relocate_app.py index 95cb0e557b9d2..48ef8a4bf95cf 100755 --- a/scripts/build/gen_relocate_app.py +++ b/scripts/build/gen_relocate_app.py @@ -8,21 +8,22 @@ """ This script will relocate .text, .rodata, .data and .bss sections from required files and places it in the required memory region. This memory region and file -are given to this python script in the form of a string. +are given to this python script in the form of a file. +A regular expression filter can be applied to select only the required sections from the file. -Example of such a string would be:: +Example of content in such an input file would be:: - SRAM2:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c,\ - SRAM1:COPY:/home/xyz/zephyr/samples/hello_world/src/main2.c, \ - FLASH2:NOCOPY:/home/xyz/zephyr/samples/hello_world/src/main3.c + SRAM2:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c,.*foo|.*bar + SRAM1:COPY:/home/xyz/zephyr/samples/hello_world/src/main2.c,.*bar + FLASH2:NOCOPY:/home/xyz/zephyr/samples/hello_world/src/main3.c, One can also specify the program header for a given memory region: - SRAM2\\ :phdr0:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c + SRAM2\\ :phdr0:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c, To invoke this script:: - python3 gen_relocate_app.py -i input_string -o generated_linker -c generated_code + python3 gen_relocate_app.py -i input_file -o generated_linker -c generated_code Configuration that needs to be sent to the python script. @@ -45,6 +46,7 @@ import argparse import os import glob +import re import warnings from collections import defaultdict from enum import Enum @@ -225,7 +227,7 @@ def region_is_default_ram(region_name: str) -> bool: return region_name == args.default_ram_region -def find_sections(filename: str) -> 'dict[SectionKind, list[OutputSection]]': +def find_sections(filename: str, symbol_filter: str) -> 'dict[SectionKind, list[OutputSection]]': """ Locate relocatable sections in the given object file. @@ -243,6 +245,9 @@ def find_sections(filename: str) -> 'dict[SectionKind, list[OutputSection]]': out = defaultdict(list) for section in sections: + if not re.search(symbol_filter, section.name): + # Section is filtered-out + continue section_kind = SectionKind.for_section_named(section.name) if section_kind is None: continue @@ -501,9 +506,10 @@ def get_obj_filename(searchpath, filename): # Extracts all possible components for the input string: -# [\ :program_header]:[;...]:[;...] -# Returns a 4-tuple with them: (mem_region, program_header, flags, files) +# [\ :program_header]:[;...]:[;...][,filter] +# Returns a 5-tuple with them: (mem_region, program_header, flags, files, filter) # If no `program_header` is defined, returns an empty string +# If no `filter` is defined, returns an empty string def parse_input_string(line): # Be careful when splitting by : to avoid breaking absolute paths on Windows mem_region, rest = line.split(':', 1) @@ -513,13 +519,19 @@ def parse_input_string(line): mem_region = mem_region.rstrip() phdr, rest = rest.split(':', 1) - # Split lists by semicolons, in part to support generator expressions - flag_list, file_list = (lst.split(';') for lst in rest.split(':', 1)) + flag_list, rest = rest.split(':', 1) + flag_list = flag_list.split(';') + + + # Split file list by semicolons, in part to support generator expressions + file_list, symbol_filter = rest.split(',', 1) + file_list = file_list.split(';') - return mem_region, phdr, flag_list, file_list + return mem_region, phdr, flag_list, file_list, symbol_filter -# Create a dict with key as memory type and files as a list of values. +# Create a dict with key as memory type and (files, symbol_filter) tuple +# as a list of values. # Also, return another dict with program headers for memory regions def create_dict_wrt_mem(): # need to support wild card * @@ -529,11 +541,12 @@ def create_dict_wrt_mem(): input_rel_dict = args.input_rel_dict.read().splitlines() if not input_rel_dict: sys.exit("Disable CONFIG_CODE_DATA_RELOCATION if no file needs relocation") + for line in input_rel_dict: if ':' not in line: continue - mem_region, phdr, flag_list, file_list = parse_input_string(line) + mem_region, phdr, flag_list, file_list, symbol_filter = parse_input_string(line) # Handle any program header if phdr != '': @@ -556,12 +569,15 @@ def create_dict_wrt_mem(): if args.verbose: print("Memory region ", mem_region, " Selected for files:", file_name_list) + # Apply filter on files + file_name_filter_list = [(f, symbol_filter) for f in file_name_list] + mem_region = "|".join((mem_region, *flag_list)) if mem_region in rel_dict: - rel_dict[mem_region].extend(file_name_list) + rel_dict[mem_region].extend(file_name_filter_list) else: - rel_dict[mem_region] = file_name_list + rel_dict[mem_region] = file_name_filter_list return rel_dict, phdrs @@ -585,13 +601,13 @@ def main(): for memory_type, files in rel_dict.items(): full_list_of_sections: 'dict[SectionKind, list[OutputSection]]' = defaultdict(list) - for filename in files: + for filename, symbol_filter in files: obj_filename = get_obj_filename(searchpath, filename) # the obj file wasn't found. Probably not compiled. if not obj_filename: continue - file_sections = find_sections(obj_filename) + file_sections = find_sections(obj_filename, symbol_filter) # Merge sections from file into collection of sections for all files for category, sections in file_sections.items(): full_list_of_sections[category].extend(sections) diff --git a/tests/application_development/code_relocation/CMakeLists.txt b/tests/application_development/code_relocation/CMakeLists.txt index 60350a6e2a51e..c58b9522e1efc 100644 --- a/tests/application_development/code_relocation/CMakeLists.txt +++ b/tests/application_development/code_relocation/CMakeLists.txt @@ -17,7 +17,7 @@ endif() # Code relocation feature zephyr_code_relocate(FILES src/test_file1.c ${SRAM2_PHDR} LOCATION SRAM2) -zephyr_code_relocate(FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_file2.c ${RAM_PHDR} LOCATION RAM) +zephyr_code_relocate(FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_file2.c ${RAM_PHDR} LOCATION RAM FILTER ".*sram") # Add custom library that we can relocate code for add_subdirectory(test_lib) diff --git a/tests/application_development/code_relocation/src/test_file1.c b/tests/application_development/code_relocation/src/test_file1.c index 1e1cbafb54f96..426f0ac56e6d6 100644 --- a/tests/application_development/code_relocation/src/test_file1.c +++ b/tests/application_development/code_relocation/src/test_file1.c @@ -23,12 +23,15 @@ __in_section(rodata, sram2, var) const uint32_t var_sram2_rodata = 100U; __in_section(custom_section, static, var) uint32_t var_custom_data = 1U; extern void function_in_sram(int32_t value); +extern void function_not_relocated(int32_t value); void function_in_custom_section(void); #define HAS_SRAM2_DATA_SECTION (CONFIG_ARM) ZTEST(code_relocation, test_function_in_sram2) { + extern uintptr_t __ram_text_reloc_start; + extern uintptr_t __ram_text_reloc_end; extern uintptr_t __sram2_text_reloc_start; extern uintptr_t __sram2_text_reloc_end; extern uintptr_t __sram2_data_reloc_start; @@ -64,7 +67,20 @@ ZTEST(code_relocation, test_function_in_sram2) "var_sram2_bss not in sram2_bss region"); /* Print values from sram */ + printk("Address of function_in_sram %p\n", &function_in_sram); + zassert_between_inclusive((uintptr_t)&function_in_sram, + (uintptr_t)&__ram_text_reloc_start, + (uintptr_t)&__ram_text_reloc_end, + "function_in_sram is not in ram region"); function_in_sram(var_sram2_data); + + /* Print values from non-relocated function */ + printk("Address of function_not_relocated %p\n", &function_not_relocated); + zassert_between_inclusive((uintptr_t)&function_not_relocated, + (uintptr_t)&__text_region_start, + (uintptr_t)&__text_region_end, + "function_not_relocated is not in flash region"); + function_not_relocated(var_sram2_data); /* Call library function */ relocated_library(); diff --git a/tests/application_development/code_relocation/src/test_file2.c b/tests/application_development/code_relocation/src/test_file2.c index d8b56730d39e5..9deccc3a42f9b 100644 --- a/tests/application_development/code_relocation/src/test_file2.c +++ b/tests/application_development/code_relocation/src/test_file2.c @@ -19,3 +19,14 @@ void function_in_sram(int32_t value) printk("Address of memcpy %p\n\n", &memcpy); zassert_mem_equal(src, dst, 8, "memcpy compare error"); } + +void function_not_relocated(int32_t value) +{ + char src[8] = "data\n"; + char dst[8]; + + printk("Hello World! %s\n", CONFIG_BOARD); + memcpy(dst, src, 8); + printk("Address of memcpy %p\n\n", &memcpy); + zassert_mem_equal(src, dst, 8, "memcpy compare error"); +} From efe3bf5b2988f82a76046e8e1567639960171902 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 1 Aug 2024 13:36:27 +0200 Subject: [PATCH 0109/6055] drivers: add nxp pf1550 mfd (charger+regulator) Add driver for nxp pf1550 PMIC Signed-off-by: Martino Facchin --- drivers/charger/CMakeLists.txt | 1 + drivers/charger/Kconfig | 1 + drivers/charger/Kconfig.pf1550 | 12 + drivers/charger/charger_pf1550.c | 691 ++++++++++++++++++ drivers/mfd/CMakeLists.txt | 1 + drivers/mfd/Kconfig | 1 + drivers/mfd/Kconfig.pf1550 | 10 + drivers/mfd/mfd_pf1550.c | 50 ++ drivers/regulator/CMakeLists.txt | 1 + drivers/regulator/Kconfig | 1 + drivers/regulator/Kconfig.pf1550 | 11 + drivers/regulator/regulator_pf1550.c | 432 +++++++++++ dts/bindings/charger/nxp,pf1550-charger.yaml | 58 ++ dts/bindings/mfd/nxp,pf1550.yaml | 12 + .../regulator/nxp,pf1550-regulator.yaml | 54 ++ 15 files changed, 1336 insertions(+) create mode 100644 drivers/charger/Kconfig.pf1550 create mode 100644 drivers/charger/charger_pf1550.c create mode 100644 drivers/mfd/Kconfig.pf1550 create mode 100644 drivers/mfd/mfd_pf1550.c create mode 100644 drivers/regulator/Kconfig.pf1550 create mode 100644 drivers/regulator/regulator_pf1550.c create mode 100644 dts/bindings/charger/nxp,pf1550-charger.yaml create mode 100644 dts/bindings/mfd/nxp,pf1550.yaml create mode 100644 dts/bindings/regulator/nxp,pf1550-regulator.yaml diff --git a/drivers/charger/CMakeLists.txt b/drivers/charger/CMakeLists.txt index 60b80b0ed25cd..fd4832eded35b 100644 --- a/drivers/charger/CMakeLists.txt +++ b/drivers/charger/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/charger.h) zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ24190 charger_bq24190.c) zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ25180 charger_bq25180.c) zephyr_library_sources_ifdef(CONFIG_CHARGER_MAX20335 charger_max20335.c) +zephyr_library_sources_ifdef(CONFIG_CHARGER_PF1550 charger_pf1550.c) zephyr_library_sources_ifdef(CONFIG_SBS_CHARGER sbs_charger.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE charger_handlers.c) zephyr_library_sources_ifdef(CONFIG_EMUL_SBS_CHARGER emul_sbs_charger.c) diff --git a/drivers/charger/Kconfig b/drivers/charger/Kconfig index 4e0b6b3c7a742..c6c68bdaba585 100644 --- a/drivers/charger/Kconfig +++ b/drivers/charger/Kconfig @@ -54,5 +54,6 @@ source "drivers/charger/Kconfig.sbs_charger" source "drivers/charger/Kconfig.bq24190" source "drivers/charger/Kconfig.bq25180" source "drivers/charger/Kconfig.max20335" +source "drivers/charger/Kconfig.pf1550" endif # CHARGER diff --git a/drivers/charger/Kconfig.pf1550 b/drivers/charger/Kconfig.pf1550 new file mode 100644 index 0000000000000..f81e0b085b91e --- /dev/null +++ b/drivers/charger/Kconfig.pf1550 @@ -0,0 +1,12 @@ +# Copyright 2024 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +config CHARGER_PF1550 + bool "NXP PF1550 battery charger driver" + default y + depends on DT_HAS_NXP_PF1550_CHARGER_ENABLED + select GPIO + select I2C + select MFD + help + Enable the NXP PF1550 battery charger driver. diff --git a/drivers/charger/charger_pf1550.c b/drivers/charger/charger_pf1550.c new file mode 100644 index 0000000000000..06ce4d3bc5c91 --- /dev/null +++ b/drivers/charger/charger_pf1550.c @@ -0,0 +1,691 @@ +/* + * Copyright 2024 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_pf1550_charger + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(pf1550_charger, CONFIG_CHARGER_LOG_LEVEL); + +#define INT_ENABLE_DELAY K_MSEC(500) + +#define CHARGER_CHG_INT (0x80 + 0x00) +#define CHARGER_CHG_INT_MASK (0x80 + 0x02) +#define CHARGER_CHG_INT_OK (0x80 + 0x04) +#define CHARGER_VBUS_SNS (0x80 + 0x06) +#define CHARGER_CHG_SNS (0x80 + 0x07) +#define CHARGER_BATT_SNS (0x80 + 0x08) +#define CHARGER_CHG_OPER (0x80 + 0x09) +#define CHARGER_CHG_TMR (0x80 + 0x0A) +#define CHARGER_CHG_EOC_CNFG (0x80 + 0x0D) +#define CHARGER_CHG_CURR_CNFG (0x80 + 0x0E) +#define CHARGER_BATT_REG (0x80 + 0x0F) +#define CHARGER_BATFET_CNFG (0x80 + 0x11) +#define CHARGER_THM_REG_CNFG (0x80 + 0x12) +#define CHARGER_VBUS_INLIM_CNFG (0x80 + 0x14) +#define CHARGER_VBUS_LIN_DPM (0x80 + 0x15) +#define CHARGER_USB_PHY_LDO_CNFG (0x80 + 0x16) +#define CHARGER_DBNC_DELAY_TIME (0x80 + 0x18) +#define CHARGER_CHG_INT_CNFG (0x80 + 0x19) +#define CHARGER_THM_ADJ_SETTING (0x80 + 0x1A) +#define CHARGER_VBUS2SYS_CNFG (0x80 + 0x1B) +#define CHARGER_LED_PWM (0x80 + 0x1C) +#define CHARGER_FAULT_BATFET_CNFG (0x80 + 0x1D) +#define CHARGER_LED_CNFG (0x80 + 0x1E) +#define CHARGER_CHGR_KEY2 (0x80 + 0x1F) + +#define PF1550_BAT_IRQ BIT(2) +#define PF1550_CHG_IRQ BIT(3) +#define PF1550_VBUS_IRQ BIT(5) +#define PF1550_VBUS_DPM_IRQ BIT(5) +#define CHG_INT_ENABLE_ALL (0xFF) + +#define LED_PWM_LED_EN BIT(7) +#define LED_PWM_FULL_ON BIT(5) + +#define LED_CNFG_LED_CFG BIT(4) +#define LED_CNFG_LEDOVRD BIT(5) + +#define CHG_OPER_CHG_OPER_MASK GENMASK(1, 0) +#define CHG_CURR_CNFG_CHG_CC_MASK GENMASK(4, 0) +#define CHG_SNS_CHG_SNS_MASK GENMASK(3, 0) +#define VBUS_INLIM_CNFG_VBUS_INLIM_MASK GENMASK(7, 3) +#define BATT_REG_CHGCV_MASK GENMASK(5, 0) +#define BATT_REG_VSYSMIN_MASK GENMASK(7, 6) +#define THM_REG_CNFG_THM_CNFG_MASK GENMASK(1, 0) + +#define CHG_OPER_CHARGER_OFF_LINEAR_OFF 0 +#define CHG_OPER_CHARGER_OFF_LINEAR_ON 1 +#define CHG_OPER_CHARGER_ON_LINEAR_ON 2 + +enum charger_pf1550_therm_mode { + PF1550_THERM_MODE_DISABLED, + PF1550_THERM_MODE_THERMISTOR, + PF1550_THERM_MODE_JEITA_1, + PF1550_THERM_MODE_JEITA_2, + PF1550_THERM_MODE_UNKNOWN, +}; + +/* synced with YAML binding */ +enum charger_pf1550_led_behaviour { + PF1550_LED_ON_IN_CHARGING_FLASH_IN_FAULT, + PF1550_LED_FLASH_IN_CHARGING_ON_IN_FAULT, + PF1550_LED_MANUAL_OFF +}; + +struct charger_pf1550_led_config { + bool enabled; + bool manual; + enum charger_pf1550_led_behaviour behaviour; +}; + +struct charger_pf1550_config { + struct i2c_dt_spec bus; + struct gpio_dt_spec int_gpio; + char *therm_mon_mode; + uint32_t charge_current_ua; + uint32_t vbus_ilim_ua; + uint32_t charge_voltage_max_uv; + uint32_t vsys_min_uv; +}; + +struct charger_pf1550_data { + const struct device *dev; + struct gpio_callback gpio_cb; + struct k_work int_routine_work; + struct k_work_delayable int_enable_work; + enum charger_status charger_status; + enum charger_online charger_online; + charger_status_notifier_t charger_status_notifier; + charger_online_notifier_t charger_online_notifier; + bool charger_enabled; + uint32_t charge_current_ua; + uint32_t vbus_ilim_ua; + struct charger_pf1550_led_config *led_config; +}; + +static const struct linear_range charger_vbus_ilim_range[] = { + LINEAR_RANGE_INIT(10000, 5000, 0, 8), + LINEAR_RANGE_INIT(100000, 50000, 9, 10), + LINEAR_RANGE_INIT(200000, 100000, 11, 19), + LINEAR_RANGE_INIT(1500000, 0, 20, 20), +}; + +static const struct linear_range charger_fast_charge_ua_range[] = { + LINEAR_RANGE_INIT(100000, 50000, 0, 18), +}; + +static const struct linear_range charger_battery_termination_uv_range[] = { + LINEAR_RANGE_INIT(3500000, 20000, 8, 55), +}; + +static const struct linear_range charger_vsysmin_uv[] = { + LINEAR_RANGE_INIT(3500000, 0, 0, 0), + LINEAR_RANGE_INIT(3700000, 0, 1, 1), + LINEAR_RANGE_INIT(4300000, 0, 2, 2), +}; + +static int pf1550_get_charger_status(const struct device *dev, enum charger_status *status) +{ + enum chg_sns { + PF1550_CHARGER_PRECHARGE, + PF1550_FAST_CHARGE_CONSTANT_CURRENT, + PF1550_FAST_CHARGE_CONSTANT_VOLTAGE, + PF1550_END_OF_CHARGE, + PF1550_CHARGE_DONE, + PF1550_TIMER_FAULT = 6, + PF1550_THERMISTOR_SUSPEND, + PF1550_CHARGER_OFF_INVALID_INPUT, + PF1550_BATTERY_OVERVOLTAGE, + PF1550_BATTERY_OVERTEMPERATURE, + PF1550_CHARGER_OFF_LINEAR_MODE = 12, + }; + + const struct charger_pf1550_config *const config = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, CHARGER_CHG_SNS, &val); + if (ret) { + return ret; + } + + val = FIELD_GET(CHG_SNS_CHG_SNS_MASK, val); + + if (val == PF1550_CHARGE_DONE) { + *status = CHARGER_STATUS_FULL; + } else if (val < PF1550_CHARGE_DONE) { + *status = CHARGER_STATUS_CHARGING; + } else { + *status = CHARGER_STATUS_NOT_CHARGING; + } + + return 0; +} + +static int pf1550_get_charger_online(const struct device *dev, enum charger_online *online) +{ + const struct charger_pf1550_config *const config = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, CHARGER_CHG_OPER, &val); + if (ret) { + return ret; + } + + val = FIELD_GET(CHG_OPER_CHG_OPER_MASK, val); + + switch (val) { + case CHG_OPER_CHARGER_ON_LINEAR_ON: + *online = CHARGER_ONLINE_FIXED; + break; + default: + *online = CHARGER_ONLINE_OFFLINE; + break; + }; + + return 0; +} + +static int pf1550_set_constant_charge_current(const struct device *dev, uint32_t current_ua) +{ + const struct charger_pf1550_config *const config = dev->config; + uint16_t idx; + uint8_t val; + int ret; + + ret = linear_range_group_get_index(charger_fast_charge_ua_range, + ARRAY_SIZE(charger_fast_charge_ua_range), current_ua, + &idx); + if (ret < 0) { + return ret; + } + + val = FIELD_PREP(CHG_CURR_CNFG_CHG_CC_MASK, idx); + + return i2c_reg_update_byte_dt(&config->bus, CHARGER_CHG_CURR_CNFG, + CHG_CURR_CNFG_CHG_CC_MASK, val); +} + +static int pf1550_set_vbus_ilim(const struct device *dev, uint32_t current_ua) +{ + const struct charger_pf1550_config *const config = dev->config; + uint16_t idx; + uint8_t val; + int ret; + + ret = linear_range_group_get_index(charger_vbus_ilim_range, + ARRAY_SIZE(charger_vbus_ilim_range), current_ua, &idx); + if (ret < 0) { + return ret; + } + + val = FIELD_PREP(VBUS_INLIM_CNFG_VBUS_INLIM_MASK, idx); + + return i2c_reg_update_byte_dt(&config->bus, CHARGER_VBUS_INLIM_CNFG, + VBUS_INLIM_CNFG_VBUS_INLIM_MASK, val); +} + +static int pf1550_set_vsys_min(const struct device *dev, uint32_t voltage_uv) +{ + const struct charger_pf1550_config *const config = dev->config; + uint16_t idx; + uint8_t val; + int ret; + + ret = linear_range_group_get_index(charger_vsysmin_uv, ARRAY_SIZE(charger_vsysmin_uv), + voltage_uv, &idx); + if (ret < 0) { + return ret; + } + + val = FIELD_PREP(BATT_REG_VSYSMIN_MASK, idx); + + return i2c_reg_update_byte_dt(&config->bus, CHARGER_BATT_REG, BATT_REG_VSYSMIN_MASK, val); +} + +static int pf1550_set_charge_termination_uv(const struct device *dev, uint32_t voltage_uv) +{ + const struct charger_pf1550_config *const config = dev->config; + uint16_t idx; + uint8_t val; + int ret; + + ret = linear_range_group_get_index(charger_battery_termination_uv_range, + ARRAY_SIZE(charger_battery_termination_uv_range), + voltage_uv, &idx); + if (ret < 0) { + return ret; + } + + val = FIELD_PREP(BATT_REG_CHGCV_MASK, idx); + + return i2c_reg_update_byte_dt(&config->bus, CHARGER_BATT_REG, BATT_REG_CHGCV_MASK, val); +} + +static int pf1550_set_thermistor_mode(const struct device *dev, enum charger_pf1550_therm_mode mode) +{ + const struct charger_pf1550_config *const config = dev->config; + uint8_t val; + + val = FIELD_PREP(THM_REG_CNFG_THM_CNFG_MASK, mode); + + return i2c_reg_update_byte_dt(&config->bus, CHARGER_THM_REG_CNFG, + THM_REG_CNFG_THM_CNFG_MASK, val); +} + +static int pf1550_set_enabled(const struct device *dev, bool enable) +{ + struct charger_pf1550_data *data = dev->data; + const struct charger_pf1550_config *const config = dev->config; + + int ret = i2c_reg_update_byte_dt(&config->bus, CHARGER_CHG_OPER, CHG_OPER_CHG_OPER_MASK, + enable ? 2 : 0); + + if (ret == 0) { + data->charger_enabled = enable; + } + + return ret; +} + +static int pf1550_get_interrupt_source(const struct device *dev, uint8_t *int_a) +{ + const struct charger_pf1550_config *config = dev->config; + uint8_t buf = 0; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, CHARGER_CHG_INT, &buf); + + if (int_a) { + *int_a = buf; + } + return ret; +} + +static int pf1550_enable_interrupts(const struct device *dev) +{ + const struct charger_pf1550_config *config = dev->config; + int ret; + + ret = pf1550_get_interrupt_source(dev, NULL); + if (ret < 0) { + LOG_WRN("Failed to clear pending interrupts: %d", ret); + return ret; + } + + return i2c_reg_write_byte_dt(&config->bus, CHARGER_CHG_INT_MASK, CHG_INT_ENABLE_ALL); +} + +static int pf1550_led_config(const struct device *dev) +{ + struct charger_pf1550_data *data = dev->data; + const struct charger_pf1550_config *config = dev->config; + struct charger_pf1550_led_config *cfg = data->led_config; + int ret; + uint8_t val; + + cfg->enabled = true; + + if (cfg->behaviour == PF1550_LED_MANUAL_OFF) { + cfg->manual = true; + cfg->enabled = false; + } + + val = (cfg->enabled ? LED_PWM_LED_EN : 0) | LED_PWM_FULL_ON; + + ret = i2c_reg_write_byte_dt(&config->bus, CHARGER_LED_PWM, val); + if (ret < 0) { + return ret; + } + + val = (cfg->manual ? LED_CNFG_LEDOVRD : 0) | + (cfg->behaviour == PF1550_LED_FLASH_IN_CHARGING_ON_IN_FAULT ? + LED_CNFG_LED_CFG : 0); + + return i2c_reg_write_byte_dt(&config->bus, CHARGER_LED_CNFG, val); +} + +static int pf1550_init_properties(const struct device *dev) +{ + struct charger_pf1550_data *data = dev->data; + const struct charger_pf1550_config *config = dev->config; + int ret; + + data->charger_enabled = true; + data->charge_current_ua = config->charge_current_ua; + data->vbus_ilim_ua = config->vbus_ilim_ua; + + ret = pf1550_get_charger_status(dev, &data->charger_status); + if (ret < 0) { + LOG_ERR("Failed to read charger status: %d", ret); + return ret; + } + + ret = pf1550_get_charger_online(dev, &data->charger_online); + if (ret < 0) { + LOG_ERR("Failed to read charger online: %d", ret); + return ret; + } + + return 0; +} + +enum charger_pf1550_therm_mode pf1550_string_to_therm_mode(const char *mode_string) +{ + static const char *const modes[] = { + [PF1550_THERM_MODE_DISABLED] = "disabled", + [PF1550_THERM_MODE_THERMISTOR] = "thermistor", + [PF1550_THERM_MODE_JEITA_1] = "JEITA-1", + [PF1550_THERM_MODE_JEITA_2] = "JEITA-2", + }; + enum charger_pf1550_therm_mode i; + + for (i = PF1550_THERM_MODE_DISABLED; i < ARRAY_SIZE(modes); i++) { + if (strncmp(mode_string, modes[i], strlen(modes[i])) == 0) { + return i; + } + } + + return PF1550_THERM_MODE_UNKNOWN; +} + +static int pf1550_update_properties(const struct device *dev) +{ + struct charger_pf1550_data *data = dev->data; + const struct charger_pf1550_config *config = dev->config; + enum charger_pf1550_therm_mode therm_mode; + int ret; + + ret = pf1550_set_vbus_ilim(dev, config->vbus_ilim_ua); + if (ret < 0) { + LOG_ERR("Failed to set vbus current limit: %d", ret); + return ret; + } + + ret = pf1550_set_vsys_min(dev, config->vsys_min_uv); + if (ret < 0) { + LOG_ERR("Failed to set minimum system voltage threshold: %d", ret); + return ret; + } + + ret = pf1550_set_charge_termination_uv(dev, config->charge_voltage_max_uv); + if (ret < 0) { + LOG_ERR("Failed to set recharge threshold: %d", ret); + return ret; + } + + therm_mode = pf1550_string_to_therm_mode(config->therm_mon_mode); + ret = pf1550_set_thermistor_mode(dev, therm_mode); + if (ret < 0) { + LOG_ERR("Failed to set thermistor mode: %d", ret); + return ret; + } + + ret = pf1550_set_constant_charge_current(dev, data->charge_current_ua); + if (ret < 0) { + LOG_ERR("Failed to set charge voltage: %d", ret); + return ret; + } + + ret = pf1550_set_enabled(dev, data->charger_enabled); + if (ret < 0) { + LOG_ERR("Failed to set enabled: %d", ret); + return ret; + } + + ret = pf1550_led_config(dev); + if (ret < 0) { + LOG_ERR("Failed to configure led: %d", ret); + return ret; + } + + return 0; +} + +static int pf1550_get_prop(const struct device *dev, charger_prop_t prop, + union charger_propval *val) +{ + struct charger_pf1550_data *data = dev->data; + + switch (prop) { + case CHARGER_PROP_ONLINE: + val->online = data->charger_online; + return 0; + case CHARGER_PROP_STATUS: + val->status = data->charger_status; + return 0; + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + val->const_charge_current_ua = data->charge_current_ua; + return 0; + default: + return -ENOTSUP; + } +} + +static int pf1550_set_prop(const struct device *dev, charger_prop_t prop, + const union charger_propval *val) +{ + struct charger_pf1550_data *data = dev->data; + int ret; + + switch (prop) { + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + ret = pf1550_set_constant_charge_current(dev, val->const_charge_current_ua); + if (ret == 0) { + data->charge_current_ua = val->const_charge_current_ua; + } + return ret; + case CHARGER_PROP_INPUT_REGULATION_CURRENT_UA: + ret = pf1550_set_vbus_ilim(dev, val->input_current_regulation_current_ua); + if (ret == 0) { + data->vbus_ilim_ua = val->input_current_regulation_current_ua; + } + return ret; + case CHARGER_PROP_STATUS_NOTIFICATION: + data->charger_status_notifier = val->status_notification; + return 0; + case CHARGER_PROP_ONLINE_NOTIFICATION: + data->charger_online_notifier = val->online_notification; + return 0; + default: + return -ENOTSUP; + } +} + +static int pf1550_enable_interrupt_pin(const struct device *dev, bool enabled) +{ + const struct charger_pf1550_config *const config = dev->config; + gpio_flags_t flags; + int ret; + + flags = enabled ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE; + + ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, flags); + if (ret < 0) { + LOG_ERR("Could not %s interrupt GPIO callback: %d", enabled ? "enable" : "disable", + ret); + } + + return ret; +} + +static void pf1550_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) +{ + struct charger_pf1550_data *data = CONTAINER_OF(cb, struct charger_pf1550_data, gpio_cb); + int ret; + + (void)pf1550_enable_interrupt_pin(data->dev, false); + + ret = k_work_submit(&data->int_routine_work); + if (ret < 0) { + LOG_WRN("Could not submit int work: %d", ret); + } +} + +static void pf1550_int_routine_work_handler(struct k_work *work) +{ + struct charger_pf1550_data *data = + CONTAINER_OF(work, struct charger_pf1550_data, int_routine_work); + uint8_t int_src; + int ret; + + ret = pf1550_get_interrupt_source(data->dev, &int_src); + if (ret < 0) { + LOG_WRN("Failed to read interrupt source: %d", ret); + return; + } + + LOG_DBG("Interrupt received: %x", int_src); + + ret = pf1550_get_charger_status(data->dev, &data->charger_status); + if (ret < 0) { + LOG_WRN("Failed to read charger status: %d", ret); + return; + } + + ret = pf1550_get_charger_online(data->dev, &data->charger_online); + if (ret < 0) { + LOG_WRN("Failed to read charger online %d", ret); + return; + } + + if (data->charger_status_notifier != NULL) { + data->charger_status_notifier(data->charger_status); + } + if (data->charger_online_notifier != NULL) { + data->charger_online_notifier(data->charger_online); + } + + if (data->charger_online != CHARGER_ONLINE_OFFLINE) { + (void)pf1550_update_properties(data->dev); + } + + ret = k_work_reschedule(&data->int_enable_work, INT_ENABLE_DELAY); + if (ret < 0) { + LOG_WRN("Could not reschedule int_enable_work: %d", ret); + } +} + +static void pf1550_int_enable_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct charger_pf1550_data *data = + CONTAINER_OF(dwork, struct charger_pf1550_data, int_enable_work); + + (void)pf1550_enable_interrupt_pin(data->dev, true); +} + +static int pf1550_configure_interrupt_pin(const struct device *dev) +{ + struct charger_pf1550_data *data = dev->data; + const struct charger_pf1550_config *config = dev->config; + int ret; + + ret = gpio_is_ready_dt(&config->int_gpio) ? 0 : -ENODEV; + if (ret < 0) { + LOG_ERR("Interrupt GPIO device not ready: %d", ret); + return ret; + } + + ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure interrupt GPIO: %d", ret); + return ret; + } + + gpio_init_callback(&data->gpio_cb, pf1550_gpio_callback, BIT(config->int_gpio.pin)); + ret = gpio_add_callback_dt(&config->int_gpio, &data->gpio_cb); + if (ret < 0) { + LOG_ERR("Could not add interrupt GPIO callback: %d", ret); + return ret; + } + + return 0; +} + +static int pf1550_init(const struct device *dev) +{ + struct charger_pf1550_data *data = dev->data; + const struct charger_pf1550_config *config = dev->config; + int ret; + + if (!i2c_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + data->dev = dev; + + ret = pf1550_init_properties(dev); + if (ret < 0) { + return ret; + } + + k_work_init(&data->int_routine_work, pf1550_int_routine_work_handler); + k_work_init_delayable(&data->int_enable_work, pf1550_int_enable_work_handler); + + ret = pf1550_configure_interrupt_pin(dev); + if (ret < 0) { + return ret; + } + + ret = pf1550_enable_interrupt_pin(dev, true); + if (ret < 0) { + return ret; + } + + ret = pf1550_enable_interrupts(dev); + if (ret < 0) { + LOG_ERR("Failed to enable interrupts: %d", ret); + return ret; + } + + ret = pf1550_update_properties(dev); + if (ret < 0) { + LOG_ERR("Failed to setup charger: %d", ret); + return ret; + } + + return 0; +} + +static const struct charger_driver_api pf1550_driver_api = { + .get_property = pf1550_get_prop, + .set_property = pf1550_set_prop, + .charge_enable = pf1550_set_enabled, +}; + +#define PF1550_DEFINE(inst) \ + static struct charger_pf1550_led_config charger_pf1550_led_config_##inst = { \ + .behaviour = DT_INST_ENUM_IDX(inst, pf1550_led_behaviour), \ + }; \ + static struct charger_pf1550_data charger_pf1550_data_##inst = { \ + .led_config = &charger_pf1550_led_config_##inst, \ + }; \ + static const struct charger_pf1550_config charger_pf1550_config_##inst = { \ + .bus = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ + .int_gpio = GPIO_DT_SPEC_INST_GET(inst, pf1550_int_gpios), \ + .charge_current_ua = DT_INST_PROP(inst, constant_charge_current_max_microamp), \ + .vsys_min_uv = DT_INST_PROP(inst, pf1550_system_voltage_min_threshold_microvolt), \ + .therm_mon_mode = DT_INST_PROP(inst, pf1550_thermistor_monitoring_mode), \ + .vbus_ilim_ua = DT_INST_PROP(inst, pf1550_vbus_current_limit_microamp), \ + .charge_voltage_max_uv = \ + DT_INST_PROP(inst, constant_charge_voltage_max_microvolt), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &pf1550_init, NULL, &charger_pf1550_data_##inst, \ + &charger_pf1550_config_##inst, POST_KERNEL, \ + CONFIG_MFD_INIT_PRIORITY, &pf1550_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PF1550_DEFINE) diff --git a/drivers/mfd/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index 5a7f5faee90ac..4bbb7eb637cbc 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -22,3 +22,4 @@ zephyr_library_sources_ifdef(CONFIG_MFD_ITE_IT8801_ALTCTRL mfd_it8801_altctrl.c) zephyr_library_sources_ifdef(CONFIG_MFD_AW9523B mfd_aw9523b.c) zephyr_library_sources_ifdef(CONFIG_MFD_DS3231 mfd_ds3231.c) zephyr_library_sources_ifdef(CONFIG_MFD_MAX22017 mfd_max22017.c) +zephyr_library_sources_ifdef(CONFIG_MFD_PF1550 mfd_pf1550.c) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0ccb41f6ba1b6..ed3af13ddd7d8 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -31,6 +31,7 @@ source "drivers/mfd/Kconfig.nct38xx" source "drivers/mfd/Kconfig.npm1300" source "drivers/mfd/Kconfig.npm2100" source "drivers/mfd/Kconfig.npm6001" +source "drivers/mfd/Kconfig.pf1550" source "drivers/mfd/Kconfig.lpflexcomm" source "drivers/mfd/Kconfig.tle9104" source "drivers/mfd/Kconfig.it8801" diff --git a/drivers/mfd/Kconfig.pf1550 b/drivers/mfd/Kconfig.pf1550 new file mode 100644 index 0000000000000..127bcbabe0b52 --- /dev/null +++ b/drivers/mfd/Kconfig.pf1550 @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +config MFD_PF1550 + bool "PF1550 PMIC multi-function device driver" + default y + depends on DT_HAS_NXP_PF1550_ENABLED + select I2C + help + Enable the NXP PF1550 PMIC multi-function device driver diff --git a/drivers/mfd/mfd_pf1550.c b/drivers/mfd/mfd_pf1550.c new file mode 100644 index 0000000000000..492f516e25335 --- /dev/null +++ b/drivers/mfd/mfd_pf1550.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 Arduino SA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_pf1550 + +#include + +#include +#include + +#define PF1550_REG_CHIP_ID 0x00 +#define PF1550_CHIP_ID_VAL ((15 << 3) | 4) + +struct mfd_pf1550_config { + struct i2c_dt_spec bus; +}; + +static int mfd_pf1550_init(const struct device *dev) +{ + const struct mfd_pf1550_config *config = dev->config; + uint8_t val; + int ret; + + if (!i2c_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + ret = i2c_reg_read_byte_dt(&config->bus, PF1550_REG_CHIP_ID, &val); + if (ret < 0) { + return ret; + } + + if (val != PF1550_CHIP_ID_VAL) { + return -ENODEV; + } + + return 0; +} + +#define MFD_PF1550_DEFINE(inst) \ + static const struct mfd_pf1550_config mfd_pf1550_config##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mfd_pf1550_init, NULL, NULL, &mfd_pf1550_config##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(MFD_PF1550_DEFINE) diff --git a/drivers/regulator/CMakeLists.txt b/drivers/regulator/CMakeLists.txt index 7ed90137c3f24..1a71ae534b64f 100644 --- a/drivers/regulator/CMakeLists.txt +++ b/drivers/regulator/CMakeLists.txt @@ -17,6 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM1300 regulator_npm1300.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM2100 regulator_npm2100.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM6001 regulator_npm6001.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_PCA9420 regulator_pca9420.c) +zephyr_library_sources_ifdef(CONFIG_REGULATOR_PF1550 regulator_pf1550.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_SHELL regulator_shell.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_RPI_PICO regulator_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_NXP_VREF regulator_nxp_vref.c) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index d4b70e6b76add..dc331b2139d36 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -39,6 +39,7 @@ source "drivers/regulator/Kconfig.npm1300" source "drivers/regulator/Kconfig.npm2100" source "drivers/regulator/Kconfig.npm6001" source "drivers/regulator/Kconfig.pca9420" +source "drivers/regulator/Kconfig.pf1550" source "drivers/regulator/Kconfig.rpi_pico" source "drivers/regulator/Kconfig.nxp_vref" source "drivers/regulator/Kconfig.mpm54304" diff --git a/drivers/regulator/Kconfig.pf1550 b/drivers/regulator/Kconfig.pf1550 new file mode 100644 index 0000000000000..667a4b411ee02 --- /dev/null +++ b/drivers/regulator/Kconfig.pf1550 @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +config REGULATOR_PF1550 + bool "NXP PF1550 PMIC regulator driver" + default y + depends on DT_HAS_NXP_PF1550_REGULATOR_ENABLED + select I2C + select MFD + help + Enable the NXP PF1550 PMIC regulator driver diff --git a/drivers/regulator/regulator_pf1550.c b/drivers/regulator/regulator_pf1550.c new file mode 100644 index 0000000000000..3759e8e912397 --- /dev/null +++ b/drivers/regulator/regulator_pf1550.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2024 Arduino SA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_pf1550_regulator + +#include +#include +#include +#include + +#define PMIC_DEVICE_ID 0x00 +#define PMIC_OTP_FLAVOR 0x01 +#define PMIC_SILICON_REV 0x02 +#define PMIC_INT_CATEGORY 0x06 +#define PMIC_SW_INT_STAT0 0x08 +#define PMIC_SW_INT_MASK0 0x09 +#define PMIC_SW_INT_SENSE0 0x0A +#define PMIC_SW_INT_STAT1 0x0B +#define PMIC_SW_INT_MASK1 0x0C +#define PMIC_SW_INT_SENSE1 0x0D +#define PMIC_SW_INT_STAT2 0x0E +#define PMIC_SW_INT_MASK2 0x0F +#define PMIC_SW_INT_SENSE2 0x10 +#define PMIC_LDO_INT_STAT0 0x18 +#define PMIC_LDO_INT_MASK0 0x19 +#define PMIC_LDO_INT_SENSE0 0x1A +#define PMIC_TEMP_INT_STAT0 0x20 +#define PMIC_TEMP_INT_MASK0 0x21 +#define PMIC_TEMP_INT_SENSE0 0x22 +#define PMIC_ONKEY_INT_STAT0 0x24 +#define PMIC_ONKEY_INT_MASK0 0x25 +#define PMIC_ONKEY_INT_SENSE0 0x26 +#define PMIC_MISC_INT_STAT0 0x28 +#define PMIC_MISC_INT_MASK0 0x29 +#define PMIC_MISC_INT_SENSE0 0x2A +#define PMIC_COINCELL_CONTROL 0x30 +#define PMIC_SW1_VOLT 0x32 +#define PMIC_SW1_STBY_VOLT 0x33 +#define PMIC_SW1_SLP_VOLT 0x34 +#define PMIC_SW1_CTRL 0x35 +#define PMIC_SW1_CTRL1 0x36 +#define PMIC_SW2_VOLT 0x38 +#define PMIC_SW2_STBY_VOLT 0x39 +#define PMIC_SW2_SLP_VOLT 0x3A +#define PMIC_SW2_CTRL 0x3B +#define PMIC_SW2_CTRL1 0x3C +#define PMIC_SW3_VOLT 0x3E +#define PMIC_SW3_STBY_VOLT 0x3F +#define PMIC_SW3_SLP_VOLT 0x40 +#define PMIC_SW3_CTRL 0x41 +#define PMIC_SW3_CTRL1 0x42 +#define PMIC_VSNVS_CTRL 0x48 +#define PMIC_VREFDDR_CTRL 0x4A +#define PMIC_LDO1_VOLT 0x4C +#define PMIC_LDO1_CTRL 0x4D +#define PMIC_LDO2_VOLT 0x4F +#define PMIC_LDO2_CTRL 0x50 +#define PMIC_LDO3_VOLT 0x52 +#define PMIC_LDO3_CTRL 0x53 +#define PMIC_PWRCTRL0 0x58 +#define PMIC_PWRCTRL1 0x59 +#define PMIC_PWRCTRL2 0x5A +#define PMIC_PWRCTRL3 0x5B +#define PMIC_SW1_PWRDN_SEQ 0x5F +#define PMIC_SW2_PWRDN_SEQ 0x60 +#define PMIC_SW3_PWRDN_SEQ 0x61 +#define PMIC_LDO1_PWRDN_SEQ 0x62 +#define PMIC_LDO2_PWRDN_SEQ 0x63 +#define PMIC_LDO3_PWRDN_SEQ 0x64 +#define PMIC_VREFDDR_PWRDN_SEQ 0x65 +#define PMIC_STATE_INFO 0x67 +#define PMIC_I2C_ADDR 0x68 +#define PMIC_RC_16MHZ 0x6B +#define PMIC_KEY1 0x6B + +enum pf1550_pmic_sources { + PF1550_PMIC_SOURCE_BUCK1, + PF1550_PMIC_SOURCE_BUCK2, + PF1550_PMIC_SOURCE_BUCK3, + PF1550_PMIC_SOURCE_LDO1, + PF1550_PMIC_SOURCE_LDO2, + PF1550_PMIC_SOURCE_LDO3, +}; + +struct regulator_pf1550_desc { + uint8_t vsel_reg; + uint8_t enable_mask; + uint8_t enable_val; + uint8_t cfg_reg; + const struct linear_range *uv_range; + uint8_t uv_nranges; + const struct linear_range *ua_range; + uint8_t ua_nranges; +}; + +struct regulator_pf1550_common_config { + struct i2c_dt_spec bus; +}; + +struct regulator_pf1550_config { + struct regulator_common_config common; + struct i2c_dt_spec bus; + const struct regulator_pf1550_desc *desc; + uint8_t source; +}; + +struct regulator_pf1550_data { + struct regulator_common_data common; +}; + +/* + * Output voltage for BUCK1/2 with DVS disabled (OTP_SWx_DVS_SEL = 1). + * This is needed to reach the 3V3 maximum range + */ +static const struct linear_range buck12_range[] = { + LINEAR_RANGE_INIT(1100000, 0, 0, 0), LINEAR_RANGE_INIT(1200000, 0, 1, 1), + LINEAR_RANGE_INIT(1350000, 0, 2, 2), LINEAR_RANGE_INIT(1500000, 0, 3, 3), + LINEAR_RANGE_INIT(1800000, 0, 4, 4), LINEAR_RANGE_INIT(2500000, 0, 5, 5), + LINEAR_RANGE_INIT(3000000, 0, 6, 6), LINEAR_RANGE_INIT(3300000, 0, 7, 7), +}; +static const struct linear_range buck3_range[] = { + LINEAR_RANGE_INIT(1800000, 100000, 0, 15), +}; +static const struct linear_range buck123_current_limit_range[] = { + LINEAR_RANGE_INIT(1000000, 0, 0, 0), + LINEAR_RANGE_INIT(1200000, 0, 0, 0), + LINEAR_RANGE_INIT(1500000, 0, 0, 0), + LINEAR_RANGE_INIT(2000000, 0, 0, 0), +}; +static const struct linear_range ldo13_range[] = { + LINEAR_RANGE_INIT(750000, 50000, 0, 15), + LINEAR_RANGE_INIT(1800000, 100000, 16, 31), +}; +static const struct linear_range ldo2_range[] = { + LINEAR_RANGE_INIT(1800000, 100000, 0, 15), +}; + +#define PF1550_RAIL_EN BIT(0) +#define PF1550_RAIL_EN_MASK GENMASK(1, 0) +#define PF1550_GOTO_SHIP BIT(0) +#define PF1550_GOTO_SHIP_MASK GENMASK(1, 0) + +static const struct regulator_pf1550_desc __maybe_unused buck1_desc = { + .vsel_reg = PMIC_SW1_VOLT, + .enable_mask = PF1550_RAIL_EN, + .enable_val = PF1550_RAIL_EN_MASK, + .cfg_reg = PMIC_SW1_CTRL, + .uv_range = buck12_range, + .uv_nranges = ARRAY_SIZE(buck12_range), + .ua_range = buck123_current_limit_range, + .ua_nranges = ARRAY_SIZE(buck123_current_limit_range), +}; + +static const struct regulator_pf1550_desc __maybe_unused buck2_desc = { + .vsel_reg = PMIC_SW2_VOLT, + .enable_mask = PF1550_RAIL_EN, + .enable_val = PF1550_RAIL_EN_MASK, + .cfg_reg = PMIC_SW2_CTRL, + .uv_range = buck12_range, + .uv_nranges = ARRAY_SIZE(buck12_range), + .ua_range = buck123_current_limit_range, + .ua_nranges = ARRAY_SIZE(buck123_current_limit_range), +}; + +static const struct regulator_pf1550_desc __maybe_unused buck3_desc = { + .vsel_reg = PMIC_SW3_VOLT, + .enable_mask = PF1550_RAIL_EN, + .enable_val = PF1550_RAIL_EN_MASK, + .cfg_reg = PMIC_SW3_CTRL, + .uv_range = buck3_range, + .uv_nranges = ARRAY_SIZE(buck3_range), + .ua_range = buck123_current_limit_range, + .ua_nranges = ARRAY_SIZE(buck123_current_limit_range), +}; + +static const struct regulator_pf1550_desc __maybe_unused ldo1_desc = { + .vsel_reg = PMIC_LDO1_VOLT, + .enable_mask = PF1550_RAIL_EN, + .enable_val = PF1550_RAIL_EN_MASK, + .cfg_reg = PMIC_LDO1_CTRL, + .uv_range = ldo13_range, + .uv_nranges = ARRAY_SIZE(ldo13_range), +}; + +static const struct regulator_pf1550_desc __maybe_unused ldo2_desc = { + .vsel_reg = PMIC_LDO2_VOLT, + .enable_mask = PF1550_RAIL_EN, + .enable_val = PF1550_RAIL_EN_MASK, + .cfg_reg = PMIC_LDO2_CTRL, + .uv_range = ldo2_range, + .uv_nranges = ARRAY_SIZE(ldo2_range), +}; + +static const struct regulator_pf1550_desc __maybe_unused ldo3_desc = { + .vsel_reg = PMIC_LDO3_VOLT, + .enable_mask = PF1550_RAIL_EN, + .enable_val = PF1550_RAIL_EN_MASK, + .cfg_reg = PMIC_LDO3_CTRL, + .uv_range = ldo13_range, + .uv_nranges = ARRAY_SIZE(ldo13_range), +}; + +static int regulator_pf1550_set_enable(const struct device *dev, bool enable) +{ + const struct regulator_pf1550_config *config = dev->config; + + return i2c_reg_update_byte_dt(&config->bus, config->desc->cfg_reg, + config->desc->enable_mask, + enable ? config->desc->enable_val : 0); +} + +static int regulator_pf1550_enable(const struct device *dev) +{ + return regulator_pf1550_set_enable(dev, true); +} + +static int regulator_pf1550_disable(const struct device *dev) +{ + return regulator_pf1550_set_enable(dev, false); +} + +static unsigned int regulator_pf1550_count_voltages(const struct device *dev) +{ + const struct regulator_pf1550_config *config = dev->config; + + return linear_range_group_values_count(config->desc->uv_range, config->desc->uv_nranges); +} + +static int regulator_pf1550_list_voltage(const struct device *dev, unsigned int idx, + int32_t *volt_uv) +{ + const struct regulator_pf1550_config *config = dev->config; + + return linear_range_group_get_value(config->desc->uv_range, config->desc->uv_nranges, idx, + volt_uv); +} + +static int regulator_pf1550_set_buck_ldo_voltage(const struct device *dev, int32_t min_uv, + int32_t max_uv, const struct linear_range *range, + const uint8_t nranges, uint8_t vout_reg) +{ + const struct regulator_pf1550_config *config = dev->config; + uint16_t idx; + int ret; + + ret = linear_range_group_get_win_index(range, nranges, min_uv, max_uv, &idx); + if (ret < 0) { + return ret; + } + + return i2c_reg_write_byte_dt(&config->bus, vout_reg, (uint8_t)idx); +} + +static int regulator_pf1550_buck12_ldo123_get_voltage(const struct device *dev, + const struct linear_range *range, + const uint8_t nranges, uint8_t vout_reg, + int32_t *volt_uv) +{ + const struct regulator_pf1550_config *config = dev->config; + uint8_t idx; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, vout_reg, &idx); + if (ret < 0) { + return ret; + } + + return linear_range_group_get_value(range, nranges, idx, volt_uv); +} + +static int regulator_pf1550_get_voltage(const struct device *dev, int32_t *volt_uv) +{ + const struct regulator_pf1550_config *config = dev->config; + + return regulator_pf1550_buck12_ldo123_get_voltage(dev, config->desc->uv_range, + config->desc->uv_nranges, + config->desc->vsel_reg, volt_uv); +} + +static int regulator_pf1550_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv) +{ + const struct regulator_pf1550_config *config = dev->config; + + return regulator_pf1550_set_buck_ldo_voltage(dev, min_uv, max_uv, config->desc->uv_range, + config->desc->uv_nranges, + config->desc->vsel_reg); +} + +static unsigned int regulator_pf1550_count_current_limits(const struct device *dev) +{ + const struct regulator_pf1550_config *config = dev->config; + + if (config->source != PF1550_PMIC_SOURCE_BUCK1 && + config->source != PF1550_PMIC_SOURCE_BUCK2 && + config->source != PF1550_PMIC_SOURCE_BUCK3) { + return -ENOTSUP; + } + + return linear_range_group_values_count(config->desc->ua_range, config->desc->ua_nranges); +} + +static int regulator_pf1550_list_current_limit(const struct device *dev, unsigned int idx, + int32_t *current_ua) +{ + const struct regulator_pf1550_config *config = dev->config; + + if (config->source != PF1550_PMIC_SOURCE_BUCK1 && + config->source != PF1550_PMIC_SOURCE_BUCK2 && + config->source != PF1550_PMIC_SOURCE_BUCK3) { + return -ENOTSUP; + } + + return linear_range_group_get_value(config->desc->ua_range, config->desc->ua_nranges, idx, + current_ua); +} + +static int regulator_pf1550_set_current_limit(const struct device *dev, int32_t min_ua, + int32_t max_ua) +{ + const struct regulator_pf1550_config *config = dev->config; + uint8_t val; + uint16_t idx; + int ret; + + if (config->source != PF1550_PMIC_SOURCE_BUCK1 && + config->source != PF1550_PMIC_SOURCE_BUCK2 && + config->source != PF1550_PMIC_SOURCE_BUCK3) { + return -ENOTSUP; + } + + /* Current is stored in SW*_CTRL1 register */ + ret = i2c_reg_read_byte_dt(&config->bus, config->desc->cfg_reg + 1, &val); + if (ret < 0) { + return ret; + } + + ret = linear_range_group_get_win_index(config->desc->ua_range, config->desc->ua_nranges, + min_ua, max_ua, &idx); + if (ret < 0) { + return ret; + } + + val |= idx; + return i2c_reg_write_byte_dt(&config->bus, config->desc->cfg_reg + 1, val); +} + +static int regulator_pf1550_power_off(const struct device *dev) +{ + const struct regulator_pf1550_common_config *common_config = dev->config; + + return i2c_reg_update_byte_dt(&common_config->bus, PMIC_PWRCTRL3, PF1550_GOTO_SHIP_MASK, + PF1550_GOTO_SHIP); +} + +static int regulator_pf1550_init(const struct device *dev) +{ + const struct regulator_pf1550_config *config = dev->config; + + if (!i2c_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + regulator_common_data_init(dev); + + return regulator_common_init(dev, false); +} + +static int regulator_pf1550_common_init(const struct device *dev) +{ + const struct regulator_pf1550_common_config *common_config = dev->config; + + if (!i2c_is_ready_dt(&common_config->bus)) { + return -ENODEV; + } + + return 0; +} + +static const struct regulator_parent_driver_api parent_api = { + .ship_mode = regulator_pf1550_power_off, +}; + +static const struct regulator_driver_api api = { + .enable = regulator_pf1550_enable, + .disable = regulator_pf1550_disable, + .count_voltages = regulator_pf1550_count_voltages, + .list_voltage = regulator_pf1550_list_voltage, + .set_voltage = regulator_pf1550_set_voltage, + .get_voltage = regulator_pf1550_get_voltage, + .count_current_limits = regulator_pf1550_count_current_limits, + .list_current_limit = regulator_pf1550_list_current_limit, + .set_current_limit = regulator_pf1550_set_current_limit, +}; + +#define REGULATOR_PF1550_DEFINE(node_id, id, child_name, _source) \ + static const struct regulator_pf1550_config regulator_pf1550_config_##id = { \ + .common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \ + .bus = I2C_DT_SPEC_GET(DT_GPARENT(node_id)), \ + .desc = &child_name##_desc, \ + .source = _source, \ + }; \ + \ + static struct regulator_pf1550_data regulator_pf1550_data_##id; \ + DEVICE_DT_DEFINE(node_id, regulator_pf1550_init, NULL, ®ulator_pf1550_data_##id, \ + ®ulator_pf1550_config_##id, POST_KERNEL, \ + CONFIG_MFD_INIT_PRIORITY, &api); + +#define REGULATOR_PF1550_DEFINE_COND(inst, child, source) \ + COND_CODE_1( \ + DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \ + (REGULATOR_PF1550_DEFINE(DT_INST_CHILD(inst, child), child##inst, child, source)), \ + ()) + +#define REGULATOR_PF1550_DEFINE_ALL(inst) \ + static const struct regulator_pf1550_common_config common_config_##inst = { \ + .bus = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, regulator_pf1550_common_init, NULL, NULL, \ + &common_config_##inst, POST_KERNEL, \ + CONFIG_MFD_INIT_PRIORITY, &parent_api); \ + \ + REGULATOR_PF1550_DEFINE_COND(inst, buck1, PF1550_PMIC_SOURCE_BUCK1) \ + REGULATOR_PF1550_DEFINE_COND(inst, buck2, PF1550_PMIC_SOURCE_BUCK2) \ + REGULATOR_PF1550_DEFINE_COND(inst, buck3, PF1550_PMIC_SOURCE_BUCK3) \ + REGULATOR_PF1550_DEFINE_COND(inst, ldo1, PF1550_PMIC_SOURCE_LDO1) \ + REGULATOR_PF1550_DEFINE_COND(inst, ldo2, PF1550_PMIC_SOURCE_LDO2) \ + REGULATOR_PF1550_DEFINE_COND(inst, ldo3, PF1550_PMIC_SOURCE_LDO3) + +DT_INST_FOREACH_STATUS_OKAY(REGULATOR_PF1550_DEFINE_ALL) diff --git a/dts/bindings/charger/nxp,pf1550-charger.yaml b/dts/bindings/charger/nxp,pf1550-charger.yaml new file mode 100644 index 0000000000000..c149221143857 --- /dev/null +++ b/dts/bindings/charger/nxp,pf1550-charger.yaml @@ -0,0 +1,58 @@ +# Copyright (c), 2024 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +description: NXP PF1550 battery charger + +include: battery.yaml + +compatible: "nxp,pf1550-charger" + +properties: + constant-charge-voltage-max-microvolt: + required: true + + constant-charge-current-max-microamp: + required: true + + pf1550,vbus-current-limit-microamp: + type: int + required: true + description: | + VBUS current limit in microamperes. + + pf1550,system-voltage-min-threshold-microvolt: + type: int + required: true + enum: + - 3500000 + - 3700000 + - 4300000 + description: | + System voltage minimum threshold. + + pf1550,thermistor-monitoring-mode: + type: string + required: true + enum: + - "disabled" + - "thermistor" + - "JEITA-1" + - "JEITA-2" + description: | + Thermistor monitoring mode. + Refer to ThrmCfg register description and Table 2 for details. + + pf1550,int-gpios: + type: phandle-array + required: true + description: Interrupt pin + + pf1550,led-behaviour: + type: string + required: true + enum: + - "on-in-charging-flash-in-fault" + - "flash-in-charging-on-in-fault" + - "manual-off" + description: | + Behaviour for charger LED. diff --git a/dts/bindings/mfd/nxp,pf1550.yaml b/dts/bindings/mfd/nxp,pf1550.yaml new file mode 100644 index 0000000000000..53f6cdf2e2399 --- /dev/null +++ b/dts/bindings/mfd/nxp,pf1550.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +description: NXP PF1550 + +compatible: "nxp,pf1550" + +include: i2c-device.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/regulator/nxp,pf1550-regulator.yaml b/dts/bindings/regulator/nxp,pf1550-regulator.yaml new file mode 100644 index 0000000000000..8964b1857ef89 --- /dev/null +++ b/dts/bindings/regulator/nxp,pf1550-regulator.yaml @@ -0,0 +1,54 @@ +# Copyright (c), 2024 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP PF1550 PMIC + + The PMIC has two buck converters and three LDOs. All need to be defined as + children nodes, strictly following the BUCK1..3, LDO1..3 node names. For + example: + + pmic@8 { + reg = <0x8>; + ... + regulators { + compatible = nxp,pf1550-regulator"; + + BUCK1 { + /* all properties for BUCK1 */ + }; + BUCK2 { + /* all properties for BUCK2 */ + }; + BUCK3 { + /* all properties for BUCK3 */ + }; + LDO1 { + /* all properties for LDO1 */ + }; + LDO2 { + /* all properties for LDO2 */ + }; + LDO3 { + /* all properties for LDO3 */ + }; + }; + }; + +compatible: "nxp,pf1550-regulator" + +include: base.yaml + +child-binding: + include: + - name: regulator.yaml + property-allowlist: + - regulator-init-microvolt + - regulator-min-microvolt + - regulator-max-microvolt + - regulator-init-microamp + - regulator-max-microamp + - regulator-always-on + - regulator-boot-on + - regulator-initial-mode + - regulator-allowed-modes From 8c9af42a6378b09a614f9d71544f3f1deb5939c6 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 1 Aug 2024 14:01:16 +0200 Subject: [PATCH 0110/6055] portenta_h7: enable onboard regulator Enable PF1550 PMIC for Arduino Portenta H7 Signed-off-by: Martino Facchin --- .../arduino_portenta_h7_stm32h747xx_m7.dts | 48 +++++++++++++++++++ ...duino_portenta_h7_stm32h747xx_m7_defconfig | 3 ++ 2 files changed, 51 insertions(+) diff --git a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.dts b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.dts index 3a3745c5a7d57..001d8509059e2 100644 --- a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.dts +++ b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.dts @@ -86,6 +86,54 @@ &i2c1 { status = "okay"; + + pf1550: pmic@8 { + status = "okay"; + reg = <0x8>; + compatible = "nxp,pf1550"; + + pmic_regulators: regulators { + status = "okay"; + compatible = "nxp,pf1550-regulator"; + pf1550_sw1: BUCK1 { + regulator-init-microvolt = <3000000>; + regulator-boot-on; + }; + pf1550_sw2: BUCK2 { + regulator-init-microvolt = <3300000>; + regulator-boot-on; + }; + pf1550_sw3: BUCK3 { + regulator-init-microvolt = <3300000>; + regulator-init-microamp = <2000000>; + regulator-boot-on; + }; + pf1550_ldo1: LDO1 { + regulator-init-microvolt = <1000000>; + regulator-boot-on; + }; + pf1550_ldo2: LDO2 { + regulator-init-microvolt = <1800000>; + regulator-boot-on; + }; + pf1550_ldo3: LDO3 { + regulator-init-microvolt = <1200000>; + regulator-boot-on; + }; + }; + + pmic_charger: charger { + status = "okay"; + compatible = "nxp,pf1550-charger"; + constant-charge-current-max-microamp = <100000>; + constant-charge-voltage-max-microvolt = <4200000>; + pf1550,int-gpios = <&gpiok 0 0>; + pf1550,led-behaviour = "manual-off"; + pf1550,system-voltage-min-threshold-microvolt = <3500000>; + pf1550,thermistor-monitoring-mode = "thermistor"; + pf1550,vbus-current-limit-microamp = <1500000>; + }; + }; }; /* Only one should be enabled */ diff --git a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7_defconfig b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7_defconfig index acc978d70c986..06d55f8db39ac 100644 --- a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7_defconfig +++ b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7_defconfig @@ -25,3 +25,6 @@ CONFIG_UART_LINE_CTRL=y # Enable regulator CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED=y + +# Enable USB Stack +CONFIG_USB_DEVICE_STACK=y From 8f8fb147dbf5bde5f023af31cb150b9f7930bcaa Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 1 Aug 2024 14:01:45 +0200 Subject: [PATCH 0111/6055] portenta_h7: enable ethernet driver On older Portenta H7, 1V2 power rail must be enabled to get a functional ethernet phy. Signed-off-by: Martino Facchin --- boards/arduino/portenta_h7/Kconfig.defconfig | 3 +++ .../arduino_portenta_h7-common.dtsi | 19 +++++++++++++++++-- .../arduino_portenta_h7_stm32h747xx_m7.yaml | 7 +++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/boards/arduino/portenta_h7/Kconfig.defconfig b/boards/arduino/portenta_h7/Kconfig.defconfig index b2a4abd35e733..3a59127ffa711 100644 --- a/boards/arduino/portenta_h7/Kconfig.defconfig +++ b/boards/arduino/portenta_h7/Kconfig.defconfig @@ -5,6 +5,9 @@ if BOARD_ARDUINO_PORTENTA_H7 if NETWORKING +config REGULATOR + default y + config NET_L2_ETHERNET default y diff --git a/boards/arduino/portenta_h7/arduino_portenta_h7-common.dtsi b/boards/arduino/portenta_h7/arduino_portenta_h7-common.dtsi index 7a61e830e5267..bf6f3348c9309 100644 --- a/boards/arduino/portenta_h7/arduino_portenta_h7-common.dtsi +++ b/boards/arduino/portenta_h7/arduino_portenta_h7-common.dtsi @@ -209,17 +209,32 @@ }; }; +&rng { + status = "okay"; +}; + &mac { pinctrl-0 = < ð_ref_clk_pa1 - ð_mdio_pa2 ð_crs_dv_pa7 - ð_mdc_pc1 ð_rxd0_pc4 ð_rxd1_pc5 ð_tx_en_pg11 ð_txd1_pg12 ð_txd0_pg13 >; pinctrl-names = "default"; + status = "okay"; +}; + +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0x00>; + status = "okay"; + }; }; zephyr_udc0: &usbotg_hs { diff --git a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.yaml b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.yaml index e4179c6e5b9c6..97a23152c59fa 100644 --- a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.yaml +++ b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.yaml @@ -9,4 +9,11 @@ ram: 512 flash: 1024 supported: - gpio + - netif:eth + - i2c + - spi + - qspi + - memc + - usb_cdc + - usb_device vendor: arduino From d720fd7279272321e7dd941296bd5ba21913d78a Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 31 Jul 2024 11:41:16 +0200 Subject: [PATCH 0112/6055] portenta_h7: fix dangerous misconfiguration Selecting the wrong power scheme could potentially destroy the board. Luckily, the bit can only be set once and the default build still uses the Arduino bootloader (which has the correct setting). Signed-off-by: Martino Facchin --- .../portenta_h7/arduino_portenta_h7_stm32h747xx_m7_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7_defconfig b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7_defconfig index 06d55f8db39ac..1260af5f054b6 100644 --- a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7_defconfig +++ b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7_defconfig @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 # Enable the internal SMPS regulator -CONFIG_POWER_SUPPLY_DIRECT_SMPS=y +CONFIG_POWER_SUPPLY_SMPS_1V8_SUPPLIES_LDO=y # Enable GPIO CONFIG_GPIO=y From 637686695c5496d56ad7806b6311ae4e7d83a067 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Tue, 5 Nov 2024 12:02:06 +0100 Subject: [PATCH 0113/6055] sensor: Introduce Phosense XBR818 Driver This Introduces a driver for the i2c interface of Phosense XBR818. XBR818 is a 10.525Ghz Radar chip with builtin detection algorithm. Signed-off-by: Camille BAUD --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/xbr818/CMakeLists.txt | 5 + drivers/sensor/xbr818/Kconfig | 10 + drivers/sensor/xbr818/xbr818.c | 434 +++++++++++++++++++++++ drivers/sensor/xbr818/xbr818.h | 97 +++++ dts/bindings/sensor/phosense,xbr818.yaml | 19 + dts/bindings/vendor-prefixes.txt | 1 + include/zephyr/drivers/sensor/xbr818.h | 44 +++ tests/drivers/build_all/sensor/i2c.dtsi | 7 + 10 files changed, 619 insertions(+) create mode 100644 drivers/sensor/xbr818/CMakeLists.txt create mode 100644 drivers/sensor/xbr818/Kconfig create mode 100644 drivers/sensor/xbr818/xbr818.c create mode 100644 drivers/sensor/xbr818/xbr818.h create mode 100644 dts/bindings/sensor/phosense,xbr818.yaml create mode 100644 include/zephyr/drivers/sensor/xbr818.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 5b7f168f250f1..46496280f0cd4 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -63,6 +63,7 @@ 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_XBR818 xbr818) add_subdirectory_ifdef(CONFIG_TACH_ENE_KB1200 ene_tach_kb1200) zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/sensor.h) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 091d8153ab8d6..096379c9c553f 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -149,6 +149,7 @@ 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/xbr818/Kconfig" source "drivers/sensor/ene_tach_kb1200/Kconfig" endif # SENSOR diff --git a/drivers/sensor/xbr818/CMakeLists.txt b/drivers/sensor/xbr818/CMakeLists.txt new file mode 100644 index 0000000000000..96d6c578d64db --- /dev/null +++ b/drivers/sensor/xbr818/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_XBR818 xbr818.c) diff --git a/drivers/sensor/xbr818/Kconfig b/drivers/sensor/xbr818/Kconfig new file mode 100644 index 0000000000000..75b91c758ac78 --- /dev/null +++ b/drivers/sensor/xbr818/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +config XBR818 + bool "XBR818 Radar" + default y + depends on DT_HAS_PHOSENSE_XBR818_ENABLED + select I2C + help + Enable driver for the Phosense XBR818 Radar Sensor diff --git a/drivers/sensor/xbr818/xbr818.c b/drivers/sensor/xbr818/xbr818.c new file mode 100644 index 0000000000000..be396ec620e6d --- /dev/null +++ b/drivers/sensor/xbr818/xbr818.c @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT phosense_xbr818 + +#include +#include + +#include +LOG_MODULE_REGISTER(XBR818, CONFIG_SENSOR_LOG_LEVEL); + +#include "xbr818.h" +#include + +static int xbr818_enable_i2c(const struct device *dev) +{ + const struct xbr818_config *config = dev->config; + int ret; + + if (config->i2c_en.port) { + ret = gpio_pin_set_dt(&config->i2c_en, 1); + if (ret != 0) { + LOG_ERR("%s: could not set i2c_en pin", dev->name); + } + k_usleep(10); + return ret; + } + return 0; +} + +static int xbr818_disable_i2c(const struct device *dev) +{ + const struct xbr818_config *config = dev->config; + int ret; + + if (config->i2c_en.port) { + ret = gpio_pin_set_dt(&config->i2c_en, 0); + if (ret != 0) { + LOG_ERR("%s: could not unset i2c_en pin", dev->name); + } + return ret; + } + return 0; +} + +static int xbr818_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct xbr818_config *config = dev->config; + struct xbr818_data *data = dev->data; + int ret; + + if (chan != SENSOR_CHAN_PROX && chan != SENSOR_CHAN_ALL) { + LOG_ERR("%s: requesting unsupported channel %i", dev->name, chan); + return -ENOTSUP; + } + + ret = gpio_pin_get_dt(&config->io_val); + if (ret < 0) { + return ret; + } + data->value = (ret == 1 ? true : false); + + return 0; +} + +static int xbr818_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct xbr818_data *data = dev->data; + + if (chan != SENSOR_CHAN_PROX) { + LOG_ERR("%s: requesting unsupported channel %i", dev->name, chan); + return -ENOTSUP; + } + + val->val1 = (data->value ? 1 : 0); + val->val2 = 0; + + return 0; +} + +static int xbr818_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + const struct xbr818_config *config = dev->config; + int ret; + uint8_t tmp[3]; + uint64_t tmpf; + + if (chan != SENSOR_CHAN_PROX) { + LOG_ERR("%s: requesting unsupported channel %i", dev->name, chan); + return -ENOTSUP; + } + + if (val->val1 < 0) { + return -EINVAL; + } + + ret = xbr818_enable_i2c(dev); + if (ret != 0) { + return ret; + } + + if (attr == SENSOR_ATTR_LOWER_THRESH) { + if (val->val1 > 0xFFFF || val->val1 < 0) { + return -EINVAL; + } + tmp[0] = val->val1 & 0xFF; + tmp[1] = (val->val1 & 0xFF00) >> 8; + ret = i2c_burst_write_dt(&config->i2c, XBR818_THRESHOLD_1, tmp, 2); + } else if ((enum sensor_attribute_xbr818)attr == SENSOR_ATTR_XBR818_NOISE_FLOOR) { + if (val->val1 > 0xFFFF || val->val1 < 0) { + return -EINVAL; + } + tmp[0] = val->val1 & 0xFF; + tmp[1] = (val->val1 & 0xFF00) >> 8; + ret = i2c_burst_write_dt(&config->i2c, XBR818_THRESHOLD_NOISE_1, tmp, 2); + } else if ((enum sensor_attribute_xbr818)attr == SENSOR_ATTR_XBR818_DELAY_TIME) { + if (val->val1 < 0 || val->val2 < 0) { + return -EINVAL; + } + tmpf = (uint64_t)val->val1 * 1000000 + (uint64_t)val->val2; + tmpf = (tmpf * SENSOR_XBR818_CLOCKRATE) / 1000000; + if (tmpf > 0xFFFFFF) { + return -EINVAL; + } + tmp[0] = tmpf & 0xFF; + tmp[1] = (tmpf & 0xFF00) >> 8; + tmp[2] = (tmpf & 0xFF0000) >> 16; + ret = i2c_burst_write_dt(&config->i2c, XBR818_DELAY_TIME_1, tmp, 3); + } else if ((enum sensor_attribute_xbr818)attr == SENSOR_ATTR_XBR818_LOCK_TIME) { + if (val->val1 < 0 || val->val2 < 0) { + return -EINVAL; + } + tmpf = (uint64_t)val->val1 * 1000000 + (uint64_t)val->val2; + tmpf = (tmpf * SENSOR_XBR818_CLOCKRATE) / 1000000; + if (tmpf > 0xFFFFFF) { + return -EINVAL; + } + tmp[0] = tmpf & 0xFF; + tmp[1] = (tmpf & 0xFF00) >> 8; + tmp[2] = (tmpf & 0xFF0000) >> 16; + ret = i2c_burst_write_dt(&config->i2c, XBR818_LOCK_TIME_1, tmp, 3); + } else if ((enum sensor_attribute_xbr818)attr == SENSOR_ATTR_XBR818_RF_POWER) { + if (val->val1 > 0x7 || val->val1 < 0) { + return -EINVAL; + } + tmp[0] = val->val1 & 0x7; + ret = i2c_reg_write_byte_dt(&config->i2c, XBR818_RF_POWER, tmp[0]); + } else if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + if (val->val1 > SENSOR_XBR818_CLOCKRATE || val->val1 <= 0) { + return -EINVAL; + } + tmp[0] = SENSOR_XBR818_CLOCKRATE / val->val1; + if (tmp[0] > 0xFF) { + return -EINVAL; + } + ret = i2c_reg_write_byte_dt(&config->i2c, XBR818_SAMPLE_RATE_DIVIDER, tmp[0]); + } else { + ret = xbr818_disable_i2c(dev); + if (ret != 0) { + return ret; + } + return -ENODEV; + } + + if (ret != 0) { + return ret; + } + + ret = xbr818_disable_i2c(dev); + + return ret; +} + +static int xbr818_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + const struct xbr818_config *config = dev->config; + int ret; + uint8_t tmp[3]; + uint64_t tmpf; + + if (chan != SENSOR_CHAN_PROX) { + LOG_ERR("%s: requesting unsupported channel %i", dev->name, chan); + return -ENOTSUP; + } + + ret = xbr818_enable_i2c(dev); + if (ret != 0) { + return ret; + } + + if (attr == SENSOR_ATTR_LOWER_THRESH) { + ret = i2c_burst_read_dt(&config->i2c, XBR818_THRESHOLD_1, tmp, 2); + if (ret != 0) { + return ret; + } + val->val1 = tmp[0] & 0xFF; + val->val1 |= (uint32_t)tmp[1] << 8; + } else if ((enum sensor_attribute_xbr818)attr == SENSOR_ATTR_XBR818_NOISE_FLOOR) { + ret = i2c_burst_read_dt(&config->i2c, XBR818_THRESHOLD_NOISE_1, tmp, 2); + if (ret != 0) { + return ret; + } + val->val1 = tmp[0] & 0xFF; + val->val1 |= (uint32_t)tmp[1] << 8; + } else if ((enum sensor_attribute_xbr818)attr == SENSOR_ATTR_XBR818_DELAY_TIME) { + ret = i2c_burst_read_dt(&config->i2c, XBR818_DELAY_TIME_1, tmp, 3); + if (ret != 0) { + return ret; + } + val->val1 = tmp[0] & 0xFF; + val->val1 |= (uint32_t)tmp[1] << 8; + val->val1 |= (uint32_t)tmp[2] << 16; + tmpf = (uint64_t)val->val1 * 1000000; + tmpf /= SENSOR_XBR818_CLOCKRATE; + val->val1 = tmpf / 1000000; + val->val2 = tmpf - val->val1 * 1000000; + } else if ((enum sensor_attribute_xbr818)attr == SENSOR_ATTR_XBR818_LOCK_TIME) { + ret = i2c_burst_read_dt(&config->i2c, XBR818_LOCK_TIME_1, tmp, 3); + if (ret != 0) { + return ret; + } + val->val1 = tmp[0] & 0xFF; + val->val1 |= (uint32_t)tmp[1] << 8; + val->val1 |= (uint32_t)tmp[2] << 16; + tmpf = (uint64_t)val->val1 * 1000000; + tmpf /= SENSOR_XBR818_CLOCKRATE; + val->val1 = tmpf / 1000000; + val->val2 = tmpf - val->val1 * 1000000; + } else if ((enum sensor_attribute_xbr818)attr == SENSOR_ATTR_XBR818_RF_POWER) { + ret = i2c_reg_read_byte_dt(&config->i2c, XBR818_RF_POWER, tmp); + if (ret != 0) { + return ret; + } + val->val1 = *tmp & 0x7; + } else if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + ret = i2c_reg_read_byte_dt(&config->i2c, XBR818_SAMPLE_RATE_DIVIDER, tmp); + if (ret != 0) { + return ret; + } + val->val1 = SENSOR_XBR818_CLOCKRATE / *tmp; + } else { + ret = xbr818_disable_i2c(dev); + if (ret != 0) { + return ret; + } + return -ENODEV; + } + + ret = xbr818_disable_i2c(dev); + + return ret; +} + +static void xbr818_work(struct k_work *work) +{ + struct xbr818_data *data = CONTAINER_OF(work, struct xbr818_data, work); + + if (likely(data->handler != NULL)) { + data->handler(data->dev, data->trigger); + } +} + +static void xbr818_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) +{ + struct xbr818_data *data = CONTAINER_OF(cb, struct xbr818_data, gpio_cb); + + k_work_submit(&data->work); +} + +static int xbr818_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct xbr818_config *config = dev->config; + struct xbr818_data *data = dev->data; + int ret; + + if (trig->chan != SENSOR_CHAN_PROX) { + LOG_ERR("%s: requesting unsupported channel %i", dev->name, trig->chan); + return -ENOTSUP; + } + + if (trig->type != SENSOR_TRIG_MOTION) { + LOG_ERR("%s: requesting unsupported trigger %i", dev->name, trig->type); + return -ENOTSUP; + } + + data->handler = handler; + data->trigger = trig; + ret = gpio_pin_interrupt_configure_dt(&config->io_val, GPIO_INT_EDGE_RISING); + if (ret < 0) { + return ret; + } + + if (handler) { + ret = gpio_add_callback(config->io_val.port, &data->gpio_cb); + } else { + ret = gpio_remove_callback(config->io_val.port, &data->gpio_cb); + } + + return ret; +} + +static int xbr818_init_defaults(const struct device *dev) +{ + const struct xbr818_config *config = dev->config; + int ret = 0; + uint8_t data[3]; + + ret |= i2c_reg_write_byte_dt(&config->i2c, XBR818_IO_ACTIVE_VALUE_REG, 0x03); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_IO_ACTIVE_VALUE_REG"); + ret |= i2c_reg_write_byte_dt(&config->i2c, XBR818_RF_EN_SEL, 0x20); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_RF_EN_SEL"); + ret |= i2c_reg_write_byte_dt(&config->i2c, XBR818_SAMPLE_RATE_DIVIDER, 0x20); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_SAMPLE_RATE_DIVIDER"); + ret |= i2c_reg_write_byte_dt(&config->i2c, XBR818_RF_POWER, 0x45); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_RF_POWER"); + ret |= i2c_reg_write_byte_dt(&config->i2c, XBR818_TIMER_CTRL, 0x21); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_TIMER_CTRL"); + + data[0] = 0x5a; + data[1] = 0x01; + ret |= i2c_burst_write_dt(&config->i2c, XBR818_THRESHOLD_1, data, 2); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_THRESHOLD"); + + data[0] = 0x55; + data[1] = 0x01; + ret |= i2c_burst_write_dt(&config->i2c, XBR818_THRESHOLD_NOISE_1, data, 2); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_THRESHOLD_NOISE"); + + /* 0.1 seconds */ + data[0] = 0x80; + data[1] = 0x0C; + data[2] = 0x00; + ret |= i2c_burst_write_dt(&config->i2c, XBR818_DELAY_TIME_1, data, 3); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_DELAY_TIME"); + + /* 0.5 seconds */ + data[0] = 0x80; + data[1] = 0x3E; + data[2] = 0x00; + ret |= i2c_burst_write_dt(&config->i2c, XBR818_LOCK_TIME_1, data, 3); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_LOCK_TIME"); + + ret |= i2c_reg_write_byte_dt(&config->i2c, XBR818_PIN_SETTINGS, 0x0C); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_PIN_SETTINGS"); + + ret |= i2c_reg_write_byte_dt(&config->i2c, XBR818_I2C_OUT, 0x1); + __ASSERT(ret == 0, "Error sending XBR818 defaults for XBR818_I2C_OUT"); + + return ret; +} + +static int xbr818_init(const struct device *dev) +{ + const struct xbr818_config *config = dev->config; + struct xbr818_data *data = dev->data; + int ret; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + + data->dev = dev; + data->work.handler = xbr818_work; + + ret = gpio_pin_configure_dt(&config->io_val, GPIO_INPUT); + if (ret != 0) { + LOG_ERR("%s: could not configure io_val(int) pin", dev->name); + return ret; + } + + if (config->i2c_en.port) { + ret = gpio_pin_configure_dt(&config->i2c_en, GPIO_OUTPUT); + if (ret != 0) { + LOG_ERR("%s: could not configure i2c_en pin", dev->name); + return ret; + } + } + + ret = xbr818_enable_i2c(dev); + if (ret != 0) { + return ret; + } + + ret = xbr818_init_defaults(dev); + if (ret != 0) { + LOG_ERR("%s: unable to configure", dev->name); + } + + ret = xbr818_disable_i2c(dev); + if (ret != 0) { + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&config->io_val, GPIO_INT_DISABLE); + if (ret) { + LOG_ERR("%s: failed to configure gpio interrupt: %d", dev->name, ret); + return ret; + } + + gpio_init_callback(&data->gpio_cb, xbr818_gpio_callback, BIT(config->io_val.pin)); + + return ret; +} + +static const struct sensor_driver_api xbr818_api = { + .sample_fetch = xbr818_sample_fetch, + .channel_get = xbr818_channel_get, + .attr_set = xbr818_attr_set, + .attr_get = xbr818_attr_get, + .trigger_set = xbr818_trigger_set, +}; + +#define XBR818_INIT(inst) \ + static const struct xbr818_config xbr818_##inst##_config = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .i2c_en = GPIO_DT_SPEC_GET_OR(DT_INST(inst, phosense_xbr818), i2c_en_gpios, {0}), \ + .io_val = GPIO_DT_SPEC_GET(DT_INST(inst, phosense_xbr818), int_gpios), \ + }; \ + \ + static struct xbr818_data xbr818_##inst##_data; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, xbr818_init, NULL, &xbr818_##inst##_data, \ + &xbr818_##inst##_config, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &xbr818_api); + +DT_INST_FOREACH_STATUS_OKAY(XBR818_INIT); diff --git a/drivers/sensor/xbr818/xbr818.h b/drivers/sensor/xbr818/xbr818.h new file mode 100644 index 0000000000000..f30f6d5ed0d48 --- /dev/null +++ b/drivers/sensor/xbr818/xbr818.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_XBR818_XBR818_H_ +#define ZEPHYR_DRIVERS_SENSOR_XBR818_XBR818_H_ + +#include +#include +#include +#include + +/* 32Khz clockrate, most time values are multiple of this */ +#define SENSOR_XBR818_CLOCKRATE 32000 + +struct xbr818_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec i2c_en; + struct gpio_dt_spec io_val; +}; + +struct xbr818_data { + bool value; + uint32_t trigger_type; + sensor_trigger_handler_t handler; + struct gpio_callback gpio_cb; + const struct sensor_trigger *trigger; + const struct device *dev; + struct k_work work; +}; + +/* reference rd-04 module manual for more information */ +/* [0-2]: power of PA + * [4-6]: mixer trim + */ +#define XBR818_RF_POWER 0x03 +#define XBR818_RF_EN_SEL 0x04 +/* minimum value of 2 */ +#define XBR818_SAMPLE_RATE_DIVIDER 0x10 +/* [0]: enable detection + * [1-2]: readable data. 0: det_dc_sum 1: det_ac_sum 2: det_dc_used 3: det_noise + * [3]: enable read on 0x28-0x29 + * [4]: signal detection threshold. 0: auto by pin 1: register + * [7]: enable read on 0x26-0x29 + */ +#define XBR818_I2C_OUT 0x13 +/* Threshold for detection + * [0-7] + */ +#define XBR818_THRESHOLD_1 0x18 +/* [8-15] */ +#define XBR818_THRESHOLD_2 0x19 +/* Threshold for noise + * [0-7] + */ +#define XBR818_THRESHOLD_NOISE_1 0x1A +/* [8-15] */ +#define XBR818_THRESHOLD_NOISE_2 0x1B +/* Delay Time (in 1/32000 seconds) + * [0-7] + */ +#define XBR818_DELAY_TIME_1 0x1D +/* [8-15] */ +#define XBR818_DELAY_TIME_2 0x1E +/* [16-23] */ +#define XBR818_DELAY_TIME_3 0x1F +/* [0]: enable + * [1-2]: light sensor timer. 0: disabled 1: 4 sec 2: 1 minute 3: 1 hour + * [3-4]: output timer. 0: 1 sec 1: 1 minute 2: 1 hour 3: 1 day + * [5]: delay time. 0: 'configure by pin' 1: configure by register + */ +#define XBR818_TIMER_CTRL 0x1C +/* Lock Time (in 1/32000 seconds) + * [0-7] + */ +#define XBR818_LOCK_TIME_1 0x20 +/* [8-15] */ +#define XBR818_LOCK_TIME_2 0x21 +/* [16-23] */ +#define XBR818_LOCK_TIME_3 0x22 +/* Pin settings + * [0-3]: IO_VAL pin + * 0xc: io_value_out, 0xd: io_value_out inverted, 0xf: GPIO + * [4-7]: INT_IRQ pin + * 0x0: t3_int_irq, 0x9: io_value_out, 0xa: io_value_out inverted, 0xf: GPIO + */ +#define XBR818_PIN_SETTINGS 0x23 +/* [0]: ADC1 is configured for VCO trimming. 0: enable, 1: disable + * [1]: Low power mode is pin or register. 0: pin 1: register + * [2]: If IO_VAL pin is GPIO, output. 0: no 1: yes + * [3]: if INT_IRQ pin is GPIO, output. 0:no 1:yes + */ +#define XBR818_IO_ACTIVE_VALUE_REG 0x24 + +#endif /* ZEPHYR_DRIVERS_SENSOR_XBR818_XBR818_H_ */ diff --git a/dts/bindings/sensor/phosense,xbr818.yaml b/dts/bindings/sensor/phosense,xbr818.yaml new file mode 100644 index 0000000000000..9eeedba058472 --- /dev/null +++ b/dts/bindings/sensor/phosense,xbr818.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: | + Phosense XBR818 I2C-capable 10 GHz Radar Sensor + +compatible: "phosense,xbr818" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + int-gpios: + type: phandle-array + required: true + description: GPIO pin connected to IO pin (IO_VAL) + + i2c-en-gpios: + type: phandle-array + description: GPIO pin connected to I2C enable (I2C_EN) diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index 70cbb8fbc2a5c..8243f706f1edf 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -510,6 +510,7 @@ peregrine Peregrine Consultoria e Servicos pericom Pericom Technology Inc. pervasive Pervasive Displays, Inc. phicomm PHICOMM Co., Ltd. +phosense Beijing Phosense Electronic Technology Co., Ltd. phytec PHYTEC picochip Picochip Ltd pine64 Pine64 diff --git a/include/zephyr/drivers/sensor/xbr818.h b/include/zephyr/drivers/sensor/xbr818.h new file mode 100644 index 0000000000000..06cac96cbde5d --- /dev/null +++ b/include/zephyr/drivers/sensor/xbr818.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Extended public API for Phosense XBR818 10 GHz Radar + * + * This exposes 4 additional attributes used to configure the IC + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_XBR818_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_XBR818_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum sensor_attribute_xbr818 { + /*! + * Time of received activity before output is triggered, in seconds + */ + SENSOR_ATTR_XBR818_DELAY_TIME = SENSOR_ATTR_PRIV_START, + /*! + * How long output stays triggered after no more activity is detected, in seconds + */ + SENSOR_ATTR_XBR818_LOCK_TIME, + /*! + * Noise floor Threshold for Radar, 16 first LSBs of the integer part. + */ + SENSOR_ATTR_XBR818_NOISE_FLOOR, + /*! + * RF Power for Radar, 0 to 7, LSB of the integer part. + */ + SENSOR_ATTR_XBR818_RF_POWER +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_XBR818_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index f9f4e3cddf1fb..6dcbea94d7783 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -1244,3 +1244,10 @@ test_i2c_tmp435: tmp435@a9 { resistance-correction; beta-compensation = <0x0f>; }; + +test_i2c_xbr818: xbr818@aa { + compatible = "phosense,xbr818"; + reg = <0xaa>; + int-gpios = <&test_gpio 0 0>; + i2c-en-gpios = <&test_gpio 0 0>; +}; From ccc21a082e19360c1c2e829d6950af44a5cc3f52 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Thu, 26 Dec 2024 11:28:09 +0800 Subject: [PATCH 0114/6055] dts: arm: nxp: add M7 ITCM/DTCM region into linker Added M7 ITCM/DTCM region into linker. Signed-off-by: Yangbo Lu --- dts/arm/nxp/nxp_rt118x_cm7.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dts/arm/nxp/nxp_rt118x_cm7.dtsi b/dts/arm/nxp/nxp_rt118x_cm7.dtsi index 50aa4aa7c4a3e..91cfc7a95a09a 100644 --- a/dts/arm/nxp/nxp_rt118x_cm7.dtsi +++ b/dts/arm/nxp/nxp_rt118x_cm7.dtsi @@ -10,13 +10,15 @@ / { soc { itcm: itcm@0{ - compatible = "nxp,imx-itcm"; + compatible = "zephyr,memory-region", "nxp,imx-itcm"; reg = <0x00000000 DT_SIZE_K(256)>; + zephyr,memory-region = "ITCM"; }; dtcm: dtcm@20000000 { - compatible = "nxp,imx-dtcm"; + compatible = "zephyr,memory-region", "nxp,imx-dtcm"; reg = <0x20000000 DT_SIZE_K(256)>; + zephyr,memory-region = "DTCM"; }; memory: memory@20484000 { From c348e03bb2e96e318d46ed47c281a0151217a55d Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Thu, 26 Dec 2024 11:41:30 +0800 Subject: [PATCH 0115/6055] boards: nxp: mimxrt1180_evk: convert to use hyperram and flash for M7 Converted to use hyperram and flash for M7. Signed-off-by: Yangbo Lu --- .../mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts index 2bc79fbca2cca..d66863eea3100 100644 --- a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts +++ b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts @@ -14,13 +14,21 @@ compatible = "nxp,mimxrt1189"; chosen { - zephyr,sram = &dtcm; + zephyr,sram = &hyperram0; + zephyr,dtcm = &dtcm; + zephyr,itcm = &itcm; zephyr,flash-controller = &w25q128jw; - zephyr,flash = &itcm; + zephyr,flash = &w25q128jw; zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; zephyr,canbus = &flexcan3; }; + + hyperram0: memory@04000000 { + /* Winbond W957A8MFYA5K */ + device_type = "memory"; + reg = <0x04000000 DT_SIZE_M(8)>; + }; }; &enetc_psi0 { From 2d72d7df7bccd78eb210c82d0a0bbddf6dfe497e Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Thu, 13 Feb 2025 10:13:42 +0800 Subject: [PATCH 0116/6055] boards: nxp: mimxrt1180_evk: enable NETC PSI0 for M7 Enabled NETC PSI0 for M7 via common board dtsi. Signed-off-by: Yangbo Lu --- boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts index d66863eea3100..5ac690d3c39df 100644 --- a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts +++ b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts @@ -31,10 +31,6 @@ }; }; -&enetc_psi0 { - status = "disabled"; -}; - &lpuart1 { status = "okay"; current-speed = <115200>; From f370d38363f24450d85aaa28e9712ad552845e7c Mon Sep 17 00:00:00 2001 From: Marcin Lyda Date: Sat, 1 Feb 2025 14:32:51 +0100 Subject: [PATCH 0117/6055] drivers: rtc: Add Maxim DS1337 RTC driver This PR adds support for Maxim Integrated DS1337 RTC chip. Supported functionalities: * Alarm interrupt (both alarms trigger INTA pin) * Time setting/reading * Both alarms setting/reading * SQW frequency configuration Tested on nRF52833-DK using rtc_api test set. Signed-off-by: Marcin Lyda --- drivers/rtc/CMakeLists.txt | 1 + drivers/rtc/Kconfig | 1 + drivers/rtc/Kconfig.ds1337 | 10 + drivers/rtc/rtc_ds1337.c | 737 ++++++++++++++++++ dts/bindings/rtc/maxim,ds1337.yaml | 30 + .../drivers/build_all/rtc/i2c_devices.overlay | 8 + 6 files changed, 787 insertions(+) create mode 100644 drivers/rtc/Kconfig.ds1337 create mode 100644 drivers/rtc/rtc_ds1337.c create mode 100644 dts/bindings/rtc/maxim,ds1337.yaml diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index d2cbe253bc17b..0344e8d63d6a3 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -32,3 +32,4 @@ zephyr_library_sources_ifdef(CONFIG_RTC_NXP_IRTC rtc_nxp_irtc.c) zephyr_library_sources_ifdef(CONFIG_RTC_RV8803 rtc_rv8803.c) zephyr_library_sources_ifdef(CONFIG_RTC_BQ32002 rtc_bq32002.c) zephyr_library_sources_ifdef(CONFIG_RTC_RX8130CE rtc_rx8130ce.c) +zephyr_library_sources_ifdef(CONFIG_RTC_DS1337 rtc_ds1337.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b8779c77201e6..7846eb2c67a7c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -64,5 +64,6 @@ source "drivers/rtc/Kconfig.nxp_irtc" source "drivers/rtc/Kconfig.rv8803" source "drivers/rtc/Kconfig.bq32002" source "drivers/rtc/Kconfig.rx8130ce" +source "drivers/rtc/Kconfig.ds1337" endif # RTC diff --git a/drivers/rtc/Kconfig.ds1337 b/drivers/rtc/Kconfig.ds1337 new file mode 100644 index 0000000000000..9d2079f46551c --- /dev/null +++ b/drivers/rtc/Kconfig.ds1337 @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Marcin Lyda +# SPDX-License-Identifier: Apache-2.0 + +config RTC_DS1337 + bool "Maxim DS1337 RTC driver" + default y + depends on DT_HAS_MAXIM_DS1337_ENABLED + select I2C + help + Enable Maxim DS1337 RTC driver. diff --git a/drivers/rtc/rtc_ds1337.c b/drivers/rtc/rtc_ds1337.c new file mode 100644 index 0000000000000..209f5086d1c82 --- /dev/null +++ b/drivers/rtc/rtc_ds1337.c @@ -0,0 +1,737 @@ +/* + * Copyright (c) 2025 Marcin Lyda + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include "rtc_utils.h" + +LOG_MODULE_REGISTER(ds1337, CONFIG_RTC_LOG_LEVEL); + +#define DT_DRV_COMPAT maxim_ds1337 + +#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 +#warning "Maxim DS1337 RTC driver enabled without any devices" +#endif + +/* Registers */ +#define DS1337_SECONDS_REG 0x00 +#define DS1337_ALARM_1_SECONDS_REG 0x07 +#define DS1337_ALARM_2_MINUTES_REG 0x0B +#define DS1337_CONTROL_REG 0x0E +#define DS1337_STATUS_REG 0x0F + +/* Bitmasks */ +#define DS1337_SECONDS_MASK GENMASK(6, 0) +#define DS1337_MINUTES_MASK GENMASK(6, 0) +#define DS1337_HOURS_MASK GENMASK(5, 0) +#define DS1337_DAY_MASK GENMASK(2, 0) +#define DS1337_DATE_MASK GENMASK(5, 0) +#define DS1337_MONTH_MASK GENMASK(4, 0) +#define DS1337_YEAR_MASK GENMASK(7, 0) +#define DS1337_ALARM_SECONDS_MASK GENMASK(6, 0) +#define DS1337_ALARM_MINUTES_MASK GENMASK(6, 0) +#define DS1337_ALARM_HOURS_MASK GENMASK(5, 0) +#define DS1337_ALARM_DAY_MASK GENMASK(3, 0) +#define DS1337_ALARM_DATE_MASK GENMASK(5, 0) + +#define DS1337_12_24_MODE_MASK BIT(6) +#define DS1337_CENTURY_MASK BIT(7) +#define DS1337_DY_DT_MASK BIT(6) + +#define DS1337_ALARM_DISABLE_MASK BIT(7) + +#define DS1337_EOSC_MASK BIT(7) +#define DS1337_RS_MASK GENMASK(4, 3) +#define DS1337_INTCN_MASK BIT(2) +#define DS1337_A2IE_MASK BIT(1) +#define DS1337_A1IE_MASK BIT(0) + +#define DS1337_OSF_MASK BIT(7) +#define DS1337_A2F_MASK BIT(1) +#define DS1337_A1F_MASK BIT(0) + +#define DS1337_SQW_FREQ_1Hz FIELD_PREP(DS1337_RS_MASK, 0x00) +#define DS1337_SQW_FREQ_4096Hz FIELD_PREP(DS1337_RS_MASK, 0x01) +#define DS1337_SQW_FREQ_8192Hz FIELD_PREP(DS1337_RS_MASK, 0x02) +#define DS1337_SQW_FREQ_32768Hz FIELD_PREP(DS1337_RS_MASK, 0x03) + +/* DS1337 features two independent alarms */ +#define DS1337_ALARM_1_ID 0 +#define DS1337_ALARM_2_ID 1 +#define DS1337_ALARMS_COUNT 2 + +/* SQW frequency property enum values */ +#define DS1337_SQW_PROP_ENUM_1HZ 0 +#define DS1337_SQW_PROP_ENUM_4096HZ 1 +#define DS1337_SQW_PROP_ENUM_8192HZ 2 +#define DS1337_SQW_PROP_ENUM_32768HZ 3 + +/* DS1337 counts weekdays from 1 to 7 */ +#define DS1337_DAY_OFFSET -1 + +/* DS1337 counts months 1 to 12 */ +#define DS1337_MONTH_OFFSET -1 + +/* Year 2000 value represented as tm_year value */ +#define DS1337_TM_YEAR_2000 (2000 - 1900) + +/* RTC time fields supported by DS1337 */ +#define DS1337_RTC_TIME_MASK \ + (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | \ + RTC_ALARM_TIME_MASK_MONTH | RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_YEAR | \ + RTC_ALARM_TIME_MASK_WEEKDAY) + +/* RTC alarm 1 fields supported by DS1337 */ +#define DS1337_RTC_ALARM_TIME_1_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_WEEKDAY) + +/* RTC alarm 2 fields supported by DS1337 */ +#define DS1337_RTC_ALARM_TIME_2_MASK \ + (RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_MONTHDAY | \ + RTC_ALARM_TIME_MASK_WEEKDAY) + +/* Helper macro to guard GPIO interrupt related stuff */ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) && defined(CONFIG_RTC_ALARM) +#define DS1337_INT_GPIOS_IN_USE 1 +#endif + +struct ds1337_config { + const struct i2c_dt_spec i2c; +#ifdef DS1337_INT_GPIOS_IN_USE + struct gpio_dt_spec gpio_int; +#endif + uint8_t sqw_freq; +}; + +struct ds1337_data { + struct k_sem lock; +#ifdef DS1337_INT_GPIOS_IN_USE + const struct device *dev; + struct gpio_callback irq_callback; + struct k_work work; +#ifdef CONFIG_RTC_ALARM + rtc_alarm_callback alarm_callbacks[DS1337_ALARMS_COUNT]; + void *alarm_user_data[DS1337_ALARMS_COUNT]; +#endif +#endif +}; + +static void ds1337_lock_sem(const struct device *dev) +{ + struct ds1337_data *data = dev->data; + + (void)k_sem_take(&data->lock, K_FOREVER); +} + +static void ds1337_unlock_sem(const struct device *dev) +{ + struct ds1337_data *data = dev->data; + + k_sem_give(&data->lock); +} + +static bool ds1337_validate_alarm_mask(uint16_t alarm_mask, uint16_t alarm_id) +{ + const uint16_t allowed_configs[6] = { + 0, + RTC_ALARM_TIME_MASK_SECOND, + RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE, + RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR, + RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | + RTC_ALARM_TIME_MASK_WEEKDAY, + RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | + RTC_ALARM_TIME_MASK_MONTHDAY + }; + + const uint16_t available_fields = + (alarm_id == 0) ? DS1337_RTC_ALARM_TIME_1_MASK : DS1337_RTC_ALARM_TIME_2_MASK; + if (alarm_mask & ~available_fields) { + return false; + } + + ARRAY_FOR_EACH_PTR(allowed_configs, config) { + if (alarm_mask == (*config & available_fields)) { + return true; + } + } + return false; +} + +#ifdef DS1337_INT_GPIOS_IN_USE + +static void ds1337_work_callback(struct k_work *work) +{ + struct ds1337_data *data = CONTAINER_OF(work, struct ds1337_data, work); + const struct device *dev = data->dev; + const struct ds1337_config *config = dev->config; + rtc_alarm_callback alarm_callbacks[DS1337_ALARMS_COUNT] = {NULL}; + void *alarm_user_data[DS1337_ALARMS_COUNT] = {NULL}; + uint8_t status_reg; + int err; + + ds1337_lock_sem(dev); + + /* Read status register */ + err = i2c_reg_read_byte_dt(&config->i2c, DS1337_STATUS_REG, &status_reg); + if (err) { + goto out_unlock; + } + +#ifdef CONFIG_RTC_ALARM + /* Handle alarm 1 event */ + if ((status_reg & DS1337_A1F_MASK) && (data->alarm_callbacks[DS1337_ALARM_1_ID] != NULL)) { + status_reg &= ~DS1337_A1F_MASK; + alarm_callbacks[DS1337_ALARM_1_ID] = data->alarm_callbacks[DS1337_ALARM_1_ID]; + alarm_user_data[DS1337_ALARM_1_ID] = data->alarm_user_data[DS1337_ALARM_1_ID]; + } + + /* Handle alarm 2 event */ + if ((status_reg & DS1337_A2F_MASK) && (data->alarm_callbacks[DS1337_ALARM_2_ID] != NULL)) { + status_reg &= ~DS1337_A2F_MASK; + alarm_callbacks[DS1337_ALARM_2_ID] = data->alarm_callbacks[DS1337_ALARM_2_ID]; + alarm_user_data[DS1337_ALARM_2_ID] = data->alarm_user_data[DS1337_ALARM_2_ID]; + } +#endif + + /* Clear alarm flag(s) */ + err = i2c_reg_write_byte_dt(&config->i2c, DS1337_STATUS_REG, status_reg); + if (err) { + goto out_unlock; + } + + /* Check if any interrupt occurred between flags register read/write */ + err = i2c_reg_read_byte_dt(&config->i2c, DS1337_STATUS_REG, &status_reg); + if (err) { + goto out_unlock; + } + + if (((status_reg & DS1337_A1F_MASK) && (alarm_callbacks[0] != NULL)) || + ((status_reg & DS1337_A2F_MASK) && (alarm_callbacks[1] != NULL))) { + /* Another interrupt occurred while servicing this one */ + (void)k_work_submit(&data->work); + } + +out_unlock: + ds1337_unlock_sem(dev); + + /* Execute alarm callback(s) */ + for (uint8_t alarm_id = DS1337_ALARM_1_ID; alarm_id < DS1337_ALARMS_COUNT; ++alarm_id) { + if (alarm_callbacks[alarm_id] != NULL) { + alarm_callbacks[alarm_id](dev, alarm_id, alarm_user_data[alarm_id]); + alarm_callbacks[alarm_id] = NULL; + } + } +} + +static void ds1337_irq_handler(const struct device *port, struct gpio_callback *callback, + gpio_port_pins_t pins) +{ + ARG_UNUSED(port); + ARG_UNUSED(pins); + + struct ds1337_data *data = CONTAINER_OF(callback, struct ds1337_data, irq_callback); + + (void)k_work_submit(&data->work); +} + +#endif + +static int ds1337_set_time(const struct device *dev, const struct rtc_time *timeptr) +{ + const struct ds1337_config *config = dev->config; + uint8_t regs[7]; + int err; + + if ((timeptr == NULL) || !rtc_utils_validate_rtc_time(timeptr, DS1337_RTC_TIME_MASK)) { + return -EINVAL; + } + + ds1337_lock_sem(dev); + + regs[0] = bin2bcd(timeptr->tm_sec) & DS1337_SECONDS_MASK; + regs[1] = bin2bcd(timeptr->tm_min) & DS1337_MINUTES_MASK; + regs[2] = bin2bcd(timeptr->tm_hour) & DS1337_HOURS_MASK; + regs[3] = bin2bcd(timeptr->tm_wday - DS1337_DAY_OFFSET) & DS1337_DAY_MASK; + regs[4] = bin2bcd(timeptr->tm_mday) & DS1337_DATE_MASK; + regs[5] = bin2bcd(timeptr->tm_mon - DS1337_MONTH_OFFSET) & DS1337_MONTH_MASK; + + /* Determine which century we're in */ + if (timeptr->tm_year >= DS1337_TM_YEAR_2000) { + regs[5] |= DS1337_CENTURY_MASK; + regs[6] = bin2bcd(timeptr->tm_year - DS1337_TM_YEAR_2000) & DS1337_YEAR_MASK; + } else { + regs[6] = bin2bcd(timeptr->tm_year) & DS1337_YEAR_MASK; + } + + /* Set new time */ + err = i2c_burst_write_dt(&config->i2c, DS1337_SECONDS_REG, regs, sizeof(regs)); + if (err) { + goto out_unlock; + } + + /* Clear Oscillator Stop Flag, indicating data validity */ + err = i2c_reg_update_byte_dt(&config->i2c, DS1337_STATUS_REG, DS1337_OSF_MASK, 0); + +out_unlock: + ds1337_unlock_sem(dev); + + if (!err) { + LOG_DBG("Set time: year: %d, month: %d, month day: %d, week day: %d, hour: %d, " + "minute: %d, second: %d", + timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); + } + + return err; +} + +static int ds1337_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + const struct ds1337_config *config = dev->config; + uint8_t regs[7]; + uint8_t status_reg; + int err; + + if (timeptr == NULL) { + return -EINVAL; + } + + ds1337_lock_sem(dev); + + /* Check data validity */ + err = i2c_reg_read_byte_dt(&config->i2c, DS1337_STATUS_REG, &status_reg); + if (err) { + goto out_unlock; + } + if (status_reg & DS1337_OSF_MASK) { + err = -ENODATA; + goto out_unlock; + } + + /* Read time data */ + err = i2c_burst_read_dt(&config->i2c, DS1337_SECONDS_REG, regs, sizeof(regs)); + if (err) { + goto out_unlock; + } + + timeptr->tm_sec = bcd2bin(regs[0] & DS1337_SECONDS_MASK); + timeptr->tm_min = bcd2bin(regs[1] & DS1337_MINUTES_MASK); + timeptr->tm_hour = bcd2bin(regs[2] & DS1337_HOURS_MASK); + timeptr->tm_wday = bcd2bin(regs[3] & DS1337_DAY_MASK) + DS1337_DAY_OFFSET; + timeptr->tm_mday = bcd2bin(regs[4] & DS1337_DATE_MASK); + timeptr->tm_mon = bcd2bin(regs[5] & DS1337_MONTH_MASK) + DS1337_MONTH_OFFSET; + timeptr->tm_year = bcd2bin(regs[6] & DS1337_YEAR_MASK); + timeptr->tm_yday = -1; /* Unsupported */ + timeptr->tm_isdst = -1; /* Unsupported */ + timeptr->tm_nsec = 0; /* Unsupported */ + + /* Apply century offset */ + if (regs[5] & DS1337_CENTURY_MASK) { + timeptr->tm_year += DS1337_TM_YEAR_2000; + } + +out_unlock: + ds1337_unlock_sem(dev); + + if (!err) { + LOG_DBG("Read time: year: %d, month: %d, month day: %d, week day: %d, hour: %d, " + "minute: %d, second: %d", + timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); + } + + return err; +} + +#ifdef CONFIG_RTC_ALARM + +static int ds1337_alarm_get_supported_fields(const struct device *dev, uint16_t id, uint16_t *mask) +{ + ARG_UNUSED(dev); + + if (id == DS1337_ALARM_1_ID) { + *mask = DS1337_RTC_ALARM_TIME_1_MASK; + return 0; + } else if (id == DS1337_ALARM_2_ID) { + *mask = DS1337_RTC_ALARM_TIME_2_MASK; + return 0; + } + + LOG_ERR("Invalid alarm ID: %d", id); + return -EINVAL; +} + +static int ds1337_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, + const struct rtc_time *timeptr) +{ + const struct ds1337_config *config = dev->config; + uint8_t regs[4]; + uint8_t reg_addr; + uint8_t reg_offset; + int err; + + if (id >= DS1337_ALARMS_COUNT) { + LOG_ERR("Invalid alarm ID: %d", id); + return -EINVAL; + } + + if ((mask & RTC_ALARM_TIME_MASK_MONTHDAY) && (mask & RTC_ALARM_TIME_MASK_WEEKDAY)) { + LOG_ERR("Month day and week day alarms cannot be set simultaneously"); + return -EINVAL; + } + + if (!ds1337_validate_alarm_mask(mask, id)) { + LOG_ERR("Unsupported mask 0x%04X for alarm %d", mask, id); + return -EINVAL; + } + + if (!rtc_utils_validate_rtc_time(timeptr, mask)) { + LOG_ERR("Invalid alarm time"); + return -EINVAL; + } + + if (mask & RTC_ALARM_TIME_MASK_SECOND) { + regs[0] = bin2bcd(timeptr->tm_sec) & DS1337_ALARM_SECONDS_MASK; + } else { + regs[0] = DS1337_ALARM_DISABLE_MASK; + } + + if (mask & RTC_ALARM_TIME_MASK_MINUTE) { + regs[1] = bin2bcd(timeptr->tm_min) & DS1337_ALARM_MINUTES_MASK; + } else { + regs[1] = DS1337_ALARM_DISABLE_MASK; + } + + if (mask & RTC_ALARM_TIME_MASK_HOUR) { + regs[2] = bin2bcd(timeptr->tm_hour) & DS1337_ALARM_HOURS_MASK; + } else { + regs[2] = DS1337_ALARM_DISABLE_MASK; + } + + if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + regs[3] = bin2bcd(timeptr->tm_mday) & DS1337_ALARM_DATE_MASK; + } else if (mask & RTC_ALARM_TIME_MASK_WEEKDAY) { + regs[3] = bin2bcd(timeptr->tm_wday - DS1337_DAY_OFFSET) & DS1337_ALARM_DAY_MASK; + regs[3] |= DS1337_DY_DT_MASK; + } else { + regs[3] = DS1337_ALARM_DISABLE_MASK; + } + + /* Update alarm registers */ + if (id == DS1337_ALARM_1_ID) { + reg_addr = DS1337_ALARM_1_SECONDS_REG; + reg_offset = 0; + } else { + reg_addr = DS1337_ALARM_2_MINUTES_REG; + reg_offset = 1; + } + + err = i2c_burst_write_dt(&config->i2c, reg_addr, ®s[reg_offset], + sizeof(regs) - reg_offset); + if (err) { + return err; + } + + LOG_DBG("Set alarm: month day: %d, week day: %d, hour: %d, minute: %d, second: %d mask: " + "0x%04X", + timeptr->tm_mday, timeptr->tm_wday, timeptr->tm_hour, timeptr->tm_min, + timeptr->tm_sec, mask); + + return 0; +} + +static int ds1337_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, + struct rtc_time *timeptr) +{ + const struct ds1337_config *config = dev->config; + uint8_t regs[4]; + uint8_t reg_addr; + uint8_t reg_offset; + int err; + + if (id >= DS1337_ALARMS_COUNT) { + LOG_ERR("Invalid alarm ID: %d", id); + return -EINVAL; + } + + /* Read alarm registers */ + if (id == DS1337_ALARM_1_ID) { + reg_addr = DS1337_ALARM_1_SECONDS_REG; + reg_offset = 0; + } else { + reg_addr = DS1337_ALARM_2_MINUTES_REG; + reg_offset = 1; + } + err = i2c_burst_read_dt(&config->i2c, reg_addr, ®s[reg_offset], + sizeof(regs) - reg_offset); + if (err) { + return err; + } + + (void)memset(timeptr, 0, sizeof(*timeptr)); + *mask = 0; + + if ((regs[0] & DS1337_ALARM_DISABLE_MASK) == 0) { + timeptr->tm_sec = bcd2bin(regs[0] & DS1337_ALARM_SECONDS_MASK); + *mask |= RTC_ALARM_TIME_MASK_SECOND; + } + + if ((regs[1] & DS1337_ALARM_DISABLE_MASK) == 0) { + timeptr->tm_min = bcd2bin(regs[1] & DS1337_ALARM_MINUTES_MASK); + *mask |= RTC_ALARM_TIME_MASK_MINUTE; + } + + if ((regs[2] & DS1337_ALARM_DISABLE_MASK) == 0) { + timeptr->tm_hour = bcd2bin(regs[2] & DS1337_ALARM_HOURS_MASK); + *mask |= RTC_ALARM_TIME_MASK_HOUR; + } + + if ((regs[3] & DS1337_ALARM_DISABLE_MASK) == 0) { + if ((regs[3] & DS1337_DY_DT_MASK) == 0) { + timeptr->tm_mday = bcd2bin(regs[3] & DS1337_ALARM_DATE_MASK); + *mask |= RTC_ALARM_TIME_MASK_MONTHDAY; + } else { + timeptr->tm_wday = + bcd2bin(regs[3] & DS1337_ALARM_DAY_MASK) + DS1337_DAY_OFFSET; + *mask |= RTC_ALARM_TIME_MASK_WEEKDAY; + } + } + + LOG_DBG("Get alarm: month day: %d, week day: %d, hour: %d, minute: %d, second: %d mask: " + "0x%04X", + timeptr->tm_mday, timeptr->tm_wday, timeptr->tm_hour, timeptr->tm_min, + timeptr->tm_sec, *mask); + + return 0; +} + +static int ds1337_alarm_is_pending(const struct device *dev, uint16_t id) +{ + const struct ds1337_config *config = dev->config; + uint8_t pending = 0; + uint8_t status_reg; + int err; + + if (id >= DS1337_ALARMS_COUNT) { + LOG_ERR("Invalid alarm ID: %d", id); + return -EINVAL; + } + + ds1337_lock_sem(dev); + + err = i2c_reg_read_byte_dt(&config->i2c, DS1337_STATUS_REG, &status_reg); + if (err) { + goto out_unlock; + } + + if (id == DS1337_ALARM_1_ID) { + if (status_reg & DS1337_A1F_MASK) { + status_reg &= ~DS1337_A1F_MASK; + pending = 1; + } + } else { + if (status_reg & DS1337_A2F_MASK) { + status_reg &= ~DS1337_A2F_MASK; + pending = 1; + } + } + + err = i2c_reg_write_byte_dt(&config->i2c, DS1337_STATUS_REG, status_reg); + if (err) { + goto out_unlock; + } + +out_unlock: + ds1337_unlock_sem(dev); + + if (err) { + return err; + } + return pending; +} + +#ifdef DS1337_INT_GPIOS_IN_USE + +static int ds1337_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) +{ + const struct ds1337_config *config = dev->config; + struct ds1337_data *data = dev->data; + uint8_t reg_val = 0; + uint8_t mask = 0; + int err; + + if (config->gpio_int.port == NULL) { + return -ENOTSUP; + } + + if (id >= DS1337_ALARMS_COUNT) { + LOG_ERR("Invalid alarm ID: %d", id); + return -EINVAL; + } + + ds1337_lock_sem(dev); + + data->alarm_callbacks[id] = callback; + data->alarm_user_data[id] = user_data; + + /* Enable alarm interrupt if callback provided */ + if (id == DS1337_ALARM_1_ID) { + mask = DS1337_A1IE_MASK; + reg_val = (callback != NULL) ? DS1337_A1IE_MASK : 0; + } else { + mask = DS1337_A2IE_MASK; + reg_val = (callback != NULL) ? DS1337_A2IE_MASK : 0; + } + err = i2c_reg_update_byte_dt(&config->i2c, DS1337_CONTROL_REG, mask, reg_val); + + ds1337_unlock_sem(dev); + + /* Alarm IRQ might have already been triggered */ + (void)k_work_submit(&data->work); + + return err; +} + +#endif + +#endif + +static int ds1337_init(const struct device *dev) +{ + const struct ds1337_config *config = dev->config; + struct ds1337_data *data = dev->data; + uint8_t reg_val; + int err; + + (void)k_sem_init(&data->lock, 1, 1); + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C bus not ready"); + return -ENODEV; + } + +#ifdef DS1337_INT_GPIOS_IN_USE + if (config->gpio_int.port != NULL) { + if (!gpio_is_ready_dt(&config->gpio_int)) { + LOG_ERR("GPIO not ready"); + return -ENODEV; + } + + err = gpio_pin_configure_dt(&config->gpio_int, GPIO_INPUT); + if (err) { + LOG_ERR("Failed to configure interrupt GPIO, error: %d", err); + return err; + } + + err = gpio_pin_interrupt_configure_dt(&config->gpio_int, GPIO_INT_EDGE_TO_ACTIVE); + if (err) { + LOG_ERR("Failed to enable GPIO interrupt, error: %d", err); + return err; + } + + gpio_init_callback(&data->irq_callback, ds1337_irq_handler, + BIT(config->gpio_int.pin)); + + err = gpio_add_callback_dt(&config->gpio_int, &data->irq_callback); + if (err) { + LOG_ERR("Failed to add GPIO callback, error: %d", err); + return err; + } + + data->dev = dev; + data->work.handler = ds1337_work_callback; + } +#endif + + /* Display warning if alarm flags are set */ + err = i2c_reg_read_byte_dt(&config->i2c, DS1337_STATUS_REG, ®_val); + if (err) { + return err; + } + if (reg_val & DS1337_A1F_MASK) { + LOG_WRN("Alarm 1 might have been missed!"); + } + if (reg_val & DS1337_A2F_MASK) { + LOG_WRN("Alarm 2 might have been missed!"); + } + + /* Enable oscillator */ + err = i2c_reg_update_byte_dt(&config->i2c, DS1337_CONTROL_REG, DS1337_EOSC_MASK, 0); + if (err) { + return err; + } + + /* Configure SQW output frequency */ + switch (config->sqw_freq) { + case DS1337_SQW_PROP_ENUM_1HZ: + reg_val = DS1337_SQW_FREQ_1Hz; + break; + case DS1337_SQW_PROP_ENUM_4096HZ: + reg_val = DS1337_SQW_FREQ_4096Hz; + break; + case DS1337_SQW_PROP_ENUM_8192HZ: + reg_val = DS1337_SQW_FREQ_8192Hz; + break; + case DS1337_SQW_PROP_ENUM_32768HZ: + default: + reg_val = DS1337_SQW_FREQ_32768Hz; + break; + } + + /* + * Set SQW frequency, enable oscillator, clear INTCN (both alarms will trigger INTA), + * disable IRQs + */ + err = i2c_reg_write_byte_dt(&config->i2c, DS1337_CONTROL_REG, reg_val); + if (err) { + return err; + } + + /* Clear alarm flags */ + err = i2c_reg_update_byte_dt(&config->i2c, DS1337_STATUS_REG, + DS1337_A1F_MASK | DS1337_A2F_MASK, 0); + if (err) { + return err; + } + + return 0; +} + +static DEVICE_API(rtc, ds1337_driver_api) = { + .get_time = ds1337_get_time, + .set_time = ds1337_set_time, +#ifdef CONFIG_RTC_ALARM + .alarm_get_supported_fields = ds1337_alarm_get_supported_fields, + .alarm_set_time = ds1337_alarm_set_time, + .alarm_get_time = ds1337_alarm_get_time, + .alarm_is_pending = ds1337_alarm_is_pending, +#ifdef DS1337_INT_GPIOS_IN_USE + .alarm_set_callback = ds1337_alarm_set_callback, +#endif +#endif +}; + +#define DS1337_INIT(inst) \ + static struct ds1337_data ds1337_data_##inst; \ + static const struct ds1337_config ds1337_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .sqw_freq = DT_INST_ENUM_IDX_OR(inst, sqw_frequency, DS1337_SQW_PROP_ENUM_1HZ), \ + IF_ENABLED( \ + DS1337_INT_GPIOS_IN_USE, \ + (.gpio_int = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0})) \ + ) \ + }; \ + DEVICE_DT_INST_DEFINE(inst, &ds1337_init, NULL, &ds1337_data_##inst, \ + &ds1337_config_##inst, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, \ + &ds1337_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DS1337_INIT) diff --git a/dts/bindings/rtc/maxim,ds1337.yaml b/dts/bindings/rtc/maxim,ds1337.yaml new file mode 100644 index 0000000000000..ac874fed276b7 --- /dev/null +++ b/dts/bindings/rtc/maxim,ds1337.yaml @@ -0,0 +1,30 @@ +# Copyright (c) 2025 Marcin Lyda +# SPDX-License-Identifier: Apache-2.0 + +description: Maxim DS1337 RTC + +compatible: "maxim,ds1337" + +include: + - name: rtc-device.yaml + - name: i2c-device.yaml + +properties: + int-gpios: + type: phandle-array + description: | + INTA interrupt output + GPIO pin to handle chip's INTA interrupt output, + used to notify about alarm events. + + sqw-frequency: + type: int + description: | + SQW/INTB frequency value [Hz] + This field enables to select output frequency at + SQW/INTB pin. + enum: + - 1 + - 4096 + - 8192 + - 32768 diff --git a/tests/drivers/build_all/rtc/i2c_devices.overlay b/tests/drivers/build_all/rtc/i2c_devices.overlay index c20e60ab43a64..1c2758f9f8f6c 100644 --- a/tests/drivers/build_all/rtc/i2c_devices.overlay +++ b/tests/drivers/build_all/rtc/i2c_devices.overlay @@ -90,6 +90,14 @@ reg = <0x8>; irq-gpios = <&test_gpio 0 0>; }; + + test_ds1337: ds1337@9 { + compatible = "maxim,ds1337"; + status = "okay"; + reg = <0x9>; + int-gpios = <&test_gpio 0 0>; + sqw-frequency = <4096>; + }; }; }; }; From 6584862897ffa8e9b2799d035892a45333efe1ce Mon Sep 17 00:00:00 2001 From: Shan Pen Date: Thu, 13 Feb 2025 08:49:28 +0800 Subject: [PATCH 0118/6055] doc: fixes minor typo in ../sensor/triggers.rst not sure "micro controller" is a typo. Happy to update it if needed, or feel free to close this. Thanks for your work! Signed-off-by: Shan Pen --- doc/hardware/peripherals/sensor/triggers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/hardware/peripherals/sensor/triggers.rst b/doc/hardware/peripherals/sensor/triggers.rst index 6dd7870103225..c4a5c9536a2cc 100644 --- a/doc/hardware/peripherals/sensor/triggers.rst +++ b/doc/hardware/peripherals/sensor/triggers.rst @@ -5,7 +5,7 @@ Sensor Triggers :dfn:`Triggers`, enumerated in :c:enum:`sensor_trigger_type`, are sensor generated events. Typically sensors allow setting up these events to cause -digital line signaling for easy capture by a micro controller. The events can +digital line signaling for easy capture by a microcontroller. The events can then commonly be inspected by reading registers to determine which event caused the digital line signaling to occur. From 8d253b78a1bf7ed0933c216c2c80c9792789e8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Feb 2025 19:35:27 +0100 Subject: [PATCH 0119/6055] tests: show thread_metric Kconfig menu first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put the thread_metric Kconfig menu first in the Kconfig "homepage", like other samples and tests typically do as this makes it easier to quickly get to the relevant options in menuconfig. Signed-off-by: Benjamin Cabé --- tests/benchmarks/thread_metric/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/benchmarks/thread_metric/Kconfig b/tests/benchmarks/thread_metric/Kconfig index 37ecca6cd0e5e..72ebc3042dfbf 100644 --- a/tests/benchmarks/thread_metric/Kconfig +++ b/tests/benchmarks/thread_metric/Kconfig @@ -3,8 +3,6 @@ mainmenu "Eclipse ThreadX Thread-Metric RTOS Test Suite" -source "Kconfig.zephyr" - choice TM_TEST prompt "Select a Thread-Metric test to execute" default TM_PREEMPTIVE @@ -81,3 +79,5 @@ config TM_SYNCHRONIZATION is reported every 30 seconds. endchoice + +source "Kconfig.zephyr" From b897d2a1e395e32c5008fe8c4e007c5fbe5f8bdc Mon Sep 17 00:00:00 2001 From: Andrei Menzopol Date: Fri, 7 Feb 2025 11:54:51 +0200 Subject: [PATCH 0120/6055] drivers: entropy: add nxp ele trng Add NXP ELE TRNG driver Signed-off-by: Andrei Menzopol --- drivers/entropy/CMakeLists.txt | 1 + drivers/entropy/Kconfig | 1 + drivers/entropy/Kconfig.nxp | 12 ++++++ drivers/entropy/entropy_nxp_ele.c | 71 +++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 drivers/entropy/Kconfig.nxp create mode 100644 drivers/entropy/entropy_nxp_ele.c diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index 6decc76781b17..6f27e39c4c6ab 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_RNG entropy_mcux_rng. zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_RNGA entropy_mcux_rnga.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_TRNG entropy_mcux_trng.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_CAAM entropy_mcux_caam.c) +zephyr_library_sources_ifdef(CONFIG_ENTROPY_NXP_ELE_TRNG entropy_nxp_ele.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_NRF5_RNG entropy_nrf5.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_NRF_CRACEN_CTR_DRBG entropy_nrf_cracen.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_SAM_RNG entropy_sam.c) diff --git a/drivers/entropy/Kconfig b/drivers/entropy/Kconfig index e170d3381a1bc..62242ecaccf2b 100644 --- a/drivers/entropy/Kconfig +++ b/drivers/entropy/Kconfig @@ -23,6 +23,7 @@ config ENTROPY_INIT_PRIORITY source "drivers/entropy/Kconfig.b91" source "drivers/entropy/Kconfig.cc13xx_cc26xx" source "drivers/entropy/Kconfig.mcux" +source "drivers/entropy/Kconfig.nxp" source "drivers/entropy/Kconfig.stm32" source "drivers/entropy/Kconfig.esp32" source "drivers/entropy/Kconfig.nrf5" diff --git a/drivers/entropy/Kconfig.nxp b/drivers/entropy/Kconfig.nxp new file mode 100644 index 0000000000000..895ff59dd76f8 --- /dev/null +++ b/drivers/entropy/Kconfig.nxp @@ -0,0 +1,12 @@ +# NXP ELE entropy configuration options + +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config ENTROPY_NXP_ELE_TRNG + bool "NXP ELE TRNG driver" + default y + depends on DT_HAS_NXP_ELE_TRNG_ENABLED + select ENTROPY_HAS_DRIVER + help + This option enables the ELE true random number generator (TRNG) diff --git a/drivers/entropy/entropy_nxp_ele.c b/drivers/entropy/entropy_nxp_ele.c new file mode 100644 index 0000000000000..8d8e037de7f04 --- /dev/null +++ b/drivers/entropy/entropy_nxp_ele.c @@ -0,0 +1,71 @@ +/* entropy_nxp_ele.c - NXP ELE entropy driver */ + +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_ele_trng + +#include +#include +#include +#include +#include +#include + +#include "sss_crypto.h" + +struct entropy_ele_data_str { + struct k_sem sem_lock; +}; + +static struct entropy_ele_data_str entropy_ele_data; + +static int entropy_ele_get_entropy(const struct device *dev, uint8_t *buf, uint16_t len) +{ + sss_sscp_rng_t ctx; + int result = -EIO; + + __ASSERT_NO_MSG(buf != NULL); + __ASSERT_NO_MSG(&entropy_ele_data == dev->data); + + k_sem_take(&entropy_ele_data.sem_lock, K_FOREVER); + + if (CRYPTO_InitHardware() != kStatus_Success) { + goto exit; + } + + if (sss_sscp_rng_context_init(&g_sssSession, &ctx, 0u) != kStatus_SSS_Success) { + goto exit; + } + + if (sss_sscp_rng_get_random(&ctx, buf, len) != kStatus_SSS_Success) { + goto exit; + } + + if (sss_sscp_rng_free(&ctx) != kStatus_SSS_Success) { + goto exit; + } + + result = 0; + +exit: + k_sem_give(&entropy_ele_data.sem_lock); + return result; +} + +static int entropy_ele_init(const struct device *dev) +{ + __ASSERT_NO_MSG(&entropy_ele_data == dev->data); + + k_sem_init(&entropy_ele_data.sem_lock, 1, 1); + + return 0; +} + +static DEVICE_API(entropy, entropy_ele_api_funcs) = {.get_entropy = entropy_ele_get_entropy}; + +DEVICE_DT_INST_DEFINE(0, entropy_ele_init, NULL, &entropy_ele_data, NULL, PRE_KERNEL_1, + CONFIG_ENTROPY_INIT_PRIORITY, &entropy_ele_api_funcs); From f7167ed606d719e51b74dcf181b2f56b60050848 Mon Sep 17 00:00:00 2001 From: Andrei Menzopol Date: Fri, 7 Feb 2025 11:58:03 +0200 Subject: [PATCH 0121/6055] drivers: ieee802154: add mcxw ieee802154 driver Add mcxw ieee802154 driver Fix compliance errors for added files. Update function names to snake_case style. Signed-off-by: Andrei Menzopol --- drivers/ieee802154/CMakeLists.txt | 1 + drivers/ieee802154/Kconfig | 2 + drivers/ieee802154/Kconfig.mcxw | 28 + drivers/ieee802154/ieee802154_mcxw.c | 1360 ++++++++++++++++++++ drivers/ieee802154/ieee802154_mcxw.h | 125 ++ drivers/ieee802154/ieee802154_mcxw_utils.c | 356 +++++ drivers/ieee802154/ieee802154_mcxw_utils.h | 16 + 7 files changed, 1888 insertions(+) create mode 100644 drivers/ieee802154/Kconfig.mcxw create mode 100644 drivers/ieee802154/ieee802154_mcxw.c create mode 100644 drivers/ieee802154/ieee802154_mcxw.h create mode 100644 drivers/ieee802154/ieee802154_mcxw_utils.c create mode 100644 drivers/ieee802154/ieee802154_mcxw_utils.h diff --git a/drivers/ieee802154/CMakeLists.txt b/drivers/ieee802154/CMakeLists.txt index 3fdb65790afeb..f731bdb9f55bf 100644 --- a/drivers/ieee802154/CMakeLists.txt +++ b/drivers/ieee802154/CMakeLists.txt @@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_IEEE802154_CC2520 ieee802154_cc2520.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_DW1000 ieee802154_dw1000.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_KW41Z ieee802154_kw41z.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_MCR20A ieee802154_mcr20a.c) +zephyr_library_sources_ifdef(CONFIG_IEEE802154_MCXW ieee802154_mcxw.c ieee802154_mcxw_utils.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_NRF5 ieee802154_nrf5.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_RF2XX ieee802154_rf2xx.c) zephyr_library_sources_ifdef(CONFIG_IEEE802154_RF2XX ieee802154_rf2xx_iface.c) diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index 447b32ccbe061..a3f89c72665b9 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -76,6 +76,8 @@ source "drivers/ieee802154/Kconfig.kw41z" source "drivers/ieee802154/Kconfig.mcr20a" +source "drivers/ieee802154/Kconfig.mcxw" + source "drivers/ieee802154/Kconfig.nrf5" source "drivers/ieee802154/Kconfig.cc1200" diff --git a/drivers/ieee802154/Kconfig.mcxw b/drivers/ieee802154/Kconfig.mcxw new file mode 100644 index 0000000000000..5829a8f9736f4 --- /dev/null +++ b/drivers/ieee802154/Kconfig.mcxw @@ -0,0 +1,28 @@ +# NXP MCXW 802.15.4 configuration options + +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig IEEE802154_MCXW + bool "NXP MCXW series IEEE 802.15.4 Driver" + default y + depends on DT_HAS_NXP_MCXW_IEEE802154_ENABLED + depends on COUNTER + +if IEEE802154_MCXW + +config IEEE802154_MCXW_INIT_PRIO + int "Initial priority for the IEEE802154 driver" + default 80 + +config IEEE802154_MCXW_RX_STACK_SIZE + int "Driver's internal RX thread stack size" + default 800 + + +config IEEE802154_MCXW_CSL_ACCURACY + int "Csl accuracy for delayed operations" + default 100 + + +endif diff --git a/drivers/ieee802154/ieee802154_mcxw.c b/drivers/ieee802154/ieee802154_mcxw.c new file mode 100644 index 0000000000000..247342e66a132 --- /dev/null +++ b/drivers/ieee802154/ieee802154_mcxw.c @@ -0,0 +1,1360 @@ +/* ieee802154_mcxw.c - NXP MCXW 802.15.4 driver */ + +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_mcxw_ieee802154 + +#define LOG_MODULE_NAME ieee802154_mcxw + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_NET_L2_OPENTHREAD) +#include +#include +#endif + +#include +#include + +#include + +#include +#include +#include + +#include "EmbeddedTypes.h" +#include "Phy.h" + +#include "fwk_platform_ot.h" + +#include "ieee802154_mcxw.h" +#include "ieee802154_mcxw_utils.h" + +void PLATFORM_RemoteActiveReq(void); +void PLATFORM_RemoteActiveRel(void); + +#if CONFIG_IEEE802154_CSL_ENDPOINT + +#define CMP_OVHD (4 * IEEE802154_SYMBOL_TIME_US) /* 2 LPTRM (32 kHz) ticks */ + +static bool_t csl_rx = FALSE; + +static void set_csl_sample_time(void); +static void start_csl_receiver(void); +static void stop_csl_receiver(void); +static uint16_t rf_compute_csl_phase(uint32_t aTimeUs); + +#else /* CONFIG_IEEE802154_CSL_ENDPOINT */ +#define start_csl_receiver() +#define stop_csl_receiver() +#endif /* CONFIG_IEEE802154_CSL_ENDPOINT */ + +static volatile uint32_t sun_rx_mode = RX_ON_IDLE_START; + +/* Private functions */ +static void rf_abort(void); +static void rf_set_channel(uint8_t channel); +static void rf_set_tx_power(int8_t tx_power); +static uint64_t rf_adjust_tstamp_from_phy(uint64_t ts); + +#if CONFIG_IEEE802154_CSL_ENDPOINT || CONFIG_NET_PKT_TXTIME +static uint32_t rf_adjust_tstamp_from_app(uint32_t time); +#endif /* CONFIG_IEEE802154_CSL_ENDPOINT || CONFIG_NET_PKT_TXTIME */ + +static void rf_rx_on_idle(uint32_t newValue); + +static uint8_t ot_phy_ctx = (uint8_t)(-1); + +static struct mcxw_context mcxw_ctx; + +/** + * Stub function used for controlling low power mode + */ +WEAK void app_allow_device_to_slepp(void) +{ +} + +/** + * Stub function used for controlling low power mode + */ +WEAK void app_disallow_device_to_slepp(void) +{ +} + +void mcxw_get_eui64(uint8_t *eui64) +{ + __ASSERT_NO_MSG(eui64); + + /* PLATFORM_GetIeee802_15_4Addr(); */ + sys_rand_get(eui64, sizeof(mcxw_ctx.mac)); + + eui64[0] = (eui64[0] & ~0x01) | 0x02; +} + +static int mcxw_set_pan_id(const struct device *dev, uint16_t aPanId) +{ + struct mcxw_context *mcxw_radio = dev->data; + + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibPanId_c; + msg.msgData.setReq.PibAttributeValue = (uint64_t)aPanId; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); + + mcxw_radio->pan_id = aPanId; + + return 0; +} + +static int mcxw_set_extended_address(const struct device *dev, const uint8_t *ieee_addr) +{ + struct mcxw_context *mcxw_radio = dev->data; + + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibLongAddress_c; + msg.msgData.setReq.PibAttributeValue = *(uint64_t *)ieee_addr; + + memcpy(mcxw_radio->mac, ieee_addr, 8); + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); + + return 0; +} + +static int mcxw_set_short_address(const struct device *dev, uint16_t aShortAddress) +{ + ARG_UNUSED(dev); + + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibShortAddress_c; + msg.msgData.setReq.PibAttributeValue = (uint64_t)aShortAddress; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); + + return 0; +} + +static int mcxw_filter(const struct device *dev, bool set, enum ieee802154_filter_type type, + const struct ieee802154_filter *filter) +{ + LOG_DBG("Applying filter %u", type); + + if (!set) { + return -ENOTSUP; + } + + if (type == IEEE802154_FILTER_TYPE_IEEE_ADDR) { + return mcxw_set_extended_address(dev, filter->ieee_addr); + } else if (type == IEEE802154_FILTER_TYPE_SHORT_ADDR) { + return mcxw_set_short_address(dev, filter->short_addr); + } else if (type == IEEE802154_FILTER_TYPE_PAN_ID) { + return mcxw_set_pan_id(dev, filter->pan_id); + } + + return -ENOTSUP; +} + +void mcxw_radio_receive(void) +{ + macToPlmeMessage_t msg; + phyStatus_t phy_status; + + app_disallow_device_to_slepp(); + + __ASSERT(mcxw_ctx.state != RADIO_STATE_DISABLED, "Radio RX invalid state"); + + mcxw_ctx.state = RADIO_STATE_RECEIVE; + + rf_abort(); + rf_set_channel(mcxw_ctx.channel); + + if (sun_rx_mode) { + start_csl_receiver(); + + /* restart Rx on idle only if it was enabled */ + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibRxOnWhenIdle; + msg.msgData.setReq.PibAttributeValue = (uint64_t)1; + + phy_status = MAC_PLME_SapHandler(&msg, ot_phy_ctx); + __ASSERT_NO_MSG(phy_status == gPhySuccess_c); + } +} + +static uint8_t mcxw_get_acc(const struct device *dev) +{ + ARG_UNUSED(dev); + + return CONFIG_IEEE802154_MCXW_CSL_ACCURACY; +} + +static int mcxw_start(const struct device *dev) +{ + struct mcxw_context *mcxw_radio = dev->data; + + __ASSERT(mcxw_radio->state == RADIO_STATE_DISABLED, "%s", __func__); + + mcxw_radio->state = RADIO_STATE_SLEEP; + + rf_rx_on_idle(RX_ON_IDLE_START); + + mcxw_radio_receive(); + + return 0; +} + +static int mcxw_stop(const struct device *dev) +{ + struct mcxw_context *mcxw_radio = dev->data; + + __ASSERT(mcxw_radio->state != RADIO_STATE_DISABLED, "%s", __func__); + + stop_csl_receiver(); + + mcxw_radio->state = RADIO_STATE_DISABLED; + + return 0; +} + +void mcxw_radio_sleep(void) +{ + __ASSERT_NO_MSG(((mcxw_ctx.state != RADIO_STATE_TRANSMIT) && + (mcxw_ctx.state != RADIO_STATE_DISABLED))); + + rf_abort(); + + stop_csl_receiver(); + + app_allow_device_to_slepp(); + + mcxw_ctx.state = RADIO_STATE_SLEEP; +} + +static void mcxw_enable_src_match(bool enable) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetSAMState_c; + msg.msgData.SAMState = enable; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +static int mcxw_src_match_entry(bool extended, uint8_t *address) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeAddToSapTable_c; + msg.msgData.deviceAddr.panId = mcxw_ctx.pan_id; + + if (extended) { + msg.msgData.deviceAddr.mode = 3; + memcpy(msg.msgData.deviceAddr.addr, address, 8); + } else { + msg.msgData.deviceAddr.mode = 2; + memcpy(msg.msgData.deviceAddr.addr, address, 2); + } + + if (gPhySuccess_c != MAC_PLME_SapHandler(&msg, ot_phy_ctx)) { + /* the status is not returned from PHY over RPMSG */ + return -ENOMEM; + } + + return 0; +} + +static int mcxw_src_clear_entry(bool extended, uint8_t *address) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeRemoveFromSAMTable_c; + msg.msgData.deviceAddr.panId = mcxw_ctx.pan_id; + + if (extended) { + msg.msgData.deviceAddr.mode = 3; + memcpy(msg.msgData.deviceAddr.addr, address, 8); + } else { + msg.msgData.deviceAddr.mode = 2; + memcpy(msg.msgData.deviceAddr.addr, address, 2); + } + + if (gPhySuccess_c != MAC_PLME_SapHandler(&msg, ot_phy_ctx)) { + /* the status is not returned from PHY over RPMSG */ + return -ENOENT; + } + + return 0; +} + +static int handle_ack(struct mcxw_context *mcxw_radio) +{ + uint8_t len; + struct net_pkt *pkt; + int err = 0; + + len = mcxw_radio->rx_ack_frame.length; + pkt = net_pkt_rx_alloc_with_buffer(mcxw_radio->iface, len, AF_UNSPEC, 0, K_NO_WAIT); + if (!pkt) { + LOG_ERR("No free packet available."); + err = -ENOMEM; + goto exit; + } + + if (net_pkt_write(pkt, mcxw_radio->rx_ack_frame.psdu, len) < 0) { + LOG_ERR("Failed to write to a packet."); + err = -ENOMEM; + goto free_ack; + } + + /* Use some fake values for LQI and RSSI. */ + net_pkt_set_ieee802154_lqi(pkt, 80); + net_pkt_set_ieee802154_rssi_dbm(pkt, -40); + + net_pkt_set_timestamp_ns(pkt, mcxw_radio->rx_ack_frame.timestamp); + + net_pkt_cursor_init(pkt); + + if (ieee802154_handle_ack(mcxw_radio->iface, pkt) != NET_OK) { + LOG_ERR("ACK packet not handled - releasing."); + } + +free_ack: + net_pkt_unref(pkt); + +exit: + mcxw_radio->rx_ack_frame.length = 0; + return err; +} + +static int mcxw_tx(const struct device *dev, enum ieee802154_tx_mode mode, struct net_pkt *pkt, + struct net_buf *frag) +{ + struct mcxw_context *mcxw_radio = dev->data; + /* tx_data buffer has reserved memory for both macToPdDataMessage_t and actual data frame + * after + */ + macToPdDataMessage_t *msg = (macToPdDataMessage_t *)mcxw_radio->tx_data; + phyStatus_t phy_status; + + uint8_t payload_len = frag->len; + uint8_t *payload = frag->data; + + app_disallow_device_to_slepp(); + + __ASSERT(mcxw_radio->state != RADIO_STATE_DISABLED, "%s: radio disabled", __func__); + + if (payload_len > IEEE802154_MTU) { + LOG_ERR("Payload too large: %d", payload_len); + return -EMSGSIZE; + } + + mcxw_radio->tx_frame.length = payload_len + IEEE802154_FCS_LENGTH; + memcpy(mcxw_radio->tx_frame.psdu, payload, payload_len); + + mcxw_radio->tx_frame.sec_processed = net_pkt_ieee802154_frame_secured(pkt); + mcxw_radio->tx_frame.hdr_updated = net_pkt_ieee802154_mac_hdr_rdy(pkt); + + rf_set_channel(mcxw_radio->channel); + + msg->msgType = gPdDataReq_c; + msg->msgData.dataReq.slottedTx = gPhyUnslottedMode_c; + msg->msgData.dataReq.psduLength = mcxw_radio->tx_frame.length; + msg->msgData.dataReq.CCABeforeTx = gPhyNoCCABeforeTx_c; + msg->msgData.dataReq.startTime = gPhySeqStartAsap_c; + + /* tx_frame.psdu will point to tx_frame.tx_data data buffer after macToPdDataMessage_t + * structure + */ + msg->msgData.dataReq.pPsdu = mcxw_radio->tx_frame.psdu; + + if (ieee802154_is_ar_flag_set(frag)) { + msg->msgData.dataReq.ackRequired = gPhyRxAckRqd_c; + /* The 3 bytes are 1 byte frame length and 2 bytes FCS */ + msg->msgData.dataReq.txDuration = + IEEE802154_CCA_LEN_SYM + IEEE802154_PHY_SHR_LEN_SYM + + (3 + mcxw_radio->tx_frame.length) * RADIO_SYMBOLS_PER_OCTET + + IEEE802154_TURNAROUND_LEN_SYM; + + if (is_frame_version_2015(frag->data, frag->len)) { + /* Because enhanced ack can be of variable length we need to set the timeout + * value to account for the FCF and addressing fields only, and stop the + * timeout timer after they are received and validated as a valid ACK + */ + msg->msgData.dataReq.txDuration += IEEE802154_ENH_ACK_WAIT_SYM; + } else { + msg->msgData.dataReq.txDuration += IEEE802154_IMM_ACK_WAIT_SYM; + } + } else { + msg->msgData.dataReq.ackRequired = gPhyNoAckRqd_c; + msg->msgData.dataReq.txDuration = 0xFFFFFFFFU; + } + + switch (mode) { + case IEEE802154_TX_MODE_DIRECT: + msg->msgData.dataReq.CCABeforeTx = gPhyNoCCABeforeTx_c; + break; + case IEEE802154_TX_MODE_CCA: + msg->msgData.dataReq.CCABeforeTx = gPhyCCAMode1_c; + break; + +#if defined(CONFIG_NET_PKT_TXTIME) + case IEEE802154_TX_MODE_TXTIME: + case IEEE802154_TX_MODE_TXTIME_CCA: + mcxw_radio->tx_frame.tx_delay = net_pkt_timestamp_ns(pkt); + msg->msgData.dataReq.startTime = + rf_adjust_tstamp_from_app(mcxw_radio->tx_frame.tx_delay); + msg->msgData.dataReq.startTime /= IEEE802154_SYMBOL_TIME_US; + break; +#endif + default: + break; + } + + msg->msgData.dataReq.flags = 0; + +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + if (is_keyid_mode_1(mcxw_radio->tx_frame.psdu, mcxw_radio->tx_frame.length)) { + if (!net_pkt_ieee802154_frame_secured(pkt)) { + msg->msgData.dataReq.flags |= gPhyEncFrame; + + if (!net_pkt_ieee802154_mac_hdr_rdy(pkt)) { + msg->msgData.dataReq.flags |= gPhyUpdHDr; + +#if CONFIG_IEEE802154_CSL_ENDPOINT + /* Previously aFrame->mInfo.mTxInfo.mCslPresent was used to + * determine if the radio code should update the IE header. This + * field is no longer set by the OT stack. Until the issue is fixed + * in OT stack check if CSL period is > 0 and always update CSL IE + * in that case. + */ + if (mcxw_radio->csl_period) { + uint32_t hdr_time_us; + + start_csl_receiver(); + + /* Add TX_ENCRYPT_DELAY_SYM symbols delay to allow + * encryption to finish + */ + msg->msgData.dataReq.startTime = + PhyTime_ReadClock() + TX_ENCRYPT_DELAY_SYM; + + hdr_time_us = mcxw_get_time(NULL) + + (TX_ENCRYPT_DELAY_SYM + + IEEE802154_PHY_SHR_LEN_SYM) * + IEEE802154_SYMBOL_TIME_US; + set_csl_ie(mcxw_radio->tx_frame.psdu, + mcxw_radio->tx_frame.length, + mcxw_radio->csl_period, + rf_compute_csl_phase(hdr_time_us)); + } +#endif /* CONFIG_IEEE802154_CSL_ENDPOINT */ + } + } + } + +#endif + + k_sem_reset(&mcxw_radio->tx_wait); + + phy_status = MAC_PD_SapHandler(msg, ot_phy_ctx); + if (phy_status == gPhySuccess_c) { + mcxw_radio->tx_status = 0; + mcxw_radio->state = RADIO_STATE_TRANSMIT; + } else { + return -EIO; + } + + k_sem_take(&mcxw_radio->tx_wait, K_FOREVER); + + /* PWR_AllowDeviceToSleep(); */ + + mcxw_radio_receive(); + + switch (mcxw_radio->tx_status) { + case 0: + if (mcxw_radio->rx_ack_frame.length) { + return handle_ack(mcxw_radio); + } + return 0; + + default: + return -(mcxw_radio->tx_status); + } +} + +void mcxw_rx_thread(void *arg1, void *arg2, void *arg3) +{ + struct mcxw_context *mcxw_radio = (struct mcxw_context *)arg1; + struct net_pkt *pkt; + struct mcxw_rx_frame rx_frame; + + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + while (true) { + pkt = NULL; + + LOG_DBG("Waiting for frame"); + + if (k_msgq_get(&mcxw_radio->rx_msgq, &rx_frame, K_FOREVER) < 0) { + LOG_ERR("Failed to get RX data from message queue"); + continue; + } + + pkt = net_pkt_rx_alloc_with_buffer(mcxw_radio->iface, rx_frame.length, AF_UNSPEC, 0, + K_FOREVER); + + if (net_pkt_write(pkt, rx_frame.psdu, rx_frame.length)) { + goto drop; + } + + net_pkt_set_ieee802154_lqi(pkt, rx_frame.lqi); + net_pkt_set_ieee802154_rssi_dbm(pkt, rx_frame.rssi); + net_pkt_set_ieee802154_ack_fpb(pkt, rx_frame.ack_fpb); + +#if defined(CONFIG_NET_PKT_TIMESTAMP) + net_pkt_set_timestamp_ns(pkt, rx_frame.timestamp); +#endif + +#if defined(CONFIG_NET_L2_OPENTHREAD) + net_pkt_set_ieee802154_ack_seb(pkt, rx_frame.ack_seb); +#endif + if (net_recv_data(mcxw_radio->iface, pkt) < 0) { + LOG_ERR("Packet dropped by NET stack"); + goto drop; + } + + k_free(rx_frame.phy_buffer); + rx_frame.phy_buffer = NULL; + + /* restart rx on idle if enough space in message queue */ + if (k_msgq_num_free_get(&mcxw_radio->rx_msgq) >= 2) { + rf_rx_on_idle(RX_ON_IDLE_START); + } + + continue; + +drop: + /* PWR_AllowDeviceToSleep(); */ + net_pkt_unref(pkt); + } +} + +int8_t mcxw_get_rssi(void) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeGetReq_c; + msg.msgData.getReq.PibAttribute = gPhyGetRSSILevel_c; + msg.msgData.getReq.PibAttributeValue = 127; /* RSSI is invalid*/ + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); + + return (int8_t)msg.msgData.getReq.PibAttributeValue; +} + +void mcxw_set_promiscuous(bool aEnable) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibPromiscuousMode_c; + msg.msgData.setReq.PibAttributeValue = (uint64_t)aEnable; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +void mcxw_set_pan_coord(bool aEnable) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibPanCoordinator_c; + msg.msgData.setReq.PibAttributeValue = (uint64_t)aEnable; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +static int mcxw_energy_scan(const struct device *dev, uint16_t duration, + energy_scan_done_cb_t done_cb) +{ + + int status = 0; + phyStatus_t phy_status; + macToPlmeMessage_t msg; + + app_disallow_device_to_slepp(); + + struct mcxw_context *mcxw_radio = dev->data; + + __ASSERT_NO_MSG(((mcxw_radio->state != RADIO_STATE_TRANSMIT) && + (mcxw_radio->state != RADIO_STATE_DISABLED))); + + rf_abort(); + + rf_set_channel(mcxw_radio->channel); + + mcxw_radio->energy_scan_done = done_cb; + + msg.msgType = gPlmeEdReq_c; + msg.msgData.edReq.startTime = gPhySeqStartAsap_c; + msg.msgData.edReq.measureDurationSym = duration * 1000; + + phy_status = MAC_PLME_SapHandler(&msg, ot_phy_ctx); + if (phy_status != gPhySuccess_c) { + mcxw_radio->energy_scan_done = NULL; + status = -EIO; + } + + return status; +} + +static int mcxw_set_txpower(const struct device *dev, int16_t dbm) +{ + struct mcxw_context *mcxw_radio = dev->data; + + LOG_DBG("%d", dbm); + + if (dbm != mcxw_radio->tx_pwr_lvl) { + /* Set Power level for TX */ + rf_set_tx_power(dbm); + mcxw_radio->tx_pwr_lvl = dbm; + } + + return 0; +} + +static void mcxw_configure_enh_ack_probing(const struct ieee802154_config *config) +{ + uint32_t ie_param = 0; + macToPlmeMessage_t msg; + + uint8_t *header_ie_buf = (uint8_t *)(config->ack_ie.header_ie); + + ie_param = (header_ie_buf[6] == 0x03 ? IeData_Lqi_c : 0) | + (header_ie_buf[7] == 0x02 ? IeData_LinkMargin_c : 0) | + (header_ie_buf[8] == 0x01 ? IeData_Rssi_c : 0); + + msg.msgType = gPlmeConfigureAckIeData_c; + msg.msgData.AckIeData.param = (ie_param > 0 ? IeData_MSB_VALID_DATA : 0); + msg.msgData.AckIeData.param |= ie_param; + msg.msgData.AckIeData.shortAddr = config->ack_ie.short_addr; + memcpy(msg.msgData.AckIeData.extAddr, config->ack_ie.ext_addr, 8); + memcpy(msg.msgData.AckIeData.data, config->ack_ie.header_ie, + config->ack_ie.header_ie->length); + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +static void mcxw_set_mac_key(struct ieee802154_key *mac_keys) +{ + macToPlmeMessage_t msg; + + __ASSERT_NO_MSG(mac_keys); + __ASSERT_NO_MSG(mac_keys[0].key_id && mac_keys[0].key_value); + __ASSERT_NO_MSG(mac_keys[1].key_id && mac_keys[1].key_value); + __ASSERT_NO_MSG(mac_keys[2].key_id && mac_keys[2].key_value); + + msg.msgType = gPlmeSetMacKey_c; + msg.msgData.MacKeyData.keyId = *(mac_keys[1].key_id); + + memcpy(msg.msgData.MacKeyData.prevKey, mac_keys[0].key_value, 16); + memcpy(msg.msgData.MacKeyData.currKey, mac_keys[1].key_value, 16); + memcpy(msg.msgData.MacKeyData.nextKey, mac_keys[2].key_value, 16); + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +void mcxw_set_mac_frame_counter(uint32_t frame_counter) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetMacFrameCounter_c; + msg.msgData.MacFrameCounter = frame_counter; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +void mcxw_set_mac_frame_counter_if_larger(uint32_t frame_counter) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetMacFrameCounterIfLarger_c; + msg.msgData.MacFrameCounter = frame_counter; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +#if CONFIG_IEEE802154_CSL_ENDPOINT + +static void mcxw_receive_at(uint8_t channel, uint32_t start, uint32_t duration) +{ + macToPlmeMessage_t msg; + + __ASSERT_NO_MSG(mcxw_ctx.state == RADIO_STATE_SLEEP); + mcxw_ctx.state = RADIO_STATE_RECEIVE; + + /* checks internally if the channel needs to be changed */ + rf_set_channel(mcxw_ctx.channel); + + start = rf_adjust_tstamp_from_app(start); + + msg.msgType = gPlmeSetTRxStateReq_c; + msg.msgData.setTRxStateReq.slottedMode = gPhyUnslottedMode_c; + msg.msgData.setTRxStateReq.state = gPhySetRxOn_c; + msg.msgData.setTRxStateReq.rxDuration = duration / IEEE802154_SYMBOL_TIME_US; + msg.msgData.setTRxStateReq.startTime = start / IEEE802154_SYMBOL_TIME_US; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +static void mcxw_enable_csl(uint16_t period) +{ + mcxw_ctx.csl_period = period; + + macToPlmeMessage_t msg; + + msg.msgType = gPlmeCslEnable_c; + msg.msgData.cslPeriod = period; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +static void set_csl_sample_time(void) +{ + if (!mcxw_ctx.csl_period) { + return; + } + + macToPlmeMessage_t msg; + uint32_t csl_period = mcxw_ctx.csl_period * 10 * IEEE802154_SYMBOL_TIME_US; + uint32_t dt = mcxw_ctx.csl_sample_time - (uint32_t)mcxw_get_time(NULL); + + /* next channel sample should be in the future */ + while ((dt <= CMP_OVHD) || (dt > (CMP_OVHD + 2 * csl_period))) { + mcxw_ctx.csl_sample_time += csl_period; + dt = mcxw_ctx.csl_sample_time - (uint32_t)mcxw_get_time(NULL); + } + + /* The CSL sample time is in microseconds and PHY function expects also microseconds */ + msg.msgType = gPlmeCslSetSampleTime_c; + msg.msgData.cslSampleTime = rf_adjust_tstamp_from_app(mcxw_ctx.csl_sample_time); + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +static void start_csl_receiver(void) +{ + if (!mcxw_ctx.csl_period) { + return; + } + + /* NBU has to be awake during CSL receiver trx so that conversion from + * PHY timebase (NBU) to TMR timebase (host) is valid + */ + if (!csl_rx) { + PLATFORM_RemoteActiveReq(); + + csl_rx = TRUE; + } + + /* sample time is converted to PHY time */ + set_csl_sample_time(); +} + +static void stop_csl_receiver(void) +{ + if (csl_rx) { + PLATFORM_RemoteActiveRel(); + + csl_rx = FALSE; + } +} + +/* + * Compute the CSL Phase for the time_us - i.e. the time from the time_us to + * mcxw_ctx.csl_sample_time. The assumption is that mcxw_ctx.csl_sample_time > time_us. Since the + * time is kept with a limited timer in reality it means that sometimes mcxw_ctx.csl_sample_time < + * time_us, when the timer overflows. Therefore the formula should be: + * + * if (time_us <= mcxw_ctx.csl_sample_time) + * csl_phase_us = mcxw_ctx.csl_sample_time - time_us; + * else + * csl_phase_us = MAX_TIMER_VALUE - time_us + mcxw_ctx.csl_sample_time; + * + * For simplicity the formula below has been used. + */ +static uint16_t rf_compute_csl_phase(uint32_t time_us) +{ + /* convert CSL Period in microseconds - it was given in 10 symbols */ + uint32_t csl_period_us = mcxw_ctx.csl_period * 10 * IEEE802154_SYMBOL_TIME_US; + uint32_t csl_phase_us = + (csl_period_us - (time_us % csl_period_us) + + (mcxw_ctx.csl_sample_time % csl_period_us)) % csl_period_us; + + return (uint16_t)(csl_phase_us / (10 * IEEE802154_SYMBOL_TIME_US) + 1); +} +#endif /* CONFIG_IEEE802154_CSL_ENDPOINT */ + +/*************************************************************************************************/ +static void rf_abort(void) +{ + macToPlmeMessage_t msg; + + sun_rx_mode = RX_ON_IDLE_START; + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibRxOnWhenIdle; + msg.msgData.setReq.PibAttributeValue = (uint64_t)0; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); + + msg.msgType = gPlmeSetTRxStateReq_c; + msg.msgData.setTRxStateReq.state = gPhyForceTRxOff_c; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +static void rf_set_channel(uint8_t channel) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibCurrentChannel_c; + msg.msgData.setReq.PibAttributeValue = (uint64_t)channel; + + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +static int mcxw_cca(const struct device *dev) +{ + macToPlmeMessage_t msg; + phyStatus_t phy_status; + + struct mcxw_context *mcxw_radio = dev->data; + + msg.msgType = gPlmeCcaReq_c; + msg.msgData.ccaReq.ccaType = gPhyCCAMode1_c; + msg.msgData.ccaReq.contCcaMode = gPhyContCcaDisabled; + + phy_status = MAC_PLME_SapHandler(&msg, ot_phy_ctx); + + __ASSERT_NO_MSG(phy_status == gPhySuccess_c); + + k_sem_take(&mcxw_radio->cca_wait, K_FOREVER); + + return (mcxw_radio->tx_status == OT_ERROR_CHANNEL_ACCESS_FAILURE) ? -EBUSY : 0; +} + +static int mcxw_set_channel(const struct device *dev, uint16_t channel) +{ + struct mcxw_context *mcxw_radio = dev->data; + + LOG_DBG("%u", channel); + + if (channel != mcxw_radio->channel) { + + if (channel < 11 || channel > 26) { + return channel < 11 ? -ENOTSUP : -EINVAL; + } + + mcxw_radio->channel = channel; + } + + return 0; +} + +static net_time_t mcxw_get_time(const struct device *dev) +{ + static uint64_t sw_timestamp; + static uint64_t hw_timestamp; + + ARG_UNUSED(dev); + + /* Get new 32bit HW timestamp */ + uint32_t ticks; + uint64_t hw_timestamp_new; + uint64_t wrapped_val = 0; + uint64_t increment; + unsigned int key; + + key = irq_lock(); + + if (counter_get_value(mcxw_ctx.counter, &ticks)) { + irq_unlock(key); + return -1; + } + + hw_timestamp_new = counter_ticks_to_us(mcxw_ctx.counter, ticks); + + /* Check if the timestamp has wrapped around */ + if (hw_timestamp > hw_timestamp_new) { + wrapped_val = + COUNT_TO_USEC(((uint64_t)1 << 32), counter_get_frequency(mcxw_ctx.counter)); + } + + increment = (hw_timestamp_new + wrapped_val) - hw_timestamp; + sw_timestamp += increment; + + /* Store new HW timestamp for next iteration */ + hw_timestamp = hw_timestamp_new; + + irq_unlock(key); + + return (net_time_t)sw_timestamp; +} + +static void rf_set_tx_power(int8_t tx_power) +{ + macToPlmeMessage_t msg; + + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibTransmitPower_c; + msg.msgData.setReq.PibAttributeValue = (uint64_t)tx_power; + + MAC_PLME_SapHandler(&msg, ot_phy_ctx); +} + +/* Used to convert from phy clock timestamp (in symbols) to platform time (in us) + * the reception timestamp which must use a true 64bit timestamp source + */ +static uint64_t rf_adjust_tstamp_from_phy(uint64_t ts) +{ + uint64_t now = PhyTime_ReadClock(); + uint64_t delta; + + delta = (now >= ts) ? (now - ts) : ((PHY_TMR_MAX_VALUE + now) - ts); + delta *= IEEE802154_SYMBOL_TIME_US; + + return mcxw_get_time(NULL) - delta; +} + +#if CONFIG_IEEE802154_CSL_ENDPOINT || CONFIG_NET_PKT_TXTIME +static uint32_t rf_adjust_tstamp_from_app(uint32_t time) +{ + /* The phy timestamp is in symbols so we need to convert it to microseconds */ + uint64_t ts = PhyTime_ReadClock() * IEEE802154_SYMBOL_TIME_US; + uint32_t delta = time - (uint32_t)mcxw_get_time(NULL); + + return (uint32_t)(ts + delta); +} +#endif /* CONFIG_IEEE802154_CSL_ENDPOINT || CONFIG_NET_PKT_TXTIME */ + +/* Phy Data Service Access Point handler + * Called by Phy to notify when Tx has been done or Rx data is available + */ +phyStatus_t pd_mac_sap_handler(void *msg, instanceId_t instance) +{ + pdDataToMacMessage_t *data_msg = (pdDataToMacMessage_t *)msg; + + __ASSERT_NO_MSG(msg != NULL); + + /* PWR_DisallowDeviceToSleep(); */ + + switch (data_msg->msgType) { + case gPdDataCnf_c: + /* TX is done */ +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + if (is_keyid_mode_1(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length) && + !mcxw_ctx.tx_frame.sec_processed && !mcxw_ctx.tx_frame.hdr_updated) { + set_frame_counter(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length, + data_msg->fc); + mcxw_ctx.tx_frame.hdr_updated = true; + } +#endif + + mcxw_ctx.tx_frame.length = 0; + mcxw_ctx.tx_status = 0; + mcxw_ctx.state = RADIO_STATE_RECEIVE; + + mcxw_ctx.rx_ack_frame.channel = mcxw_ctx.channel; + mcxw_ctx.rx_ack_frame.length = data_msg->msgData.dataCnf.ackLength; + mcxw_ctx.rx_ack_frame.timestamp = data_msg->msgData.dataCnf.timeStamp; + memcpy(mcxw_ctx.rx_ack_frame.psdu, data_msg->msgData.dataCnf.ackData, + mcxw_ctx.rx_ack_frame.length); + + k_sem_give(&mcxw_ctx.tx_wait); + + k_free(msg); + break; + + case gPdDataInd_c: + /* RX is done */ + struct mcxw_rx_frame rx_frame; + + /* retrieve frame information and data */ + rx_frame.lqi = data_msg->msgData.dataInd.ppduLinkQuality; + rx_frame.rssi = data_msg->msgData.dataInd.ppduRssi; + rx_frame.timestamp = rf_adjust_tstamp_from_phy(data_msg->msgData.dataInd.timeStamp); + rx_frame.ack_fpb = data_msg->msgData.dataInd.rxAckFp; + rx_frame.length = data_msg->msgData.dataInd.psduLength; + rx_frame.psdu = data_msg->msgData.dataInd.pPsdu; + rx_frame.ack_seb = data_msg->msgData.dataInd.ackedWithSecEnhAck; + + rx_frame.phy_buffer = (void *)msg; + + /* stop rx on idle if message queue is almost full */ + if (k_msgq_num_free_get(&mcxw_ctx.rx_msgq) == 1) { + rf_rx_on_idle(RX_ON_IDLE_STOP); + } + + /* add the rx message in queue */ + if (k_msgq_put(&mcxw_ctx.rx_msgq, &rx_frame, K_NO_WAIT) < 0) { + LOG_ERR("Failed to push RX data to message queue"); + } + break; + + default: + /* PWR_AllowDeviceToSleep(); */ + break; + } + + stop_csl_receiver(); + + return gPhySuccess_c; +} + +/* Phy Layer Management Entities Service Access Point handler + * Called by Phy to notify PLME event + */ +phyStatus_t plme_mac_sap_handler(void *msg, instanceId_t instance) +{ + plmeToMacMessage_t *plme_msg = (plmeToMacMessage_t *)msg; + + __ASSERT_NO_MSG(msg != NULL); + + /* PWR_DisallowDeviceToSleep(); */ + + switch (plme_msg->msgType) { + case gPlmeCcaCnf_c: + if (plme_msg->msgData.ccaCnf.status == gPhyChannelBusy_c) { + /* Channel is busy */ + mcxw_ctx.tx_status = EBUSY; + } else { + mcxw_ctx.tx_status = 0; + } + mcxw_ctx.state = RADIO_STATE_RECEIVE; + + k_sem_give(&mcxw_ctx.cca_wait); + break; + case gPlmeEdCnf_c: + /* Scan done */ + if (mcxw_ctx.energy_scan_done != NULL) { + energy_scan_done_cb_t callback = mcxw_ctx.energy_scan_done; + + mcxw_ctx.max_ed = plme_msg->msgData.edCnf.maxEnergyLeveldB; + + mcxw_ctx.energy_scan_done = NULL; + callback(net_if_get_device(mcxw_ctx.iface), mcxw_ctx.max_ed); + } + break; + case gPlmeTimeoutInd_c: + if (RADIO_STATE_TRANSMIT == mcxw_ctx.state) { + /* Ack timeout */ +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + if (is_keyid_mode_1(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length) && + !mcxw_ctx.tx_frame.sec_processed && !mcxw_ctx.tx_frame.hdr_updated) { + set_frame_counter(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length, + plme_msg->fc); + mcxw_ctx.tx_frame.hdr_updated = true; + } +#endif + + mcxw_ctx.state = RADIO_STATE_RECEIVE; + /* No ack */ + mcxw_ctx.tx_status = ENOMSG; + + k_sem_give(&mcxw_ctx.tx_wait); + } else if (RADIO_STATE_RECEIVE == mcxw_ctx.state) { + /* CSL Receive AT state has ended with timeout and we are returning to SLEEP + * state + */ + mcxw_ctx.state = RADIO_STATE_SLEEP; + /* PWR_AllowDeviceToSleep(); */ + } + break; + case gPlmeAbortInd_c: + /* TX Packet was loaded into TX Packet RAM but the TX/TR seq did not ended ok */ +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + if (is_keyid_mode_1(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length) && + !mcxw_ctx.tx_frame.sec_processed && !mcxw_ctx.tx_frame.hdr_updated) { + set_frame_counter(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length, + plme_msg->fc); + mcxw_ctx.tx_frame.hdr_updated = true; + } +#endif + + mcxw_ctx.state = RADIO_STATE_RECEIVE; + mcxw_ctx.tx_status = EIO; + + k_sem_give(&mcxw_ctx.tx_wait); + break; + default: + /* PWR_AllowDeviceToSleep(); */ + break; + } + /* The message has been allocated by the Phy, we have to free it */ + k_free(msg); + + stop_csl_receiver(); + + return gPhySuccess_c; +} + +static int mcxw_configure(const struct device *dev, enum ieee802154_config_type type, + const struct ieee802154_config *config) +{ + ARG_UNUSED(dev); + + switch (type) { + + case IEEE802154_CONFIG_AUTO_ACK_FPB: + if (config->auto_ack_fpb.mode == IEEE802154_FPB_ADDR_MATCH_THREAD) { + mcxw_enable_src_match(config->auto_ack_fpb.enabled); + } + /* TODO IEEE802154_FPB_ADDR_MATCH_ZIGBEE */ + break; + + case IEEE802154_CONFIG_ACK_FPB: + if (config->ack_fpb.enabled) { + return mcxw_src_match_entry(config->ack_fpb.extended, config->ack_fpb.addr); + } else { + return mcxw_src_clear_entry(config->ack_fpb.extended, config->ack_fpb.addr); + } + + /* TODO otPlatRadioClearSrcMatchShortEntries */ + /* TODO otPlatRadioClearSrcMatchExtEntries */ + break; + + case IEEE802154_CONFIG_PAN_COORDINATOR: + mcxw_set_pan_coord(config->pan_coordinator); + break; + + case IEEE802154_CONFIG_PROMISCUOUS: + mcxw_set_promiscuous(config->promiscuous); + break; + + case IEEE802154_CONFIG_MAC_KEYS: + mcxw_set_mac_key(config->mac_keys); + break; + + case IEEE802154_CONFIG_FRAME_COUNTER: + mcxw_set_mac_frame_counter(config->frame_counter); + break; + + case IEEE802154_CONFIG_FRAME_COUNTER_IF_LARGER: + mcxw_set_mac_frame_counter_if_larger(config->frame_counter); + break; + + case IEEE802154_CONFIG_ENH_ACK_HEADER_IE: + mcxw_configure_enh_ack_probing(config); + break; + +#if defined(CONFIG_IEEE802154_CSL_ENDPOINT) + case IEEE802154_CONFIG_EXPECTED_RX_TIME: + mcxw_ctx.csl_sample_time = config->expected_rx_time; + break; + + case IEEE802154_CONFIG_RX_SLOT: + mcxw_receive_at(config->rx_slot.channel, config->rx_slot.start / NSEC_PER_USEC, + config->rx_slot.duration / NSEC_PER_USEC); + break; + + case IEEE802154_CONFIG_CSL_PERIOD: + mcxw_enable_csl(config->csl_period); + break; +#endif /* CONFIG_IEEE802154_CSL_ENDPOINT */ + + case IEEE802154_CONFIG_RX_ON_WHEN_IDLE: + if (config->rx_on_when_idle) { + rf_rx_on_idle(RX_ON_IDLE_START); + } else { + rf_rx_on_idle(RX_ON_IDLE_STOP); + } + break; + + case IEEE802154_CONFIG_EVENT_HANDLER: + break; + + case IEEE802154_OPENTHREAD_CONFIG_MAX_EXTRA_CCA_ATTEMPTS: + break; + + default: + return -EINVAL; + } + + return 0; +} + +IEEE802154_DEFINE_PHY_SUPPORTED_CHANNELS(drv_attr, 11, 26); + +static int mcxw_attr_get(const struct device *dev, enum ieee802154_attr attr, + struct ieee802154_attr_value *value) +{ + ARG_UNUSED(dev); + + if (ieee802154_attr_get_channel_page_and_range( + attr, IEEE802154_ATTR_PHY_CHANNEL_PAGE_ZERO_OQPSK_2450_BPSK_868_915, + &drv_attr.phy_supported_channels, value) == 0) { + return 0; + } + + return -EIO; +} + +static enum ieee802154_hw_caps mcxw_get_capabilities(const struct device *dev) +{ + enum ieee802154_hw_caps caps; + + caps = IEEE802154_HW_FCS | IEEE802154_HW_PROMISC | IEEE802154_HW_FILTER | + IEEE802154_HW_TX_RX_ACK | IEEE802154_HW_RX_TX_ACK | IEEE802154_HW_ENERGY_SCAN | + IEEE802154_HW_TXTIME | IEEE802154_HW_RXTIME | IEEE802154_HW_SLEEP_TO_TX | + IEEE802154_RX_ON_WHEN_IDLE | IEEE802154_HW_TX_SEC | + IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA | IEEE802154_HW_SELECTIVE_TXCHANNEL | + IEEE802154_OPENTHREAD_HW_CST; + return caps; +} + +static int mcxw_init(const struct device *dev) +{ + struct mcxw_context *mcxw_radio = dev->data; + + macToPlmeMessage_t msg; + + if (PLATFORM_InitOT() < 0) { + return -EIO; + } + + Phy_Init(); + + ot_phy_ctx = PHY_get_ctx(); + + /* Register Phy Data Service Access Point and Phy Layer Management Entities Service Access + * Point handlers + */ + Phy_RegisterSapHandlers((PD_MAC_SapHandler_t)pd_mac_sap_handler, + (PLME_MAC_SapHandler_t)plme_mac_sap_handler, ot_phy_ctx); + + msg.msgType = gPlmeEnableEncryption_c; + (void)MAC_PLME_SapHandler(&msg, ot_phy_ctx); + + mcxw_radio->state = RADIO_STATE_DISABLED; + mcxw_radio->energy_scan_done = NULL; + + mcxw_radio->channel = DEFAULT_CHANNEL; + rf_set_channel(mcxw_radio->channel); + + mcxw_radio->tx_frame.length = 0; + /* Make the psdu point to the space after macToPdDataMessage_t in the data buffer */ + mcxw_radio->tx_frame.psdu = mcxw_radio->tx_data + sizeof(macToPdDataMessage_t); + + /* Get and start LPTRM counter */ + mcxw_radio->counter = DEVICE_DT_GET(DT_NODELABEL(lptmr0)); + if (counter_start(mcxw_radio->counter)) { + return -EIO; + } + + /* Init TX semaphore */ + k_sem_init(&mcxw_radio->tx_wait, 0, 1); + /* Init CCA semaphore */ + k_sem_init(&mcxw_radio->cca_wait, 0, 1); + + /* Init RX message queue */ + k_msgq_init(&mcxw_radio->rx_msgq, mcxw_radio->rx_msgq_buffer, sizeof(mcxw_rx_frame), + NMAX_RXRING_BUFFERS); + + memset(&(mcxw_radio->rx_ack_frame), 0, sizeof(mcxw_radio->rx_ack_frame)); + mcxw_radio->rx_ack_frame.psdu = mcxw_radio->rx_ack_data; + + k_thread_create(&mcxw_radio->rx_thread, mcxw_radio->rx_stack, + CONFIG_IEEE802154_MCXW_RX_STACK_SIZE, mcxw_rx_thread, mcxw_radio, NULL, + NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); + + k_thread_name_set(&mcxw_radio->rx_thread, "mcxw_rx"); + + return 0; +} + +static void mcxw_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct mcxw_context *mcxw_radio = dev->data; + + mcxw_get_eui64(mcxw_radio->mac); + + net_if_set_link_addr(iface, mcxw_radio->mac, sizeof(mcxw_radio->mac), NET_LINK_IEEE802154); + mcxw_radio->iface = iface; + ieee802154_init(iface); +} + +static void rf_rx_on_idle(uint32_t new_val) +{ + macToPlmeMessage_t msg; + phyStatus_t phy_status; + + new_val %= 2; + if (sun_rx_mode != new_val) { + sun_rx_mode = new_val; + msg.msgType = gPlmeSetReq_c; + msg.msgData.setReq.PibAttribute = gPhyPibRxOnWhenIdle; + msg.msgData.setReq.PibAttributeValue = (uint64_t)sun_rx_mode; + + phy_status = MAC_PLME_SapHandler(&msg, ot_phy_ctx); + + __ASSERT_NO_MSG(phy_status == gPhySuccess_c); + } +} + +static const struct ieee802154_radio_api mcxw71_radio_api = { + .iface_api.init = mcxw_iface_init, + + .get_capabilities = mcxw_get_capabilities, + .cca = mcxw_cca, + .set_channel = mcxw_set_channel, + .filter = mcxw_filter, + .set_txpower = mcxw_set_txpower, + .start = mcxw_start, + .stop = mcxw_stop, + .configure = mcxw_configure, + .tx = mcxw_tx, + .ed_scan = mcxw_energy_scan, + .get_time = mcxw_get_time, + .get_sch_acc = mcxw_get_acc, + .attr_get = mcxw_attr_get, +}; + +#if defined(CONFIG_NET_L2_IEEE802154) +#define L2 IEEE802154_L2 +#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(IEEE802154_L2) +#define MTU IEEE802154_MTU +#elif defined(CONFIG_NET_L2_OPENTHREAD) +#define L2 OPENTHREAD_L2 +#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(OPENTHREAD_L2) +#define MTU 1280 +#elif defined(CONFIG_NET_L2_CUSTOM_IEEE802154) +#define L2 CUSTOM_IEEE802154_L2 +#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(CUSTOM_IEEE802154_L2) +#define MTU CONFIG_NET_L2_CUSTOM_IEEE802154_MTU +#endif + +NET_DEVICE_DT_INST_DEFINE(0, mcxw_init, NULL, &mcxw_ctx, NULL, CONFIG_IEEE802154_MCXW_INIT_PRIO, + &mcxw71_radio_api, L2, L2_CTX_TYPE, MTU); diff --git a/drivers/ieee802154/ieee802154_mcxw.h b/drivers/ieee802154/ieee802154_mcxw.h new file mode 100644 index 0000000000000..eb3fb284dc6ef --- /dev/null +++ b/drivers/ieee802154/ieee802154_mcxw.h @@ -0,0 +1,125 @@ +/* ieee802154_mcxw.h - NXP MCXW 802.15.4 driver */ + +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_IEEE802154_IEEE802154_MCXW_H_ +#define ZEPHYR_DRIVERS_IEEE802154_IEEE802154_MCXW_H_ + +#include + +#include "PhyInterface.h" + +#define TX_ENCRYPT_DELAY_SYM 200 + +#define DEFAULT_CHANNEL (11) +#define DEFAULT_CCA_MODE (gPhyCCAMode1_c) +#define IEEE802154_ACK_REQUEST (1 << 5) +#define IEEE802154_MIN_LENGTH (5) +#define IEEE802154_FRM_CTL_LO_OFFSET (0) +#define IEEE802154_DSN_OFFSET (2) +#define IEEE802154_FRM_TYPE_MASK (0x7) +#define IEEE802154_FRM_TYPE_ACK (0x2) +#define IEEE802154_SYMBOL_TIME_US (16) +#define IEEE802154_TURNAROUND_LEN_SYM (12) +#define IEEE802154_CCA_LEN_SYM (8) +#define IEEE802154_PHY_SHR_LEN_SYM (10) +#define IEEE802154_IMM_ACK_WAIT_SYM (54) +#define IEEE802154_ENH_ACK_WAIT_SYM (90) + +#define NMAX_RXRING_BUFFERS (8) +#define RX_ON_IDLE_START (1) +#define RX_ON_IDLE_STOP (0) + +#define PHY_TMR_MAX_VALUE (0x00FFFFFF) + +/* The Uncertainty of the scheduling CSL of transmission by the parent, in ±10 us units. */ +#define CSL_UNCERT 32 + +#define RADIO_SYMBOLS_PER_OCTET (2) + +typedef enum mcxw_radio_state { + RADIO_STATE_DISABLED = 0, + RADIO_STATE_SLEEP = 1, + RADIO_STATE_RECEIVE = 2, + RADIO_STATE_TRANSMIT = 3, + RADIO_STATE_INVALID = 255, +} mcxw_radio_state; + +typedef struct mcxw_rx_frame { + uint8_t *psdu; + uint8_t length; + int8_t rssi; + uint8_t lqi; + uint32_t timestamp; + bool ack_fpb; + bool ack_seb; + uint64_t time; + void *phy_buffer; + uint8_t channel; +} mcxw_rx_frame; + +typedef struct mcxw_tx_frame { + uint8_t *psdu; + uint8_t length; + uint32_t tx_delay; + uint32_t tx_delay_base; + bool sec_processed; + bool hdr_updated; +} mcxw_tx_frame; + +struct mcxw_context { + /* Pointer to the network interface. */ + struct net_if *iface; + /* Pointer to the LPTMR counter device structure*/ + const struct device *counter; + /* 802.15.4 HW address. */ + uint8_t mac[8]; + /* RX thread stack. */ + K_KERNEL_STACK_MEMBER(rx_stack, CONFIG_IEEE802154_MCXW_RX_STACK_SIZE); + /* RX thread control block. */ + struct k_thread rx_thread; + /* RX message queue */ + struct k_msgq rx_msgq; + /* RX message queue buffer */ + char rx_msgq_buffer[NMAX_RXRING_BUFFERS * sizeof(mcxw_rx_frame)]; + /* TX synchronization semaphore */ + struct k_sem tx_wait; + /* TX synchronization semaphore */ + struct k_sem cca_wait; + /* Radio state */ + mcxw_radio_state state; + /* Pan ID */ + uint16_t pan_id; + /* Channel */ + uint8_t channel; + /* Maximum energy detected during ED scan */ + int8_t max_ed; + /* TX power level */ + int8_t tx_pwr_lvl; + /* Enery detect */ + energy_scan_done_cb_t energy_scan_done; + /* TX Status */ + int tx_status; + /* TX frame */ + mcxw_tx_frame tx_frame; + /* TX data */ + uint8_t tx_data[sizeof(macToPdDataMessage_t) + IEEE802154_MAX_PHY_PACKET_SIZE]; + /* RX mode */ + uint32_t rx_mode; + /* RX ACK buffers */ + mcxw_rx_frame rx_ack_frame; + /* RX ACK data */ + uint8_t rx_ack_data[IEEE802154_MAX_PHY_PACKET_SIZE]; + /* CSL period */ + uint32_t csl_period; + /* CSL sample time in microseconds */ + uint32_t csl_sample_time; + /* PHY context */ + uint8_t ot_phy_ctx; +}; + +#endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_MCXW_H_ */ diff --git a/drivers/ieee802154/ieee802154_mcxw_utils.c b/drivers/ieee802154/ieee802154_mcxw_utils.c new file mode 100644 index 0000000000000..0367f8a26b64c --- /dev/null +++ b/drivers/ieee802154/ieee802154_mcxw_utils.c @@ -0,0 +1,356 @@ +/* ieee802154_mcxw_utils.c - NXP MCXW 802.15.4 driver utils*/ + +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include +#include + +#include + +#include "ieee802154_mcxw_utils.h" + +/* TODO IEEE 802.15.4 MAC Multipurpose frame format */ +/* TODO add function checks */ + +enum offset_fcf_fields { + OffsetFrameType = 0x00, + OffsetSecurityEnabled = 0x03, + OffsetFramePending = 0x04, + OffsetAR = 0x05, + OffsetPanIdCompression = 0x06, + OffsetSeqNumberSuppression = 0x08, + OffsetIEPresent = 0x09, + OffsetDstAddrMode = 0x0A, + OffsetFrameVersion = 0x0C, + OffsetSrcAddrMode = 0x0E, +}; + +enum mask_fcf_fields { + MaskFrameType = (0x7 << OffsetFrameType), + MaskSecurityEnabled = (0x01 << OffsetSecurityEnabled), + MaskFramePending = (0x01 << OffsetFramePending), + MaskAR = (0x01 << OffsetAR), + MaskPanIdCompression = (0x01 << OffsetPanIdCompression), + MaskSeqNumberSuppression = (0x01 << OffsetSeqNumberSuppression), + MaskIEPresent = (0x01 << OffsetIEPresent), + MaskDstAddrMode = (0x03 << OffsetDstAddrMode), + MaskFrameVersion = (0x03 << OffsetFrameVersion), + MaskSrcAddrMode = (0x03 << OffsetSrcAddrMode), +}; + +enum modes_dst_addr { + ModeDstAddrNone = 0x00, + ModeDstAddrShort = (0x02 << OffsetDstAddrMode), + ModeDstAddrExt = (0x03 << OffsetDstAddrMode), +}; + +enum version_frame { + VersionIeee2003 = 0x00, + VersionIeee2006 = 0x01, + VersionIeee2015 = 0x02, +}; + +enum modes_src_addr { + ModeSrcAddrNone = 0x00, + ModeSrcAddrShort = (0x02 << OffsetSrcAddrMode), + ModeSrcAddrExt = (0x03 << OffsetSrcAddrMode), +}; + +enum offset_scf_fields { + OffsetSecurityLevel = 0x00, + OffsetKeyIdMode = 0x03, + OffsetFrameCntSuppression = 0x05, + OffsetASNinNonce = 0x06, +}; + +enum mask_scf_fields { + MaskSecurityLevel = (0x07 << OffsetSecurityLevel), + MaskKeyIdMode = (0x03 << OffsetKeyIdMode), + MaskFrameCntSuppression = (0x1 << OffsetFrameCntSuppression), + MaskASNinNonce = (0x01 << OffsetASNinNonce), +}; + +static uint16_t get_frame_control_field(uint8_t *pdu, uint16_t length) +{ + if ((pdu == NULL) || (length < 3)) { + return 0x00; + } + + return (uint16_t)(pdu[0] | (pdu[1] << 8)); +} + +static bool is_security_enabled(uint16_t fcf) +{ + if (fcf) { + return (bool)(fcf & MaskSecurityEnabled); + } + + return false; +} + +static bool is_ie_present(uint16_t fcf) +{ + if (fcf) { + return (bool)(fcf & MaskIEPresent); + } + + return false; +} + +static uint8_t get_frame_version(uint16_t fcf) +{ + if (fcf) { + return (uint8_t)((fcf & MaskFrameVersion) >> OffsetFrameVersion); + } + + return 0xFF; +} + +static bool is_frame_version_2015_fcf(uint16_t fcf) +{ + if (fcf) { + return get_frame_version(fcf) == VersionIeee2015; + } + + return false; +} + +bool is_frame_version_2015(uint8_t *pdu, uint16_t length) +{ + uint16_t fcf = get_frame_control_field(pdu, length); + + if (fcf) { + return get_frame_version(fcf) == VersionIeee2015; + } + + return false; +} + +static bool is_sequence_number_suppression(uint16_t fcf) +{ + if (fcf) { + return (bool)(fcf & MaskSeqNumberSuppression); + } + + return false; +} + +static bool is_dst_panid_present(uint16_t fcf) +{ + bool present; + + if (!fcf) { + return false; + } + + if (is_frame_version_2015_fcf(fcf)) { + switch (fcf & (MaskDstAddrMode | MaskSrcAddrMode | MaskPanIdCompression)) { + case (ModeDstAddrNone | ModeSrcAddrNone): + case (ModeDstAddrShort | ModeSrcAddrNone | MaskPanIdCompression): + case (ModeDstAddrExt | ModeSrcAddrNone | MaskPanIdCompression): + case (ModeDstAddrNone | ModeSrcAddrShort): + case (ModeDstAddrNone | ModeSrcAddrExt): + case (ModeDstAddrNone | ModeSrcAddrShort | MaskPanIdCompression): + case (ModeDstAddrNone | ModeSrcAddrExt | MaskPanIdCompression): + case (ModeDstAddrExt | ModeSrcAddrExt | MaskPanIdCompression): + present = false; + break; + default: + present = true; + } + } else { + present = (bool)(fcf & MaskDstAddrMode); + } + + return present; +} + +static bool is_src_panid_present(uint16_t fcf) +{ + bool present; + + if (!fcf) { + return false; + } + + if (is_frame_version_2015_fcf(fcf)) { + switch (fcf & (MaskDstAddrMode | MaskSrcAddrMode | MaskPanIdCompression)) { + case (ModeDstAddrNone | ModeSrcAddrShort): + case (ModeDstAddrNone | ModeSrcAddrExt): + case (ModeDstAddrShort | ModeSrcAddrShort): + case (ModeDstAddrShort | ModeSrcAddrExt): + case (ModeDstAddrExt | ModeSrcAddrShort): + present = true; + break; + default: + present = false; + } + + } else { + present = ((fcf & MaskSrcAddrMode) != 0) && ((fcf & MaskPanIdCompression) == 0); + } + + return present; +} + +static uint8_t calculate_addr_field_size(uint16_t fcf) +{ + uint8_t size = 2; + + if (!fcf) { + return 0; + } + + if (!is_sequence_number_suppression(fcf)) { + size += 1; + } + + if (is_dst_panid_present(fcf)) { + size += 2; + } + + /* destination addressing mode */ + switch (fcf & MaskDstAddrMode) { + case ModeDstAddrShort: + size += 2; + break; + case ModeDstAddrExt: + size += 8; + break; + default: + break; + } + + if (is_src_panid_present(fcf)) { + size += 2; + } + + /* source addressing mode */ + switch (fcf & MaskSrcAddrMode) { + case ModeSrcAddrShort: + size += 2; + break; + case ModeSrcAddrExt: + size += 8; + break; + default: + break; + } + + return size; +} + +static uint8_t get_keyid_mode(uint8_t *pdu, uint16_t length) +{ + uint16_t fcf = get_frame_control_field(pdu, length); + uint8_t ash_start; + + if (is_security_enabled(fcf)) { + ash_start = calculate_addr_field_size(fcf); + return (uint8_t)((pdu[ash_start] & MaskKeyIdMode) >> OffsetKeyIdMode); + } + + return 0xFF; +} + +bool is_keyid_mode_1(uint8_t *pdu, uint16_t length) +{ + uint8_t key_mode = get_keyid_mode(pdu, length); + + if (key_mode == 0x01) { + return true; + } + + return false; +} + +void set_frame_counter(uint8_t *pdu, uint16_t length, uint32_t fc) +{ + uint16_t fcf = get_frame_control_field(pdu, length); + + if (is_security_enabled(fcf)) { + uint8_t ash_start = calculate_addr_field_size(fcf); + uint8_t scf = pdu[ash_start]; + + /* check that Frame Counter Suppression is not set */ + if (!(scf & MaskFrameCntSuppression)) { + sys_put_le32(fc, &pdu[ash_start + 1]); + } + } +} + +static uint8_t get_asn_size(uint8_t *pdu, uint16_t length) +{ + uint16_t fcf = get_frame_control_field(pdu, length); + + if (is_security_enabled(fcf)) { + uint8_t ash_start = calculate_addr_field_size(fcf); + uint8_t scf = pdu[ash_start]; + uint8_t size = 1; + + /* Frame Counter Suppression is not set */ + if (!(scf & MaskFrameCntSuppression)) { + size += 4; + } + + uint8_t key_mode = get_keyid_mode(pdu, length); + + switch (key_mode) { + case 0x01: + size += 1; + break; + case 0x02: + size += 5; + case 0x03: + size += 9; + default: + break; + } + + return size; + } + return 0; +} + +static uint8_t *get_csl_ie_content_start(uint8_t *pdu, uint16_t length) +{ + uint16_t fcf = get_frame_control_field(pdu, length); + + if (is_ie_present(fcf)) { + uint8_t ie_start_idx = calculate_addr_field_size(fcf) + get_asn_size(pdu, length); + uint8_t *cur_ie = &pdu[ie_start_idx]; + + uint8_t ie_header = (uint16_t)(cur_ie[0] | (cur_ie[1] << 8)); + uint8_t ie_length = ie_header & 0x7F; + uint8_t ie_el_id = ie_header & 0x7F80; + + while ((ie_el_id != 0x7e) && (ie_el_id != 0x7f)) { + if (ie_el_id == 0x1a) { + return (cur_ie + 2); + } + cur_ie += (2 + ie_length); + ie_header = (uint16_t)(cur_ie[0] | (cur_ie[1] << 8)); + ie_length = ie_header & 0x7F; + ie_el_id = ie_header & 0x7F80; + } + } + + return NULL; +} + +void set_csl_ie(uint8_t *pdu, uint16_t length, uint16_t period, uint16_t phase) +{ + uint8_t *csl_ie_content = get_csl_ie_content_start(pdu, length); + + if (csl_ie_content) { + sys_put_le16(phase, csl_ie_content); + sys_put_le16(period, csl_ie_content + 2); + } +} diff --git a/drivers/ieee802154/ieee802154_mcxw_utils.h b/drivers/ieee802154/ieee802154_mcxw_utils.h new file mode 100644 index 0000000000000..2b37538eeeb05 --- /dev/null +++ b/drivers/ieee802154/ieee802154_mcxw_utils.h @@ -0,0 +1,16 @@ +/* ieee802154_mcxw_utils.h - NXP MCXW 802.15.4 driver utils*/ + +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +bool is_frame_version_2015(uint8_t *pdu, uint16_t length); + +bool is_keyid_mode_1(uint8_t *pdu, uint16_t length); + +void set_frame_counter(uint8_t *pdu, uint16_t length, uint32_t fc); + +void set_csl_ie(uint8_t *pdu, uint16_t length, uint16_t period, uint16_t phase); From e9cdc6e77634dff4713403111e66a1e14db2121d Mon Sep 17 00:00:00 2001 From: Andrei Menzopol Date: Fri, 7 Feb 2025 11:59:30 +0200 Subject: [PATCH 0122/6055] dts: nxp: add ieee and trng bindings and nodes Add ieee802154 and trng bindings and nodes Signed-off-by: Andrei Menzopol --- dts/arm/nxp/nxp_mcxw7x_common.dtsi | 10 ++++++++++ dts/bindings/ieee802154/nxp,mcxw-ieee802154.yaml | 8 ++++++++ dts/bindings/rng/nxp,ele-trng.yaml | 8 ++++++++ 3 files changed, 26 insertions(+) create mode 100644 dts/bindings/ieee802154/nxp,mcxw-ieee802154.yaml create mode 100644 dts/bindings/rng/nxp,ele-trng.yaml diff --git a/dts/arm/nxp/nxp_mcxw7x_common.dtsi b/dts/arm/nxp/nxp_mcxw7x_common.dtsi index dba26683e83c9..7e0a42c405726 100644 --- a/dts/arm/nxp/nxp_mcxw7x_common.dtsi +++ b/dts/arm/nxp/nxp_mcxw7x_common.dtsi @@ -19,6 +19,8 @@ chosen { zephyr,bt-hci = &hci; + zephyr,ieee802154 = &ieee802154; + zephyr,entropy = &trng; zephyr,nbu = &nbu; }; @@ -286,6 +288,14 @@ compatible = "nxp,hci-ble"; }; + ieee802154: ieee802154 { + compatible = "nxp,mcxw-ieee802154"; + }; + + trng: trng { + compatible = "nxp,ele-trng"; + }; + flexcan0: can@3b000 { compatible = "nxp,flexcan"; reg = <0x3b000 0x3080>; diff --git a/dts/bindings/ieee802154/nxp,mcxw-ieee802154.yaml b/dts/bindings/ieee802154/nxp,mcxw-ieee802154.yaml new file mode 100644 index 0000000000000..cb76bf63ac8ce --- /dev/null +++ b/dts/bindings/ieee802154/nxp,mcxw-ieee802154.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2025, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP MCXW71 IEEE 802.15.4 node + +compatible: "nxp,mcxw-ieee802154" + +include: base.yaml diff --git a/dts/bindings/rng/nxp,ele-trng.yaml b/dts/bindings/rng/nxp,ele-trng.yaml new file mode 100644 index 0000000000000..c501461da760f --- /dev/null +++ b/dts/bindings/rng/nxp,ele-trng.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2025, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP ELE (EdgeLock secure enclave) TRNG (True Random Number Generator) + +compatible: "nxp,ele-trng" + +include: base.yaml From 50de97fedbf6279ff1c82829ae12c9e9434c9b9f Mon Sep 17 00:00:00 2001 From: Andrei Menzopol Date: Fri, 7 Feb 2025 12:07:00 +0200 Subject: [PATCH 0123/6055] soc: nxp: mcxw: update conditions to account for ieee driver Add ram section for ieee driver. Use config for ieee driver. Signed-off-by: Andrei Menzopol --- soc/nxp/mcx/mcxw/CMakeLists.txt | 6 ++++-- soc/nxp/mcx/mcxw/Kconfig.defconfig | 12 +++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/soc/nxp/mcx/mcxw/CMakeLists.txt b/soc/nxp/mcx/mcxw/CMakeLists.txt index 5109d3175ab3f..aad110de351bf 100644 --- a/soc/nxp/mcx/mcxw/CMakeLists.txt +++ b/soc/nxp/mcx/mcxw/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2023-2024 NXP +# Copyright 2023-2025 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -14,4 +14,6 @@ zephyr_include_directories(.) set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") -zephyr_linker_sources_ifdef(CONFIG_BT RAM_SECTIONS sections.ld) +if (CONFIG_BT OR CONFIG_IEEE802154) + zephyr_linker_sources(RAM_SECTIONS sections.ld) +endif() diff --git a/soc/nxp/mcx/mcxw/Kconfig.defconfig b/soc/nxp/mcx/mcxw/Kconfig.defconfig index 5f7ad6800e628..d04ed76905a88 100644 --- a/soc/nxp/mcx/mcxw/Kconfig.defconfig +++ b/soc/nxp/mcx/mcxw/Kconfig.defconfig @@ -1,4 +1,4 @@ -# Copyright 2023-2024 NXP +# Copyright 2023-2025 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_MCXW @@ -45,4 +45,14 @@ config HCI_NXP_RX_THREAD default y endif # BT + +if NET_L2_IEEE802154 || NET_L2_OPENTHREAD + +# Include intercore messaging component +config NXP_RF_IMU + default y + +endif # NET_L2_IEEE802154 || NET_L2_OPENTHREAD + + endif # SOC_SERIES_MCXW From e6be77bc1d307f2d104d865cb13e28ea9b5b2bd4 Mon Sep 17 00:00:00 2001 From: Andrei Menzopol Date: Fri, 7 Feb 2025 12:08:57 +0200 Subject: [PATCH 0124/6055] samples: echo_client echo_server: add frdm_mcxw7 board overlays Add frdm_mcxw7 board conf and overlay files for echo_client and echo_server sample applications. Signed-off-by: Andrei Menzopol --- .../echo_client/boards/frdm_mcxw71.conf | 4 ++++ .../echo_client/boards/frdm_mcxw71.overlay | 20 +++++++++++++++++++ .../echo_server/boards/frdm_mcxw71.conf | 4 ++++ .../echo_server/boards/frdm_mcxw71.overlay | 20 +++++++++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 samples/net/sockets/echo_client/boards/frdm_mcxw71.conf create mode 100644 samples/net/sockets/echo_client/boards/frdm_mcxw71.overlay create mode 100644 samples/net/sockets/echo_server/boards/frdm_mcxw71.conf create mode 100644 samples/net/sockets/echo_server/boards/frdm_mcxw71.overlay diff --git a/samples/net/sockets/echo_client/boards/frdm_mcxw71.conf b/samples/net/sockets/echo_client/boards/frdm_mcxw71.conf new file mode 100644 index 0000000000000..36b66408f8675 --- /dev/null +++ b/samples/net/sockets/echo_client/boards/frdm_mcxw71.conf @@ -0,0 +1,4 @@ +CONFIG_COUNTER=y + +CONFIG_OPENTHREAD_MAX_IP_ADDR_PER_CHILD=4 +CONFIG_OPENTHREAD_MAX_CHILDREN=30 diff --git a/samples/net/sockets/echo_client/boards/frdm_mcxw71.overlay b/samples/net/sockets/echo_client/boards/frdm_mcxw71.overlay new file mode 100644 index 0000000000000..71da6a25089fd --- /dev/null +++ b/samples/net/sockets/echo_client/boards/frdm_mcxw71.overlay @@ -0,0 +1,20 @@ +/* + * Copyright 2023-2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&stcm { + ranges = <0x0 0x30000000 DT_SIZE_K(112)>; + + stcm1: system_memory@1a000 { + compatible = "zephyr,memory-region","mmio-sram"; + reg = <0x1a000 DT_SIZE_K(4)>; + zephyr,memory-region = "RetainedMem"; + }; +}; + +&stcm0 { + /* With only the first 64KB having ECC */ + reg = <0x0 DT_SIZE_K(108)>; +}; diff --git a/samples/net/sockets/echo_server/boards/frdm_mcxw71.conf b/samples/net/sockets/echo_server/boards/frdm_mcxw71.conf new file mode 100644 index 0000000000000..36b66408f8675 --- /dev/null +++ b/samples/net/sockets/echo_server/boards/frdm_mcxw71.conf @@ -0,0 +1,4 @@ +CONFIG_COUNTER=y + +CONFIG_OPENTHREAD_MAX_IP_ADDR_PER_CHILD=4 +CONFIG_OPENTHREAD_MAX_CHILDREN=30 diff --git a/samples/net/sockets/echo_server/boards/frdm_mcxw71.overlay b/samples/net/sockets/echo_server/boards/frdm_mcxw71.overlay new file mode 100644 index 0000000000000..71da6a25089fd --- /dev/null +++ b/samples/net/sockets/echo_server/boards/frdm_mcxw71.overlay @@ -0,0 +1,20 @@ +/* + * Copyright 2023-2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&stcm { + ranges = <0x0 0x30000000 DT_SIZE_K(112)>; + + stcm1: system_memory@1a000 { + compatible = "zephyr,memory-region","mmio-sram"; + reg = <0x1a000 DT_SIZE_K(4)>; + zephyr,memory-region = "RetainedMem"; + }; +}; + +&stcm0 { + /* With only the first 64KB having ECC */ + reg = <0x0 DT_SIZE_K(108)>; +}; From 17cc683c4eaaf25bbe6ab6244f8205819e153dbf Mon Sep 17 00:00:00 2001 From: Andrei Menzopol Date: Fri, 7 Feb 2025 12:11:50 +0200 Subject: [PATCH 0125/6055] samples: echo_client echo_server: update tests Group openthread tests under the same case and add frdm_mcxw71. Signed-off-by: Andrei Menzopol --- samples/net/sockets/echo_client/sample.yaml | 24 ++++++--------------- samples/net/sockets/echo_server/sample.yaml | 24 ++++++--------------- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/samples/net/sockets/echo_client/sample.yaml b/samples/net/sockets/echo_client/sample.yaml index ccde0349ed4d9..6ded48ae319f7 100644 --- a/samples/net/sockets/echo_client/sample.yaml +++ b/samples/net/sockets/echo_client/sample.yaml @@ -70,33 +70,21 @@ tests: sample.net.sockets.echo_client.nrf_802154: extra_args: EXTRA_CONF_FILE="overlay-802154.conf" platform_allow: nrf52840dk/nrf52840 - sample.net.sockets.echo_client.nrf_openthread: + sample.net.sockets.echo_client.openthread: extra_args: EXTRA_CONF_FILE="overlay-ot.conf" slow: true tags: - net - openthread - platform_allow: nrf52840dk/nrf52840 + platform_allow: + - frdm_kw41z + - frdm_mcxw71 + - nrf52840dk/nrf52840 + - tlsr9518adk80d filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample.net.sockets.echo_client.b91_802154: extra_args: EXTRA_CONF_FILE="overlay-802154.conf" platform_allow: tlsr9518adk80d - sample.net.sockets.echo_client.b91_openthread: - extra_args: EXTRA_CONF_FILE="overlay-ot.conf" - slow: true - tags: - - net - - openthread - platform_allow: tlsr9518adk80d - filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC - sample.net.sockets.echo_client.kw41z_openthread: - extra_args: EXTRA_CONF_FILE="overlay-ot.conf" - slow: true - tags: - - net - - openthread - platform_allow: frdm_kw41z - filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample.net.sockets.echo_client.rw612_openthread_rcp_host: build_only: true extra_args: diff --git a/samples/net/sockets/echo_server/sample.yaml b/samples/net/sockets/echo_server/sample.yaml index deaa6247aa495..9595e2444439f 100644 --- a/samples/net/sockets/echo_server/sample.yaml +++ b/samples/net/sockets/echo_server/sample.yaml @@ -88,29 +88,17 @@ tests: - native_sim/native/64 - native_posix - native_posix/native/64 - sample.net.sockets.echo_server.nrf_openthread: + sample.net.sockets.echo_server.openthread: extra_args: EXTRA_CONF_FILE="overlay-ot.conf" slow: true tags: - net - openthread - platform_allow: nrf52840dk/nrf52840 - filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC - sample.net.sockets.echo_server.b91_openthread: - extra_args: EXTRA_CONF_FILE="overlay-ot.conf" - slow: true - tags: - - net - - openthread - platform_allow: tlsr9518adk80d - filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC - sample.net.sockets.echo_server.kw41z_openthread: - extra_args: EXTRA_CONF_FILE="overlay-ot.conf" - slow: true - tags: - - net - - openthread - platform_allow: frdm_kw41z + platform_allow: + - frdm_kw41z + - frdm_mcxw71 + - nrf52840dk/nrf52840 + - tlsr9518adk80d filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample.net.sockets.echo_server.rw612_openthread_rcp_host: build_only: true From b6e136f274123bb800537b4d09bb346baf7f31df Mon Sep 17 00:00:00 2001 From: Andrei Menzopol Date: Fri, 7 Feb 2025 12:13:41 +0200 Subject: [PATCH 0126/6055] doc: frdm_mcxw71: update documentation Update documentation for dynamic NBU. Add openthread application building examples. Signed-off-by: Andrei Menzopol --- boards/nxp/frdm_mcxw71/doc/index.rst | 70 +++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/boards/nxp/frdm_mcxw71/doc/index.rst b/boards/nxp/frdm_mcxw71/doc/index.rst index 0169c52eff72a..ad0802ecbb009 100644 --- a/boards/nxp/frdm_mcxw71/doc/index.rst +++ b/boards/nxp/frdm_mcxw71/doc/index.rst @@ -70,6 +70,10 @@ The ``frdm_mcxw71`` board target in Zephyr currently supports the following feat +-----------+------------+-------------------------------------+ | LPADC | on-chip | adc | +-----------+------------+-------------------------------------+ +| ELE | on-chip | entropy | ++-----------+------------+-------------------------------------+ +| PHY | on-chip | ieee802154 | ++-----------+------------+-------------------------------------+ Fetch Binary Blobs ****************** @@ -130,8 +134,26 @@ Connect a USB cable from your PC to J10, and use the serial terminal of your cho - Parity: None - Stop bits: 1 -Flashing -======== +Application Building +==================== + +Openthread applications +----------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/net/sockets/echo_server + :board: frdm_mcxw71 + :goals: build + :west-args: -- -DEXTRA_CONF_FILE=overlay-ot.conf + +.. zephyr-app-commands:: + :zephyr-app: samples/net/sockets/echo_client + :board: frdm_mcxw71 + :goals: build + :west-args: -- -DEXTRA_CONF_FILE=overlay-ot.conf + +Application Flashing +==================== Here is an example for the :zephyr:code-sample:`hello_world` application. @@ -166,15 +188,17 @@ should see the following message in the terminal: *** Booting Zephyr OS build v3.7.0-xxx-xxxx *** Hello World! frdm_mcxw71/mcxw716c -Bluetooth -========= +NBU Flashing +============ BLE functionality requires to fetch binary blobs, so make sure to follow the ``Fetch Binary Blobs`` section first. Two images must be written to the board: one for the host (CM33) and one for the NBU (CM3). -- To flash the application (CM33) refer to the ``Flashing`` section above. -- To flash the NBU, follow the instructions below: + +- To flash the application (CM33) refer to the ``Application Flashing`` section above. + +- To flash the ``NBU Flashing``, follow the instructions below: * Install ``blhost`` from NXP's website. This is the tool that will allow you to flash the NBU. * Enter ISP mode. To boot the MCU in ISP mode, follow these steps: @@ -184,17 +208,39 @@ Two images must be written to the board: one for the host (CM33) and one for the - Reconnect any external power supply, if needed. * Use the following command to flash NBU file: -.. code-block:: console +.. tabs:: + + .. group-tab:: BLE NBU - Windows + + .. code-block:: console + :caption: Flash BLE only NBU on Windows + + blhost.exe -p COMxx -- receive-sb-file mcxw71_nbu_ble.sb3 + + .. group-tab:: BLE NBU - Linux + + .. code-block:: console + :caption: Flash BLE only NBU on Linux + + ./blhost -p /dev/ttyxx -- receive-sb-file mcxw71_nbu_ble.sb3 + + .. group-tab:: DYN NBU - Windows + + .. code-block:: console + :caption: Flash Dynamic NBU (BLE + 15.4) on Windows + + blhost.exe -p COMxx -- receive-sb-file mcxw71_nbu_ble_15_4_dyn.sb3 + + .. group-tab:: DYN NBU - Linux - # On Windows - blhost.exe -p COMxx -- receive-sb-file mcxw71_nbu_ble.sb3 + .. code-block:: console + :caption: Flash Dynamic NBU (BLE + 15.4) on Linux - # On Linux - ./blhost -p /dev/ttyxx -- receive-sb-file mcxw71_nbu_ble.sb3 + ./blhost -p /dev/ttyxx -- receive-sb-file mcxw71_nbu_ble_15_4_dyn.sb3 Please consider changing ``COMxx`` on Windows or ``ttyxx`` on Linux to the serial port used by your board. -The NBU file can be found in : ``/modules/hal/nxp/zephyr/blobs/mcxw71/mcxw71_nbu_ble.sb3`` +The NBU files can be found in : ``/modules/hal/nxp/zephyr/blobs/mcxw71/`` folder. For more details: From 827a725f9fffd2706be224bc3e7bc31e50d84c12 Mon Sep 17 00:00:00 2001 From: George Stefan Date: Thu, 13 Feb 2025 17:59:34 +0200 Subject: [PATCH 0127/6055] west.yml: update hal_nxp to support new features on MCXW71 - add MCXW71 NBU combo BLE LL and IEEE 802.15.4 PHY firmware blob - fix elemu driver: undef BIT if already defined - add mcux-secure-subsystem middleware - add ieee_802.15.4 middleware Signed-off-by: George Stefan --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index f446f270996fd..d6f104e3e320a 100644 --- a/west.yml +++ b/west.yml @@ -203,7 +203,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 5e1979c7dd94dc84a09f5deb1b59ab83c94d5e83 + revision: 605560a680318ec417c1ee38d05ac092c383dc1d path: modules/hal/nxp groups: - hal From 6d490e9cf0bdb1fb3aa0f4560c9156970be881d9 Mon Sep 17 00:00:00 2001 From: Utsav Munendra Date: Thu, 13 Feb 2025 10:33:21 +0530 Subject: [PATCH 0128/6055] portability: cmsis: Run clang-format on CMSIS-RTOSv2 clang-format -i subsys/portability/cmsis_rtos_v2/*.h clang-format -i subsys/portability/cmsis_rtos_v2/*.c Signed-off-by: Utsav Munendra --- .../portability/cmsis_rtos_v2/event_flags.c | 26 ++++----- subsys/portability/cmsis_rtos_v2/kernel.c | 7 ++- subsys/portability/cmsis_rtos_v2/mempool.c | 29 ++++------ subsys/portability/cmsis_rtos_v2/msgq.c | 26 ++++----- subsys/portability/cmsis_rtos_v2/mutex.c | 17 +++--- subsys/portability/cmsis_rtos_v2/semaphore.c | 23 ++++---- subsys/portability/cmsis_rtos_v2/thread.c | 53 +++++++------------ .../portability/cmsis_rtos_v2/thread_flags.c | 18 +++---- subsys/portability/cmsis_rtos_v2/timer.c | 17 +++--- subsys/portability/cmsis_rtos_v2/wrapper.h | 4 +- 10 files changed, 85 insertions(+), 135 deletions(-) diff --git a/subsys/portability/cmsis_rtos_v2/event_flags.c b/subsys/portability/cmsis_rtos_v2/event_flags.c index cd91c69a4a264..7718dcb55ae1e 100644 --- a/subsys/portability/cmsis_rtos_v2/event_flags.c +++ b/subsys/portability/cmsis_rtos_v2/event_flags.c @@ -18,7 +18,7 @@ static const osEventFlagsAttr_t init_event_flags_attrs = { .cb_size = 0, }; -#define DONT_CARE (0) +#define DONT_CARE (0) /** * @brief Create and Initialize an Event Flags object. @@ -35,21 +35,19 @@ osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr) attr = &init_event_flags_attrs; } - if (k_mem_slab_alloc(&cv2_event_flags_slab, (void **)&events, K_MSEC(100)) - == 0) { + if (k_mem_slab_alloc(&cv2_event_flags_slab, (void **)&events, K_MSEC(100)) == 0) { memset(events, 0, sizeof(struct cv2_event_flags)); } else { return NULL; } k_poll_signal_init(&events->poll_signal); - k_poll_event_init(&events->poll_event, K_POLL_TYPE_SIGNAL, - K_POLL_MODE_NOTIFY_ONLY, &events->poll_signal); + k_poll_event_init(&events->poll_event, K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, + &events->poll_signal); events->signal_results = 0U; if (attr->name == NULL) { - strncpy(events->name, init_event_flags_attrs.name, - sizeof(events->name) - 1); + strncpy(events->name, init_event_flags_attrs.name, sizeof(events->name) - 1); } else { strncpy(events->name, attr->name, sizeof(events->name) - 1); } @@ -102,8 +100,8 @@ uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) /** * @brief Wait for one or more Event Flags to become signaled. */ -uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, - uint32_t options, uint32_t timeout) +uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, + uint32_t timeout) { struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; int retval, key; @@ -173,12 +171,11 @@ uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, * adjust the timeout value accordingly based on * the time that has already elapsed. */ - ticks_elapsed = - (uint64_t)k_uptime_ticks() - time_stamp_start; + ticks_elapsed = (uint64_t)k_uptime_ticks() - time_stamp_start; if (ticks_elapsed < (uint64_t)timeout) { - poll_timeout = Z_TIMEOUT_TICKS((k_ticks_t)( - timeout - (uint32_t)ticks_elapsed)); + poll_timeout = Z_TIMEOUT_TICKS( + (k_ticks_t)(timeout - (uint32_t)ticks_elapsed)); } else { return osFlagsErrorTimeout; } @@ -198,8 +195,7 @@ uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, */ __ASSERT(events->poll_event.state == K_POLL_STATE_SIGNALED, "event state not signalled!"); - __ASSERT(events->poll_event.signal->signaled == 1U, - "event signaled is not 1"); + __ASSERT(events->poll_event.signal->signaled == 1U, "event signaled is not 1"); } return sig; diff --git a/subsys/portability/cmsis_rtos_v2/kernel.c b/subsys/portability/cmsis_rtos_v2/kernel.c index 519be96023ddb..4b647866fe9f2 100644 --- a/subsys/portability/cmsis_rtos_v2/kernel.c +++ b/subsys/portability/cmsis_rtos_v2/kernel.c @@ -24,8 +24,7 @@ osStatus_t osKernelGetInfo(osVersion_t *version, char *id_buf, uint32_t id_size) } if ((id_buf != NULL) && (version != NULL)) { - snprintf(id_buf, id_size, - "Zephyr V%2"PRIu32".%2"PRIu32".%2"PRIu32, + snprintf(id_buf, id_size, "Zephyr V%2" PRIu32 ".%2" PRIu32 ".%2" PRIu32, SYS_KERNEL_VER_MAJOR(version->kernel), SYS_KERNEL_VER_MINOR(version->kernel), SYS_KERNEL_VER_PATCHLEVEL(version->kernel)); @@ -78,9 +77,9 @@ int32_t osKernelRestoreLock(int32_t lock) } if (lock < 0) { - return 1; /* locked */ + return 1; /* locked */ } else { - return 0; /* not locked */ + return 0; /* not locked */ } } diff --git a/subsys/portability/cmsis_rtos_v2/mempool.c b/subsys/portability/cmsis_rtos_v2/mempool.c index a5a0891975376..9af6a024a1768 100644 --- a/subsys/portability/cmsis_rtos_v2/mempool.c +++ b/subsys/portability/cmsis_rtos_v2/mempool.c @@ -8,10 +8,9 @@ #include #include "wrapper.h" -#define TIME_OUT_TICKS 10 +#define TIME_OUT_TICKS 10 -K_MEM_SLAB_DEFINE(cv2_mem_slab, sizeof(struct cv2_mslab), - CONFIG_CMSIS_V2_MEM_SLAB_MAX_COUNT, 4); +K_MEM_SLAB_DEFINE(cv2_mem_slab, sizeof(struct cv2_mslab), CONFIG_CMSIS_V2_MEM_SLAB_MAX_COUNT, 4); static const osMemoryPoolAttr_t init_mslab_attrs = { .name = "ZephyrMemPool", @@ -30,8 +29,7 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, { struct cv2_mslab *mslab; - BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= - CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE, + BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE, "heap must be configured to be at least the max dynamic size"); if (k_is_in_isr()) { @@ -53,8 +51,7 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, } if (attr->mp_mem == NULL) { - __ASSERT((block_count * block_size) <= - CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE, + __ASSERT((block_count * block_size) <= CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE, "memory slab/pool size exceeds dynamic maximum"); mslab->pool = k_calloc(block_count, block_size); @@ -79,8 +76,7 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, } if (attr->name == NULL) { - strncpy(mslab->name, init_mslab_attrs.name, - sizeof(mslab->name) - 1); + strncpy(mslab->name, init_mslab_attrs.name, sizeof(mslab->name) - 1); } else { strncpy(mslab->name, attr->name, sizeof(mslab->name) - 1); } @@ -107,17 +103,14 @@ void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout) } if (timeout == 0U) { - retval = k_mem_slab_alloc( - (struct k_mem_slab *)(&mslab->z_mslab), - (void **)&ptr, K_NO_WAIT); + retval = k_mem_slab_alloc((struct k_mem_slab *)(&mslab->z_mslab), (void **)&ptr, + K_NO_WAIT); } else if (timeout == osWaitForever) { - retval = k_mem_slab_alloc( - (struct k_mem_slab *)(&mslab->z_mslab), - (void **)&ptr, K_FOREVER); + retval = k_mem_slab_alloc((struct k_mem_slab *)(&mslab->z_mslab), (void **)&ptr, + K_FOREVER); } else { - retval = k_mem_slab_alloc( - (struct k_mem_slab *)(&mslab->z_mslab), - (void **)&ptr, K_TICKS(timeout)); + retval = k_mem_slab_alloc((struct k_mem_slab *)(&mslab->z_mslab), (void **)&ptr, + K_TICKS(timeout)); } if (retval == 0) { diff --git a/subsys/portability/cmsis_rtos_v2/msgq.c b/subsys/portability/cmsis_rtos_v2/msgq.c index af8c910c189b6..d603de6dee6ad 100644 --- a/subsys/portability/cmsis_rtos_v2/msgq.c +++ b/subsys/portability/cmsis_rtos_v2/msgq.c @@ -8,8 +8,7 @@ #include #include "wrapper.h" -K_MEM_SLAB_DEFINE(cv2_msgq_slab, sizeof(struct cv2_msgq), - CONFIG_CMSIS_V2_MSGQ_MAX_COUNT, 4); +K_MEM_SLAB_DEFINE(cv2_msgq_slab, sizeof(struct cv2_msgq), CONFIG_CMSIS_V2_MSGQ_MAX_COUNT, 4); static const osMessageQueueAttr_t init_msgq_attrs = { .name = "ZephyrMsgQ", @@ -28,8 +27,7 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, { struct cv2_msgq *msgq; - BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= - CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE, + BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE, "heap must be configured to be at least the max dynamic size"); if (k_is_in_isr()) { @@ -51,8 +49,7 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, } if (attr->mq_mem == NULL) { - __ASSERT((msg_count * msg_size) <= - CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE, + __ASSERT((msg_count * msg_size) <= CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE, "message queue size exceeds dynamic maximum"); #if (K_HEAP_MEM_POOL_SIZE > 0) @@ -74,8 +71,7 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, k_msgq_init(&msgq->z_msgq, msgq->pool, msg_size, msg_count); if (attr->name == NULL) { - strncpy(msgq->name, init_msgq_attrs.name, - sizeof(msgq->name) - 1); + strncpy(msgq->name, init_msgq_attrs.name, sizeof(msgq->name) - 1); } else { strncpy(msgq->name, attr->name, sizeof(msgq->name) - 1); } @@ -86,8 +82,8 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, /** * @brief Put a message to a Queue. */ -osStatus_t osMessageQueuePut(osMessageQueueId_t msgq_id, const void *msg_ptr, - uint8_t msg_prio, uint32_t timeout) +osStatus_t osMessageQueuePut(osMessageQueueId_t msgq_id, const void *msg_ptr, uint8_t msg_prio, + uint32_t timeout) { struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; int retval; @@ -108,8 +104,7 @@ osStatus_t osMessageQueuePut(osMessageQueueId_t msgq_id, const void *msg_ptr, } else if (timeout == osWaitForever) { retval = k_msgq_put(&msgq->z_msgq, (void *)msg_ptr, K_FOREVER); } else { - retval = k_msgq_put(&msgq->z_msgq, (void *)msg_ptr, - K_TICKS(timeout)); + retval = k_msgq_put(&msgq->z_msgq, (void *)msg_ptr, K_TICKS(timeout)); } if (retval == 0) { @@ -124,8 +119,8 @@ osStatus_t osMessageQueuePut(osMessageQueueId_t msgq_id, const void *msg_ptr, /** * @brief Get a message or Wait for a Message from a Queue. */ -osStatus_t osMessageQueueGet(osMessageQueueId_t msgq_id, void *msg_ptr, - uint8_t *msg_prio, uint32_t timeout) +osStatus_t osMessageQueueGet(osMessageQueueId_t msgq_id, void *msg_ptr, uint8_t *msg_prio, + uint32_t timeout) { struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; int retval; @@ -146,8 +141,7 @@ osStatus_t osMessageQueueGet(osMessageQueueId_t msgq_id, void *msg_ptr, } else if (timeout == osWaitForever) { retval = k_msgq_get(&msgq->z_msgq, msg_ptr, K_FOREVER); } else { - retval = k_msgq_get(&msgq->z_msgq, msg_ptr, - K_TICKS(timeout)); + retval = k_msgq_get(&msgq->z_msgq, msg_ptr, K_TICKS(timeout)); } if (retval == 0) { diff --git a/subsys/portability/cmsis_rtos_v2/mutex.c b/subsys/portability/cmsis_rtos_v2/mutex.c index d942f20e1bd58..74c314a77ae52 100644 --- a/subsys/portability/cmsis_rtos_v2/mutex.c +++ b/subsys/portability/cmsis_rtos_v2/mutex.c @@ -8,8 +8,7 @@ #include #include "wrapper.h" -K_MEM_SLAB_DEFINE(cv2_mutex_slab, sizeof(struct cv2_mutex), - CONFIG_CMSIS_V2_MUTEX_MAX_COUNT, 4); +K_MEM_SLAB_DEFINE(cv2_mutex_slab, sizeof(struct cv2_mutex), CONFIG_CMSIS_V2_MUTEX_MAX_COUNT, 4); static const osMutexAttr_t init_mutex_attrs = { .name = "ZephyrMutex", @@ -36,8 +35,7 @@ osMutexId_t osMutexNew(const osMutexAttr_t *attr) __ASSERT(attr->attr_bits & osMutexPrioInherit, "Zephyr supports osMutexPrioInherit by default. Do not unselect it\n"); - __ASSERT(!(attr->attr_bits & osMutexRobust), - "Zephyr does not support osMutexRobust.\n"); + __ASSERT(!(attr->attr_bits & osMutexRobust), "Zephyr does not support osMutexRobust.\n"); if (k_mem_slab_alloc(&cv2_mutex_slab, (void **)&mutex, K_MSEC(100)) == 0) { memset(mutex, 0, sizeof(struct cv2_mutex)); @@ -49,8 +47,7 @@ osMutexId_t osMutexNew(const osMutexAttr_t *attr) mutex->state = attr->attr_bits; if (attr->name == NULL) { - strncpy(mutex->name, init_mutex_attrs.name, - sizeof(mutex->name) - 1); + strncpy(mutex->name, init_mutex_attrs.name, sizeof(mutex->name) - 1); } else { strncpy(mutex->name, attr->name, sizeof(mutex->name) - 1); } @@ -63,7 +60,7 @@ osMutexId_t osMutexNew(const osMutexAttr_t *attr) */ osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout) { - struct cv2_mutex *mutex = (struct cv2_mutex *) mutex_id; + struct cv2_mutex *mutex = (struct cv2_mutex *)mutex_id; int status; if (mutex_id == NULL) { @@ -79,8 +76,7 @@ osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout) } else if (timeout == 0U) { status = k_mutex_lock(&mutex->z_mutex, K_NO_WAIT); } else { - status = k_mutex_lock(&mutex->z_mutex, - K_TICKS(timeout)); + status = k_mutex_lock(&mutex->z_mutex, K_TICKS(timeout)); } if (timeout != 0 && (status == -EAGAIN || status == -EBUSY)) { @@ -97,7 +93,7 @@ osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout) */ osStatus_t osMutexRelease(osMutexId_t mutex_id) { - struct cv2_mutex *mutex = (struct cv2_mutex *) mutex_id; + struct cv2_mutex *mutex = (struct cv2_mutex *)mutex_id; if (mutex_id == NULL) { return osErrorParameter; @@ -138,7 +134,6 @@ osStatus_t osMutexDelete(osMutexId_t mutex_id) return osOK; } - osThreadId_t osMutexGetOwner(osMutexId_t mutex_id) { struct cv2_mutex *mutex = (struct cv2_mutex *)mutex_id; diff --git a/subsys/portability/cmsis_rtos_v2/semaphore.c b/subsys/portability/cmsis_rtos_v2/semaphore.c index 6a006d1259b86..9d52fdda08679 100644 --- a/subsys/portability/cmsis_rtos_v2/semaphore.c +++ b/subsys/portability/cmsis_rtos_v2/semaphore.c @@ -8,8 +8,8 @@ #include #include "wrapper.h" -K_MEM_SLAB_DEFINE(cv2_semaphore_slab, sizeof(struct cv2_sem), - CONFIG_CMSIS_V2_SEMAPHORE_MAX_COUNT, 4); +K_MEM_SLAB_DEFINE(cv2_semaphore_slab, sizeof(struct cv2_sem), CONFIG_CMSIS_V2_SEMAPHORE_MAX_COUNT, + 4); static const osSemaphoreAttr_t init_sema_attrs = { .name = "ZephyrSem", @@ -34,8 +34,7 @@ osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, attr = &init_sema_attrs; } - if (k_mem_slab_alloc(&cv2_semaphore_slab, - (void **)&semaphore, K_MSEC(100)) == 0) { + if (k_mem_slab_alloc(&cv2_semaphore_slab, (void **)&semaphore, K_MSEC(100)) == 0) { (void)memset(semaphore, 0, sizeof(struct cv2_sem)); } else { return NULL; @@ -44,11 +43,9 @@ osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, k_sem_init(&semaphore->z_semaphore, initial_count, max_count); if (attr->name == NULL) { - strncpy(semaphore->name, init_sema_attrs.name, - sizeof(semaphore->name) - 1); + strncpy(semaphore->name, init_sema_attrs.name, sizeof(semaphore->name) - 1); } else { - strncpy(semaphore->name, attr->name, - sizeof(semaphore->name) - 1); + strncpy(semaphore->name, attr->name, sizeof(semaphore->name) - 1); } return (osSemaphoreId_t)semaphore; @@ -59,7 +56,7 @@ osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, */ osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout) { - struct cv2_sem *semaphore = (struct cv2_sem *) semaphore_id; + struct cv2_sem *semaphore = (struct cv2_sem *)semaphore_id; int status; if (semaphore_id == NULL) { @@ -76,8 +73,7 @@ osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout) } else if (timeout == 0U) { status = k_sem_take(&semaphore->z_semaphore, K_NO_WAIT); } else { - status = k_sem_take(&semaphore->z_semaphore, - K_TICKS(timeout)); + status = k_sem_take(&semaphore->z_semaphore, K_TICKS(timeout)); } if (status == -EBUSY) { @@ -105,15 +101,14 @@ uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id) */ osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id) { - struct cv2_sem *semaphore = (struct cv2_sem *) semaphore_id; + struct cv2_sem *semaphore = (struct cv2_sem *)semaphore_id; if (semaphore_id == NULL) { return osErrorParameter; } /* All tokens have already been released */ - if (k_sem_count_get(&semaphore->z_semaphore) == - semaphore->z_semaphore.limit) { + if (k_sem_count_get(&semaphore->z_semaphore) == semaphore->z_semaphore.limit) { return osErrorResource; } diff --git a/subsys/portability/cmsis_rtos_v2/thread.c b/subsys/portability/cmsis_rtos_v2/thread.c index 9cbc702b5fc0f..7e650e36a890a 100644 --- a/subsys/portability/cmsis_rtos_v2/thread.c +++ b/subsys/portability/cmsis_rtos_v2/thread.c @@ -30,8 +30,7 @@ static atomic_t thread_num; static atomic_t thread_num_dynamic; #if CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT != 0 -static K_THREAD_STACK_ARRAY_DEFINE(cv2_thread_stack_pool, \ - CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT, \ +static K_THREAD_STACK_ARRAY_DEFINE(cv2_thread_stack_pool, CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT, CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE); #endif @@ -55,7 +54,7 @@ static inline uint32_t cmsis_to_zephyr_priority(uint32_t c_prio) static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) { struct cv2_thread *tid = arg2; - void * (*fun_ptr)(void *) = arg3; + void *(*fun_ptr)(void *) = arg3; fun_ptr(arg1); @@ -100,8 +99,7 @@ osThreadId_t get_cmsis_thread_id(k_tid_t tid) /** * @brief Create a thread and add it to Active Threads. */ -osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, - const osThreadAttr_t *attr) +osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, const osThreadAttr_t *attr) { int32_t prio; osPriority_t cv2_prio; @@ -129,27 +127,24 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, cv2_prio = attr->priority; } - if ((attr->stack_mem == NULL) && (thread_num_dynamic >= - CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT)) { + if ((attr->stack_mem == NULL) && + (thread_num_dynamic >= CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT)) { return NULL; } BUILD_ASSERT(osPriorityISR <= CONFIG_NUM_PREEMPT_PRIORITIES, "Configure NUM_PREEMPT_PRIORITIES to at least osPriorityISR"); - BUILD_ASSERT(CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT <= - CONFIG_CMSIS_V2_THREAD_MAX_COUNT, + BUILD_ASSERT(CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT <= CONFIG_CMSIS_V2_THREAD_MAX_COUNT, "Number of dynamic threads cannot exceed max number of threads."); BUILD_ASSERT(CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE <= - CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE, + CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE, "Default dynamic thread stack size cannot exceed max stack size"); - __ASSERT(attr->stack_size <= CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE, - "invalid stack size\n"); + __ASSERT(attr->stack_size <= CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE, "invalid stack size\n"); - __ASSERT((cv2_prio >= osPriorityIdle) && (cv2_prio <= osPriorityISR), - "invalid priority\n"); + __ASSERT((cv2_prio >= osPriorityIdle) && (cv2_prio <= osPriorityISR), "invalid priority\n"); if (attr->stack_mem != NULL) { if (attr->stack_size == 0) { @@ -169,8 +164,7 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, uint32_t this_thread_num_dynamic; __ASSERT(CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE > 0, "dynamic stack size must be configured to be non-zero\n"); - this_thread_num_dynamic = - atomic_inc((atomic_t *)&thread_num_dynamic); + this_thread_num_dynamic = atomic_inc((atomic_t *)&thread_num_dynamic); stack_size = CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE; stack = cv2_thread_stack_pool[this_thread_num_dynamic]; } else @@ -181,8 +175,8 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, } k_poll_signal_init(&tid->poll_signal); - k_poll_event_init(&tid->poll_event, K_POLL_TYPE_SIGNAL, - K_POLL_MODE_NOTIFY_ONLY, &tid->poll_signal); + k_poll_event_init(&tid->poll_event, K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, + &tid->poll_signal); tid->signal_results = 0U; /* TODO: Do this somewhere only once */ @@ -196,15 +190,11 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, k_sem_init(&tid->join_guard, 0, 1); tid->has_joined = FALSE; - (void)k_thread_create(&tid->z_thread, - stack, stack_size, - zephyr_thread_wrapper, - (void *)arg, tid, threadfunc, - prio, 0, K_NO_WAIT); + (void)k_thread_create(&tid->z_thread, stack, stack_size, zephyr_thread_wrapper, (void *)arg, + tid, threadfunc, prio, 0, K_NO_WAIT); if (attr->name == NULL) { - strncpy(tid->name, init_thread_attrs.name, - sizeof(tid->name) - 1); + strncpy(tid->name, init_thread_attrs.name, sizeof(tid->name) - 1); } else { strncpy(tid->name, attr->name, sizeof(tid->name) - 1); } @@ -227,8 +217,7 @@ const char *osThreadGetName(osThreadId_t thread_id) if (is_cmsis_rtos_v2_thread(thread_id) == NULL) { name = NULL; } else { - struct cv2_thread *tid = - (struct cv2_thread *)thread_id; + struct cv2_thread *tid = (struct cv2_thread *)thread_id; name = k_thread_name_get(&tid->z_thread); } @@ -255,8 +244,7 @@ osPriority_t osThreadGetPriority(osThreadId_t thread_id) struct cv2_thread *tid = (struct cv2_thread *)thread_id; uint32_t priority; - if (k_is_in_isr() || (tid == NULL) || - (is_cmsis_rtos_v2_thread(tid) == NULL) || + if (k_is_in_isr() || (tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL) || (_is_thread_cmsis_inactive(&tid->z_thread))) { return osPriorityError; } @@ -285,8 +273,7 @@ osStatus_t osThreadSetPriority(osThreadId_t thread_id, osPriority_t priority) return osErrorResource; } - k_thread_priority_set((k_tid_t)&tid->z_thread, - cmsis_to_zephyr_priority(priority)); + k_thread_priority_set((k_tid_t)&tid->z_thread, cmsis_to_zephyr_priority(priority)); return osOK; } @@ -299,8 +286,7 @@ osThreadState_t osThreadGetState(osThreadId_t thread_id) struct cv2_thread *tid = (struct cv2_thread *)thread_id; osThreadState_t state; - if (k_is_in_isr() || (tid == NULL) || - (is_cmsis_rtos_v2_thread(tid) == NULL)) { + if (k_is_in_isr() || (tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) { return osThreadError; } @@ -541,7 +527,6 @@ osStatus_t osThreadTerminate(osThreadId_t thread_id) return osOK; } - /** * @brief Get number of active threads. */ diff --git a/subsys/portability/cmsis_rtos_v2/thread_flags.c b/subsys/portability/cmsis_rtos_v2/thread_flags.c index 2ef8cea513c8c..abc4cdc22bccb 100644 --- a/subsys/portability/cmsis_rtos_v2/thread_flags.c +++ b/subsys/portability/cmsis_rtos_v2/thread_flags.c @@ -7,7 +7,7 @@ #include #include "wrapper.h" -#define DONT_CARE (0) +#define DONT_CARE (0) /** * @brief Set the specified Thread Flags of a thread. @@ -17,8 +17,8 @@ uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags) unsigned int key; struct cv2_thread *tid = (struct cv2_thread *)thread_id; - if ((thread_id == NULL) || (is_cmsis_rtos_v2_thread(thread_id) == NULL) - || (flags & 0x80000000)) { + if ((thread_id == NULL) || (is_cmsis_rtos_v2_thread(thread_id) == NULL) || + (flags & 0x80000000)) { return osFlagsErrorParameter; } @@ -116,8 +116,7 @@ uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout) retval = k_poll(&tid->poll_event, 1, K_FOREVER); break; default: - retval = k_poll(&tid->poll_event, 1, - K_MSEC(timeout_ms)); + retval = k_poll(&tid->poll_event, 1, K_MSEC(timeout_ms)); break; } @@ -132,8 +131,7 @@ uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout) __ASSERT(tid->poll_event.state == K_POLL_STATE_SIGNALED, "event state not signalled!"); - __ASSERT(tid->poll_event.signal->signaled == 1U, - "event signaled is not 1"); + __ASSERT(tid->poll_event.signal->signaled == 1U, "event signaled is not 1"); /* Reset the states to facilitate the next trigger */ tid->poll_event.signal->signaled = 0U; @@ -151,11 +149,9 @@ uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout) * adjust the timeout value accordingly based on * the time that has already elapsed. */ - hwclk_cycles_delta = - (uint64_t)k_cycle_get_32() - time_stamp_start; + hwclk_cycles_delta = (uint64_t)k_cycle_get_32() - time_stamp_start; - time_delta_ns = - (uint32_t)k_cyc_to_ns_floor64(hwclk_cycles_delta); + time_delta_ns = (uint32_t)k_cyc_to_ns_floor64(hwclk_cycles_delta); time_delta_ms = (uint32_t)time_delta_ns / NSEC_PER_MSEC; diff --git a/subsys/portability/cmsis_rtos_v2/timer.c b/subsys/portability/cmsis_rtos_v2/timer.c index abdb1e7bc6d96..a1a9aff30efd2 100644 --- a/subsys/portability/cmsis_rtos_v2/timer.c +++ b/subsys/portability/cmsis_rtos_v2/timer.c @@ -8,13 +8,12 @@ #include #include "wrapper.h" -#define ACTIVE 1 +#define ACTIVE 1 #define NOT_ACTIVE 0 static void zephyr_timer_wrapper(struct k_timer *timer); -K_MEM_SLAB_DEFINE(cv2_timer_slab, sizeof(struct cv2_timer), - CONFIG_CMSIS_V2_TIMER_MAX_COUNT, 4); +K_MEM_SLAB_DEFINE(cv2_timer_slab, sizeof(struct cv2_timer), CONFIG_CMSIS_V2_TIMER_MAX_COUNT, 4); static const osTimerAttr_t init_timer_attrs = { .name = "ZephyrTimer", @@ -34,8 +33,8 @@ static void zephyr_timer_wrapper(struct k_timer *timer) /** * @brief Create a Timer */ -osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, - void *argument, const osTimerAttr_t *attr) +osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, + const osTimerAttr_t *attr) { struct cv2_timer *timer; @@ -65,8 +64,7 @@ osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, k_timer_init(&timer->z_timer, zephyr_timer_wrapper, NULL); if (attr->name == NULL) { - strncpy(timer->name, init_timer_attrs.name, - sizeof(timer->name) - 1); + strncpy(timer->name, init_timer_attrs.name, sizeof(timer->name) - 1); } else { strncpy(timer->name, attr->name, sizeof(timer->name) - 1); } @@ -92,8 +90,7 @@ osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks) if (timer->type == osTimerOnce) { k_timer_start(&timer->z_timer, K_TICKS(ticks), K_NO_WAIT); } else if (timer->type == osTimerPeriodic) { - k_timer_start(&timer->z_timer, - K_TICKS(ticks), K_TICKS(ticks)); + k_timer_start(&timer->z_timer, K_TICKS(ticks), K_TICKS(ticks)); } timer->status = ACTIVE; @@ -129,7 +126,7 @@ osStatus_t osTimerStop(osTimerId_t timer_id) */ osStatus_t osTimerDelete(osTimerId_t timer_id) { - struct cv2_timer *timer = (struct cv2_timer *) timer_id; + struct cv2_timer *timer = (struct cv2_timer *)timer_id; if (timer == NULL) { return osErrorParameter; diff --git a/subsys/portability/cmsis_rtos_v2/wrapper.h b/subsys/portability/cmsis_rtos_v2/wrapper.h index 41e9e42f2431f..b599a59c67ead 100644 --- a/subsys/portability/cmsis_rtos_v2/wrapper.h +++ b/subsys/portability/cmsis_rtos_v2/wrapper.h @@ -11,10 +11,10 @@ #include #ifndef TRUE -#define TRUE 1 +#define TRUE 1 #endif #ifndef FALSE -#define FALSE 0 +#define FALSE 0 #endif struct cv2_thread { From 13ef44200e240ccd0a191b31e9be8db1a0ccbfb8 Mon Sep 17 00:00:00 2001 From: Utsav Munendra Date: Thu, 13 Feb 2025 10:46:38 +0530 Subject: [PATCH 0129/6055] portability: cmsis: Move cmsis wrapper types to public header This enables the cmsis wrapper types to be declared statically and then passed along to CMSIS-RTOSv2 APIs, enabling static allocation of RTOS control blocks in the subsequent commits. Signed-off-by: Utsav Munendra --- include/zephyr/portability/cmsis_types.h | 66 +++++++++++++++++++ .../portability/cmsis_rtos_v2/event_flags.c | 2 +- subsys/portability/cmsis_rtos_v2/kernel.c | 2 +- subsys/portability/cmsis_rtos_v2/mempool.c | 1 + subsys/portability/cmsis_rtos_v2/msgq.c | 1 + subsys/portability/cmsis_rtos_v2/mutex.c | 1 + subsys/portability/cmsis_rtos_v2/semaphore.c | 2 +- subsys/portability/cmsis_rtos_v2/thread.c | 1 + .../portability/cmsis_rtos_v2/thread_flags.c | 1 + subsys/portability/cmsis_rtos_v2/timer.c | 2 +- subsys/portability/cmsis_rtos_v2/wrapper.h | 56 +--------------- 11 files changed, 77 insertions(+), 58 deletions(-) create mode 100644 include/zephyr/portability/cmsis_types.h diff --git a/include/zephyr/portability/cmsis_types.h b/include/zephyr/portability/cmsis_types.h new file mode 100644 index 0000000000000..8fba9344ec4ae --- /dev/null +++ b/include/zephyr/portability/cmsis_types.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_CMSIS_TYPES_H_ +#define ZEPHYR_INCLUDE_CMSIS_TYPES_H_ + +#include +#include + +struct cv2_thread { + sys_dnode_t node; + struct k_thread z_thread; + struct k_poll_signal poll_signal; + struct k_poll_event poll_event; + uint32_t signal_results; + char name[16]; + uint32_t attr_bits; + struct k_sem join_guard; + char has_joined; +}; + +struct cv2_timer { + struct k_timer z_timer; + osTimerType_t type; + uint32_t status; + char name[16]; + void (*callback_function)(void *argument); + void *arg; +}; + +struct cv2_mutex { + struct k_mutex z_mutex; + char name[16]; + uint32_t state; +}; + +struct cv2_sem { + struct k_sem z_semaphore; + char name[16]; +}; + +struct cv2_mslab { + struct k_mem_slab z_mslab; + void *pool; + char is_dynamic_allocation; + char name[16]; +}; + +struct cv2_msgq { + struct k_msgq z_msgq; + void *pool; + char is_dynamic_allocation; + char name[16]; +}; + +struct cv2_event_flags { + struct k_poll_signal poll_signal; + struct k_poll_event poll_event; + uint32_t signal_results; + char name[16]; +}; + +#endif diff --git a/subsys/portability/cmsis_rtos_v2/event_flags.c b/subsys/portability/cmsis_rtos_v2/event_flags.c index 7718dcb55ae1e..829d5fd402d6e 100644 --- a/subsys/portability/cmsis_rtos_v2/event_flags.c +++ b/subsys/portability/cmsis_rtos_v2/event_flags.c @@ -5,8 +5,8 @@ */ #include +#include #include -#include "wrapper.h" K_MEM_SLAB_DEFINE(cv2_event_flags_slab, sizeof(struct cv2_event_flags), CONFIG_CMSIS_V2_EVT_FLAGS_MAX_COUNT, 4); diff --git a/subsys/portability/cmsis_rtos_v2/kernel.c b/subsys/portability/cmsis_rtos_v2/kernel.c index 4b647866fe9f2..9f19e89e69fc9 100644 --- a/subsys/portability/cmsis_rtos_v2/kernel.c +++ b/subsys/portability/cmsis_rtos_v2/kernel.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include extern uint32_t sys_clock_tick_get_32(void); diff --git a/subsys/portability/cmsis_rtos_v2/mempool.c b/subsys/portability/cmsis_rtos_v2/mempool.c index 9af6a024a1768..f7b2ca224510b 100644 --- a/subsys/portability/cmsis_rtos_v2/mempool.c +++ b/subsys/portability/cmsis_rtos_v2/mempool.c @@ -5,6 +5,7 @@ */ #include +#include #include #include "wrapper.h" diff --git a/subsys/portability/cmsis_rtos_v2/msgq.c b/subsys/portability/cmsis_rtos_v2/msgq.c index d603de6dee6ad..c4811a3e40dc3 100644 --- a/subsys/portability/cmsis_rtos_v2/msgq.c +++ b/subsys/portability/cmsis_rtos_v2/msgq.c @@ -5,6 +5,7 @@ */ #include +#include #include #include "wrapper.h" diff --git a/subsys/portability/cmsis_rtos_v2/mutex.c b/subsys/portability/cmsis_rtos_v2/mutex.c index 74c314a77ae52..1cdc00a04a697 100644 --- a/subsys/portability/cmsis_rtos_v2/mutex.c +++ b/subsys/portability/cmsis_rtos_v2/mutex.c @@ -5,6 +5,7 @@ */ #include +#include #include #include "wrapper.h" diff --git a/subsys/portability/cmsis_rtos_v2/semaphore.c b/subsys/portability/cmsis_rtos_v2/semaphore.c index 9d52fdda08679..7d37410cd1572 100644 --- a/subsys/portability/cmsis_rtos_v2/semaphore.c +++ b/subsys/portability/cmsis_rtos_v2/semaphore.c @@ -5,8 +5,8 @@ */ #include +#include #include -#include "wrapper.h" K_MEM_SLAB_DEFINE(cv2_semaphore_slab, sizeof(struct cv2_sem), CONFIG_CMSIS_V2_SEMAPHORE_MAX_COUNT, 4); diff --git a/subsys/portability/cmsis_rtos_v2/thread.c b/subsys/portability/cmsis_rtos_v2/thread.c index 7e650e36a890a..3f42658cbbcf4 100644 --- a/subsys/portability/cmsis_rtos_v2/thread.c +++ b/subsys/portability/cmsis_rtos_v2/thread.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "wrapper.h" static const osThreadAttr_t init_thread_attrs = { diff --git a/subsys/portability/cmsis_rtos_v2/thread_flags.c b/subsys/portability/cmsis_rtos_v2/thread_flags.c index abc4cdc22bccb..a573c59a4527d 100644 --- a/subsys/portability/cmsis_rtos_v2/thread_flags.c +++ b/subsys/portability/cmsis_rtos_v2/thread_flags.c @@ -5,6 +5,7 @@ */ #include +#include #include "wrapper.h" #define DONT_CARE (0) diff --git a/subsys/portability/cmsis_rtos_v2/timer.c b/subsys/portability/cmsis_rtos_v2/timer.c index a1a9aff30efd2..eeb155f933f49 100644 --- a/subsys/portability/cmsis_rtos_v2/timer.c +++ b/subsys/portability/cmsis_rtos_v2/timer.c @@ -5,8 +5,8 @@ */ #include +#include #include -#include "wrapper.h" #define ACTIVE 1 #define NOT_ACTIVE 0 diff --git a/subsys/portability/cmsis_rtos_v2/wrapper.h b/subsys/portability/cmsis_rtos_v2/wrapper.h index b599a59c67ead..0d3f6e33722fa 100644 --- a/subsys/portability/cmsis_rtos_v2/wrapper.h +++ b/subsys/portability/cmsis_rtos_v2/wrapper.h @@ -8,7 +8,8 @@ #define __WRAPPER_H__ #include -#include +#include +#include #ifndef TRUE #define TRUE 1 @@ -17,59 +18,6 @@ #define FALSE 0 #endif -struct cv2_thread { - sys_dnode_t node; - struct k_thread z_thread; - struct k_poll_signal poll_signal; - struct k_poll_event poll_event; - uint32_t signal_results; - char name[16]; - uint32_t attr_bits; - struct k_sem join_guard; - char has_joined; -}; - -struct cv2_timer { - struct k_timer z_timer; - osTimerType_t type; - uint32_t status; - char name[16]; - void (*callback_function)(void *argument); - void *arg; -}; - -struct cv2_mutex { - struct k_mutex z_mutex; - char name[16]; - uint32_t state; -}; - -struct cv2_sem { - struct k_sem z_semaphore; - char name[16]; -}; - -struct cv2_mslab { - struct k_mem_slab z_mslab; - void *pool; - char is_dynamic_allocation; - char name[16]; -}; - -struct cv2_msgq { - struct k_msgq z_msgq; - void *pool; - char is_dynamic_allocation; - char name[16]; -}; - -struct cv2_event_flags { - struct k_poll_signal poll_signal; - struct k_poll_event poll_event; - uint32_t signal_results; - char name[16]; -}; - extern osThreadId_t get_cmsis_thread_id(k_tid_t tid); extern void *is_cmsis_rtos_v2_thread(void *thread_id); From 11eb0ce4db41573473cd888e530681394162681e Mon Sep 17 00:00:00 2001 From: Utsav Munendra Date: Thu, 13 Feb 2025 10:55:58 +0530 Subject: [PATCH 0130/6055] portability: cmsis: Rename cmsis wrapper types Namespace this types with `cmsis_rtos` instead of `cv2` Signed-off-by: Utsav Munendra --- include/zephyr/portability/cmsis_types.h | 73 +++++++++++++++---- .../portability/cmsis_rtos_v2/event_flags.c | 22 +++--- subsys/portability/cmsis_rtos_v2/mempool.c | 23 +++--- subsys/portability/cmsis_rtos_v2/msgq.c | 33 +++++---- subsys/portability/cmsis_rtos_v2/mutex.c | 21 +++--- subsys/portability/cmsis_rtos_v2/semaphore.c | 23 +++--- subsys/portability/cmsis_rtos_v2/thread.c | 45 ++++++------ .../portability/cmsis_rtos_v2/thread_flags.c | 14 ++-- subsys/portability/cmsis_rtos_v2/timer.c | 25 ++++--- 9 files changed, 165 insertions(+), 114 deletions(-) diff --git a/include/zephyr/portability/cmsis_types.h b/include/zephyr/portability/cmsis_types.h index 8fba9344ec4ae..1f4f28081002c 100644 --- a/include/zephyr/portability/cmsis_types.h +++ b/include/zephyr/portability/cmsis_types.h @@ -10,57 +10,102 @@ #include #include -struct cv2_thread { +/** @brief Size for names of RTOS objects. */ +#define CMSIS_OBJ_NAME_MAX_LEN 16 + +/** + * @brief Control block for a CMSIS-RTOSv2 thread. + * + * Application can use manual user-defined allocation for RTOS objects by supplying a pointer to + * thread control block. Control block is initiazed within `osThreadNew()`. + */ +struct cmsis_rtos_thread_cb { sys_dnode_t node; struct k_thread z_thread; struct k_poll_signal poll_signal; struct k_poll_event poll_event; uint32_t signal_results; - char name[16]; + char name[CMSIS_OBJ_NAME_MAX_LEN]; uint32_t attr_bits; struct k_sem join_guard; char has_joined; }; -struct cv2_timer { +/** + * @brief Control block for a CMSIS-RTOSv2 timer. + * + * Application can use manual user-defined allocation for RTOS objects by supplying a pointer to + * timer control block. Control block is initiazed within `osTimerNew()`. + */ +struct cmsis_rtos_timer_cb { struct k_timer z_timer; osTimerType_t type; uint32_t status; - char name[16]; + char name[CMSIS_OBJ_NAME_MAX_LEN]; void (*callback_function)(void *argument); void *arg; }; -struct cv2_mutex { +/** + * @brief Control block for a CMSIS-RTOSv2 mutex. + * + * Application can use manual user-defined allocation for RTOS objects by supplying a pointer to + * mutex control block. Control block is initiazed within `osMutexNew()`. + */ +struct cmsis_rtos_mutex_cb { struct k_mutex z_mutex; - char name[16]; + char name[CMSIS_OBJ_NAME_MAX_LEN]; uint32_t state; }; -struct cv2_sem { +/** + * @brief Control block for a CMSIS-RTOSv2 semaphore. + * + * Application can use manual user-defined allocation for RTOS objects by supplying a pointer to + * semaphore control block. Control block is initiazed within `osSemaphoreNew()`. + */ +struct cmsis_rtos_semaphore_cb { struct k_sem z_semaphore; - char name[16]; + char name[CMSIS_OBJ_NAME_MAX_LEN]; }; -struct cv2_mslab { +/** + * @brief Control block for a CMSIS-RTOSv2 memory pool. + * + * Application can use manual user-defined allocation for RTOS objects by supplying a pointer to + * memory pool control block. Control block is initiazed within `osMemoryPoolNew()`. + */ +struct cmsis_rtos_mempool_cb { struct k_mem_slab z_mslab; void *pool; char is_dynamic_allocation; - char name[16]; + char name[CMSIS_OBJ_NAME_MAX_LEN]; }; -struct cv2_msgq { +/** + * @brief Control block for a CMSIS-RTOSv2 message queue. + * + * Application can use manual user-defined allocation for RTOS objects by supplying a pointer to + * message queue control block. Control block is initiazed within `osMessageQueueNew()`. + */ +struct cmsis_rtos_msgq_cb { struct k_msgq z_msgq; void *pool; char is_dynamic_allocation; - char name[16]; + char name[CMSIS_OBJ_NAME_MAX_LEN]; }; -struct cv2_event_flags { +/** + * @brief Control block for a CMSIS-RTOSv2 event flag. + * + * Application can use manual user-defined allocation for RTOS objects by supplying a pointer to + * event flag control block. Control block is initiazed within `osEventFlagsNew()`. + */ +struct cmsis_rtos_event_cb { struct k_poll_signal poll_signal; struct k_poll_event poll_event; uint32_t signal_results; - char name[16]; + char name[CMSIS_OBJ_NAME_MAX_LEN]; }; #endif diff --git a/subsys/portability/cmsis_rtos_v2/event_flags.c b/subsys/portability/cmsis_rtos_v2/event_flags.c index 829d5fd402d6e..d2c563b79c0a8 100644 --- a/subsys/portability/cmsis_rtos_v2/event_flags.c +++ b/subsys/portability/cmsis_rtos_v2/event_flags.c @@ -8,7 +8,7 @@ #include #include -K_MEM_SLAB_DEFINE(cv2_event_flags_slab, sizeof(struct cv2_event_flags), +K_MEM_SLAB_DEFINE(cmsis_rtos_event_cb_slab, sizeof(struct cmsis_rtos_event_cb), CONFIG_CMSIS_V2_EVT_FLAGS_MAX_COUNT, 4); static const osEventFlagsAttr_t init_event_flags_attrs = { @@ -25,7 +25,7 @@ static const osEventFlagsAttr_t init_event_flags_attrs = { */ osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr) { - struct cv2_event_flags *events; + struct cmsis_rtos_event_cb *events; if (k_is_in_isr()) { return NULL; @@ -35,8 +35,8 @@ osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr) attr = &init_event_flags_attrs; } - if (k_mem_slab_alloc(&cv2_event_flags_slab, (void **)&events, K_MSEC(100)) == 0) { - memset(events, 0, sizeof(struct cv2_event_flags)); + if (k_mem_slab_alloc(&cmsis_rtos_event_cb_slab, (void **)&events, K_MSEC(100)) == 0) { + memset(events, 0, sizeof(struct cmsis_rtos_event_cb)); } else { return NULL; } @@ -60,7 +60,7 @@ osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr) */ uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) { - struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id; unsigned int key; if ((ef_id == NULL) || (flags & osFlagsError)) { @@ -81,7 +81,7 @@ uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) */ uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) { - struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id; unsigned int key; uint32_t sig; @@ -103,7 +103,7 @@ uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) { - struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id; int retval, key; uint32_t sig; k_timeout_t poll_timeout; @@ -206,7 +206,7 @@ uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t optio */ const char *osEventFlagsGetName(osEventFlagsId_t ef_id) { - struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id; if (!k_is_in_isr() && (ef_id != NULL)) { return events->name; @@ -220,7 +220,7 @@ const char *osEventFlagsGetName(osEventFlagsId_t ef_id) */ uint32_t osEventFlagsGet(osEventFlagsId_t ef_id) { - struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id; if (ef_id == NULL) { return 0; @@ -234,7 +234,7 @@ uint32_t osEventFlagsGet(osEventFlagsId_t ef_id) */ osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) { - struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + struct cmsis_rtos_event_cb *events = (struct cmsis_rtos_event_cb *)ef_id; if (ef_id == NULL) { return osErrorResource; @@ -248,7 +248,7 @@ osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) * ef_id is incorrect) is not supported in Zephyr. */ - k_mem_slab_free(&cv2_event_flags_slab, (void *)events); + k_mem_slab_free(&cmsis_rtos_event_cb_slab, (void *)events); return osOK; } diff --git a/subsys/portability/cmsis_rtos_v2/mempool.c b/subsys/portability/cmsis_rtos_v2/mempool.c index f7b2ca224510b..90a8f329bb668 100644 --- a/subsys/portability/cmsis_rtos_v2/mempool.c +++ b/subsys/portability/cmsis_rtos_v2/mempool.c @@ -11,7 +11,8 @@ #define TIME_OUT_TICKS 10 -K_MEM_SLAB_DEFINE(cv2_mem_slab, sizeof(struct cv2_mslab), CONFIG_CMSIS_V2_MEM_SLAB_MAX_COUNT, 4); +K_MEM_SLAB_DEFINE(cv2_mem_slab, sizeof(struct cmsis_rtos_mempool_cb), + CONFIG_CMSIS_V2_MEM_SLAB_MAX_COUNT, 4); static const osMemoryPoolAttr_t init_mslab_attrs = { .name = "ZephyrMemPool", @@ -28,7 +29,7 @@ static const osMemoryPoolAttr_t init_mslab_attrs = { osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) { - struct cv2_mslab *mslab; + struct cmsis_rtos_mempool_cb *mslab; BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE, "heap must be configured to be at least the max dynamic size"); @@ -46,7 +47,7 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, } if (k_mem_slab_alloc(&cv2_mem_slab, (void **)&mslab, K_MSEC(100)) == 0) { - (void)memset(mslab, 0, sizeof(struct cv2_mslab)); + (void)memset(mslab, 0, sizeof(struct cmsis_rtos_mempool_cb)); } else { return NULL; } @@ -90,7 +91,7 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, */ void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout) { - struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id; + struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id; int retval; void *ptr; @@ -126,7 +127,7 @@ void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout) */ osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block) { - struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id; + struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id; if (mslab == NULL) { return osErrorParameter; @@ -147,7 +148,7 @@ osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block) */ const char *osMemoryPoolGetName(osMemoryPoolId_t mp_id) { - struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id; + struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id; if (!k_is_in_isr() && (mslab != NULL)) { return mslab->name; @@ -161,7 +162,7 @@ const char *osMemoryPoolGetName(osMemoryPoolId_t mp_id) */ uint32_t osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id) { - struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id; + struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id; if (mslab == NULL) { return 0; @@ -175,7 +176,7 @@ uint32_t osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id) */ uint32_t osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id) { - struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id; + struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id; if (mslab == NULL) { return 0; @@ -189,7 +190,7 @@ uint32_t osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id) */ uint32_t osMemoryPoolGetCount(osMemoryPoolId_t mp_id) { - struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id; + struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id; if (mslab == NULL) { return 0; @@ -203,7 +204,7 @@ uint32_t osMemoryPoolGetCount(osMemoryPoolId_t mp_id) */ uint32_t osMemoryPoolGetSpace(osMemoryPoolId_t mp_id) { - struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id; + struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id; if (mslab == NULL) { return 0; @@ -217,7 +218,7 @@ uint32_t osMemoryPoolGetSpace(osMemoryPoolId_t mp_id) */ osStatus_t osMemoryPoolDelete(osMemoryPoolId_t mp_id) { - struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id; + struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id; if (mslab == NULL) { return osErrorParameter; diff --git a/subsys/portability/cmsis_rtos_v2/msgq.c b/subsys/portability/cmsis_rtos_v2/msgq.c index c4811a3e40dc3..5d8d12de38976 100644 --- a/subsys/portability/cmsis_rtos_v2/msgq.c +++ b/subsys/portability/cmsis_rtos_v2/msgq.c @@ -9,7 +9,8 @@ #include #include "wrapper.h" -K_MEM_SLAB_DEFINE(cv2_msgq_slab, sizeof(struct cv2_msgq), CONFIG_CMSIS_V2_MSGQ_MAX_COUNT, 4); +K_MEM_SLAB_DEFINE(cmsis_rtos_msgq_cb_slab, sizeof(struct cmsis_rtos_msgq_cb), + CONFIG_CMSIS_V2_MSGQ_MAX_COUNT, 4); static const osMessageQueueAttr_t init_msgq_attrs = { .name = "ZephyrMsgQ", @@ -26,7 +27,7 @@ static const osMessageQueueAttr_t init_msgq_attrs = { osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) { - struct cv2_msgq *msgq; + struct cmsis_rtos_msgq_cb *msgq; BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE, "heap must be configured to be at least the max dynamic size"); @@ -43,8 +44,8 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, attr = &init_msgq_attrs; } - if (k_mem_slab_alloc(&cv2_msgq_slab, (void **)&msgq, K_MSEC(100)) == 0) { - (void)memset(msgq, 0, sizeof(struct cv2_msgq)); + if (k_mem_slab_alloc(&cmsis_rtos_msgq_cb_slab, (void **)&msgq, K_MSEC(100)) == 0) { + (void)memset(msgq, 0, sizeof(struct cmsis_rtos_msgq_cb)); } else { return NULL; } @@ -56,12 +57,12 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, #if (K_HEAP_MEM_POOL_SIZE > 0) msgq->pool = k_calloc(msg_count, msg_size); if (msgq->pool == NULL) { - k_mem_slab_free(&cv2_msgq_slab, (void *)msgq); + k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq); return NULL; } msgq->is_dynamic_allocation = TRUE; #else - k_mem_slab_free(&cv2_msgq_slab, (void *)msgq); + k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq); return NULL; #endif } else { @@ -86,7 +87,7 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, osStatus_t osMessageQueuePut(osMessageQueueId_t msgq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) { - struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; + struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id; int retval; ARG_UNUSED(msg_prio); @@ -123,7 +124,7 @@ osStatus_t osMessageQueuePut(osMessageQueueId_t msgq_id, const void *msg_ptr, ui osStatus_t osMessageQueueGet(osMessageQueueId_t msgq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) { - struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; + struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id; int retval; ARG_UNUSED(msg_prio); @@ -161,7 +162,7 @@ osStatus_t osMessageQueueGet(osMessageQueueId_t msgq_id, void *msg_ptr, uint8_t */ uint32_t osMessageQueueGetCapacity(osMessageQueueId_t msgq_id) { - struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; + struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id; if (msgq == NULL) { return 0; @@ -175,7 +176,7 @@ uint32_t osMessageQueueGetCapacity(osMessageQueueId_t msgq_id) */ uint32_t osMessageQueueGetMsgSize(osMessageQueueId_t msgq_id) { - struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; + struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id; if (msgq == NULL) { return 0; @@ -189,7 +190,7 @@ uint32_t osMessageQueueGetMsgSize(osMessageQueueId_t msgq_id) */ uint32_t osMessageQueueGetCount(osMessageQueueId_t msgq_id) { - struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; + struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id; if (msgq == NULL) { return 0; @@ -203,7 +204,7 @@ uint32_t osMessageQueueGetCount(osMessageQueueId_t msgq_id) */ uint32_t osMessageQueueGetSpace(osMessageQueueId_t msgq_id) { - struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; + struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id; if (msgq == NULL) { return 0; @@ -217,7 +218,7 @@ uint32_t osMessageQueueGetSpace(osMessageQueueId_t msgq_id) */ const char *osMessageQueueGetName(osMessageQueueId_t msgq_id) { - struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; + struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id; if (!k_is_in_isr() && (msgq_id != NULL)) { return msgq->name; @@ -231,7 +232,7 @@ const char *osMessageQueueGetName(osMessageQueueId_t msgq_id) */ osStatus_t osMessageQueueReset(osMessageQueueId_t msgq_id) { - struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; + struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id; if (msgq == NULL) { return osErrorParameter; @@ -256,7 +257,7 @@ osStatus_t osMessageQueueReset(osMessageQueueId_t msgq_id) */ osStatus_t osMessageQueueDelete(osMessageQueueId_t msgq_id) { - struct cv2_msgq *msgq = (struct cv2_msgq *)msgq_id; + struct cmsis_rtos_msgq_cb *msgq = (struct cmsis_rtos_msgq_cb *)msgq_id; if (msgq == NULL) { return osErrorParameter; @@ -274,7 +275,7 @@ osStatus_t osMessageQueueDelete(osMessageQueueId_t msgq_id) if (msgq->is_dynamic_allocation) { k_free(msgq->pool); } - k_mem_slab_free(&cv2_msgq_slab, (void *)msgq); + k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq); return osOK; } diff --git a/subsys/portability/cmsis_rtos_v2/mutex.c b/subsys/portability/cmsis_rtos_v2/mutex.c index 1cdc00a04a697..f3bbc79f73496 100644 --- a/subsys/portability/cmsis_rtos_v2/mutex.c +++ b/subsys/portability/cmsis_rtos_v2/mutex.c @@ -9,7 +9,8 @@ #include #include "wrapper.h" -K_MEM_SLAB_DEFINE(cv2_mutex_slab, sizeof(struct cv2_mutex), CONFIG_CMSIS_V2_MUTEX_MAX_COUNT, 4); +K_MEM_SLAB_DEFINE(cmsis_rtos_mutex_cb_slab, sizeof(struct cmsis_rtos_mutex_cb), + CONFIG_CMSIS_V2_MUTEX_MAX_COUNT, 4); static const osMutexAttr_t init_mutex_attrs = { .name = "ZephyrMutex", @@ -23,7 +24,7 @@ static const osMutexAttr_t init_mutex_attrs = { */ osMutexId_t osMutexNew(const osMutexAttr_t *attr) { - struct cv2_mutex *mutex; + struct cmsis_rtos_mutex_cb *mutex; if (k_is_in_isr()) { return NULL; @@ -38,8 +39,8 @@ osMutexId_t osMutexNew(const osMutexAttr_t *attr) __ASSERT(!(attr->attr_bits & osMutexRobust), "Zephyr does not support osMutexRobust.\n"); - if (k_mem_slab_alloc(&cv2_mutex_slab, (void **)&mutex, K_MSEC(100)) == 0) { - memset(mutex, 0, sizeof(struct cv2_mutex)); + if (k_mem_slab_alloc(&cmsis_rtos_mutex_cb_slab, (void **)&mutex, K_MSEC(100)) == 0) { + memset(mutex, 0, sizeof(struct cmsis_rtos_mutex_cb)); } else { return NULL; } @@ -61,7 +62,7 @@ osMutexId_t osMutexNew(const osMutexAttr_t *attr) */ osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout) { - struct cv2_mutex *mutex = (struct cv2_mutex *)mutex_id; + struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id; int status; if (mutex_id == NULL) { @@ -94,7 +95,7 @@ osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout) */ osStatus_t osMutexRelease(osMutexId_t mutex_id) { - struct cv2_mutex *mutex = (struct cv2_mutex *)mutex_id; + struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id; if (mutex_id == NULL) { return osErrorParameter; @@ -116,7 +117,7 @@ osStatus_t osMutexRelease(osMutexId_t mutex_id) */ osStatus_t osMutexDelete(osMutexId_t mutex_id) { - struct cv2_mutex *mutex = (struct cv2_mutex *)mutex_id; + struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id; if (mutex_id == NULL) { return osErrorParameter; @@ -130,14 +131,14 @@ osStatus_t osMutexDelete(osMutexId_t mutex_id) * mutex_id is in an invalid mutex state) is not supported in Zephyr. */ - k_mem_slab_free(&cv2_mutex_slab, (void *)mutex); + k_mem_slab_free(&cmsis_rtos_mutex_cb_slab, (void *)mutex); return osOK; } osThreadId_t osMutexGetOwner(osMutexId_t mutex_id) { - struct cv2_mutex *mutex = (struct cv2_mutex *)mutex_id; + struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id; if (k_is_in_isr() || (mutex == NULL)) { return NULL; @@ -153,7 +154,7 @@ osThreadId_t osMutexGetOwner(osMutexId_t mutex_id) const char *osMutexGetName(osMutexId_t mutex_id) { - struct cv2_mutex *mutex = (struct cv2_mutex *)mutex_id; + struct cmsis_rtos_mutex_cb *mutex = (struct cmsis_rtos_mutex_cb *)mutex_id; if (k_is_in_isr() || (mutex == NULL)) { return NULL; diff --git a/subsys/portability/cmsis_rtos_v2/semaphore.c b/subsys/portability/cmsis_rtos_v2/semaphore.c index 7d37410cd1572..37f62710208f3 100644 --- a/subsys/portability/cmsis_rtos_v2/semaphore.c +++ b/subsys/portability/cmsis_rtos_v2/semaphore.c @@ -8,8 +8,8 @@ #include #include -K_MEM_SLAB_DEFINE(cv2_semaphore_slab, sizeof(struct cv2_sem), CONFIG_CMSIS_V2_SEMAPHORE_MAX_COUNT, - 4); +K_MEM_SLAB_DEFINE(cmsis_rtos_semaphore_cb_slab, sizeof(struct cmsis_rtos_semaphore_cb), + CONFIG_CMSIS_V2_SEMAPHORE_MAX_COUNT, 4); static const osSemaphoreAttr_t init_sema_attrs = { .name = "ZephyrSem", @@ -24,7 +24,7 @@ static const osSemaphoreAttr_t init_sema_attrs = { osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) { - struct cv2_sem *semaphore; + struct cmsis_rtos_semaphore_cb *semaphore; if (k_is_in_isr()) { return NULL; @@ -34,8 +34,9 @@ osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, attr = &init_sema_attrs; } - if (k_mem_slab_alloc(&cv2_semaphore_slab, (void **)&semaphore, K_MSEC(100)) == 0) { - (void)memset(semaphore, 0, sizeof(struct cv2_sem)); + if (k_mem_slab_alloc(&cmsis_rtos_semaphore_cb_slab, (void **)&semaphore, K_MSEC(100)) == + 0) { + (void)memset(semaphore, 0, sizeof(struct cmsis_rtos_semaphore_cb)); } else { return NULL; } @@ -56,7 +57,7 @@ osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, */ osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout) { - struct cv2_sem *semaphore = (struct cv2_sem *)semaphore_id; + struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id; int status; if (semaphore_id == NULL) { @@ -87,7 +88,7 @@ osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout) uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id) { - struct cv2_sem *semaphore = (struct cv2_sem *)semaphore_id; + struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id; if (semaphore_id == NULL) { return 0; @@ -101,7 +102,7 @@ uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id) */ osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id) { - struct cv2_sem *semaphore = (struct cv2_sem *)semaphore_id; + struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id; if (semaphore_id == NULL) { return osErrorParameter; @@ -122,7 +123,7 @@ osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id) */ osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id) { - struct cv2_sem *semaphore = (struct cv2_sem *)semaphore_id; + struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id; if (semaphore_id == NULL) { return osErrorParameter; @@ -137,14 +138,14 @@ osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id) * supported in Zephyr. */ - k_mem_slab_free(&cv2_semaphore_slab, (void *)semaphore); + k_mem_slab_free(&cmsis_rtos_semaphore_cb_slab, (void *)semaphore); return osOK; } const char *osSemaphoreGetName(osSemaphoreId_t semaphore_id) { - struct cv2_sem *semaphore = (struct cv2_sem *)semaphore_id; + struct cmsis_rtos_semaphore_cb *semaphore = (struct cmsis_rtos_semaphore_cb *)semaphore_id; if (!k_is_in_isr() && (semaphore_id != NULL)) { return semaphore->name; diff --git a/subsys/portability/cmsis_rtos_v2/thread.c b/subsys/portability/cmsis_rtos_v2/thread.c index 3f42658cbbcf4..6a8af803b2247 100644 --- a/subsys/portability/cmsis_rtos_v2/thread.c +++ b/subsys/portability/cmsis_rtos_v2/thread.c @@ -26,12 +26,13 @@ static const osThreadAttr_t init_thread_attrs = { }; static sys_dlist_t thread_list; -static struct cv2_thread cv2_thread_pool[CONFIG_CMSIS_V2_THREAD_MAX_COUNT]; +static struct cmsis_rtos_thread_cb cmsis_rtos_thread_cb_pool[CONFIG_CMSIS_V2_THREAD_MAX_COUNT]; static atomic_t thread_num; static atomic_t thread_num_dynamic; #if CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT != 0 -static K_THREAD_STACK_ARRAY_DEFINE(cv2_thread_stack_pool, CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT, +static K_THREAD_STACK_ARRAY_DEFINE(cmsis_rtos_thread_stack_pool, + CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT, CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE); #endif @@ -54,7 +55,7 @@ static inline uint32_t cmsis_to_zephyr_priority(uint32_t c_prio) static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) { - struct cv2_thread *tid = arg2; + struct cmsis_rtos_thread_cb *tid = arg2; void *(*fun_ptr)(void *) = arg3; fun_ptr(arg1); @@ -66,10 +67,10 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) void *is_cmsis_rtos_v2_thread(void *thread_id) { sys_dnode_t *pnode; - struct cv2_thread *itr; + struct cmsis_rtos_thread_cb *itr; SYS_DLIST_FOR_EACH_NODE(&thread_list, pnode) { - itr = CONTAINER_OF(pnode, struct cv2_thread, node); + itr = CONTAINER_OF(pnode, struct cmsis_rtos_thread_cb, node); if ((void *)itr == thread_id) { return itr; @@ -82,11 +83,11 @@ void *is_cmsis_rtos_v2_thread(void *thread_id) osThreadId_t get_cmsis_thread_id(k_tid_t tid) { sys_dnode_t *pnode; - struct cv2_thread *itr; + struct cmsis_rtos_thread_cb *itr; if (tid != NULL) { SYS_DLIST_FOR_EACH_NODE(&thread_list, pnode) { - itr = CONTAINER_OF(pnode, struct cv2_thread, node); + itr = CONTAINER_OF(pnode, struct cmsis_rtos_thread_cb, node); if (&itr->z_thread == tid) { return (osThreadId_t)itr; @@ -104,7 +105,7 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, const osThreadAtt { int32_t prio; osPriority_t cv2_prio; - struct cv2_thread *tid; + struct cmsis_rtos_thread_cb *tid; static uint32_t one_time; void *stack; size_t stack_size; @@ -157,7 +158,7 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, const osThreadAtt this_thread_num = atomic_inc((atomic_t *)&thread_num); - tid = &cv2_thread_pool[this_thread_num]; + tid = &cmsis_rtos_thread_cb_pool[this_thread_num]; tid->attr_bits = attr->attr_bits; #if CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT != 0 @@ -167,7 +168,7 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, const osThreadAtt "dynamic stack size must be configured to be non-zero\n"); this_thread_num_dynamic = atomic_inc((atomic_t *)&thread_num_dynamic); stack_size = CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE; - stack = cv2_thread_stack_pool[this_thread_num_dynamic]; + stack = cmsis_rtos_thread_stack_pool[this_thread_num_dynamic]; } else #endif { @@ -218,7 +219,7 @@ const char *osThreadGetName(osThreadId_t thread_id) if (is_cmsis_rtos_v2_thread(thread_id) == NULL) { name = NULL; } else { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; name = k_thread_name_get(&tid->z_thread); } @@ -242,7 +243,7 @@ osThreadId_t osThreadGetId(void) */ osPriority_t osThreadGetPriority(osThreadId_t thread_id) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; uint32_t priority; if (k_is_in_isr() || (tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL) || @@ -259,7 +260,7 @@ osPriority_t osThreadGetPriority(osThreadId_t thread_id) */ osStatus_t osThreadSetPriority(osThreadId_t thread_id, osPriority_t priority) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL) || (priority <= osPriorityNone) || (priority > osPriorityISR)) { @@ -284,7 +285,7 @@ osStatus_t osThreadSetPriority(osThreadId_t thread_id, osPriority_t priority) */ osThreadState_t osThreadGetState(osThreadId_t thread_id) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; osThreadState_t state; if (k_is_in_isr() || (tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) { @@ -336,7 +337,7 @@ osStatus_t osThreadYield(void) */ uint32_t osThreadGetStackSize(osThreadId_t thread_id) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; __ASSERT(tid, ""); __ASSERT(is_cmsis_rtos_v2_thread(tid), ""); @@ -351,7 +352,7 @@ uint32_t osThreadGetStackSize(osThreadId_t thread_id) */ uint32_t osThreadGetStackSpace(osThreadId_t thread_id) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; size_t unused; int ret; @@ -372,7 +373,7 @@ uint32_t osThreadGetStackSpace(osThreadId_t thread_id) */ osStatus_t osThreadSuspend(osThreadId_t thread_id) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) { return osErrorParameter; @@ -396,7 +397,7 @@ osStatus_t osThreadSuspend(osThreadId_t thread_id) */ osStatus_t osThreadResume(osThreadId_t thread_id) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) { return osErrorParameter; @@ -421,7 +422,7 @@ osStatus_t osThreadResume(osThreadId_t thread_id) */ osStatus_t osThreadDetach(osThreadId_t thread_id) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) { return osErrorParameter; @@ -450,7 +451,7 @@ osStatus_t osThreadDetach(osThreadId_t thread_id) */ osStatus_t osThreadJoin(osThreadId_t thread_id) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; osStatus_t status = osError; if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) { @@ -491,7 +492,7 @@ osStatus_t osThreadJoin(osThreadId_t thread_id) */ __NO_RETURN void osThreadExit(void) { - struct cv2_thread *tid; + struct cmsis_rtos_thread_cb *tid; __ASSERT(!k_is_in_isr(), ""); tid = osThreadGetId(); @@ -508,7 +509,7 @@ __NO_RETURN void osThreadExit(void) */ osStatus_t osThreadTerminate(osThreadId_t thread_id) { - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) { return osErrorParameter; diff --git a/subsys/portability/cmsis_rtos_v2/thread_flags.c b/subsys/portability/cmsis_rtos_v2/thread_flags.c index a573c59a4527d..1264fa7be606d 100644 --- a/subsys/portability/cmsis_rtos_v2/thread_flags.c +++ b/subsys/portability/cmsis_rtos_v2/thread_flags.c @@ -16,7 +16,7 @@ uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags) { unsigned int key; - struct cv2_thread *tid = (struct cv2_thread *)thread_id; + struct cmsis_rtos_thread_cb *tid = (struct cmsis_rtos_thread_cb *)thread_id; if ((thread_id == NULL) || (is_cmsis_rtos_v2_thread(thread_id) == NULL) || (flags & 0x80000000)) { @@ -37,13 +37,13 @@ uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags) */ uint32_t osThreadFlagsGet(void) { - struct cv2_thread *tid; + struct cmsis_rtos_thread_cb *tid; if (k_is_in_isr()) { return 0; } - tid = (struct cv2_thread *)osThreadGetId(); + tid = (struct cmsis_rtos_thread_cb *)osThreadGetId(); if (tid == NULL) { return 0; } else { @@ -56,7 +56,7 @@ uint32_t osThreadFlagsGet(void) */ uint32_t osThreadFlagsClear(uint32_t flags) { - struct cv2_thread *tid; + struct cmsis_rtos_thread_cb *tid; int sig, key; if (k_is_in_isr()) { @@ -67,7 +67,7 @@ uint32_t osThreadFlagsClear(uint32_t flags) return osFlagsErrorParameter; } - tid = (struct cv2_thread *)osThreadGetId(); + tid = (struct cmsis_rtos_thread_cb *)osThreadGetId(); if (tid == NULL) { return osFlagsErrorUnknown; } @@ -86,7 +86,7 @@ uint32_t osThreadFlagsClear(uint32_t flags) */ uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout) { - struct cv2_thread *tid; + struct cmsis_rtos_thread_cb *tid; int retval, key; uint32_t sig; uint32_t time_delta_ms, timeout_ms = k_ticks_to_ms_floor64(timeout); @@ -100,7 +100,7 @@ uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout) return osFlagsErrorParameter; } - tid = (struct cv2_thread *)osThreadGetId(); + tid = (struct cmsis_rtos_thread_cb *)osThreadGetId(); if (tid == NULL) { return osFlagsErrorUnknown; } diff --git a/subsys/portability/cmsis_rtos_v2/timer.c b/subsys/portability/cmsis_rtos_v2/timer.c index eeb155f933f49..4dfca21b67c0f 100644 --- a/subsys/portability/cmsis_rtos_v2/timer.c +++ b/subsys/portability/cmsis_rtos_v2/timer.c @@ -13,7 +13,8 @@ static void zephyr_timer_wrapper(struct k_timer *timer); -K_MEM_SLAB_DEFINE(cv2_timer_slab, sizeof(struct cv2_timer), CONFIG_CMSIS_V2_TIMER_MAX_COUNT, 4); +K_MEM_SLAB_DEFINE(cmsis_rtos_timer_cb_slab, sizeof(struct cmsis_rtos_timer_cb), + CONFIG_CMSIS_V2_TIMER_MAX_COUNT, 4); static const osTimerAttr_t init_timer_attrs = { .name = "ZephyrTimer", @@ -24,9 +25,9 @@ static const osTimerAttr_t init_timer_attrs = { static void zephyr_timer_wrapper(struct k_timer *timer) { - struct cv2_timer *cm_timer; + struct cmsis_rtos_timer_cb *cm_timer; - cm_timer = CONTAINER_OF(timer, struct cv2_timer, z_timer); + cm_timer = CONTAINER_OF(timer, struct cmsis_rtos_timer_cb, z_timer); (cm_timer->callback_function)(cm_timer->arg); } @@ -36,7 +37,7 @@ static void zephyr_timer_wrapper(struct k_timer *timer) osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) { - struct cv2_timer *timer; + struct cmsis_rtos_timer_cb *timer; if (type != osTimerOnce && type != osTimerPeriodic) { return NULL; @@ -50,8 +51,8 @@ osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, attr = &init_timer_attrs; } - if (k_mem_slab_alloc(&cv2_timer_slab, (void **)&timer, K_MSEC(100)) == 0) { - (void)memset(timer, 0, sizeof(struct cv2_timer)); + if (k_mem_slab_alloc(&cmsis_rtos_timer_cb_slab, (void **)&timer, K_MSEC(100)) == 0) { + (void)memset(timer, 0, sizeof(struct cmsis_rtos_timer_cb)); } else { return NULL; } @@ -77,7 +78,7 @@ osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, */ osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks) { - struct cv2_timer *timer = (struct cv2_timer *)timer_id; + struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id; if (timer == NULL) { return osErrorParameter; @@ -102,7 +103,7 @@ osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks) */ osStatus_t osTimerStop(osTimerId_t timer_id) { - struct cv2_timer *timer = (struct cv2_timer *)timer_id; + struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id; if (timer == NULL) { return osErrorParameter; @@ -126,7 +127,7 @@ osStatus_t osTimerStop(osTimerId_t timer_id) */ osStatus_t osTimerDelete(osTimerId_t timer_id) { - struct cv2_timer *timer = (struct cv2_timer *)timer_id; + struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id; if (timer == NULL) { return osErrorParameter; @@ -141,7 +142,7 @@ osStatus_t osTimerDelete(osTimerId_t timer_id) timer->status = NOT_ACTIVE; } - k_mem_slab_free(&cv2_timer_slab, (void *)timer); + k_mem_slab_free(&cmsis_rtos_timer_cb_slab, (void *)timer); return osOK; } @@ -150,7 +151,7 @@ osStatus_t osTimerDelete(osTimerId_t timer_id) */ const char *osTimerGetName(osTimerId_t timer_id) { - struct cv2_timer *timer = (struct cv2_timer *)timer_id; + struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id; if (k_is_in_isr() || (timer == NULL)) { return NULL; @@ -164,7 +165,7 @@ const char *osTimerGetName(osTimerId_t timer_id) */ uint32_t osTimerIsRunning(osTimerId_t timer_id) { - struct cv2_timer *timer = (struct cv2_timer *)timer_id; + struct cmsis_rtos_timer_cb *timer = (struct cmsis_rtos_timer_cb *)timer_id; if (k_is_in_isr() || (timer == NULL)) { return 0; From ed2e557d4c817a32b5b48907917ad89e9decdb99 Mon Sep 17 00:00:00 2001 From: Utsav Munendra Date: Mon, 20 Jan 2025 19:08:33 -0800 Subject: [PATCH 0131/6055] portability: cmsis: CMSIS-RTOSv2 thread port to track dynamic cb No functionality change, in preparation for allowing threads with user provided stack and control block. Signed-off-by: Utsav Munendra --- subsys/portability/cmsis_rtos_v2/thread.c | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/subsys/portability/cmsis_rtos_v2/thread.c b/subsys/portability/cmsis_rtos_v2/thread.c index 6a8af803b2247..149a635b54715 100644 --- a/subsys/portability/cmsis_rtos_v2/thread.c +++ b/subsys/portability/cmsis_rtos_v2/thread.c @@ -26,10 +26,12 @@ static const osThreadAttr_t init_thread_attrs = { }; static sys_dlist_t thread_list; -static struct cmsis_rtos_thread_cb cmsis_rtos_thread_cb_pool[CONFIG_CMSIS_V2_THREAD_MAX_COUNT]; static atomic_t thread_num; -static atomic_t thread_num_dynamic; +static atomic_t num_dynamic_cb; +static struct cmsis_rtos_thread_cb cmsis_rtos_thread_cb_pool[CONFIG_CMSIS_V2_THREAD_MAX_COUNT]; + +static atomic_t num_dynamic_stack; #if CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT != 0 static K_THREAD_STACK_ARRAY_DEFINE(cmsis_rtos_thread_stack_pool, CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT, @@ -129,8 +131,12 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, const osThreadAtt cv2_prio = attr->priority; } - if ((attr->stack_mem == NULL) && - (thread_num_dynamic >= CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT)) { + if (attr->cb_mem == NULL && num_dynamic_cb >= CONFIG_CMSIS_V2_THREAD_MAX_COUNT) { + return NULL; + } + + if (attr->stack_mem == NULL && + num_dynamic_stack >= CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT) { return NULL; } @@ -154,21 +160,20 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, const osThreadAtt } } - prio = cmsis_to_zephyr_priority(cv2_prio); - - this_thread_num = atomic_inc((atomic_t *)&thread_num); + this_thread_num = atomic_inc(&thread_num); - tid = &cmsis_rtos_thread_cb_pool[this_thread_num]; + uint32_t this_dynamic_cb = atomic_inc(&num_dynamic_cb); + tid = &cmsis_rtos_thread_cb_pool[this_dynamic_cb]; tid->attr_bits = attr->attr_bits; #if CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT != 0 if (attr->stack_mem == NULL) { - uint32_t this_thread_num_dynamic; + uint32_t this_dynamic_stack; __ASSERT(CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE > 0, "dynamic stack size must be configured to be non-zero\n"); - this_thread_num_dynamic = atomic_inc((atomic_t *)&thread_num_dynamic); + this_dynamic_stack = atomic_inc(&num_dynamic_stack); stack_size = CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE; - stack = cmsis_rtos_thread_stack_pool[this_thread_num_dynamic]; + stack = cmsis_rtos_thread_stack_pool[this_dynamic_stack]; } else #endif { @@ -192,6 +197,8 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, const osThreadAtt k_sem_init(&tid->join_guard, 0, 1); tid->has_joined = FALSE; + prio = cmsis_to_zephyr_priority(cv2_prio); + (void)k_thread_create(&tid->z_thread, stack, stack_size, zephyr_thread_wrapper, (void *)arg, tid, threadfunc, prio, 0, K_NO_WAIT); From 10c6b34800c58a9abcd4994adc8d2b10f23505b7 Mon Sep 17 00:00:00 2001 From: Utsav Munendra Date: Mon, 20 Jan 2025 19:15:41 -0800 Subject: [PATCH 0132/6055] portability: cmsis: Support static CMSIS-RTOSv2 control blocks Do not use memory slabs for the control blocks when the application provides the memory for it. This implements manual user-defined allocation memory management support in CMSIS-RTOSv2 API. Signed-off-by: Utsav Munendra --- include/zephyr/portability/cmsis_types.h | 7 +++++ .../portability/cmsis_rtos_v2/event_flags.c | 16 ++++++---- subsys/portability/cmsis_rtos_v2/mempool.c | 30 ++++++++++++------- subsys/portability/cmsis_rtos_v2/msgq.c | 22 +++++++++----- subsys/portability/cmsis_rtos_v2/mutex.c | 14 +++++---- subsys/portability/cmsis_rtos_v2/semaphore.c | 17 +++++++---- subsys/portability/cmsis_rtos_v2/thread.c | 10 +++++-- subsys/portability/cmsis_rtos_v2/timer.c | 13 +++++--- 8 files changed, 88 insertions(+), 41 deletions(-) diff --git a/include/zephyr/portability/cmsis_types.h b/include/zephyr/portability/cmsis_types.h index 1f4f28081002c..cb73a50ffa36b 100644 --- a/include/zephyr/portability/cmsis_types.h +++ b/include/zephyr/portability/cmsis_types.h @@ -7,6 +7,7 @@ #ifndef ZEPHYR_INCLUDE_CMSIS_TYPES_H_ #define ZEPHYR_INCLUDE_CMSIS_TYPES_H_ +#include #include #include @@ -41,6 +42,7 @@ struct cmsis_rtos_timer_cb { struct k_timer z_timer; osTimerType_t type; uint32_t status; + bool is_cb_dynamic_allocation; char name[CMSIS_OBJ_NAME_MAX_LEN]; void (*callback_function)(void *argument); void *arg; @@ -54,6 +56,7 @@ struct cmsis_rtos_timer_cb { */ struct cmsis_rtos_mutex_cb { struct k_mutex z_mutex; + bool is_cb_dynamic_allocation; char name[CMSIS_OBJ_NAME_MAX_LEN]; uint32_t state; }; @@ -66,6 +69,7 @@ struct cmsis_rtos_mutex_cb { */ struct cmsis_rtos_semaphore_cb { struct k_sem z_semaphore; + bool is_cb_dynamic_allocation; char name[CMSIS_OBJ_NAME_MAX_LEN]; }; @@ -79,6 +83,7 @@ struct cmsis_rtos_mempool_cb { struct k_mem_slab z_mslab; void *pool; char is_dynamic_allocation; + bool is_cb_dynamic_allocation; char name[CMSIS_OBJ_NAME_MAX_LEN]; }; @@ -92,6 +97,7 @@ struct cmsis_rtos_msgq_cb { struct k_msgq z_msgq; void *pool; char is_dynamic_allocation; + bool is_cb_dynamic_allocation; char name[CMSIS_OBJ_NAME_MAX_LEN]; }; @@ -105,6 +111,7 @@ struct cmsis_rtos_event_cb { struct k_poll_signal poll_signal; struct k_poll_event poll_event; uint32_t signal_results; + bool is_cb_dynamic_allocation; char name[CMSIS_OBJ_NAME_MAX_LEN]; }; diff --git a/subsys/portability/cmsis_rtos_v2/event_flags.c b/subsys/portability/cmsis_rtos_v2/event_flags.c index d2c563b79c0a8..41d947f169d14 100644 --- a/subsys/portability/cmsis_rtos_v2/event_flags.c +++ b/subsys/portability/cmsis_rtos_v2/event_flags.c @@ -35,11 +35,15 @@ osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr) attr = &init_event_flags_attrs; } - if (k_mem_slab_alloc(&cmsis_rtos_event_cb_slab, (void **)&events, K_MSEC(100)) == 0) { - memset(events, 0, sizeof(struct cmsis_rtos_event_cb)); - } else { + if (attr->cb_mem != NULL) { + __ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_event_cb), "Invalid cb_size\n"); + events = (struct cmsis_rtos_event_cb *)attr->cb_mem; + } else if (k_mem_slab_alloc(&cmsis_rtos_event_cb_slab, (void **)&events, K_MSEC(100)) != + 0) { return NULL; } + memset(events, 0, sizeof(struct cmsis_rtos_event_cb)); + events->is_cb_dynamic_allocation = attr->cb_mem == NULL; k_poll_signal_init(&events->poll_signal); k_poll_event_init(&events->poll_event, K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, @@ -247,8 +251,8 @@ osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) /* The status code "osErrorParameter" (the value of the parameter * ef_id is incorrect) is not supported in Zephyr. */ - - k_mem_slab_free(&cmsis_rtos_event_cb_slab, (void *)events); - + if (events->is_cb_dynamic_allocation) { + k_mem_slab_free(&cmsis_rtos_event_cb_slab, (void *)events); + } return osOK; } diff --git a/subsys/portability/cmsis_rtos_v2/mempool.c b/subsys/portability/cmsis_rtos_v2/mempool.c index 90a8f329bb668..d645e658108c6 100644 --- a/subsys/portability/cmsis_rtos_v2/mempool.c +++ b/subsys/portability/cmsis_rtos_v2/mempool.c @@ -46,11 +46,15 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, attr = &init_mslab_attrs; } - if (k_mem_slab_alloc(&cv2_mem_slab, (void **)&mslab, K_MSEC(100)) == 0) { - (void)memset(mslab, 0, sizeof(struct cmsis_rtos_mempool_cb)); - } else { + if (attr->cb_mem != NULL) { + __ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_mempool_cb), + "Invalid cb_size\n"); + mslab = (struct cmsis_rtos_mempool_cb *)attr->cb_mem; + } else if (k_mem_slab_alloc(&cv2_mem_slab, (void **)&mslab, K_MSEC(100)) != 0) { return NULL; } + (void)memset(mslab, 0, sizeof(struct cmsis_rtos_mempool_cb)); + mslab->is_cb_dynamic_allocation = attr->cb_mem == NULL; if (attr->mp_mem == NULL) { __ASSERT((block_count * block_size) <= CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE, @@ -58,7 +62,9 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, mslab->pool = k_calloc(block_count, block_size); if (mslab->pool == NULL) { - k_mem_slab_free(&cv2_mem_slab, (void *)mslab); + if (mslab->is_cb_dynamic_allocation) { + k_mem_slab_free(&cv2_mem_slab, (void *)mslab); + } return NULL; } mslab->is_dynamic_allocation = TRUE; @@ -68,9 +74,10 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, } int rc = k_mem_slab_init(&mslab->z_mslab, mslab->pool, block_size, block_count); - if (rc != 0) { - k_mem_slab_free(&cv2_mem_slab, (void *)mslab); + if (mslab->is_cb_dynamic_allocation) { + k_mem_slab_free(&cv2_mem_slab, (void *)mslab); + } if (attr->mp_mem == NULL) { k_free(mslab->pool); } @@ -137,9 +144,9 @@ osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block) * osErrorResource: the memory pool specified by parameter mp_id * is in an invalid memory pool state. */ - - k_mem_slab_free((struct k_mem_slab *)(&mslab->z_mslab), (void *)block); - + if (mslab->is_cb_dynamic_allocation) { + k_mem_slab_free((struct k_mem_slab *)(&mslab->z_mslab), (void *)block); + } return osOK; } @@ -236,7 +243,8 @@ osStatus_t osMemoryPoolDelete(osMemoryPoolId_t mp_id) if (mslab->is_dynamic_allocation) { k_free(mslab->pool); } - k_mem_slab_free(&cv2_mem_slab, (void *)mslab); - + if (mslab->is_cb_dynamic_allocation) { + k_mem_slab_free(&cv2_mem_slab, (void *)mslab); + } return osOK; } diff --git a/subsys/portability/cmsis_rtos_v2/msgq.c b/subsys/portability/cmsis_rtos_v2/msgq.c index 5d8d12de38976..5f67fffd64710 100644 --- a/subsys/portability/cmsis_rtos_v2/msgq.c +++ b/subsys/portability/cmsis_rtos_v2/msgq.c @@ -44,11 +44,14 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, attr = &init_msgq_attrs; } - if (k_mem_slab_alloc(&cmsis_rtos_msgq_cb_slab, (void **)&msgq, K_MSEC(100)) == 0) { - (void)memset(msgq, 0, sizeof(struct cmsis_rtos_msgq_cb)); - } else { + if (attr->cb_mem != NULL) { + __ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_msgq_cb), "Invalid cb_size\n"); + msgq = (struct cmsis_rtos_msgq_cb *)attr->cb_mem; + } else if (k_mem_slab_alloc(&cmsis_rtos_msgq_cb_slab, (void **)&msgq, K_MSEC(100)) != 0) { return NULL; } + (void)memset(msgq, 0, sizeof(struct cmsis_rtos_msgq_cb)); + msgq->is_cb_dynamic_allocation = attr->cb_mem == NULL; if (attr->mq_mem == NULL) { __ASSERT((msg_count * msg_size) <= CONFIG_CMSIS_V2_MSGQ_MAX_DYNAMIC_SIZE, @@ -57,12 +60,16 @@ osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, #if (K_HEAP_MEM_POOL_SIZE > 0) msgq->pool = k_calloc(msg_count, msg_size); if (msgq->pool == NULL) { - k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq); + if (msgq->is_cb_dynamic_allocation) { + k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq); + } return NULL; } msgq->is_dynamic_allocation = TRUE; #else - k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq); + if (msgq->is_cb_dynamic_allocation) { + k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq); + } return NULL; #endif } else { @@ -275,7 +282,8 @@ osStatus_t osMessageQueueDelete(osMessageQueueId_t msgq_id) if (msgq->is_dynamic_allocation) { k_free(msgq->pool); } - k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq); - + if (msgq->is_cb_dynamic_allocation) { + k_mem_slab_free(&cmsis_rtos_msgq_cb_slab, (void *)msgq); + } return osOK; } diff --git a/subsys/portability/cmsis_rtos_v2/mutex.c b/subsys/portability/cmsis_rtos_v2/mutex.c index f3bbc79f73496..e869fff5d6bb4 100644 --- a/subsys/portability/cmsis_rtos_v2/mutex.c +++ b/subsys/portability/cmsis_rtos_v2/mutex.c @@ -39,11 +39,14 @@ osMutexId_t osMutexNew(const osMutexAttr_t *attr) __ASSERT(!(attr->attr_bits & osMutexRobust), "Zephyr does not support osMutexRobust.\n"); - if (k_mem_slab_alloc(&cmsis_rtos_mutex_cb_slab, (void **)&mutex, K_MSEC(100)) == 0) { - memset(mutex, 0, sizeof(struct cmsis_rtos_mutex_cb)); - } else { + if (attr->cb_mem != NULL) { + __ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_mutex_cb), "Invalid cb_size\n"); + mutex = (struct cmsis_rtos_mutex_cb *)attr->cb_mem; + } else if (k_mem_slab_alloc(&cmsis_rtos_mutex_cb_slab, (void **)&mutex, K_MSEC(100)) != 0) { return NULL; } + memset(mutex, 0, sizeof(struct cmsis_rtos_mutex_cb)); + mutex->is_cb_dynamic_allocation = attr->cb_mem == NULL; k_mutex_init(&mutex->z_mutex); mutex->state = attr->attr_bits; @@ -130,8 +133,9 @@ osStatus_t osMutexDelete(osMutexId_t mutex_id) /* The status code "osErrorResource" (mutex specified by parameter * mutex_id is in an invalid mutex state) is not supported in Zephyr. */ - - k_mem_slab_free(&cmsis_rtos_mutex_cb_slab, (void *)mutex); + if (mutex->is_cb_dynamic_allocation) { + k_mem_slab_free(&cmsis_rtos_mutex_cb_slab, (void *)mutex); + } return osOK; } diff --git a/subsys/portability/cmsis_rtos_v2/semaphore.c b/subsys/portability/cmsis_rtos_v2/semaphore.c index 37f62710208f3..33ce0e05a73f9 100644 --- a/subsys/portability/cmsis_rtos_v2/semaphore.c +++ b/subsys/portability/cmsis_rtos_v2/semaphore.c @@ -34,12 +34,16 @@ osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, attr = &init_sema_attrs; } - if (k_mem_slab_alloc(&cmsis_rtos_semaphore_cb_slab, (void **)&semaphore, K_MSEC(100)) == - 0) { - (void)memset(semaphore, 0, sizeof(struct cmsis_rtos_semaphore_cb)); - } else { + if (attr->cb_mem != NULL) { + __ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_semaphore_cb), + "Invalid cb_size\n"); + semaphore = (struct cmsis_rtos_semaphore_cb *)attr->cb_mem; + } else if (k_mem_slab_alloc(&cmsis_rtos_semaphore_cb_slab, (void **)&semaphore, + K_MSEC(100)) != 0) { return NULL; } + (void)memset(semaphore, 0, sizeof(struct cmsis_rtos_semaphore_cb)); + semaphore->is_cb_dynamic_allocation = attr->cb_mem == NULL; k_sem_init(&semaphore->z_semaphore, initial_count, max_count); @@ -137,8 +141,9 @@ osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id) * parameter semaphore_id is in an invalid semaphore state) is not * supported in Zephyr. */ - - k_mem_slab_free(&cmsis_rtos_semaphore_cb_slab, (void *)semaphore); + if (semaphore->is_cb_dynamic_allocation) { + k_mem_slab_free(&cmsis_rtos_semaphore_cb_slab, (void *)semaphore); + } return osOK; } diff --git a/subsys/portability/cmsis_rtos_v2/thread.c b/subsys/portability/cmsis_rtos_v2/thread.c index 149a635b54715..a925b6b11d109 100644 --- a/subsys/portability/cmsis_rtos_v2/thread.c +++ b/subsys/portability/cmsis_rtos_v2/thread.c @@ -112,6 +112,7 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, const osThreadAtt void *stack; size_t stack_size; uint32_t this_thread_num; + uint32_t this_dynamic_cb; if (k_is_in_isr()) { return NULL; @@ -162,8 +163,13 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg, const osThreadAtt this_thread_num = atomic_inc(&thread_num); - uint32_t this_dynamic_cb = atomic_inc(&num_dynamic_cb); - tid = &cmsis_rtos_thread_cb_pool[this_dynamic_cb]; + if (attr->cb_mem == NULL) { + this_dynamic_cb = atomic_inc(&num_dynamic_cb); + tid = &cmsis_rtos_thread_cb_pool[this_dynamic_cb]; + } else { + tid = (struct cmsis_rtos_thread_cb *)attr->cb_mem; + } + tid->attr_bits = attr->attr_bits; #if CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT != 0 diff --git a/subsys/portability/cmsis_rtos_v2/timer.c b/subsys/portability/cmsis_rtos_v2/timer.c index 4dfca21b67c0f..e7f5f24bafee3 100644 --- a/subsys/portability/cmsis_rtos_v2/timer.c +++ b/subsys/portability/cmsis_rtos_v2/timer.c @@ -51,11 +51,14 @@ osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, attr = &init_timer_attrs; } - if (k_mem_slab_alloc(&cmsis_rtos_timer_cb_slab, (void **)&timer, K_MSEC(100)) == 0) { - (void)memset(timer, 0, sizeof(struct cmsis_rtos_timer_cb)); - } else { + if (attr->cb_mem != NULL) { + __ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_timer_cb), "Invalid cb_size\n"); + timer = (struct cmsis_rtos_timer_cb *)attr->cb_mem; + } else if (k_mem_slab_alloc(&cmsis_rtos_timer_cb_slab, (void **)&timer, K_MSEC(100)) != 0) { return NULL; } + (void)memset(timer, 0, sizeof(struct cmsis_rtos_timer_cb)); + timer->is_cb_dynamic_allocation = attr->cb_mem == NULL; timer->callback_function = func; timer->arg = argument; @@ -142,7 +145,9 @@ osStatus_t osTimerDelete(osTimerId_t timer_id) timer->status = NOT_ACTIVE; } - k_mem_slab_free(&cmsis_rtos_timer_cb_slab, (void *)timer); + if (timer->is_cb_dynamic_allocation) { + k_mem_slab_free(&cmsis_rtos_timer_cb_slab, (void *)timer); + } return osOK; } From 137c7cb1493c31816403add9f8dc470d91860184 Mon Sep 17 00:00:00 2001 From: Utsav Munendra Date: Mon, 20 Jan 2025 21:17:21 -0800 Subject: [PATCH 0133/6055] tests: portability: cmsis: Run clang-format on CMSIS-RTOSv2 tests clang-format -i tests/subsys/portability/cmsis_rtos_v2/src/*.c Signed-off-by: Utsav Munendra --- .../cmsis_rtos_v2/src/event_flags.c | 54 ++++++---------- .../portability/cmsis_rtos_v2/src/kernel.c | 14 ++--- .../portability/cmsis_rtos_v2/src/mempool.c | 31 ++++----- .../portability/cmsis_rtos_v2/src/msgq.c | 51 ++++++--------- .../portability/cmsis_rtos_v2/src/mutex.c | 39 +++++------- .../portability/cmsis_rtos_v2/src/semaphore.c | 56 +++++++---------- .../cmsis_rtos_v2/src/thread_apis.c | 63 +++++++------------ .../cmsis_rtos_v2/src/thread_flags.c | 33 ++++------ .../portability/cmsis_rtos_v2/src/timer.c | 28 +++------ 9 files changed, 137 insertions(+), 232 deletions(-) diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/event_flags.c b/tests/subsys/portability/cmsis_rtos_v2/src/event_flags.c index c4906eb5e9686..77d07ae03181b 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/event_flags.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/event_flags.c @@ -11,12 +11,12 @@ #include #include -#define TIMEOUT_TICKS (100) -#define FLAG1 (0x00000020) -#define FLAG2 (0x00000004) -#define FLAG (FLAG1 | FLAG2) -#define ISR_FLAG 0x50 -#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE +#define TIMEOUT_TICKS (100) +#define FLAG1 (0x00000020) +#define FLAG2 (0x00000004) +#define FLAG (FLAG1 | FLAG2) +#define ISR_FLAG 0x50 +#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE osEventFlagsId_t evt_id; @@ -77,12 +77,10 @@ void test_event_flags_no_wait_timeout(void) zassert_true(evt_id != NULL, "Failed creating event flags"); name = osEventFlagsGetName(dummy_id); - zassert_true(name == NULL, - "Invalid event Flags ID is unexpectedly working!"); + zassert_true(name == NULL, "Invalid event Flags ID is unexpectedly working!"); name = osEventFlagsGetName(evt_id); - zassert_str_equal(event_flags_attrs.name, name, - "Error getting event_flags object name"); + zassert_str_equal(event_flags_attrs.name, name, "Error getting event_flags object name"); id1 = osThreadNew(thread1, evt_id, &thread1_attr); zassert_true(id1 != NULL, "Failed creating thread1"); @@ -93,8 +91,7 @@ void test_event_flags_no_wait_timeout(void) /* wait for FLAG1. It should return immediately as it is * already triggered. */ - flags = osEventFlagsWait(evt_id, FLAG1, - osFlagsWaitAny | osFlagsNoClear, 0); + flags = osEventFlagsWait(evt_id, FLAG1, osFlagsWaitAny | osFlagsNoClear, 0); zassert_equal(flags & FLAG1, FLAG1, ""); /* Since the flags are not cleared automatically in the previous step, @@ -104,8 +101,7 @@ void test_event_flags_no_wait_timeout(void) zassert_equal(flags & FLAG1, FLAG1, ""); flags = osEventFlagsGet(dummy_id); - zassert_true(flags == 0U, - "Invalid event Flags ID is unexpectedly working!"); + zassert_true(flags == 0U, "Invalid event Flags ID is unexpectedly working!"); /* Clear the Flag explicitly */ flags = osEventFlagsClear(evt_id, FLAG1); zassert_not_equal(flags, osFlagsErrorParameter, "Event clear failed"); @@ -135,34 +131,29 @@ void test_event_flags_signalled(void) * upon being set since "osFlagsNoClear" is not opted for. */ flags = osEventFlagsWait(evt_id, FLAG, osFlagsWaitAll, TIMEOUT_TICKS); - zassert_equal(flags & FLAG, FLAG, - "osEventFlagsWait failed unexpectedly"); + zassert_equal(flags & FLAG, FLAG, "osEventFlagsWait failed unexpectedly"); /* set any single flag */ flags = osEventFlagsSet(evt_id, FLAG1); zassert_equal(flags & FLAG1, FLAG1, "set any flag failed"); flags = osEventFlagsWait(evt_id, FLAG1, osFlagsWaitAny, TIMEOUT_TICKS); - zassert_equal(flags & FLAG1, FLAG1, - "osEventFlagsWait failed unexpectedly"); + zassert_equal(flags & FLAG1, FLAG1, "osEventFlagsWait failed unexpectedly"); /* validate by passing invalid parameters */ zassert_equal(osEventFlagsSet(NULL, 0), osFlagsErrorParameter, "Invalid event Flags ID is unexpectedly working!"); - zassert_equal(osEventFlagsSet(evt_id, 0x80010000), - osFlagsErrorParameter, + zassert_equal(osEventFlagsSet(evt_id, 0x80010000), osFlagsErrorParameter, "Event with MSB set is set unexpectedly"); zassert_equal(osEventFlagsClear(NULL, 0), osFlagsErrorParameter, "Invalid event Flags ID is unexpectedly working!"); - zassert_equal(osEventFlagsClear(evt_id, 0x80010000), - osFlagsErrorParameter, + zassert_equal(osEventFlagsClear(evt_id, 0x80010000), osFlagsErrorParameter, "Event with MSB set is cleared unexpectedly"); /* cannot wait for Flag mask with MSB set */ zassert_equal(osEventFlagsWait(evt_id, 0x80010000, osFlagsWaitAny, 0), - osFlagsErrorParameter, - "EventFlagsWait passed unexpectedly"); + osFlagsErrorParameter, "EventFlagsWait passed unexpectedly"); } /* IRQ offload function handler to set event flag */ @@ -174,8 +165,7 @@ static void offload_function(const void *param) zassert_true(k_is_in_isr(), "Not in IRQ context!"); flags = osEventFlagsSet((osEventFlagsId_t)param, ISR_FLAG); - zassert_equal(flags & ISR_FLAG, ISR_FLAG, - "EventFlagsSet failed in ISR"); + zassert_equal(flags & ISR_FLAG, ISR_FLAG, "EventFlagsSet failed in ISR"); } void test_event_from_isr(void *event_id) @@ -201,21 +191,17 @@ void test_event_flags_isr(void) id = osThreadNew(test_event_from_isr, evt_id, &thread3_attr); zassert_true(id != NULL, "Failed creating thread"); - flags = osEventFlagsWait(dummy_id, ISR_FLAG, - osFlagsWaitAll, TIMEOUT_TICKS); + flags = osEventFlagsWait(dummy_id, ISR_FLAG, osFlagsWaitAll, TIMEOUT_TICKS); zassert_true(flags == osFlagsErrorParameter, "Invalid event Flags ID is unexpectedly working!"); - flags = osEventFlagsWait(evt_id, ISR_FLAG, - osFlagsWaitAll, TIMEOUT_TICKS); - zassert_equal((flags & ISR_FLAG), - ISR_FLAG, "unexpected event flags value"); + flags = osEventFlagsWait(evt_id, ISR_FLAG, osFlagsWaitAll, TIMEOUT_TICKS); + zassert_equal((flags & ISR_FLAG), ISR_FLAG, "unexpected event flags value"); zassert_true(osEventFlagsDelete(dummy_id) == osErrorResource, "Invalid event Flags ID is unexpectedly working!"); - zassert_true(osEventFlagsDelete(evt_id) == osOK, - "EventFlagsDelete failed"); + zassert_true(osEventFlagsDelete(evt_id) == osOK, "EventFlagsDelete failed"); } ZTEST(cmsis_event_flags, test_event_flags) { diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/kernel.c b/tests/subsys/portability/cmsis_rtos_v2/src/kernel.c index 96071d0f1fc90..a8cf5a8af6336 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/kernel.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/kernel.c @@ -60,18 +60,12 @@ void lock_unlock_check(const void *arg) ZTEST(cmsis_kernel, test_kernel_apis) { versionInfo version = { - .os_info = { - .api = 0xfefefefe, - .kernel = 0xfdfdfdfd, - }, - .info = "local function call info is uninitialized" + .os_info = {.api = 0xfefefefe, .kernel = 0xfdfdfdfd}, + .info = "local function call info is uninitialized", }; versionInfo version_irq = { - .os_info = { - .api = 0xfcfcfcfc, - .kernel = 0xfbfbfbfb, - }, - .info = "irq_offload function call info is uninitialized" + .os_info = {.api = 0xfcfcfcfc, .kernel = 0xfbfbfbfb}, + .info = "irq_offload function call info is uninitialized", }; get_version_check(&version); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c b/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c index c0e4530f8648d..644e294090c9b 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c @@ -8,8 +8,8 @@ #include #include -#define MAX_BLOCKS 10 -#define TIMEOUT_TICKS 10 +#define MAX_BLOCKS 10 +#define TIMEOUT_TICKS 10 struct mem_block { int member1; @@ -26,8 +26,7 @@ static const osMemoryPoolAttr_t mp_attrs = { .mp_size = sizeof(struct mem_block) * MAX_BLOCKS, }; -static void mempool_common_tests(osMemoryPoolId_t mp_id, - const char *expected_name) +static void mempool_common_tests(osMemoryPoolId_t mp_id, const char *expected_name) { int i; osMemoryPoolId_t dummy_id = NULL; @@ -50,8 +49,7 @@ static void mempool_common_tests(osMemoryPoolId_t mp_id, zassert_equal(osMemoryPoolGetBlockSize(dummy_id), 0, "Something's wrong with osMemoryPoolGetBlockSize!"); - zassert_equal(osMemoryPoolGetBlockSize(mp_id), - sizeof(struct mem_block), + zassert_equal(osMemoryPoolGetBlockSize(mp_id), sizeof(struct mem_block), "Something's wrong with osMemoryPoolGetBlockSize!"); /* The memory pool should be completely available at this point */ @@ -61,8 +59,7 @@ static void mempool_common_tests(osMemoryPoolId_t mp_id, "Something's wrong with osMemoryPoolGetSpace!"); for (i = 0; i < MAX_BLOCKS; i++) { - addr_list[i] = (struct mem_block *)osMemoryPoolAlloc(mp_id, - osWaitForever); + addr_list[i] = (struct mem_block *)osMemoryPoolAlloc(mp_id, osWaitForever); zassert_true(addr_list[i] != NULL, "mempool allocation failed"); } @@ -75,13 +72,12 @@ static void mempool_common_tests(osMemoryPoolId_t mp_id, /* All blocks in mempool are allocated, any more allocation * without free should fail */ - addr_list[i] = (struct mem_block *)osMemoryPoolAlloc(mp_id, - TIMEOUT_TICKS); + addr_list[i] = (struct mem_block *)osMemoryPoolAlloc(mp_id, TIMEOUT_TICKS); zassert_true(addr_list[i] == NULL, "allocation happened." - " Something's wrong!"); + " Something's wrong!"); - zassert_equal(osMemoryPoolFree(dummy_id, addr_list[0]), - osErrorParameter, "mempool free worked unexpectedly!"); + zassert_equal(osMemoryPoolFree(dummy_id, addr_list[0]), osErrorParameter, + "mempool free worked unexpectedly!"); for (i = 0; i < MAX_BLOCKS; i++) { status = osMemoryPoolFree(mp_id, addr_list[i]); @@ -104,8 +100,7 @@ ZTEST(cmsis_mempool, test_mempool_dynamic) { osMemoryPoolId_t mp_id; - mp_id = osMemoryPoolNew(MAX_BLOCKS, sizeof(struct mem_block), - NULL); + mp_id = osMemoryPoolNew(MAX_BLOCKS, sizeof(struct mem_block), NULL); zassert_true(mp_id != NULL, "mempool creation failed"); mempool_common_tests(mp_id, "ZephyrMemPool"); @@ -121,12 +116,10 @@ ZTEST(cmsis_mempool, test_mempool) osMemoryPoolId_t mp_id; /* Create memory pool with invalid block size */ - mp_id = osMemoryPoolNew(MAX_BLOCKS + 1, sizeof(struct mem_block), - &mp_attrs); + mp_id = osMemoryPoolNew(MAX_BLOCKS + 1, sizeof(struct mem_block), &mp_attrs); zassert_true(mp_id == NULL, "osMemoryPoolNew worked unexpectedly!"); - mp_id = osMemoryPoolNew(MAX_BLOCKS, sizeof(struct mem_block), - &mp_attrs); + mp_id = osMemoryPoolNew(MAX_BLOCKS, sizeof(struct mem_block), &mp_attrs); zassert_true(mp_id != NULL, "mempool creation failed"); mempool_common_tests(mp_id, mp_attrs.name); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/msgq.c b/tests/subsys/portability/cmsis_rtos_v2/src/msgq.c index 0ec116e88e217..959e3bf8163d7 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/msgq.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/msgq.c @@ -14,11 +14,11 @@ struct sample_data { unsigned int data3; }; -#define MESSAGE1 512 -#define MESSAGE2 123456 -#define TIMEOUT_TICKS 50 -#define Q_LEN 5 -#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE +#define MESSAGE1 512 +#define MESSAGE2 123456 +#define TIMEOUT_TICKS 50 +#define Q_LEN 5 +#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE osMessageQueueId_t message_id; @@ -27,7 +27,7 @@ void send_msg_thread(void *argument) int i; osStatus_t status; struct sample_data sample; - struct sample_data data[Q_LEN] = { { 0 } }; + struct sample_data data[Q_LEN] = {{0}}; /* Wait for message_recv to complete initial checks */ osDelay(TIMEOUT_TICKS); @@ -48,10 +48,8 @@ void send_msg_thread(void *argument) data[i].data1 = i * 3; data[i].data2 = i * 3 + 1; data[i].data3 = i * 3 + 2; - status = osMessageQueuePut(message_id, data + i, - 0, osWaitForever); - zassert_true(status == osOK, - "osMessageQueuePut failure for message!"); + status = osMessageQueuePut(message_id, data + i, 0, osWaitForever); + zassert_true(status == osOK, "osMessageQueuePut failure for message!"); } /* The Queue should be full at this point */ @@ -65,22 +63,19 @@ void send_msg_thread(void *argument) */ sample.data1 = MESSAGE2; status = osMessageQueuePut(message_id, &sample, 0, 0); - zassert_true(status == osErrorResource, - "Something's wrong with osMessageQueuePut!"); + zassert_true(status == osErrorResource, "Something's wrong with osMessageQueuePut!"); /* Try putting message to a full queue within a duration * less than TIMEOUT_TICKS, before the queue is emptied out */ sample.data1 = MESSAGE2; status = osMessageQueuePut(message_id, &sample, 0, TIMEOUT_TICKS / 2); - zassert_true(status == osErrorTimeout, - "Something's wrong with osMessageQueuePut!"); + zassert_true(status == osErrorTimeout, "Something's wrong with osMessageQueuePut!"); /* Send another message after the queue is emptied */ sample.data1 = MESSAGE2; status = osMessageQueuePut(message_id, &sample, 0, TIMEOUT_TICKS * 2); - zassert_true(status == osOK, - "osMessageQueuePut failure for message!"); + zassert_true(status == osOK, "osMessageQueuePut failure for message!"); } void message_recv(void) @@ -91,25 +86,20 @@ void message_recv(void) /* Try getting message immediately before the queue is populated */ status = osMessageQueueGet(message_id, (void *)&recv_data, NULL, 0); - zassert_true(status == osErrorResource, - "Something's wrong with osMessageQueueGet!"); + zassert_true(status == osErrorResource, "Something's wrong with osMessageQueueGet!"); /* Try receiving message within a duration of TIMEOUT */ - status = osMessageQueueGet(message_id, (void *)&recv_data, - NULL, TIMEOUT_TICKS); - zassert_true(status == osErrorTimeout, - "Something's wrong with osMessageQueueGet!"); + status = osMessageQueueGet(message_id, (void *)&recv_data, NULL, TIMEOUT_TICKS); + zassert_true(status == osErrorTimeout, "Something's wrong with osMessageQueueGet!"); zassert_equal(osMessageQueueGetCapacity(message_id), Q_LEN, "Something's wrong with osMessageQueueGetCapacity!"); - zassert_equal(osMessageQueueGetMsgSize(message_id), - sizeof(struct sample_data), + zassert_equal(osMessageQueueGetMsgSize(message_id), sizeof(struct sample_data), "Something's wrong with osMessageQueueGetMsgSize!"); /* Receive 1st message */ - status = osMessageQueueGet(message_id, (void *)&recv_data, - NULL, osWaitForever); + status = osMessageQueueGet(message_id, (void *)&recv_data, NULL, osWaitForever); zassert_true(status == osOK, "osMessageQueueGet failure"); zassert_equal(recv_data.data1, MESSAGE1); @@ -118,8 +108,7 @@ void message_recv(void) /* Empty the queue */ for (i = 0; i < Q_LEN; i++) { - status = osMessageQueueGet(message_id, (void *)&recv_data, NULL, - osWaitForever); + status = osMessageQueueGet(message_id, (void *)&recv_data, NULL, osWaitForever); zassert_true(status == osOK, "osMessageQueueGet failure"); zassert_equal(recv_data.data1, i * 3); @@ -128,8 +117,7 @@ void message_recv(void) } /* Receive the next message */ - status = osMessageQueueGet(message_id, (void *)&recv_data, - NULL, osWaitForever); + status = osMessageQueueGet(message_id, (void *)&recv_data, NULL, osWaitForever); zassert_true(status == osOK, "osMessageQueueGet failure"); zassert_equal(recv_data.data1, MESSAGE2); } @@ -158,8 +146,7 @@ ZTEST(cmsis_msgq, test_messageq) struct sample_data sample; osThreadId_t tid; - message_id = osMessageQueueNew(Q_LEN, sizeof(struct sample_data), - &init_mem_attrs); + message_id = osMessageQueueNew(Q_LEN, sizeof(struct sample_data), &init_mem_attrs); zassert_true(message_id != NULL, "Message creation failed"); tid = osThreadNew(send_msg_thread, NULL, &thread_attr); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/mutex.c b/tests/subsys/portability/cmsis_rtos_v2/src/mutex.c index bfb1b0735d5e9..c9b4def0738f2 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/mutex.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/mutex.c @@ -8,17 +8,12 @@ #include #include -#define WAIT_TICKS 5 -#define TIMEOUT_TICKS (10 + WAIT_TICKS) -#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE +#define WAIT_TICKS 5 +#define TIMEOUT_TICKS (10 + WAIT_TICKS) +#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE int max_mtx_cnt = CONFIG_CMSIS_V2_MUTEX_MAX_COUNT; -const osMutexAttr_t mutex_attr = { - "myMutex", - osMutexRecursive | osMutexPrioInherit, - NULL, - 0U -}; +const osMutexAttr_t mutex_attr = {"myMutex", osMutexRecursive | osMutexPrioInherit, NULL, 0U}; void cleanup_max_mutex(osMutexId_t *mutex_ids) { @@ -59,8 +54,7 @@ ZTEST(cmsis_mutex, test_mutex) /* Try deleting invalid mutex object */ status = osMutexDelete(mutex_id); - zassert_true(status == osErrorParameter, - "Invalid Mutex deleted unexpectedly!"); + zassert_true(status == osErrorParameter, "Invalid Mutex deleted unexpectedly!"); mutex_id = osMutexNew(&mutex_attr); zassert_true(mutex_id != NULL, "Mutex1 creation failed"); @@ -124,8 +118,7 @@ void tThread_entry_lock_timeout(void *arg) zassert_true(status == osErrorResource, "Mutex unexpectedly released"); id = osMutexGetOwner((osMutexId_t)arg); - zassert_not_equal(id, osThreadGetId(), - "Unexpectedly, current thread is the mutex owner!"); + zassert_not_equal(id, osThreadGetId(), "Unexpectedly, current thread is the mutex owner!"); /* This delay ensures that the mutex gets released by the other * thread in the meantime @@ -141,17 +134,15 @@ void tThread_entry_lock_timeout(void *arg) } static K_THREAD_STACK_DEFINE(test_stack, STACKSZ); -static osThreadAttr_t thread_attr = { - .name = "Mutex_check", - .attr_bits = osThreadDetached, - .cb_mem = NULL, - .cb_size = 0, - .stack_mem = &test_stack, - .stack_size = STACKSZ, - .priority = osPriorityNormal, - .tz_module = 0, - .reserved = 0 -}; +static osThreadAttr_t thread_attr = {.name = "Mutex_check", + .attr_bits = osThreadDetached, + .cb_mem = NULL, + .cb_size = 0, + .stack_mem = &test_stack, + .stack_size = STACKSZ, + .priority = osPriorityNormal, + .tz_module = 0, + .reserved = 0}; ZTEST(cmsis_mutex, test_mutex_lock_timeout) { diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/semaphore.c b/tests/subsys/portability/cmsis_rtos_v2/src/semaphore.c index 9259cf69b47de..0dd9949345b21 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/semaphore.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/semaphore.c @@ -8,9 +8,9 @@ #include #include -#define WAIT_TICKS 5 -#define TIMEOUT_TICKS (10 + WAIT_TICKS) -#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE +#define WAIT_TICKS 5 +#define TIMEOUT_TICKS (10 + WAIT_TICKS) +#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE void thread_sema(void *arg) { @@ -18,13 +18,11 @@ void thread_sema(void *arg) /* Try taking semaphore immediately when it is not available */ status = osSemaphoreAcquire((osSemaphoreId_t)arg, 0); - zassert_true(status == osErrorResource, - "Semaphore acquired unexpectedly!"); + zassert_true(status == osErrorResource, "Semaphore acquired unexpectedly!"); /* Try taking semaphore after a TIMEOUT, but before release */ status = osSemaphoreAcquire((osSemaphoreId_t)arg, WAIT_TICKS); - zassert_true(status == osErrorTimeout, - "Semaphore acquired unexpectedly!"); + zassert_true(status == osErrorTimeout, "Semaphore acquired unexpectedly!"); /* This delay ensures that the semaphore gets released by the other * thread in the meantime @@ -37,34 +35,25 @@ void thread_sema(void *arg) status = osSemaphoreAcquire((osSemaphoreId_t)arg, 0); zassert_true(status == osOK, "Semaphore could not be acquired"); - zassert_true(osSemaphoreRelease((osSemaphoreId_t)arg) == osOK, - "Semaphore release failure"); + zassert_true(osSemaphoreRelease((osSemaphoreId_t)arg) == osOK, "Semaphore release failure"); /* Try releasing when no semaphore is obtained */ - zassert_true( - osSemaphoreRelease((osSemaphoreId_t)arg) == osErrorResource, - "Semaphore released unexpectedly!"); + zassert_true(osSemaphoreRelease((osSemaphoreId_t)arg) == osErrorResource, + "Semaphore released unexpectedly!"); } static K_THREAD_STACK_DEFINE(test_stack, STACKSZ); -static osThreadAttr_t thread_attr = { - .name = "Sema_check", - .attr_bits = osThreadDetached, - .cb_mem = NULL, - .cb_size = 0, - .stack_mem = &test_stack, - .stack_size = STACKSZ, - .priority = osPriorityNormal, - .tz_module = 0, - .reserved = 0 -}; - -const osSemaphoreAttr_t sema_attr = { - "mySemaphore", - 0, - NULL, - 0U -}; +static osThreadAttr_t thread_attr = {.name = "Sema_check", + .attr_bits = osThreadDetached, + .cb_mem = NULL, + .cb_size = 0, + .stack_mem = &test_stack, + .stack_size = STACKSZ, + .priority = osPriorityNormal, + .tz_module = 0, + .reserved = 0}; + +const osSemaphoreAttr_t sema_attr = {"mySemaphore", 0, NULL, 0U}; ZTEST(cmsis_semaphore, test_semaphore) { @@ -78,8 +67,7 @@ ZTEST(cmsis_semaphore, test_semaphore) zassert_true(semaphore_id != NULL, "semaphore creation failed"); name = osSemaphoreGetName(semaphore_id); - zassert_str_equal(sema_attr.name, name, - "Error getting Semaphore name"); + zassert_str_equal(sema_attr.name, name, "Error getting Semaphore name"); id = osThreadNew(thread_sema, semaphore_id, &thread_attr); zassert_true(id != NULL, "Thread creation failed"); @@ -87,8 +75,8 @@ ZTEST(cmsis_semaphore, test_semaphore) zassert_true(osSemaphoreGetCount(semaphore_id) == 1); /* Acquire invalid semaphore */ - zassert_equal(osSemaphoreAcquire(dummy_sem_id, osWaitForever), - osErrorParameter, "Semaphore wait worked unexpectedly"); + zassert_equal(osSemaphoreAcquire(dummy_sem_id, osWaitForever), osErrorParameter, + "Semaphore wait worked unexpectedly"); status = osSemaphoreAcquire(semaphore_id, osWaitForever); zassert_true(status == osOK, "Semaphore wait failure"); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/thread_apis.c b/tests/subsys/portability/cmsis_rtos_v2/src/thread_apis.c index ea73756a6631d..3529aa1a49cf5 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/thread_apis.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/thread_apis.c @@ -8,7 +8,7 @@ #include #include -#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE +#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE /* This is used to check the thread yield functionality between 2 threads */ static int thread_yield_check; @@ -78,15 +78,13 @@ static void thread2(void *argument) thread_array = k_calloc(max_num_threads, sizeof(osThreadId_t)); num_threads = osThreadEnumerate(thread_array, max_num_threads); - zassert_equal(num_threads, 2, - "Incorrect number of cmsis rtos v2 threads"); + zassert_equal(num_threads, 2, "Incorrect number of cmsis rtos v2 threads"); for (i = 0U; i < num_threads; i++) { uint32_t size = osThreadGetStackSize(thread_array[i]); uint32_t space = osThreadGetStackSpace(thread_array[i]); - zassert_true(space < size, - "stack size remaining is not what is expected"); + zassert_true(space < size, "stack size remaining is not what is expected"); } zassert_equal(osThreadGetState(thread_array[1]), osThreadReady, @@ -108,18 +106,13 @@ static void thread2(void *argument) osThreadYield(); } -static void thread_apis_common(int *yield_check, - const char *thread1_name, - osThreadAttr_t *thread1_attr, - osThreadAttr_t *thread2_attr) +static void thread_apis_common(int *yield_check, const char *thread1_name, + osThreadAttr_t *thread1_attr, osThreadAttr_t *thread2_attr) { osThreadId_t id1; osThreadId_t id2; - struct thread1_args args = { - .yield_check = yield_check, - .name = thread1_name - }; + struct thread1_args args = {.yield_check = yield_check, .name = thread1_name}; id1 = osThreadNew(thread1, &args, thread1_attr); zassert_true(id1 != NULL, "Failed creating thread1"); @@ -127,8 +120,7 @@ static void thread_apis_common(int *yield_check, id2 = osThreadNew(thread2, yield_check, thread2_attr); zassert_true(id2 != NULL, "Failed creating thread2"); - zassert_equal(osThreadGetCount(), 2, - "Incorrect number of cmsis rtos v2 threads"); + zassert_equal(osThreadGetCount(), 2, "Incorrect number of cmsis rtos v2 threads"); do { osDelay(100); @@ -137,14 +129,13 @@ static void thread_apis_common(int *yield_check, ZTEST(cmsis_thread_apis, test_thread_apis_dynamic) { - thread_apis_common(&thread_yield_check_dynamic, "ZephyrThread", - NULL, NULL); + thread_apis_common(&thread_yield_check_dynamic, "ZephyrThread", NULL, NULL); } ZTEST(cmsis_thread_apis, test_thread_apis) { - thread_apis_common(&thread_yield_check, os_thread1_attr.name, - &os_thread1_attr, &os_thread2_attr); + thread_apis_common(&thread_yield_check, os_thread1_attr.name, &os_thread1_attr, + &os_thread2_attr); } static osPriority_t OsPriorityInvalid = 60; @@ -172,28 +163,24 @@ static void thread3(void *argument) /* Lower the priority of the current thread */ osThreadSetPriority(id, osPriorityBelowNormal); rv = osThreadGetPriority(id); - zassert_equal(rv, osPriorityBelowNormal, - "Expected priority to be changed to %d, not %d", + zassert_equal(rv, osPriorityBelowNormal, "Expected priority to be changed to %d, not %d", (int)osPriorityBelowNormal, (int)rv); /* Increase the priority of the current thread */ osThreadSetPriority(id, osPriorityAboveNormal); rv = osThreadGetPriority(id); - zassert_equal(rv, osPriorityAboveNormal, - "Expected priority to be changed to %d, not %d", + zassert_equal(rv, osPriorityAboveNormal, "Expected priority to be changed to %d, not %d", (int)osPriorityAboveNormal, (int)rv); /* Restore the priority of the current thread */ osThreadSetPriority(id, prio); rv = osThreadGetPriority(id); - zassert_equal(rv, prio, - "Expected priority to be changed to %d, not %d", - (int)prio, (int)rv); + zassert_equal(rv, prio, "Expected priority to be changed to %d, not %d", (int)prio, + (int)rv); /* Try to set unsupported priority and assert failure */ status = osThreadSetPriority(id, OsPriorityInvalid); - zassert_true(status == osErrorParameter, - "Something's wrong with osThreadSetPriority!"); + zassert_true(status == osErrorParameter, "Something's wrong with osThreadSetPriority!"); /* Indication that thread3 is done with its processing */ *state = 1; @@ -224,13 +211,11 @@ static void thread_prior_common(int *state, osThreadAttr_t *attr) /* Try to set priority to inactive thread and assert failure */ status = osThreadSetPriority(id3, osPriorityNormal); - zassert_true(status == osErrorResource, - "Something's wrong with osThreadSetPriority!"); + zassert_true(status == osErrorResource, "Something's wrong with osThreadSetPriority!"); /* Try to terminate inactive thread and assert failure */ status = osThreadTerminate(id3); - zassert_true(status == osErrorResource, - "Something's wrong with osThreadTerminate!"); + zassert_true(status == osErrorResource, "Something's wrong with osThreadTerminate!"); *state = 0; } @@ -268,7 +253,7 @@ static void thread4(void *argument) ZTEST(cmsis_thread_apis, test_thread_join) { - osThreadAttr_t attr = { 0 }; + osThreadAttr_t attr = {0}; int64_t time_stamp; int64_t milliseconds_spent; osThreadId_t tA, tB; @@ -297,7 +282,7 @@ ZTEST(cmsis_thread_apis, test_thread_join) milliseconds_spent = k_uptime_delta(&time_stamp); zassert_true((milliseconds_spent >= DELAY_MS - DELTA_MS) && - (milliseconds_spent <= DELAY_MS + DELTA_MS), + (milliseconds_spent <= DELAY_MS + DELTA_MS), "Join completed but was too fast or too slow."); printk(" - Waiting for thread A to join...\n"); @@ -320,8 +305,7 @@ ZTEST(cmsis_thread_apis, test_thread_detached) osDelay(k_ms_to_ticks_ceil32(DELAY_MS - DELTA_MS)); status = osThreadJoin(thread); - zassert_equal(status, osErrorResource, - "Incorrect status returned from osThreadJoin!"); + zassert_equal(status, osErrorResource, "Incorrect status returned from osThreadJoin!"); osDelay(k_ms_to_ticks_ceil32(DELTA_MS)); } @@ -332,13 +316,12 @@ void thread6(void *argument) osStatus_t status; status = osThreadJoin(thread); - zassert_equal(status, osErrorResource, - "Incorrect status returned from osThreadJoin!"); + zassert_equal(status, osErrorResource, "Incorrect status returned from osThreadJoin!"); } ZTEST(cmsis_thread_apis, test_thread_joinable_detach) { - osThreadAttr_t attr = { 0 }; + osThreadAttr_t attr = {0}; osThreadId_t tA, tB; osStatus_t status; @@ -360,7 +343,7 @@ ZTEST(cmsis_thread_apis, test_thread_joinable_detach) ZTEST(cmsis_thread_apis, test_thread_joinable_terminate) { - osThreadAttr_t attr = { 0 }; + osThreadAttr_t attr = {0}; osThreadId_t tA, tB; osStatus_t status; diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/thread_flags.c b/tests/subsys/portability/cmsis_rtos_v2/src/thread_flags.c index 8b84cd2e8eae9..9473d5a22630d 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/thread_flags.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/thread_flags.c @@ -11,12 +11,12 @@ #include #include -#define TIMEOUT_TICKS (10) -#define FLAG1 (0x00000020) -#define FLAG2 (0x00000004) -#define FLAG (FLAG1 | FLAG2) -#define ISR_FLAG (0x50) -#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE +#define TIMEOUT_TICKS (10) +#define FLAG1 (0x00000020) +#define FLAG2 (0x00000004) +#define FLAG (FLAG1 | FLAG2) +#define ISR_FLAG (0x50) +#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE static void thread1(void *arg) { @@ -36,8 +36,7 @@ static void thread1(void *arg) /* Clear the Flag explicitly */ flags = osThreadFlagsClear(FLAG1); - zassert_not_equal(flags, osFlagsErrorParameter, - "ThreadFlagsClear failed"); + zassert_not_equal(flags, osFlagsErrorParameter, "ThreadFlagsClear failed"); /* wait for FLAG1. It should timeout here as the flag * though triggered, gets cleared in the previous step. @@ -51,22 +50,19 @@ static void thread2(void *arg) uint32_t flags; flags = osThreadFlagsWait(FLAG, osFlagsWaitAll, TIMEOUT_TICKS); - zassert_equal(flags & FLAG, FLAG, - "osThreadFlagsWait failed unexpectedly"); + zassert_equal(flags & FLAG, FLAG, "osThreadFlagsWait failed unexpectedly"); /* validate by passing invalid parameters */ zassert_equal(osThreadFlagsSet(NULL, 0), osFlagsErrorParameter, "Invalid Thread Flags ID is unexpectedly working!"); - zassert_equal(osThreadFlagsSet(osThreadGetId(), 0x80010000), - osFlagsErrorParameter, + zassert_equal(osThreadFlagsSet(osThreadGetId(), 0x80010000), osFlagsErrorParameter, "Thread with MSB set is set unexpectedly"); zassert_equal(osThreadFlagsClear(0x80010000), osFlagsErrorParameter, "Thread with MSB set is cleared unexpectedly"); /* cannot wait for Flag mask with MSB set */ - zassert_equal(osThreadFlagsWait(0x80010000, osFlagsWaitAny, 0), - osFlagsErrorParameter, + zassert_equal(osThreadFlagsWait(0x80010000, osFlagsWaitAny, 0), osFlagsErrorParameter, "ThreadFlagsWait passed unexpectedly"); } @@ -134,8 +130,7 @@ static void offload_function(const void *param) zassert_true(k_is_in_isr(), "Not in IRQ context!"); flags = osThreadFlagsSet((osThreadId_t)param, ISR_FLAG); - zassert_equal(flags & ISR_FLAG, ISR_FLAG, - "ThreadFlagsSet failed in ISR"); + zassert_equal(flags & ISR_FLAG, ISR_FLAG, "ThreadFlagsSet failed in ISR"); } void test_thread_flags_from_isr(void *thread_id) @@ -146,8 +141,7 @@ void test_thread_flags_from_isr(void *thread_id) irq_offload(offload_function, (const void *)osThreadGetId()); flags = osThreadFlagsWait(ISR_FLAG, osFlagsWaitAll, TIMEOUT_TICKS); - zassert_equal((flags & ISR_FLAG), - ISR_FLAG, "unexpected Thread flags value"); + zassert_equal((flags & ISR_FLAG), ISR_FLAG, "unexpected Thread flags value"); } static K_THREAD_STACK_DEFINE(test_stack3, STACKSZ); @@ -162,8 +156,7 @@ ZTEST(cmsis_thread_flags, test_thread_flags_isr) { osThreadId_t id; - id = osThreadNew(test_thread_flags_from_isr, osThreadGetId(), - &thread3_attr); + id = osThreadNew(test_thread_flags_from_isr, osThreadGetId(), &thread3_attr); zassert_true(id != NULL, "Failed creating thread"); osDelay(TIMEOUT_TICKS); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/timer.c b/tests/subsys/portability/cmsis_rtos_v2/src/timer.c index 35ab88ed17417..512b81de1d10f 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/timer.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/timer.c @@ -7,27 +7,21 @@ #include #include -#define ONESHOT_TIME_TICKS 100 -#define PERIOD_TICKS MAX(50, k_ms_to_ticks_ceil32(10)) -#define NUM_PERIODS 5 +#define ONESHOT_TIME_TICKS 100 +#define PERIOD_TICKS MAX(50, k_ms_to_ticks_ceil32(10)) +#define NUM_PERIODS 5 uint32_t num_oneshots_executed; uint32_t num_periods_executed; -const osTimerAttr_t timer_attr = { - "myTimer", - 0, - NULL, - 0U -}; +const osTimerAttr_t timer_attr = {"myTimer", 0, NULL, 0U}; void Timer1_Callback(void *arg) { uint32_t Tmr = *(uint32_t *)arg; num_oneshots_executed++; - TC_PRINT("oneshot_callback (Timer %d) = %d\n", - Tmr, num_oneshots_executed); + TC_PRINT("oneshot_callback (Timer %d) = %d\n", Tmr, num_oneshots_executed); } void Timer2_Callback(void *arg) @@ -35,8 +29,7 @@ void Timer2_Callback(void *arg) uint32_t Tmr = *(uint32_t *)arg; num_periods_executed++; - TC_PRINT("periodic_callback (Timer %d) = %d\n", - Tmr, num_periods_executed); + TC_PRINT("periodic_callback (Timer %d) = %d\n", Tmr, num_periods_executed); } ZTEST(cmsis_timer, test_timer) @@ -59,8 +52,7 @@ ZTEST(cmsis_timer, test_timer) /* Stop the timer before start */ status = osTimerStop(id1); - zassert_true(status == osErrorResource, - "error while stopping non-active timer"); + zassert_true(status == osErrorResource, "error while stopping non-active timer"); timerDelay = ONESHOT_TIME_TICKS; status = osTimerStart(id1, timerDelay); @@ -73,8 +65,7 @@ ZTEST(cmsis_timer, test_timer) * if it fires more than once. */ osDelay(timerDelay * 3U + 10); - zassert_true(num_oneshots_executed == 1U, - "error setting up one-shot timer"); + zassert_true(num_oneshots_executed == 1U, "error setting up one-shot timer"); status = osTimerStop(id1); zassert_true(status == osOK, "error stopping one-shot timer"); @@ -99,8 +90,7 @@ ZTEST(cmsis_timer, test_timer) */ osDelay(timerDelay * NUM_PERIODS + 10); - zassert_true(num_periods_executed == NUM_PERIODS, - "error setting up periodic timer"); + zassert_true(num_periods_executed == NUM_PERIODS, "error setting up periodic timer"); /* Delete the timer before stop */ status = osTimerDelete(id2); From 66c43a8f776afb147adb781fc04fb9de84bc0fda Mon Sep 17 00:00:00 2001 From: Utsav Munendra Date: Mon, 20 Jan 2025 21:05:04 -0800 Subject: [PATCH 0134/6055] tests: portability: cmsis: Add tests for CMSIS-RTOSv2 static cb Every CMSIS-RTOSv2 now supports static allocation control blocks. Add tests for this. Signed-off-by: Utsav Munendra --- .../subsys/portability/cmsis_rtos_v2/prj.conf | 2 +- .../cmsis_rtos_v2/src/event_flags.c | 20 ++++++++++++- .../portability/cmsis_rtos_v2/src/mempool.c | 27 +++++++++++++++++- .../portability/cmsis_rtos_v2/src/msgq.c | 26 +++++++++++++++-- .../portability/cmsis_rtos_v2/src/mutex.c | 20 ++++++++++++- .../portability/cmsis_rtos_v2/src/semaphore.c | 20 ++++++++++++- .../cmsis_rtos_v2/src/thread_apis.c | 25 ++++++++++++++++- .../portability/cmsis_rtos_v2/src/timer.c | 28 +++++++++++++++++-- 8 files changed, 157 insertions(+), 11 deletions(-) diff --git a/tests/subsys/portability/cmsis_rtos_v2/prj.conf b/tests/subsys/portability/cmsis_rtos_v2/prj.conf index d8e93b747852a..d11349d09940c 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/prj.conf +++ b/tests/subsys/portability/cmsis_rtos_v2/prj.conf @@ -11,7 +11,7 @@ CONFIG_INIT_STACKS=y CONFIG_MAX_THREAD_BYTES=4 CONFIG_SCHED_SCALABLE=y CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE=128 -CONFIG_CMSIS_V2_THREAD_MAX_COUNT=23 +CONFIG_CMSIS_V2_THREAD_MAX_COUNT=24 CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT=10 CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE=1024 CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE=1024 diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/event_flags.c b/tests/subsys/portability/cmsis_rtos_v2/src/event_flags.c index 77d07ae03181b..9d84d6b9d4ef1 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/event_flags.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/event_flags.c @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include #include @@ -214,4 +215,21 @@ ZTEST(cmsis_event_flags, test_event_flags) test_event_flags_signalled(); test_event_flags_isr(); } + +static struct cmsis_rtos_event_cb event_cb2; +static const osEventFlagsAttr_t event_flags_attrs2 = { + .name = "Event2", + .attr_bits = 0, + .cb_mem = &event_cb2, + .cb_size = sizeof(event_cb2), +}; +ZTEST(cmsis_event_flags, test_event_flags_static_allocation) +{ + osEventFlagsId_t id; + + id = osEventFlagsNew(&event_flags_attrs2); + zassert_not_null(id, "Failed creating event flags using static cb"); + + zassert_true(osEventFlagsDelete(evt_id) == osOK, "EventFlagsDelete failed"); +} ZTEST_SUITE(cmsis_event_flags, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c b/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c index 644e294090c9b..26cccb56f2a76 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #define MAX_BLOCKS 10 #define TIMEOUT_TICKS 10 @@ -124,4 +125,28 @@ ZTEST(cmsis_mempool, test_mempool) mempool_common_tests(mp_id, mp_attrs.name); } + +static struct cmsis_rtos_mempool_cb mempool_cb2; +static const osMemoryPoolAttr_t mp_attrs2 = { + .name = "TestMempool2", + .attr_bits = 0, + .cb_mem = &mempool_cb2, + .cb_size = sizeof(mempool_cb2), + .mp_mem = sample_mem, + .mp_size = sizeof(struct mem_block) * MAX_BLOCKS, +}; +/** + * @brief Test memory pool allocation and free + * + * @see osMemoryPoolNew(), osMemoryPoolAlloc(), osMemoryPoolFree(), + */ +ZTEST(cmsis_mempool, test_mempool_static_allocation) +{ + osMemoryPoolId_t mp_id; + + mp_id = osMemoryPoolNew(MAX_BLOCKS, sizeof(struct mem_block), &mp_attrs2); + zassert_true(mp_id != NULL, "mempool creation failed"); + + mempool_common_tests(mp_id, mp_attrs2.name); +} ZTEST_SUITE(cmsis_mempool, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/msgq.c b/tests/subsys/portability/cmsis_rtos_v2/src/msgq.c index 959e3bf8163d7..ae0a2e7df8590 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/msgq.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/msgq.c @@ -6,7 +6,8 @@ #include #include -#include +#include +#include struct sample_data { int data1; @@ -147,7 +148,7 @@ ZTEST(cmsis_msgq, test_messageq) osThreadId_t tid; message_id = osMessageQueueNew(Q_LEN, sizeof(struct sample_data), &init_mem_attrs); - zassert_true(message_id != NULL, "Message creation failed"); + zassert_true(message_id != NULL, "Message Queue creation failed"); tid = osThreadNew(send_msg_thread, NULL, &thread_attr); zassert_true(tid != NULL, "Thread creation failed"); @@ -180,4 +181,25 @@ ZTEST(cmsis_msgq, test_messageq) status = osMessageQueueDelete(message_id); zassert_true(status == osOK, "osMessageQueueDelete failure"); } + +static struct cmsis_rtos_msgq_cb msgq_cb2; +static const osMessageQueueAttr_t msgq_attrs2 = { + .name = "TestMsgQ2", + .attr_bits = 0, + .cb_mem = &msgq_cb2, + .cb_size = sizeof(msgq_cb2), + .mq_mem = sample_mem, + .mq_size = sizeof(struct sample_data) * Q_LEN, +}; +ZTEST(cmsis_msgq, test_messageq_static_allocation) +{ + osMessageQueueId_t message_id; + osStatus_t status; + + message_id = osMessageQueueNew(Q_LEN, sizeof(struct sample_data), &msgq_attrs2); + zassert_true(message_id != NULL, "Message Queue creation failed with static cb"); + + status = osMessageQueueDelete(message_id); + zassert_true(status == osOK, "osMessageQueueDelete failure"); +} ZTEST_SUITE(cmsis_msgq, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/mutex.c b/tests/subsys/portability/cmsis_rtos_v2/src/mutex.c index c9b4def0738f2..b93e226671882 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/mutex.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/mutex.c @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #define WAIT_TICKS 5 #define TIMEOUT_TICKS (10 + WAIT_TICKS) @@ -168,4 +169,21 @@ ZTEST(cmsis_mutex, test_mutex_lock_timeout) osMutexDelete(mutex_id); } + +static struct cmsis_rtos_mutex_cb mutex_cb2; +static const osMutexAttr_t mutex_attrs2 = { + .name = "Mutex2", + .attr_bits = osMutexPrioInherit, + .cb_mem = &mutex_cb2, + .cb_size = sizeof(mutex_cb2), +}; +ZTEST(cmsis_mutex, test_mutex_static_allocation) +{ + osMutexId_t id; + + id = osMutexNew(&mutex_attrs2); + zassert_not_null(id, "Failed creating mutex using static cb"); + + zassert_true(osMutexDelete(id) == osOK, "osMutexDelete failed"); +} ZTEST_SUITE(cmsis_mutex, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/semaphore.c b/tests/subsys/portability/cmsis_rtos_v2/src/semaphore.c index 0dd9949345b21..9258b62588827 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/semaphore.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/semaphore.c @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #define WAIT_TICKS 5 #define TIMEOUT_TICKS (10 + WAIT_TICKS) @@ -103,4 +104,21 @@ ZTEST(cmsis_semaphore, test_semaphore) status = osSemaphoreDelete(semaphore_id); zassert_true(status == osOK, "semaphore delete failure"); } + +static struct cmsis_rtos_semaphore_cb semaphore_cb2; +static const osSemaphoreAttr_t semaphore_attrs2 = { + .name = "Semaphore2", + .attr_bits = 0, + .cb_mem = &semaphore_cb2, + .cb_size = sizeof(semaphore_cb2), +}; +ZTEST(cmsis_semaphore, test_semaphore_static_allocation) +{ + osSemaphoreId_t id; + + id = osSemaphoreNew(1, 1, &semaphore_attrs2); + zassert_not_null(id, "Failed creating semaphores using static cb"); + + zassert_true(osSemaphoreDelete(id) == osOK, "semaphore delete failure"); +} ZTEST_SUITE(cmsis_semaphore, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/thread_apis.c b/tests/subsys/portability/cmsis_rtos_v2/src/thread_apis.c index 3529aa1a49cf5..8dc40747723cd 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/thread_apis.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/thread_apis.c @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE @@ -362,4 +363,26 @@ ZTEST(cmsis_thread_apis, test_thread_joinable_terminate) osDelay(k_ms_to_ticks_ceil32(DELTA_MS)); } + +static K_THREAD_STACK_DEFINE(test_stack7, STACKSZ); +static struct cmsis_rtos_thread_cb test_cb7; +static const osThreadAttr_t os_thread7_attr = { + .name = "Thread7", + .cb_mem = &test_cb7, + .cb_size = sizeof(test_cb7), + .stack_mem = &test_stack7, + .stack_size = STACKSZ, + .priority = osPriorityNormal, +}; +static void thread7(void *argument) +{ + printf("Thread 7 ran\n"); +} +ZTEST(cmsis_thread_apis, test_thread_apis_static_allocation) +{ + osThreadId_t id; + + id = osThreadNew(thread7, NULL, &os_thread7_attr); + zassert_not_null(id, "Failed to create thread with osThreadNew using static cb/stack"); +} ZTEST_SUITE(cmsis_thread_apis, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/timer.c b/tests/subsys/portability/cmsis_rtos_v2/src/timer.c index 512b81de1d10f..831c76bf32a59 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/timer.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/timer.c @@ -5,7 +5,8 @@ */ #include -#include +#include +#include #define ONESHOT_TIME_TICKS 100 #define PERIOD_TICKS MAX(50, k_ms_to_ticks_ceil32(10)) @@ -16,7 +17,7 @@ uint32_t num_periods_executed; const osTimerAttr_t timer_attr = {"myTimer", 0, NULL, 0U}; -void Timer1_Callback(void *arg) +static void Timer1_Callback(void *arg) { uint32_t Tmr = *(uint32_t *)arg; @@ -24,7 +25,7 @@ void Timer1_Callback(void *arg) TC_PRINT("oneshot_callback (Timer %d) = %d\n", Tmr, num_oneshots_executed); } -void Timer2_Callback(void *arg) +static void Timer2_Callback(void *arg) { uint32_t Tmr = *(uint32_t *)arg; @@ -96,4 +97,25 @@ ZTEST(cmsis_timer, test_timer) status = osTimerDelete(id2); zassert_true(status == osOK, "error deleting periodic timer"); } + +static struct cmsis_rtos_timer_cb timer_cb3; +static const osTimerAttr_t timer_attr3 = { + .name = "Timer3", + .cb_mem = &timer_cb3, + .cb_size = sizeof(timer_cb3), +}; +static void Timer3_Callback(void *arg) +{ + printf("Timer3 callback ran\n"); +} +ZTEST(cmsis_timer, test_timer_static_allocation) +{ + osTimerId_t id; + osStatus_t status; + + id = osTimerNew(Timer3_Callback, osTimerOnce, NULL, &timer_attr3); + zassert_true(id != NULL, "error creating timer with static cb"); + status = osTimerDelete(id); + zassert_true(status == osOK, "error timer with static cb"); +} ZTEST_SUITE(cmsis_timer, NULL, NULL, NULL, NULL, NULL); From 104fa969c65fa253cf144eaaab1258672de9cf0f Mon Sep 17 00:00:00 2001 From: Pierrick Curt Date: Sun, 26 Jan 2025 17:05:35 +0100 Subject: [PATCH 0135/6055] samples: sensor: accel_trig: add sample tap detection feature. Add the tap detection trigger to the existing example. For this example it uses lis2dw12 accelerometer to detect a double tap. This feature can be enabled with CONFIG_SAMPLE_TAP_DETECTION option. Signed-off-by: Pierrick Curt --- samples/sensor/accel_trig/Kconfig | 13 ++++++ samples/sensor/accel_trig/README.rst | 46 ++++++++++++++++++- .../boards/nrf52dk_nrf52832.overlay | 20 ++++++++ .../accel_trig/boards/stm32f3_disco.conf | 4 ++ .../accel_trig/boards/stm32f3_disco.overlay | 33 +++++++++++++ samples/sensor/accel_trig/src/main.c | 23 ++++++++++ 6 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 samples/sensor/accel_trig/Kconfig create mode 100644 samples/sensor/accel_trig/boards/nrf52dk_nrf52832.overlay create mode 100644 samples/sensor/accel_trig/boards/stm32f3_disco.conf create mode 100644 samples/sensor/accel_trig/boards/stm32f3_disco.overlay diff --git a/samples/sensor/accel_trig/Kconfig b/samples/sensor/accel_trig/Kconfig new file mode 100644 index 0000000000000..ec0fa9d253e80 --- /dev/null +++ b/samples/sensor/accel_trig/Kconfig @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 Pierrick Curt +# +# SPDX-License-Identifier: Apache-2.0 +# + +mainmenu "Accelerometer trigger sample application" + +config SAMPLE_TAP_DETECTION + bool "Set tap detection as trigger in the sample" + default n + +source "Kconfig.zephyr" diff --git a/samples/sensor/accel_trig/README.rst b/samples/sensor/accel_trig/README.rst index 37a3f18e8c8e5..1933edf1671e5 100644 --- a/samples/sensor/accel_trig/README.rst +++ b/samples/sensor/accel_trig/README.rst @@ -7,6 +7,10 @@ Overview ******** This sample application demonstrates how to use 3-Axis accelerometers with triggers. +By default it uses a data ready trigger to read the accelerometer data and print it to the console. + +If the accelerometer is enabled with a tap trigger, the sample uses the tap trigger event to +read the accelerometer data and print it to the console. Building and Running ******************** @@ -27,8 +31,21 @@ Make sure the aliases are in devicetree, then build and run with: :goals: build flash :compact: -Sample Output -============= +With this example, you can also detect a double tap with an accelerometer by activating the +:kconfig:option:`CONFIG_SAMPLE_TAP_DETECTION`. +In this example we use a x_nucleo_iks01a3 shield with a LIS2DW12 accelerometer. +You can build it with the following command: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/accel_trig + :board: nrf52dk/nrf52832 + :shield: x_nucleo_iks01a3 + :goals: build + :compact: + + +Sample Output (SENSOR_TRIG_DATA_READY) +======================================= .. code-block:: console @@ -43,3 +60,28 @@ Sample Output fxos8700@1d [m/s^2]: ( -0.105345, -0.028731, 9.921571) fxos8700@1d [m/s^2]: ( -0.095769, -0.028731, 9.931148) fxos8700@1d [m/s^2]: ( -0.095769, -0.009577, 9.940725) + + +Sample Output (SENSOR_TRIG_DOUBLE_TAP) +====================================== + +.. code-block:: console + + TAP detected + lis2dw12@19 [m/s^2]: ( -1.899901, -12.550355, -2.742174) + TAP detected + lis2dw12@19 [m/s^2]: ( 12.349357, -18.125630, 6.015556) + TAP detected + lis2dw12@19 [m/s^2]: ( -11.385050, -7.274181, -9.229117) + TAP detected + lis2dw12@19 [m/s^2]: ( 9.214760, -9.286545, 2.311466) + TAP detected + lis2dw12@19 [m/s^2]: ( 10.090533, -17.391034, 12.320643) + TAP detected + lis2dw12@19 [m/s^2]: ( -0.478564, 2.390429, 15.876378) + TAP detected + lis2dw12@19 [m/s^2]: ( -5.668596, -13.138989, 0.741775) + TAP detected + lis2dw12@19 [m/s^2]: ( -2.385644, -10.559526, 9.899107) + TAP detected + lis2dw12@19 [m/s^2]: ( 7.537391, -8.551948, 16.740187) diff --git a/samples/sensor/accel_trig/boards/nrf52dk_nrf52832.overlay b/samples/sensor/accel_trig/boards/nrf52dk_nrf52832.overlay new file mode 100644 index 0000000000000..f33cce2022116 --- /dev/null +++ b/samples/sensor/accel_trig/boards/nrf52dk_nrf52832.overlay @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Pierrick Curt + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +&lis2dw12_19_x_nucleo_iks01a3 { + status = "okay"; + compatible = "st,lis2dw12"; + reg = <0x19>; + odr = <400>; + tap-mode = ; + tap-threshold = <12>, <12>, <12>; + power-mode = ; + tap-shock = <0x03>; + tap-quiet = <0x03>; + tap-latency = <0x03>; + irq-gpios = <&arduino_header 3 GPIO_ACTIVE_HIGH>; /* A3 */ +}; diff --git a/samples/sensor/accel_trig/boards/stm32f3_disco.conf b/samples/sensor/accel_trig/boards/stm32f3_disco.conf new file mode 100644 index 0000000000000..67dc73ec34251 --- /dev/null +++ b/samples/sensor/accel_trig/boards/stm32f3_disco.conf @@ -0,0 +1,4 @@ +CONFIG_I2C=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD=y +CONFIG_LIS2DW12_TAP=y diff --git a/samples/sensor/accel_trig/boards/stm32f3_disco.overlay b/samples/sensor/accel_trig/boards/stm32f3_disco.overlay new file mode 100644 index 0000000000000..79d5a106a8894 --- /dev/null +++ b/samples/sensor/accel_trig/boards/stm32f3_disco.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, Pierrick Curt. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + accel0 = &lis2dw12_accel; + }; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_pa9 &i2c2_sda_pa10>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; + + lis2dw12_accel: lis2dw12@19 { + compatible = "st,lis2dw12"; + reg = <0x19>; + odr = <400>; + tap-mode = ; + tap-threshold = <12>, <12>, <12>; + power-mode = ; + tap-shock = <0x03>; + tap-quiet = <0x03>; + tap-latency = <0x03>; + irq-gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/samples/sensor/accel_trig/src/main.c b/samples/sensor/accel_trig/src/main.c index e5ddde1e2bef3..6f56cc1e9d51e 100644 --- a/samples/sensor/accel_trig/src/main.c +++ b/samples/sensor/accel_trig/src/main.c @@ -11,6 +11,19 @@ K_SEM_DEFINE(sem, 0, 1); /* starts off "not available" */ +#ifdef CONFIG_SAMPLE_TAP_DETECTION +static void tap_trigger_handler(const struct device *dev, const struct sensor_trigger *trigger) +{ + ARG_UNUSED(trigger); + printf("TAP detected\n"); + + if (sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ) < 0) { + printf("ERROR: SENSOR_CHAN_ACCEL_XYZ fetch failed\n"); + } + + k_sem_give(&sem); +} +#else static void trigger_handler(const struct device *dev, const struct sensor_trigger *trigger) { ARG_UNUSED(trigger); @@ -25,6 +38,7 @@ static void trigger_handler(const struct device *dev, const struct sensor_trigge k_sem_give(&sem); } +#endif int main(void) { @@ -41,10 +55,19 @@ int main(void) return 0; } +#ifdef CONFIG_SAMPLE_TAP_DETECTION + trig.type = SENSOR_TRIG_DOUBLE_TAP; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + if (sensor_trigger_set(dev, &trig, tap_trigger_handler) < 0) { + printf("Could not set tap trigger\n"); + return 0; + } +#else if (sensor_trigger_set(dev, &trig, trigger_handler)) { printf("Could not set trigger\n"); return 0; } +#endif while (1) { k_sem_take(&sem, K_FOREVER); From 27c41b42c1aa6a72615aa36313dfd853c5777297 Mon Sep 17 00:00:00 2001 From: Andrew Featherstone Date: Sun, 2 Feb 2025 10:54:20 +0000 Subject: [PATCH 0136/6055] drivers: gpio_rpi_pico: Support GPIO_DISCONNECTED flag Out of reset the pads are input enabled, output disabled. Disconnect the pad's input and output buffers, as well as any pullups. This can reduce input leakage current. Signed-off-by: Andrew Featherstone --- drivers/gpio/gpio_rpi_pico.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio_rpi_pico.c b/drivers/gpio/gpio_rpi_pico.c index 1950144cc7260..93927f93fa120 100644 --- a/drivers/gpio/gpio_rpi_pico.c +++ b/drivers/gpio/gpio_rpi_pico.c @@ -39,8 +39,15 @@ static int gpio_rpi_configure(const struct device *dev, { struct gpio_rpi_data *data = dev->data; - if ((flags & GPIO_DIR_MASK) == GPIO_DISCONNECTED) { - return -ENOTSUP; + if (flags == GPIO_DISCONNECTED) { + gpio_disable_pulls(pin); + /* This is almost the opposite of the Pico SDK's gpio_set_function. */ + hw_write_masked(&pads_bank0_hw->io[pin], PADS_BANK0_GPIO0_OD_BITS, + PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); +#ifdef SOC_SERIES_RP2350 + hw_set_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_ISO_BITS); +#endif + return 0; } gpio_set_pulls(pin, From 608e6a30b151ad04fc8b582e91892666a432be68 Mon Sep 17 00:00:00 2001 From: Andrew Featherstone Date: Sun, 2 Feb 2025 16:40:28 +0000 Subject: [PATCH 0137/6055] drivers: gpio_rpi_pico: Disable inputs when not in use Reorder gpio_rpi_configure to disable input buffers when not in use. gpio_rpi_get_config can then determine whether a pin is configured as an input without requiring additional state variables, as well as reducing input leakage current. Signed-off-by: Andrew Featherstone --- drivers/gpio/gpio_rpi_pico.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio_rpi_pico.c b/drivers/gpio/gpio_rpi_pico.c index 93927f93fa120..d0c07b7e80b8c 100644 --- a/drivers/gpio/gpio_rpi_pico.c +++ b/drivers/gpio/gpio_rpi_pico.c @@ -57,6 +57,12 @@ static int gpio_rpi_configure(const struct device *dev, /* Avoid gpio_init, since that also clears previously set direction/high/low */ gpio_set_function(pin, GPIO_FUNC_SIO); + if (flags & GPIO_INPUT) { + gpio_set_dir(pin, GPIO_IN); + } else { + gpio_set_input_enabled(pin, false); + } + if (flags & GPIO_OUTPUT) { if (flags & GPIO_SINGLE_ENDED) { data->single_ended_mask |= BIT(pin); @@ -84,8 +90,6 @@ static int gpio_rpi_configure(const struct device *dev, } gpio_set_dir(pin, GPIO_OUT); } - } else if (flags & GPIO_INPUT) { - gpio_set_dir(pin, GPIO_IN); } return 0; From 91c4c4363e1bb0e7aa44802c599768286fe511a7 Mon Sep 17 00:00:00 2001 From: Andrew Featherstone Date: Thu, 23 Jan 2025 22:38:46 +0000 Subject: [PATCH 0138/6055] drivers: gpio_rpi_pico: Add gpio_get_pending_int API Implement `gpio_get_pending_int`. Signed-off-by: Andrew Featherstone --- drivers/gpio/gpio_rpi_pico.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpio/gpio_rpi_pico.c b/drivers/gpio/gpio_rpi_pico.c index d0c07b7e80b8c..7f6dd74143bca 100644 --- a/drivers/gpio/gpio_rpi_pico.c +++ b/drivers/gpio/gpio_rpi_pico.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Yonatan Schachter + * Copyright (c) 2025, Andrew Featherstone * * SPDX-License-Identifier: Apache-2.0 */ @@ -193,6 +194,19 @@ static int gpio_rpi_manage_callback(const struct device *dev, return gpio_manage_callback(&data->callbacks, callback, set); } +static uint32_t gpio_rpi_get_pending_int(const struct device *dev) +{ + io_bank0_irq_ctrl_hw_t *irq_ctrl_base = + get_core_num() ? &io_bank0_hw->proc1_irq_ctrl : &io_bank0_hw->proc0_irq_ctrl; + ARRAY_FOR_EACH_PTR(irq_ctrl_base->ints, p) { + if (*p) { + return 1; + } + } + + return 0; +} + static DEVICE_API(gpio, gpio_rpi_driver_api) = { .pin_configure = gpio_rpi_configure, .port_get_raw = gpio_rpi_port_get_raw, @@ -202,6 +216,7 @@ static DEVICE_API(gpio, gpio_rpi_driver_api) = { .port_toggle_bits = gpio_rpi_port_toggle_bits, .pin_interrupt_configure = gpio_rpi_pin_interrupt_configure, .manage_callback = gpio_rpi_manage_callback, + .get_pending_int = gpio_rpi_get_pending_int, }; static void gpio_rpi_isr(const struct device *dev) From c1b69710a1d25d1555ecc1080f9a53eef9e833ea Mon Sep 17 00:00:00 2001 From: Andrew Featherstone Date: Thu, 30 Jan 2025 22:26:12 +0000 Subject: [PATCH 0139/6055] drivers: gpio_rpi_pico: Add gpio_port_get_direction API THe driver didn't implement this API, so add it. Signed-off-by: Andrew Featherstone --- drivers/gpio/gpio_rpi_pico.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpio/gpio_rpi_pico.c b/drivers/gpio/gpio_rpi_pico.c index 7f6dd74143bca..848c97954e86c 100644 --- a/drivers/gpio/gpio_rpi_pico.c +++ b/drivers/gpio/gpio_rpi_pico.c @@ -207,6 +207,32 @@ static uint32_t gpio_rpi_get_pending_int(const struct device *dev) return 0; } +#ifdef CONFIG_GPIO_GET_DIRECTION +static int gpio_rpi_port_get_direction(const struct device *port, gpio_port_pins_t map, + gpio_port_pins_t *inputs, gpio_port_pins_t *outputs) +{ + /* The Zephyr API considers a disconnected pin to be neither an input nor output. + * Since we disable both OE and IE for disconnected pins clear the mask bits. + */ + for (int pin = 0; pin < NUM_BANK0_GPIOS; pin++) { + if (pads_bank0_hw->io[pin] & PADS_BANK0_GPIO0_OD_BITS) { + map &= ~BIT(pin); + } + if (inputs && (pads_bank0_hw->io[pin] & PADS_BANK0_GPIO0_IE_BITS)) { + *inputs |= BIT(pin); + } + } + if (inputs) { + *inputs &= map; + } + if (outputs) { + *outputs = sio_hw->gpio_oe & map; + } + + return 0; +} +#endif + static DEVICE_API(gpio, gpio_rpi_driver_api) = { .pin_configure = gpio_rpi_configure, .port_get_raw = gpio_rpi_port_get_raw, @@ -217,6 +243,9 @@ static DEVICE_API(gpio, gpio_rpi_driver_api) = { .pin_interrupt_configure = gpio_rpi_pin_interrupt_configure, .manage_callback = gpio_rpi_manage_callback, .get_pending_int = gpio_rpi_get_pending_int, +#ifdef CONFIG_GPIO_GET_DIRECTION + .port_get_direction = gpio_rpi_port_get_direction, +#endif }; static void gpio_rpi_isr(const struct device *dev) From 06be6ebf3a1c8f02ca311267c6dfb451826d28d0 Mon Sep 17 00:00:00 2001 From: Andrew Featherstone Date: Wed, 22 Jan 2025 21:35:10 +0000 Subject: [PATCH 0140/6055] drivers: gpio_rpi_pico: Add gpio_get_config API Implement the `gpio_get_config` N.b. adding this API results in a new test failure in `test_gpio_config_trigger`. This suggests that there is some kind of dependency between this and the now-enabled `pin_get_config` test cases. Note that this adds a read-only API, it is unlikely to be the cause of the failure. Signed-off-by: Andrew Featherstone --- drivers/gpio/gpio_rpi_pico.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/gpio/gpio_rpi_pico.c b/drivers/gpio/gpio_rpi_pico.c index 848c97954e86c..2e2e592eee82f 100644 --- a/drivers/gpio/gpio_rpi_pico.c +++ b/drivers/gpio/gpio_rpi_pico.c @@ -96,6 +96,37 @@ static int gpio_rpi_configure(const struct device *dev, return 0; } +#ifdef CONFIG_GPIO_GET_CONFIG +static int gpio_rpi_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *flags) +{ + struct gpio_rpi_data *data = dev->data; + + *flags = 0; + + /* RP2xxxx supports Bus Keeper mode where both pull-up and pull-down are enabled. */ + if (gpio_is_pulled_up(pin)) { + *flags |= GPIO_PULL_UP; + } + if (gpio_is_pulled_down(pin)) { + *flags |= GPIO_PULL_DOWN; + } + + if (gpio_get_dir(pin)) { + *flags |= gpio_get_out_level(pin) ? GPIO_OUTPUT_HIGH : GPIO_OUTPUT_LOW; + if (data->single_ended_mask & BIT(pin)) { + *flags |= + data->open_drain_mask & BIT(pin) ? GPIO_OPEN_DRAIN : GPIO_PUSH_PULL; + } + } + + if (pads_bank0_hw->io[pin] & PADS_BANK0_GPIO0_IE_BITS) { + *flags |= GPIO_INPUT; + } + + return 0; +} +#endif + static int gpio_rpi_port_get_raw(const struct device *dev, uint32_t *value) { *value = gpio_get_all(); @@ -235,6 +266,9 @@ static int gpio_rpi_port_get_direction(const struct device *port, gpio_port_pins static DEVICE_API(gpio, gpio_rpi_driver_api) = { .pin_configure = gpio_rpi_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = gpio_rpi_get_config, +#endif .port_get_raw = gpio_rpi_port_get_raw, .port_set_masked_raw = gpio_rpi_port_set_masked_raw, .port_set_bits_raw = gpio_rpi_port_set_bits_raw, From ef348187ae603b766bad1af7aa29d37e7a5d8c9a Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Tue, 11 Feb 2025 11:39:20 +0800 Subject: [PATCH 0141/6055] soc: nxp: imxrt: imxrt118x: change trdc permission getting strategy When TRDC permission fails to be obtained, it does not recycle to access ELE core to prevent blocking problems. The current practice only generates a log warning alarm. Signed-off-by: Lucien Zhao --- soc/nxp/imxrt/imxrt118x/soc.c | 37 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/soc/nxp/imxrt/imxrt118x/soc.c b/soc/nxp/imxrt/imxrt118x/soc.c index 169234e1bbf6c..261250870a9eb 100644 --- a/soc/nxp/imxrt/imxrt118x/soc.c +++ b/soc/nxp/imxrt/imxrt118x/soc.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,8 @@ #include #include +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + /* * Set ELE_STICK_FAILED_STS to 0 when ELE status check is not required, * which is useful when debug reset, where the core has already get the @@ -521,34 +524,36 @@ static ALWAYS_INLINE void trdc_enable_all_access(void) status_t sts; uint8_t i, j; - /* Get ELE FW status */ + /* Get ELE FW status */ do { uint32_t ele_fw_sts; sts = ELE_BaseAPI_GetFwStatus(MU_RT_S3MUA, &ele_fw_sts); } while (sts != kStatus_Success); - do { #if defined(CONFIG_SOC_MIMXRT1189_CM33) - /* Release TRDC A to CM33 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM33_ID); + /* Release TRDC AON to CM33 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM33_ID); #elif defined(CONFIG_SOC_MIMXRT1189_CM7) - /* Release TRDC A to CM7 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM7_ID); + /* Release TRDC AON to CM7 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_AON_ID, ELE_CORE_CM7_ID); #endif - } while (ELE_IS_FAILED(sts)); + if (sts != kStatus_Success) { + LOG_WRN("warning: TRDC AON permission get failed. If core don't get TRDC " + "AON permission, AON domain permission can't be configured."); + } - /* Release TRDC W to CM33 core */ - do { #if defined(CONFIG_SOC_MIMXRT1189_CM33) - /* Release TRDC A to CM33 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM33_ID); + /* Release TRDC Wakeup to CM33 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM33_ID); #elif defined(CONFIG_SOC_MIMXRT1189_CM7) - /* Release TRDC A to CM7 core */ - sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM7_ID); + /* Release TRDC Wakeup to CM7 core */ + sts = ELE_BaseAPI_ReleaseRDC(MU_RT_S3MUA, ELE_TRDC_WAKEUP_ID, ELE_CORE_CM7_ID); #endif - } while (ELE_IS_FAILED(sts)); - + if (sts != kStatus_Success) { + LOG_WRN("warning: TRDC Wakeup permission get failed. If core don't get TRDC " + "Wakeup permission, Wakeup domain permission can't be configured."); + } /* Set the master domain access configuration for eDMA3/eDMA4 */ trdc_non_processor_domain_assignment_t edmaAssignment; From b1fe93e0470bde93926c321882a4c02ee33d2303 Mon Sep 17 00:00:00 2001 From: Xinyu Hong Date: Tue, 11 Feb 2025 18:06:37 -0800 Subject: [PATCH 0142/6055] drivers: wifi: nxp: Fix wrong current PHY TX rate For embedded supplicant case, fix current PHY TX rate is 0 always after STAUT connects to Ex-AP Signed-off-by: Xinyu Hong --- drivers/wifi/nxp/nxp_wifi_drv.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/wifi/nxp/nxp_wifi_drv.c b/drivers/wifi/nxp/nxp_wifi_drv.c index 806fdcc380cfb..effa76c808d62 100644 --- a/drivers/wifi/nxp/nxp_wifi_drv.c +++ b/drivers/wifi/nxp/nxp_wifi_drv.c @@ -1167,6 +1167,7 @@ static int nxp_wifi_status(const struct device *dev, struct wifi_iface_status *s } else if (connection_state == WLAN_AUTHENTICATED || connection_state == WLAN_CONNECTED) { status->state = WIFI_STATE_COMPLETED; + wlan_ds_rate ds_rate = {0}; if (!wlan_get_current_network(&nxp_wlan_network)) { strncpy(status->ssid, nxp_wlan_network.ssid, WIFI_SSID_MAX_LEN - 1); @@ -1216,6 +1217,22 @@ static int nxp_wifi_status(const struct device *dev, struct wifi_iface_status *s status->mfp = nxp_wlan_network.security.mfpr ? WIFI_MFP_REQUIRED : (nxp_wlan_network.security.mfpc ? WIFI_MFP_OPTIONAL : 0); } + ds_rate.sub_command = WIFI_DS_GET_DATA_RATE; + if (!wlan_get_data_rate(&ds_rate, WLAN_BSS_TYPE_STA)) { + wifi_data_rate_t *datarate = (wifi_data_rate_t *)&ds_rate.param.data_rate; + int lg_rate[12] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54}; + + if (datarate->tx_rate_format == MLAN_RATE_FORMAT_LG && + datarate->tx_data_rate < 12) { + /* Legacy rates (in bps) */ + /* Need to feed Zephyr L2 Wi-Fi with rate value in unit of Mbps*/ + status->current_phy_tx_rate = lg_rate[datarate->tx_data_rate]; + } else if (datarate->tx_rate_format <= 3) { + /* HT, VHT, HE rates (in bps) */ + /* Need to feed Zephyr L2 Wi-Fi with rate value in unit of Mbps*/ + status->current_phy_tx_rate = (datarate->tx_data_rate >> 1); + } + } } return 0; From 4b4f8999d189bc23c3b06c088efa56c324ba437e Mon Sep 17 00:00:00 2001 From: The Nguyen Date: Wed, 11 Dec 2024 11:27:04 +0000 Subject: [PATCH 0143/6055] manifest: update rev of hal_renesas to support USBFS module Update revision of hal_renesas module to add support of UDC on Renesas RA USBFS module Signed-off-by: The Nguyen --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index d6f104e3e320a..05332b09611f5 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: - hal - name: hal_renesas path: modules/hal/renesas - revision: abca7ee376c86fe4f0032d083c1af39e2600cbe5 + revision: 3237c5db010a3137c67ebc9bcdb911f07557fb3c groups: - hal - name: hal_rpi_pico From 0fc95b8927a4f105964180e30e721070fb8ad618 Mon Sep 17 00:00:00 2001 From: The Nguyen Date: Fri, 13 Dec 2024 14:58:01 +0700 Subject: [PATCH 0144/6055] dts: arm: renesas: add uclk clock node for ra2a1 Add missing clock node of uclk on Renesas RA2A1 SoC Signed-off-by: The Nguyen --- dts/arm/renesas/ra/ra2/r7fa2a1xh.dtsi | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dts/arm/renesas/ra/ra2/r7fa2a1xh.dtsi b/dts/arm/renesas/ra/ra2/r7fa2a1xh.dtsi index b44495183cce6..6d123486697f2 100644 --- a/dts/arm/renesas/ra/ra2/r7fa2a1xh.dtsi +++ b/dts/arm/renesas/ra/ra2/r7fa2a1xh.dtsi @@ -173,12 +173,17 @@ status = "disabled"; }; - sdadcclk: sdadcclk { compatible = "renesas,ra-cgc-pclk"; #clock-cells = <2>; status = "disabled"; }; + + uclk: uclk { + compatible = "renesas,ra-cgc-pclk"; + #clock-cells = <2>; + status = "disabled"; + }; }; }; }; From 227f2c4fb4dac4621629bfaa379061305ca03cf1 Mon Sep 17 00:00:00 2001 From: The Nguyen Date: Tue, 26 Nov 2024 18:17:25 +0700 Subject: [PATCH 0145/6055] drivers: udc: add UDC support for USBFS on Renesas RA family First commit to add support for USBFS module on Renesas RA - Remove renesas,ra-usb binding - Add 2 new binding for Renesas RA USBFS and USBHS - Remove unused interrupts of USBHS Signed-off-by: The Nguyen --- drivers/usb/udc/udc_renesas_ra.c | 211 ++++++++++++------ dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi | 6 +- dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi | 6 +- dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi | 6 +- dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi | 6 +- dts/bindings/usb/renesas/renesas,ra-usb.yaml | 16 -- .../usb/renesas/renesas,ra-usbfs.yaml | 34 +++ .../usb/renesas/renesas,ra-usbhs.yaml | 33 +++ 8 files changed, 223 insertions(+), 95 deletions(-) delete mode 100644 dts/bindings/usb/renesas/renesas,ra-usb.yaml create mode 100644 dts/bindings/usb/renesas/renesas,ra-usbfs.yaml create mode 100644 dts/bindings/usb/renesas/renesas,ra-usbhs.yaml diff --git a/drivers/usb/udc/udc_renesas_ra.c b/drivers/usb/udc/udc_renesas_ra.c index 66f3ae3084049..a113bcad8a3dd 100644 --- a/drivers/usb/udc/udc_renesas_ra.c +++ b/drivers/usb/udc/udc_renesas_ra.c @@ -17,6 +17,8 @@ LOG_MODULE_REGISTER(udc_renesas_ra, CONFIG_UDC_DRIVER_LOG_LEVEL); struct udc_renesas_ra_config { const struct pinctrl_dev_config *pcfg; + const struct device **clocks; + size_t num_of_clocks; size_t num_of_eps; struct udc_ep_config *ep_cfg_in; struct udc_ep_config *ep_cfg_out; @@ -497,43 +499,6 @@ static int udc_renesas_ra_init(const struct device *dev) { struct udc_renesas_ra_data *data = udc_get_private(dev); -#if !USBHS_PHY_CLOCK_SOURCE_IS_XTAL - if (data->udc_cfg.usb_speed == USBD_SPEED_HS) { - LOG_ERR("High-speed operation is not supported in case PHY clock source is not " - "XTAL"); - return -ENOTSUP; - } - - uint32_t uclk_src = RA_CGC_CLK_SRC(DT_CLOCKS_CTLR(DT_NODELABEL(uclk))); - uint32_t uclk_div = DT_PROP_OR(DT_NODELABEL(uclk), div, 1); - uint32_t u60clk_src = RA_CGC_CLK_SRC(DT_CLOCKS_CTLR(DT_NODELABEL(u60clk))); - uint32_t u60clk_div = DT_PROP_OR(DT_NODELABEL(u60clk), div, 1); - - if (uclk_src == BSP_CLOCKS_CLOCK_DISABLED || u60clk_src == BSP_CLOCKS_CLOCK_DISABLED) { - LOG_ERR("PHY clock is not working"); - return -EINVAL; - } - - uint32_t uclk_clock_rate = R_BSP_SourceClockHzGet(uclk_src) / uclk_div; - uint32_t u60clk_clock_rate = R_BSP_SourceClockHzGet(u60clk_src) / u60clk_div; - - if (uclk_clock_rate != 48000000) { - LOG_ERR("Setting for uclk should be 48Mhz"); - return -ENOTSUP; - } - - if (u60clk_clock_rate != 60000000) { - LOG_ERR("Setting for u60clk should be 60Mhz"); - return -ENOTSUP; - } -#endif - - if (!(data->udc_cfg.usb_speed == USBD_SPEED_HS || - data->udc_cfg.usb_speed == USBD_SPEED_FS)) { - LOG_ERR("USB device mode support full-speed and high-speed only"); - return -ENOTSUP; - } - if (FSP_SUCCESS != R_USBD_Open(&data->udc, &data->udc_cfg)) { return -EIO; } @@ -548,7 +513,19 @@ static int udc_renesas_ra_init(const struct device *dev) return -EIO; } - irq_enable(data->udc_cfg.hs_irq); +#if DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_usbhs) + if (data->udc_cfg.hs_irq != (IRQn_Type)BSP_IRQ_DISABLED) { + irq_enable(data->udc_cfg.hs_irq); + } +#endif + + if (data->udc_cfg.irq != (IRQn_Type)BSP_IRQ_DISABLED) { + irq_enable(data->udc_cfg.irq); + } + + if (data->udc_cfg.irq_r != (IRQn_Type)BSP_IRQ_DISABLED) { + irq_enable(data->udc_cfg.irq_r); + } return 0; } @@ -574,13 +551,86 @@ static int udc_renesas_ra_shutdown(const struct device *dev) return 0; } +static int udc_renesas_ra_clock_check(const struct device *dev) +{ + const struct udc_renesas_ra_config *config = dev->config; + +#if USBHS_PHY_CLOCK_SOURCE_IS_XTAL + if (config->speed_idx == UDC_BUS_SPEED_HS) { + if (BSP_CFG_XTAL_HZ == 0) { + LOG_ERR("XTAL clock should be provided"); + return -EINVAL; + } + + return 0; + } +#endif + + for (size_t i = 0; i < config->num_of_clocks; i++) { + const struct device *clock_dev = *(config->clocks + i); + const struct clock_control_ra_pclk_cfg *clock_cfg = clock_dev->config; + uint32_t clk_src_rate; + uint32_t clock_rate; + + if (!device_is_ready(clock_dev)) { + LOG_ERR("%s is not ready", clock_dev->name); + return -ENODEV; + } + + clk_src_rate = R_BSP_SourceClockHzGet(clock_cfg->clk_src); + clock_rate = clk_src_rate / clock_cfg->clk_div; + + if (strcmp(clock_dev->name, "uclk") == 0 && clock_rate != MHZ(48)) { + LOG_ERR("Setting for uclk should be 48Mhz"); + return -ENOTSUP; + } + +#if DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_usbhs) + if (strcmp(clock_dev->name, "u60clk") == 0 && clock_rate != MHZ(60)) { + LOG_ERR("Setting for u60clk should be 60Mhz"); + return -ENOTSUP; + } +#endif + } + + return 0; +} + static int udc_renesas_ra_driver_preinit(const struct device *dev) { const struct udc_renesas_ra_config *config = dev->config; + struct udc_renesas_ra_data *priv = udc_get_private(dev); struct udc_data *data = dev->data; uint16_t mps = 1023; int err; +#if !USBHS_PHY_CLOCK_SOURCE_IS_XTAL + if (priv->udc_cfg.usb_speed == USBD_SPEED_HS) { + LOG_ERR("High-speed operation is not supported in case PHY clock source is not " + "XTAL"); + return -ENOTSUP; + } +#endif + + if (config->speed_idx == UDC_BUS_SPEED_HS) { + if (!(priv->udc_cfg.usb_speed == USBD_SPEED_HS || + priv->udc_cfg.usb_speed == USBD_SPEED_FS)) { + LOG_ERR("USBHS module only support high-speed and full-speed device"); + return -ENOTSUP; + } + } else { + /* config->speed_idx == UDC_BUS_SPEED_FS */ + if (priv->udc_cfg.usb_speed != USBD_SPEED_FS) { + LOG_ERR("USBFS module only support full-speed device"); + return -ENOTSUP; + } + } + + err = udc_renesas_ra_clock_check(dev); + if (err < 0) { + return err; + } + err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); if (err < 0) { return err; @@ -590,7 +640,7 @@ static int udc_renesas_ra_driver_preinit(const struct device *dev) data->caps.rwup = true; data->caps.mps0 = UDC_MPS0_64; - if (config->speed_idx == UDC_BUS_SPEED_HS) { + if (priv->udc_cfg.usb_speed == USBD_SPEED_HS) { data->caps.hs = true; mps = 1024; } @@ -635,8 +685,22 @@ static int udc_renesas_ra_driver_preinit(const struct device *dev) } } +#if DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_usbhs) + if (priv->udc_cfg.hs_irq != (IRQn_Type)BSP_IRQ_DISABLED) { + R_ICU->IELSR[priv->udc_cfg.hs_irq] = ELC_EVENT_USBHS_USB_INT_RESUME; + } +#endif + + if (priv->udc_cfg.irq != (IRQn_Type)BSP_IRQ_DISABLED) { + R_ICU->IELSR[priv->udc_cfg.irq] = ELC_EVENT_USBFS_INT; + } + + if (priv->udc_cfg.irq_r != (IRQn_Type)BSP_IRQ_DISABLED) { + R_ICU->IELSR[priv->udc_cfg.irq_r] = ELC_EVENT_USBFS_RESUME; + } + config->make_thread(dev); - LOG_INF("Device %p (max. speed %d)", dev, config->speed_idx); + LOG_INF("Device %p (max. speed %d)", dev, priv->udc_cfg.usb_speed); return 0; } @@ -671,32 +735,36 @@ static const struct udc_api udc_renesas_ra_api = { #define DT_DRV_COMPAT renesas_ra_udc -#define USB_MODULE_NUMBER(n) ((DT_REG_ADDR(DT_INST_PARENT(n))) == R_USB_HS0_BASE ? 1 : 0) +#define USB_RENESAS_RA_MODULE_NUMBER(id) (DT_REG_ADDR(id) == R_USB_FS0_BASE ? 0 : 1) -#define RENESAS_RA_USB_IRQ_CONFIG_FUNC(n) \ - static int udc_renesas_ra_irq_config_func_##n(const struct device *dev) \ - { \ - struct udc_renesas_ra_data *data = udc_get_private(dev); \ - \ - data->udc_cfg.hs_irq = DT_IRQ_BY_NAME(DT_INST_PARENT(n), usbhs_ir, irq); \ - data->udc_cfg.hsirq_d0 = DT_IRQ_BY_NAME(DT_INST_PARENT(n), usbhs_d0, irq); \ - data->udc_cfg.hsirq_d1 = DT_IRQ_BY_NAME(DT_INST_PARENT(n), usbhs_d1, irq); \ - data->udc_cfg.hsipl = DT_IRQ_BY_NAME(DT_INST_PARENT(n), usbhs_ir, priority); \ - data->udc_cfg.hsipl_d0 = DT_IRQ_BY_NAME(DT_INST_PARENT(n), usbhs_d0, priority); \ - data->udc_cfg.hsipl_d1 = DT_IRQ_BY_NAME(DT_INST_PARENT(n), usbhs_d1, priority); \ - \ - R_ICU->IELSR[DT_IRQ_BY_NAME(DT_NODELABEL(usbhs), usbhs_ir, irq)] = \ - ELC_EVENT_USBHS_USB_INT_RESUME; \ - IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(usbhs), usbhs_ir, irq), \ - DT_IRQ_BY_NAME(DT_NODELABEL(usbhs), usbhs_ir, priority), \ - udc_renesas_ra_interrupt_handler, DEVICE_DT_INST_GET(n), 0); \ - return 0; \ - } +#define USB_RENESAS_RA_IRQ_GET(id, name, cell) \ + COND_CODE_1(DT_IRQ_HAS_NAME(id, name), (DT_IRQ_BY_NAME(id, name, cell)), \ + ((IRQn_Type) BSP_IRQ_DISABLED)) + +#define USB_RENESAS_RA_MAX_SPEED_IDX(id) \ + (DT_NODE_HAS_COMPAT(id, renesas_ra_usbhs) ? UDC_BUS_SPEED_HS : UDC_BUS_SPEED_FS) + +#define USB_RENESAS_RA_SPEED_IDX(id) \ + (DT_NODE_HAS_COMPAT(id, renesas_ra_usbhs) \ + ? DT_ENUM_IDX_OR(id, maximum_speed, UDC_BUS_SPEED_HS) \ + : DT_ENUM_IDX_OR(id, maximum_speed, UDC_BUS_SPEED_FS)) + +#define USB_RENESAS_RA_IRQ_CONNECT(idx, n) \ + IRQ_CONNECT(DT_IRQ_BY_IDX(DT_INST_PARENT(n), idx, irq), \ + DT_IRQ_BY_IDX(DT_INST_PARENT(n), idx, priority), \ + udc_renesas_ra_interrupt_handler, DEVICE_DT_INST_GET(n), 0) + +#define USB_RENESAS_RA_CLOCKS_GET(idx, id) \ + DEVICE_DT_GET_OR_NULL(DT_PHANDLE_BY_IDX(id, phys_clock, idx)) #define UDC_RENESAS_RA_DEVICE_DEFINE(n) \ PINCTRL_DT_DEFINE(DT_INST_PARENT(n)); \ K_THREAD_STACK_DEFINE(udc_renesas_ra_stack_##n, CONFIG_UDC_RENESAS_RA_STACK_SIZE); \ - RENESAS_RA_USB_IRQ_CONFIG_FUNC(n); \ + \ + static const struct device *udc_renesas_ra_clock_dev_##n[] = { \ + LISTIFY(DT_PROP_LEN_OR(DT_INST_PARENT(n), phys_clock, 0), \ + USB_RENESAS_RA_CLOCKS_GET, (,), DT_INST_PARENT(n)) \ + }; \ \ static void udc_renesas_ra_thread_##n(void *dev, void *arg1, void *arg2) \ { \ @@ -721,29 +789,38 @@ static const struct udc_api udc_renesas_ra_api = { \ static const struct udc_renesas_ra_config udc_renesas_ra_config_##n = { \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(n)), \ + .clocks = udc_renesas_ra_clock_dev_##n, \ + .num_of_clocks = DT_PROP_LEN_OR(DT_INST_PARENT(n), phys_clock, 0), \ .num_of_eps = DT_PROP(DT_INST_PARENT(n), num_bidir_endpoints), \ .ep_cfg_in = ep_cfg_in##n, \ .ep_cfg_out = ep_cfg_out##n, \ .make_thread = udc_renesas_ra_make_thread_##n, \ - .speed_idx = DT_ENUM_IDX_OR(DT_INST_PARENT(n), maximum_speed, UDC_BUS_SPEED_HS), \ + .speed_idx = USB_RENESAS_RA_MAX_SPEED_IDX(DT_INST_PARENT(n)), \ }; \ \ static struct udc_renesas_ra_data udc_priv_##n = { \ .udc_cfg = { \ - .module_number = USB_MODULE_NUMBER(n), \ - .usb_speed = DT_ENUM_IDX_OR(DT_INST_PARENT(n), maximum_speed, \ - UDC_BUS_SPEED_HS), \ + .module_number = USB_RENESAS_RA_MODULE_NUMBER(DT_INST_PARENT(n)), \ + .usb_speed = USB_RENESAS_RA_SPEED_IDX(DT_INST_PARENT(n)), \ + .irq = USB_RENESAS_RA_IRQ_GET(DT_INST_PARENT(n), usbfs_i, irq), \ + .irq_r = USB_RENESAS_RA_IRQ_GET(DT_INST_PARENT(n), usbfs_r, irq), \ + .hs_irq = USB_RENESAS_RA_IRQ_GET(DT_INST_PARENT(n), usbhs_ir, irq), \ + .ipl = USB_RENESAS_RA_IRQ_GET(DT_INST_PARENT(n), usbfs_i, priority), \ + .ipl_r = USB_RENESAS_RA_IRQ_GET(DT_INST_PARENT(n), usbfs_r, priority), \ + .hsipl = USB_RENESAS_RA_IRQ_GET(DT_INST_PARENT(n), usbhs_ir, priority), \ .p_context = DEVICE_DT_INST_GET(n), \ .p_callback = udc_renesas_ra_event_handler, \ - }}; \ + }, \ + }; \ \ static struct udc_data udc_data_##n = { \ .mutex = Z_MUTEX_INITIALIZER(udc_data_##n.mutex), \ .priv = &udc_priv_##n, \ }; \ + \ int udc_renesas_ra_driver_preinit##n(const struct device *dev) \ { \ - udc_renesas_ra_irq_config_func_##n(dev); \ + LISTIFY(DT_NUM_IRQS(DT_INST_PARENT(n)), USB_RENESAS_RA_IRQ_CONNECT, (;), n); \ return udc_renesas_ra_driver_preinit(dev); \ } \ \ diff --git a/dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi b/dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi index a13ed21e3d2df..5b9c66079f2fb 100644 --- a/dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi +++ b/dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi @@ -105,10 +105,10 @@ }; usbhs: usbhs@40060000 { - compatible = "renesas,ra-usb"; + compatible = "renesas,ra-usbhs"; reg = <0x40060000 0x2000>; - interrupts = <54 12>, <55 12>, <56 12>; - interrupt-names = "usbhs-ir", "usbhs-d0", "usbhs-d1"; + interrupts = <54 12>; + interrupt-names = "usbhs-ir"; num-bidir-endpoints = <10>; phys = <&usbhs_phy>; status = "disabled"; diff --git a/dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi b/dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi index 44337da8d5a81..77d32d26afc94 100644 --- a/dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi +++ b/dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi @@ -195,10 +195,10 @@ }; usbhs: usbhs@40111000 { - compatible = "renesas,ra-usb"; + compatible = "renesas,ra-usbhs"; reg = <0x40111000 0x2000>; - interrupts = <54 12>, <55 12>, <56 12>; - interrupt-names = "usbhs-ir", "usbhs-d0", "usbhs-d1"; + interrupts = <54 12>; + interrupt-names = "usbhs-ir"; num-bidir-endpoints = <10>; phys = <&usbhs_phy>; status = "disabled"; diff --git a/dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi b/dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi index 838d705e6d18d..e71cffebaf1f8 100644 --- a/dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi +++ b/dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi @@ -280,10 +280,10 @@ soc { usbhs: usbhs@40351000 { - compatible = "renesas,ra-usb"; + compatible = "renesas,ra-usbhs"; reg = <0x40351000 0x2000>; - interrupts = <54 12>, <55 12>, <56 12>; - interrupt-names = "usbhs-ir", "usbhs-d0", "usbhs-d1"; + interrupts = <54 12>; + interrupt-names = "usbhs-ir"; num-bidir-endpoints = <10>; phys = <&usbhs_phy>; status = "disabled"; diff --git a/dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi b/dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi index c8ebbd5edc997..a262e0e02ca00 100644 --- a/dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi +++ b/dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi @@ -244,10 +244,10 @@ soc { usbhs: usbhs@40351000 { - compatible = "renesas,ra-usb"; + compatible = "renesas,ra-usbhs"; reg = <0x40351000 0x2000>; - interrupts = <54 12>, <55 12>, <56 12>; - interrupt-names = "usbhs-ir", "usbhs-d0", "usbhs-d1"; + interrupts = <54 12>; + interrupt-names = "usbhs-ir"; num-bidir-endpoints = <10>; phys = <&usbhs_phy>; status = "disabled"; diff --git a/dts/bindings/usb/renesas/renesas,ra-usb.yaml b/dts/bindings/usb/renesas/renesas,ra-usb.yaml deleted file mode 100644 index ec31e250eb305..0000000000000 --- a/dts/bindings/usb/renesas/renesas,ra-usb.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2024 Renesas Electronics Corporation -# SPDX-License-Identifier: Apache-2.0 - -description: Renesas RA USB controller - -compatible: "renesas,ra-usb" - -include: [pinctrl-device.yaml, usb-ep.yaml] - -properties: - reg: - required: true - - phys: - type: phandle - description: PHY provider specifier diff --git a/dts/bindings/usb/renesas/renesas,ra-usbfs.yaml b/dts/bindings/usb/renesas/renesas,ra-usbfs.yaml new file mode 100644 index 0000000000000..58ec9aa344e83 --- /dev/null +++ b/dts/bindings/usb/renesas/renesas,ra-usbfs.yaml @@ -0,0 +1,34 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA USB full-speed controller + +compatible: "renesas,ra-usbfs" + +include: [pinctrl-device.yaml, usb-ep.yaml] + +properties: + phys-clock: + type: phandles + required: true + description: USBFS physical clock. + + interrupts: + required: true + description: | + IRQ number and priority to use for USBFS. + + interrupt-names: + required: true + enum: + - "usbfs-i" + - "usbfs-r" + description: | + Interrupts must be given corresponding names so that the shim driver can recognize them. + + reg: + required: true + + phys: + type: phandle + description: PHY provider specifier diff --git a/dts/bindings/usb/renesas/renesas,ra-usbhs.yaml b/dts/bindings/usb/renesas/renesas,ra-usbhs.yaml new file mode 100644 index 0000000000000..9428c2413bc5d --- /dev/null +++ b/dts/bindings/usb/renesas/renesas,ra-usbhs.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA USB high-speed controller + +compatible: "renesas,ra-usbhs" + +include: [pinctrl-device.yaml, usb-ep.yaml] + +properties: + phys-clock: + type: phandles + description: | + USBHS physical clocks. Should be provided in case internal clock source is set in phys node. + + interrupts: + required: true + description: | + IRQ number and priority to use for USBHS. + + interrupt-names: + required: true + enum: + - "usbhs-ir" + description: | + Interrupts must be given corresponding names so that the shim driver can recognize them. + + reg: + required: true + + phys: + type: phandle + description: PHY provider specifier From 164847f3a618f3fb30f9616c86697328afdf47d5 Mon Sep 17 00:00:00 2001 From: The Nguyen Date: Tue, 26 Nov 2024 18:21:48 +0700 Subject: [PATCH 0146/6055] dts: arm: renesas: add UDC support for USBFS module Add device node of usbfs on Renesas RA SoC Signed-off-by: The Nguyen --- dts/arm/renesas/ra/ra4/r7fa4e2b93cfm.dtsi | 2 ++ dts/arm/renesas/ra/ra4/ra4-cm33-common.dtsi | 21 +++++++++++++++++++++ dts/arm/renesas/ra/ra4/ra4-cm4-common.dtsi | 19 +++++++++++++++++++ dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi | 5 +++-- dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi | 21 +++++++++++++++++++++ dts/arm/renesas/ra/ra6/ra6-cm4-common.dtsi | 21 +++++++++++++++++++++ dts/arm/renesas/ra/ra8/ra8x1.dtsi | 21 +++++++++++++++++++++ 7 files changed, 108 insertions(+), 2 deletions(-) diff --git a/dts/arm/renesas/ra/ra4/r7fa4e2b93cfm.dtsi b/dts/arm/renesas/ra/ra4/r7fa4e2b93cfm.dtsi index 6bdf17e87d39d..d4379f683cd9a 100644 --- a/dts/arm/renesas/ra/ra4/r7fa4e2b93cfm.dtsi +++ b/dts/arm/renesas/ra/ra4/r7fa4e2b93cfm.dtsi @@ -15,6 +15,8 @@ /delete-node/ &agt5; /delete-node/ &iic0; /delete-node/ &iic1; +/delete-node/ &usbfs; +/delete-node/ &usbfs_phy; /delete-node/ &adc1; /delete-node/ &dac1; diff --git a/dts/arm/renesas/ra/ra4/ra4-cm33-common.dtsi b/dts/arm/renesas/ra/ra4/ra4-cm33-common.dtsi index 3afb46ee9f83a..86669aa57dc06 100644 --- a/dts/arm/renesas/ra/ra4/ra4-cm33-common.dtsi +++ b/dts/arm/renesas/ra/ra4/ra4-cm33-common.dtsi @@ -306,6 +306,22 @@ status = "disabled"; }; + usbfs: usbfs@40090000 { + compatible = "renesas,ra-usbfs"; + reg = <0x40090000 0x2000>; + interrupts = <32 1>, <33 1>; + interrupt-names = "usbfs-i", "usbfs-r"; + num-bidir-endpoints = <10>; + phys = <&usbfs_phy>; + phys-clock = <&uclk>; + status = "disabled"; + + udc { + compatible = "renesas,ra-udc"; + status = "disabled"; + }; + }; + option_setting_ofs: option_setting_ofs@100a100 { compatible = "zephyr,memory-region"; reg = <0x0100a100 0x18>; @@ -511,6 +527,11 @@ status = "disabled"; }; }; + + usbfs_phy: usbfs-phy { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; }; &nvic { diff --git a/dts/arm/renesas/ra/ra4/ra4-cm4-common.dtsi b/dts/arm/renesas/ra/ra4/ra4-cm4-common.dtsi index a1cd196a0d326..1be403e71df4f 100644 --- a/dts/arm/renesas/ra/ra4/ra4-cm4-common.dtsi +++ b/dts/arm/renesas/ra/ra4/ra4-cm4-common.dtsi @@ -232,6 +232,20 @@ status = "disabled"; }; + usbfs: usbfs@40090000 { + compatible = "renesas,ra-usbfs"; + reg = <0x40090000 0x2000>; + num-bidir-endpoints = <10>; + phys = <&usbfs_phy>; + phys-clock = <&uclk>; + status = "disabled"; + + udc { + compatible = "renesas,ra-udc"; + status = "disabled"; + }; + }; + id_code: id_code@1010018 { compatible = "zephyr,memory-region"; reg = <0x01010018 0x20>; @@ -396,6 +410,11 @@ status = "disabled"; }; }; + + usbfs_phy: usbfs-phy { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; }; &nvic { diff --git a/dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi b/dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi index 29a93715dea58..caa296d3f32a6 100644 --- a/dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi +++ b/dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi @@ -6,6 +6,7 @@ #include #include +#include /delete-node/ &agt0; /delete-node/ &agt1; @@ -13,9 +14,9 @@ /delete-node/ &agt3; /delete-node/ &agt4; /delete-node/ &agt5; -#include - /delete-node/ &adc1; +/delete-node/ &usbfs; +/delete-node/ &usbfs_phy; / { soc { diff --git a/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi b/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi index 7318ca9037918..aaf1020a755c3 100644 --- a/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi +++ b/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi @@ -300,6 +300,22 @@ }; }; + usbfs: usbfs@40090000 { + compatible = "renesas,ra-usbfs"; + reg = <0x40090000 0x2000>; + interrupts = <55 12>, <56 12>; + interrupt-names = "usbfs-i", "usbfs-r"; + num-bidir-endpoints = <10>; + phys = <&usbfs_phy>; + phys-clock = <&uclk>; + status = "disabled"; + + udc { + compatible = "renesas,ra-udc"; + status = "disabled"; + }; + }; + option_setting_ofs: option_setting_ofs@100a100 { compatible = "zephyr,memory-region"; reg = <0x0100a100 0x18>; @@ -514,6 +530,11 @@ status = "disabled"; }; }; + + usbfs_phy: usbfs-phy { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; }; &nvic { diff --git a/dts/arm/renesas/ra/ra6/ra6-cm4-common.dtsi b/dts/arm/renesas/ra/ra6/ra6-cm4-common.dtsi index 9f554cda1037f..b388b28c7ceba 100644 --- a/dts/arm/renesas/ra/ra6/ra6-cm4-common.dtsi +++ b/dts/arm/renesas/ra/ra6/ra6-cm4-common.dtsi @@ -319,6 +319,22 @@ }; }; + usbfs: usbfs@40090000 { + compatible = "renesas,ra-usbfs"; + reg = <0x40090000 0x2000>; + interrupts = <55 12>, <56 12>; + interrupt-names = "usbfs-i", "usbfs-r"; + num-bidir-endpoints = <10>; + phys = <&usbfs_phy>; + phys-clock = <&uclk>; + status = "disabled"; + + udc { + compatible = "renesas,ra-udc"; + status = "disabled"; + }; + }; + id_code: id_code@100a150 { compatible = "zephyr,memory-region"; reg = <0x0100a150 0x10>; @@ -609,6 +625,11 @@ interrupt-names = "frdyi", "fiferr"; }; }; + + usbfs_phy: usbfs-phy { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; }; &nvic { diff --git a/dts/arm/renesas/ra/ra8/ra8x1.dtsi b/dts/arm/renesas/ra/ra8/ra8x1.dtsi index 70b3c50182489..ab83f15aafa68 100644 --- a/dts/arm/renesas/ra/ra8/ra8x1.dtsi +++ b/dts/arm/renesas/ra/ra8/ra8x1.dtsi @@ -770,6 +770,27 @@ reg = <0x40252400 0x0400>; status = "disabled"; }; + + usbfs: usbfs@40250000 { + compatible = "renesas,ra-usbfs"; + reg = <0x40250000 0x2000>; + interrupts = <55 12>, <56 12>; + interrupt-names = "usbfs-i", "usbfs-r"; + num-bidir-endpoints = <10>; + phys = <&usbfs_phy>; + phys-clock = <&uclk>; + status = "disabled"; + + udc { + compatible = "renesas,ra-udc"; + status = "disabled"; + }; + }; + }; + + usbfs_phy: usbfs-phy { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; }; }; From b513a8db3479aaf9004d58ee9a0f2fc549912ce1 Mon Sep 17 00:00:00 2001 From: The Nguyen Date: Mon, 3 Feb 2025 13:20:19 +0700 Subject: [PATCH 0147/6055] dts: arm: renesas: add phys-clock for usbhs node Add phys-clock to usbhs node in case internal phys-clock-src is used Signed-off-by: The Nguyen --- dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi | 1 + dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi | 1 + dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi | 1 + dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi | 1 + 4 files changed, 4 insertions(+) diff --git a/dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi b/dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi index 5b9c66079f2fb..d705afc56947e 100644 --- a/dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi +++ b/dts/arm/renesas/ra/ra6/r7fa6m3ax.dtsi @@ -111,6 +111,7 @@ interrupt-names = "usbhs-ir"; num-bidir-endpoints = <10>; phys = <&usbhs_phy>; + phys-clock = <&uclk>; status = "disabled"; udc { compatible = "renesas,ra-udc"; diff --git a/dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi b/dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi index 77d32d26afc94..df6b6e6681297 100644 --- a/dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi +++ b/dts/arm/renesas/ra/ra6/r7fa6m5xh.dtsi @@ -201,6 +201,7 @@ interrupt-names = "usbhs-ir"; num-bidir-endpoints = <10>; phys = <&usbhs_phy>; + phys-clock = <&uclk>, <&u60clk>; status = "disabled"; udc { compatible = "renesas,ra-udc"; diff --git a/dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi b/dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi index e71cffebaf1f8..5ee87dd34fed1 100644 --- a/dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi +++ b/dts/arm/renesas/ra/ra8/r7fa8d1xh.dtsi @@ -286,6 +286,7 @@ interrupt-names = "usbhs-ir"; num-bidir-endpoints = <10>; phys = <&usbhs_phy>; + phys-clock = <&uclk>, <&u60clk>; status = "disabled"; udc { compatible = "renesas,ra-udc"; diff --git a/dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi b/dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi index a262e0e02ca00..57fa3dd97bfd6 100644 --- a/dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi +++ b/dts/arm/renesas/ra/ra8/r7fa8m1xh.dtsi @@ -250,6 +250,7 @@ interrupt-names = "usbhs-ir"; num-bidir-endpoints = <10>; phys = <&usbhs_phy>; + phys-clock = <&uclk>, <&u60clk>; status = "disabled"; udc { compatible = "renesas,ra-udc"; From c684fea123783a30a6d46ab5d6aec2567259e14b Mon Sep 17 00:00:00 2001 From: The Nguyen Date: Tue, 26 Nov 2024 18:23:38 +0700 Subject: [PATCH 0148/6055] boards: renesas: add support for USBFS port on Renesas RA boards Add USB support on USBFS port on these boards: - RA8: ek_ra8m1, ek_ra8d1, mck_ra8t1 - RA6: ek_ra6m1, ek_ra6m2, ek_ra6m3, ek_ra6m4, ek_ra6m5 - RA4: ek_ra4m2, ek_ra4m3, voice_ra4e1 Signed-off-by: The Nguyen --- boards/renesas/ek_ra4m2/doc/index.rst | 2 ++ boards/renesas/ek_ra4m2/ek_ra4m2-pinctrl.dtsi | 8 +++++++ boards/renesas/ek_ra4m2/ek_ra4m2.dts | 23 +++++++++++++++++++ boards/renesas/ek_ra4m2/ek_ra4m2.yaml | 2 ++ boards/renesas/ek_ra4m3/doc/index.rst | 2 ++ boards/renesas/ek_ra4m3/ek_ra4m3-pinctrl.dtsi | 8 +++++++ boards/renesas/ek_ra4m3/ek_ra4m3.dts | 23 +++++++++++++++++++ boards/renesas/ek_ra4m3/ek_ra4m3.yaml | 2 ++ boards/renesas/ek_ra6m1/doc/index.rst | 2 ++ boards/renesas/ek_ra6m1/ek_ra6m1-pinctrl.dtsi | 8 +++++++ boards/renesas/ek_ra6m1/ek_ra6m1.dts | 16 +++++++++++++ boards/renesas/ek_ra6m1/ek_ra6m1.yaml | 2 ++ boards/renesas/ek_ra6m2/doc/index.rst | 2 ++ boards/renesas/ek_ra6m2/ek_ra6m2-pinctrl.dtsi | 8 +++++++ boards/renesas/ek_ra6m2/ek_ra6m2.dts | 16 +++++++++++++ boards/renesas/ek_ra6m2/ek_ra6m2.yaml | 2 ++ boards/renesas/ek_ra6m3/doc/index.rst | 2 ++ boards/renesas/ek_ra6m3/ek_ra6m3-pinctrl.dtsi | 8 +++++++ boards/renesas/ek_ra6m3/ek_ra6m3.dts | 12 ++++++++++ boards/renesas/ek_ra6m3/ek_ra6m3.yaml | 2 ++ boards/renesas/ek_ra6m4/doc/index.rst | 2 ++ boards/renesas/ek_ra6m4/ek_ra6m4-pinctrl.dtsi | 8 +++++++ boards/renesas/ek_ra6m4/ek_ra6m4.dts | 23 +++++++++++++++++++ boards/renesas/ek_ra6m4/ek_ra6m4.yaml | 2 ++ boards/renesas/ek_ra6m5/doc/index.rst | 2 ++ boards/renesas/ek_ra6m5/ek_ra6m5-pinctrl.dtsi | 8 +++++++ boards/renesas/ek_ra6m5/ek_ra6m5.dts | 19 +++++++++++++++ boards/renesas/ek_ra6m5/ek_ra6m5.yaml | 2 ++ boards/renesas/ek_ra8d1/doc/index.rst | 2 ++ boards/renesas/ek_ra8d1/ek_ra8d1-pinctrl.dtsi | 10 ++++++++ boards/renesas/ek_ra8d1/ek_ra8d1.dts | 14 +++++++++++ boards/renesas/ek_ra8d1/ek_ra8d1.yaml | 2 ++ boards/renesas/ek_ra8m1/doc/index.rst | 2 ++ boards/renesas/ek_ra8m1/ek_ra8m1-pinctrl.dtsi | 10 ++++++++ boards/renesas/ek_ra8m1/ek_ra8m1.dts | 14 +++++++++++ boards/renesas/ek_ra8m1/ek_ra8m1.yaml | 2 ++ boards/renesas/mck_ra8t1/doc/index.rst | 2 ++ .../renesas/mck_ra8t1/mck_ra8t1-pinctrl.dtsi | 10 ++++++++ boards/renesas/mck_ra8t1/mck_ra8t1.dts | 18 +++++++++++++++ boards/renesas/mck_ra8t1/mck_ra8t1.yaml | 2 ++ boards/renesas/voice_ra4e1/doc/index.rst | 2 ++ .../voice_ra4e1/voice_ra4e1-pinctrl.dtsi | 8 +++++++ boards/renesas/voice_ra4e1/voice_ra4e1.dts | 23 +++++++++++++++++++ boards/renesas/voice_ra4e1/voice_ra4e1.yaml | 2 ++ 44 files changed, 339 insertions(+) diff --git a/boards/renesas/ek_ra4m2/doc/index.rst b/boards/renesas/ek_ra4m2/doc/index.rst index 6d66b8ac1b3ff..1719bf3187e8e 100644 --- a/boards/renesas/ek_ra4m2/doc/index.rst +++ b/boards/renesas/ek_ra4m2/doc/index.rst @@ -114,6 +114,8 @@ The below features are currently supported on Zephyr OS for EK-RA4M2 board: +-----------+------------+----------------------+ | DAC | on-chip | dac | +-----------+------------+----------------------+ +| USBFS | on-chip | udc | ++-----------+------------+----------------------+ Other hardware features are currently not supported by the port. diff --git a/boards/renesas/ek_ra4m2/ek_ra4m2-pinctrl.dtsi b/boards/renesas/ek_ra4m2/ek_ra4m2-pinctrl.dtsi index 205c1eb4f5ed2..97e386641c8ec 100644 --- a/boards/renesas/ek_ra4m2/ek_ra4m2-pinctrl.dtsi +++ b/boards/renesas/ek_ra4m2/ek_ra4m2-pinctrl.dtsi @@ -54,4 +54,12 @@ drive-strength = "medium"; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USB_VBUS */ + psels = ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra4m2/ek_ra4m2.dts b/boards/renesas/ek_ra4m2/ek_ra4m2.dts index acd5aed6b6a41..b0800e68de02c 100644 --- a/boards/renesas/ek_ra4m2/ek_ra4m2.dts +++ b/boards/renesas/ek_ra4m2/ek_ra4m2.dts @@ -79,6 +79,19 @@ status = "okay"; }; +&pll2 { + clocks = <&xtal>; + div = <2>; + mul = <20 0>; + status = "okay"; +}; + +&uclk { + clocks = <&pll2>; + div = <5>; + status = "okay"; +}; + &sci0 { pinctrl-0 = <&sci0_default>; pinctrl-names = "default"; @@ -160,3 +173,13 @@ &trng { status = "okay"; }; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; + status = "okay"; + zephyr_udc0: udc { + status = "okay"; + }; +}; diff --git a/boards/renesas/ek_ra4m2/ek_ra4m2.yaml b/boards/renesas/ek_ra4m2/ek_ra4m2.yaml index d61c6bf05fe82..a32c36021c478 100644 --- a/boards/renesas/ek_ra4m2/ek_ra4m2.yaml +++ b/boards/renesas/ek_ra4m2/ek_ra4m2.yaml @@ -10,3 +10,5 @@ toolchain: supported: - gpio - uart + - usbd +vendor: renesas diff --git a/boards/renesas/ek_ra4m3/doc/index.rst b/boards/renesas/ek_ra4m3/doc/index.rst index b57781215e007..8ed2359c08d4f 100644 --- a/boards/renesas/ek_ra4m3/doc/index.rst +++ b/boards/renesas/ek_ra4m3/doc/index.rst @@ -116,6 +116,8 @@ The below features are currently supported on Zephyr OS for EK-RA4M3 board: +-----------+------------+----------------------+ | DAC | on-chip | dac | +-----------+------------+----------------------+ +| USBFS | on-chip | udc | ++-----------+------------+----------------------+ Other hardware features are currently not supported by the port. diff --git a/boards/renesas/ek_ra4m3/ek_ra4m3-pinctrl.dtsi b/boards/renesas/ek_ra4m3/ek_ra4m3-pinctrl.dtsi index f9b7c31fe47b8..0b574b13c5ffb 100644 --- a/boards/renesas/ek_ra4m3/ek_ra4m3-pinctrl.dtsi +++ b/boards/renesas/ek_ra4m3/ek_ra4m3-pinctrl.dtsi @@ -54,4 +54,12 @@ drive-strength = "medium"; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USB_VBUS */ + psels = ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra4m3/ek_ra4m3.dts b/boards/renesas/ek_ra4m3/ek_ra4m3.dts index e58e910cf0962..903c9997c9ae8 100644 --- a/boards/renesas/ek_ra4m3/ek_ra4m3.dts +++ b/boards/renesas/ek_ra4m3/ek_ra4m3.dts @@ -79,6 +79,19 @@ status = "okay"; }; +&pll2 { + clocks = <&xtal>; + div = <3>; + mul = <24 0>; + status = "okay"; +}; + +&uclk { + clocks = <&pll2>; + div = <4>; + status = "okay"; +}; + &sci0 { pinctrl-0 = <&sci0_default>; pinctrl-names = "default"; @@ -160,3 +173,13 @@ &trng { status = "okay"; }; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; + status = "okay"; + zephyr_udc0: udc { + status = "okay"; + }; +}; diff --git a/boards/renesas/ek_ra4m3/ek_ra4m3.yaml b/boards/renesas/ek_ra4m3/ek_ra4m3.yaml index e05b8e804da78..6abc856677445 100644 --- a/boards/renesas/ek_ra4m3/ek_ra4m3.yaml +++ b/boards/renesas/ek_ra4m3/ek_ra4m3.yaml @@ -10,3 +10,5 @@ toolchain: supported: - gpio - uart + - usbd +vendor: renesas diff --git a/boards/renesas/ek_ra6m1/doc/index.rst b/boards/renesas/ek_ra6m1/doc/index.rst index 78ea7c4bffb45..0394397ce07e2 100644 --- a/boards/renesas/ek_ra6m1/doc/index.rst +++ b/boards/renesas/ek_ra6m1/doc/index.rst @@ -108,6 +108,8 @@ The below features are currently supported on Zephyr OS for EK-RA6M1 board: +-----------+------------+----------------------+ | DAC | on-chip | dac | +-----------+------------+----------------------+ +| USBFS | on-chip | udc | ++-----------+------------+----------------------+ Other hardware features are currently not supported by the port. diff --git a/boards/renesas/ek_ra6m1/ek_ra6m1-pinctrl.dtsi b/boards/renesas/ek_ra6m1/ek_ra6m1-pinctrl.dtsi index bb51b310e29f3..87e76e218caea 100644 --- a/boards/renesas/ek_ra6m1/ek_ra6m1-pinctrl.dtsi +++ b/boards/renesas/ek_ra6m1/ek_ra6m1-pinctrl.dtsi @@ -54,4 +54,12 @@ ; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USB_VBUS */ + psels = ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra6m1/ek_ra6m1.dts b/boards/renesas/ek_ra6m1/ek_ra6m1.dts index 0d0c9b8156ee8..c89506b825312 100644 --- a/boards/renesas/ek_ra6m1/ek_ra6m1.dts +++ b/boards/renesas/ek_ra6m1/ek_ra6m1.dts @@ -142,3 +142,19 @@ }; }; }; + +&uclk { + clocks = <&pll>; + div = <5>; + status = "okay"; +}; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; + status = "okay"; + zephyr_udc0: udc { + status = "okay"; + }; +}; diff --git a/boards/renesas/ek_ra6m1/ek_ra6m1.yaml b/boards/renesas/ek_ra6m1/ek_ra6m1.yaml index 92e8d569db224..5d23e1841edea 100644 --- a/boards/renesas/ek_ra6m1/ek_ra6m1.yaml +++ b/boards/renesas/ek_ra6m1/ek_ra6m1.yaml @@ -10,3 +10,5 @@ toolchain: supported: - gpio - uart + - usbd +vendor: renesas diff --git a/boards/renesas/ek_ra6m2/doc/index.rst b/boards/renesas/ek_ra6m2/doc/index.rst index 2e9d6a0612c35..b0cd6689c65a6 100644 --- a/boards/renesas/ek_ra6m2/doc/index.rst +++ b/boards/renesas/ek_ra6m2/doc/index.rst @@ -102,6 +102,8 @@ The below features are currently supported on Zephyr OS for EK-RA6M2 board: +-----------+------------+----------------------+ | DAC | on-chip | dac | +-----------+------------+----------------------+ +| USBFS | on-chip | udc | ++-----------+------------+----------------------+ Other hardware features are currently not supported by the port. diff --git a/boards/renesas/ek_ra6m2/ek_ra6m2-pinctrl.dtsi b/boards/renesas/ek_ra6m2/ek_ra6m2-pinctrl.dtsi index b6c1265b43b2c..85a43362ea8c7 100644 --- a/boards/renesas/ek_ra6m2/ek_ra6m2-pinctrl.dtsi +++ b/boards/renesas/ek_ra6m2/ek_ra6m2-pinctrl.dtsi @@ -54,4 +54,12 @@ ; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USB_VBUS */ + psels = ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra6m2/ek_ra6m2.dts b/boards/renesas/ek_ra6m2/ek_ra6m2.dts index 8932a511ab91f..5fcd07f5ad50a 100644 --- a/boards/renesas/ek_ra6m2/ek_ra6m2.dts +++ b/boards/renesas/ek_ra6m2/ek_ra6m2.dts @@ -138,3 +138,19 @@ }; }; }; + +&uclk { + clocks = <&pll>; + div = <5>; + status = "okay"; +}; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; + status = "okay"; + zephyr_udc0: udc { + status = "okay"; + }; +}; diff --git a/boards/renesas/ek_ra6m2/ek_ra6m2.yaml b/boards/renesas/ek_ra6m2/ek_ra6m2.yaml index 3f3c049c5e563..8ddf34e307c86 100644 --- a/boards/renesas/ek_ra6m2/ek_ra6m2.yaml +++ b/boards/renesas/ek_ra6m2/ek_ra6m2.yaml @@ -9,3 +9,5 @@ toolchain: - gnuarmemb supported: - gpio + - usbd +vendor: renesas diff --git a/boards/renesas/ek_ra6m3/doc/index.rst b/boards/renesas/ek_ra6m3/doc/index.rst index 61e427a7bee4c..a26a24c6e2369 100644 --- a/boards/renesas/ek_ra6m3/doc/index.rst +++ b/boards/renesas/ek_ra6m3/doc/index.rst @@ -104,6 +104,8 @@ The below features are currently supported on Zephyr OS for EK-RA6M3 board: +-----------+------------+----------------------+ | USBHS | on-chip | udc | +-----------+------------+----------------------+ +| USBFS | on-chip | udc | ++-----------+------------+----------------------+ | ADC | on-chip | adc | +-----------+------------+----------------------+ | PWM | on-chip | pwm | diff --git a/boards/renesas/ek_ra6m3/ek_ra6m3-pinctrl.dtsi b/boards/renesas/ek_ra6m3/ek_ra6m3-pinctrl.dtsi index bd2e69903d8a1..525b985659d8a 100644 --- a/boards/renesas/ek_ra6m3/ek_ra6m3-pinctrl.dtsi +++ b/boards/renesas/ek_ra6m3/ek_ra6m3-pinctrl.dtsi @@ -61,4 +61,12 @@ ; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USB_VBUS */ + psels = ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra6m3/ek_ra6m3.dts b/boards/renesas/ek_ra6m3/ek_ra6m3.dts index 1f19d1f103f5f..6876f280e4e40 100644 --- a/boards/renesas/ek_ra6m3/ek_ra6m3.dts +++ b/boards/renesas/ek_ra6m3/ek_ra6m3.dts @@ -123,6 +123,12 @@ status ="okay"; }; +&uclk { + clocks = <&pll>; + div = <5>; + status = "okay"; +}; + &usbhs { pinctrl-0 = <&usbhs_default>; pinctrl-names = "default"; @@ -179,3 +185,9 @@ }; }; }; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; +}; diff --git a/boards/renesas/ek_ra6m3/ek_ra6m3.yaml b/boards/renesas/ek_ra6m3/ek_ra6m3.yaml index 50cc8737e921f..16aa58a8f5c6d 100644 --- a/boards/renesas/ek_ra6m3/ek_ra6m3.yaml +++ b/boards/renesas/ek_ra6m3/ek_ra6m3.yaml @@ -9,3 +9,5 @@ toolchain: - gnuarmemb supported: - gpio + - usbd +vendor: renesas diff --git a/boards/renesas/ek_ra6m4/doc/index.rst b/boards/renesas/ek_ra6m4/doc/index.rst index 526757e77b7c9..7a550ccf80cee 100644 --- a/boards/renesas/ek_ra6m4/doc/index.rst +++ b/boards/renesas/ek_ra6m4/doc/index.rst @@ -117,6 +117,8 @@ The below features are currently supported on Zephyr OS for EK-RA6M4 board: +-----------+------------+----------------------+ | DAC | on-chip | dac | +-----------+------------+----------------------+ +| USBFS | on-chip | udc | ++-----------+------------+----------------------+ Other hardware features are currently not supported by the port. diff --git a/boards/renesas/ek_ra6m4/ek_ra6m4-pinctrl.dtsi b/boards/renesas/ek_ra6m4/ek_ra6m4-pinctrl.dtsi index df284f33df345..86e7a2506f813 100644 --- a/boards/renesas/ek_ra6m4/ek_ra6m4-pinctrl.dtsi +++ b/boards/renesas/ek_ra6m4/ek_ra6m4-pinctrl.dtsi @@ -54,4 +54,12 @@ ; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USB_VBUS */ + psels = ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra6m4/ek_ra6m4.dts b/boards/renesas/ek_ra6m4/ek_ra6m4.dts index 6356fa35491de..3eda814aa1bda 100644 --- a/boards/renesas/ek_ra6m4/ek_ra6m4.dts +++ b/boards/renesas/ek_ra6m4/ek_ra6m4.dts @@ -115,6 +115,13 @@ status = "okay"; }; +&pll2 { + clocks = <&hoco>; + div = <2>; + mul = <24 0>; + status = "okay"; +}; + &pclka { clocks = <&pll>; div = <2>; @@ -167,3 +174,19 @@ &trng { status = "okay"; }; + +&uclk { + clocks = <&pll2>; + div = <5>; + status = "okay"; +}; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; + status = "okay"; + zephyr_udc0: udc { + status = "okay"; + }; +}; diff --git a/boards/renesas/ek_ra6m4/ek_ra6m4.yaml b/boards/renesas/ek_ra6m4/ek_ra6m4.yaml index d9488b99e8129..6f6f324f20253 100644 --- a/boards/renesas/ek_ra6m4/ek_ra6m4.yaml +++ b/boards/renesas/ek_ra6m4/ek_ra6m4.yaml @@ -9,3 +9,5 @@ toolchain: - gnuarmemb supported: - gpio + - usbd +vendor: renesas diff --git a/boards/renesas/ek_ra6m5/doc/index.rst b/boards/renesas/ek_ra6m5/doc/index.rst index 79340026186cd..f3d074f373bd9 100644 --- a/boards/renesas/ek_ra6m5/doc/index.rst +++ b/boards/renesas/ek_ra6m5/doc/index.rst @@ -117,6 +117,8 @@ The below features are currently supported on Zephyr OS for EK-RA6M5 board: +-----------+------------+----------------------+ | DAC | on-chip | dac | +-----------+------------+----------------------+ +| USBFS | on-chip | udc | ++-----------+------------+----------------------+ Other hardware features are currently not supported by the port. diff --git a/boards/renesas/ek_ra6m5/ek_ra6m5-pinctrl.dtsi b/boards/renesas/ek_ra6m5/ek_ra6m5-pinctrl.dtsi index e5828ec9e7067..b279f0540ad1b 100644 --- a/boards/renesas/ek_ra6m5/ek_ra6m5-pinctrl.dtsi +++ b/boards/renesas/ek_ra6m5/ek_ra6m5-pinctrl.dtsi @@ -61,4 +61,12 @@ ; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USB_VBUS */ + psels = ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra6m5/ek_ra6m5.dts b/boards/renesas/ek_ra6m5/ek_ra6m5.dts index 55f1eb43b5d21..929765d4f9b3d 100644 --- a/boards/renesas/ek_ra6m5/ek_ra6m5.dts +++ b/boards/renesas/ek_ra6m5/ek_ra6m5.dts @@ -111,6 +111,19 @@ status = "okay"; }; +&pll2 { + clocks = <&xtal>; + div = <2>; + mul = <20 0>; + status = "okay"; +}; + +&uclk { + clocks = <&pll2>; + div = <5>; + status = "okay"; +}; + &usbhs { pinctrl-0 = <&usbhs_default>; pinctrl-names = "default"; @@ -171,3 +184,9 @@ &trng { status = "okay"; }; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; +}; diff --git a/boards/renesas/ek_ra6m5/ek_ra6m5.yaml b/boards/renesas/ek_ra6m5/ek_ra6m5.yaml index 2f65bfb229d83..4ce78217fd2f7 100644 --- a/boards/renesas/ek_ra6m5/ek_ra6m5.yaml +++ b/boards/renesas/ek_ra6m5/ek_ra6m5.yaml @@ -9,3 +9,5 @@ toolchain: - gnuarmemb supported: - gpio + - usbd +vendor: renesas diff --git a/boards/renesas/ek_ra8d1/doc/index.rst b/boards/renesas/ek_ra8d1/doc/index.rst index 4e0a8dd02db10..a66c98a974247 100644 --- a/boards/renesas/ek_ra8d1/doc/index.rst +++ b/boards/renesas/ek_ra8d1/doc/index.rst @@ -114,6 +114,8 @@ The below features are currently supported on Zephyr OS for EK-RA8D1 board: +--------------+------------+-----------------------------------+ | USBHS | on-chip | udc | +--------------+------------+-----------------------------------+ +| USBFS | on-chip | udc | ++--------------+------------+-----------------------------------+ | DISPLAY | on-chip | LCDIF; MIPI-DSI. Tested with | | | | :ref:`rtkmipilcdb00000be` shields | +--------------+------------+-----------------------------------+ diff --git a/boards/renesas/ek_ra8d1/ek_ra8d1-pinctrl.dtsi b/boards/renesas/ek_ra8d1/ek_ra8d1-pinctrl.dtsi index ec6f0bd16dce3..4ae1dcec244a2 100644 --- a/boards/renesas/ek_ra8d1/ek_ra8d1-pinctrl.dtsi +++ b/boards/renesas/ek_ra8d1/ek_ra8d1-pinctrl.dtsi @@ -269,4 +269,14 @@ drive-strength = "highspeed-high"; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USBP USBN */ + psels = , + , + ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra8d1/ek_ra8d1.dts b/boards/renesas/ek_ra8d1/ek_ra8d1.dts index c4a51f71103e8..8fa8bb7c4f6ac 100644 --- a/boards/renesas/ek_ra8d1/ek_ra8d1.dts +++ b/boards/renesas/ek_ra8d1/ek_ra8d1.dts @@ -103,6 +103,8 @@ }; pllq { + div = <4>; + freq = ; status = "okay"; }; @@ -130,6 +132,12 @@ status = "okay"; }; +&uclk { + clocks = <&pllq>; + div = <5>; + status = "okay"; +}; + &ioport0 { status = "okay"; }; @@ -300,3 +308,9 @@ zephyr_mipi_dsi: &mipi_dsi {}; renesas_mipi_i2c: &iic1{}; pmod_sd_shield: &sdhc1 {}; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; +}; diff --git a/boards/renesas/ek_ra8d1/ek_ra8d1.yaml b/boards/renesas/ek_ra8d1/ek_ra8d1.yaml index 2432f8ed657c6..49272cd4c480a 100644 --- a/boards/renesas/ek_ra8d1/ek_ra8d1.yaml +++ b/boards/renesas/ek_ra8d1/ek_ra8d1.yaml @@ -10,3 +10,5 @@ toolchain: supported: - gpio - uart + - usbd +vendor: renesas diff --git a/boards/renesas/ek_ra8m1/doc/index.rst b/boards/renesas/ek_ra8m1/doc/index.rst index c7afb0cd641b3..31dd6fa78208c 100644 --- a/boards/renesas/ek_ra8m1/doc/index.rst +++ b/boards/renesas/ek_ra8m1/doc/index.rst @@ -114,6 +114,8 @@ The below features are currently supported on Zephyr OS for EK-RA8M1 board: +-----------+------------+----------------------+ | USBHS | on-chip | udc | +-----------+------------+----------------------+ +| USBFS | on-chip | udc | ++-----------+------------+----------------------+ | ETHERNET | on-chip | ethernet | +-----------+------------+----------------------+ | ADC | on-chip | adc | diff --git a/boards/renesas/ek_ra8m1/ek_ra8m1-pinctrl.dtsi b/boards/renesas/ek_ra8m1/ek_ra8m1-pinctrl.dtsi index 0aa9e44d5af55..cdb7b3f9c9337 100644 --- a/boards/renesas/ek_ra8m1/ek_ra8m1-pinctrl.dtsi +++ b/boards/renesas/ek_ra8m1/ek_ra8m1-pinctrl.dtsi @@ -146,4 +146,14 @@ drive-strength = "highspeed-high"; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USBP USBN */ + psels = , + , + ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra8m1/ek_ra8m1.dts b/boards/renesas/ek_ra8m1/ek_ra8m1.dts index 551ca1ff7a928..08858dc5be93c 100644 --- a/boards/renesas/ek_ra8m1/ek_ra8m1.dts +++ b/boards/renesas/ek_ra8m1/ek_ra8m1.dts @@ -140,6 +140,8 @@ }; pllq { + div = <4>; + freq = ; status = "okay"; }; @@ -161,6 +163,12 @@ status = "okay"; }; +&uclk { + clocks = <&pllq>; + div = <5>; + status = "okay"; +}; + &ioport0 { status = "okay"; }; @@ -355,3 +363,9 @@ pmod_header: &pmod1_header {}; }; pmod_sd_shield: &sdhc0 {}; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; +}; diff --git a/boards/renesas/ek_ra8m1/ek_ra8m1.yaml b/boards/renesas/ek_ra8m1/ek_ra8m1.yaml index 28c7aa4296b7b..8e3881a1a2d5d 100644 --- a/boards/renesas/ek_ra8m1/ek_ra8m1.yaml +++ b/boards/renesas/ek_ra8m1/ek_ra8m1.yaml @@ -10,3 +10,5 @@ toolchain: supported: - gpio - uart + - usbd +vendor: renesas diff --git a/boards/renesas/mck_ra8t1/doc/index.rst b/boards/renesas/mck_ra8t1/doc/index.rst index b2ac68a698110..339a917fff579 100644 --- a/boards/renesas/mck_ra8t1/doc/index.rst +++ b/boards/renesas/mck_ra8t1/doc/index.rst @@ -118,6 +118,8 @@ The below features are currently supported on Zephyr OS for MCB-RA8T1 board: +--------------+------------+----------------------+ | DAC | on-chip | dac | +--------------+------------+----------------------+ +| USBFS | on-chip | udc | ++--------------+------------+----------------------+ **Note:** For using SDHC module on EK-RA8M1, Connect microSD Card to microSD Socket (CN12) diff --git a/boards/renesas/mck_ra8t1/mck_ra8t1-pinctrl.dtsi b/boards/renesas/mck_ra8t1/mck_ra8t1-pinctrl.dtsi index fd4ab139aa4a0..1ceb15c547e87 100644 --- a/boards/renesas/mck_ra8t1/mck_ra8t1-pinctrl.dtsi +++ b/boards/renesas/mck_ra8t1/mck_ra8t1-pinctrl.dtsi @@ -103,4 +103,14 @@ drive-strength = "highspeed-high"; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USBP USBN */ + psels = , + , + ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/mck_ra8t1/mck_ra8t1.dts b/boards/renesas/mck_ra8t1/mck_ra8t1.dts index 08be2e4d9963e..763f794a99789 100644 --- a/boards/renesas/mck_ra8t1/mck_ra8t1.dts +++ b/boards/renesas/mck_ra8t1/mck_ra8t1.dts @@ -68,6 +68,8 @@ }; pllq { + div = <4>; + freq = ; status = "okay"; }; @@ -88,6 +90,12 @@ status = "okay"; }; +&uclk { + clocks = <&pllq>; + div = <5>; + status = "okay"; +}; + &ioport3 { status = "okay"; }; @@ -202,3 +210,13 @@ status = "okay"; }; }; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; + status = "okay"; + zephyr_udc0: udc { + status = "okay"; + }; +}; diff --git a/boards/renesas/mck_ra8t1/mck_ra8t1.yaml b/boards/renesas/mck_ra8t1/mck_ra8t1.yaml index 52ef233d98f82..f4a0d4e8af2ff 100644 --- a/boards/renesas/mck_ra8t1/mck_ra8t1.yaml +++ b/boards/renesas/mck_ra8t1/mck_ra8t1.yaml @@ -10,3 +10,5 @@ toolchain: supported: - gpio - uart + - usbd +vendor: renesas diff --git a/boards/renesas/voice_ra4e1/doc/index.rst b/boards/renesas/voice_ra4e1/doc/index.rst index 846701d20fdf4..cdf1e4ef78fd3 100644 --- a/boards/renesas/voice_ra4e1/doc/index.rst +++ b/boards/renesas/voice_ra4e1/doc/index.rst @@ -76,6 +76,8 @@ The below features are currently supported on Zephyr for the ``voice_ra4e1`` boa +-----------+------------+----------------------+ | FLASH | on-chip | flash | +-----------+------------+----------------------+ +| USBFS | on-chip | udc | ++-----------+------------+----------------------+ Other hardware features are currently not supported by the port. diff --git a/boards/renesas/voice_ra4e1/voice_ra4e1-pinctrl.dtsi b/boards/renesas/voice_ra4e1/voice_ra4e1-pinctrl.dtsi index 6968b20dadb6a..48093d9a49495 100644 --- a/boards/renesas/voice_ra4e1/voice_ra4e1-pinctrl.dtsi +++ b/boards/renesas/voice_ra4e1/voice_ra4e1-pinctrl.dtsi @@ -11,4 +11,12 @@ ; }; }; + + usbfs_default: usbfs_default { + group1 { + /* USB_VBUS */ + psels = ; + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/voice_ra4e1/voice_ra4e1.dts b/boards/renesas/voice_ra4e1/voice_ra4e1.dts index cc01c703825cf..9c756b0d6459f 100644 --- a/boards/renesas/voice_ra4e1/voice_ra4e1.dts +++ b/boards/renesas/voice_ra4e1/voice_ra4e1.dts @@ -60,6 +60,19 @@ status = "okay"; }; +&pll2 { + clocks = <&hoco>; + div = <2>; + mul = <24 0>; + status = "okay"; +}; + +&uclk { + clocks = <&pll2>; + div = <5>; + status = "okay"; +}; + &sci3 { interrupts = <16 1>, <17 1>, <18 1>, <19 1>; interrupt-names = "rxi", "txi", "tei", "eri"; @@ -110,3 +123,13 @@ }; }; }; + +&usbfs { + pinctrl-0 = <&usbfs_default>; + pinctrl-names = "default"; + maximum-speed = "full-speed"; + status = "okay"; + zephyr_udc0: udc { + status = "okay"; + }; +}; diff --git a/boards/renesas/voice_ra4e1/voice_ra4e1.yaml b/boards/renesas/voice_ra4e1/voice_ra4e1.yaml index fd64e1fff59e8..f6051167fff09 100644 --- a/boards/renesas/voice_ra4e1/voice_ra4e1.yaml +++ b/boards/renesas/voice_ra4e1/voice_ra4e1.yaml @@ -10,3 +10,5 @@ toolchain: supported: - gpio - uart + - usbd +vendor: renesas From 16d5d5e480ab892ab47ce8ea3e522362eced87e1 Mon Sep 17 00:00:00 2001 From: Mubin Sayyed Date: Wed, 29 Jan 2025 08:19:33 +0000 Subject: [PATCH 0149/6055] west_commands: runners: Fix parameters passed to xsdb Existing logic is passing elf file as parameter only when fsbl or bit file parameter is present. This is incorrect, elf file should be always passed irrespective of other parameters. Signed-off-by: Mubin Sayyed --- scripts/west_commands/runners/xsdb.py | 2 +- scripts/west_commands/tests/test_xsdb.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/west_commands/runners/xsdb.py b/scripts/west_commands/runners/xsdb.py index e084a917a0ccc..7029a3a9354ae 100644 --- a/scripts/west_commands/runners/xsdb.py +++ b/scripts/west_commands/runners/xsdb.py @@ -54,5 +54,5 @@ def do_run(self, command, **kwargs): elif self.fsbl: cmd = ['xsdb', self.xsdb_cfg_file, self.elf_file, self.fsbl] else: - cmd = ['xsdb', self.xsdb_cfg_file] + cmd = ['xsdb', self.xsdb_cfg_file, self.elf_file] self.check_call(cmd) diff --git a/scripts/west_commands/tests/test_xsdb.py b/scripts/west_commands/tests/test_xsdb.py index ca97e7ad5118b..0711da5f38e3e 100644 --- a/scripts/west_commands/tests/test_xsdb.py +++ b/scripts/west_commands/tests/test_xsdb.py @@ -13,13 +13,13 @@ "config": None, "bitstream": None, "fsbl": None, - "expected_cmd": ["xsdb", "default_cfg_path"], + "expected_cmd": ["xsdb", "default_cfg_path", RC_KERNEL_ELF], }, { "config": "custom_cfg_path", "bitstream": None, "fsbl": None, - "expected_cmd": ["xsdb", "custom_cfg_path"], + "expected_cmd": ["xsdb", "custom_cfg_path", RC_KERNEL_ELF], }, { "config": None, From 2f2a91a8db7b872ae661538880da0a58ce6ef2a8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 13 Feb 2025 17:50:26 +0100 Subject: [PATCH 0150/6055] samples/*/*shell: filter test with shell harness on bsim targets The shell harness expects the UART can be routed to stdin/out on POSIX arch based targets, but this is not the case for the bsim targets (at least not yet, and not using the native_posix UART configuration option) This causes these tests to fail timing out in CI => let's filter these platforms by now. Signed-off-by: Alberto Escolar Piedras --- samples/drivers/flash_shell/sample.yaml | 1 + samples/subsys/shell/shell_module/sample.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/drivers/flash_shell/sample.yaml b/samples/drivers/flash_shell/sample.yaml index 01c5596b6ee84..dff4a058b1f90 100644 --- a/samples/drivers/flash_shell/sample.yaml +++ b/samples/drivers/flash_shell/sample.yaml @@ -7,6 +7,7 @@ tests: - flash - shell filter: CONFIG_FLASH_HAS_DRIVER_ENABLED and dt_chosen_enabled('zephyr,flash-controller') + and not CONFIG_SOC_SERIES_BSIM_NRFXX platform_exclude: - stm32h7s78_dk - gd32f350r_eval diff --git a/samples/subsys/shell/shell_module/sample.yaml b/samples/subsys/shell/shell_module/sample.yaml index 3c439e928cac3..70ea442d93b34 100644 --- a/samples/subsys/shell/shell_module/sample.yaml +++ b/samples/subsys/shell/shell_module/sample.yaml @@ -1,7 +1,7 @@ sample: name: Shell Sample common: - filter: not CONFIG_NATIVE_LIBC + filter: not CONFIG_NATIVE_LIBC and not CONFIG_SOC_SERIES_BSIM_NRFXX platform_exclude: - native_posix - native_posix/native/64 From ee37a94aa81f0f98879f615dd31c8cab4d322240 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Fri, 14 Feb 2025 04:01:06 +0100 Subject: [PATCH 0151/6055] sensor: xbr818: struct sensor... to DEVICE_API This makes static const struct sensor_driver_api into DEVICE_API(sensor Signed-off-by: Camille BAUD --- drivers/sensor/xbr818/xbr818.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/xbr818/xbr818.c b/drivers/sensor/xbr818/xbr818.c index be396ec620e6d..1b426cbfefe59 100644 --- a/drivers/sensor/xbr818/xbr818.c +++ b/drivers/sensor/xbr818/xbr818.c @@ -410,7 +410,7 @@ static int xbr818_init(const struct device *dev) return ret; } -static const struct sensor_driver_api xbr818_api = { +static DEVICE_API(sensor, xbr818_api) = { .sample_fetch = xbr818_sample_fetch, .channel_get = xbr818_channel_get, .attr_set = xbr818_attr_set, From 099970e130003d63adbea9b5a618b1e4bfabd06c Mon Sep 17 00:00:00 2001 From: Lubos Koudelka Date: Wed, 5 Feb 2025 10:30:57 +0100 Subject: [PATCH 0152/6055] dt-bindings: clock: Add MCO register definition for STM32WBA Added MCO register definition to support MCO functionality in the STM32WBA series. This update also includes the addition of MCO_PRE_DIV and MCO_SEL defines. Signed-off-by: Lubos Koudelka --- .../zephyr/dt-bindings/clock/stm32wba_clock.h | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/zephyr/dt-bindings/clock/stm32wba_clock.h b/include/zephyr/dt-bindings/clock/stm32wba_clock.h index b8baaada6be88..51c7b398d0435 100644 --- a/include/zephyr/dt-bindings/clock/stm32wba_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wba_clock.h @@ -100,5 +100,29 @@ #define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 12, CCIPR3_REG) /** BCDR1 devices */ #define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BCDR1_REG) +/** @brief RCC_CFGRx register offset */ +#define CFGR1_REG 0x1C +/** CFGR1 devices */ +#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0xF, 24, CFGR1_REG) +#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 28, CFGR1_REG) + +/* MCO prescaler : division factor */ +#define MCO_PRE_DIV_1 0 +#define MCO_PRE_DIV_2 1 +#define MCO_PRE_DIV_4 2 +#define MCO_PRE_DIV_8 3 +#define MCO_PRE_DIV_16 4 + +/* MCO clock output */ +#define MCO_SEL_SYSCLKPRE 1 +#define MCO_SEL_HSI16 3 +#define MCO_SEL_HSE32 4 +#define MCO_SEL_PLL1RCLK 5 +#define MCO_SEL_LSI 6 +#define MCO_SEL_LSE 7 +#define MCO_SEL_PLL1PCLK 8 +#define MCO_SEL_PLL1QCLK 9 +#define MCO_SEL_HCLK5 10 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_H_ */ From 21e4084917110308346b1e1c91204c4d27d845c2 Mon Sep 17 00:00:00 2001 From: Lubos Koudelka Date: Wed, 5 Feb 2025 10:31:43 +0100 Subject: [PATCH 0153/6055] dts: arm: st: wba: Add MCO1 peripheral to STM32WBA device tree Added MCO1 peripheral definition to the STM32WBA device tree to enable MCO functionality. Signed-off-by: Lubos Koudelka --- dts/arm/st/wba/stm32wba.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 713c913da5e21..697d7789b03c4 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -118,6 +118,13 @@ }; }; + mcos { + mco1: mco1 { + compatible = "st,stm32-clock-mco"; + status = "disabled"; + }; + }; + soc { flash: flash-controller@40022000 { compatible = "st,stm32-flash-controller", "st,stm32wba-flash-controller"; From 64e48014cd3c61f2fb21035d4b570002e7ce8412 Mon Sep 17 00:00:00 2001 From: Lubos Koudelka Date: Wed, 5 Feb 2025 10:40:17 +0100 Subject: [PATCH 0154/6055] samples: boards: Add MCO support for nucleo_wba55cg Added overlay and modified sample.yaml to support the nucleo_wba55cg board in the MCO example. Due to GPIO conflict, UART print out is not functional. Signed-off-by: Lubos Koudelka --- .../st/mco/boards/nucleo_wba55cg.overlay | 30 +++++++++++++++++++ samples/boards/st/mco/sample.yaml | 1 + 2 files changed, 31 insertions(+) create mode 100644 samples/boards/st/mco/boards/nucleo_wba55cg.overlay diff --git a/samples/boards/st/mco/boards/nucleo_wba55cg.overlay b/samples/boards/st/mco/boards/nucleo_wba55cg.overlay new file mode 100644 index 0000000000000..ea9fb97f2691c --- /dev/null +++ b/samples/boards/st/mco/boards/nucleo_wba55cg.overlay @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 STMicroelectronics + */ + +/* The clock that is output must be enabled. */ +&clk_lse { + status = "okay"; +}; +/* MCO use same pin like usart1 RX - disable usart */ +/ { + chosen { + zephyr,bt-c2h-uart = &lpuart1; + zephyr,uart-pipe = &lpuart1; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + }; +}; +&usart1 { + status = "disabled"; +}; + +&mco1 { + status = "okay"; + clocks = <&rcc STM32_SRC_LSE MCO1_SEL(MCO_SEL_LSE)>; + prescaler = ; + pinctrl-0 = <&rcc_mco_pa8>; + pinctrl-names = "default"; +}; diff --git a/samples/boards/st/mco/sample.yaml b/samples/boards/st/mco/sample.yaml index 6d052cae771ab..e9f9cddcb0f19 100644 --- a/samples/boards/st/mco/sample.yaml +++ b/samples/boards/st/mco/sample.yaml @@ -7,6 +7,7 @@ tests: - nucleo_f446ze - stm32f746g_disco - nucleo_u5a5zj_q + - nucleo_wba55cg integration_platforms: - stm32f746g_disco tags: board From 3f92a8bbdd63fff851ff4e4d244cfcec3a6b261d Mon Sep 17 00:00:00 2001 From: Dmytro Firsov Date: Wed, 27 Nov 2024 21:16:27 +0200 Subject: [PATCH 0155/6055] drivers: xen: gnttab: use correct struct for grant frames unmapping Previously the driver's 'gnttab_unmap_refs()' signature used incorrect struct - the same one that is used for mapping. Since 'host_addr' membber, that is used to point to required frame is first in both structures it somehow worked. Fix mistake and use 'struct gnttab_unmap_grant_ref' for grant frames unmapping hypercalls. Signed-off-by: Dmytro Firsov --- drivers/xen/gnttab.c | 4 ++-- include/zephyr/xen/gnttab.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/xen/gnttab.c b/drivers/xen/gnttab.c index 8ceb97e2db125..b769b6786d9d4 100644 --- a/drivers/xen/gnttab.c +++ b/drivers/xen/gnttab.c @@ -2,7 +2,7 @@ /* **************************************************************************** * (C) 2006 - Cambridge University - * (C) 2021-2022 - EPAM Systems + * (C) 2021-2024 - EPAM Systems **************************************************************************** * * File: gnttab.c @@ -277,7 +277,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, unsigned int count) return 0; } -int gnttab_unmap_refs(struct gnttab_map_grant_ref *unmap_ops, unsigned int count) +int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, unsigned int count) { return HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count); } diff --git a/include/zephyr/xen/gnttab.h b/include/zephyr/xen/gnttab.h index be6a0d5c906e9..4cfc65e580e92 100644 --- a/include/zephyr/xen/gnttab.h +++ b/include/zephyr/xen/gnttab.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 EPAM Systems + * Copyright (c) 2021-2024 EPAM Systems * * SPDX-License-Identifier: Apache-2.0 */ @@ -76,12 +76,12 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, unsigned int count); * Unmap foreign grant refs. The gnttab_put_page() should be used after this for * each page, that was successfully unmapped. * - * @param unmap_ops - array of prepared gnttab_map_grant_ref's for unmapping + * @param unmap_ops - array of prepared gnttab_unmap_grant_ref's for unmapping * @param count - number of grefs in unmap_ops array * @return - @count on success or negative errno on failure * also per-page status will be set in unmap_ops[i].status (GNTST_*) */ -int gnttab_unmap_refs(struct gnttab_map_grant_ref *unmap_ops, unsigned int count); +int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, unsigned int count); /* * Convert grant ref status codes (GNTST_*) to text messages. From 63ea48cacc1528f4e206b3c42c225e69c1180040 Mon Sep 17 00:00:00 2001 From: Dmytro Firsov Date: Wed, 24 Apr 2024 19:36:29 +0300 Subject: [PATCH 0156/6055] include: xen: add gnttab_query_size struct to public headers Xen public headers were imported into Zephyr source tree and only used structs were added (not copied as is). Mow, for refactoring and improving gnttab driver we need to augment grant table public header with one more struct. It will be used for reading actual number of available Xen grant frames. Signed-off-by: Dmytro Firsov --- include/zephyr/xen/public/grant_table.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/include/zephyr/xen/public/grant_table.h b/include/zephyr/xen/public/grant_table.h index 0124046d042f4..81803a1daa3f6 100644 --- a/include/zephyr/xen/public/grant_table.h +++ b/include/zephyr/xen/public/grant_table.h @@ -324,7 +324,23 @@ struct gnttab_setup_table { typedef struct gnttab_setup_table gnttab_setup_table_t; DEFINE_XEN_GUEST_HANDLE(gnttab_setup_table_t); - +/* + * GNTTABOP_query_size: Query the current and maximum sizes of the shared + * grant table. + * NOTES: + * 1. may be specified as DOMID_SELF. + * 2. Only a sufficiently-privileged domain may specify != DOMID_SELF. + */ +struct gnttab_query_size { + /* IN parameters. */ + domid_t dom; + /* OUT parameters. */ + uint32_t nr_frames; + uint32_t max_nr_frames; + int16_t status; /* => enum grant_status */ +}; +typedef struct gnttab_query_size gnttab_query_size_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_query_size_t); /* * Bitfield values for gnttab_map_grant_ref.flags. From 0e21b25245c80bc6688852b830e4f3585047d5b2 Mon Sep 17 00:00:00 2001 From: Dmytro Firsov Date: Fri, 3 May 2024 18:05:50 +0300 Subject: [PATCH 0157/6055] drivers: xen: gnttab: prevent double-free for grant refs Grant references are allocated via simple O(1) allocator - idx of first free gref is always stored in the "0" list entry (e.g. list[0] == "A"). Next free gref (e.g. B) will be stored inside list entry with the index of previous (list[A] == B) and so on. This allows to find free gref instantly if available. However, current implementation allows a user to perform a double-free of some taken grefs since it doesn't store any information about entries being currently claimed. This may cause gref_list to break. Add GNTTAB_GREF_USED value and mark all taken grefs with it to prevent double free in put_grant_entry(). These changes also required updates for allocator and semaphore init sequences, since we can not use put_free_entry() during driver initialization anymore. Signed-off-by: Dmytro Firsov --- drivers/xen/gnttab.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/xen/gnttab.c b/drivers/xen/gnttab.c index b769b6786d9d4..a74e3be328567 100644 --- a/drivers/xen/gnttab.c +++ b/drivers/xen/gnttab.c @@ -35,6 +35,7 @@ LOG_MODULE_REGISTER(xen_gnttab); /* Timeout for grant table ops retrying */ #define GOP_RETRY_DELAY 200 +#define GNTTAB_GREF_USED (UINT32_MAX - 1) #define GNTTAB_SIZE DT_REG_SIZE_BY_IDX(DT_INST(0, xen_xen), 0) BUILD_ASSERT(!(GNTTAB_SIZE % XEN_PAGE_SIZE), "Size of gnttab have to be aligned on XEN_PAGE_SIZE"); @@ -64,6 +65,7 @@ static grant_ref_t get_free_entry(void) __ASSERT((gref >= GNTTAB_NR_RESERVED_ENTRIES && gref < NR_GRANT_ENTRIES), "Invalid gref = %d", gref); gnttab.gref_list[0] = gnttab.gref_list[gref]; + gnttab.gref_list[gref] = GNTTAB_GREF_USED; irq_unlock(flags); return gref; @@ -74,6 +76,12 @@ static void put_free_entry(grant_ref_t gref) unsigned int flags; flags = irq_lock(); + if (gnttab.gref_list[gref] != GNTTAB_GREF_USED) { + LOG_WRN("Trying to put already free gref = %u", gref); + + return; + } + gnttab.gref_list[gref] = gnttab.gref_list[0]; gnttab.gref_list[0] = gref; @@ -304,14 +312,14 @@ static int gnttab_init(void) int rc = 0, i; /* Will be taken/given during gnt_refs allocation/release */ - k_sem_init(&gnttab.sem, 0, NR_GRANT_ENTRIES - GNTTAB_NR_RESERVED_ENTRIES); - - for ( - gref = GNTTAB_NR_RESERVED_ENTRIES; - gref < NR_GRANT_ENTRIES; - gref++ - ) { - put_free_entry(gref); + k_sem_init(&gnttab.sem, NR_GRANT_ENTRIES - GNTTAB_NR_RESERVED_ENTRIES, + NR_GRANT_ENTRIES - GNTTAB_NR_RESERVED_ENTRIES); + + /* Initialize O(1) allocator, gnttab.gref_list[0] always shows first free entry */ + gnttab.gref_list[0] = GNTTAB_NR_RESERVED_ENTRIES; + gnttab.gref_list[NR_GRANT_ENTRIES - 1] = 0; + for (gref = GNTTAB_NR_RESERVED_ENTRIES; gref < NR_GRANT_ENTRIES - 1; gref++) { + gnttab.gref_list[gref] = gref + 1; } for (i = 0; i < NR_GRANT_FRAMES; i++) { From cd31a413284dfa68dd85a694c1e5f6fc245bd5f8 Mon Sep 17 00:00:00 2001 From: Dmytro Firsov Date: Tue, 14 May 2024 20:53:41 +0300 Subject: [PATCH 0158/6055] drivers: xen: gnttab: limit number of grant frames via config Xen allocates a region that should be used as a place for grant table mapping and passes it via the device tree. By design, this region may be quite large (up to 4096+ frames/pages), but the number of frames is usually limited by the max_grant_frames domain parameter (usually 32 or 64). Linux maps these frames on demand and when reaches mentioned limit it just stops expanding. At the same time, previous implementation of Zephyr gnttab driver calculated the number of grant frames by dividing whole region by page size and tried to map it during init. If the region specified in the device tree was larger than the max_grant_frames set by Xen, it would fail on ASSERT, since Xen would return an error. To address these issues CONFIG_NR_GRANT_FRAMES was introduced. It allows to limit size of grant table and map only required number of pages. Additionally, a check for max_grant_frames Xen limit was introduced to initialization - if this value will be less than CONFIG_NR_GRANT_FRAMES, k_panic() will be called. Signed-off-by: Dmytro Firsov --- drivers/xen/Kconfig | 11 ++++++++- drivers/xen/gnttab.c | 57 +++++++++++++++++++++++++++++++++----------- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 361c71a3538d0..99ad113887b12 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (c) 2022-2023 EPAM Systems +# Copyright (c) 2022-2024 EPAM Systems if XEN @@ -20,6 +20,15 @@ config XEN_GRANT_TABLE_INIT_PRIORITY depends on XEN_GRANT_TABLE default 50 +config NR_GRANT_FRAMES + int "Number of grant frames mapped to Zephyr" + depends on XEN_GRANT_TABLE + default 1 + help + This value configures how much grant frames will be supported by Zephyr + grant table driver in runtime. This value should be <= max_grant_frames + configured for domain in Xen hypervisor. + endmenu endif # XEN diff --git a/drivers/xen/gnttab.c b/drivers/xen/gnttab.c index a74e3be328567..bea767fec2ef6 100644 --- a/drivers/xen/gnttab.c +++ b/drivers/xen/gnttab.c @@ -36,16 +36,12 @@ LOG_MODULE_REGISTER(xen_gnttab); #define GOP_RETRY_DELAY 200 #define GNTTAB_GREF_USED (UINT32_MAX - 1) -#define GNTTAB_SIZE DT_REG_SIZE_BY_IDX(DT_INST(0, xen_xen), 0) -BUILD_ASSERT(!(GNTTAB_SIZE % XEN_PAGE_SIZE), "Size of gnttab have to be aligned on XEN_PAGE_SIZE"); - -/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */ -#define NR_GRANT_FRAMES (GNTTAB_SIZE / XEN_PAGE_SIZE) -#define NR_GRANT_ENTRIES \ - (NR_GRANT_FRAMES * XEN_PAGE_SIZE / sizeof(grant_entry_v1_t)) +#define GNTTAB_SIZE (CONFIG_NR_GRANT_FRAMES * XEN_PAGE_SIZE) +#define NR_GRANT_ENTRIES (GNTTAB_SIZE / sizeof(grant_entry_v1_t)) +BUILD_ASSERT(GNTTAB_SIZE <= DT_REG_SIZE_BY_IDX(DT_INST(0, xen_xen), 0), + "Number of grant frames is bigger than grant table DT region!"); BUILD_ASSERT(GNTTAB_SIZE <= CONFIG_KERNEL_VM_SIZE); -DEVICE_MMIO_TOPLEVEL_STATIC(grant_tables, DT_INST(0, xen_xen)); static struct gnttab { struct k_sem sem; @@ -303,13 +299,39 @@ const char *gnttabop_error(int16_t status) } } +/* Picked from Linux implementation */ +#define LEGACY_MAX_GNT_FRAMES_SUPPORTED 4 +static unsigned long gnttab_get_max_frames(void) +{ + int ret; + struct gnttab_query_size q = { + .dom = DOMID_SELF, + }; + + ret = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &q, 1); + if ((ret < 0) || (q.status != GNTST_okay)) { + return LEGACY_MAX_GNT_FRAMES_SUPPORTED; + } + + return q.max_nr_frames; +} + static int gnttab_init(void) { grant_ref_t gref; struct xen_add_to_physmap xatp; struct gnttab_setup_table setup; - xen_pfn_t frames[NR_GRANT_FRAMES]; + xen_pfn_t frames[CONFIG_NR_GRANT_FRAMES]; int rc = 0, i; + unsigned long xen_max_grant_frames; + uintptr_t gnttab_base = DT_REG_ADDR_BY_IDX(DT_INST(0, xen_xen), 0); + mm_reg_t gnttab_reg; + + xen_max_grant_frames = gnttab_get_max_frames(); + if (xen_max_grant_frames < CONFIG_NR_GRANT_FRAMES) { + LOG_ERR("Xen max_grant_frames is less than CONFIG_NR_GRANT_FRAMES!"); + k_panic(); + } /* Will be taken/given during gnt_refs allocation/release */ k_sem_init(&gnttab.sem, NR_GRANT_ENTRIES - GNTTAB_NR_RESERVED_ENTRIES, @@ -322,25 +344,32 @@ static int gnttab_init(void) gnttab.gref_list[gref] = gref + 1; } - for (i = 0; i < NR_GRANT_FRAMES; i++) { + for (i = 0; i < CONFIG_NR_GRANT_FRAMES; i++) { xatp.domid = DOMID_SELF; xatp.size = 0; xatp.space = XENMAPSPACE_grant_table; xatp.idx = i; - xatp.gpfn = xen_virt_to_gfn(Z_TOPLEVEL_ROM_NAME(grant_tables).phys_addr) + i; + xatp.gpfn = xen_virt_to_gfn(gnttab_base) + i; rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); __ASSERT(!rc, "add_to_physmap failed; status = %d\n", rc); } setup.dom = DOMID_SELF; - setup.nr_frames = NR_GRANT_FRAMES; + setup.nr_frames = CONFIG_NR_GRANT_FRAMES; set_xen_guest_handle(setup.frame_list, frames); rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); __ASSERT((!rc) && (!setup.status), "Table setup failed; status = %s\n", gnttabop_error(setup.status)); - DEVICE_MMIO_TOPLEVEL_MAP(grant_tables, K_MEM_CACHE_WB | K_MEM_PERM_RW); - gnttab.table = (grant_entry_v1_t *)DEVICE_MMIO_TOPLEVEL_GET(grant_tables); + /* + * Xen DT region reserved for grant table (first reg in hypervisor node) + * may be much bigger than CONFIG_NR_GRANT_FRAMES multiplied by page size. + * Thus, we need to map only part of region, that is limited by config. + * The size of this part is calculated in GNTTAB_SIZE macro and used as + * parameter for device_map() + */ + device_map(&gnttab_reg, gnttab_base, GNTTAB_SIZE, K_MEM_CACHE_WB | K_MEM_PERM_RW); + gnttab.table = (grant_entry_v1_t *)gnttab_reg; LOG_DBG("%s: grant table mapped\n", __func__); From 71b9ec2c2cc770d191a5958ef91a189e5815e2fc Mon Sep 17 00:00:00 2001 From: Dmytro Firsov Date: Wed, 27 Nov 2024 20:11:38 +0200 Subject: [PATCH 0159/6055] drivers: xen: gnttab: remove redundant GNTTABOP_setup_table call Initially this driver was a port from mini-os. Michal Orzel (@orzelmichal) pointed that it contains incorrect grant table initialization sequence and redundant calls. Driver mapped grant table frames via loop of XENMEM_add_to_physmap calls and then tried to do the same but via GNTTABOP_setup_table operation. After completion of latter it did not even use provided frames list. This did not cause any major issues, since XENMEM_add_to_physmap correctly map gnttab frames that were used. Remove redundant GNTTABOP_setup_table call from grant table driver to clean up its initialization sequence. Signed-off-by: Dmytro Firsov --- drivers/xen/gnttab.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/xen/gnttab.c b/drivers/xen/gnttab.c index bea767fec2ef6..ee1e81bda6cee 100644 --- a/drivers/xen/gnttab.c +++ b/drivers/xen/gnttab.c @@ -320,8 +320,6 @@ static int gnttab_init(void) { grant_ref_t gref; struct xen_add_to_physmap xatp; - struct gnttab_setup_table setup; - xen_pfn_t frames[CONFIG_NR_GRANT_FRAMES]; int rc = 0, i; unsigned long xen_max_grant_frames; uintptr_t gnttab_base = DT_REG_ADDR_BY_IDX(DT_INST(0, xen_xen), 0); @@ -354,13 +352,6 @@ static int gnttab_init(void) __ASSERT(!rc, "add_to_physmap failed; status = %d\n", rc); } - setup.dom = DOMID_SELF; - setup.nr_frames = CONFIG_NR_GRANT_FRAMES; - set_xen_guest_handle(setup.frame_list, frames); - rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); - __ASSERT((!rc) && (!setup.status), "Table setup failed; status = %s\n", - gnttabop_error(setup.status)); - /* * Xen DT region reserved for grant table (first reg in hypervisor node) * may be much bigger than CONFIG_NR_GRANT_FRAMES multiplied by page size. From e549bc702ab7826e8b41b48f8dc9588e389f3e8d Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 10 Jun 2024 13:08:10 +0300 Subject: [PATCH 0160/6055] drivers: xen: gnttab: process gnttabs in reverse order The Xen extends domain grant tables every time domain requests gnttab basing on gnttab idx. If idx > xen_current_max_gnttab_idx the Xen extends grant table so that idx <= xen_current_max_gnttab_idx. The growing grant tables on every hypercall is a bit costly operation and it also results in the bunch of log messages: (XEN) xen-source/xen/common/grant_table.c:1909:d0v0 Expanding d0 \ grant table from 1 to 2 frames This patch changes gnttab processing from gnttab max_idx to low_idx, so the first hypercall has the largest index, ensuring that the grant table will grow only once. It also reduces number of log messages. Signed-off-by: Grygorii Strashko Signed-off-by: Dmytro Firsov --- drivers/xen/gnttab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/gnttab.c b/drivers/xen/gnttab.c index ee1e81bda6cee..ccf1b888e17a6 100644 --- a/drivers/xen/gnttab.c +++ b/drivers/xen/gnttab.c @@ -342,7 +342,7 @@ static int gnttab_init(void) gnttab.gref_list[gref] = gref + 1; } - for (i = 0; i < CONFIG_NR_GRANT_FRAMES; i++) { + for (i = CONFIG_NR_GRANT_FRAMES - 1; i >= 0; i--) { xatp.domid = DOMID_SELF; xatp.size = 0; xatp.space = XENMAPSPACE_grant_table; From baa41f43aff0cb42b9000313e9954596e0e994f7 Mon Sep 17 00:00:00 2001 From: Titouan Christophe Date: Sun, 22 Dec 2024 23:53:07 +0100 Subject: [PATCH 0161/6055] boards: stm32h7s78-dk: add support for OTGFS (USB port 2) Add OTGFS peripheral to the stm32h7rs soc series, and enable it on the Discovery board STM32H7S78-DK, where it is wired to USB Type-C port 2. Signed-off-by: Titouan Christophe --- boards/st/stm32h7s78_dk/doc/index.rst | 8 ++++++++ boards/st/stm32h7s78_dk/stm32h7s78_dk.dts | 8 ++++++++ boards/st/stm32h7s78_dk/stm32h7s78_dk.yaml | 2 ++ dts/arm/st/h7rs/stm32h7rs.dtsi | 19 +++++++++++++++++++ .../dt-bindings/clock/stm32h7rs_clock.h | 1 + 5 files changed, 38 insertions(+) diff --git a/boards/st/stm32h7s78_dk/doc/index.rst b/boards/st/stm32h7s78_dk/doc/index.rst index 430b3d9dd0edc..a6f8455dc6d00 100644 --- a/boards/st/stm32h7s78_dk/doc/index.rst +++ b/boards/st/stm32h7s78_dk/doc/index.rst @@ -172,6 +172,8 @@ hardware features: +-----------+------------+-------------------------------------+ | SPI | on-chip | spi bus | +-----------+------------+-------------------------------------+ +| USB | on-chip | usb | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. @@ -215,6 +217,7 @@ Default Zephyr Peripheral Mapping: - LD3 (red) : PM2 - LD4 (blue) : PM3 - ADC1 channel 6 input : PF12 +- USB OTG FS DM/DP : PM12/PM11 System Clock ------------ @@ -229,6 +232,11 @@ Serial Port STM32H7S78-DK Discovery board has 2 U(S)ARTs. The Zephyr console output is assigned to USART4. Default settings are 115200 8N1. +USB +--- + +STM32H7S78-DK Discovery board has 2 USB Type-C connectors. Currently, only +USB port2 (FS) is supported. Programming and Debugging ************************* diff --git a/boards/st/stm32h7s78_dk/stm32h7s78_dk.dts b/boards/st/stm32h7s78_dk/stm32h7s78_dk.dts index e4192d41641a1..5cfbbb449b85a 100644 --- a/boards/st/stm32h7s78_dk/stm32h7s78_dk.dts +++ b/boards/st/stm32h7s78_dk/stm32h7s78_dk.dts @@ -184,3 +184,11 @@ &vbat { status = "okay"; }; + +usb2: &usbotg_fs { + pinctrl-0 = <&usb_otg_fs_dm_pm12 &usb_otg_fs_dp_pm11>; + pinctrl-names = "default"; + status = "okay"; +}; + +zephyr_udc0: &usb2 {}; diff --git a/boards/st/stm32h7s78_dk/stm32h7s78_dk.yaml b/boards/st/stm32h7s78_dk/stm32h7s78_dk.yaml index e48895cbce1bb..7e14a410259ff 100644 --- a/boards/st/stm32h7s78_dk/stm32h7s78_dk.yaml +++ b/boards/st/stm32h7s78_dk/stm32h7s78_dk.yaml @@ -13,4 +13,6 @@ supported: - watchdog - entropy - adc + - usb_device + - usbd vendor: st diff --git a/dts/arm/st/h7rs/stm32h7rs.dtsi b/dts/arm/st/h7rs/stm32h7rs.dtsi index 25ba574d5b1f6..e41e465c7ebfa 100644 --- a/dts/arm/st/h7rs/stm32h7rs.dtsi +++ b/dts/arm/st/h7rs/stm32h7rs.dtsi @@ -776,6 +776,25 @@ interrupts = <37 0>; status = "disabled"; }; + + usbotg_fs: usb@40080000 { + compatible = "st,stm32-otgfs"; + reg = <0x40080000 0x40000>; + interrupts = <112 0>; + interrupt-names = "otgfs"; + num-bidir-endpoints = <6>; + ram-size = <1280>; + maximum-speed = "full-speed"; + phys = <&otgfs_phy>; + clocks = <&rcc STM32_CLOCK(AHB1, 27U)>, + <&rcc STM32_SRC_HSI48 OTGFS_SEL(0)>; + status = "disabled"; + }; + }; + + otgfs_phy: otgfs_phy { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; }; die_temp: dietemp { diff --git a/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h b/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h index e2c1ed81289e5..44698cbeca4b1 100644 --- a/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h @@ -103,6 +103,7 @@ #define SDMMC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 2, D1CCIPR_REG) #define XSPI1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, D1CCIPR_REG) #define XSPI2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, D1CCIPR_REG) +#define OTGFS_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, D1CCIPR_REG) #define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 24, D1CCIPR_REG) #define CKPER_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 28, D1CCIPR_REG) From d6fdbb8953d5c66f1adbee5d9e85a5d2a3e410df Mon Sep 17 00:00:00 2001 From: Kacper Brzostowski Date: Sat, 18 Jan 2025 19:26:40 +0100 Subject: [PATCH 0162/6055] dts: st: h5: addSTM32H562xG SoC support Added STM32H562xG dts file Signed-off-by: Kacper Brzostowski --- dts/arm/st/h5/stm32h562Xg.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 dts/arm/st/h5/stm32h562Xg.dtsi diff --git a/dts/arm/st/h5/stm32h562Xg.dtsi b/dts/arm/st/h5/stm32h562Xg.dtsi new file mode 100644 index 0000000000000..969c61d5d9c7f --- /dev/null +++ b/dts/arm/st/h5/stm32h562Xg.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Kacper Brzostowski + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +/ { + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_M(1)>; + }; + }; + }; +}; From eb4c8fc319a9405ae41e97b8e984ffdd9b021591 Mon Sep 17 00:00:00 2001 From: Kacper Brzostowski Date: Sat, 18 Jan 2025 19:27:42 +0100 Subject: [PATCH 0163/6055] boards: weact: Add support for WeAct STM32H5 Core Board Low cost STM32H5 series development board with bare minimum to run the MCU Signed-off-by: Kacper Brzostowski --- .../stm32h5_core/Kconfig.weact_stm32h5_core | 5 + boards/weact/stm32h5_core/board.cmake | 7 + boards/weact/stm32h5_core/board.yml | 6 + boards/weact/stm32h5_core/doc/index.rst | 230 ++++++++++++++++++ .../weact/stm32h5_core/weact_stm32h5_core.dts | 172 +++++++++++++ .../stm32h5_core/weact_stm32h5_core.yaml | 20 ++ .../stm32h5_core/weact_stm32h5_core_defconfig | 18 ++ 7 files changed, 458 insertions(+) create mode 100644 boards/weact/stm32h5_core/Kconfig.weact_stm32h5_core create mode 100644 boards/weact/stm32h5_core/board.cmake create mode 100644 boards/weact/stm32h5_core/board.yml create mode 100644 boards/weact/stm32h5_core/doc/index.rst create mode 100644 boards/weact/stm32h5_core/weact_stm32h5_core.dts create mode 100644 boards/weact/stm32h5_core/weact_stm32h5_core.yaml create mode 100644 boards/weact/stm32h5_core/weact_stm32h5_core_defconfig diff --git a/boards/weact/stm32h5_core/Kconfig.weact_stm32h5_core b/boards/weact/stm32h5_core/Kconfig.weact_stm32h5_core new file mode 100644 index 0000000000000..999012b1955ed --- /dev/null +++ b/boards/weact/stm32h5_core/Kconfig.weact_stm32h5_core @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Kacper Brzostowski +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_WEACT_STM32H5_CORE + select SOC_STM32H562XX diff --git a/boards/weact/stm32h5_core/board.cmake b/boards/weact/stm32h5_core/board.cmake new file mode 100644 index 0000000000000..2288b4765efc8 --- /dev/null +++ b/boards/weact/stm32h5_core/board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2025 Kacper Brzostowski +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") + +# Keep first +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) diff --git a/boards/weact/stm32h5_core/board.yml b/boards/weact/stm32h5_core/board.yml new file mode 100644 index 0000000000000..ad89ef703655f --- /dev/null +++ b/boards/weact/stm32h5_core/board.yml @@ -0,0 +1,6 @@ +board: + name: weact_stm32h5_core + full_name: STM32H5 Core Board + vendor: weact + socs: + - name: stm32h562xx diff --git a/boards/weact/stm32h5_core/doc/index.rst b/boards/weact/stm32h5_core/doc/index.rst new file mode 100644 index 0000000000000..a128d4b358b6d --- /dev/null +++ b/boards/weact/stm32h5_core/doc/index.rst @@ -0,0 +1,230 @@ +.. zephyr:board:: weact_stm32h5_core + +Overview +******** + +The ``weact_stm32h5_core`` board is a compact development board equipped with +an STM32H562RGT6 microcontroller. It features basic set of peripherals: +user LED and button, microSD |trade| card slot, and combined SWD & UART header. + +Key Features + +- STM32 microcontroller in LQFP64 package +- USB OTG or full-speed device +- 1 user LED +- User, boot, and reset push-buttons +- 32.768 kHz and 8MHz HSE crystal oscillators +- Board connectors: + + - microSD |trade| card + - USB Type-C Connector + - SWD & UART header for external debugger + - 2x 30-pin GPIO connector + +More information about the board can be found on the `WeAct GitHub`_. + +Hardware +******** + +The ``weact_stm32h5_core`` board provides the following hardware components: + + - STM32H562RGT6 in LQFP64 package + - ARM 32-bit Cortex-M33 CPU with FPU + - CORDIC for trigonometric functions acceleration + - FMAC (filter mathematical accelerator) + - CRC calculation unit + - 240 MHz max CPU frequency + - VDD from 1.71 V to 3.6 V + - 1MB Flash, 2 banks read-while-write + - 640kB SRAM + - 4 Kbytes of backup SRAM available in the lowest power modes + - 2x watchdogs + - 2x SysTick timer + - 32-bit timers (2) + - 16-bit advanced motor control timers (2) + - 16-bit low power timers (6) + - 16-bit timers (10) + - 1x USB Type-C / USB power-delivery controller + - 1x USB 2.0 full-speed host and device + - 4x I2C FM+ interfaces (SMBus/PMBus) + - 1x I3C interface + - 12x U(S)ARTS (ISO7816 interface, LIN, IrDA, modem control) + - 1x LP UART + - 6x SPIs including 3 muxed with full-duplex I2S + - 2x SAI + - 1x FDCAN + - Flexible external memory controller with up to 16-bit data bus: SRAM, PSRAM, FRAM, SDRAM/LPSDR SDRAM, NOR/NAND memories + - 1x OCTOSPI memory interface with on-the-fly decryption and support for serial PSRAM/NAND/NOR, Hyper RAM/Flash frame formats + - 1x SD/SDIO/MMC interfaces + - 1x HDMI-CEC + - 2x 12-bit ADC with up to 5 MSPS in 12-bit + - 1x 12-bit D/A with 2 channels + - 1x Digital temperature sensor + +More information about STM32H562RG can be found here: + +- `STM32H562RG on www.st.com`_ +- `STM32H562 reference manual`_ + +Supported Features +================== + +The Zephyr ``weact_stm32h5_core`` board supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| CAN/CANFD | on-chip | CAN | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | reset and clock control | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-----------+------------+-------------------------------------+ +| RTC | on-chip | Real Time Clock | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi bus | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c bus | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ +| USB | on-chip | USB full-speed host/device bus | ++-----------+------------+-------------------------------------+ +| SDMMC | on-chip | disk access | ++-----------+------------+-------------------------------------+ + +Other hardware features have not been enabled yet for this board. + +The default configuration per core can be found in the defconfig file: +:zephyr_file:`boards/weact/stm32h5_core/weact_stm32h5_core_defconfig` + +Pin Mapping +=========== + +Default Zephyr Peripheral Mapping: +---------------------------------- + +The ``weact_stm32h5_core`` board is configured as follows + +- USER_LED : PB2 +- USER_PB : PC13 +- SDMMC1 CLK/DCMD/CD/D0/D1/D2/D3 : PC12/PD2/PD4/PC8/PC9/PC10/PC11 (microSD card) +- USB DM/DP : PA11/PA12 (USB CDC ACM) +- UART on debug header : RX/TX - pA10/PA9 + +System Clock +============ + +The STM32H562RG System Clock can be driven by an internal or external oscillator, +as well as by the main PLL clock. By default, the System clock is driven +by the PLL clock at 240MHz. PLL clock is fed by a 8MHz external clock. + +Serial Port (USB CDC ACM) +========================= + +The Zephyr console output is assigned to the USB CDC ACM virtual serial port. +Virtual COM port interface. Default communication settings are 115200 8N1. + +Programming and Debugging +************************* + +The ``weact_stm32h5_core`` board facilitates firmware flashing via the USB DFU +bootloader. This method simplifies the process of updating images, although +it doesn't provide debugging capabilities. However, the board provides header +pins for the Serial Wire Debug (SWD) interface, which can be used to connect +an external debugger, such as ST-Link. + +Flashing +======== + +To activate the bootloader, follow these steps: + +1. Press and hold the BOOT0 key. +2. While still holding the BOOT0 key, press and release the RESET key. +3. Wait for 0.5 seconds, then release the BOOT0 key. + +Upon successful execution of these steps, the device will transition into +bootloader mode and present itself as a USB DFU Mode device. You can program +the device using the west tool or the STM32CubeProgrammer. + +Flashing an application to ``weact_stm32h5_core`` +------------------------------------------------- + +Here is an example for the :zephyr:code-sample:`hello_world` application. + +First, put the board in bootloader mode as described above. Then build and flash +the application in the usual way. Just add ``CONFIG_BOOT_DELAY=5000`` to the +configuration, so that USB CDC ACM is initialized before any text is printed, +as below: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: weact_stm32h5_core + :goals: build flash + :gen-args: -DCONFIG_BOOT_DELAY=5000 + +Run a serial host program to connect with your board: + +.. code-block:: console + + $ minicom -D -b 115200 + +Then, press the RESET button, you should see the following message after few seconds: + +.. code-block:: console + + Hello World! weact_stm32h5_core + +Replace :code:`` with the port where the board can be found. +For example, under Linux, :code:`/dev/ttyACM0`. + +Debugging +--------- + +This current Zephyr port does not support debugging. + +Testing the LEDs in the ``weact_stm32h5_core`` +********************************************** + +There is a sample that allows to test that LED on the board are working +properly with Zephyr: + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: weact_stm32h5_core + :goals: build flash + :gen-args: -DCONFIG_BOOT_DELAY=5000 + +You can build and flash the examples to make sure Zephyr is running correctly on +your board. The LED definitions can be found in +:zephyr_file:`boards/weact/stm32h5_core/weact_stm32h5_core.dts`. + +Testing shell over USB in the ``weact_stm32h5_core`` +**************************************************** + +There is a sample that allows to test shell interface over USB CDC ACM interface +with Zephyr: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/shell/shell_module + :board: weact_stm32h5_core + :goals: build flash + :gen-args: -DCONFIG_BOOT_DELAY=5000 + +.. _WeAct GitHub: + https://github.com/WeActStudio/WeActStudio.STM32H5_64Pin_CoreBoard + +.. _STM32H562RG on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32h562rg.html + +.. _STM32H562 reference manual: + https://www.st.com/resource/en/reference_manual/rm0481-stm32h52333xx-stm32h56263xx-and-stm32h573xx-armbased-32bit-mcus-stmicroelectronics.pdf diff --git a/boards/weact/stm32h5_core/weact_stm32h5_core.dts b/boards/weact/stm32h5_core/weact_stm32h5_core.dts new file mode 100644 index 0000000000000..1d39eea4c2018 --- /dev/null +++ b/boards/weact/stm32h5_core/weact_stm32h5_core.dts @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2025 Kacper Brzostowski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "WeAct Studio STM32H5 Core Board"; + compatible = "weact,stm32h5-core"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,code-partition = &slot0_partition; + zephyr,sram = &sram1; + zephyr,flash = &flash0; + }; + + aliases { + led0 = &led_0; + sw0 = &button_0; + watchdog0 = &iwdg; + }; + + leds { + compatible = "gpio-leds"; + + led_0: led0 { + gpios = <&gpiob 2 GPIO_ACTIVE_HIGH>; + label = "User LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + button_0: button0 { + label = "User Button"; + gpios = <&gpioc 13 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + zephyr,code = ; + }; + }; +}; + +&sdmmc1 { + pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9 + &sdmmc1_d2_pc10 &sdmmc1_d3_pc11 + &sdmmc1_ck_pc12 &sdmmc1_cmd_pd2>; + cd-gpios = <&gpioa 8 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + cd-gpios = <&gpioa 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + status = "okay"; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hsi { + status = "okay"; +}; + +&clk_hse { + status = "okay"; + clock-frequency = ; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <2>; + apb2-prescaler = <1>; + apb3-prescaler = <2>; +}; + +&pll { + div-m = <2>; + mul-n = <120>; + div-p = <2>; + div-q = <3>; + div-r = <2>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00200000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + status = "okay"; +}; + +stm32_lp_tick_source: &lptim4 { + clocks = <&rcc STM32_CLOCK_BUS_APB3 0x2000>, + <&rcc STM32_SRC_LSI LPTIM4_SEL(4)>; + status = "okay"; +}; + +&iwdg { + status = "okay"; +}; + +&usart1 { + status = "okay"; + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; +}; + +&rng { + status = "okay"; +}; + +&spi1 { + pinctrl-0 = <&spi1_nss_pa4 &spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; + pinctrl-names = "default"; + cs-gpios = <&gpioa 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; +}; + +&fdcan1 { + pinctrl-0 = <&fdcan1_rx_pb8 &fdcan1_tx_pb7>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000200>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; + clk-divider = <2>; + status = "okay"; +}; + +zephyr_udc0: &usb { + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(448)>; + }; + + slot1_partition: partition@80000 { + label = "image-1"; + reg = <0x00080000 DT_SIZE_K(448)>; + }; + + storage_partition: partition@f0000 { + label = "storage"; + reg = <0x000f0000 DT_SIZE_K(64)>; + }; + }; +}; diff --git a/boards/weact/stm32h5_core/weact_stm32h5_core.yaml b/boards/weact/stm32h5_core/weact_stm32h5_core.yaml new file mode 100644 index 0000000000000..942b2f55025bb --- /dev/null +++ b/boards/weact/stm32h5_core/weact_stm32h5_core.yaml @@ -0,0 +1,20 @@ +identifier: weact_stm32h5_core +name: WeAct Studio STM32H5 Core Board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 640 +flash: 1024 +supported: + - gpio + - can + - uart + - entropy + - spi + - usb_device + - rtc + - watchdog +vendor: weact diff --git a/boards/weact/stm32h5_core/weact_stm32h5_core_defconfig b/boards/weact/stm32h5_core/weact_stm32h5_core_defconfig new file mode 100644 index 0000000000000..4b8a61df364a4 --- /dev/null +++ b/boards/weact/stm32h5_core/weact_stm32h5_core_defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2025 Kacper Brzostowski +# SPDX-License-Identifier: Apache-2.0 + +# Enable uart driver +CONFIG_SERIAL=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable GPIO +CONFIG_GPIO=y From c0139fad06ea251b48487c2dae183cb7a5c41b85 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Thu, 28 Nov 2024 15:34:39 +0000 Subject: [PATCH 0164/6055] drivers: gpio: mmio32: update gpio_mmio32 to behave like other divers The current implementation requires SoCs/Boards to manualy instantiate the preripherals and initilize them. The change lets Zephyr rely on the device tree setup to instantiate & initialize the relevant gpio peripheral. Signed-off-by: Wilfried Chauveau --- boards/arm/mps2/mps2_an521-common.dtsi | 7 +- boards/arm/mps2/mps2_an521_cpu0.yaml | 1 - boards/arm/mps2/mps2_base.dtsi | 7 +- .../arm/mps3/mps3_common_soc_peripheral.dtsi | 7 +- boards/arm/mps3/mps3_corstone300_fvp.yaml | 1 - drivers/gpio/gpio_mmio32.c | 71 +++++++++++++---- ...-fpgaio-gpio.yaml => arm,mmio32-gpio.yaml} | 8 +- dts/bindings/gpio/arm,mps3-fpgaio-gpio.yaml | 18 ----- include/zephyr/drivers/gpio/gpio_mmio32.h | 79 ------------------- soc/arm/mps2/soc.c | 32 ++------ soc/arm/mps3/CMakeLists.txt | 4 - soc/arm/mps3/soc.c | 24 ------ .../boards/arm/mps2/mps2_an521-common.dtsi | 7 +- .../gpio/gpio_get_direction/testcase.yaml | 1 - 14 files changed, 83 insertions(+), 184 deletions(-) rename dts/bindings/gpio/{arm,mps2-fpgaio-gpio.yaml => arm,mmio32-gpio.yaml} (52%) delete mode 100644 dts/bindings/gpio/arm,mps3-fpgaio-gpio.yaml delete mode 100644 include/zephyr/drivers/gpio/gpio_mmio32.h delete mode 100644 soc/arm/mps3/soc.c diff --git a/boards/arm/mps2/mps2_an521-common.dtsi b/boards/arm/mps2/mps2_an521-common.dtsi index 5b1959ff5fe38..acd2be8da72e6 100644 --- a/boards/arm/mps2/mps2_an521-common.dtsi +++ b/boards/arm/mps2/mps2_an521-common.dtsi @@ -156,7 +156,7 @@ i2c_shield1: i2c@20d000 { }; gpio_led0: mps2_fpgaio@302000 { - compatible = "arm,mps2-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x302000 0x4>; gpio-controller; @@ -165,16 +165,17 @@ gpio_led0: mps2_fpgaio@302000 { }; gpio_button: mps2_fpgaio@302008 { - compatible = "arm,mps2-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x302008 0x4>; gpio-controller; #gpio-cells = <1>; ngpios = <2>; + direction-input; }; gpio_misc: mps2_fpgaio@30204c { - compatible = "arm,mps2-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x30204c 0x4>; gpio-controller; diff --git a/boards/arm/mps2/mps2_an521_cpu0.yaml b/boards/arm/mps2/mps2_an521_cpu0.yaml index 2e73e6b113abc..e511285c190f4 100644 --- a/boards/arm/mps2/mps2_an521_cpu0.yaml +++ b/boards/arm/mps2/mps2_an521_cpu0.yaml @@ -15,7 +15,6 @@ supported: testing: default: true ignore_tags: - - drivers - bluetooth - net - timer diff --git a/boards/arm/mps2/mps2_base.dtsi b/boards/arm/mps2/mps2_base.dtsi index 4d8106aa9126b..0733b6e342d86 100644 --- a/boards/arm/mps2/mps2_base.dtsi +++ b/boards/arm/mps2/mps2_base.dtsi @@ -236,7 +236,7 @@ }; gpio_led0: mps2_fpgaio@40028000 { - compatible = "arm,mps2-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x40028000 0x4>; gpio-controller; #gpio-cells = <1>; @@ -244,15 +244,16 @@ }; gpio_button: mps2_fpgaio@40028008 { - compatible = "arm,mps2-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x40028008 0x4>; gpio-controller; #gpio-cells = <1>; ngpios = <2>; + direction-input; }; gpio_misc: mps2_fpgaio@4002804c { - compatible = "arm,mps2-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x4002804c 0x4>; gpio-controller; #gpio-cells = <1>; diff --git a/boards/arm/mps3/mps3_common_soc_peripheral.dtsi b/boards/arm/mps3/mps3_common_soc_peripheral.dtsi index 6fd5c7acd4024..4fc90627eec4f 100644 --- a/boards/arm/mps3/mps3_common_soc_peripheral.dtsi +++ b/boards/arm/mps3/mps3_common_soc_peripheral.dtsi @@ -122,7 +122,7 @@ i2c_ddr4_eeprom: i2c@9208000 { }; gpio_led0: mps3_fpgaio@9302000 { - compatible = "arm,mps3-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x9302000 0x4>; gpio-controller; @@ -131,16 +131,17 @@ gpio_led0: mps3_fpgaio@9302000 { }; gpio_button: mps3_fpgaio@9302008 { - compatible = "arm,mps3-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x9302008 0x4>; gpio-controller; #gpio-cells = <1>; ngpios = <2>; + direction-input; }; gpio_misc: mps3_fpgaio@930204c { - compatible = "arm,mps3-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x930204c 0x4>; gpio-controller; diff --git a/boards/arm/mps3/mps3_corstone300_fvp.yaml b/boards/arm/mps3/mps3_corstone300_fvp.yaml index 07c8c8a131e11..0629af2dea980 100644 --- a/boards/arm/mps3/mps3_corstone300_fvp.yaml +++ b/boards/arm/mps3/mps3_corstone300_fvp.yaml @@ -17,7 +17,6 @@ supported: - gpio testing: ignore_tags: - - drivers - bluetooth - net - timer diff --git a/drivers/gpio/gpio_mmio32.c b/drivers/gpio/gpio_mmio32.c index 5244f45f29e27..7c0c8e0c9ab57 100644 --- a/drivers/gpio/gpio_mmio32.c +++ b/drivers/gpio/gpio_mmio32.c @@ -26,12 +26,30 @@ * gpio_port_write. */ -#include +#define DT_DRV_COMPAT arm_mmio32_gpio + #include #include -static int gpio_mmio32_config(const struct device *dev, - gpio_pin_t pin, gpio_flags_t flags) +#include + +struct gpio_mmio32_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + volatile uint32_t *reg; + uint32_t mask; + bool is_input; +}; + +struct gpio_mmio32_context { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + const struct gpio_mmio32_config *config; +}; + +int gpio_mmio32_init(const struct device *dev); + +static int gpio_mmio32_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { struct gpio_mmio32_context *context = dev->data; const struct gpio_mmio32_config *config = context->config; @@ -40,13 +58,19 @@ static int gpio_mmio32_config(const struct device *dev, return -EINVAL; /* Pin not in our validity mask */ } - if (flags & ~(GPIO_INPUT | GPIO_OUTPUT | - GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH | + if (flags & ~(GPIO_INPUT | GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH | GPIO_ACTIVE_LOW)) { /* We ignore direction and fake polarity, rest is unsupported */ return -ENOTSUP; } + if (config->is_input && ((flags & GPIO_OUTPUT) != 0)) { + return -ENOTSUP; + } + if (!config->is_input && ((flags & GPIO_INPUT) != 0)) { + return -ENOTSUP; + } + if ((flags & GPIO_OUTPUT) != 0) { unsigned int key; volatile uint32_t *reg = config->reg; @@ -73,9 +97,7 @@ static int gpio_mmio32_port_get_raw(const struct device *dev, uint32_t *value) return 0; } -static int gpio_mmio32_port_set_masked_raw(const struct device *dev, - uint32_t mask, - uint32_t value) +static int gpio_mmio32_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) { struct gpio_mmio32_context *context = dev->data; const struct gpio_mmio32_config *config = context->config; @@ -93,8 +115,7 @@ static int gpio_mmio32_port_set_masked_raw(const struct device *dev, return 0; } -static int gpio_mmio32_port_set_bits_raw(const struct device *dev, - uint32_t mask) +static int gpio_mmio32_port_set_bits_raw(const struct device *dev, uint32_t mask) { struct gpio_mmio32_context *context = dev->data; const struct gpio_mmio32_config *config = context->config; @@ -111,8 +132,7 @@ static int gpio_mmio32_port_set_bits_raw(const struct device *dev, return 0; } -static int gpio_mmio32_port_clear_bits_raw(const struct device *dev, - uint32_t mask) +static int gpio_mmio32_port_clear_bits_raw(const struct device *dev, uint32_t mask) { struct gpio_mmio32_context *context = dev->data; const struct gpio_mmio32_config *config = context->config; @@ -129,8 +149,7 @@ static int gpio_mmio32_port_clear_bits_raw(const struct device *dev, return 0; } -static int gpio_mmio32_port_toggle_bits(const struct device *dev, - uint32_t mask) +static int gpio_mmio32_port_toggle_bits(const struct device *dev, uint32_t mask) { struct gpio_mmio32_context *context = dev->data; const struct gpio_mmio32_config *config = context->config; @@ -147,8 +166,7 @@ static int gpio_mmio32_port_toggle_bits(const struct device *dev, return 0; } -int gpio_mmio_pin_interrupt_configure(const struct device *port, - gpio_pin_t pin, +int gpio_mmio32_pin_interrupt_configure(const struct device *port, gpio_pin_t pin, enum gpio_int_mode, enum gpio_int_trig) { return -ENOTSUP; @@ -161,7 +179,7 @@ DEVICE_API(gpio, gpio_mmio32_api) = { .port_set_bits_raw = gpio_mmio32_port_set_bits_raw, .port_clear_bits_raw = gpio_mmio32_port_clear_bits_raw, .port_toggle_bits = gpio_mmio32_port_toggle_bits, - .pin_interrupt_configure = gpio_mmio_pin_interrupt_configure, + .pin_interrupt_configure = gpio_mmio32_pin_interrupt_configure, }; int gpio_mmio32_init(const struct device *dev) @@ -173,3 +191,22 @@ int gpio_mmio32_init(const struct device *dev) return 0; } + +#define MMIO32_GPIO_DEVICE(n) \ + static struct gpio_mmio32_context gpio_mmio32_##n##_ctx; \ + \ + static const struct gpio_mmio32_config gpio_mmio32_##n##_cfg = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .reg = (volatile uint32_t *)DT_INST_REG_ADDR(n), \ + .mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + .is_input = DT_INST_PROP(n, direction_input), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_mmio32_init, NULL, &gpio_mmio32_##n##_ctx, \ + &gpio_mmio32_##n##_cfg, PRE_KERNEL_1, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &gpio_mmio32_api); + +DT_INST_FOREACH_STATUS_OKAY(MMIO32_GPIO_DEVICE) diff --git a/dts/bindings/gpio/arm,mps2-fpgaio-gpio.yaml b/dts/bindings/gpio/arm,mmio32-gpio.yaml similarity index 52% rename from dts/bindings/gpio/arm,mps2-fpgaio-gpio.yaml rename to dts/bindings/gpio/arm,mmio32-gpio.yaml index 1c91ef9ca2a5a..0a8692adef4e0 100644 --- a/dts/bindings/gpio/arm,mps2-fpgaio-gpio.yaml +++ b/dts/bindings/gpio/arm,mmio32-gpio.yaml @@ -1,6 +1,6 @@ -description: GPIO controller on ARM MPS2 FPGA +description: ARM MMIO32 GPIO -compatible: "arm,mps2-fpgaio-gpio" +compatible: "arm,mmio32-gpio" include: [gpio-controller.yaml, base.yaml] @@ -14,5 +14,9 @@ properties: "#gpio-cells": const: 1 + direction-input: + type: boolean + description: Marks this pin set as all input pins. + gpio-cells: - pin diff --git a/dts/bindings/gpio/arm,mps3-fpgaio-gpio.yaml b/dts/bindings/gpio/arm,mps3-fpgaio-gpio.yaml deleted file mode 100644 index 8d93742f9edc7..0000000000000 --- a/dts/bindings/gpio/arm,mps3-fpgaio-gpio.yaml +++ /dev/null @@ -1,18 +0,0 @@ -description: GPIO controller on ARM MPS3 FPGA - -compatible: "arm,mps3-fpgaio-gpio" - -include: [gpio-controller.yaml, base.yaml] - -properties: - reg: - required: true - - ngpios: - required: true - - "#gpio-cells": - const: 1 - -gpio-cells: - - pin diff --git a/include/zephyr/drivers/gpio/gpio_mmio32.h b/include/zephyr/drivers/gpio/gpio_mmio32.h deleted file mode 100644 index 005f72052936d..0000000000000 --- a/include/zephyr/drivers/gpio/gpio_mmio32.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2016 Linaro Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_DRIVERS_GPIO_GPIO_MMIO32_H_ -#define ZEPHYR_INCLUDE_DRIVERS_GPIO_GPIO_MMIO32_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern const struct gpio_driver_api gpio_mmio32_api; - -struct gpio_mmio32_config { - /* gpio_driver_config needs to be first */ - struct gpio_driver_config common; - volatile uint32_t *reg; - uint32_t mask; -}; - -struct gpio_mmio32_context { - /* gpio_driver_data needs to be first */ - struct gpio_driver_data common; - const struct gpio_mmio32_config *config; -}; - -int gpio_mmio32_init(const struct device *dev); - -#ifdef CONFIG_GPIO_MMIO32 - -/** - * Create a device object for accessing a simple 32-bit i/o register using the - * same APIs as GPIO drivers. - * - * @param node_id The devicetree node identifier. - * @param _address The address of the 32-bit i/o register the device will - * provide access to. - * @param _mask Mask of bits in the register that it is valid to access. - * E.g. 0xffffffffu to allow access to all of them. - * - */ -#define GPIO_MMIO32_INIT(node_id, _address, _mask) \ -static struct gpio_mmio32_context _CONCAT(Z_DEVICE_DT_DEV_ID(node_id), _ctx); \ - \ -static const struct gpio_mmio32_config _CONCAT(Z_DEVICE_DT_DEV_ID(node_id), _cfg) = { \ - .common = { \ - .port_pin_mask = _mask, \ - }, \ - .reg = (volatile uint32_t *)_address, \ - .mask = _mask, \ -}; \ - \ -DEVICE_DT_DEFINE(node_id, \ - &gpio_mmio32_init, \ - NULL, \ - &_CONCAT(Z_DEVICE_DT_DEV_ID(node_id), _ctx), \ - &_CONCAT(Z_DEVICE_DT_DEV_ID(node_id), _cfg), \ - PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ - &gpio_mmio32_api) - - -#else /* CONFIG_GPIO_MMIO32 */ - -/* Null definition for when support not configured into kernel */ -#define GPIO_MMIO32_INIT(node_id, _address, _mask) - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_INCLUDE_DRIVERS_GPIO_GPIO_MMIO32_H_ */ diff --git a/soc/arm/mps2/soc.c b/soc/arm/mps2/soc.c index 343330d4515c8..a45e1815f3d7e 100644 --- a/soc/arm/mps2/soc.c +++ b/soc/arm/mps2/soc.c @@ -7,40 +7,24 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include - -/* Setup GPIO drivers for accessing FPGAIO registers */ -#define FPGAIO_NODE(n) DT_INST(n, arm_mps2_fpgaio_gpio) -#define FPGAIO_INIT(n) \ - GPIO_MMIO32_INIT(FPGAIO_NODE(n), \ - DT_REG_ADDR(FPGAIO_NODE(n)), \ - BIT_MASK(DT_PROP(FPGAIO_NODE(n), ngpios))) - -/* We expect there to be 3 arm,mps2-fpgaio-gpio devices: - * led0, button, and misc - */ -FPGAIO_INIT(0); -FPGAIO_INIT(1); -FPGAIO_INIT(2); - /* (Secure System Control) Base Address */ -#define SSE_200_SYSTEM_CTRL_S_BASE (0x50021000UL) -#define SSE_200_SYSTEM_CTRL_INITSVTOR1 (SSE_200_SYSTEM_CTRL_S_BASE + 0x114) -#define SSE_200_SYSTEM_CTRL_CPU_WAIT (SSE_200_SYSTEM_CTRL_S_BASE + 0x118) -#define SSE_200_CPU_ID_UNIT_BASE (0x5001F000UL) +#define SSE_200_SYSTEM_CTRL_S_BASE (0x50021000UL) +#define SSE_200_SYSTEM_CTRL_INITSVTOR1 (SSE_200_SYSTEM_CTRL_S_BASE + 0x114) +#define SSE_200_SYSTEM_CTRL_CPU_WAIT (SSE_200_SYSTEM_CTRL_S_BASE + 0x118) +#define SSE_200_CPU_ID_UNIT_BASE (0x5001F000UL) /* The base address that the application image will start at on the secondary * (non-TrustZone) Cortex-M33 mcu. */ -#define CPU1_FLASH_ADDRESS (0x38B000) +#define CPU1_FLASH_ADDRESS (0x38B000) /* The memory map offset for the application image, which is used * to determine the location of the reset vector at startup. */ -#define CPU1_FLASH_OFFSET (0x10000000) +#define CPU1_FLASH_OFFSET (0x10000000) /** * @brief Wake up CPU 1 from another CPU, this is platform specific. @@ -49,9 +33,7 @@ void wakeup_cpu1(void) { /* Set the Initial Secure Reset Vector Register for CPU 1 */ *(uint32_t *)(SSE_200_SYSTEM_CTRL_INITSVTOR1) = - (uint32_t)_vector_start + - CPU1_FLASH_ADDRESS - - CPU1_FLASH_OFFSET; + (uint32_t)_vector_start + CPU1_FLASH_ADDRESS - CPU1_FLASH_OFFSET; /* Set the CPU Boot wait control after reset */ *(uint32_t *)(SSE_200_SYSTEM_CTRL_CPU_WAIT) = 0; diff --git a/soc/arm/mps3/CMakeLists.txt b/soc/arm/mps3/CMakeLists.txt index 3cf33caa58dba..bd8fb92d7804f 100644 --- a/soc/arm/mps3/CMakeLists.txt +++ b/soc/arm/mps3/CMakeLists.txt @@ -1,10 +1,6 @@ # Copyright (c) 2021 Linaro Limited # 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/arm/mps3/soc.c b/soc/arm/mps3/soc.c deleted file mode 100644 index e51a9ba5c59ad..0000000000000 --- a/soc/arm/mps3/soc.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2021 Linaro Limited - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - - -/* Setup GPIO drivers for accessing FPGAIO registers */ -#define FPGAIO_NODE(n) DT_INST(n, arm_mps3_fpgaio_gpio) -#define FPGAIO_INIT(n) \ - GPIO_MMIO32_INIT(FPGAIO_NODE(n), \ - DT_REG_ADDR(FPGAIO_NODE(n)), \ - BIT_MASK(DT_PROP(FPGAIO_NODE(n), ngpios))) - -/* We expect there to be 3 arm,mps3-fpgaio-gpio devices: - * led0, button, and misc - */ -FPGAIO_INIT(0); -FPGAIO_INIT(1); -FPGAIO_INIT(2); diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521-common.dtsi b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521-common.dtsi index 5b1959ff5fe38..acd2be8da72e6 100644 --- a/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521-common.dtsi +++ b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521-common.dtsi @@ -156,7 +156,7 @@ i2c_shield1: i2c@20d000 { }; gpio_led0: mps2_fpgaio@302000 { - compatible = "arm,mps2-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x302000 0x4>; gpio-controller; @@ -165,16 +165,17 @@ gpio_led0: mps2_fpgaio@302000 { }; gpio_button: mps2_fpgaio@302008 { - compatible = "arm,mps2-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x302008 0x4>; gpio-controller; #gpio-cells = <1>; ngpios = <2>; + direction-input; }; gpio_misc: mps2_fpgaio@30204c { - compatible = "arm,mps2-fpgaio-gpio"; + compatible = "arm,mmio32-gpio"; reg = <0x30204c 0x4>; gpio-controller; diff --git a/tests/drivers/gpio/gpio_get_direction/testcase.yaml b/tests/drivers/gpio/gpio_get_direction/testcase.yaml index b66145fc9af4a..c8dfc105c27e1 100644 --- a/tests/drivers/gpio/gpio_get_direction/testcase.yaml +++ b/tests/drivers/gpio/gpio_get_direction/testcase.yaml @@ -8,6 +8,5 @@ tests: # Fix exclude when we can exclude just sim run platform_exclude: - mps2/an385 - - mps2/an521/cpu0 - neorv32 filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") From e9f95b7c92564aa8f981699f8d9dbf3c6a725d8f Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 28 Jan 2025 15:08:36 +0000 Subject: [PATCH 0165/6055] drivers: gpio: mmio32: remove redundant mask field. The pin mask is already present in the common structure. Signed-off-by: Wilfried Chauveau --- drivers/gpio/gpio_mmio32.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio_mmio32.c b/drivers/gpio/gpio_mmio32.c index 7c0c8e0c9ab57..04d84441fdcb6 100644 --- a/drivers/gpio/gpio_mmio32.c +++ b/drivers/gpio/gpio_mmio32.c @@ -37,7 +37,6 @@ struct gpio_mmio32_config { /* gpio_driver_config needs to be first */ struct gpio_driver_config common; volatile uint32_t *reg; - uint32_t mask; bool is_input; }; @@ -54,7 +53,7 @@ static int gpio_mmio32_config(const struct device *dev, gpio_pin_t pin, gpio_fla struct gpio_mmio32_context *context = dev->data; const struct gpio_mmio32_config *config = context->config; - if ((config->mask & (1 << pin)) == 0) { + if ((config->common.port_pin_mask & (1 << pin)) == 0) { return -EINVAL; /* Pin not in our validity mask */ } @@ -79,7 +78,7 @@ static int gpio_mmio32_config(const struct device *dev, gpio_pin_t pin, gpio_fla if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { *reg = (*reg | (1 << pin)); } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { - *reg = (*reg & (config->mask & ~(1 << pin))); + *reg = (*reg & (config->common.port_pin_mask & ~(1 << pin))); } irq_unlock(key); } @@ -92,7 +91,7 @@ static int gpio_mmio32_port_get_raw(const struct device *dev, uint32_t *value) struct gpio_mmio32_context *context = dev->data; const struct gpio_mmio32_config *config = context->config; - *value = *config->reg & config->mask; + *value = *config->reg & config->common.port_pin_mask; return 0; } @@ -104,7 +103,7 @@ static int gpio_mmio32_port_set_masked_raw(const struct device *dev, uint32_t ma volatile uint32_t *reg = config->reg; unsigned int key; - mask &= config->mask; + mask &= config->common.port_pin_mask; value &= mask; /* Update pin state atomically */ @@ -122,7 +121,7 @@ static int gpio_mmio32_port_set_bits_raw(const struct device *dev, uint32_t mask volatile uint32_t *reg = config->reg; unsigned int key; - mask &= config->mask; + mask &= config->common.port_pin_mask; /* Update pin state atomically */ key = irq_lock(); @@ -139,7 +138,7 @@ static int gpio_mmio32_port_clear_bits_raw(const struct device *dev, uint32_t ma volatile uint32_t *reg = config->reg; unsigned int key; - mask &= config->mask; + mask &= config->common.port_pin_mask; /* Update pin state atomically */ key = irq_lock(); @@ -156,7 +155,7 @@ static int gpio_mmio32_port_toggle_bits(const struct device *dev, uint32_t mask) volatile uint32_t *reg = config->reg; unsigned int key; - mask &= config->mask; + mask &= config->common.port_pin_mask; /* Update pin state atomically */ key = irq_lock(); @@ -201,7 +200,6 @@ int gpio_mmio32_init(const struct device *dev) .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ }, \ .reg = (volatile uint32_t *)DT_INST_REG_ADDR(n), \ - .mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ .is_input = DT_INST_PROP(n, direction_input), \ }; \ \ From dc0fd3af17387e1d421625e5f6cc63252d24e12f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 28 Jan 2025 08:13:53 -0800 Subject: [PATCH 0166/6055] picolibc: Use common abort(), call from assert when !__ASSERT_ON Switch to the common abort implementation so that we can use it from the assert hooks to avoid undefined behavior. Closes: 84824 Signed-off-by: Keith Packard --- lib/libc/Kconfig | 1 + lib/libc/picolibc/assert.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index 150ab256c6fff..eb3c19247ce7a 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -87,6 +87,7 @@ config PICOLIBC select NEED_LIBC_MEM_PARTITION select TC_PROVIDES_POSIX_C_LANG_SUPPORT_R imply COMMON_LIBC_MALLOC + imply COMMON_LIBC_ABORT depends on PICOLIBC_SUPPORTED help Build with picolibc library. The picolibc library is built as diff --git a/lib/libc/picolibc/assert.c b/lib/libc/picolibc/assert.c index 806d996a230a1..7eede1e49d92b 100644 --- a/lib/libc/picolibc/assert.c +++ b/lib/libc/picolibc/assert.c @@ -11,18 +11,22 @@ FUNC_NORETURN void __assert_func(const char *file, int line, const char *function, const char *expression) { +#if __ASSERT_ON __ASSERT(0, "assertion \"%s\" failed: file \"%s\", line %d%s%s\n", expression, file, line, function ? ", function: " : "", function ? function : ""); - CODE_UNREACHABLE; +#endif + abort(); } #else FUNC_NORETURN void __assert_no_args(void) { +#if __ASSERT_ON __ASSERT_NO_MSG(0); - CODE_UNREACHABLE; +#endif + abort(); } #endif From 1c6915b9b1c8fb7157aed5e99cfc04e29fe9cec6 Mon Sep 17 00:00:00 2001 From: Khaoula Bidani Date: Wed, 5 Feb 2025 17:41:41 +0100 Subject: [PATCH 0167/6055] dts: bindings: clock: make clocks property required Modify properties clocks as required in stm32-clock-mux.yaml. Signed-off-by: Khaoula Bidani --- dts/bindings/clock/st,stm32-clock-mux.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dts/bindings/clock/st,stm32-clock-mux.yaml b/dts/bindings/clock/st,stm32-clock-mux.yaml index 1798ee686d2ce..a6a1409c69fe3 100644 --- a/dts/bindings/clock/st,stm32-clock-mux.yaml +++ b/dts/bindings/clock/st,stm32-clock-mux.yaml @@ -4,7 +4,7 @@ description: | STM32 Clock multiplexer Describes a clock multiplexer, such as per_ck on STM32H7 or - CLK48 on STM32L5. + CLK48 on STM32WB. The only property of this node is to select a clock input. For instance: &perck { @@ -20,3 +20,8 @@ include: - status - compatible - clocks + +properties: + + clocks: + required: true From d2818c4d4905daa8db2d635bdc1b5bbeb93ca70d Mon Sep 17 00:00:00 2001 From: Titouan Christophe Date: Tue, 4 Feb 2025 22:21:08 +0100 Subject: [PATCH 0168/6055] audio: codec: add new cs43l22 driver Add new driver for the Cirrus CS43L22 audio DAC. Signed-off-by: Titouan Christophe --- drivers/audio/CMakeLists.txt | 1 + drivers/audio/Kconfig | 1 + drivers/audio/Kconfig.cs43l22 | 12 + drivers/audio/cs43l22.c | 311 ++++++++++++++++++++++++++ dts/bindings/audio/cirrus,c43l22.yaml | 18 ++ 5 files changed, 343 insertions(+) create mode 100644 drivers/audio/Kconfig.cs43l22 create mode 100644 drivers/audio/cs43l22.c create mode 100644 dts/bindings/audio/cirrus,c43l22.yaml diff --git a/drivers/audio/CMakeLists.txt b/drivers/audio/CMakeLists.txt index 0396ae23e483f..92119d25defaa 100644 --- a/drivers/audio/CMakeLists.txt +++ b/drivers/audio/CMakeLists.txt @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_AUDIO_TAS6422DAC tas6422dac.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_SHELL codec_shell.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_DMIC_MCUX dmic_mcux.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_WM8904 wm8904.c) +zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_CS43L22 cs43l22.c) diff --git a/drivers/audio/Kconfig b/drivers/audio/Kconfig index 70d02b5320a21..ccc4a7375d4f3 100644 --- a/drivers/audio/Kconfig +++ b/drivers/audio/Kconfig @@ -35,6 +35,7 @@ module = AUDIO_CODEC module-str = audio codec source "subsys/logging/Kconfig.template.log_config" +source "drivers/audio/Kconfig.cs43l22" source "drivers/audio/Kconfig.tas6422dac" source "drivers/audio/Kconfig.tlv320dac" source "drivers/audio/Kconfig.wm8904" diff --git a/drivers/audio/Kconfig.cs43l22 b/drivers/audio/Kconfig.cs43l22 new file mode 100644 index 0000000000000..6fa65a451b943 --- /dev/null +++ b/drivers/audio/Kconfig.cs43l22 @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Titouan Christophe +# SPDX-License-Identifier: Apache-2.0 + +config AUDIO_CODEC_CS43L22 + bool "Cirrus CS43L22 driver" + default y + select I2C + depends on GPIO + depends on DT_HAS_CIRRUS_CS43L22_ENABLED + help + Enable the driver for the Cirrus CS43L22 low Power, stereo DAC + with headphone & speaker amplifiers diff --git a/drivers/audio/cs43l22.c b/drivers/audio/cs43l22.c new file mode 100644 index 0000000000000..0da2af130b498 --- /dev/null +++ b/drivers/audio/cs43l22.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2025 Titouan Christophe + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(cirrus_cs43l22); + +#define DT_DRV_COMPAT cirrus_cs43l22 + +/* + * See datasheet: https://statics.cirrus.com/pubs/proDatasheet/CS43L22_F2.pdf + */ + +/* (datasheet) 6. REGISTER QUICK REFERENCE */ +#define REG_ID 0x01 +#define REG_POWER_CTL_1 0x02 +#define REG_POWER_CTL_2 0x04 +#define REG_CLOCKING_CTL 0x05 +#define REG_INTERFACE_CTL_1 0x06 +#define REG_INTERFACE_CTL_2 0x07 +#define REG_PASSTHROUGH_A 0x08 +#define REG_PASSTHROUGH_B 0x09 +#define REG_ANALOG_ZC_AND_SR 0x0a +#define REG_PASSTHROUGH_GANG_CONTROL 0x0c +#define REG_PLAYBACK_CTL_1 0x0d +#define REG_MISC_CTL 0x0e +#define REG_PLAYBACK_CTL_2 0x0f +#define REG_PASSTHROUGH_A_VOL 0x14 +#define REG_PASSTHROUGH_B_VOL 0x15 +#define REG_PCMA_VOL 0x1a +#define REG_PCMB_VOL 0x1b +#define REG_BEEP_FREQ 0x1c +#define REG_BEEP_VOL 0x1d +#define REG_BEEP_TONE 0x1e +#define REG_TONE_CTL 0x1f +#define REG_MASTER_A_VOL 0x20 +#define REG_MASTER_B_VOL 0x21 +#define REG_HEADPHONES_A_VOL 0x22 +#define REG_HEADPHONES_B_VOL 0x23 +#define REG_SPEAKER_A_VOL 0x22 +#define REG_SPEAKER_B_VOL 0x23 +#define REG_LIMITER_CTL_1 0x27 +#define REG_LIMITER_CTL_2 0x28 +#define REG_STATUS 0x2e +#define REG_SPEAKER_STATUS 0x31 + +/* (datasheet) 7.5.4 DAC Interface Format */ +#define DAC_IF_FORMAT_LEFT_JUSTIFIED 0 +#define DAC_IF_FORMAT_I2S 1 +#define DAC_IF_FORMAT_RIGHT_JUSTIFIED 2 + +/* (datasheet) 7.5.5 Audio Word Length */ +#define WORDLEN_32 0 +#define WORDLEN_24 1 +#define WORDLEN_20 2 +#define WORDLEN_16 3 +#define WORDLEN_RIGHT_24 0 +#define WORDLEN_RIGHT_20 1 +#define WORDLEN_RIGHT_18 2 +#define WORDLEN_RIGHT_16 3 + +/* (datasheet) 7.12 Playback Control 2 */ +#define HEADPHONES_B_MUTE (1 << 7) +#define HEADPHONES_A_MUTE (1 << 6) +#define SPEAKER_B_MUTE (1 << 5) +#define SPEAKER_A_MUTE (1 << 4) + +#define cs43l22_write(_i2c, _reg, _value) \ + cs43l22_write_masked(_i2c, _reg, _value, 0xff) + +static inline int cs43l22_write_masked(const struct i2c_dt_spec *i2c, uint8_t reg, + uint8_t value, uint8_t mask) +{ + int ret; + uint8_t actual_value = 0; + + if (mask != 0xff) { + ret = i2c_burst_read_dt(i2c, reg, &actual_value, 1); + if (ret) { + LOG_ERR("Unable to get actual register value [%02X]", reg); + return ret; + } + } + actual_value = (actual_value & ~mask) | (value & mask); + + return i2c_burst_write_dt(i2c, reg, &actual_value, 1); +} + +#define cs43l22_soft_power_down(_i2c) cs43l22_write(_i2c, REG_POWER_CTL_1, 0x01) +#define cs43l22_soft_power_up(_i2c) cs43l22_write(_i2c, REG_POWER_CTL_1, 0x9e) + +struct cs43l22_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec reset_gpio; +}; + +static int cs43l22_configure(const struct device *dev, struct audio_codec_cfg *audiocfg) +{ + uint8_t format, wordlen; + const struct cs43l22_config *cfg = dev->config; + + if (audiocfg->dai_route != AUDIO_ROUTE_PLAYBACK) { + return -ENOTSUP; + } + + switch (audiocfg->dai_type) { + case AUDIO_DAI_TYPE_LEFT_JUSTIFIED: + format = DAC_IF_FORMAT_LEFT_JUSTIFIED; + break; + case AUDIO_DAI_TYPE_I2S: + format = DAC_IF_FORMAT_I2S; + break; + case AUDIO_DAI_TYPE_RIGHT_JUSTIFIED: + format = DAC_IF_FORMAT_RIGHT_JUSTIFIED; + break; + default: + return -ENOTSUP; + } + + if (format == DAC_IF_FORMAT_RIGHT_JUSTIFIED) { + switch (audiocfg->dai_cfg.i2s.word_size) { + case 16: + wordlen = WORDLEN_RIGHT_16; + break; + case 18: + wordlen = WORDLEN_RIGHT_18; + break; + case 20: + wordlen = WORDLEN_RIGHT_20; + break; + case 24: + wordlen = WORDLEN_RIGHT_24; + break; + default: + return -ENOTSUP; + } + } else { + switch (audiocfg->dai_cfg.i2s.word_size) { + case 16: + wordlen = WORDLEN_16; + break; + case 20: + wordlen = WORDLEN_20; + break; + case 24: + wordlen = WORDLEN_24; + break; + case 32: + wordlen = WORDLEN_32; + break; + default: + return -ENOTSUP; + } + } + + if (cs43l22_soft_power_down(&cfg->i2c)) { + return -EIO; + } + /* Set automatic clock detection */ + if (cs43l22_write(&cfg->i2c, REG_CLOCKING_CTL, (1 << 7))) { + return -EIO; + } + /* Set input audio format */ + if (cs43l22_write_masked(&cfg->i2c, REG_INTERFACE_CTL_1, (format << 2) | wordlen, 0xdf)) { + return -EIO; + } + if (cs43l22_soft_power_up(&cfg->i2c)) { + return -EIO; + } + return 0; +} + +static void cs43l22_start_output(const struct device *dev) +{ +} + +static void cs43l22_stop_output(const struct device *dev) +{ +} + +static int cs43l22_apply_properties(const struct device *dev) +{ + return 0; +} + +static inline int cs43l22_set_mute(const struct i2c_dt_spec *i2c, + audio_channel_t channel, bool mute) +{ + uint8_t chan_mute_mask = 0; + + switch (channel) { + case AUDIO_CHANNEL_ALL: + chan_mute_mask = HEADPHONES_A_MUTE + | HEADPHONES_B_MUTE + | SPEAKER_A_MUTE + | SPEAKER_B_MUTE; + break; + case AUDIO_CHANNEL_HEADPHONE_LEFT: + chan_mute_mask = HEADPHONES_A_MUTE; + break; + case AUDIO_CHANNEL_HEADPHONE_RIGHT: + chan_mute_mask = HEADPHONES_B_MUTE; + break; + case AUDIO_CHANNEL_FRONT_LEFT: + chan_mute_mask = SPEAKER_A_MUTE; + break; + case AUDIO_CHANNEL_FRONT_RIGHT: + chan_mute_mask = SPEAKER_B_MUTE; + break; + default: + return -ENOTSUP; + } + + return cs43l22_write_masked(i2c, REG_PLAYBACK_CTL_2, + mute * chan_mute_mask, chan_mute_mask); +} + +static inline int cs43l22_set_volume(const struct i2c_dt_spec *i2c, + audio_channel_t channel, int vol) +{ + uint8_t reg; + uint8_t volume_scaled = 65 + (191 * vol / 100); + + switch (channel) { + case AUDIO_CHANNEL_HEADPHONE_LEFT: + reg = REG_HEADPHONES_A_VOL; + break; + case AUDIO_CHANNEL_HEADPHONE_RIGHT: + reg = REG_HEADPHONES_B_VOL; + break; + case AUDIO_CHANNEL_FRONT_LEFT: + reg = REG_SPEAKER_A_VOL; + break; + case AUDIO_CHANNEL_FRONT_RIGHT: + reg = REG_SPEAKER_B_VOL; + break; + default: + return -ENOTSUP; + } + + return cs43l22_write(i2c, reg, volume_scaled); +} + +static int cs43l22_set_property(const struct device *dev, audio_property_t property, + audio_channel_t channel, audio_property_value_t val) +{ + const struct cs43l22_config *cfg = dev->config; + + switch (property) { + case AUDIO_PROPERTY_OUTPUT_MUTE: + return cs43l22_set_mute(&cfg->i2c, channel, val.mute); + case AUDIO_PROPERTY_OUTPUT_VOLUME: + return cs43l22_set_volume(&cfg->i2c, channel, val.vol); + default: + return -ENOTSUP; + } + +} + +static const struct audio_codec_api cs43l22_api = { + .configure = cs43l22_configure, + .start_output = cs43l22_start_output, + .stop_output = cs43l22_stop_output, + .set_property = cs43l22_set_property, + .apply_properties = cs43l22_apply_properties, +}; + +static int cs43l22_init(const struct device *dev) +{ + uint8_t regval; + const struct cs43l22_config *cfg = dev->config; + int ret; + + ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE); + if (ret) { + return -EIO; + } + + ret = i2c_burst_read_dt(&cfg->i2c, REG_ID, ®val, 1); + if (ret) { + LOG_ERR("Unable to read device ID"); + return -ENODEV; + } + + if ((regval >> 3) != 0x1C) { + LOG_ERR("Wrong Chip ID"); + return -ENODEV; + } + + LOG_DBG("Found CS43L22 (chip=%02X, rev=%c%d)", + regval >> 3, 'A' + ((regval >> 1) & 3), regval & 1); + + return 0; +} + +#define CS43L22_INIT(inst) \ + static const struct cs43l22_config cs43l22_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, cs43l22_init, NULL, NULL, \ + &cs43l22_config_##inst, POST_KERNEL, \ + CONFIG_AUDIO_CODEC_INIT_PRIORITY, \ + &cs43l22_api); + +DT_INST_FOREACH_STATUS_OKAY(CS43L22_INIT) diff --git a/dts/bindings/audio/cirrus,c43l22.yaml b/dts/bindings/audio/cirrus,c43l22.yaml new file mode 100644 index 0000000000000..59c5795856567 --- /dev/null +++ b/dts/bindings/audio/cirrus,c43l22.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2025 Titouan Christophe +# SPDX-License-Identifier: Apache-2.0 + +description: Cirrus CS43L22 audio DAC + +include: [i2c-device.yaml] + +compatible: "cirrus,cs43l22" + +properties: + reg: + required: true + + reset-gpios: + required: true + type: phandle-array + description: | + RESET pin From 88454c2e67435895b6eba04495e7d2f8c3a8ec63 Mon Sep 17 00:00:00 2001 From: Titouan Christophe Date: Tue, 4 Feb 2025 22:31:13 +0100 Subject: [PATCH 0169/6055] boards: st: stm32f4_disco: add support for audio output The stm32f4_disco board features an audio codec (cs43l22) connected to an audio jack (TRS) output, and to the stm32f4 via I2S and I2C. To set this up, several peripherals must be configured: - Enable I2S3 and the PLLI2S (tuned for 22.05/44.1/88.2 kHz audio) - Enable DMA1 (used by I2S3) - Enable I2C1, and add definition for the CS43L22 on the bus - Disable USART1 and CAN1 which have conflicting pinctrl with I2C1 This new setting is more appropriate, because this gives access to the audio jack output by default (instead of "bare" pins not connected to anything on the board). Signed-off-by: Titouan Christophe --- boards/st/stm32f4_disco/doc/index.rst | 16 +++++-- boards/st/stm32f4_disco/stm32f4_disco.dts | 52 +++++++++++++++++------ doc/releases/migration-guide-4.1.rst | 4 ++ 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/boards/st/stm32f4_disco/doc/index.rst b/boards/st/stm32f4_disco/doc/index.rst index f21b1cdc01407..b0106f4a6621a 100644 --- a/boards/st/stm32f4_disco/doc/index.rst +++ b/boards/st/stm32f4_disco/doc/index.rst @@ -89,6 +89,12 @@ The Zephyr stm32f4_disco board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | CAN | on-chip | CAN controller | +-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c controller | ++-----------+------------+-------------------------------------+ +| I2S | on-chip | i2s controller | ++-----------+------------+-------------------------------------+ +| AUDIO | on-board | audio codec on CS43L22 via I2S3 | ++-----------+------------+-------------------------------------+ .. note:: CAN feature requires CAN transceiver, such as `SK Pang CAN breakout board`_. Zephyr default configuration uses CAN_2 exclusively, as simultaneous use @@ -113,8 +119,6 @@ Default Zephyr Peripheral Mapping: .. rst-class:: rst-columns -- UART_1_TX : PB6 -- UART_1_RX : PB7 - UART_2_TX : PA2 - UART_2_RX : PA3 - USER_PB : PA0 @@ -124,10 +128,14 @@ Default Zephyr Peripheral Mapping: - LD6 : PD15 - USB DM : PA11 - USB DP : PA12 -- CAN1_RX : PB8 -- CAN1_TX : PB9 - CAN2_RX : PB5 - CAN2_TX : PB13 +- I2C1_SDA : PB9 +- I2C1_SCL : PB6 +- I2S3_MCK : PC7 +- I2S3_CK : PC10 +- I2S3_SD : PC12 +- I2S3_WS : PA4 System Clock ============ diff --git a/boards/st/stm32f4_disco/stm32f4_disco.dts b/boards/st/stm32f4_disco/stm32f4_disco.dts index 4e5d9ff87f869..10404e49103cd 100644 --- a/boards/st/stm32f4_disco/stm32f4_disco.dts +++ b/boards/st/stm32f4_disco/stm32f4_disco.dts @@ -83,13 +83,6 @@ }; }; -&usart1 { - pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>; - pinctrl-names = "default"; - current-speed = <115200>; - status = "okay"; -}; - &clk_lsi { status = "okay"; }; @@ -159,12 +152,6 @@ zephyr_udc0: &usbotg_fs { status = "okay"; }; -&can1 { - pinctrl-0 = <&can1_rx_pb8 &can1_tx_pb9>; - pinctrl-names = "default"; - status = "disabled"; -}; - &can2 { pinctrl-0 = <&can2_rx_pb5 &can2_tx_pb13>; pinctrl-names = "default"; @@ -187,3 +174,42 @@ zephyr_udc0: &usbotg_fs { &vbat { status = "okay"; }; + +&dma1 { + status = "okay"; +}; + +&plli2s { + /* Minimize audio clock error (with i2s mck-enabled) for all of: + * - 22.05kHz / 16b, 24b or 32b + * - 44.1kHz / 16b, 24b or 32b + * - 88.2kHz / 16b or 24b + * Note: because the PLLI2S is dependent on the main PLL, the latter + * should not be changed without checking impact on PLLI2S + */ + mul-n = <271>; + div-r = <2>; + status = "okay"; +}; + +&i2s3 { + mck-enabled; + pinctrl-0 = <&i2s3_ws_pa4 &i2s3_ck_pc10 &i2s3_sd_pc12 &i2s3_mck_pc7>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK(APB1, 15U)>, + <&rcc STM32_SRC_PLLI2S_R I2S_SEL(0)>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = ; + pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb9>; + pinctrl-names = "default"; + status = "okay"; + + audio_codec: cs43l22@4a { + compatible = "cirrus,cs43l22"; + reg = <0x4a>; + reset-gpios = <&gpiod 4 0>; + }; +}; diff --git a/doc/releases/migration-guide-4.1.rst b/doc/releases/migration-guide-4.1.rst index 7315df74144e5..59439d6a7e7ef 100644 --- a/doc/releases/migration-guide-4.1.rst +++ b/doc/releases/migration-guide-4.1.rst @@ -67,6 +67,10 @@ Boards always erase only the sectors of the external flash used by the new firmware, and the ``nrfutil`` one would always erase the whole external flash. +* CAN1 and USART1 have been disabled on the ``stm32f4_disco``, because of + conflicting pinctrl on I2C1, which is now used to control the audio codec + connected to the audio jack output. + Devicetree ********** From 74bef41e0aaa33755147ad4b38521c16a52490cd Mon Sep 17 00:00:00 2001 From: Titouan Christophe Date: Fri, 7 Feb 2025 11:59:01 +0100 Subject: [PATCH 0170/6055] samples: drivers: i2s: i2s_codec: add support for stm32f4_disco Add configuration and board overlay in the I2S audio codec sample to demonstrate usage of the newly introduced audio output feature. Signed-off-by: Titouan Christophe --- .../drivers/i2s/i2s_codec/boards/stm32f4_disco.conf | 8 ++++++++ .../drivers/i2s/i2s_codec/boards/stm32f4_disco.overlay | 10 ++++++++++ 2 files changed, 18 insertions(+) create mode 100644 samples/drivers/i2s/i2s_codec/boards/stm32f4_disco.conf create mode 100644 samples/drivers/i2s/i2s_codec/boards/stm32f4_disco.overlay diff --git a/samples/drivers/i2s/i2s_codec/boards/stm32f4_disco.conf b/samples/drivers/i2s/i2s_codec/boards/stm32f4_disco.conf new file mode 100644 index 0000000000000..b3872c1efe5e2 --- /dev/null +++ b/samples/drivers/i2s/i2s_codec/boards/stm32f4_disco.conf @@ -0,0 +1,8 @@ +# Copyright 2025 Titouan Christophe +# SPDX-License-Identifier: Apache-2.0 + +# Even though the stm32f4_disco board overlay is tuned for 22.05/44.1/88.2kHz +# audio output, it hasn't enough RAM to hold all buffers allocated by this +# sample at such higher audio rates +CONFIG_SAMPLE_FREQ=8000 +CONFIG_AUDIO_CODEC=y diff --git a/samples/drivers/i2s/i2s_codec/boards/stm32f4_disco.overlay b/samples/drivers/i2s/i2s_codec/boards/stm32f4_disco.overlay new file mode 100644 index 0000000000000..e4adf92457874 --- /dev/null +++ b/samples/drivers/i2s/i2s_codec/boards/stm32f4_disco.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Titouan Christophe + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2s-codec-tx = &i2s3; + }; +}; From 2f211f415be34819e0f4c523afc06cb4c8612e23 Mon Sep 17 00:00:00 2001 From: Alexander Kozhinov Date: Fri, 7 Feb 2025 22:03:07 +0100 Subject: [PATCH 0171/6055] soc: st: stm32: stm32h7x This change splits eth sram region name definition and configuration. In the end the configuration is stored only once er declared name. This name shall increase readability and maintainability Signed-off-by: Alexander Kozhinov --- soc/st/stm32/stm32h7x/mpu_regions.c | 20 ++++++++++---------- soc/st/stm32/stm32h7x/sections.ld | 29 ++++++++++++++--------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/soc/st/stm32/stm32h7x/mpu_regions.c b/soc/st/stm32/stm32h7x/mpu_regions.c index 8582db6072493..f77018d36caed 100644 --- a/soc/st/stm32/stm32h7x/mpu_regions.c +++ b/soc/st/stm32/stm32h7x/mpu_regions.c @@ -22,19 +22,19 @@ static const struct arm_mpu_region mpu_regions[] = { MPU_RASR_XN_Msk | P_RW_U_NA_Msk) }), #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(mac)) + #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sram3)) - MPU_REGION_ENTRY("SRAM3_ETH_BUF", - DT_REG_ADDR(DT_NODELABEL(sram3)), - REGION_RAM_NOCACHE_ATTR(REGION_16K)), - MPU_REGION_ENTRY("SRAM3_ETH_DESC", - DT_REG_ADDR(DT_NODELABEL(sram3)), - REGION_PPB_ATTR(REGION_256B)), +#define sram_eth_node DT_NODELABEL(sram3) #else - MPU_REGION_ENTRY("SRAM2_ETH_BUF", - DT_REG_ADDR(DT_NODELABEL(sram2)), +#define sram_eth_node DT_NODELABEL(sram2) +#endif + +#if DT_NODE_HAS_STATUS_OKAY(sram_eth_node) + MPU_REGION_ENTRY("SRAM_ETH_BUF", + DT_REG_ADDR(sram_eth_node), REGION_RAM_NOCACHE_ATTR(REGION_16K)), - MPU_REGION_ENTRY("SRAM2_ETH_DESC", - DT_REG_ADDR(DT_NODELABEL(sram2)), + MPU_REGION_ENTRY("SRAM_ETH_DESC", + DT_REG_ADDR(sram_eth_node), REGION_PPB_ATTR(REGION_256B)), #endif #endif diff --git a/soc/st/stm32/stm32h7x/sections.ld b/soc/st/stm32/stm32h7x/sections.ld index 5f4fd794dd2a1..4989d8e90ea38 100644 --- a/soc/st/stm32/stm32h7x/sections.ld +++ b/soc/st/stm32/stm32h7x/sections.ld @@ -4,24 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -#if DT_NODE_HAS_STATUS(DT_NODELABEL(mac), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(mac)) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sram3)) +#define sram_eth_node DT_NODELABEL(sram3) +#else +#define sram_eth_node DT_NODELABEL(sram2) +#endif + +#if DT_NODE_HAS_STATUS_OKAY(sram_eth_node) SECTION_DATA_PROLOGUE(eth_stm32,(NOLOAD),) { -#if DT_NODE_HAS_STATUS(DT_NODELABEL(sram3), okay) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram3))); + . = ABSOLUTE(DT_REG_ADDR(sram_eth_node)); *(.eth_stm32_desc) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram3))) + 256; + . = ABSOLUTE(DT_REG_ADDR(sram_eth_node)) + 256; *(.eth_stm32_buf) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram3))) + 16K; -} GROUP_DATA_LINK_IN(LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram3)), LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram3))) - -#else - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram2))); - *(.eth_stm32_desc) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram2))) + 256; - *(.eth_stm32_buf) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram2))) + 16K; -} GROUP_DATA_LINK_IN(LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram2)), LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram2))) -#endif + . = ABSOLUTE(DT_REG_ADDR(sram_eth_node)) + 16K; +} GROUP_DATA_LINK_IN(LINKER_DT_NODE_REGION_NAME(sram_eth_node), LINKER_DT_NODE_REGION_NAME(sram_eth_node)) #endif + +#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(mac), okay) */ From 2a250b0d659098509396c01d8dca95af5a0e159d Mon Sep 17 00:00:00 2001 From: Van Petrosyan Date: Sat, 8 Feb 2025 15:56:46 +0100 Subject: [PATCH 0172/6055] sensor: scd4x: Fix ID for power down command Fixed command ID for power down command in SCD4X sensor driver Signed-off-by: Van Petrosyan --- drivers/sensor/sensirion/scd4x/scd4x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/sensirion/scd4x/scd4x.h b/drivers/sensor/sensirion/scd4x/scd4x.h index 3955d2021990f..2e7c8e0dcc42a 100644 --- a/drivers/sensor/sensirion/scd4x/scd4x.h +++ b/drivers/sensor/sensirion/scd4x/scd4x.h @@ -29,7 +29,7 @@ #define SCD4X_CMD_FACTORY_RESET 17 #define SCD4X_CMD_MEASURE_SINGLE_SHOT 18 #define SCD4X_CMD_MEASURE_SINGLE_SHOT_RHT 19 -#define SCD4X_CMD_POWER_DOWN 10 +#define SCD4X_CMD_POWER_DOWN 20 #define SCD4X_CMD_WAKE_UP 21 #define SCD4X_CMD_SET_SELF_CALIB_INITIAL_PERIOD 22 #define SCD4X_CMD_GET_SELF_CALIB_INITIAL_PERIOD 23 From c1d05bfaeae6304759bfbbba0b1f8758c985ac66 Mon Sep 17 00:00:00 2001 From: Yishai Jaffe Date: Sun, 9 Feb 2025 16:29:40 +0200 Subject: [PATCH 0173/6055] dts: st: use ST DMA defines Use dma_stm32.h DMA defines instead of using hard-coded values Signed-off-by: Yishai Jaffe --- boards/st/b_l4s5i_iot01a/b_l4s5i_iot01a.dts | 2 +- boards/st/stm32l496g_disco/stm32l496g_disco.dts | 2 +- dts/arm/st/f4/stm32f401.dtsi | 8 ++++---- dts/arm/st/f4/stm32f410.dtsi | 12 ++++++------ dts/arm/st/f4/stm32f411.dtsi | 12 ++++++------ dts/arm/st/f4/stm32f412.dtsi | 4 ++-- dts/arm/st/f4/stm32f446.dtsi | 4 ++-- dts/arm/st/h7/stm32h7a3.dtsi | 3 ++- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/boards/st/b_l4s5i_iot01a/b_l4s5i_iot01a.dts b/boards/st/b_l4s5i_iot01a/b_l4s5i_iot01a.dts index d7f5adab5bebc..da6bcc44c6a70 100644 --- a/boards/st/b_l4s5i_iot01a/b_l4s5i_iot01a.dts +++ b/boards/st/b_l4s5i_iot01a/b_l4s5i_iot01a.dts @@ -239,7 +239,7 @@ zephyr_udc0: &usbotg_fs { &octospim_p1_io2_pe14 &octospim_p1_io3_pe15>; pinctrl-names = "default"; - dmas = <&dma1 0 40 0x480>; /* request 40 for OCTOSPI1 */ + dmas = <&dma1 0 40 STM32_DMA_PERIPH_RX>; /* request 40 for OCTOSPI1 */ dma-names = "tx_rx"; status = "okay"; diff --git a/boards/st/stm32l496g_disco/stm32l496g_disco.dts b/boards/st/stm32l496g_disco/stm32l496g_disco.dts index 9027656636a47..4a942a5ab066c 100644 --- a/boards/st/stm32l496g_disco/stm32l496g_disco.dts +++ b/boards/st/stm32l496g_disco/stm32l496g_disco.dts @@ -194,7 +194,7 @@ zephyr_udc0: &usbotg_fs { &quadspi_bk1_ncs_pb11 &quadspi_clk_pa3>; pinctrl-names = "default"; - dmas = <&dma2 7 3 0x480>; /* channel 7 request 3 on DMA2 */ + dmas = <&dma2 7 3 STM32_DMA_PERIPH_RX>; /* channel 7 request 3 on DMA2 */ dma-names = "tx_rx"; flash-id = <1>; diff --git a/dts/arm/st/f4/stm32f401.dtsi b/dts/arm/st/f4/stm32f401.dtsi index eda9b1e4a9824..e113144d2e1ee 100644 --- a/dts/arm/st/f4/stm32f401.dtsi +++ b/dts/arm/st/f4/stm32f401.dtsi @@ -55,8 +55,8 @@ reg = <0x40003800 0x400>; clocks = <&rcc STM32_CLOCK(APB1, 14U)>; interrupts = <36 5>; - dmas = <&dma1 4 0 0x400 0x3 - &dma1 3 0 0x400 0x3>; + dmas = <&dma1 4 0 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma1 3 0 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; @@ -68,8 +68,8 @@ reg = <0x40003c00 0x400>; clocks = <&rcc STM32_CLOCK(APB1, 15U)>; interrupts = <51 5>; - dmas = <&dma1 5 0 0x400 0x3 - &dma1 0 0 0x400 0x3>; + dmas = <&dma1 5 0 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma1 0 0 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; diff --git a/dts/arm/st/f4/stm32f410.dtsi b/dts/arm/st/f4/stm32f410.dtsi index cd98599212af8..0f149a98e8cc0 100644 --- a/dts/arm/st/f4/stm32f410.dtsi +++ b/dts/arm/st/f4/stm32f410.dtsi @@ -42,8 +42,8 @@ reg = <0x40013000 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 12U)>; interrupts = <35 5>; - dmas = <&dma2 3 3 0x400 0x3 - &dma2 2 3 0x400 0x3>; + dmas = <&dma2 3 3 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma2 2 3 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; @@ -55,8 +55,8 @@ reg = <0x40003800 0x400>; clocks = <&rcc STM32_CLOCK(APB1, 14U)>; interrupts = <36 5>; - dmas = <&dma1 4 0 0x400 0x3 - &dma1 3 0 0x400 0x3>; + dmas = <&dma1 4 0 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma1 3 0 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; @@ -68,8 +68,8 @@ reg = <0x40015000 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 20U)>; interrupts = <85 5>; - dmas = <&dma2 6 7 0x400 0x3 - &dma2 5 7 0x400 0x3>; + dmas = <&dma2 6 7 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma2 5 7 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; diff --git a/dts/arm/st/f4/stm32f411.dtsi b/dts/arm/st/f4/stm32f411.dtsi index 8b1cec9089374..b0dfddd40ef67 100644 --- a/dts/arm/st/f4/stm32f411.dtsi +++ b/dts/arm/st/f4/stm32f411.dtsi @@ -35,8 +35,8 @@ reg = <0x40013000 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 12U)>; interrupts = <35 5>; - dmas = <&dma2 3 3 0x400 0x3 - &dma2 2 3 0x400 0x3>; + dmas = <&dma2 3 3 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma2 2 3 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; @@ -48,8 +48,8 @@ reg = <0x40013400 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 13U)>; interrupts = <84 5>; - dmas = <&dma2 1 4 0x400 0x3 - &dma2 0 4 0x400 0x3>; + dmas = <&dma2 1 4 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma2 0 4 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; @@ -61,8 +61,8 @@ reg = <0x40015000 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 20U)>; interrupts = <85 5>; - dmas = <&dma2 6 7 0x400 0x3 - &dma2 5 7 0x400 0x3>; + dmas = <&dma2 6 7 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma2 5 7 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; diff --git a/dts/arm/st/f4/stm32f412.dtsi b/dts/arm/st/f4/stm32f412.dtsi index e7620cba2f4c4..899a9325bfdbe 100644 --- a/dts/arm/st/f4/stm32f412.dtsi +++ b/dts/arm/st/f4/stm32f412.dtsi @@ -84,8 +84,8 @@ reg = <0x40013400 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 13U)>; interrupts = <84 5>; - dmas = <&dma2 1 4 0x400 0x3 - &dma2 0 4 0x400 0x3>; + dmas = <&dma2 1 4 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma2 0 4 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; diff --git a/dts/arm/st/f4/stm32f446.dtsi b/dts/arm/st/f4/stm32f446.dtsi index 84c6df6432f4f..a015b1d87b4f1 100644 --- a/dts/arm/st/f4/stm32f446.dtsi +++ b/dts/arm/st/f4/stm32f446.dtsi @@ -25,8 +25,8 @@ reg = <0x40013000 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 12U)>; interrupts = <35 5>; - dmas = <&dma2 3 3 0x400 0x3 - &dma2 2 3 0x400 0x3>; + dmas = <&dma2 3 3 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL + &dma2 2 3 STM32_DMA_MEM_INC STM32_DMA_FIFO_FULL>; dma-names = "tx", "rx"; status = "disabled"; }; diff --git a/dts/arm/st/h7/stm32h7a3.dtsi b/dts/arm/st/h7/stm32h7a3.dtsi index 67afdbafb3cdb..72879a8713695 100644 --- a/dts/arm/st/h7/stm32h7a3.dtsi +++ b/dts/arm/st/h7/stm32h7a3.dtsi @@ -87,7 +87,8 @@ reg = <0x58001400 0x400>; clocks = <&rcc STM32_CLOCK(APB4, 5U)>, <&rcc STM32_SRC_PLL1_Q SPI6_SEL(0)>; - dmas = <&dmamux2 0 12 0x20440 &dmamux2 1 11 0x20480>; + dmas = <&dmamux2 0 12 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) + &dmamux2 1 11 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; dma-names = "tx", "rx"; interrupts = <86 0>; status = "disabled"; From ba251072b8a78b5e2ffd5465d9ebc3b229f8ef46 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 4 Feb 2025 15:58:26 +0100 Subject: [PATCH 0174/6055] dts: arm: st: n6: add i2c Add I2C nodes to STM32N6 Signed-off-by: Guillaume Gautier --- dts/arm/st/n6/stm32n6.dtsi | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/dts/arm/st/n6/stm32n6.dtsi b/dts/arm/st/n6/stm32n6.dtsi index d5dfb4e28adaf..a2230d632bd52 100644 --- a/dts/arm/st/n6/stm32n6.dtsi +++ b/dts/arm/st/n6/stm32n6.dtsi @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -485,6 +486,54 @@ status = "disabled"; }; + i2c1: i2c@50005400 { + compatible = "st,stm32-i2c-v2"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x50005400 0x400>; + clocks = <&rcc STM32_CLOCK(APB1, 21)>; + interrupts = <100 0>, <101 0>; + interrupt-names = "event", "error"; + status = "disabled"; + }; + + i2c2: i2c@50005800 { + compatible = "st,stm32-i2c-v2"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x50005800 0x400>; + clocks = <&rcc STM32_CLOCK(APB1, 22)>; + interrupts = <102 0>, <103 0>; + interrupt-names = "event", "error"; + status = "disabled"; + }; + + i2c3: i2c@50005c00 { + compatible = "st,stm32-i2c-v2"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x50005C00 0x400>; + clocks = <&rcc STM32_CLOCK(APB1, 23)>; + interrupts = <104 0>, <105 0>; + interrupt-names = "event", "error"; + status = "disabled"; + }; + + i2c4: i2c@56001c00 { + compatible = "st,stm32-i2c-v2"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x56001C00 0x400>; + clocks = <&rcc STM32_CLOCK(APB4, 7)>; + interrupts = <106 0>, <107 0>; + interrupt-names = "event", "error"; + status = "disabled"; + }; + gpdma1: dma@50021000 { compatible = "st,stm32u5-dma"; #dma-cells = <3>; From 5d2b0a57c88250ab2b54a39acbeaa819cb39c27d Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 5 Feb 2025 15:30:14 +0100 Subject: [PATCH 0175/6055] boards: st: stm32n6: enable i2c Enable I2C on STM32N657X0-DK and Nucleo N657X0 boards. Signed-off-by: Guillaume Gautier --- .../nucleo_n657x0_q/arduino_r3_connector.dtsi | 1 + boards/st/nucleo_n657x0_q/doc/index.rst | 6 ++++++ .../nucleo_n657x0_q_common.dtsi | 19 +++++++++++++++++++ boards/st/nucleo_n657x0_q/twister.yaml | 2 ++ .../stm32n6570_dk/arduino_r3_connector.dtsi | 1 + boards/st/stm32n6570_dk/doc/index.rst | 6 ++++++ .../stm32n6570_dk/stm32n6570_dk_common.dtsi | 19 +++++++++++++++++++ boards/st/stm32n6570_dk/twister.yaml | 2 ++ 8 files changed, 56 insertions(+) diff --git a/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi b/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi index 17ca546f87ec7..6657111417b8b 100644 --- a/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi +++ b/boards/st/nucleo_n657x0_q/arduino_r3_connector.dtsi @@ -35,3 +35,4 @@ }; arduino_serial: &usart3 {}; +arduino_i2c: &i2c1 {}; diff --git a/boards/st/nucleo_n657x0_q/doc/index.rst b/boards/st/nucleo_n657x0_q/doc/index.rst index d4bd1a05107c2..d0e38a33dbccb 100644 --- a/boards/st/nucleo_n657x0_q/doc/index.rst +++ b/boards/st/nucleo_n657x0_q/doc/index.rst @@ -73,6 +73,8 @@ The Zephyr ``nucleo_n657x0_q`` board supports the following hardware features: +-----------+------------+-------------------------------------+ | GPIO | on-chip | gpio | +-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ | NVIC | on-chip | nested vector interrupt controller | +-----------+------------+-------------------------------------+ | UART | on-chip | serial port-polling; | @@ -99,6 +101,10 @@ Default Zephyr Peripheral Mapping: - FDCAN1_TX : PH2 - FDCAN1_RX : PD0 +- I2C1_SCL : PH9 +- I2C1_SDA : PC1 +- I2C4_SCL : PE13 +- I2C4_SDA : PE14 - LD1 : PO1 - LD2 : PG10 - USART_1_TX : PE5 diff --git a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi index d7c117876b338..08f5b5b308d60 100644 --- a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi +++ b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi @@ -7,6 +7,7 @@ #include #include #include +#include "arduino_r3_connector.dtsi" / { chosen { @@ -119,6 +120,24 @@ status = "okay"; }; +&i2c1 { + clocks = <&rcc STM32_CLOCK(APB1, 21)>, + <&rcc STM32_SRC_CKPER I2C1_SEL(1)>; + pinctrl-0 = <&i2c1_scl_ph9 &i2c1_sda_pc1>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; +}; + +&i2c4 { + clocks = <&rcc STM32_CLOCK(APB4, 7)>, + <&rcc STM32_SRC_CKPER I2C4_SEL(1)>; + pinctrl-0 = <&i2c4_scl_pe13 &i2c4_sda_pe14>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; +}; + &usart1 { clocks = <&rcc STM32_CLOCK(APB2, 4)>, <&rcc STM32_SRC_CKPER USART1_SEL(1)>; diff --git a/boards/st/nucleo_n657x0_q/twister.yaml b/boards/st/nucleo_n657x0_q/twister.yaml index 9a4790009af24..df264f33da838 100644 --- a/boards/st/nucleo_n657x0_q/twister.yaml +++ b/boards/st/nucleo_n657x0_q/twister.yaml @@ -4,9 +4,11 @@ arch: arm ram: 1024 flash: 1024 supported: + - arduino_i2c - arduino_serial - can - dma + - i2c - gpio - uart vendor: st diff --git a/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi b/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi index 6d887ee41bd6f..c77d0b143e56e 100644 --- a/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi +++ b/boards/st/stm32n6570_dk/arduino_r3_connector.dtsi @@ -36,3 +36,4 @@ }; arduino_serial: &usart2 {}; +arduino_i2c: &i2c1 {}; diff --git a/boards/st/stm32n6570_dk/doc/index.rst b/boards/st/stm32n6570_dk/doc/index.rst index d5b2493f62521..ab2d5116d7f4f 100644 --- a/boards/st/stm32n6570_dk/doc/index.rst +++ b/boards/st/stm32n6570_dk/doc/index.rst @@ -77,6 +77,8 @@ The Zephyr ``stm32n6570_dk`` board supports the following hardware features: +-----------+------------+-------------------------------------+ | GPIO | on-chip | gpio | +-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ | NVIC | on-chip | nested vector interrupt controller | +-----------+------------+-------------------------------------+ | UART | on-chip | serial port-polling; | @@ -103,6 +105,10 @@ Default Zephyr Peripheral Mapping: - FDCAN1_TX : PH2 - FDCAN1_RX : PD0 +- I2C1_SCL : PH9 +- I2C1_SDA : PC1 +- I2C4_SCL : PE13 +- I2C4_SDA : PE14 - LD1 : PO1 - LD2 : PG10 - USART_1_TX : PE5 diff --git a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi index 1cbf7e60b732c..1ddfb2068b2d6 100644 --- a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi +++ b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi @@ -6,6 +6,7 @@ #include #include +#include "arduino_r3_connector.dtsi" #include / { @@ -103,6 +104,24 @@ status = "okay"; }; +&i2c1 { + clocks = <&rcc STM32_CLOCK(APB1, 21)>, + <&rcc STM32_SRC_CKPER I2C1_SEL(1)>; + pinctrl-0 = <&i2c1_scl_ph9 &i2c1_sda_pc1>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; +}; + +&i2c4 { + clocks = <&rcc STM32_CLOCK(APB4, 7)>, + <&rcc STM32_SRC_CKPER I2C4_SEL(1)>; + pinctrl-0 = <&i2c4_scl_pe13 &i2c4_sda_pe14>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; +}; + &usart1 { clocks = <&rcc STM32_CLOCK(APB2, 4)>, <&rcc STM32_SRC_CKPER USART1_SEL(1)>; diff --git a/boards/st/stm32n6570_dk/twister.yaml b/boards/st/stm32n6570_dk/twister.yaml index 1ea433c8bbbaa..784b7f1629e2f 100644 --- a/boards/st/stm32n6570_dk/twister.yaml +++ b/boards/st/stm32n6570_dk/twister.yaml @@ -5,9 +5,11 @@ ram: 1024 flash: 1024 vendor: st supported: + - arduino_i2c - arduino_serial - can - dma + - i2c - gpio - uart variants: From c0164e4afe50cabd1c5b5270146278252cf3b86a Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 5 Feb 2025 15:55:21 +0100 Subject: [PATCH 0176/6055] tests: drivers: i2c: target_api: add stm32n6 overlays Add overlays for STM32N657X0-DK and Nucleo N657X0 boards. Signed-off-by: Guillaume Gautier --- .../nucleo_n657x0_q_stm32n657xx_sb.conf | 2 ++ .../nucleo_n657x0_q_stm32n657xx_sb.overlay | 30 +++++++++++++++++++ .../boards/stm32n6570_dk_stm32n657xx_sb.conf | 2 ++ .../stm32n6570_dk_stm32n657xx_sb.overlay | 30 +++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_n657x0_q_stm32n657xx_sb.overlay create mode 100644 tests/drivers/i2c/i2c_target_api/boards/stm32n6570_dk_stm32n657xx_sb.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/stm32n6570_dk_stm32n657xx_sb.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf b/tests/drivers/i2c/i2c_target_api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf new file mode 100644 index 0000000000000..34b2571d12516 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_n657x0_q_stm32n657xx_sb.conf @@ -0,0 +1,2 @@ +CONFIG_I2C_STM32_INTERRUPT=y +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_n657x0_q_stm32n657xx_sb.overlay b/tests/drivers/i2c/i2c_target_api/boards/nucleo_n657x0_q_stm32n657xx_sb.overlay new file mode 100644 index 0000000000000..cbf9f516799e0 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_n657x0_q_stm32n657xx_sb.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * SPDX-License-Identifier: Apache-2.0 + */ + +/* I2C bus pins are exposed on the ST Arduino header. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PC1 CN15:5 PH9 CN15:3 + * i2c4 PE14 CN15:26 PE13 CN15:28 + * + * Short Pin PC1 to PE14, and PH9 to PE13, for the test to pass. + */ + +&i2c1 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <256>; + }; +}; + +&i2c4 { + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <256>; + }; +}; diff --git a/tests/drivers/i2c/i2c_target_api/boards/stm32n6570_dk_stm32n657xx_sb.conf b/tests/drivers/i2c/i2c_target_api/boards/stm32n6570_dk_stm32n657xx_sb.conf new file mode 100644 index 0000000000000..34b2571d12516 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/stm32n6570_dk_stm32n657xx_sb.conf @@ -0,0 +1,2 @@ +CONFIG_I2C_STM32_INTERRUPT=y +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/stm32n6570_dk_stm32n657xx_sb.overlay b/tests/drivers/i2c/i2c_target_api/boards/stm32n6570_dk_stm32n657xx_sb.overlay new file mode 100644 index 0000000000000..8c0215c406bd7 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/stm32n6570_dk_stm32n657xx_sb.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * SPDX-License-Identifier: Apache-2.0 + */ + +/* I2C bus pins are exposed on the ST Arduino header. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PC1 CN12:10 (D15) PH9 CN12:9 (D14) + * i2c4 PE14 CN12:2 (D9) PE13 CN11:7 (D6) + * + * Short Pin PC1 to PE14, and PH9 to PE13, for the test to pass. + */ + +&i2c1 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <256>; + }; +}; + +&i2c4 { + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <256>; + }; +}; From 33301e69dee816a750d8ddf4c320c0342feab624 Mon Sep 17 00:00:00 2001 From: David Brown Date: Thu, 13 Feb 2025 08:13:32 -0700 Subject: [PATCH 0177/6055] modules: optional: Feature update for Rust Move to the latest Rust. This moves the rust support to the latest version of the module: commit 49c6712fe53b5b82e5c09e94548a4a51a021acfe Author: David Brown Date: Wed Feb 12 12:16:22 2025 -0700 zephyr: various comment cleanups from review suggestions This primarily brings in support for Zephyr Work queues, along with an implementation of an Async Executor built using work queues and triggered work to schedule the execution. Signed-off-by: David Brown --- submanifests/optional.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index 73fd9a1c7e4aa..b3d961d267034 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -60,7 +60,7 @@ manifest: groups: - optional - name: zephyr-lang-rust - revision: cf3dc6cb79631717464f1cd6b3fb122220f12915 + revision: 49c6712fe53b5b82e5c09e94548a4a51a021acfe path: modules/lang/rust remote: upstream groups: From d68763be42d3f92d95db77ae17fdf5999c91a81a Mon Sep 17 00:00:00 2001 From: Steffen Jahnke Date: Mon, 10 Feb 2025 13:24:12 +0000 Subject: [PATCH 0178/6055] boards: panasonic: Add PAN B511 Evaluation Board The PAN B511 evaluation board is a development tool for the nRF54L15 from Nordic Semiconductor. Signed-off-by: Steffen Jahnke --- boards/panasonic/panb511evb/Kconfig.defconfig | 9 + .../panasonic/panb511evb/Kconfig.panb511evb | 7 + boards/panasonic/panb511evb/board.cmake | 12 ++ boards/panasonic/panb511evb/board.yml | 9 + .../panb511evb/doc/img/panb511evb.webp | Bin 0 -> 46034 bytes boards/panasonic/panb511evb/doc/index.rst | 44 +++++ .../panb511evb_nrf54l15-pinctrl.dtsi | 78 ++++++++ .../panb511evb_nrf54l15_common.dtsi | 172 ++++++++++++++++++ .../panb511evb/panb511evb_nrf54l15_cpuapp.dts | 59 ++++++ .../panb511evb_nrf54l15_cpuapp.yaml | 23 +++ .../panb511evb_nrf54l15_cpuapp_common.dtsi | 122 +++++++++++++ .../panb511evb_nrf54l15_cpuapp_defconfig | 29 +++ .../panb511evb_nrf54l15_cpuflpr.dts | 71 ++++++++ .../panb511evb_nrf54l15_cpuflpr.yaml | 18 ++ .../panb511evb_nrf54l15_cpuflpr_defconfig | 17 ++ .../panb511evb_nrf54l15_cpuflpr_xip.dts | 12 ++ .../panb511evb_nrf54l15_cpuflpr_xip.yaml | 18 ++ .../panb511evb_nrf54l15_cpuflpr_xip_defconfig | 15 ++ .../support/nrf54l15_cpuflpr.JLinkScript | 5 + 19 files changed, 720 insertions(+) create mode 100644 boards/panasonic/panb511evb/Kconfig.defconfig create mode 100644 boards/panasonic/panb511evb/Kconfig.panb511evb create mode 100644 boards/panasonic/panb511evb/board.cmake create mode 100644 boards/panasonic/panb511evb/board.yml create mode 100644 boards/panasonic/panb511evb/doc/img/panb511evb.webp create mode 100644 boards/panasonic/panb511evb/doc/index.rst create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15-pinctrl.dtsi create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_common.dtsi create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp.dts create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp.yaml create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp_common.dtsi create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp_defconfig create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr.dts create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr.yaml create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_defconfig create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip.dts create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip.yaml create mode 100644 boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip_defconfig create mode 100644 boards/panasonic/panb511evb/support/nrf54l15_cpuflpr.JLinkScript diff --git a/boards/panasonic/panb511evb/Kconfig.defconfig b/boards/panasonic/panb511evb/Kconfig.defconfig new file mode 100644 index 0000000000000..03c84b8f538ee --- /dev/null +++ b/boards/panasonic/panb511evb/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_PANB511EVB_NRF54L15_CPUAPP + +config ROM_START_OFFSET + default 0x800 if BOOTLOADER_MCUBOOT + +endif # BOARD_PANB511EVB_NRF54L15_CPUAPP diff --git a/boards/panasonic/panb511evb/Kconfig.panb511evb b/boards/panasonic/panb511evb/Kconfig.panb511evb new file mode 100644 index 0000000000000..2454aba6270c1 --- /dev/null +++ b/boards/panasonic/panb511evb/Kconfig.panb511evb @@ -0,0 +1,7 @@ +# Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_PANB511EVB + select SOC_NRF54L15_CPUAPP if BOARD_PANB511EVB_NRF54L15_CPUAPP + select SOC_NRF54L15_CPUFLPR if BOARD_PANB511EVB_NRF54L15_CPUFLPR || \ + BOARD_PANB511EVB_NRF54L15_CPUFLPR_XIP diff --git a/boards/panasonic/panb511evb/board.cmake b/boards/panasonic/panb511evb/board.cmake new file mode 100644 index 0000000000000..3138d0b04d779 --- /dev/null +++ b/boards/panasonic/panb511evb/board.cmake @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_SOC_NRF54L15_CPUAPP) + board_runner_args(jlink "--device=nRF54L15_M33" "--speed=4000") +elseif(CONFIG_SOC_NRF54L15_CPUFLPR) + set(JLINKSCRIPTFILE ${CMAKE_CURRENT_LIST_DIR}/support/nrf54l15_cpuflpr.JLinkScript) + board_runner_args(jlink "--device=RISC-V" "--speed=4000" "-if SW" "--tool-opt=-jlinkscriptfile ${JLINKSCRIPTFILE}") +endif() + +include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/panasonic/panb511evb/board.yml b/boards/panasonic/panb511evb/board.yml new file mode 100644 index 0000000000000..a7e9a5901a4f5 --- /dev/null +++ b/boards/panasonic/panb511evb/board.yml @@ -0,0 +1,9 @@ +board: + name: panb511evb + full_name: PAN B511 Evaluation Board + vendor: panasonic + socs: + - name: nrf54l15 + variants: + - name: xip + cpucluster: cpuflpr diff --git a/boards/panasonic/panb511evb/doc/img/panb511evb.webp b/boards/panasonic/panb511evb/doc/img/panb511evb.webp new file mode 100644 index 0000000000000000000000000000000000000000..51748e65c8df5c6fb1bda339dedca79601f66e9d GIT binary patch literal 46034 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 OgE=Dpp?M(=y8Z|6v^O09 literal 0 HcmV?d00001 diff --git a/boards/panasonic/panb511evb/doc/index.rst b/boards/panasonic/panb511evb/doc/index.rst new file mode 100644 index 0000000000000..934f55fc7a20c --- /dev/null +++ b/boards/panasonic/panb511evb/doc/index.rst @@ -0,0 +1,44 @@ +.. zephyr:board:: panb511evb + +Overview +******** + +The PAN B511 Evaluation Board (panb511evb) is a development tool +for the PAN B511 module which is based on the nRF54L15 chipset +from Nordic Semiconductor. + +More information about the PAN B511 Module Variants and Evaluation Board can be found +on the `product website`_. + +Usage +***** + +You can find the `panb511evb user guide`_ for the PAN B511 Evaluation Board in the +`Panasonic Wireless Connectivity Development Hub`_. + +The User Guide contains (amongst other things) detailed information about + +* pin mapping +* powering options +* breakout pin header interface +* current consumption measurement +* software development + +and other things. + +The schematics for the PANB511 Evaluation Boards are available in the +`download section PANB511`_ of the `Panasonic Wireless Connectivity Development Hub`_. + +Programming and Debugging +************************* + +Applications for the ``panb511evb/nrf54l15/cpuapp`` board target can +be built, flashed, and debugged in the usual way. See +:ref:`build_an_application` and :ref:`application_run` for more details on +building and running. + +.. target-notes:: +.. _product website: https://industry.panasonic.eu/products/devices/wireless-connectivity/bluetooth-low-energy-modules +.. _Panasonic Wireless Connectivity Development Hub: https://pideu.panasonic.de/development-hub/ +.. _panb511evb user guide: https://pideu.panasonic.de/development-hub/panb511/evaluation_board/user_guide/ +.. _download section PANB511: https://pideu.panasonic.de/development-hub/panb511/downloads/ diff --git a/boards/panasonic/panb511evb/panb511evb_nrf54l15-pinctrl.dtsi b/boards/panasonic/panb511evb/panb511evb_nrf54l15-pinctrl.dtsi new file mode 100644 index 0000000000000..bc3a54459d978 --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15-pinctrl.dtsi @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH + * 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/panasonic/panb511evb/panb511evb_nrf54l15_common.dtsi b/boards/panasonic/panb511evb/panb511evb_nrf54l15_common.dtsi new file mode 100644 index 0000000000000..fc300f888b92a --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_common.dtsi @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "panb511evb_nrf54l15-pinctrl.dtsi" + +/ { + leds { + compatible = "gpio-leds"; + + evb_led1: evb_led_1 { + gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; + label = "LED1 on EVB"; + }; + + evb_led2: evb_led_2 { + gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + label = "LED2 on EVB"; + }; + + evb_led3: evb_led_3 { + gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + label = "LED3 on EVB"; + }; + + evb_led4: evb_led_4 { + gpios = <&gpio2 7 GPIO_ACTIVE_LOW>; + label = "LED4 on EVB"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + + /* + * PWM signal can be exposed on GPIO pin only within same domain. + * There is only one domain which contains both PWM and GPIO: + * PWM20/21/22 and GPIO Port P1. + * Only LEDs connected to P1 can work with PWM, for example LED1. + */ + pwm_evb_led1: pwm_evb_led_1 { + pwms = <&pwm20 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + + buttons { + compatible = "gpio-keys"; + + evb_sw1: evb_sw_1 { + gpios = <&gpio1 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW1 on EVB"; + zephyr,code = ; + }; + + evb_sw2: evb_sw_2 { + gpios = <&gpio1 12 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW2 on EVB"; + zephyr,code = ; + }; + + evb_sw3: evb_sw_3 { + gpios = <&gpio1 13 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW3 on EVB"; + zephyr,code = ; + }; + + evb_sw4: evb_sw_4 { + gpios = <&gpio1 14 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW4 on EVB"; + zephyr,code = ; + }; + }; + + mikrobus_header: mikrobus-connector { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio1 6 0>, /* AN */ + /* Not a GPIO*/ /* RST */ + <2 0 &gpio2 10 0>, /* CS */ + <3 0 &gpio2 6 0>, /* SCK */ + <4 0 &gpio2 9 0>, /* MISO */ + <5 0 &gpio2 8 0>, /* MOSI */ + /* +3.3V */ + /* GND */ + <6 0 &gpio1 15 0>, /* PWM */ + <7 0 &gpio2 7 0>, /* INT */ + <8 0 &gpio1 5 0>, /* RX */ + <9 0 &gpio1 4 0>, /* TX */ + <10 0 &gpio1 8 0>, /* SCL */ + <11 0 &gpio1 9 0>; /* SDA */ + /* +5V */ + /* GND */ + }; + + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio1 6 0>, /* A0 */ + <1 0 &gpio1 7 0>, /* A1 */ + <2 0 &gpio1 11 0>, /* A2 */ + <3 0 &gpio1 12 0>, /* A3 */ + <4 0 &gpio1 13 0>, /* A4 */ + <5 0 &gpio1 14 0>, /* A5 */ + <6 0 &gpio1 4 0>, /* D0 */ + <7 0 &gpio1 5 0>, /* D1 */ + <8 0 &gpio0 0 0>, /* D2 */ + <9 0 &gpio1 2 0>, /* D3 */ + <10 0 &gpio1 3 0>, /* D4 */ + <11 0 &gpio1 10 0>, /* D5 */ + <12 0 &gpio1 13 0>, /* D6 */ + <13 0 &gpio1 14 0>, /* D7 */ + <14 0 &gpio1 15 0>, /* D8 */ + <15 0 &gpio2 7 0>, /* D9 */ + <16 0 &gpio2 10 0>, /* D10 */ + <17 0 &gpio2 8 0>, /* D11 */ + <18 0 &gpio2 9 0>, /* D12 */ + <19 0 &gpio2 6 0>, /* D13 */ + <20 0 &gpio1 9 0>, /* D14 */ + <21 0 &gpio1 8 0>; /* D15 */ + }; + + arduino_adc: analog-connector { + compatible = "arduino,uno-adc"; + #io-channel-cells = <1>; + io-channel-map = <0 &adc 0>, /* A0 = P1.06 = AIN0 */ + <1 &adc 1>, /* A1 = P1.07 = AIN1 */ + <2 &adc 2>, /* A2 = P1.11 = AIN2 */ + <3 &adc 3>, /* A3 = P1.12 = AIN3 */ + <4 &adc 4>, /* A4 = P1.13 = AIN4 */ + <5 &adc 5>; /* A5 = P1.14 = AIN5 */ + }; + + aliases { + led0 = &evb_led1; + led1 = &evb_led2; + led2 = &evb_led3; + led3 = &evb_led4; + pwm-led0 = &pwm_evb_led1; + sw0 = &evb_sw1; + sw1 = &evb_sw2; + sw2 = &evb_sw3; + sw3 = &evb_sw4; + 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/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp.dts b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp.dts new file mode 100644 index 0000000000000..c79847a3b57b0 --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp.dts @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "panb511evb_nrf54l15_cpuapp_common.dtsi" + +/ { + compatible = "panasonic-industrial-devices-europe-gmbh,panb511evb-cpuapp"; + model = "Panasonic PAN B511 EVB nRF54L15 Application MCU"; + + chosen { + zephyr,code-partition = &slot0_partition; + zephyr,sram = &cpuapp_sram; + }; +}; + +&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)>; + }; + }; +}; diff --git a/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp.yaml b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp.yaml new file mode 100644 index 0000000000000..b30e5ffa106b4 --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +identifier: panb511evb/nrf54l15/cpuapp +name: PANB511-EVB-nRF54l15-Application +type: mcu +arch: arm +toolchain: + - gnuarmemb + - zephyr +sysbuild: true +ram: 188 +flash: 324 +supported: + - adc + - counter + - gpio + - i2c + - pwm + - retained_mem + - spi + - watchdog + - i2s diff --git a/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp_common.dtsi b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp_common.dtsi new file mode 100644 index 0000000000000..bf7922d8069eb --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp_common.dtsi @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This file is common to the secure and non-secure domain */ + +#include "panb511evb_nrf54l15_common.dtsi" + +/ { + chosen { + zephyr,console = &uart30; + zephyr,shell-uart = &uart30; + zephyr,uart-mcumgr = &uart30; + zephyr,bt-mon-uart = &uart30; + zephyr,bt-c2h-uart = &uart30; + zephyr,flash-controller = &rram_controller; + zephyr,flash = &cpuapp_rram; + zephyr,ieee802154 = &ieee802154; + }; +}; + +&cpuapp_sram { + status = "okay"; +}; + +&lfxo { + load-capacitors = "internal"; + load-capacitance-femtofarad = <15500>; +}; + +&hfxo { + load-capacitors = "internal"; + load-capacitance-femtofarad = <15000>; +}; + +®ulators { + status = "okay"; +}; + +&vregmain { + status = "okay"; + regulator-initial-mode = ; +}; + +&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"; +}; + +&uart30 { + status = "okay"; +}; + +&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 = "okay"; + 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/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp_defconfig b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp_defconfig new file mode 100644 index 0000000000000..41648ab5b23b0 --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuapp_defconfig @@ -0,0 +1,29 @@ +# Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH +# 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 MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# MPU-based null-pointer dereferencing detection cannot +# be applied as the (0x0 - 0x400) is unmapped for this target. +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + +# Enable Cache +CONFIG_CACHE_MANAGEMENT=y +CONFIG_EXTERNAL_CACHE=y + +# Start SYSCOUNTER on driver init +CONFIG_NRF_GRTC_START_SYSCOUNTER=y diff --git a/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr.dts b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr.dts new file mode 100644 index 0000000000000..5a238b48a6ba1 --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr.dts @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "panb511evb_nrf54l15_common.dtsi" + +/ { + model = "Panasonic PAN B511 EVB nRF54L15 FLPR MCU"; + compatible = "panasonic-industrial-devices-europe-gmbh,panb511evb-cpuflpr"; + + chosen { + zephyr,console = &uart20; + zephyr,shell-uart = &uart20; + 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"; +}; + +&uart20 { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpiote20 { + status = "okay"; +}; + +&gpiote30 { + status = "okay"; +}; diff --git a/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr.yaml b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr.yaml new file mode 100644 index 0000000000000..481fcb00bd05d --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +identifier: panb511evb/nrf54l15/cpuflpr +name: PANB511-EVB-nRF54L15-Fast-Lightweight-Peripheral-Processor +type: mcu +arch: riscv +toolchain: + - zephyr +sysbuild: true +ram: 96 +flash: 96 +supported: + - counter + - gpio + - i2c + - spi + - watchdog diff --git a/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_defconfig b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_defconfig new file mode 100644 index 0000000000000..35618b20a6e63 --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_defconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH +# 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/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip.dts b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip.dts new file mode 100644 index 0000000000000..f14f44e097597 --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip.dts @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "panb511evb_nrf54l15_cpuflpr.dts" + +&cpuflpr_sram { + reg = <0x2002f000 DT_SIZE_K(68)>; + ranges = <0x0 0x2002f000 0x11000>; +}; diff --git a/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip.yaml b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip.yaml new file mode 100644 index 0000000000000..e54c5a7b9fdd6 --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +identifier: panb511evb/nrf54l15/cpuflpr/xip +name: PANB511-EVB-nRF54L15-Fast-Lightweight-Peripheral-Processor (RRAM XIP) +type: mcu +arch: riscv +toolchain: + - zephyr +sysbuild: true +ram: 68 +flash: 96 +supported: + - counter + - gpio + - i2c + - spi + - watchdog diff --git a/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip_defconfig b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip_defconfig new file mode 100644 index 0000000000000..8f75855af3cd4 --- /dev/null +++ b/boards/panasonic/panb511evb/panb511evb_nrf54l15_cpuflpr_xip_defconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH +# 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/panasonic/panb511evb/support/nrf54l15_cpuflpr.JLinkScript b/boards/panasonic/panb511evb/support/nrf54l15_cpuflpr.JLinkScript new file mode 100644 index 0000000000000..1cf94ee52a4d0 --- /dev/null +++ b/boards/panasonic/panb511evb/support/nrf54l15_cpuflpr.JLinkScript @@ -0,0 +1,5 @@ +int InitTarget(void) { + // Base address where DMI registers can be found in the APB address space + JLINK_ExecCommand("CORESIGHT_SetCoreBaseAddr = 0x5004C400"); + return 0; +} From fa0ac7515191d0369a4d45a3bc3885a10bc92a77 Mon Sep 17 00:00:00 2001 From: Steffen Jahnke Date: Wed, 12 Feb 2025 07:26:05 +0000 Subject: [PATCH 0179/6055] samples: Add necessary configurations for PAN B511 EVB Running samples for PAN B511 evaluation board needs additional configuartion. Signed-off-by: Steffen Jahnke --- .../boards/panb511evb_nrf54l15_cpuapp.overlay | 12 +++++++ .../panb511evb_nrf54l15_cpuapp_df.overlay | 33 +++++++++++++++++++ samples/drivers/watchdog/sample.yaml | 3 ++ 3 files changed, 48 insertions(+) create mode 100644 samples/bluetooth/hci_uart/boards/panb511evb_nrf54l15_cpuapp.overlay create mode 100644 samples/bluetooth/hci_uart/boards/panb511evb_nrf54l15_cpuapp_df.overlay diff --git a/samples/bluetooth/hci_uart/boards/panb511evb_nrf54l15_cpuapp.overlay b/samples/bluetooth/hci_uart/boards/panb511evb_nrf54l15_cpuapp.overlay new file mode 100644 index 0000000000000..fde3e0775dd3b --- /dev/null +++ b/samples/bluetooth/hci_uart/boards/panb511evb_nrf54l15_cpuapp.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&uart30 { + compatible = "nordic,nrf-uarte"; + current-speed = <1000000>; + status = "okay"; + hw-flow-control; +}; diff --git a/samples/bluetooth/hci_uart/boards/panb511evb_nrf54l15_cpuapp_df.overlay b/samples/bluetooth/hci_uart/boards/panb511evb_nrf54l15_cpuapp_df.overlay new file mode 100644 index 0000000000000..0d2af26d4ed7b --- /dev/null +++ b/samples/bluetooth/hci_uart/boards/panb511evb_nrf54l15_cpuapp_df.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&uart30 { + compatible = "nordic,nrf-uarte"; + current-speed = <1000000>; + status = "okay"; + hw-flow-control; +}; + +&radio { + status = "okay"; + /* This is an example number of antennas that may be available + * on antenna matrix board. + */ + dfe-antenna-num = <10>; + /* This is an example switch pattern that will be used to set an + * antenna for Tx PDU (period before start of Tx CTE). + */ + dfe-pdu-antenna = <0x0>; + + /* These are example GPIO pin numbers that are provided to + * Radio peripheral. The pins will be acquired by Radio to + * drive antenna switching when AoD is enabled. + */ + dfegpio0-gpios = <&gpio1 4 0>; + dfegpio1-gpios = <&gpio1 5 0>; + dfegpio2-gpios = <&gpio1 6 0>; + dfegpio3-gpios = <&gpio1 7 0>; +}; diff --git a/samples/drivers/watchdog/sample.yaml b/samples/drivers/watchdog/sample.yaml index ce97a6f921319..504c952105316 100644 --- a/samples/drivers/watchdog/sample.yaml +++ b/samples/drivers/watchdog/sample.yaml @@ -22,6 +22,9 @@ tests: - s32z2xxdc2/s32z270/rtu1 - s32z2xxdc2@D/s32z270/rtu0 - s32z2xxdc2@D/s32z270/rtu1 + - panb511evb/nrf54l15/cpuapp + - panb511evb/nrf54l15/cpuflpr + - panb511evb/nrf54l15/cpuflpr/xip sample.drivers.watchdog.stm32_wwdg: extra_args: DTC_OVERLAY_FILE=boards/stm32_wwdg.overlay filter: dt_compat_enabled("st,stm32-window-watchdog") From 16c4b6a51aa71b670ad21a631972e3e86c4bfcc9 Mon Sep 17 00:00:00 2001 From: Steffen Jahnke Date: Wed, 12 Feb 2025 07:35:16 +0000 Subject: [PATCH 0180/6055] tests: Add necessary configurations for PAN B511 EVB Running tests for PAN B511 evaluation board needs additional configuartion. Signed-off-by: Steffen Jahnke --- .../boards/panb511evb_nrf54l15_cpuapp.conf | 24 +++++++++++++++++++ .../boards/panb511evb_nrf54l15_cpuapp.overlay | 18 ++++++++++++++ tests/drivers/adc/adc_api/testcase.yaml | 1 + .../watchdog/wdt_basic_api/testcase.yaml | 3 +++ 4 files changed, 46 insertions(+) create mode 100644 tests/bluetooth/tester/boards/panb511evb_nrf54l15_cpuapp.conf create mode 100644 tests/bluetooth/tester/boards/panb511evb_nrf54l15_cpuapp.overlay diff --git a/tests/bluetooth/tester/boards/panb511evb_nrf54l15_cpuapp.conf b/tests/bluetooth/tester/boards/panb511evb_nrf54l15_cpuapp.conf new file mode 100644 index 0000000000000..5bb1c4d82846e --- /dev/null +++ b/tests/bluetooth/tester/boards/panb511evb_nrf54l15_cpuapp.conf @@ -0,0 +1,24 @@ +# CONFIG_TEST enforces minimal logging, which we don't want +CONFIG_TEST=n + +CONFIG_ASSERT=y +# Enable the option below to measure stack usage +#CONFIG_INIT_STACKS=y +CONFIG_THREAD_NAME=y +CONFIG_HW_STACK_PROTECTION=y + +CONFIG_LOG=y +CONFIG_LOG_BUFFER_SIZE=4096 +CONFIG_RTT_CONSOLE=y +CONFIG_LOG_BACKEND_RTT=y +CONFIG_LOG_BACKEND_RTT_MODE_DROP=y +CONFIG_LOG_BACKEND_RTT_MESSAGE_SIZE=256 +CONFIG_USE_SEGGER_RTT=y +CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096 +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=1024 + +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_BTTESTER_LOG_LEVEL_DBG=y + +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/tests/bluetooth/tester/boards/panb511evb_nrf54l15_cpuapp.overlay b/tests/bluetooth/tester/boards/panb511evb_nrf54l15_cpuapp.overlay new file mode 100644 index 0000000000000..a179dd8306fec --- /dev/null +++ b/tests/bluetooth/tester/boards/panb511evb_nrf54l15_cpuapp.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,uart-pipe = &uart30; + }; +}; + +&uart30 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + status = "okay"; + hw-flow-control; +}; diff --git a/tests/drivers/adc/adc_api/testcase.yaml b/tests/drivers/adc/adc_api/testcase.yaml index b66fcf2dee3cb..9a19bf0fceaad 100644 --- a/tests/drivers/adc/adc_api/testcase.yaml +++ b/tests/drivers/adc/adc_api/testcase.yaml @@ -9,6 +9,7 @@ tests: min_flash: 40 platform_exclude: - nucleo_u031r8 + - panb511evb/nrf54l15/cpuapp drivers.adc.b_u585i_iot02a_adc4: extra_args: - DTC_OVERLAY_FILE="boards/b_u585i_iot02a_adc4.overlay" diff --git a/tests/drivers/watchdog/wdt_basic_api/testcase.yaml b/tests/drivers/watchdog/wdt_basic_api/testcase.yaml index b1d05417cea67..a7d3a6f68cd4a 100644 --- a/tests/drivers/watchdog/wdt_basic_api/testcase.yaml +++ b/tests/drivers/watchdog/wdt_basic_api/testcase.yaml @@ -20,6 +20,9 @@ tests: - mps2/an383 - mps2/an386 - mps2/an500 + - panb511evb/nrf54l15/cpuapp + - panb511evb/nrf54l15/cpuflpr + - panb511evb/nrf54l15/cpuflpr/xip drivers.watchdog.stm32wwdg: filter: dt_compat_enabled("st,stm32-window-watchdog") or dt_compat_enabled("st,stm32-watchdog") extra_args: DTC_OVERLAY_FILE="boards/stm32_wwdg.overlay" From b7bbfbf1f2a23b21f4b62f6dbd8b0ba0a4dbe5e9 Mon Sep 17 00:00:00 2001 From: Helge Juul Date: Wed, 12 Feb 2025 09:02:40 +0100 Subject: [PATCH 0181/6055] net: dns: Log with debug level instead of error level when recv fails This condition can happen if there is MDNS activity on the network that is either not according to specifications or not supported by Zephyr. Lowering the log level from ERR to DBG, since this does not indicate an error in the Zephyr application. Signed-off-by: Helge Juul --- subsys/net/lib/dns/dispatcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/dns/dispatcher.c b/subsys/net/lib/dns/dispatcher.c index a3b11a594c9c7..a296adcb69882 100644 --- a/subsys/net/lib/dns/dispatcher.c +++ b/subsys/net/lib/dns/dispatcher.c @@ -190,7 +190,7 @@ void dns_dispatcher_svc_handler(struct net_socket_service_event *pev) ret = recv_data(pev); if (ret < 0 && ret != DNS_EAI_ALLDONE && ret != -ENOENT) { - NET_ERR("DNS recv error (%d)", ret); + NET_DBG("DNS recv error (%d)", ret); } } From e7fb3c68480a6c9de23861d7babd95d121d81208 Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Wed, 12 Feb 2025 16:54:43 +0100 Subject: [PATCH 0182/6055] drivers: gpio: davinci: Select PINCTRL This driver includes pin-muxing functions and requires to have CONFIG_PINCTRL enabled. Automatically set this config when this driver is enabled. Signed-off-by: Daniel Schultz --- drivers/gpio/Kconfig.davinci | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/Kconfig.davinci b/drivers/gpio/Kconfig.davinci index 2bd94cade4382..b7de108de7141 100644 --- a/drivers/gpio/Kconfig.davinci +++ b/drivers/gpio/Kconfig.davinci @@ -7,5 +7,6 @@ config GPIO_DAVINCI bool "Davinci GPIO Driver" default y depends on DT_HAS_TI_DAVINCI_GPIO_ENABLED + select PINCTRL help Enable the Davinci GPIO controller support. From 8cdee9fe519d34e9da6853f3bb5c148039d16301 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 19 Nov 2024 08:36:45 +0100 Subject: [PATCH 0183/6055] dts: bindings: adc: add adc bindings for stm32n6 STM32N6 ADC doesn't have an integrated prescaler, so these properties have to be removed. Though the F1 compatible also removes these two same properties, grouping the N6 with the F1 would not be convenient since there are lots of differences between the two. Signed-off-by: Guillaume Gautier --- dts/bindings/adc/st,stm32n6-adc.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 dts/bindings/adc/st,stm32n6-adc.yaml diff --git a/dts/bindings/adc/st,stm32n6-adc.yaml b/dts/bindings/adc/st,stm32n6-adc.yaml new file mode 100644 index 0000000000000..dd791bdcc6729 --- /dev/null +++ b/dts/bindings/adc/st,stm32n6-adc.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 STMicroelectronics + +# SPDX-License-Identifier: Apache-2.0 + +description: | + ST STM32N6 ADC + This compatible stands for STM32N6 ADC. + +compatible: "st,stm32n6-adc" + +include: + - name: st,stm32-adc.yaml + property-blocklist: + - st,adc-clock-source + - st,adc-prescaler From 9ee33e990eddbcf463d158969c98ebb57945124b Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 20 Nov 2024 09:02:40 +0100 Subject: [PATCH 0184/6055] drivers: adc: stm32: add support for stm32n6 adc Add support for STM32N6 ADC in the STM32 ADC driver. Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 101 ++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 15 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 1e246668bb6bf..24723ec975159 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -23,7 +23,8 @@ #include #include #include -#if defined(CONFIG_SOC_SERIES_STM32U5X) +#if defined(CONFIG_SOC_SERIES_STM32N6X) || \ + defined(CONFIG_SOC_SERIES_STM32U5X) #include #endif /* CONFIG_SOC_SERIES_STM32U5X */ @@ -196,7 +197,9 @@ static void adc_stm32_enable_dma_support(ADC_TypeDef *adc) /* Allow ADC to create DMA request and set to one-shot mode as implemented in HAL drivers */ #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_UNLIMITED); -#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32U5X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) || \ + defined(CONFIG_SOC_SERIES_STM32N6X) || \ + defined(CONFIG_SOC_SERIES_STM32U5X) /* H72x ADC3 and U5 ADC4 are different from the rest, but this call works also for them, * so no need to call their specific function */ @@ -469,6 +472,41 @@ static void adc_stm32_calibration_delay(const struct device *dev) } } +#if defined(CONFIG_SOC_SERIES_STM32N6X) +/* Number of ADC measurement during calibration procedure */ +#define ADC_CALIBRATION_STEPS (8U) + +static void adc_stm32_calibration_measure(ADC_TypeDef *adc, uint32_t *calibration_factor) +{ + uint32_t calib_step; + uint32_t calib_factor_avg = 0; + uint8_t done = 0; + + do { + for (calib_step = 0; calib_step < ADC_CALIBRATION_STEPS; calib_step++) { + LL_ADC_REG_StartConversion(adc); + while (LL_ADC_REG_IsConversionOngoing(adc) != 0UL) { + } + + calib_factor_avg += LL_ADC_REG_ReadConversionData32(adc); + } + + /* Compute the average data */ + calib_factor_avg /= ADC_CALIBRATION_STEPS; + + if ((calib_factor_avg == 0) && (LL_ADC_IsCalibrationOffsetEnabled(adc) == 0UL)) { + /* If average is 0 and offset is disabled + * set offset and repeat measurements + */ + LL_ADC_EnableCalibrationOffset(adc); + } else { + *calibration_factor = (uint32_t)(calib_factor_avg); + done = 1; + } + } while (done == 0); +} +#endif + static void adc_stm32_calibration_start(const struct device *dev) { const struct adc_stm32_cfg *config = @@ -517,6 +555,17 @@ static void adc_stm32_calibration_start(const struct device *dev) LL_ADC_StartCalibration(adc, LL_ADC_CALIB_OFFSET); #elif defined(CONFIG_SOC_SERIES_STM32H7X) LL_ADC_StartCalibration(adc, LL_ADC_CALIB_OFFSET, LL_ADC_SINGLE_ENDED); +#elif defined(CONFIG_SOC_SERIES_STM32N6X) + uint32_t calibration_factor; + /* Start ADC calibration */ + LL_ADC_StartCalibration(adc, LL_ADC_SINGLE_ENDED); + /* Disable additional offset before calibration start */ + LL_ADC_DisableCalibrationOffset(adc); + + adc_stm32_calibration_measure(adc, &calibration_factor); + + LL_ADC_SetCalibrationFactor(adc, LL_ADC_SINGLE_ENDED, calibration_factor); + LL_ADC_StopCalibration(adc); #endif /* Make sure ADCAL is cleared before returning for proper operations * on the ADC control register, for enabling the peripheral for example @@ -551,7 +600,8 @@ static int adc_stm32_calibrate(const struct device *dev) #endif /* CONFIG_SOC_SERIES_* */ #endif /* CONFIG_ADC_STM32_DMA */ -#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) +#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ + !defined(CONFIG_SOC_SERIES_STM32N6X) adc_stm32_disable(adc); adc_stm32_calibration_start(dev); adc_stm32_calibration_delay(dev); @@ -562,7 +612,8 @@ static int adc_stm32_calibrate(const struct device *dev) return err; } -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) || \ + defined(CONFIG_SOC_SERIES_STM32N6X) adc_stm32_calibration_delay(dev); adc_stm32_calibration_start(dev); #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ @@ -868,7 +919,9 @@ static int set_sequencer(const struct device *dev) #if ANY_ADC_SEQUENCER_TYPE_IS(FULLY_CONFIGURABLE) if (config->sequencer_type == FULLY_CONFIGURABLE) { -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32U5X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || \ + defined(CONFIG_SOC_SERIES_STM32N6X) || \ + defined(CONFIG_SOC_SERIES_STM32U5X) /* * Each channel in the sequence must be previously enabled in PCSEL. * This register controls the analog switch integrated in the IO level. @@ -1451,6 +1504,7 @@ static int adc_stm32_set_clock(const struct device *dev) } } +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source) #if defined(CONFIG_SOC_SERIES_STM32F0X) LL_ADC_SetClock(adc, config->clk_prescaler); #elif defined(ADC_STM32_HAS_INDIVIDUAL_CLOCKS) @@ -1461,7 +1515,7 @@ static int adc_stm32_set_clock(const struct device *dev) config->clk_prescaler); LL_ADC_SetClock(adc, LL_ADC_CLOCK_ASYNC); } -#elif !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) +#else LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(adc), config->clk_prescaler); @@ -1470,6 +1524,7 @@ static int adc_stm32_set_clock(const struct device *dev) ret = adc_stm32h7_setup_boost(config, adc, clk); #endif #endif +#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source) */ return ret; } @@ -1522,7 +1577,10 @@ static int adc_stm32_init(const struct device *dev) #if defined(CONFIG_SOC_SERIES_STM32U5X) /* Enable the independent analog supply */ LL_PWR_EnableVDDA(); -#endif /* CONFIG_SOC_SERIES_STM32U5X */ +#elif defined(CONFIG_SOC_SERIES_STM32N6X) + /* Enable the independent analog supply */ + LL_PWR_EnableVddADC(); +#endif /* CONFIG_SOC_SERIES_STM32N6X */ #ifdef CONFIG_ADC_STM32_DMA if ((data->dma.dma_dev != NULL) && @@ -1539,6 +1597,7 @@ static int adc_stm32_init(const struct device *dev) defined(CONFIG_SOC_SERIES_STM32H5X) || \ defined(CONFIG_SOC_SERIES_STM32H7X) || \ defined(CONFIG_SOC_SERIES_STM32H7RSX) || \ + defined(CONFIG_SOC_SERIES_STM32N6X) || \ defined(CONFIG_SOC_SERIES_STM32U5X) /* * L4, WB, G4, H5, H7 and U5 series STM32 needs to be awaken from deep sleep @@ -1554,7 +1613,8 @@ static int adc_stm32_init(const struct device *dev) */ #if !defined(CONFIG_SOC_SERIES_STM32F0X) && \ !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) && \ + !defined(CONFIG_SOC_SERIES_STM32N6X) LL_ADC_EnableInternalRegulator(adc); /* Wait for Internal regulator stabilisation * Some series have a dedicated status bit, others relie on a delay @@ -1604,7 +1664,8 @@ static int adc_stm32_suspend_setup(const struct device *dev) #if !defined(CONFIG_SOC_SERIES_STM32F0X) && \ !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) && \ + !defined(CONFIG_SOC_SERIES_STM32N6X) /* Disable ADC internal voltage regulator */ LL_ADC_DisableInternalRegulator(adc); while (LL_ADC_IsInternalRegulatorEnabled(adc) == 1U) { @@ -1618,6 +1679,7 @@ static int adc_stm32_suspend_setup(const struct device *dev) defined(CONFIG_SOC_SERIES_STM32H5X) || \ defined(CONFIG_SOC_SERIES_STM32H7X) || \ defined(CONFIG_SOC_SERIES_STM32H7RSX) || \ + defined(CONFIG_SOC_SERIES_STM32N6X) || \ defined(CONFIG_SOC_SERIES_STM32U5X) /* * L4, WB, G4, H5, H7 and U5 series STM32 needs to be put into @@ -1630,7 +1692,10 @@ static int adc_stm32_suspend_setup(const struct device *dev) #if defined(CONFIG_SOC_SERIES_STM32U5X) /* Disable the independent analog supply */ LL_PWR_DisableVDDA(); -#endif /* CONFIG_SOC_SERIES_STM32U5X */ +#elif defined(CONFIG_SOC_SERIES_STM32N6X) + /* Disable the independent analog supply */ + LL_PWR_DisableVddADC(); +#endif /* CONFIG_SOC_SERIES_STM32N6X */ /* Stop device clock. Note: fixed clocks are not handled yet. */ err = clock_control_off(clk, (clock_control_subsys_t)&config->pclken[0]); @@ -1680,6 +1745,9 @@ static DEVICE_API(adc, api_stm32_driver_api) = { .ref_internal = STM32_ADC_VREF_MV, /* VREF is usually connected to VDD */ }; +/* Macros for ADC clock source and prescaler */ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source) + #if defined(CONFIG_SOC_SERIES_STM32F0X) /* LL_ADC_CLOCK_ASYNC_DIV1 doesn't exist in F0 LL. Define it here. */ #define LL_ADC_CLOCK_ASYNC_DIV1 LL_ADC_CLOCK_ASYNC @@ -1696,17 +1764,20 @@ static DEVICE_API(adc, api_stm32_driver_api) = { (LL_ADC_CLOCK_ASYNC_DIV)) /* Concat prefix (1st element) and DIV value (2nd element) of st,adc-prescaler */ -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) -#define ADC_STM32_DT_PRESC(x) 0 -#define ADC_STM32_CHECK_DT_CLOCK(x) -#else #define ADC_STM32_DT_PRESC(x) \ _CONCAT(ADC_STM32_CLOCK_PREFIX(x), ADC_STM32_DIV(x)) + /* Macro to check if the ADC instance clock setup is correct */ #define ADC_STM32_CHECK_DT_CLOCK(x) \ BUILD_ASSERT(IS_EQ(ADC_STM32_CLOCK(x), SYNC) || (DT_INST_NUM_CLOCKS(x) > 1), \ "ASYNC clock mode defined without ASYNC clock defined in device tree") -#endif + +#else /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source) */ + +#define ADC_STM32_DT_PRESC(x) 0 +#define ADC_STM32_CHECK_DT_CLOCK(x) + +#endif /* !DT_ANY_INST_HAS_PROP_STATUS_OKAY(st_adc_clock_source) */ #if defined(CONFIG_ADC_STM32_DMA) From a28381f459aa970a8a540254468640078835c505 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Mon, 9 Dec 2024 12:13:20 +0100 Subject: [PATCH 0185/6055] drivers: adc: stm32: enable analog supply in dedicated function Move code to enable the analog supply in a dedicated function. Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 24723ec975159..364011568ea67 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -1529,6 +1529,26 @@ static int adc_stm32_set_clock(const struct device *dev) return ret; } +static void adc_stm32_enable_analog_supply(void) +{ +#if defined(CONFIG_SOC_SERIES_STM32N6X) + LL_PWR_EnableVddADC(); +#elif defined(CONFIG_SOC_SERIES_STM32U5X) + LL_PWR_EnableVDDA(); +#endif /* CONFIG_SOC_SERIES_STM32U5X */ +} + +#ifdef CONFIG_PM_DEVICE +static void adc_stm32_disable_analog_supply(void) +{ +#if defined(CONFIG_SOC_SERIES_STM32N6X) + LL_PWR_DisableVddADC(); +#elif defined(CONFIG_SOC_SERIES_STM32U5X) + LL_PWR_DisableVDDA(); +#endif /* CONFIG_SOC_SERIES_STM32U5X */ +} +#endif + static int adc_stm32_init(const struct device *dev) { struct adc_stm32_data *data = dev->data; @@ -1574,13 +1594,7 @@ static int adc_stm32_init(const struct device *dev) return err; } -#if defined(CONFIG_SOC_SERIES_STM32U5X) - /* Enable the independent analog supply */ - LL_PWR_EnableVDDA(); -#elif defined(CONFIG_SOC_SERIES_STM32N6X) - /* Enable the independent analog supply */ - LL_PWR_EnableVddADC(); -#endif /* CONFIG_SOC_SERIES_STM32N6X */ + adc_stm32_enable_analog_supply(); #ifdef CONFIG_ADC_STM32_DMA if ((data->dma.dma_dev != NULL) && @@ -1689,13 +1703,7 @@ static int adc_stm32_suspend_setup(const struct device *dev) LL_ADC_EnableDeepPowerDown(adc); #endif -#if defined(CONFIG_SOC_SERIES_STM32U5X) - /* Disable the independent analog supply */ - LL_PWR_DisableVDDA(); -#elif defined(CONFIG_SOC_SERIES_STM32N6X) - /* Disable the independent analog supply */ - LL_PWR_DisableVddADC(); -#endif /* CONFIG_SOC_SERIES_STM32N6X */ + adc_stm32_disable_analog_supply(); /* Stop device clock. Note: fixed clocks are not handled yet. */ err = clock_control_off(clk, (clock_control_subsys_t)&config->pclken[0]); From a0761d6353f80f786034f819e009859599b8656b Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 29 Nov 2024 09:02:29 +0100 Subject: [PATCH 0186/6055] drivers: adc: stm32: configure data size for stm32n6 On STM32N6, the register holding the data is 32 bits and DMA must operate in word transfer to work properly. So we change the type of the buffer in which we store the ADC data from uint16_t to uint32_t for N6. Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 364011568ea67..54a076c897d1a 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -158,11 +158,17 @@ struct stream { }; #endif /* CONFIG_ADC_STM32_DMA */ +#if defined(CONFIG_SOC_SERIES_STM32N6X) +typedef uint32_t adc_data_size_t; +#else +typedef uint16_t adc_data_size_t; +#endif + struct adc_stm32_data { struct adc_context ctx; const struct device *dev; - uint16_t *buffer; - uint16_t *repeat_buffer; + adc_data_size_t *buffer; + adc_data_size_t *repeat_buffer; uint8_t resolution; uint32_t channels; @@ -224,7 +230,7 @@ static int adc_stm32_dma_start(const struct device *dev, blk_cfg = &dma->dma_blk_cfg; /* prepare the block */ - blk_cfg->block_size = channel_count * sizeof(int16_t); + blk_cfg->block_size = channel_count * sizeof(adc_data_size_t); /* Source and destination */ blk_cfg->source_address = (uint32_t)LL_ADC_DMA_GetRegAddr(adc, LL_ADC_DMA_REG_REGULAR_DATA); @@ -299,7 +305,7 @@ static int check_buffer(const struct adc_sequence *sequence, { size_t needed_buffer_size; - needed_buffer_size = active_channels * sizeof(uint16_t); + needed_buffer_size = active_channels * sizeof(adc_data_size_t); if (sequence->options) { needed_buffer_size *= (1 + sequence->options->extra_samplings); From 20d1b6c6c7172c52473633db74a86f78452196df Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 11 Feb 2025 10:54:20 +0100 Subject: [PATCH 0187/6055] dts: arm: st: n6: add adc node to stm32n6 dtsi Add ADC1 and ADC2 to STM32N6 device tree. Signed-off-by: Guillaume Gautier --- dts/arm/st/n6/stm32n6.dtsi | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/dts/arm/st/n6/stm32n6.dtsi b/dts/arm/st/n6/stm32n6.dtsi index a2230d632bd52..cfb149b2a87c5 100644 --- a/dts/arm/st/n6/stm32n6.dtsi +++ b/dts/arm/st/n6/stm32n6.dtsi @@ -5,6 +5,8 @@ */ #include +#include +#include #include #include #include @@ -363,6 +365,38 @@ }; }; + adc1: adc@50022000 { + compatible = "st,stm32n6-adc", "st,stm32-adc"; + reg = <0x50022000 0x400>; + clocks = <&rcc STM32_CLOCK(AHB1, 5)>; + interrupts = <46 0>; + status = "disabled"; + #io-channel-cells = <1>; + resolutions = ; + sampling-times = <2 3 7 12 14 47 247 1500>; + st,adc-sequencer = "FULLY_CONFIGURABLE"; + st,adc-oversampler = "OVERSAMPLER_EXTENDED"; + }; + + adc2: adc@50022100 { + compatible = "st,stm32n6-adc", "st,stm32-adc"; + reg = <0x50022100 0x300>; + clocks = <&rcc STM32_CLOCK(AHB1, 5)>; + interrupts = <46 0>; + status = "disabled"; + #io-channel-cells = <1>; + resolutions = ; + sampling-times = <2 3 7 12 14 47 247 1500>; + st,adc-sequencer = "FULLY_CONFIGURABLE"; + st,adc-oversampler = "OVERSAMPLER_EXTENDED"; + }; + fdcan1: can@5000a000 { compatible = "st,stm32h7-fdcan"; reg = <0x5000A000 0x400>, <0x5000C000 0xd54>; From e7ca08525e50ba0369779fda4dd94985ef83a5fe Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 11 Feb 2025 11:05:50 +0100 Subject: [PATCH 0188/6055] boards: st: stm32n6: enable adc node for stm32n6 board Enable ADC for STM32N6570-DK and Nucleo N657X0 boards. Signed-off-by: Guillaume Gautier --- boards/st/nucleo_n657x0_q/doc/index.rst | 4 ++++ boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi | 9 +++++++++ boards/st/nucleo_n657x0_q/twister.yaml | 1 + boards/st/stm32n6570_dk/doc/index.rst | 4 ++++ boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi | 9 +++++++++ boards/st/stm32n6570_dk/twister.yaml | 1 + 6 files changed, 28 insertions(+) diff --git a/boards/st/nucleo_n657x0_q/doc/index.rst b/boards/st/nucleo_n657x0_q/doc/index.rst index d0e38a33dbccb..48f72c300a489 100644 --- a/boards/st/nucleo_n657x0_q/doc/index.rst +++ b/boards/st/nucleo_n657x0_q/doc/index.rst @@ -65,6 +65,8 @@ The Zephyr ``nucleo_n657x0_q`` board supports the following hardware features: +-----------+------------+-------------------------------------+ | Interface | Controller | Driver/Component | +===========+============+=====================================+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ | CLOCK | on-chip | reset and clock control | +-----------+------------+-------------------------------------+ | CAN/CANFD | on-chip | canbus | @@ -99,6 +101,8 @@ For more details please refer to `NUCLEO-N657X0-Q User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- +- ADC1_INP10 : PA9 +- ADC1_INP11 : PA10 - FDCAN1_TX : PH2 - FDCAN1_RX : PD0 - I2C1_SCL : PH9 diff --git a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi index 08f5b5b308d60..3812a1381919f 100644 --- a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi +++ b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi @@ -112,6 +112,15 @@ apb5-prescaler = <1>; }; +&adc1 { + clocks = <&rcc STM32_CLOCK(AHB1, 5)>, + <&rcc STM32_SRC_CKPER ADC12_SEL(1)>; + pinctrl-0 = <&adc1_inp10_pa9 &adc1_inp11_pa10>; /* Arduino A1 & A2 */ + pinctrl-names = "default"; + vref-mv = <1800>; + status = "okay"; +}; + &fdcan1 { clocks = <&rcc STM32_CLOCK(APB1_2, 8)>, <&rcc STM32_SRC_CKPER FDCAN_SEL(1)>; diff --git a/boards/st/nucleo_n657x0_q/twister.yaml b/boards/st/nucleo_n657x0_q/twister.yaml index df264f33da838..69589f57de6c3 100644 --- a/boards/st/nucleo_n657x0_q/twister.yaml +++ b/boards/st/nucleo_n657x0_q/twister.yaml @@ -6,6 +6,7 @@ flash: 1024 supported: - arduino_i2c - arduino_serial + - adc - can - dma - i2c diff --git a/boards/st/stm32n6570_dk/doc/index.rst b/boards/st/stm32n6570_dk/doc/index.rst index ab2d5116d7f4f..b754a20bdbdb0 100644 --- a/boards/st/stm32n6570_dk/doc/index.rst +++ b/boards/st/stm32n6570_dk/doc/index.rst @@ -69,6 +69,8 @@ The Zephyr ``stm32n6570_dk`` board supports the following hardware features: +-----------+------------+-------------------------------------+ | Interface | Controller | Driver/Component | +===========+============+=====================================+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ | CLOCK | on-chip | reset and clock control | +-----------+------------+-------------------------------------+ | CAN/CANFD | on-chip | canbus | @@ -103,6 +105,8 @@ For more details please refer to `STM32N6570_DK User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- +- ADC1_INP10 : PA9 +- ADC1_INP11 : PA10 - FDCAN1_TX : PH2 - FDCAN1_RX : PD0 - I2C1_SCL : PH9 diff --git a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi index 1ddfb2068b2d6..02e5d5c33925a 100644 --- a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi +++ b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi @@ -96,6 +96,15 @@ apb5-prescaler = <1>; }; +&adc1 { + clocks = <&rcc STM32_CLOCK(AHB1, 5)>, + <&rcc STM32_SRC_CKPER ADC12_SEL(1)>; + pinctrl-0 = <&adc1_inp10_pa9 &adc1_inp11_pa10>; /* Arduino A1 & A2 */ + pinctrl-names = "default"; + vref-mv = <1800>; + status = "okay"; +}; + &fdcan1 { clocks = <&rcc STM32_CLOCK(APB1_2, 8)>, <&rcc STM32_SRC_CKPER FDCAN_SEL(1)>; diff --git a/boards/st/stm32n6570_dk/twister.yaml b/boards/st/stm32n6570_dk/twister.yaml index 784b7f1629e2f..82cf091e74986 100644 --- a/boards/st/stm32n6570_dk/twister.yaml +++ b/boards/st/stm32n6570_dk/twister.yaml @@ -7,6 +7,7 @@ vendor: st supported: - arduino_i2c - arduino_serial + - adc - can - dma - i2c From ed673d5e887e42dd60923e55b148ebd3553455ad Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 29 Nov 2024 09:07:18 +0100 Subject: [PATCH 0189/6055] tests: drivers: adc: adc_api: src: change data size for stm32n6 STM32N6 needs to have a buffer of 32-bit data instead of 16-bit. Adds a Kconfig to select whether the test shall use a 32-bit buffer. Signed-off-by: Guillaume Gautier --- tests/drivers/adc/adc_api/Kconfig | 3 +++ tests/drivers/adc/adc_api/src/test_adc.c | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/drivers/adc/adc_api/Kconfig b/tests/drivers/adc/adc_api/Kconfig index 5807a1c155f06..f4748c6d3805e 100644 --- a/tests/drivers/adc/adc_api/Kconfig +++ b/tests/drivers/adc/adc_api/Kconfig @@ -10,3 +10,6 @@ source "Kconfig.zephyr" config ADC_API_SAMPLE_INTERVAL_US int "Interval between repeatead samples in us" default 0 + +config ADC_32_BITS_DATA + bool "ADC data is 32-bits long" diff --git a/tests/drivers/adc/adc_api/src/test_adc.c b/tests/drivers/adc/adc_api/src/test_adc.c index e7d1958cd5a2b..49af36dc0d4c5 100644 --- a/tests/drivers/adc/adc_api/src/test_adc.c +++ b/tests/drivers/adc/adc_api/src/test_adc.c @@ -12,6 +12,13 @@ #include #include +#if CONFIG_ADC_32_BITS_DATA +typedef int32_t adc_data_size_t; +#define INVALID_ADC_VALUE INT_MIN +#else +typedef int16_t adc_data_size_t; +#endif + /* Invalid value that is not supposed to be written by the driver. It is used * to mark the sample buffer entries as empty. If needed, it can be overridden * for a particular board by providing a specific definition above. @@ -28,9 +35,9 @@ #define BUFFER_SIZE 6 #ifdef CONFIG_TEST_USERSPACE -static ZTEST_BMEM int16_t m_sample_buffer[BUFFER_SIZE]; +static ZTEST_BMEM adc_data_size_t m_sample_buffer[BUFFER_SIZE]; #else -static __aligned(32) int16_t m_sample_buffer[BUFFER_SIZE] __NOCACHE; +static __aligned(32) adc_data_size_t m_sample_buffer[BUFFER_SIZE] __NOCACHE; #endif #define DT_SPEC_AND_COMMA(node_id, prop, idx) ADC_DT_SPEC_GET_BY_IDX(node_id, idx), @@ -102,9 +109,13 @@ static void check_samples(int expected_count) TC_PRINT("Samples read: "); for (i = 0; i < BUFFER_SIZE; i++) { - int16_t sample_value = m_sample_buffer[i]; + adc_data_size_t sample_value = m_sample_buffer[i]; +#if CONFIG_ADC_32_BITS_DATA + TC_PRINT("0x%08x ", sample_value); +#else TC_PRINT("0x%04hx ", sample_value); +#endif if (i < expected_count) { zassert_not_equal(INVALID_ADC_VALUE, sample_value, "[%u] should be filled", i); From 5155cb673f0203e671e63db6dc93e4c15c501642 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 20 Nov 2024 09:13:34 +0100 Subject: [PATCH 0190/6055] tests: drivers: adc: adc_api: boards: add overlays for stm32n6 boards Add dts and conf overlay for nucleo_n657x0 and stm32n6570_dk boards. Signed-off-by: Guillaume Gautier --- .../adc/adc_api/boards/nucleo_n657x0_sb.conf | 3 ++ .../adc_api/boards/nucleo_n657x0_sb.overlay | 40 +++++++++++++++++++ .../adc/adc_api/boards/stm32n6570_dk_sb.conf | 3 ++ .../adc_api/boards/stm32n6570_dk_sb.overlay | 40 +++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_n657x0_sb.conf create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_n657x0_sb.overlay create mode 100644 tests/drivers/adc/adc_api/boards/stm32n6570_dk_sb.conf create mode 100644 tests/drivers/adc/adc_api/boards/stm32n6570_dk_sb.overlay diff --git a/tests/drivers/adc/adc_api/boards/nucleo_n657x0_sb.conf b/tests/drivers/adc/adc_api/boards/nucleo_n657x0_sb.conf new file mode 100644 index 0000000000000..22b66784845b2 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_n657x0_sb.conf @@ -0,0 +1,3 @@ +# USERSPACE not functional on N6 yet +CONFIG_TEST_USERSPACE=n +CONFIG_ADC_32_BITS_DATA=y diff --git a/tests/drivers/adc/adc_api/boards/nucleo_n657x0_sb.overlay b/tests/drivers/adc/adc_api/boards/nucleo_n657x0_sb.overlay new file mode 100644 index 0000000000000..a009c76274492 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_n657x0_sb.overlay @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 10>, <&adc1 11>; + }; +}; + +&adc1 { + dmas = <&gpdma1 0 7 (STM32_DMA_PERIPH_RX | STM32_DMA_MEM_32BITS | STM32_DMA_PERIPH_32BITS)>; + dma-names = "gpdma"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@a { + reg = <10>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@b { + reg = <11>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + +&gpdma1 { + status = "okay"; +}; diff --git a/tests/drivers/adc/adc_api/boards/stm32n6570_dk_sb.conf b/tests/drivers/adc/adc_api/boards/stm32n6570_dk_sb.conf new file mode 100644 index 0000000000000..22b66784845b2 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/stm32n6570_dk_sb.conf @@ -0,0 +1,3 @@ +# USERSPACE not functional on N6 yet +CONFIG_TEST_USERSPACE=n +CONFIG_ADC_32_BITS_DATA=y diff --git a/tests/drivers/adc/adc_api/boards/stm32n6570_dk_sb.overlay b/tests/drivers/adc/adc_api/boards/stm32n6570_dk_sb.overlay new file mode 100644 index 0000000000000..a009c76274492 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/stm32n6570_dk_sb.overlay @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 10>, <&adc1 11>; + }; +}; + +&adc1 { + dmas = <&gpdma1 0 7 (STM32_DMA_PERIPH_RX | STM32_DMA_MEM_32BITS | STM32_DMA_PERIPH_32BITS)>; + dma-names = "gpdma"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@a { + reg = <10>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@b { + reg = <11>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + +&gpdma1 { + status = "okay"; +}; From 84a215aff88cec00cb64b7ddef8a53976137f67c Mon Sep 17 00:00:00 2001 From: Dominik Kilian Date: Fri, 24 Jan 2025 12:26:45 +0100 Subject: [PATCH 0191/6055] ipc_service: icmsg: Add "unbound" functionality In some cases, CPUs that may need to reset or temporary stop communication. This commit adds "unbound" functionality that provides a callback to IPC service user when connection was interrupted for some reason, e.g. expected or unexpected CPU reset, closing the endpoint. The "unbound" callback is optional to implement by endpoints. This commit implements it in the ICMsg backend. Signed-off-by: Dominik Kilian --- .../backends/ipc_service_icmsg.rst | 3 +- dts/bindings/ipc/zephyr,ipc-icmsg.yaml | 15 + include/zephyr/ipc/icmsg.h | 51 +- include/zephyr/ipc/ipc_service.h | 15 + include/zephyr/ipc/pbuf.h | 92 +++- .../subsys/ipc/ipc_service/icmsg/src/main.c | 12 + subsys/ipc/ipc_service/backends/ipc_icbmsg.c | 5 +- subsys/ipc/ipc_service/backends/ipc_icmsg.c | 73 ++- .../backends/ipc_icmsg_me_follower.c | 5 +- .../backends/ipc_icmsg_me_initiator.c | 5 +- subsys/ipc/ipc_service/lib/Kconfig.icmsg | 35 +- subsys/ipc/ipc_service/lib/icmsg.c | 496 ++++++++++++------ subsys/ipc/ipc_service/lib/pbuf.c | 61 +++ 13 files changed, 632 insertions(+), 236 deletions(-) diff --git a/doc/services/ipc/ipc_service/backends/ipc_service_icmsg.rst b/doc/services/ipc/ipc_service/backends/ipc_service_icmsg.rst index 251a332027a44..369929a876f50 100644 --- a/doc/services/ipc/ipc_service/backends/ipc_service_icmsg.rst +++ b/doc/services/ipc/ipc_service/backends/ipc_service_icmsg.rst @@ -83,8 +83,7 @@ connected through the IPC instance: memory. #. It then sends a signal to the other domain or CPU, informing that the data has been written. Sending the signal to the other domain or CPU is repeated - with timeout specified by - :kconfig:option:`CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS` option. + with timeout. #. When the signal from the other domain or CPU is received, the magic number is read from ``rx-region``. If it is correct, the bonding process is finished and the backend informs the application by calling diff --git a/dts/bindings/ipc/zephyr,ipc-icmsg.yaml b/dts/bindings/ipc/zephyr,ipc-icmsg.yaml index 13a9e2b84b69c..d1730dddb0f09 100644 --- a/dts/bindings/ipc/zephyr,ipc-icmsg.yaml +++ b/dts/bindings/ipc/zephyr,ipc-icmsg.yaml @@ -21,6 +21,21 @@ properties: required: true type: phandle + unbound: + type: string + enum: + - disable + - enable + - detect + default: disable + description: | + Select unbound() callback mode. The callback can be enabled or disabled with the + "enable" and "disable" option respectively. This functionality requires session + number handshake procedure on both sides, so you cannot set "enable" on one side + and "disable" on the other. The "detect" mode detects if the remote side + supports handshake procedure and adjusts its behavior accordingly. The + "detect" mode is possible only if "dcache-alignment" is at least 8 bytes. + dcache-alignment: type: int description: | diff --git a/include/zephyr/ipc/icmsg.h b/include/zephyr/ipc/icmsg.h index 6e4cbaeaa86c4..41967d7515360 100644 --- a/include/zephyr/ipc/icmsg.h +++ b/include/zephyr/ipc/icmsg.h @@ -27,14 +27,58 @@ extern "C" { */ enum icmsg_state { + /** Instance is not initialized yet. In this state: sending will fail, opening allowed. + */ ICMSG_STATE_OFF, - ICMSG_STATE_BUSY, - ICMSG_STATE_READY, + + /** Instance is initializing without session handshake. In this state: sending will fail, + * opening will fail. + */ + ICMSG_STATE_INITIALIZING_SID_DISABLED, + + /** Instance is initializing with session handshake. It is waiting for remote to acknowledge + * local session id. In this state: sending will fail, opening is allowed (local session id + * will change, so the remote may get unbound() callback). + */ + ICMSG_STATE_INITIALIZING_SID_ENABLED, + + /** Instance is initializing with detection of session handshake support on remote side. + * It is waiting for remote to acknowledge local session id or to send magic bytes. + * In this state: sending will fail, opening is allowed (local session id + * will change, so the remote may get unbound() callback if it supports it). + */ + ICMSG_STATE_INITIALIZING_SID_DETECT, + + /** Instance was closed on remote side. The unbound() callback was send on local side. + * In this state: sending will be silently discarded (there may be outdated sends), + * opening is allowed. + */ + ICMSG_STATE_DISCONNECTED, + + /* Connected states must be at the end. */ + + /** Instance is connected without session handshake support. In this state: sending will be + * successful, opening will fail. + */ + ICMSG_STATE_CONNECTED_SID_DISABLED, + + /** Instance is connected with session handshake support. In this state: sending will be + * successful, opening is allowed (session will change and remote will get unbound() + * callback). + */ + ICMSG_STATE_CONNECTED_SID_ENABLED, +}; + +enum icmsg_unbound_mode { + ICMSG_UNBOUND_MODE_DISABLE = ICMSG_STATE_INITIALIZING_SID_DISABLED, + ICMSG_UNBOUND_MODE_ENABLE = ICMSG_STATE_INITIALIZING_SID_ENABLED, + ICMSG_UNBOUND_MODE_DETECT = ICMSG_STATE_INITIALIZING_SID_DETECT, }; struct icmsg_config_t { struct mbox_dt_spec mbox_tx; struct mbox_dt_spec mbox_rx; + enum icmsg_unbound_mode unbound_mode; }; struct icmsg_data_t { @@ -52,9 +96,10 @@ struct icmsg_data_t { /* General */ const struct icmsg_config_t *cfg; #ifdef CONFIG_MULTITHREADING - struct k_work_delayable notify_work; struct k_work mbox_work; #endif + uint16_t remote_sid; + uint16_t local_sid; atomic_t state; }; diff --git a/include/zephyr/ipc/ipc_service.h b/include/zephyr/ipc/ipc_service.h index 65411a6be1ca8..dbc0b8b7ee48a 100644 --- a/include/zephyr/ipc/ipc_service.h +++ b/include/zephyr/ipc/ipc_service.h @@ -151,6 +151,21 @@ struct ipc_service_cb { */ void (*bound)(void *priv); + /** @brief The endpoint unbound by the remote. + * + * This callback is called when the endpoint binding is removed. It may happen on + * different reasons, e.g. when the remote deregistered the endpoint, connection was + * lost, or remote CPU got reset. + * + * You may want to do some cleanup, resetting, e.t.c. and after that if you want to bound + * again, you can register the endpoint. When the remote becomes available again and it + * also registers the endpoint, the binding will be reestablished and the `bound()` + * callback will be called. + * + * @param[in] priv Private user data. + */ + void (*unbound)(void *priv); + /** @brief New packet arrived. * * This callback is called when new data is received. diff --git a/include/zephyr/ipc/pbuf.h b/include/zephyr/ipc/pbuf.h index 8783cdbbf1465..4bc42bfdf4509 100644 --- a/include/zephyr/ipc/pbuf.h +++ b/include/zephyr/ipc/pbuf.h @@ -47,20 +47,23 @@ extern "C" { * The structure contains configuration data. */ struct pbuf_cfg { - volatile uint32_t *rd_idx_loc; /* Address of the variable holding - * index value of the first valid byte - * in data[]. - */ - volatile uint32_t *wr_idx_loc; /* Address of the variable holding - * index value of the first free byte - * in data[]. - */ - uint32_t dcache_alignment; /* CPU data cache line size in bytes. - * Used for validation - TODO: To be - * replaced by flags. - */ - uint32_t len; /* Length of data[] in bytes. */ - uint8_t *data_loc; /* Location of the data[]. */ + volatile uint32_t *rd_idx_loc; /* Address of the variable holding + * index value of the first valid byte + * in data[]. + */ + volatile uint32_t *handshake_loc;/* Address of the variable holding + * handshake information. + */ + volatile uint32_t *wr_idx_loc; /* Address of the variable holding + * index value of the first free byte + * in data[]. + */ + uint32_t dcache_alignment; /* CPU data cache line size in bytes. + * Used for validation - TODO: To be + * replaced by flags. + */ + uint32_t len; /* Length of data[] in bytes. */ + uint8_t *data_loc; /* Location of the data[]. */ }; /** @@ -111,16 +114,21 @@ struct pbuf { * @param mem_addr Memory address for pbuf. * @param size Size of the memory. * @param dcache_align Data cache alignment. + * @param use_handshake Add handshake word inside shared memory that can be access with + * @ref pbuf_handshake_read and @ref pbuf_handshake_write. */ -#define PBUF_CFG_INIT(mem_addr, size, dcache_align) \ +#define PBUF_CFG_INIT(mem_addr, size, dcache_align, use_handshake) \ { \ .rd_idx_loc = (uint32_t *)(mem_addr), \ - .wr_idx_loc = (uint32_t *)((uint8_t *)(mem_addr) + \ - MAX(dcache_align, _PBUF_IDX_SIZE)), \ + .handshake_loc = use_handshake ? (uint32_t *)((uint8_t *)(mem_addr) + \ + _PBUF_IDX_SIZE) : NULL, \ + .wr_idx_loc = (uint32_t *)((uint8_t *)(mem_addr) + MAX(dcache_align, \ + (use_handshake ? 2 : 1) * _PBUF_IDX_SIZE)), \ .data_loc = (uint8_t *)((uint8_t *)(mem_addr) + \ - MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE), \ - .len = (uint32_t)((uint32_t)(size) - MAX(dcache_align, _PBUF_IDX_SIZE) - \ - _PBUF_IDX_SIZE), \ + MAX(dcache_align, (use_handshake ? 2 : 1) * \ + _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE), \ + .len = (uint32_t)((uint32_t)(size) - MAX(dcache_align, \ + (use_handshake ? 2 : 1) * _PBUF_IDX_SIZE) - _PBUF_IDX_SIZE), \ .dcache_alignment = (dcache_align), \ } @@ -140,9 +148,11 @@ struct pbuf { * @param name Name of the pbuf. * @param mem_addr Memory address for pbuf. * @param size Size of the memory. - * @param dcache_align Data cache line size. + * @param dcache_align Data cache line size. + * @param use_handshake Add handshake word inside shared memory that can be access with + * @ref pbuf_handshake_read and @ref pbuf_handshake_write. */ -#define PBUF_DEFINE(name, mem_addr, size, dcache_align) \ +#define PBUF_DEFINE(name, mem_addr, size, dcache_align, use_handshake, compatibility) \ BUILD_ASSERT(dcache_align >= 0, \ "Cache line size must be non negative."); \ BUILD_ASSERT((size) > 0 && IS_PTR_ALIGNED_BYTES(size, _PBUF_IDX_SIZE), \ @@ -151,8 +161,10 @@ struct pbuf { "Misaligned memory."); \ BUILD_ASSERT(size >= (MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE + \ _PBUF_MIN_DATA_LEN), "Insufficient size."); \ + BUILD_ASSERT(!(compatibility) || (dcache_align) >= 8, \ + "Data cache alignment must be at least 8 if compatibility is enabled.");\ static PBUF_MAYBE_CONST struct pbuf_cfg cfg_##name = \ - PBUF_CFG_INIT(mem_addr, size, dcache_align); \ + PBUF_CFG_INIT(mem_addr, size, dcache_align, use_handshake); \ static struct pbuf name = { \ .cfg = &cfg_##name, \ } @@ -223,6 +235,40 @@ int pbuf_write(struct pbuf *pb, const char *buf, uint16_t len); */ int pbuf_read(struct pbuf *pb, char *buf, uint16_t len); +/** + * @brief Read handshake word from pbuf. + * + * The pb must be defined with "PBUF_DEFINE" with "use_handshake" set. + * + * @param pb A buffer from which data will be read. + * @retval uint32_t The handshake word value. + */ +uint32_t pbuf_handshake_read(struct pbuf *pb); + +/** + * @brief Write handshake word to pbuf. + * + * The pb must be defined with "PBUF_DEFINE" with "use_handshake" set. + * + * @param pb A buffer to which data will be written. + * @param value A handshake value. + */ +void pbuf_handshake_write(struct pbuf *pb, uint32_t value); + +/** + * @brief Get first buffer from pbuf. + * + * This function retrieves buffer located at the beginning of queue. + * It will be continuous block since it is the first buffer. + * + * @param pb A buffer from which data will be read. + * @param[out] buf A pointer to output pointer to the date of the first buffer. + * @param[out] len A pointer to output length the first buffer. + * @retval 0 on success. + * -EINVAL when there is no buffer at the beginning of queue. + */ +int pbuf_get_initial_buf(struct pbuf *pb, volatile char **buf, uint16_t *len); + /** * @} */ diff --git a/samples/subsys/ipc/ipc_service/icmsg/src/main.c b/samples/subsys/ipc/ipc_service/icmsg/src/main.c index 86469cac64b02..afb5016dbeb36 100644 --- a/samples/subsys/ipc/ipc_service/icmsg/src/main.c +++ b/samples/subsys/ipc/ipc_service/icmsg/src/main.c @@ -40,6 +40,11 @@ static void ep_bound(void *priv) LOG_INF("Ep bounded"); } +static void ep_unbound(void *priv) +{ + LOG_INF("Ep unbounded"); +} + static void ep_recv(const void *data, size_t len, void *priv) { #if defined(CONFIG_ASSERT) @@ -68,6 +73,11 @@ static void ep_recv(const void *data, size_t len, void *priv) } } +static void ep_error(const char *message, void *priv) +{ + LOG_ERR("ICMsg error: %s", message); +} + static int send_for_time(struct ipc_ept *ep, const int64_t sending_time_ms) { struct data_packet msg = {.data[0] = 'a'}; @@ -123,7 +133,9 @@ static int send_for_time(struct ipc_ept *ep, const int64_t sending_time_ms) static struct ipc_ept_cfg ep_cfg = { .cb = { .bound = ep_bound, + .unbound = ep_unbound, .received = ep_recv, + .error = ep_error, }, }; diff --git a/subsys/ipc/ipc_service/backends/ipc_icbmsg.c b/subsys/ipc/ipc_service/backends/ipc_icbmsg.c index 7e985aa76deb0..3dbb018e7e19a 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icbmsg.c +++ b/subsys/ipc/ipc_service/backends/ipc_icbmsg.c @@ -1408,11 +1408,11 @@ const static struct ipc_service_backend backend_ops = { PBUF_DEFINE(tx_icbmsg_pb_##i, \ GET_MEM_ADDR_INST(i, tx), \ GET_ICMSG_SIZE_INST(i, tx, rx), \ - GET_CACHE_ALIGNMENT(i)); \ + GET_CACHE_ALIGNMENT(i), 0, 0); \ PBUF_DEFINE(rx_icbmsg_pb_##i, \ GET_MEM_ADDR_INST(i, rx), \ GET_ICMSG_SIZE_INST(i, rx, tx), \ - GET_CACHE_ALIGNMENT(i)); \ + GET_CACHE_ALIGNMENT(i), 0, 0); \ static struct backend_data backend_data_##i = { \ .control_data = { \ .tx_pb = &tx_icbmsg_pb_##i, \ @@ -1424,6 +1424,7 @@ const static struct ipc_service_backend backend_ops = { .control_config = { \ .mbox_tx = MBOX_DT_SPEC_INST_GET(i, tx), \ .mbox_rx = MBOX_DT_SPEC_INST_GET(i, rx), \ + .unbound_mode = ICMSG_UNBOUND_MODE_DISABLE, \ }, \ .tx = { \ .blocks_ptr = (uint8_t *)GET_BLOCKS_ADDR_INST(i, tx, rx), \ diff --git a/subsys/ipc/ipc_service/backends/ipc_icmsg.c b/subsys/ipc/ipc_service/backends/ipc_icmsg.c index 40cc06b8a6ff9..77b118633ea55 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg.c @@ -54,33 +54,52 @@ static int backend_init(const struct device *instance) return 0; } -#define DEFINE_BACKEND_DEVICE(i) \ - static const struct icmsg_config_t backend_config_##i = { \ - .mbox_tx = MBOX_DT_SPEC_INST_GET(i, tx), \ - .mbox_rx = MBOX_DT_SPEC_INST_GET(i, rx), \ - }; \ - \ - PBUF_DEFINE(tx_pb_##i, \ - DT_REG_ADDR(DT_INST_PHANDLE(i, tx_region)), \ - DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)), \ - DT_INST_PROP_OR(i, dcache_alignment, 0)); \ - PBUF_DEFINE(rx_pb_##i, \ - DT_REG_ADDR(DT_INST_PHANDLE(i, rx_region)), \ - DT_REG_SIZE(DT_INST_PHANDLE(i, rx_region)), \ - DT_INST_PROP_OR(i, dcache_alignment, 0)); \ - \ - static struct icmsg_data_t backend_data_##i = { \ - .tx_pb = &tx_pb_##i, \ - .rx_pb = &rx_pb_##i, \ - }; \ - \ - DEVICE_DT_INST_DEFINE(i, \ - &backend_init, \ - NULL, \ - &backend_data_##i, \ - &backend_config_##i, \ - POST_KERNEL, \ - CONFIG_IPC_SERVICE_REG_BACKEND_PRIORITY, \ +#define UNBOUND_MODE(i) CONCAT(ICMSG_UNBOUND_MODE_, DT_INST_STRING_UPPER_TOKEN(i, unbound)) + +#define DEFINE_BACKEND_DEVICE(i) \ + static const struct icmsg_config_t backend_config_##i = { \ + .mbox_tx = MBOX_DT_SPEC_INST_GET(i, tx), \ + .mbox_rx = MBOX_DT_SPEC_INST_GET(i, rx), \ + .unbound_mode = UNBOUND_MODE(i), \ + }; \ + \ + PBUF_DEFINE(tx_pb_##i, \ + DT_REG_ADDR(DT_INST_PHANDLE(i, tx_region)), \ + DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)), \ + DT_INST_PROP_OR(i, dcache_alignment, 0), \ + UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_DISABLE, \ + UNBOUND_MODE(i) == ICMSG_UNBOUND_MODE_DETECT); \ + PBUF_DEFINE(rx_pb_##i, \ + DT_REG_ADDR(DT_INST_PHANDLE(i, rx_region)), \ + DT_REG_SIZE(DT_INST_PHANDLE(i, rx_region)), \ + DT_INST_PROP_OR(i, dcache_alignment, 0), \ + UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_DISABLE, \ + UNBOUND_MODE(i) == ICMSG_UNBOUND_MODE_DETECT); \ + \ + BUILD_ASSERT(UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_DISABLE || \ + IS_ENABLED(CONFIG_IPC_SERVICE_ICMSG_UNBOUND_DISABLED_ALLOWED), \ + "Unbound mode \"disabled\" is was forbidden in Kconfig."); \ + \ + BUILD_ASSERT(UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_ENABLE || \ + IS_ENABLED(CONFIG_IPC_SERVICE_ICMSG_UNBOUND_ENABLED_ALLOWED), \ + "Unbound mode \"enabled\" is was forbidden in Kconfig."); \ + \ + BUILD_ASSERT(UNBOUND_MODE(i) != ICMSG_UNBOUND_MODE_DETECT || \ + IS_ENABLED(CONFIG_IPC_SERVICE_ICMSG_UNBOUND_DETECT_ALLOWED), \ + "Unbound mode \"detect\" is was forbidden in Kconfig."); \ + \ + static struct icmsg_data_t backend_data_##i = { \ + .tx_pb = &tx_pb_##i, \ + .rx_pb = &rx_pb_##i, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(i, \ + &backend_init, \ + NULL, \ + &backend_data_##i, \ + &backend_config_##i, \ + POST_KERNEL, \ + CONFIG_IPC_SERVICE_REG_BACKEND_PRIORITY, \ &backend_ops); DT_INST_FOREACH_STATUS_OKAY(DEFINE_BACKEND_DEVICE) diff --git a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c index cc374b31f57d6..bf682cd51e18c 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c @@ -280,16 +280,17 @@ static int backend_init(const struct device *instance) static const struct icmsg_config_t backend_config_##i = { \ .mbox_tx = MBOX_DT_SPEC_INST_GET(i, tx), \ .mbox_rx = MBOX_DT_SPEC_INST_GET(i, rx), \ + .unbound_mode = ICMSG_UNBOUND_MODE_DISABLE, \ }; \ \ PBUF_DEFINE(tx_pb_##i, \ DT_REG_ADDR(DT_INST_PHANDLE(i, tx_region)), \ DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)), \ - DT_INST_PROP_OR(i, dcache_alignment, 0)); \ + DT_INST_PROP_OR(i, dcache_alignment, 0), 0, 0); \ PBUF_DEFINE(rx_pb_##i, \ DT_REG_ADDR(DT_INST_PHANDLE(i, rx_region)), \ DT_REG_SIZE(DT_INST_PHANDLE(i, rx_region)), \ - DT_INST_PROP_OR(i, dcache_alignment, 0)); \ + DT_INST_PROP_OR(i, dcache_alignment, 0), 0, 0); \ \ static struct backend_data_t backend_data_##i = { \ .icmsg_me_data = { \ diff --git a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c index 28170f909ece4..f2064a9dc0f27 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c @@ -186,16 +186,17 @@ static int backend_init(const struct device *instance) static const struct icmsg_config_t backend_config_##i = { \ .mbox_tx = MBOX_DT_SPEC_INST_GET(i, tx), \ .mbox_rx = MBOX_DT_SPEC_INST_GET(i, rx), \ + .unbound_mode = ICMSG_UNBOUND_MODE_DISABLE, \ }; \ \ PBUF_DEFINE(tx_pb_##i, \ DT_REG_ADDR(DT_INST_PHANDLE(i, tx_region)), \ DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)), \ - DT_INST_PROP_OR(i, dcache_alignment, 0)); \ + DT_INST_PROP_OR(i, dcache_alignment, 0), 0, 0); \ PBUF_DEFINE(rx_pb_##i, \ DT_REG_ADDR(DT_INST_PHANDLE(i, rx_region)), \ DT_REG_SIZE(DT_INST_PHANDLE(i, rx_region)), \ - DT_INST_PROP_OR(i, dcache_alignment, 0)); \ + DT_INST_PROP_OR(i, dcache_alignment, 0), 0, 0); \ \ static struct backend_data_t backend_data_##i = { \ .icmsg_me_data = { \ diff --git a/subsys/ipc/ipc_service/lib/Kconfig.icmsg b/subsys/ipc/ipc_service/lib/Kconfig.icmsg index bc15d9a599934..6bbc79d4fa2ab 100644 --- a/subsys/ipc/ipc_service/lib/Kconfig.icmsg +++ b/subsys/ipc/ipc_service/lib/Kconfig.icmsg @@ -21,14 +21,6 @@ config IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS Maximum time to wait, in milliseconds, for access to send data with backends basing on icmsg library. This time should be relatively low. -config IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS - int "Bond notification timeout in miliseconds" - range 1 100 - default 1 - help - Time to wait for remote bonding notification before the - notification is repeated. - config IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE bool "Use dedicated workqueue" depends on MULTITHREADING @@ -68,6 +60,33 @@ config IPC_SERVICE_BACKEND_ICMSG_WQ_PRIORITY endif +config IPC_SERVICE_ICMSG_UNBOUND_ENABLED_ALLOWED + bool "Instance is allowed to set unbound to enabled" + default y + help + Controls whether the "enabled" value of the "unbound" + property is allowed to be set in any of the ICMsg instances. You + can set this option to "n", if you want to reduce code size and + no instance of ICMsg is using unbound functionality. + +config IPC_SERVICE_ICMSG_UNBOUND_DISABLED_ALLOWED + bool "Instance is allowed to set unbound to disabled" + default y + help + Controls whether the "disabled" value of the "unbound" + property is allowed to be set in any of the ICMsg instances. You + can set this option to "n", if you want to reduce code size and + all instances of ICMsg are using unbound functionality. + +config IPC_SERVICE_ICMSG_UNBOUND_DETECT_ALLOWED + bool "Instance is allowed to set unbound to detect" + default y + help + Controls whether the "detect" value of the "unbound" + property is allowed to be set in any of the ICMsg instances. You + can set this option to "n", if you want to reduce code size and + all instances of ICMsg are using unbound detection functionality. + # The Icmsg library in its simplicity requires the system workqueue to execute # at a cooperative priority. config SYSTEM_WORKQUEUE_PRIORITY diff --git a/subsys/ipc/ipc_service/lib/icmsg.c b/subsys/ipc/ipc_service/lib/icmsg.c index f574e71ec1478..500ca20cde641 100644 --- a/subsys/ipc/ipc_service/lib/icmsg.c +++ b/subsys/ipc/ipc_service/lib/icmsg.c @@ -12,7 +12,39 @@ #include #include -#define BOND_NOTIFY_REPEAT_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS) + +#define UNBOUND_DISABLED IS_ENABLED(CONFIG_IPC_SERVICE_ICMSG_UNBOUND_DISABLED_ALLOWED) +#define UNBOUND_ENABLED IS_ENABLED(CONFIG_IPC_SERVICE_ICMSG_UNBOUND_ENABLED_ALLOWED) +#define UNBOUND_DETECT IS_ENABLED(CONFIG_IPC_SERVICE_ICMSG_UNBOUND_DETECT_ALLOWED) + +/** Get local session id request from RX handshake word. + */ +#define LOCAL_SID_REQ_FROM_RX(rx_handshake) ((rx_handshake) & 0xFFFF) + +/** Get remote session id request from TX handshake word. + */ +#define REMOTE_SID_REQ_FROM_TX(tx_handshake) ((tx_handshake) & 0xFFFF) + +/** Get local session id acknowledge from TX handshake word. + */ +#define LOCAL_SID_ACK_FROM_TX(tx_handshake) ((tx_handshake) >> 16) + +/** Create RX handshake word from local session id request + * and remote session id acknowledge. + */ +#define MAKE_RX_HANDSHAKE(local_sid_req, remote_sid_ack) \ + ((local_sid_req) | ((remote_sid_ack) << 16)) + +/** Create TX handshake word from remote session id request + * and local session id acknowledge. + */ +#define MAKE_TX_HANDSHAKE(remote_sid_req, local_sid_ack) \ + ((remote_sid_req) | ((local_sid_ack) << 16)) + +/** Special session id indicating that peers are disconnected. + */ +#define SID_DISCONNECTED 0 + #define SHMEM_ACCESS_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS) static const uint8_t magic[] = {0x45, 0x6d, 0x31, 0x6c, 0x31, 0x4b, @@ -23,13 +55,10 @@ static const uint8_t magic[] = {0x45, 0x6d, 0x31, 0x6c, 0x31, 0x4b, static K_THREAD_STACK_DEFINE(icmsg_stack, CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_STACK_SIZE); static struct k_work_q icmsg_workq; static struct k_work_q *const workq = &icmsg_workq; -#else +#else /* defined(CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE) */ static struct k_work_q *const workq = &k_sys_work_q; -#endif -static void mbox_callback_process(struct k_work *item); -#else -static void mbox_callback_process(struct icmsg_data_t *dev_data); -#endif +#endif /* defined(CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE) */ +#endif /* def CONFIG_MULTITHREADING */ static int mbox_deinit(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data) @@ -48,76 +77,33 @@ static int mbox_deinit(const struct icmsg_config_t *conf, #ifdef CONFIG_MULTITHREADING (void)k_work_cancel(&dev_data->mbox_work); - (void)k_work_cancel_delayable(&dev_data->notify_work); #endif return 0; } -static bool is_endpoint_ready(struct icmsg_data_t *dev_data) +static bool is_endpoint_ready(atomic_t state) { - return atomic_get(&dev_data->state) == ICMSG_STATE_READY; + return state >= MIN(ICMSG_STATE_CONNECTED_SID_DISABLED, ICMSG_STATE_CONNECTED_SID_ENABLED); } -#ifdef CONFIG_MULTITHREADING -static void notify_process(struct k_work *item) +static inline int reserve_tx_buffer_if_unused(struct icmsg_data_t *dev_data) { - struct k_work_delayable *dwork = k_work_delayable_from_work(item); - struct icmsg_data_t *dev_data = - CONTAINER_OF(dwork, struct icmsg_data_t, notify_work); - - (void)mbox_send_dt(&dev_data->cfg->mbox_tx, NULL); - - atomic_t state = atomic_get(&dev_data->state); - - if (state != ICMSG_STATE_READY) { - int ret; - - ret = k_work_reschedule_for_queue(workq, dwork, BOND_NOTIFY_REPEAT_TO); - __ASSERT_NO_MSG(ret >= 0); - (void)ret; - } -} -#else -static void notify_process(struct icmsg_data_t *dev_data) -{ - (void)mbox_send_dt(&dev_data->cfg->mbox_tx, NULL); -#if defined(CONFIG_SYS_CLOCK_EXISTS) - int64_t start = k_uptime_get(); -#endif - - while (false == is_endpoint_ready(dev_data)) { - mbox_callback_process(dev_data); - -#if defined(CONFIG_SYS_CLOCK_EXISTS) - if ((k_uptime_get() - start) > CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS) { -#endif - (void)mbox_send_dt(&dev_data->cfg->mbox_tx, NULL); -#if defined(CONFIG_SYS_CLOCK_EXISTS) - start = k_uptime_get(); - }; -#endif - } -} -#endif - #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC -static int reserve_tx_buffer_if_unused(struct icmsg_data_t *dev_data) -{ - int ret = k_mutex_lock(&dev_data->tx_lock, SHMEM_ACCESS_TO); - - if (ret < 0) { - return ret; - } - + return k_mutex_lock(&dev_data->tx_lock, SHMEM_ACCESS_TO); +#else return 0; +#endif } -static int release_tx_buffer(struct icmsg_data_t *dev_data) +static inline int release_tx_buffer(struct icmsg_data_t *dev_data) { +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC return k_mutex_unlock(&dev_data->tx_lock); -} +#else + return 0; #endif +} static uint32_t data_available(struct icmsg_data_t *dev_data) { @@ -135,103 +121,242 @@ static void submit_mbox_work(struct icmsg_data_t *dev_data) } } -static void submit_work_if_buffer_free(struct icmsg_data_t *dev_data) -{ - submit_mbox_work(dev_data); -} +#endif -static void submit_work_if_buffer_free_and_data_available( - struct icmsg_data_t *dev_data) +static int initialize_tx_with_sid_disabled(struct icmsg_data_t *dev_data) { - if (!data_available(dev_data)) { - return; + int ret; + + ret = pbuf_tx_init(dev_data->tx_pb); + + if (ret < 0) { + __ASSERT(false, "Incorrect Tx configuration"); + return ret; } - submit_mbox_work(dev_data); -} -#else -static void submit_if_buffer_free(struct icmsg_data_t *dev_data) -{ - mbox_callback_process(dev_data); -} + ret = pbuf_write(dev_data->tx_pb, magic, sizeof(magic)); -static void submit_if_buffer_free_and_data_available( - struct icmsg_data_t *dev_data) -{ + if (ret < 0) { + __ASSERT_NO_MSG(false); + return ret; + } - if (!data_available(dev_data)) { - return; + if (ret < (int)sizeof(magic)) { + __ASSERT_NO_MSG(ret == sizeof(magic)); + return -EINVAL; } - mbox_callback_process(dev_data); + return 0; } -#endif -#ifdef CONFIG_MULTITHREADING -static void mbox_callback_process(struct k_work *item) -#else -static void mbox_callback_process(struct icmsg_data_t *dev_data) -#endif +static bool callback_process(struct icmsg_data_t *dev_data) { -#ifdef CONFIG_MULTITHREADING - struct icmsg_data_t *dev_data = CONTAINER_OF(item, struct icmsg_data_t, mbox_work); -#endif + int ret; uint8_t rx_buffer[CONFIG_PBUF_RX_READ_BUF_SIZE] __aligned(4); - + uint32_t len = 0; + uint32_t len_available; + bool rerun = false; + bool notify_remote = false; atomic_t state = atomic_get(&dev_data->state); - uint32_t len = data_available(dev_data); - - if (len == 0) { - /* Unlikely, no data in buffer. */ - return; + switch (state) { + +#if UNBOUND_DETECT + case ICMSG_STATE_INITIALIZING_SID_DETECT: { + /* Initialization with detection of remote session awareness */ + volatile char *magic_buf; + uint16_t magic_len; + + ret = pbuf_get_initial_buf(dev_data->rx_pb, &magic_buf, &magic_len); + + if (ret == 0 && magic_len == sizeof(magic) && + memcmp((void *)magic_buf, magic, sizeof(magic)) == 0) { + /* Remote initialized in session-unaware mode, so we do old way of + * initialization. + */ + ret = initialize_tx_with_sid_disabled(dev_data); + if (ret < 0) { + if (dev_data->cb->error) { + dev_data->cb->error("Incorrect Tx configuration", + dev_data->ctx); + } + __ASSERT(false, "Incorrect Tx configuration"); + atomic_set(&dev_data->state, ICMSG_STATE_OFF); + return false; + } + /* We got magic data, so we can handle it later. */ + notify_remote = true; + rerun = true; + atomic_set(&dev_data->state, ICMSG_STATE_INITIALIZING_SID_DISABLED); + break; + } + /* If remote did not initialize the RX in session-unaware mode, we can try + * with session-aware initialization. + */ + __fallthrough; } +#endif /* UNBOUND_DETECT */ + +#if UNBOUND_ENABLED || UNBOUND_DETECT + case ICMSG_STATE_INITIALIZING_SID_ENABLED: { + uint32_t tx_handshake = pbuf_handshake_read(dev_data->tx_pb); + uint32_t remote_sid_req = REMOTE_SID_REQ_FROM_TX(tx_handshake); + uint32_t local_sid_ack = LOCAL_SID_ACK_FROM_TX(tx_handshake); + + if (remote_sid_req != dev_data->remote_sid && remote_sid_req != SID_DISCONNECTED) { + /* We can now initialize TX, since we know that remote, during receiving, + * will first read FIFO indexes and later, it will check if session has + * changed before using indexes to receive the message. Additionally, + * we know that remote after session request change will no try to receive + * more data. + */ + ret = pbuf_tx_init(dev_data->tx_pb); + if (ret < 0) { + if (dev_data->cb->error) { + dev_data->cb->error("Incorrect Tx configuration", + dev_data->ctx); + } + __ASSERT(false, "Incorrect Tx configuration"); + atomic_set(&dev_data->state, ICMSG_STATE_DISCONNECTED); + return false; + } + /* Acknowledge the remote session. */ + dev_data->remote_sid = remote_sid_req; + pbuf_handshake_write(dev_data->rx_pb, + MAKE_RX_HANDSHAKE(dev_data->local_sid, dev_data->remote_sid)); + notify_remote = true; + } - __ASSERT_NO_MSG(len <= sizeof(rx_buffer)); + if (local_sid_ack == dev_data->local_sid && + dev_data->remote_sid != SID_DISCONNECTED) { + /* We send acknowledge to remote, receive acknowledge from remote, + * so we are ready. + */ + atomic_set(&dev_data->state, ICMSG_STATE_CONNECTED_SID_ENABLED); + + if (dev_data->cb->bound) { + dev_data->cb->bound(dev_data->ctx); + } + /* Re-run this handler, because remote may already send something. */ + rerun = true; + notify_remote = true; + } - if (sizeof(rx_buffer) < len) { - return; + break; } +#endif /* UNBOUND_ENABLED || UNBOUND_DETECT */ - len = pbuf_read(dev_data->rx_pb, rx_buffer, sizeof(rx_buffer)); +#if UNBOUND_ENABLED || UNBOUND_DETECT + case ICMSG_STATE_CONNECTED_SID_ENABLED: +#endif +#if UNBOUND_DISABLED || UNBOUND_DETECT + case ICMSG_STATE_CONNECTED_SID_DISABLED: +#endif +#if UNBOUND_DISABLED + case ICMSG_STATE_INITIALIZING_SID_DISABLED: +#endif + + len_available = data_available(dev_data); - if (state == ICMSG_STATE_READY) { - if (dev_data->cb->received) { - dev_data->cb->received(rx_buffer, len, dev_data->ctx); + if (len_available > 0 && sizeof(rx_buffer) >= len_available) { + len = pbuf_read(dev_data->rx_pb, rx_buffer, sizeof(rx_buffer)); + } + + if (state == ICMSG_STATE_CONNECTED_SID_ENABLED && + (UNBOUND_ENABLED || UNBOUND_DETECT)) { + /* The incoming message is valid only if remote session is as expected, + * so we need to check remote session now. + */ + uint32_t remote_sid_req = REMOTE_SID_REQ_FROM_TX( + pbuf_handshake_read(dev_data->tx_pb)); + + if (remote_sid_req != dev_data->remote_sid) { + atomic_set(&dev_data->state, ICMSG_STATE_DISCONNECTED); + if (dev_data->cb->unbound) { + dev_data->cb->unbound(dev_data->ctx); + } + return false; + } + } + + if (len_available == 0) { + /* Unlikely, no data in buffer. */ + return false; } - } else { - __ASSERT_NO_MSG(state == ICMSG_STATE_BUSY); - /* Allow magic number longer than sizeof(magic) for future protocol version. */ - bool endpoint_invalid = (len < sizeof(magic) || - memcmp(magic, rx_buffer, sizeof(magic))); + __ASSERT_NO_MSG(len_available <= sizeof(rx_buffer)); - if (endpoint_invalid) { - __ASSERT_NO_MSG(false); - return; + if (sizeof(rx_buffer) < len_available) { + return false; } - if (dev_data->cb->bound) { - dev_data->cb->bound(dev_data->ctx); + if (state != ICMSG_STATE_INITIALIZING_SID_DISABLED || !UNBOUND_DISABLED) { + if (dev_data->cb->received) { + dev_data->cb->received(rx_buffer, len, dev_data->ctx); + } + } else { + /* Allow magic number longer than sizeof(magic) for future protocol + * version. + */ + bool endpoint_invalid = (len < sizeof(magic) || + memcmp(magic, rx_buffer, sizeof(magic))); + + if (endpoint_invalid) { + __ASSERT_NO_MSG(false); + return false; + } + + if (dev_data->cb->bound) { + dev_data->cb->bound(dev_data->ctx); + } + + atomic_set(&dev_data->state, ICMSG_STATE_CONNECTED_SID_DISABLED); + notify_remote = true; } - atomic_set(&dev_data->state, ICMSG_STATE_READY); + rerun = (data_available(dev_data) > 0); + break; + + case ICMSG_STATE_OFF: + case ICMSG_STATE_DISCONNECTED: + default: + /* Nothing to do in this state. */ + return false; } + + if (notify_remote) { + (void)mbox_send_dt(&dev_data->cfg->mbox_tx, NULL); + } + + return rerun; +} + #ifdef CONFIG_MULTITHREADING - submit_work_if_buffer_free_and_data_available(dev_data); -#else - submit_if_buffer_free_and_data_available(dev_data); -#endif +static void workq_callback_process(struct k_work *item) +{ + bool rerun; + struct icmsg_data_t *dev_data = CONTAINER_OF(item, struct icmsg_data_t, mbox_work); + + rerun = callback_process(dev_data); + if (rerun) { + submit_mbox_work(dev_data); + } } +#endif /* def CONFIG_MULTITHREADING */ static void mbox_callback(const struct device *instance, uint32_t channel, void *user_data, struct mbox_msg *msg_data) { + bool rerun; struct icmsg_data_t *dev_data = user_data; + #ifdef CONFIG_MULTITHREADING - submit_work_if_buffer_free(dev_data); + ARG_UNUSED(rerun); + submit_mbox_work(dev_data); #else - submit_if_buffer_free(dev_data); + do { + rerun = callback_process(dev_data); + } while (rerun); #endif } @@ -241,8 +366,7 @@ static int mbox_init(const struct icmsg_config_t *conf, int err; #ifdef CONFIG_MULTITHREADING - k_work_init(&dev_data->mbox_work, mbox_callback_process); - k_work_init_delayable(&dev_data->notify_work, notify_process); + k_work_init(&dev_data->mbox_work, workq_callback_process); #endif err = mbox_register_callback_dt(&conf->mbox_rx, mbox_callback, dev_data); @@ -257,9 +381,27 @@ int icmsg_open(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const struct ipc_service_cb *cb, void *ctx) { - if (!atomic_cas(&dev_data->state, ICMSG_STATE_OFF, ICMSG_STATE_BUSY)) { - /* Already opened. */ - return -EALREADY; + int ret; + enum icmsg_state old_state; + + __ASSERT(conf->unbound_mode != ICMSG_UNBOUND_MODE_DISABLE || UNBOUND_DISABLED, + "Unbound mode \"disabled\" is was forbidden in Kconfig."); + __ASSERT(conf->unbound_mode != ICMSG_UNBOUND_MODE_ENABLE || UNBOUND_ENABLED, + "Unbound mode \"enabled\" is was forbidden in Kconfig."); + __ASSERT(conf->unbound_mode != ICMSG_UNBOUND_MODE_DETECT || UNBOUND_DETECT, + "Unbound mode \"detect\" is was forbidden in Kconfig."); + + if (conf->unbound_mode == ICMSG_UNBOUND_MODE_DISABLE || + !(UNBOUND_ENABLED || UNBOUND_DETECT)) { + if (!atomic_cas(&dev_data->state, ICMSG_STATE_OFF, + ICMSG_STATE_INITIALIZING_SID_DISABLED)) { + /* Already opened. */ + return -EALREADY; + } + old_state = ICMSG_STATE_OFF; + } else { + /* Unbound mode has the same values as ICMSG_STATE_INITIALIZING_* */ + old_state = atomic_set(&dev_data->state, conf->unbound_mode); } dev_data->cb = cb; @@ -270,60 +412,82 @@ int icmsg_open(const struct icmsg_config_t *conf, k_mutex_init(&dev_data->tx_lock); #endif - int ret = pbuf_tx_init(dev_data->tx_pb); - - if (ret < 0) { - __ASSERT(false, "Incorrect Tx configuration"); - return ret; - } - ret = pbuf_rx_init(dev_data->rx_pb); if (ret < 0) { __ASSERT(false, "Incorrect Rx configuration"); - return ret; + goto cleanup_and_exit; } - ret = pbuf_write(dev_data->tx_pb, magic, sizeof(magic)); - - if (ret < 0) { - __ASSERT_NO_MSG(false); - return ret; + if (conf->unbound_mode != ICMSG_UNBOUND_MODE_DISABLE && + (UNBOUND_ENABLED || UNBOUND_DETECT)) { + /* Increment local session id without conflicts with forbidden values. */ + uint32_t local_sid_ack = + LOCAL_SID_ACK_FROM_TX(pbuf_handshake_read(dev_data->tx_pb)); + dev_data->local_sid = + LOCAL_SID_REQ_FROM_RX(pbuf_handshake_read(dev_data->tx_pb)); + dev_data->remote_sid = SID_DISCONNECTED; + do { + dev_data->local_sid = (dev_data->local_sid + 1) & 0xFFFF; + } while (dev_data->local_sid == local_sid_ack || + dev_data->local_sid == SID_DISCONNECTED); + /* Write local session id request without remote acknowledge */ + pbuf_handshake_write(dev_data->rx_pb, + MAKE_RX_HANDSHAKE(dev_data->local_sid, SID_DISCONNECTED)); + } else if (UNBOUND_DISABLED) { + ret = initialize_tx_with_sid_disabled(dev_data); } - if (ret < (int)sizeof(magic)) { - __ASSERT_NO_MSG(ret == sizeof(magic)); - return ret; + if (old_state == ICMSG_STATE_OFF && (UNBOUND_ENABLED || UNBOUND_DETECT)) { + /* Initialize mbox only if we are doing first-time open (not re-open + * after unbound) + */ + ret = mbox_init(conf, dev_data); + if (ret) { + goto cleanup_and_exit; + } } - ret = mbox_init(conf, dev_data); - if (ret) { - return ret; - } -#ifdef CONFIG_MULTITHREADING - ret = k_work_schedule_for_queue(workq, &dev_data->notify_work, K_NO_WAIT); + /* We need to send a notification to remote, it may not be delivered + * since it may be uninitialized yet, but when it finishes the initialization + * we get a notification from it. We need to send this notification in callback + * again to make sure that it arrived. + */ + ret = mbox_send_dt(&conf->mbox_tx, NULL); + if (ret < 0) { - return ret; + __ASSERT(false, "Cannot send mbox notification"); + goto cleanup_and_exit; } -#else - notify_process(dev_data); -#endif - return 0; + + return ret; + +cleanup_and_exit: + atomic_set(&dev_data->state, ICMSG_STATE_OFF); + return ret; } int icmsg_close(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data) { - int ret; + int ret = 0; + enum icmsg_state old_state; - ret = mbox_deinit(conf, dev_data); - if (ret) { - return ret; + if (conf->unbound_mode != ICMSG_UNBOUND_MODE_DISABLE && + (UNBOUND_ENABLED || UNBOUND_DETECT)) { + pbuf_handshake_write(dev_data->rx_pb, + MAKE_RX_HANDSHAKE(SID_DISCONNECTED, SID_DISCONNECTED)); } - atomic_set(&dev_data->state, ICMSG_STATE_OFF); + (void)mbox_send_dt(&conf->mbox_tx, NULL); - return 0; + old_state = atomic_set(&dev_data->state, ICMSG_STATE_OFF); + + if (old_state != ICMSG_STATE_OFF) { + ret = mbox_deinit(conf, dev_data); + } + + return ret; } int icmsg_send(const struct icmsg_config_t *conf, @@ -332,13 +496,15 @@ int icmsg_send(const struct icmsg_config_t *conf, { int ret; int write_ret; -#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC int release_ret; -#endif int sent_bytes; + uint32_t state = atomic_get(&dev_data->state); - if (!is_endpoint_ready(dev_data)) { - return -EBUSY; + if (!is_endpoint_ready(state)) { + /* If instance was disconnected on the remote side, some threads may still + * don't know it yet and still may try to send messages. + */ + return (state == ICMSG_STATE_DISCONNECTED) ? len : -EBUSY; } /* Empty message is not allowed */ @@ -346,19 +512,15 @@ int icmsg_send(const struct icmsg_config_t *conf, return -ENODATA; } -#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC ret = reserve_tx_buffer_if_unused(dev_data); if (ret < 0) { return -ENOBUFS; } -#endif write_ret = pbuf_write(dev_data->tx_pb, msg, len); -#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC release_ret = release_tx_buffer(dev_data); __ASSERT_NO_MSG(!release_ret); -#endif if (write_ret < 0) { return write_ret; diff --git a/subsys/ipc/ipc_service/lib/pbuf.c b/subsys/ipc/ipc_service/lib/pbuf.c index d96b6106cf8fb..d45c86bcd517f 100644 --- a/subsys/ipc/ipc_service/lib/pbuf.c +++ b/subsys/ipc/ipc_service/lib/pbuf.c @@ -38,6 +38,7 @@ static int validate_cfg(const struct pbuf_cfg *cfg) /* Validate pointer alignment. */ if (!IS_PTR_ALIGNED_BYTES(cfg->rd_idx_loc, MAX(cfg->dcache_alignment, _PBUF_IDX_SIZE)) || !IS_PTR_ALIGNED_BYTES(cfg->wr_idx_loc, MAX(cfg->dcache_alignment, _PBUF_IDX_SIZE)) || + !IS_PTR_ALIGNED_BYTES(cfg->handshake_loc, _PBUF_IDX_SIZE) || !IS_PTR_ALIGNED_BYTES(cfg->data_loc, _PBUF_IDX_SIZE)) { return -EINVAL; } @@ -49,6 +50,8 @@ static int validate_cfg(const struct pbuf_cfg *cfg) /* Validate pointer values. */ if (!(cfg->rd_idx_loc < cfg->wr_idx_loc) || + (cfg->handshake_loc && !(cfg->rd_idx_loc < cfg->handshake_loc)) || + !(cfg->handshake_loc < cfg->wr_idx_loc) || !((uint8_t *)cfg->wr_idx_loc < cfg->data_loc) || !(((uint8_t *)cfg->rd_idx_loc + MAX(_PBUF_IDX_SIZE, cfg->dcache_alignment)) == (uint8_t *)cfg->wr_idx_loc)) { @@ -176,6 +179,44 @@ int pbuf_write(struct pbuf *pb, const char *data, uint16_t len) return len; } +int pbuf_get_initial_buf(struct pbuf *pb, volatile char **buf, uint16_t *len) +{ + uint32_t wr_idx; + uint16_t plen; + + if (pb == NULL || pb->data.rd_idx != 0) { + /* Incorrect call. */ + return -EINVAL; + } + + sys_cache_data_invd_range((void *)(pb->cfg->wr_idx_loc), sizeof(*(pb->cfg->wr_idx_loc))); + __sync_synchronize(); + + wr_idx = *(pb->cfg->wr_idx_loc); + if (wr_idx >= pb->cfg->len || wr_idx > 0xFFFF || wr_idx == 0) { + /* Wrong index - probably pbuf was not initialized or message was not send yet. */ + return -EINVAL; + } + + sys_cache_data_invd_range((void *)(pb->cfg->data_loc), PBUF_PACKET_LEN_SZ); + __sync_synchronize(); + + plen = sys_get_be16(&pb->cfg->data_loc[0]); + + if (plen + 4 > wr_idx) { + /* Wrong length - probably pbuf was not initialized or message was not send yet. */ + return -EINVAL; + } + + *buf = &pb->cfg->data_loc[PBUF_PACKET_LEN_SZ]; + *len = plen; + + sys_cache_data_invd_range((void *)*buf, plen); + __sync_synchronize(); + + return 0; +} + int pbuf_read(struct pbuf *pb, char *buf, uint16_t len) { if (pb == NULL) { @@ -253,3 +294,23 @@ int pbuf_read(struct pbuf *pb, char *buf, uint16_t len) return len; } + +uint32_t pbuf_handshake_read(struct pbuf *pb) +{ + volatile uint32_t *ptr = pb->cfg->handshake_loc; + + __ASSERT_NO_MSG(ptr); + sys_cache_data_invd_range((void *)ptr, sizeof(*ptr)); + __sync_synchronize(); + return *ptr; +} + +void pbuf_handshake_write(struct pbuf *pb, uint32_t value) +{ + volatile uint32_t *ptr = pb->cfg->handshake_loc; + + __ASSERT_NO_MSG(ptr); + *ptr = value; + __sync_synchronize(); + sys_cache_data_flush_range((void *)ptr, sizeof(*ptr)); +} From 0e4efdb2a6b09f87e80d1ac3a90612dd2124a491 Mon Sep 17 00:00:00 2001 From: Dominik Kilian Date: Fri, 24 Jan 2025 12:26:46 +0100 Subject: [PATCH 0192/6055] tests: ipc_service: Test restarting session in different scenarios This commit adds a test that checks if disconnecting and restarting the IPC session works correctly. The test is also focused on the "unbound" callback. Signed-off-by: Dominik Kilian Co-authored-by: Radoslaw Koppel --- scripts/ci/check_compliance.py | 2 + tests/subsys/ipc/ipc_sessions/CMakeLists.txt | 16 + tests/subsys/ipc/ipc_sessions/Kconfig | 37 ++ .../subsys/ipc/ipc_sessions/Kconfig.sysbuild | 13 + .../boards/nrf5340dk_nrf5340_cpuapp.conf | 7 + .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 37 ++ .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 12 + .../nrf54h20dk_nrf54h20_cpuapp_cpuppr.overlay | 26 + .../ipc/ipc_sessions/common/test_commands.h | 81 +++ .../ipc/ipc_sessions/interoperability/Kconfig | 29 ++ .../interoperability/Kconfig.icmsg_v1 | 90 ++++ .../ipc_sessions/interoperability/icmsg_v1.c | 392 +++++++++++++++ .../ipc_sessions/interoperability/icmsg_v1.h | 168 +++++++ .../interoperability/ipc_icmsg_v1.c | 86 ++++ .../interoperability/ipc_icmsg_v1.h | 5 + .../ipc_sessions/interoperability/pbuf_v1.c | 255 ++++++++++ .../ipc_sessions/interoperability/pbuf_v1.h | 234 +++++++++ tests/subsys/ipc/ipc_sessions/prj.conf | 10 + .../ipc/ipc_sessions/remote/CMakeLists.txt | 19 + tests/subsys/ipc/ipc_sessions/remote/Kconfig | 11 + .../boards/nrf5340dk_nrf5340_cpunet.overlay | 36 ++ .../boards/nrf54h20dk_nrf54h20_cpuppr.conf | 1 + .../boards/nrf54h20dk_nrf54h20_cpuppr.overlay | 31 ++ .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 15 + tests/subsys/ipc/ipc_sessions/remote/prj.conf | 23 + .../ipc/ipc_sessions/remote/src/remote.c | 452 +++++++++++++++++ .../subsys/ipc/ipc_sessions/src/data_queue.c | 65 +++ .../subsys/ipc/ipc_sessions/src/data_queue.h | 25 + tests/subsys/ipc/ipc_sessions/src/main.c | 469 ++++++++++++++++++ tests/subsys/ipc/ipc_sessions/sysbuild.cmake | 26 + .../ipc/ipc_sessions/sysbuild_cpuppr.conf | 4 + tests/subsys/ipc/ipc_sessions/testcase.yaml | 50 ++ tests/subsys/ipc/pbuf/src/main.c | 12 +- 33 files changed, 2734 insertions(+), 5 deletions(-) create mode 100644 tests/subsys/ipc/ipc_sessions/CMakeLists.txt create mode 100644 tests/subsys/ipc/ipc_sessions/Kconfig create mode 100644 tests/subsys/ipc/ipc_sessions/Kconfig.sysbuild create mode 100644 tests/subsys/ipc/ipc_sessions/boards/nrf5340dk_nrf5340_cpuapp.conf create mode 100644 tests/subsys/ipc/ipc_sessions/boards/nrf5340dk_nrf5340_cpuapp.overlay create mode 100644 tests/subsys/ipc/ipc_sessions/boards/nrf54h20dk_nrf54h20_cpuapp.overlay create mode 100644 tests/subsys/ipc/ipc_sessions/boards/nrf54h20dk_nrf54h20_cpuapp_cpuppr.overlay create mode 100644 tests/subsys/ipc/ipc_sessions/common/test_commands.h create mode 100644 tests/subsys/ipc/ipc_sessions/interoperability/Kconfig create mode 100644 tests/subsys/ipc/ipc_sessions/interoperability/Kconfig.icmsg_v1 create mode 100644 tests/subsys/ipc/ipc_sessions/interoperability/icmsg_v1.c create mode 100644 tests/subsys/ipc/ipc_sessions/interoperability/icmsg_v1.h create mode 100644 tests/subsys/ipc/ipc_sessions/interoperability/ipc_icmsg_v1.c create mode 100644 tests/subsys/ipc/ipc_sessions/interoperability/ipc_icmsg_v1.h create mode 100644 tests/subsys/ipc/ipc_sessions/interoperability/pbuf_v1.c create mode 100644 tests/subsys/ipc/ipc_sessions/interoperability/pbuf_v1.h create mode 100644 tests/subsys/ipc/ipc_sessions/prj.conf create mode 100644 tests/subsys/ipc/ipc_sessions/remote/CMakeLists.txt create mode 100644 tests/subsys/ipc/ipc_sessions/remote/Kconfig create mode 100644 tests/subsys/ipc/ipc_sessions/remote/boards/nrf5340dk_nrf5340_cpunet.overlay create mode 100644 tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpuppr.conf create mode 100644 tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpuppr.overlay create mode 100644 tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay create mode 100644 tests/subsys/ipc/ipc_sessions/remote/prj.conf create mode 100644 tests/subsys/ipc/ipc_sessions/remote/src/remote.c create mode 100644 tests/subsys/ipc/ipc_sessions/src/data_queue.c create mode 100644 tests/subsys/ipc/ipc_sessions/src/data_queue.h create mode 100644 tests/subsys/ipc/ipc_sessions/src/main.c create mode 100644 tests/subsys/ipc/ipc_sessions/sysbuild.cmake create mode 100644 tests/subsys/ipc/ipc_sessions/sysbuild_cpuppr.conf create mode 100644 tests/subsys/ipc/ipc_sessions/testcase.yaml diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 7155a8a859bb8..81ebf8733929f 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -1059,6 +1059,8 @@ def check_no_undef_outside_kconfig(self, kconf): "FOO_SETTING_2", "HEAP_MEM_POOL_ADD_SIZE_", # Used as an option matching prefix "HUGETLBFS", # Linux, in boards/xtensa/intel_adsp_cavs25/doc + "IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS", # Used in ICMsg tests for intercompatibility + # with older versions of the ICMsg. "LIBGCC_RTLIB", "LLVM_USE_LD", # Both LLVM_USE_* are in cmake/toolchain/llvm/Kconfig "LLVM_USE_LLD", # which are only included if LLVM is selected but diff --git a/tests/subsys/ipc/ipc_sessions/CMakeLists.txt b/tests/subsys/ipc/ipc_sessions/CMakeLists.txt new file mode 100644 index 0000000000000..79b2b9c49c36f --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright 2021 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ipc_service) + +zephyr_include_directories(./common) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +zephyr_sources_ifdef(CONFIG_IPC_SERVICE_ICMSG_V1 interoperability/icmsg_v1.c) +zephyr_sources_ifdef(CONFIG_PBUF_V1 interoperability/pbuf_v1.c) +zephyr_sources_ifdef(CONFIG_IPC_SERVICE_BACKEND_ICMSG_V1 interoperability/ipc_icmsg_v1.c) diff --git a/tests/subsys/ipc/ipc_sessions/Kconfig b/tests/subsys/ipc/ipc_sessions/Kconfig new file mode 100644 index 0000000000000..1c1ec5f3725cc --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/Kconfig @@ -0,0 +1,37 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +rsource "interoperability/Kconfig" + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config IPC_TEST_MSG_HEAP_SIZE + int "The heap to copy processed messages" + default 512 + help + Internal heap where all the message data would be copied to be processed + linearry in tests. + +config IPC_TEST_SKIP_CORE_RESET + bool "Skip the tests that includes core resetting" + help + Some of the cores cannot be safely restarted. + Skip the tests that require it in such a cases. + +config IPC_TEST_BLOCK_SIZE + int "Block size for multiple transfers test" + default 32 + +config IPC_TEST_BLOCK_CNT + int "Number of blocks for multiple transfers test" + default 8000 + +config IPC_TEST_SKIP_UNBOUND + bool "Skip unbound tests" + help + Whether to skip tests that requires unbound callback functionality. diff --git a/tests/subsys/ipc/ipc_sessions/Kconfig.sysbuild b/tests/subsys/ipc/ipc_sessions/Kconfig.sysbuild new file mode 100644 index 0000000000000..3c064f59d5250 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/Kconfig.sysbuild @@ -0,0 +1,13 @@ +# +# 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" + default "nrf5340dk/nrf5340/cpunet" if BOARD_NRF5340DK_NRF5340_CPUAPP + default "nrf5340dk/nrf5340/cpunet" if BOARD_NRF5340DK_NRF5340_CPUAPP_NS + default "nrf54h20dk/nrf54h20/cpurad" if BOARD_NRF54H20DK_NRF54H20_CPUAPP diff --git a/tests/subsys/ipc/ipc_sessions/boards/nrf5340dk_nrf5340_cpuapp.conf b/tests/subsys/ipc/ipc_sessions/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 0000000000000..4946c417b1612 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,7 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_NRF53_CPUNET_ENABLE=y diff --git a/tests/subsys/ipc/ipc_sessions/boards/nrf5340dk_nrf5340_cpuapp.overlay b/tests/subsys/ipc/ipc_sessions/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 0000000000000..d87bb33b3b314 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &ipc0; + +/ { + chosen { + /delete-property/ zephyr,ipc_shm; + /delete-property/ zephyr,bt-hci; + }; + + reserved-memory { + /delete-node/ memory@20070000; + + sram_tx: memory@20070000 { + reg = <0x20070000 0x8000>; + }; + + sram_rx: memory@20078000 { + reg = <0x20078000 0x8000>; + }; + }; + + ipc0: ipc0 { + compatible = "zephyr,ipc-icmsg"; + tx-region = <&sram_tx>; + rx-region = <&sram_rx>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "tx", "rx"; + dcache-alignment = <8>; + unbound = "detect"; + status = "okay"; + }; +}; diff --git a/tests/subsys/ipc/ipc_sessions/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/subsys/ipc/ipc_sessions/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 0000000000000..68efc08002249 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Replace default ipc0 instance */ +&ipc0 { + compatible = "zephyr,ipc-icmsg"; + /delete-property/ tx-blocks; + /delete-property/ rx-blocks; + unbound = "enable"; +}; diff --git a/tests/subsys/ipc/ipc_sessions/boards/nrf54h20dk_nrf54h20_cpuapp_cpuppr.overlay b/tests/subsys/ipc/ipc_sessions/boards/nrf54h20dk_nrf54h20_cpuapp_cpuppr.overlay new file mode 100644 index 0000000000000..90ef82327e9fa --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/boards/nrf54h20dk_nrf54h20_cpuapp_cpuppr.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Replace default ipc0 instance */ +/delete-node/ &ipc0; + +ipc0: &cpuapp_cpuppr_ipc { + status = "okay"; + unbound = "detect"; +}; + +&cpuppr_vevif { + status = "okay"; +}; + +&cpuapp_bellboard { + status = "okay"; +}; + +/ { + chosen { + /delete-property/ zephyr,bt-hci; + }; +}; diff --git a/tests/subsys/ipc/ipc_sessions/common/test_commands.h b/tests/subsys/ipc/ipc_sessions/common/test_commands.h new file mode 100644 index 0000000000000..f992d34d52ea9 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/common/test_commands.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef TEST_COMMANDS_H +#include + +/** + * @brief Test commands executable by remote + */ +enum ipc_test_commands { + IPC_TEST_CMD_NONE, /**< Command to be ingored */ + IPC_TEST_CMD_PING, /**< Respond with the @ref IPC_TEST_CMD_PONG message */ + IPC_TEST_CMD_PONG, /**< Expected response to IPC_TEST_CMD_PING */ + IPC_TEST_CMD_ECHO, /**< Respond with the same data */ + IPC_TEST_CMD_ECHO_RSP, /**< Echo respond */ + IPC_TEST_CMD_REBOND, /**< Unbond and rebond back whole interface */ + IPC_TEST_CMD_REBOOT, /**< Restart remote CPU after a given delay */ + /* Commands used for data transfer test */ + IPC_TEST_CMD_RXSTART, /**< Start receiving data */ + IPC_TEST_CMD_TXSTART, /**< Start sending data */ + IPC_TEST_CMD_RXGET, /**< Get rx status */ + IPC_TEST_CMD_TXGET, /**< Get tx status */ + IPC_TEST_CMD_XSTAT, /**< rx/tx status response */ + IPC_TEST_CMD_XDATA, /**< Transfer data block */ + /* End of commands used for data transfer test */ +}; + +/** + * @brief Base command structure + */ +struct ipc_test_cmd { + uint32_t cmd; /**< The command of @ref ipc_test_command type */ + uint8_t data[]; /**< Command data depending on the command itself */ +}; + +/** + * @brief Rebond command structure + */ +struct ipc_test_cmd_rebond { + struct ipc_test_cmd base; + uint32_t timeout_ms; +}; + +/** + * @brief Reboot command structure + */ +struct ipc_test_cmd_reboot { + struct ipc_test_cmd base; + uint32_t timeout_ms; +}; + +/** + * @brief Start the rx or tx transfer + */ +struct ipc_test_cmd_xstart { + struct ipc_test_cmd base; + uint32_t blk_size; + uint32_t blk_cnt; + uint32_t seed; +}; + +/** + * @brief Get the status of rx or tx transfer + */ +struct ipc_test_cmd_xstat { + struct ipc_test_cmd base; + uint32_t blk_cnt; /**< Transfers left */ + int32_t result; /**< Current result */ +}; + +/** + * @brief The result of rx or tx transfer + */ +struct ipc_test_cmd_xrsp { + struct ipc_test_cmd base; + int32_t result; +}; + +#endif /* TEST_COMMANDS_H */ diff --git a/tests/subsys/ipc/ipc_sessions/interoperability/Kconfig b/tests/subsys/ipc/ipc_sessions/interoperability/Kconfig new file mode 100644 index 0000000000000..e50f208b15348 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/interoperability/Kconfig @@ -0,0 +1,29 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +config IPC_SERVICE_BACKEND_ICMSG + default n if IPC_SERVICE_BACKEND_ICMSG_V1 + +config IPC_SERVICE_ICMSG + default n if IPC_SERVICE_ICMSG_V1 + +config IPC_SERVICE_BACKEND_ICMSG_V1 + bool "ICMSG backend with SPSC packet buffer (old implementation)" + depends on MBOX + select IPC_SERVICE_ICMSG_V1 + help + Chosing this backend results in single endpoint implementation based + on circular packet buffer. + +menuconfig IPC_SERVICE_ICMSG_V1 + bool "icmsg IPC library (old implementation)" + select PBUF_V1 + help + Icmsg library + +if IPC_SERVICE_ICMSG_V1 + rsource "Kconfig.icmsg_v1" +endif diff --git a/tests/subsys/ipc/ipc_sessions/interoperability/Kconfig.icmsg_v1 b/tests/subsys/ipc/ipc_sessions/interoperability/Kconfig.icmsg_v1 new file mode 100644 index 0000000000000..463a1a0ad3cea --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/interoperability/Kconfig.icmsg_v1 @@ -0,0 +1,90 @@ +# Copyright (c) 2022 Nordic Semiconductor (ASA) +# SPDX-License-Identifier: Apache-2.0 + +config IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC_V1 + bool "Synchronize access to shared memory" + depends on MULTITHREADING + default y + help + Provide synchronization access to shared memory at a library level. + This option is enabled by default to allow to use sending API from + multiple contexts. Mutex is used to guard access to the memory. + This option can be safely disabled if an application ensures data + are sent from single context. + +config IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS_V1 + int "Mutex lock timeout in milliseconds" + depends on IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC_V1 + range 1 5 + default 1 + help + Maximum time to wait, in milliseconds, for access to send data with + backends basing on icmsg library. This time should be relatively low. + +config IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS_V1 + int "Bond notification timeout in miliseconds" + range 1 100 + default 1 + help + Time to wait for remote bonding notification before the + notification is repeated. + +config IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE_V1 + bool "Use dedicated workqueue" + depends on MULTITHREADING + default y + help + Enable dedicated workqueue thread for the ICMsg backend. + Disabling this configuration will cause the ICMsg backend to + process incoming data through the system workqueue context, and + therefore reduces the RAM footprint of the backend. + Disabling this config may result in deadlocks in certain usage + scenarios, such as when synchronous IPC is executed from the system + workqueue context. + The callbacks coming from the backend are executed from the workqueue + context. + When the option is disabled, the user must obey the restrictions + imposed by the system workqueue, such as never performing blocking + operations from within the callback. + +if IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE_V1 + +config IPC_SERVICE_BACKEND_ICMSG_WQ_STACK_SIZE_V1 + int "Size of RX work queue stack" + default 1280 + help + Size of stack used by work queue RX thread. This work queue is + created to prevent notifying service users about received data + from the system work queue. The queue is shared among instances. + +config IPC_SERVICE_BACKEND_ICMSG_WQ_PRIORITY_V1 + int "Priority of RX work queue thread" + default -1 + range -256 -1 + help + Priority of the ICMSG RX work queue thread. + The ICMSG library in its simplicity requires the workqueue to execute + at a cooperative priority. + +endif + +# The Icmsg library in its simplicity requires the system workqueue to execute +# at a cooperative priority. +config SYSTEM_WORKQUEUE_PRIORITY + range -256 -1 if !IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE_V1 + +config PBUF_V1 + bool "Packed buffer support library (old implementation)" + help + The packet buffer implements lightweight unidirectional packet buffer + with read/write semantics on top of a memory region shared by the + reader and writer. It optionally embeds cache and memory barrier + management to ensure correct data access. + +if PBUF_V1 + +config PBUF_RX_READ_BUF_SIZE_V1 + int "Size of PBUF read buffer in bytes" + default 128 + +endif # PBUF diff --git a/tests/subsys/ipc/ipc_sessions/interoperability/icmsg_v1.c b/tests/subsys/ipc/ipc_sessions/interoperability/icmsg_v1.c new file mode 100644 index 0000000000000..ae83dd30beb94 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/interoperability/icmsg_v1.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "icmsg_v1.h" + +#include +#include +#include +#include "pbuf_v1.h" +#include + +#define BOND_NOTIFY_REPEAT_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS) +#define SHMEM_ACCESS_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS) + +static const uint8_t magic[] = {0x45, 0x6d, 0x31, 0x6c, 0x31, 0x4b, + 0x30, 0x72, 0x6e, 0x33, 0x6c, 0x69, 0x34}; + +#ifdef CONFIG_MULTITHREADING +#if defined(CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE) +static K_THREAD_STACK_DEFINE(icmsg_stack, CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_STACK_SIZE); +static struct k_work_q icmsg_workq; +static struct k_work_q *const workq = &icmsg_workq; +#else +static struct k_work_q *const workq = &k_sys_work_q; +#endif +static void mbox_callback_process(struct k_work *item); +#else +static void mbox_callback_process(struct icmsg_data_t *dev_data); +#endif + +static int mbox_deinit(const struct icmsg_config_t *conf, + struct icmsg_data_t *dev_data) +{ + int err; + + err = mbox_set_enabled_dt(&conf->mbox_rx, 0); + if (err != 0) { + return err; + } + + err = mbox_register_callback_dt(&conf->mbox_rx, NULL, NULL); + if (err != 0) { + return err; + } + +#ifdef CONFIG_MULTITHREADING + (void)k_work_cancel(&dev_data->mbox_work); + (void)k_work_cancel_delayable(&dev_data->notify_work); +#endif + + return 0; +} + +static bool is_endpoint_ready(struct icmsg_data_t *dev_data) +{ + return atomic_get(&dev_data->state) == ICMSG_STATE_READY; +} + +#ifdef CONFIG_MULTITHREADING +static void notify_process(struct k_work *item) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(item); + struct icmsg_data_t *dev_data = + CONTAINER_OF(dwork, struct icmsg_data_t, notify_work); + + (void)mbox_send_dt(&dev_data->cfg->mbox_tx, NULL); + + atomic_t state = atomic_get(&dev_data->state); + + if (state != ICMSG_STATE_READY) { + int ret; + + ret = k_work_reschedule_for_queue(workq, dwork, BOND_NOTIFY_REPEAT_TO); + __ASSERT_NO_MSG(ret >= 0); + (void)ret; + } +} +#else +static void notify_process(struct icmsg_data_t *dev_data) +{ + (void)mbox_send_dt(&dev_data->cfg->mbox_tx, NULL); +#if defined(CONFIG_SYS_CLOCK_EXISTS) + int64_t start = k_uptime_get(); +#endif + + while (false == is_endpoint_ready(dev_data)) { + mbox_callback_process(dev_data); + +#if defined(CONFIG_SYS_CLOCK_EXISTS) + if ((k_uptime_get() - start) > CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS) { +#endif + (void)mbox_send_dt(&dev_data->cfg->mbox_tx, NULL); +#if defined(CONFIG_SYS_CLOCK_EXISTS) + start = k_uptime_get(); + }; +#endif + } +} +#endif + +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC +static int reserve_tx_buffer_if_unused(struct icmsg_data_t *dev_data) +{ + int ret = k_mutex_lock(&dev_data->tx_lock, SHMEM_ACCESS_TO); + + if (ret < 0) { + return ret; + } + + return 0; +} + +static int release_tx_buffer(struct icmsg_data_t *dev_data) +{ + return k_mutex_unlock(&dev_data->tx_lock); +} +#endif + +static uint32_t data_available(struct icmsg_data_t *dev_data) +{ + return pbuf_read(dev_data->rx_pb, NULL, 0); +} + +#ifdef CONFIG_MULTITHREADING +static void submit_mbox_work(struct icmsg_data_t *dev_data) +{ + if (k_work_submit_to_queue(workq, &dev_data->mbox_work) < 0) { + /* The mbox processing work is never canceled. + * The negative error code should never be seen. + */ + __ASSERT_NO_MSG(false); + } +} + +static void submit_work_if_buffer_free(struct icmsg_data_t *dev_data) +{ + submit_mbox_work(dev_data); +} + +static void submit_work_if_buffer_free_and_data_available( + struct icmsg_data_t *dev_data) +{ + if (!data_available(dev_data)) { + return; + } + + submit_mbox_work(dev_data); +} +#else +static void submit_if_buffer_free(struct icmsg_data_t *dev_data) +{ + mbox_callback_process(dev_data); +} + +static void submit_if_buffer_free_and_data_available( + struct icmsg_data_t *dev_data) +{ + + if (!data_available(dev_data)) { + return; + } + + mbox_callback_process(dev_data); +} +#endif + +#ifdef CONFIG_MULTITHREADING +static void mbox_callback_process(struct k_work *item) +#else +static void mbox_callback_process(struct icmsg_data_t *dev_data) +#endif +{ +#ifdef CONFIG_MULTITHREADING + struct icmsg_data_t *dev_data = CONTAINER_OF(item, struct icmsg_data_t, mbox_work); +#endif + uint8_t rx_buffer[CONFIG_PBUF_RX_READ_BUF_SIZE] __aligned(4); + + atomic_t state = atomic_get(&dev_data->state); + + uint32_t len = data_available(dev_data); + + if (len == 0) { + /* Unlikely, no data in buffer. */ + return; + } + + __ASSERT_NO_MSG(len <= sizeof(rx_buffer)); + + if (sizeof(rx_buffer) < len) { + return; + } + + len = pbuf_read(dev_data->rx_pb, rx_buffer, sizeof(rx_buffer)); + + if (state == ICMSG_STATE_READY) { + if (dev_data->cb->received) { + dev_data->cb->received(rx_buffer, len, dev_data->ctx); + } + } else { + __ASSERT_NO_MSG(state == ICMSG_STATE_BUSY); + + /* Allow magic number longer than sizeof(magic) for future protocol version. */ + bool endpoint_invalid = (len < sizeof(magic) || + memcmp(magic, rx_buffer, sizeof(magic))); + + if (endpoint_invalid) { + __ASSERT_NO_MSG(false); + return; + } + + if (dev_data->cb->bound) { + dev_data->cb->bound(dev_data->ctx); + } + + atomic_set(&dev_data->state, ICMSG_STATE_READY); + } +#ifdef CONFIG_MULTITHREADING + submit_work_if_buffer_free_and_data_available(dev_data); +#else + submit_if_buffer_free_and_data_available(dev_data); +#endif +} + +static void mbox_callback(const struct device *instance, uint32_t channel, + void *user_data, struct mbox_msg *msg_data) +{ + struct icmsg_data_t *dev_data = user_data; +#ifdef CONFIG_MULTITHREADING + submit_work_if_buffer_free(dev_data); +#else + submit_if_buffer_free(dev_data); +#endif +} + +static int mbox_init(const struct icmsg_config_t *conf, + struct icmsg_data_t *dev_data) +{ + int err; + +#ifdef CONFIG_MULTITHREADING + k_work_init(&dev_data->mbox_work, mbox_callback_process); + k_work_init_delayable(&dev_data->notify_work, notify_process); +#endif + + err = mbox_register_callback_dt(&conf->mbox_rx, mbox_callback, dev_data); + if (err != 0) { + return err; + } + + return mbox_set_enabled_dt(&conf->mbox_rx, 1); +} + +int icmsg_open(const struct icmsg_config_t *conf, + struct icmsg_data_t *dev_data, + const struct ipc_service_cb *cb, void *ctx) +{ + if (!atomic_cas(&dev_data->state, ICMSG_STATE_OFF, ICMSG_STATE_BUSY)) { + /* Already opened. */ + return -EALREADY; + } + + dev_data->cb = cb; + dev_data->ctx = ctx; + dev_data->cfg = conf; + +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC + k_mutex_init(&dev_data->tx_lock); +#endif + + int ret = pbuf_tx_init(dev_data->tx_pb); + + if (ret < 0) { + __ASSERT(false, "Incorrect configuration"); + return ret; + } + + (void)pbuf_rx_init(dev_data->rx_pb); + + ret = pbuf_write(dev_data->tx_pb, magic, sizeof(magic)); + + if (ret < 0) { + __ASSERT_NO_MSG(false); + return ret; + } + + if (ret < (int)sizeof(magic)) { + __ASSERT_NO_MSG(ret == sizeof(magic)); + return ret; + } + + ret = mbox_init(conf, dev_data); + if (ret) { + return ret; + } +#ifdef CONFIG_MULTITHREADING + ret = k_work_schedule_for_queue(workq, &dev_data->notify_work, K_NO_WAIT); + if (ret < 0) { + return ret; + } +#else + notify_process(dev_data); +#endif + return 0; +} + +int icmsg_close(const struct icmsg_config_t *conf, + struct icmsg_data_t *dev_data) +{ + int ret; + + ret = mbox_deinit(conf, dev_data); + if (ret) { + return ret; + } + + atomic_set(&dev_data->state, ICMSG_STATE_OFF); + + return 0; +} + +int icmsg_send(const struct icmsg_config_t *conf, + struct icmsg_data_t *dev_data, + const void *msg, size_t len) +{ + int ret; + int write_ret; +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC + int release_ret; +#endif + int sent_bytes; + + if (!is_endpoint_ready(dev_data)) { + return -EBUSY; + } + + /* Empty message is not allowed */ + if (len == 0) { + return -ENODATA; + } + +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC + ret = reserve_tx_buffer_if_unused(dev_data); + if (ret < 0) { + return -ENOBUFS; + } +#endif + + write_ret = pbuf_write(dev_data->tx_pb, msg, len); + +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC + release_ret = release_tx_buffer(dev_data); + __ASSERT_NO_MSG(!release_ret); +#endif + + if (write_ret < 0) { + return write_ret; + } else if (write_ret < len) { + return -EBADMSG; + } + sent_bytes = write_ret; + + __ASSERT_NO_MSG(conf->mbox_tx.dev != NULL); + + ret = mbox_send_dt(&conf->mbox_tx, NULL); + if (ret) { + return ret; + } + + return sent_bytes; +} + +#if defined(CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE) + +static int work_q_init(void) +{ + struct k_work_queue_config cfg = { + .name = "icmsg_workq", + }; + + k_work_queue_start(&icmsg_workq, + icmsg_stack, + K_KERNEL_STACK_SIZEOF(icmsg_stack), + CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_PRIORITY, &cfg); + return 0; +} + +SYS_INIT(work_q_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +#endif diff --git a/tests/subsys/ipc/ipc_sessions/interoperability/icmsg_v1.h b/tests/subsys/ipc/ipc_sessions/interoperability/icmsg_v1.h new file mode 100644 index 0000000000000..b0f2849765d2a --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/interoperability/icmsg_v1.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_IPC_ICMSG_H_ +#define ZEPHYR_INCLUDE_IPC_ICMSG_H_ + +#include +#include +#include +#include +#include +#include "pbuf_v1.h" +#include + +/* Config aliases that prevenets from config collisions: */ +#undef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC_V1 +#define CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC_V1 +#endif +#undef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS_V1 +#define CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS_V1 +#endif +#undef CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS +#ifdef CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS_V1 +#define CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS \ + CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS_V1 +#endif +#undef CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE +#ifdef CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE_V1 +#define CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE_V1 +#endif +#undef CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_STACK_SIZE +#ifdef CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_STACK_SIZE_V1 +#define CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_STACK_SIZE \ + CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_STACK_SIZE_V1 +#endif +#undef CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_PRIORITY +#ifdef CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_PRIORITY_V1 +#define CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_PRIORITY CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_PRIORITY_V1 +#endif +#undef CONFIG_PBUF_RX_READ_BUF_SIZE +#ifdef CONFIG_PBUF_RX_READ_BUF_SIZE_V1 +#define CONFIG_PBUF_RX_READ_BUF_SIZE CONFIG_PBUF_RX_READ_BUF_SIZE_V1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Icmsg IPC library API + * @defgroup ipc_icmsg_api Icmsg IPC library API + * @ingroup ipc + * @{ + */ + +enum icmsg_state { + ICMSG_STATE_OFF, + ICMSG_STATE_BUSY, + ICMSG_STATE_READY, +}; + +struct icmsg_config_t { + struct mbox_dt_spec mbox_tx; + struct mbox_dt_spec mbox_rx; +}; + +struct icmsg_data_t { + /* Tx/Rx buffers. */ + struct pbuf *tx_pb; + struct pbuf *rx_pb; +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC + struct k_mutex tx_lock; +#endif + + /* Callbacks for an endpoint. */ + const struct ipc_service_cb *cb; + void *ctx; + + /* General */ + const struct icmsg_config_t *cfg; +#ifdef CONFIG_MULTITHREADING + struct k_work_delayable notify_work; + struct k_work mbox_work; +#endif + atomic_t state; +}; + +/** @brief Open an icmsg instance + * + * Open an icmsg instance to be able to send and receive messages to a remote + * instance. + * This function is blocking until the handshake with the remote instance is + * completed. + * This function is intended to be called late in the initialization process, + * possibly from a thread which can be safely blocked while handshake with the + * remote instance is being pefromed. + * + * @param[in] conf Structure containing configuration parameters for the icmsg + * instance. + * @param[inout] dev_data Structure containing run-time data used by the icmsg + * instance. + * @param[in] cb Structure containing callback functions to be called on + * events generated by this icmsg instance. The pointed memory + * must be preserved while the icmsg instance is active. + * @param[in] ctx Pointer to context passed as an argument to callbacks. + * + * + * @retval 0 on success. + * @retval -EALREADY when the instance is already opened. + * @retval other errno codes from dependent modules. + */ +int icmsg_open(const struct icmsg_config_t *conf, + struct icmsg_data_t *dev_data, + const struct ipc_service_cb *cb, void *ctx); + +/** @brief Close an icmsg instance + * + * Closing an icmsg instance results in releasing all resources used by given + * instance including the shared memory regions and mbox devices. + * + * @param[in] conf Structure containing configuration parameters for the icmsg + * instance being closed. Its content must be the same as used + * for creating this instance with @ref icmsg_open. + * @param[inout] dev_data Structure containing run-time data used by the icmsg + * instance. + * + * @retval 0 on success. + * @retval other errno codes from dependent modules. + */ +int icmsg_close(const struct icmsg_config_t *conf, + struct icmsg_data_t *dev_data); + +/** @brief Send a message to the remote icmsg instance. + * + * @param[in] conf Structure containing configuration parameters for the icmsg + * instance. + * @param[inout] dev_data Structure containing run-time data used by the icmsg + * instance. + * @param[in] msg Pointer to a buffer containing data to send. + * @param[in] len Size of data in the @p msg buffer. + * + * + * @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. + * @retval -EBADMSG when the requested data to send is too big. + * @retval -ENOBUFS when there are no TX buffers available. + * @retval other errno codes from dependent modules. + */ +int icmsg_send(const struct icmsg_config_t *conf, + struct icmsg_data_t *dev_data, + const void *msg, size_t len); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_IPC_ICMSG_H_ */ diff --git a/tests/subsys/ipc/ipc_sessions/interoperability/ipc_icmsg_v1.c b/tests/subsys/ipc/ipc_sessions/interoperability/ipc_icmsg_v1.c new file mode 100644 index 0000000000000..4ce003667b052 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/interoperability/ipc_icmsg_v1.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "ipc_icmsg_v1.h" + +#include +#include +#include "icmsg_v1.h" + +#include + +#define DT_DRV_COMPAT zephyr_ipc_icmsg + +static int register_ept(const struct device *instance, void **token, + const struct ipc_ept_cfg *cfg) +{ + const struct icmsg_config_t *conf = instance->config; + struct icmsg_data_t *dev_data = instance->data; + + /* Only one endpoint is supported. No need for a token. */ + *token = NULL; + + return icmsg_open(conf, dev_data, &cfg->cb, cfg->priv); +} + +static int deregister_ept(const struct device *instance, void *token) +{ + const struct icmsg_config_t *conf = instance->config; + struct icmsg_data_t *dev_data = instance->data; + + return icmsg_close(conf, dev_data); +} + +static int send(const struct device *instance, void *token, + const void *msg, size_t len) +{ + const struct icmsg_config_t *conf = instance->config; + struct icmsg_data_t *dev_data = instance->data; + + return icmsg_send(conf, dev_data, msg, len); +} + +const static struct ipc_service_backend backend_ops = { + .register_endpoint = register_ept, + .deregister_endpoint = deregister_ept, + .send = send, +}; + +static int backend_init(const struct device *instance) +{ + return 0; +} + +#define DEFINE_BACKEND_DEVICE(i) \ + static const struct icmsg_config_t backend_config_##i = { \ + .mbox_tx = MBOX_DT_SPEC_INST_GET(i, tx), \ + .mbox_rx = MBOX_DT_SPEC_INST_GET(i, rx), \ + }; \ + \ + PBUF_DEFINE(tx_pb_##i, \ + DT_REG_ADDR(DT_INST_PHANDLE(i, tx_region)), \ + DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)), \ + DT_INST_PROP_OR(i, dcache_alignment, 0)); \ + PBUF_DEFINE(rx_pb_##i, \ + DT_REG_ADDR(DT_INST_PHANDLE(i, rx_region)), \ + DT_REG_SIZE(DT_INST_PHANDLE(i, rx_region)), \ + DT_INST_PROP_OR(i, dcache_alignment, 0)); \ + \ + static struct icmsg_data_t backend_data_##i = { \ + .tx_pb = &tx_pb_##i, \ + .rx_pb = &rx_pb_##i, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(i, \ + &backend_init, \ + NULL, \ + &backend_data_##i, \ + &backend_config_##i, \ + POST_KERNEL, \ + CONFIG_IPC_SERVICE_REG_BACKEND_PRIORITY, \ + &backend_ops); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_BACKEND_DEVICE) diff --git a/tests/subsys/ipc/ipc_sessions/interoperability/ipc_icmsg_v1.h b/tests/subsys/ipc/ipc_sessions/interoperability/ipc_icmsg_v1.h new file mode 100644 index 0000000000000..5407ea3e2e8c4 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/interoperability/ipc_icmsg_v1.h @@ -0,0 +1,5 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ diff --git a/tests/subsys/ipc/ipc_sessions/interoperability/pbuf_v1.c b/tests/subsys/ipc/ipc_sessions/interoperability/pbuf_v1.c new file mode 100644 index 0000000000000..7c72098af1d7d --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/interoperability/pbuf_v1.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "pbuf_v1.h" +#include + +#if defined(CONFIG_ARCH_POSIX) +#include +#endif + +/* Helper funciton for getting number of bytes being written to the buffer. */ +static uint32_t idx_occupied(uint32_t len, uint32_t wr_idx, uint32_t rd_idx) +{ + /* It is implicitly assumed wr_idx and rd_idx cannot differ by more then len. */ + return (rd_idx > wr_idx) ? (len - (rd_idx - wr_idx)) : (wr_idx - rd_idx); +} + +/* Helper function for wrapping the index from the begging if above buffer len. */ +static uint32_t idx_wrap(uint32_t len, uint32_t idx) +{ + return (idx >= len) ? (idx % len) : (idx); +} + +static int validate_cfg(const struct pbuf_cfg *cfg) +{ + /* Validate pointers. */ + if (!cfg || !cfg->rd_idx_loc || !cfg->wr_idx_loc || !cfg->data_loc) { + return -EINVAL; + } + + /* Validate pointer alignment. */ + if (!IS_PTR_ALIGNED_BYTES(cfg->rd_idx_loc, MAX(cfg->dcache_alignment, _PBUF_IDX_SIZE)) || + !IS_PTR_ALIGNED_BYTES(cfg->wr_idx_loc, MAX(cfg->dcache_alignment, _PBUF_IDX_SIZE)) || + !IS_PTR_ALIGNED_BYTES(cfg->data_loc, _PBUF_IDX_SIZE)) { + return -EINVAL; + } + + /* Validate len. */ + if (cfg->len < _PBUF_MIN_DATA_LEN || !IS_PTR_ALIGNED_BYTES(cfg->len, _PBUF_IDX_SIZE)) { + return -EINVAL; + } + + /* Validate pointer values. */ + if (!(cfg->rd_idx_loc < cfg->wr_idx_loc) || + !((uint8_t *)cfg->wr_idx_loc < cfg->data_loc) || + !(((uint8_t *)cfg->rd_idx_loc + MAX(_PBUF_IDX_SIZE, cfg->dcache_alignment)) == + (uint8_t *)cfg->wr_idx_loc)) { + return -EINVAL; + } + + return 0; +} + +#if defined(CONFIG_ARCH_POSIX) +void pbuf_native_addr_remap(struct pbuf *pb) +{ + native_emb_addr_remap((void **)&pb->cfg->rd_idx_loc); + native_emb_addr_remap((void **)&pb->cfg->wr_idx_loc); + native_emb_addr_remap((void **)&pb->cfg->data_loc); +} +#endif + +int pbuf_tx_init(struct pbuf *pb) +{ + if (validate_cfg(pb->cfg) != 0) { + return -EINVAL; + } +#if defined(CONFIG_ARCH_POSIX) + pbuf_native_addr_remap(pb); +#endif + + /* Initialize local copy of indexes. */ + pb->data.wr_idx = 0; + pb->data.rd_idx = 0; + + /* Clear shared memory. */ + *(pb->cfg->wr_idx_loc) = pb->data.wr_idx; + *(pb->cfg->rd_idx_loc) = pb->data.rd_idx; + + __sync_synchronize(); + + /* Take care cache. */ + sys_cache_data_flush_range((void *)(pb->cfg->wr_idx_loc), sizeof(*(pb->cfg->wr_idx_loc))); + sys_cache_data_flush_range((void *)(pb->cfg->rd_idx_loc), sizeof(*(pb->cfg->rd_idx_loc))); + + return 0; +} + +int pbuf_rx_init(struct pbuf *pb) +{ + if (validate_cfg(pb->cfg) != 0) { + return -EINVAL; + } +#if defined(CONFIG_ARCH_POSIX) + pbuf_native_addr_remap(pb); +#endif + + /* Initialize local copy of indexes. */ + pb->data.wr_idx = 0; + pb->data.rd_idx = 0; + + return 0; +} + +int pbuf_write(struct pbuf *pb, const char *data, uint16_t len) +{ + if (pb == NULL || len == 0 || data == NULL) { + /* Incorrect call. */ + return -EINVAL; + } + + /* Invalidate rd_idx only, local wr_idx is used to increase buffer security. */ + sys_cache_data_invd_range((void *)(pb->cfg->rd_idx_loc), sizeof(*(pb->cfg->rd_idx_loc))); + __sync_synchronize(); + + uint8_t *const data_loc = pb->cfg->data_loc; + const uint32_t blen = pb->cfg->len; + uint32_t rd_idx = *(pb->cfg->rd_idx_loc); + uint32_t wr_idx = pb->data.wr_idx; + + /* wr_idx must always be aligned. */ + __ASSERT_NO_MSG(IS_PTR_ALIGNED_BYTES(wr_idx, _PBUF_IDX_SIZE)); + /* rd_idx shall always be aligned, but its value is received from the reader. + * Can not assert. + */ + if (!IS_PTR_ALIGNED_BYTES(rd_idx, _PBUF_IDX_SIZE)) { + return -EINVAL; + } + + uint32_t free_space = blen - idx_occupied(blen, wr_idx, rd_idx) - _PBUF_IDX_SIZE; + + /* Packet length, data + packet length size. */ + uint32_t plen = len + PBUF_PACKET_LEN_SZ; + + /* Check if packet will fit into the buffer. */ + if (free_space < plen) { + return -ENOMEM; + } + + /* Clear packet len with zeros and update. Clearing is done for possible versioning in the + * future. Writing is allowed now, because shared wr_idx value is updated at the very end. + */ + *((uint32_t *)(&data_loc[wr_idx])) = 0; + sys_put_be16(len, &data_loc[wr_idx]); + __sync_synchronize(); + sys_cache_data_flush_range(&data_loc[wr_idx], PBUF_PACKET_LEN_SZ); + + wr_idx = idx_wrap(blen, wr_idx + PBUF_PACKET_LEN_SZ); + + /* Write until end of the buffer, if data will be wrapped. */ + uint32_t tail = MIN(len, blen - wr_idx); + + memcpy(&data_loc[wr_idx], data, tail); + sys_cache_data_flush_range(&data_loc[wr_idx], tail); + + if (len > tail) { + /* Copy remaining data to buffer front. */ + memcpy(&data_loc[0], data + tail, len - tail); + sys_cache_data_flush_range(&data_loc[0], len - tail); + } + + wr_idx = idx_wrap(blen, ROUND_UP(wr_idx + len, _PBUF_IDX_SIZE)); + /* Update wr_idx. */ + pb->data.wr_idx = wr_idx; + *(pb->cfg->wr_idx_loc) = wr_idx; + __sync_synchronize(); + sys_cache_data_flush_range((void *)pb->cfg->wr_idx_loc, sizeof(*(pb->cfg->wr_idx_loc))); + + return len; +} + +int pbuf_read(struct pbuf *pb, char *buf, uint16_t len) +{ + if (pb == NULL) { + /* Incorrect call. */ + return -EINVAL; + } + + /* Invalidate wr_idx only, local rd_idx is used to increase buffer security. */ + sys_cache_data_invd_range((void *)(pb->cfg->wr_idx_loc), sizeof(*(pb->cfg->wr_idx_loc))); + __sync_synchronize(); + + uint8_t *const data_loc = pb->cfg->data_loc; + const uint32_t blen = pb->cfg->len; + uint32_t wr_idx = *(pb->cfg->wr_idx_loc); + uint32_t rd_idx = pb->data.rd_idx; + + /* rd_idx must always be aligned. */ + __ASSERT_NO_MSG(IS_PTR_ALIGNED_BYTES(rd_idx, _PBUF_IDX_SIZE)); + /* wr_idx shall always be aligned, but its value is received from the + * writer. Can not assert. + */ + if (!IS_PTR_ALIGNED_BYTES(wr_idx, _PBUF_IDX_SIZE)) { + return -EINVAL; + } + + if (rd_idx == wr_idx) { + /* Buffer is empty. */ + return 0; + } + + /* Get packet len.*/ + sys_cache_data_invd_range(&data_loc[rd_idx], PBUF_PACKET_LEN_SZ); + uint16_t plen = sys_get_be16(&data_loc[rd_idx]); + + if (!buf) { + return (int)plen; + } + + if (plen > len) { + return -ENOMEM; + } + + uint32_t occupied_space = idx_occupied(blen, wr_idx, rd_idx); + + if (occupied_space < plen + PBUF_PACKET_LEN_SZ) { + /* This should never happen. */ + return -EAGAIN; + } + + rd_idx = idx_wrap(blen, rd_idx + PBUF_PACKET_LEN_SZ); + + /* Packet will fit into provided buffer, truncate len if provided len + * is bigger than necessary. + */ + len = MIN(plen, len); + + /* Read until end of the buffer, if data are wrapped. */ + uint32_t tail = MIN(blen - rd_idx, len); + + sys_cache_data_invd_range(&data_loc[rd_idx], tail); + memcpy(buf, &data_loc[rd_idx], tail); + + if (len > tail) { + sys_cache_data_invd_range(&data_loc[0], len - tail); + memcpy(&buf[tail], &pb->cfg->data_loc[0], len - tail); + } + + /* Update rd_idx. */ + rd_idx = idx_wrap(blen, ROUND_UP(rd_idx + len, _PBUF_IDX_SIZE)); + + pb->data.rd_idx = rd_idx; + *(pb->cfg->rd_idx_loc) = rd_idx; + __sync_synchronize(); + sys_cache_data_flush_range((void *)pb->cfg->rd_idx_loc, sizeof(*(pb->cfg->rd_idx_loc))); + + return len; +} diff --git a/tests/subsys/ipc/ipc_sessions/interoperability/pbuf_v1.h b/tests/subsys/ipc/ipc_sessions/interoperability/pbuf_v1.h new file mode 100644 index 0000000000000..8783cdbbf1465 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/interoperability/pbuf_v1.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_IPC_PBUF_H_ +#define ZEPHYR_INCLUDE_IPC_PBUF_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Packed buffer API + * @defgroup pbuf Packed Buffer API + * @ingroup ipc + * @{ + */ + +/** @brief Size of packet length field. */ +#define PBUF_PACKET_LEN_SZ sizeof(uint32_t) + +/* Amount of data that is left unused to distinguish between empty and full. */ +#define _PBUF_IDX_SIZE sizeof(uint32_t) + +/* Minimal length of the data field in the buffer to store the smalest packet + * possible. + * (+1) for at least one byte of data. + * (+_PBUF_IDX_SIZE) to distinguish buffer full and buffer empty. + * Rounded up to keep wr/rd indexes pointing to aligned address. + */ +#define _PBUF_MIN_DATA_LEN ROUND_UP(PBUF_PACKET_LEN_SZ + 1 + _PBUF_IDX_SIZE, _PBUF_IDX_SIZE) + +#if defined(CONFIG_ARCH_POSIX) +/* For the native simulated boards we need to modify some pointers at init */ +#define PBUF_MAYBE_CONST +#else +#define PBUF_MAYBE_CONST const +#endif + +/** @brief Control block of packet buffer. + * + * The structure contains configuration data. + */ +struct pbuf_cfg { + volatile uint32_t *rd_idx_loc; /* Address of the variable holding + * index value of the first valid byte + * in data[]. + */ + volatile uint32_t *wr_idx_loc; /* Address of the variable holding + * index value of the first free byte + * in data[]. + */ + uint32_t dcache_alignment; /* CPU data cache line size in bytes. + * Used for validation - TODO: To be + * replaced by flags. + */ + uint32_t len; /* Length of data[] in bytes. */ + uint8_t *data_loc; /* Location of the data[]. */ +}; + +/** + * @brief Data block of the packed buffer. + * + * The structure contains local copies of wr and rd indexes used by writer and + * reader respectively. + */ +struct pbuf_data { + volatile uint32_t wr_idx; /* Index of the first holding first + * free byte in data[]. Used for + * writing. + */ + volatile uint32_t rd_idx; /* Index of the first holding first + * valid byte in data[]. Used for + * reading. + */ +}; + + +/** + * @brief Scure packed buffer. + * + * The packet buffer implements lightweight unidirectional packet + * buffer with read/write semantics on top of a memory region shared + * by the reader and writer. It embeds cache and memory barrier management to + * ensure correct data access. + * + * This structure supports single writer and reader. Data stored in the buffer + * is encapsulated to a message (with length header). The read/write API is + * written in a way to protect the data from being corrupted. + */ +struct pbuf { + PBUF_MAYBE_CONST struct pbuf_cfg *const cfg; /* Configuration of the + * buffer. + */ + struct pbuf_data data; /* Data used to read and write + * to the buffer + */ +}; + +/** + * @brief Macro for configuration initialization. + * + * It is recommended to use this macro to initialize packed buffer + * configuration. + * + * @param mem_addr Memory address for pbuf. + * @param size Size of the memory. + * @param dcache_align Data cache alignment. + */ +#define PBUF_CFG_INIT(mem_addr, size, dcache_align) \ +{ \ + .rd_idx_loc = (uint32_t *)(mem_addr), \ + .wr_idx_loc = (uint32_t *)((uint8_t *)(mem_addr) + \ + MAX(dcache_align, _PBUF_IDX_SIZE)), \ + .data_loc = (uint8_t *)((uint8_t *)(mem_addr) + \ + MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE), \ + .len = (uint32_t)((uint32_t)(size) - MAX(dcache_align, _PBUF_IDX_SIZE) - \ + _PBUF_IDX_SIZE), \ + .dcache_alignment = (dcache_align), \ +} + +/** + * @brief Macro calculates memory overhead taken by the header in shared memory. + * + * It contains the read index, write index and padding. + * + * @param dcache_align Data cache alignment. + */ +#define PBUF_HEADER_OVERHEAD(dcache_align) \ + (MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE) + +/** + * @brief Statically define and initialize pbuf. + * + * @param name Name of the pbuf. + * @param mem_addr Memory address for pbuf. + * @param size Size of the memory. + * @param dcache_align Data cache line size. + */ +#define PBUF_DEFINE(name, mem_addr, size, dcache_align) \ + BUILD_ASSERT(dcache_align >= 0, \ + "Cache line size must be non negative."); \ + BUILD_ASSERT((size) > 0 && IS_PTR_ALIGNED_BYTES(size, _PBUF_IDX_SIZE), \ + "Incorrect size."); \ + BUILD_ASSERT(IS_PTR_ALIGNED_BYTES(mem_addr, MAX(dcache_align, _PBUF_IDX_SIZE)), \ + "Misaligned memory."); \ + BUILD_ASSERT(size >= (MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE + \ + _PBUF_MIN_DATA_LEN), "Insufficient size."); \ + static PBUF_MAYBE_CONST struct pbuf_cfg cfg_##name = \ + PBUF_CFG_INIT(mem_addr, size, dcache_align); \ + static struct pbuf name = { \ + .cfg = &cfg_##name, \ + } + +/** + * @brief Initialize the Tx packet buffer. + * + * This function initializes the Tx packet buffer based on provided configuration. + * If the configuration is incorrect, the function will return error. + * + * It is recommended to use PBUF_DEFINE macro for build time initialization. + * + * @param pb Pointer to the packed buffer containing + * configuration and data. Configuration has to be + * fixed before the initialization. + * @retval 0 on success. + * @retval -EINVAL when the input parameter is incorrect. + */ +int pbuf_tx_init(struct pbuf *pb); + +/** + * @brief Initialize the Rx packet buffer. + * + * This function initializes the Rx packet buffer. + * If the configuration is incorrect, the function will return error. + * + * It is recommended to use PBUF_DEFINE macro for build time initialization. + * + * @param pb Pointer to the packed buffer containing + * configuration and data. Configuration has to be + * fixed before the initialization. + * @retval 0 on success. + * @retval -EINVAL when the input parameter is incorrect. + */ +int pbuf_rx_init(struct pbuf *pb); + +/** + * @brief Write specified amount of data to the packet buffer. + * + * This function call writes specified amount of data to the packet buffer if + * the buffer will fit the data. + * + * @param pb A buffer to which to write. + * @param buf Pointer to the data to be written to the buffer. + * @param len Number of bytes to be written to the buffer. Must be positive. + * @retval int Number of bytes written, negative error code on fail. + * -EINVAL, if any of input parameter is incorrect. + * -ENOMEM, if len is bigger than the buffer can fit. + */ + +int pbuf_write(struct pbuf *pb, const char *buf, uint16_t len); + +/** + * @brief Read specified amount of data from the packet buffer. + * + * Single read allows to read the message send by the single write. + * The provided %p buf must be big enough to store the whole message. + * + * @param pb A buffer from which data will be read. + * @param buf Data pointer to which read data will be written. + * If NULL, len of stored message is returned. + * @param len Number of bytes to be read from the buffer. + * @retval int Bytes read, negative error code on fail. + * Bytes to be read, if buf == NULL. + * -EINVAL, if any of input parameter is incorrect. + * -ENOMEM, if message can not fit in provided buf. + * -EAGAIN, if not whole message is ready yet. + */ +int pbuf_read(struct pbuf *pb, char *buf, uint16_t len); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_IPC_PBUF_H_ */ diff --git a/tests/subsys/ipc/ipc_sessions/prj.conf b/tests/subsys/ipc/ipc_sessions/prj.conf new file mode 100644 index 0000000000000..e721953414be5 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/prj.conf @@ -0,0 +1,10 @@ +# Copyright 2021 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +# We need rand_r function +CONFIG_GNU_C_EXTENSIONS=y + +CONFIG_ZTEST=y +CONFIG_MMU=y +CONFIG_IPC_SERVICE=y +CONFIG_MBOX=y diff --git a/tests/subsys/ipc/ipc_sessions/remote/CMakeLists.txt b/tests/subsys/ipc/ipc_sessions/remote/CMakeLists.txt new file mode 100644 index 0000000000000..1fa2d9c278be0 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/remote/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# 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_icmsg) + +zephyr_include_directories(../common) + +FILE(GLOB remote_sources src/*.c) +target_sources(app PRIVATE ${remote_sources}) + +zephyr_sources_ifdef(CONFIG_IPC_SERVICE_ICMSG_V1 ../interoperability/icmsg_v1.c) +zephyr_sources_ifdef(CONFIG_PBUF_V1 ../interoperability/pbuf_v1.c) +zephyr_sources_ifdef(CONFIG_IPC_SERVICE_BACKEND_ICMSG_V1 ../interoperability/ipc_icmsg_v1.c) diff --git a/tests/subsys/ipc/ipc_sessions/remote/Kconfig b/tests/subsys/ipc/ipc_sessions/remote/Kconfig new file mode 100644 index 0000000000000..169ab615a2066 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/remote/Kconfig @@ -0,0 +1,11 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +rsource "../interoperability/Kconfig" + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu diff --git a/tests/subsys/ipc/ipc_sessions/remote/boards/nrf5340dk_nrf5340_cpunet.overlay b/tests/subsys/ipc/ipc_sessions/remote/boards/nrf5340dk_nrf5340_cpunet.overlay new file mode 100644 index 0000000000000..95dffe367e4d5 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/remote/boards/nrf5340dk_nrf5340_cpunet.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &ipc0; + +/ { + chosen { + /delete-property/ zephyr,ipc_shm; + }; + + reserved-memory { + /delete-node/ memory@20070000; + + sram_rx: memory@20070000 { + reg = <0x20070000 0x8000>; + }; + + sram_tx: memory@20078000 { + reg = <0x20078000 0x8000>; + }; + }; + + ipc0: ipc0 { + compatible = "zephyr,ipc-icmsg"; + tx-region = <&sram_tx>; + rx-region = <&sram_rx>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "rx", "tx"; + dcache-alignment = <8>; + unbound = "detect"; + status = "okay"; + }; +}; diff --git a/tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpuppr.conf b/tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpuppr.conf new file mode 100644 index 0000000000000..80e211dcedd2e --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpuppr.conf @@ -0,0 +1 @@ +CONFIG_WATCHDOG=y diff --git a/tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpuppr.overlay new file mode 100644 index 0000000000000..5728b0a1f32a7 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +ipc0: &cpuapp_cpuppr_ipc { + status = "okay"; + unbound = "detect"; +}; + +&cpuppr_vevif { + status = "okay"; +}; + +&cpuapp_bellboard { + status = "okay"; +}; + +&wdt131 { + status = "okay"; +}; + +/ { + chosen { + /delete-property/ zephyr,bt-hci; + }; + + aliases { + watchdog0 = &wdt131; + }; +}; diff --git a/tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 0000000000000..00e376b5df862 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +&uart135 { + /delete-property/ hw-flow-control; +}; + +&ipc0 { + compatible = "zephyr,ipc-icmsg"; + /delete-property/ tx-blocks; + /delete-property/ rx-blocks; + unbound = "enable"; +}; diff --git a/tests/subsys/ipc/ipc_sessions/remote/prj.conf b/tests/subsys/ipc/ipc_sessions/remote/prj.conf new file mode 100644 index 0000000000000..78730ee7dd593 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/remote/prj.conf @@ -0,0 +1,23 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# We need rand_r function +CONFIG_GNU_C_EXTENSIONS=y +CONFIG_PRINTK=y +CONFIG_EVENTS=y + +CONFIG_LOG=y +CONFIG_LOG_ALWAYS_RUNTIME=y +CONFIG_LOG_MODE_MINIMAL=y +#CONFIG_LOG_PROCESS_THREAD_PRIORITY=-15 +#CONFIG_LOG_PROCESS_THREAD_CUSTOM_PRIORITY=y + +CONFIG_HEAP_MEM_POOL_SIZE=2048 + +CONFIG_IPC_SERVICE=y +CONFIG_IPC_SERVICE_LOG_LEVEL_INF=y + +CONFIG_MBOX=y +CONFIG_WATCHDOG=y + +CONFIG_REBOOT=y diff --git a/tests/subsys/ipc/ipc_sessions/remote/src/remote.c b/tests/subsys/ipc/ipc_sessions/remote/src/remote.c new file mode 100644 index 0000000000000..dd2b845587aef --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/remote/src/remote.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +LOG_MODULE_REGISTER(remote, LOG_LEVEL_INF); + +#define IPC_TEST_EV_REBOND 0x01 +#define IPC_TEST_EV_BOND 0x02 +#define IPC_TEST_EV_TXTEST 0x04 + +static const struct device *ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); +static volatile bool ipc0_bounded; +K_SEM_DEFINE(bound_sem, 0, 1); +K_EVENT_DEFINE(ipc_ev_req); + +struct ipc_xfer_params { + uint32_t blk_size; + uint32_t blk_cnt; + unsigned int seed; + int result; +}; + +static struct ipc_xfer_params ipc_rx_params; +static struct ipc_xfer_params ipc_tx_params; + +static struct k_timer timer_reboot; +static struct k_timer timer_rebond; + +static void ep_bound(void *priv); +static void ep_unbound(void *priv); +static void ep_recv(const void *data, size_t len, void *priv); +static void ep_error(const char *message, void *priv); + +static struct ipc_ept_cfg ep_cfg = { + .cb = { + .bound = ep_bound, + .unbound = ep_unbound, + .received = ep_recv, + .error = ep_error + }, +}; + +/** + * @brief Trying to reset by WDT + * + * @note If this function return, it means it fails + */ +static int reboot_by_wdt(void) +{ + int err; + static const struct device *const wdt = + COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_ALIAS(watchdog0)), + (DEVICE_DT_GET(DT_ALIAS(watchdog0))), (NULL)); + static const struct wdt_timeout_cfg m_cfg_wdt = { + .callback = NULL, + .flags = WDT_FLAG_RESET_SOC, + .window.max = 10, + }; + static const uint8_t wdt_options[] = { + WDT_OPT_PAUSE_HALTED_BY_DBG | WDT_OPT_PAUSE_IN_SLEEP, + WDT_OPT_PAUSE_IN_SLEEP, + 0 + }; + + if (!wdt) { + return -ENOTSUP; + } + + if (!device_is_ready(wdt)) { + LOG_ERR("WDT device is not ready"); + return -EIO; + } + + err = wdt_install_timeout(wdt, &m_cfg_wdt); + if (err < 0) { + LOG_ERR("WDT install error"); + return -EIO; + } + + for (size_t i = 0; i < ARRAY_SIZE(wdt_options); ++i) { + err = wdt_setup(wdt, wdt_options[i]); + if (err < 0) { + LOG_ERR("Failed WDT setup with options = %u", wdt_options[i]); + } else { + /* We are ok with the configuration: + * just wait for the WDT to trigger + */ + for (;;) { + k_cpu_idle(); + } + } + } + + return -EIO; +} + +/** + * @brief Just force to reboot, anyway you find possible + */ +FUNC_NORETURN static void reboot_anyway(void) +{ + reboot_by_wdt(); + /* If WDT restart fails - try another way */ + sys_reboot(SYS_REBOOT_COLD); +} + +static void ep_bound(void *priv) +{ + ipc0_bounded = true; + k_sem_give(&bound_sem); + + LOG_INF("Endpoint bounded"); +} + +static void ep_unbound(void *priv) +{ + ipc0_bounded = false; + k_sem_give(&bound_sem); + + LOG_INF("Endpoint unbounded"); + + /* Try to restore the connection */ + k_event_set(&ipc_ev_req, IPC_TEST_EV_BOND); +} + +static void ep_recv(const void *data, size_t len, void *priv) +{ + int ret; + const struct ipc_test_cmd *cmd = data; + struct ipc_ept *ep = priv; + + if (len < sizeof(struct ipc_test_cmd)) { + LOG_ERR("The unexpected size of received data: %u < %u", len, + sizeof(struct ipc_test_cmd)); + /* Dropping further processing */ + return; + } + + switch (cmd->cmd) { + case IPC_TEST_CMD_NONE: + LOG_INF("Command processing: NONE"); + /* Ignore */ + break; + case IPC_TEST_CMD_PING: { + LOG_INF("Command processing: PING"); + + static const struct ipc_test_cmd cmd_pong = {IPC_TEST_CMD_PONG}; + + ret = ipc_service_send(ep, &cmd_pong, sizeof(cmd_pong)); + if (ret < 0) { + LOG_ERR("PONG response failed: %d", ret); + } + break; + } + case IPC_TEST_CMD_ECHO: { + LOG_INF("Command processing: ECHO"); + + struct ipc_test_cmd *cmd_rsp = k_malloc(len); + + if (!cmd_rsp) { + LOG_ERR("ECHO response failed: memory allocation"); + break; + } + + cmd_rsp->cmd = IPC_TEST_CMD_ECHO_RSP; + memcpy(cmd_rsp->data, cmd->data, len - sizeof(struct ipc_test_cmd)); + ret = ipc_service_send(ep, cmd_rsp, len); + k_free(cmd_rsp); + if (ret < 0) { + LOG_ERR("ECHO response failed: %d", ret); + } + break; + } + case IPC_TEST_CMD_REBOND: { + LOG_INF("Command processing: REBOOT"); + + struct ipc_test_cmd_rebond *cmd_rebond = (struct ipc_test_cmd_rebond *)cmd; + + k_timer_start(&timer_rebond, K_MSEC(cmd_rebond->timeout_ms), K_FOREVER); + break; + } + case IPC_TEST_CMD_REBOOT: { + LOG_INF("Command processing: REBOOT"); + + struct ipc_test_cmd_reboot *cmd_reboot = (struct ipc_test_cmd_reboot *)cmd; + + k_timer_start(&timer_reboot, K_MSEC(cmd_reboot->timeout_ms), K_FOREVER); + break; + } + case IPC_TEST_CMD_RXSTART: { + LOG_INF("Command processing: RXSTART"); + + struct ipc_test_cmd_xstart *cmd_rxstart = (struct ipc_test_cmd_xstart *)cmd; + + ipc_rx_params.blk_size = cmd_rxstart->blk_size; + ipc_rx_params.blk_cnt = cmd_rxstart->blk_cnt; + ipc_rx_params.seed = cmd_rxstart->seed; + ipc_rx_params.result = 0; + break; + } + case IPC_TEST_CMD_TXSTART: { + LOG_INF("Command processing: TXSTART"); + + struct ipc_test_cmd_xstart *cmd_txstart = (struct ipc_test_cmd_xstart *)cmd; + + ipc_tx_params.blk_size = cmd_txstart->blk_size; + ipc_tx_params.blk_cnt = cmd_txstart->blk_cnt; + ipc_tx_params.seed = cmd_txstart->seed; + ipc_tx_params.result = 0; + k_event_set(&ipc_ev_req, IPC_TEST_EV_TXTEST); + break; + } + case IPC_TEST_CMD_RXGET: { + LOG_INF("Command processing: RXGET"); + + int ret; + struct ipc_test_cmd_xstat cmd_stat = { + .base.cmd = IPC_TEST_CMD_XSTAT, + .blk_cnt = ipc_rx_params.blk_cnt, + .result = ipc_rx_params.result + }; + + ret = ipc_service_send(ep, &cmd_stat, sizeof(cmd_stat)); + if (ret < 0) { + LOG_ERR("RXGET response send failed"); + } + break; + } + case IPC_TEST_CMD_TXGET: { + LOG_INF("Command processing: TXGET"); + + int ret; + struct ipc_test_cmd_xstat cmd_stat = { + .base.cmd = IPC_TEST_CMD_XSTAT, + .blk_cnt = ipc_tx_params.blk_cnt, + .result = ipc_tx_params.result + }; + + ret = ipc_service_send(ep, &cmd_stat, sizeof(cmd_stat)); + if (ret < 0) { + LOG_ERR("TXGET response send failed"); + } + break; + } + case IPC_TEST_CMD_XDATA: { + if ((ipc_rx_params.blk_cnt % 1000) == 0) { + /* Logging only every N-th command not to slowdown the transfer too much */ + LOG_INF("Command processing: XDATA (left: %u)", ipc_rx_params.blk_cnt); + } + + /* Ignore if there is an error */ + if (ipc_rx_params.result) { + LOG_ERR("There is error in Rx transfer already"); + break; + } + + if (len != ipc_rx_params.blk_size + offsetof(struct ipc_test_cmd, data)) { + LOG_ERR("Size mismatch"); + ipc_rx_params.result = -EMSGSIZE; + break; + } + + if (ipc_rx_params.blk_cnt <= 0) { + LOG_ERR("Data not expected"); + ipc_rx_params.result = -EFAULT; + break; + } + + /* Check the data */ + for (size_t n = 0; n < ipc_rx_params.blk_size; ++n) { + uint8_t expected = (uint8_t)rand_r(&ipc_rx_params.seed); + + if (cmd->data[n] != expected) { + LOG_ERR("Data value error at %u", n); + ipc_rx_params.result = -EINVAL; + break; + } + } + + ipc_rx_params.blk_cnt -= 1; + break; + } + default: + LOG_ERR("Unhandled command: %u", cmd->cmd); + break; + } +} + +static void ep_error(const char *message, void *priv) +{ + LOG_ERR("EP error: \"%s\"", message); +} + +static int init_ipc(void) +{ + int ret; + static struct ipc_ept ep; + + /* Store the pointer to the endpoint */ + ep_cfg.priv = &ep; + + LOG_INF("IPC-sessions test remote started"); + + ret = ipc_service_open_instance(ipc0_instance); + if ((ret < 0) && (ret != -EALREADY)) { + LOG_ERR("ipc_service_open_instance() failure: %d", ret); + return ret; + } + + ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); + if (ret < 0) { + LOG_ERR("ipc_service_register_endpoint() failure: %d", ret); + return ret; + } + + do { + k_sem_take(&bound_sem, K_FOREVER); + } while (!ipc0_bounded); + + LOG_INF("IPC connection estabilished"); + + return 0; +} + +static void timer_rebond_cb(struct k_timer *timer) +{ + (void)timer; + LOG_INF("Setting rebond request"); + k_event_set(&ipc_ev_req, IPC_TEST_EV_REBOND); +} + +static void timer_reboot_cb(struct k_timer *timer) +{ + (void)timer; + LOG_INF("Resetting CPU"); + reboot_anyway(); + __ASSERT(0, "Still working after reboot request"); +} + + +int main(void) +{ + int ret; + + k_timer_init(&timer_rebond, timer_rebond_cb, NULL); + k_timer_init(&timer_reboot, timer_reboot_cb, NULL); + ret = init_ipc(); + if (ret) { + return ret; + } + + while (1) { + uint32_t ev; + + ev = k_event_wait(&ipc_ev_req, ~0U, false, K_FOREVER); + k_event_clear(&ipc_ev_req, ev); + + if (ev & IPC_TEST_EV_REBOND) { + /* Rebond now */ + ret = ipc_service_deregister_endpoint(ep_cfg.priv); + if (ret) { + LOG_ERR("ipc_service_deregister_endpoint() failure: %d", ret); + continue; + } + ipc0_bounded = false; + + ret = ipc_service_register_endpoint(ipc0_instance, ep_cfg.priv, &ep_cfg); + if (ret < 0) { + LOG_ERR("ipc_service_register_endpoint() failure: %d", ret); + return ret; + } + + do { + k_sem_take(&bound_sem, K_FOREVER); + } while (!ipc0_bounded); + } + if (ev & IPC_TEST_EV_BOND) { + LOG_INF("Bonding endpoint"); + /* Bond missing endpoint */ + if (!ipc0_bounded) { + ret = ipc_service_register_endpoint(ipc0_instance, ep_cfg.priv, + &ep_cfg); + if (ret < 0) { + LOG_ERR("ipc_service_register_endpoint() failure: %d", ret); + return ret; + } + + do { + k_sem_take(&bound_sem, K_FOREVER); + } while (!ipc0_bounded); + } + LOG_INF("Bonding done"); + } + if (ev & IPC_TEST_EV_TXTEST) { + LOG_INF("Transfer TX test started"); + + size_t cmd_size = ipc_tx_params.blk_size + offsetof(struct ipc_test_cmd, + data); + struct ipc_test_cmd *cmd_data = k_malloc(cmd_size); + + if (!cmd_data) { + LOG_ERR("Cannot create TX test buffer"); + ipc_tx_params.result = -ENOMEM; + continue; + } + + LOG_INF("Initial seed: %u", ipc_tx_params.seed); + + cmd_data->cmd = IPC_TEST_CMD_XDATA; + for (/* No init */; ipc_tx_params.blk_cnt > 0; --ipc_tx_params.blk_cnt) { + int ret; + + if (ipc_tx_params.blk_cnt % 1000 == 0) { + LOG_INF("Sending: %u blocks left", ipc_tx_params.blk_cnt); + } + /* Generate the block data */ + for (size_t n = 0; n < ipc_tx_params.blk_size; ++n) { + cmd_data->data[n] = (uint8_t)rand_r(&ipc_tx_params.seed); + } + do { + ret = ipc_service_send(ep_cfg.priv, cmd_data, cmd_size); + } while (ret == -ENOMEM); + if (ret < 0) { + LOG_ERR("Cannot send TX test buffer: %d", ret); + ipc_tx_params.result = -EIO; + continue; + } + } + + k_free(cmd_data); + + LOG_INF("Transfer TX test finished"); + } + + + } + + return 0; +} diff --git a/tests/subsys/ipc/ipc_sessions/src/data_queue.c b/tests/subsys/ipc/ipc_sessions/src/data_queue.c new file mode 100644 index 0000000000000..03dc93257a38e --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/src/data_queue.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "data_queue.h" + +#define DATA_QUEUE_MEMORY_ALIGN sizeof(uint32_t) + +struct data_queue_format { + uint32_t header; /* Required by kernel k_queue_append */ + size_t size; + uint32_t data[]; +}; + + +void data_queue_init(struct data_queue *q, void *mem, size_t bytes) +{ + k_heap_init(&q->h, mem, bytes); + k_queue_init(&q->q); +} + +int data_queue_put(struct data_queue *q, const void *data, size_t bytes, k_timeout_t timeout) +{ + struct data_queue_format *buffer = k_heap_aligned_alloc( + &q->h, + DATA_QUEUE_MEMORY_ALIGN, + bytes + sizeof(struct data_queue_format), + timeout); + + if (!buffer) { + return -ENOMEM; + } + buffer->size = bytes; + memcpy(buffer->data, data, bytes); + + k_queue_append(&q->q, buffer); + return 0; +} + +void *data_queue_get(struct data_queue *q, size_t *size, k_timeout_t timeout) +{ + struct data_queue_format *buffer = k_queue_get(&q->q, timeout); + + if (!buffer) { + return NULL; + } + + if (size) { + *size = buffer->size; + } + return buffer->data; +} + +void data_queue_release(struct data_queue *q, void *data) +{ + struct data_queue_format *buffer = CONTAINER_OF(data, struct data_queue_format, data); + + k_heap_free(&q->h, buffer); +} + +int data_queue_is_empty(struct data_queue *q) +{ + return k_queue_is_empty(&q->q); +} diff --git a/tests/subsys/ipc/ipc_sessions/src/data_queue.h b/tests/subsys/ipc/ipc_sessions/src/data_queue.h new file mode 100644 index 0000000000000..5e5eef14c3e22 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/src/data_queue.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef DATA_QUEUE_H +#include + + +struct data_queue { + struct k_queue q; + struct k_heap h; +}; + +void data_queue_init(struct data_queue *q, void *mem, size_t bytes); + +int data_queue_put(struct data_queue *q, const void *data, size_t bytes, k_timeout_t timeout); + +void *data_queue_get(struct data_queue *q, size_t *size, k_timeout_t timeout); + +void data_queue_release(struct data_queue *q, void *data); + +int data_queue_is_empty(struct data_queue *q); + +#endif /* DATA_QUEUE_H */ diff --git a/tests/subsys/ipc/ipc_sessions/src/main.c b/tests/subsys/ipc/ipc_sessions/src/main.c new file mode 100644 index 0000000000000..1215530e09f87 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/src/main.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include "data_queue.h" + +#include +LOG_MODULE_REGISTER(ipc_sessions, LOG_LEVEL_INF); + +enum test_ipc_events { + TEST_IPC_EVENT_BOUNDED, + TEST_IPC_EVENT_UNBOUNDED, + TEST_IPC_EVENT_ERROR +}; + +struct test_ipc_event_state { + enum test_ipc_events ev; + struct ipc_ep *ep; +}; + +static const struct device *ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); +static volatile bool ipc0_bounded; +K_MSGQ_DEFINE(ipc_events, sizeof(struct test_ipc_event_state), 16, 4); + +static uint32_t data_queue_memory[ROUND_UP(CONFIG_IPC_TEST_MSG_HEAP_SIZE, sizeof(uint32_t))]; +static struct data_queue ipc_data_queue; + +struct test_cmd_xdata { + struct ipc_test_cmd base; + uint8_t data[CONFIG_IPC_TEST_BLOCK_SIZE]; +}; + +static void (*ep_received_override_cb)(const void *data, size_t len, void *priv); + +static void ep_bound(void *priv) +{ + int ret; + struct test_ipc_event_state ev = { + .ev = TEST_IPC_EVENT_BOUNDED, + .ep = priv + }; + + ipc0_bounded = true; + ret = k_msgq_put(&ipc_events, &ev, K_NO_WAIT); + if (ret) { + LOG_ERR("Cannot put event in queue: %d", ret); + } +} + +static void ep_unbound(void *priv) +{ + int ret; + struct test_ipc_event_state ev = { + .ev = TEST_IPC_EVENT_UNBOUNDED, + .ep = priv + }; + + ipc0_bounded = false; + ret = k_msgq_put(&ipc_events, &ev, K_NO_WAIT); + if (ret) { + LOG_ERR("Cannot put event in queue: %d", ret); + } +} + +static void ep_recv(const void *data, size_t len, void *priv) +{ + int ret; + + if (ep_received_override_cb) { + ep_received_override_cb(data, len, priv); + } else { + ret = data_queue_put(&ipc_data_queue, data, len, K_NO_WAIT); + __ASSERT(ret >= 0, "Cannot put data into queue: %d", ret); + (void)ret; + } +} + +static void ep_error(const char *message, void *priv) +{ + int ret; + struct test_ipc_event_state ev = { + .ev = TEST_IPC_EVENT_ERROR, + .ep = priv + }; + + ret = k_msgq_put(&ipc_events, &ev, K_NO_WAIT); + if (ret) { + LOG_ERR("Cannot put event in queue: %d", ret); + } +} + +static struct ipc_ept_cfg ep_cfg = { + .cb = { + .bound = ep_bound, + .unbound = ep_unbound, + .received = ep_recv, + .error = ep_error + }, +}; + +static struct ipc_ept ep; + + + +/** + * @brief Estabilish connection before any test run + */ +void *test_suite_setup(void) +{ + int ret; + struct test_ipc_event_state ev; + + data_queue_init(&ipc_data_queue, data_queue_memory, sizeof(data_queue_memory)); + + ret = ipc_service_open_instance(ipc0_instance); + zassert_true((ret >= 0) || ret == -EALREADY, "ipc_service_open_instance() failure: %d", + ret); + + /* Store the pointer to the endpoint */ + ep_cfg.priv = &ep; + ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); + zassert_true((ret >= 0), "ipc_service_register_endpoint() failure: %d", ret); + + do { + ret = k_msgq_get(&ipc_events, &ev, K_MSEC(1000)); + zassert_ok(ret, "Cannot bound to the remote interface"); + } while (!ipc0_bounded); + + return NULL; +} + +/** + * @brief Prepare the test structures + */ +void test_suite_before(void *fixture) +{ + ep_received_override_cb = NULL; + k_msgq_purge(&ipc_events); +} + +static void execute_test_ping_pong(void) +{ + int ret; + static const struct ipc_test_cmd cmd_ping = { IPC_TEST_CMD_PING }; + struct ipc_test_cmd *cmd_rsp; + size_t cmd_rsp_size; + + zassert_not_ok(data_queue_is_empty(&ipc_data_queue), + "IPC data queue contains unexpected data"); + /* Sending data */ + ret = ipc_service_send(&ep, &cmd_ping, sizeof(cmd_ping)); + zassert_equal(ret, sizeof(cmd_ping), "ipc_service_send failed: %d, expected: %u", ret, + sizeof(cmd_ping)); + /* Waiting for response */ + cmd_rsp = data_queue_get(&ipc_data_queue, &cmd_rsp_size, K_MSEC(1000)); + zassert_not_null(cmd_rsp, "No command response on time"); + zassert_equal(cmd_rsp_size, sizeof(struct ipc_test_cmd), + "Unexpected response size: %u, expected: %u", cmd_rsp_size, + sizeof(struct ipc_test_cmd)); + zassert_equal(cmd_rsp->cmd, IPC_TEST_CMD_PONG, + "Unexpected response cmd value: %u, expected: %u", cmd_rsp->cmd, + IPC_TEST_CMD_PONG); + data_queue_release(&ipc_data_queue, cmd_rsp); +} + +ZTEST(ipc_sessions, test_ping_pong) +{ + execute_test_ping_pong(); +} + +ZTEST(ipc_sessions, test_echo) +{ + int ret; + static const struct ipc_test_cmd cmd_echo = { + IPC_TEST_CMD_ECHO, {'H', 'e', 'l', 'l', 'o', '!'} + }; + struct ipc_test_cmd *cmd_rsp; + size_t cmd_rsp_size; + + zassert_not_ok(data_queue_is_empty(&ipc_data_queue), + "IPC data queue contains unexpected data"); + /* Sending data */ + ret = ipc_service_send(&ep, &cmd_echo, sizeof(cmd_echo)); + zassert_equal(ret, sizeof(cmd_echo), "ipc_service_send failed: %d, expected: %u", ret, + sizeof(cmd_echo)); + /* Waiting for response */ + cmd_rsp = data_queue_get(&ipc_data_queue, &cmd_rsp_size, K_MSEC(1000)); + zassert_not_null(cmd_rsp, "No command response on time"); + /* Checking response */ + zassert_equal(cmd_rsp_size, sizeof(cmd_echo), "Unexpected response size: %u, expected: %u", + cmd_rsp_size, sizeof(cmd_echo)); + zassert_equal(cmd_rsp->cmd, IPC_TEST_CMD_ECHO_RSP, + "Unexpected response cmd value: %u, expected: %u", cmd_rsp->cmd, + IPC_TEST_CMD_ECHO_RSP); + zassert_mem_equal(cmd_rsp->data, cmd_echo.data, + sizeof(cmd_echo) - sizeof(struct ipc_test_cmd), + "Unexpected response content"); + data_queue_release(&ipc_data_queue, cmd_rsp); +} + +ZTEST(ipc_sessions, test_reboot) +{ + Z_TEST_SKIP_IFDEF(CONFIG_IPC_TEST_SKIP_UNBOUND); + Z_TEST_SKIP_IFDEF(CONFIG_IPC_TEST_SKIP_CORE_RESET); + + int ret; + struct test_ipc_event_state ev; + static const struct ipc_test_cmd_reboot cmd_rebond = { { IPC_TEST_CMD_REBOOT }, 10 }; + + zassert_not_ok(data_queue_is_empty(&ipc_data_queue), + "IPC data queue contains unexpected data"); + /* Sending data */ + ret = ipc_service_send(&ep, &cmd_rebond, sizeof(cmd_rebond)); + zassert_equal(ret, sizeof(cmd_rebond), "ipc_service_send failed: %d, expected: %u", ret, + sizeof(cmd_rebond)); + /* Waiting for IPC to unbound */ + ret = k_msgq_get(&ipc_events, &ev, K_MSEC(1000)); + zassert_ok(ret, "No IPC unbound event on time"); + zassert_equal(ev.ev, TEST_IPC_EVENT_UNBOUNDED, "Unexpected IPC event: %u, expected: %u", + ev.ev, TEST_IPC_EVENT_UNBOUNDED); + zassert_equal_ptr(ev.ep, &ep, "Unexpected endpoint (unbound)"); + /* Reconnecting */ + ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); + zassert_true((ret >= 0), "ipc_service_register_endpoint() failure: %d", ret); + /* Waiting for bound */ + ret = k_msgq_get(&ipc_events, &ev, K_MSEC(1000)); + zassert_ok(ret, "No IPC bound event on time"); + zassert_equal(ev.ev, TEST_IPC_EVENT_BOUNDED, "Unexpected IPC event: %u, expected: %u", + ev.ev, TEST_IPC_EVENT_UNBOUNDED); + zassert_equal_ptr(ev.ep, &ep, "Unexpected endpoint (bound)"); + + /* After reconnection - test communication */ + execute_test_ping_pong(); +} + +ZTEST(ipc_sessions, test_rebond) +{ + Z_TEST_SKIP_IFDEF(CONFIG_IPC_TEST_SKIP_UNBOUND); + + int ret; + struct test_ipc_event_state ev; + static const struct ipc_test_cmd_reboot cmd_rebond = { { IPC_TEST_CMD_REBOND }, 10 }; + + zassert_not_ok(data_queue_is_empty(&ipc_data_queue), + "IPC data queue contains unexpected data"); + /* Sending data */ + ret = ipc_service_send(&ep, &cmd_rebond, sizeof(cmd_rebond)); + zassert_equal(ret, sizeof(cmd_rebond), "ipc_service_send failed: %d, expected: %u", ret, + sizeof(cmd_rebond)); + /* Waiting for IPC to unbound */ + ret = k_msgq_get(&ipc_events, &ev, K_MSEC(1000)); + zassert_ok(ret, "No IPC unbound event on time"); + zassert_equal(ev.ev, TEST_IPC_EVENT_UNBOUNDED, "Unexpected IPC event: %u, expected: %u", + ev.ev, TEST_IPC_EVENT_UNBOUNDED); + zassert_equal_ptr(ev.ep, &ep, "Unexpected endpoint (unbound)"); + /* Reconnecting */ + ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); + zassert_true((ret >= 0), "ipc_service_register_endpoint() failure: %d", ret); + /* Waiting for bound */ + ret = k_msgq_get(&ipc_events, &ev, K_MSEC(1000)); + zassert_ok(ret, "No IPC bound event on time"); + zassert_equal(ev.ev, TEST_IPC_EVENT_BOUNDED, "Unexpected IPC event: %u, expected: %u", + ev.ev, TEST_IPC_EVENT_UNBOUNDED); + zassert_equal_ptr(ev.ep, &ep, "Unexpected endpoint (bound)"); + + /* After reconnection - test communication */ + execute_test_ping_pong(); +} + +ZTEST(ipc_sessions, test_local_rebond) +{ + Z_TEST_SKIP_IFDEF(CONFIG_IPC_TEST_SKIP_UNBOUND); + + int ret; + struct test_ipc_event_state ev; + + zassert_not_ok(data_queue_is_empty(&ipc_data_queue), + "IPC data queue contains unexpected data"); + /* Rebond locally */ + ret = ipc_service_deregister_endpoint(ep_cfg.priv); + zassert_ok(ret, "ipc_service_deregister_endpoint() failure: %d", ret); + ipc0_bounded = false; + + ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); + zassert_true((ret >= 0), "ipc_service_register_endpoint() failure: %d", ret); + do { + ret = k_msgq_get(&ipc_events, &ev, K_MSEC(1000)); + zassert_ok(ret, "Cannot bound to the remote interface"); + } while (!ipc0_bounded); + + /* After reconnection - test communication */ + execute_test_ping_pong(); +} + +ZTEST(ipc_sessions, test_tx_long) +{ + #define SEED_TXSTART_VALUE 1 + int ret; + static const struct ipc_test_cmd_xstart cmd_rxstart = { + .base = { .cmd = IPC_TEST_CMD_RXSTART }, + .blk_size = CONFIG_IPC_TEST_BLOCK_SIZE, + .blk_cnt = CONFIG_IPC_TEST_BLOCK_CNT, + .seed = SEED_TXSTART_VALUE }; + static const struct ipc_test_cmd cmd_rxget = { IPC_TEST_CMD_RXGET }; + struct test_cmd_xdata cmd_txdata = { .base = { .cmd = IPC_TEST_CMD_XDATA } }; + unsigned int seed = SEED_TXSTART_VALUE; + + struct ipc_test_cmd_xstat *cmd_rxstat; + size_t cmd_rsp_size; + + zassert_not_ok(data_queue_is_empty(&ipc_data_queue), + "IPC data queue contains unexpected data"); + + /* Sending command for the remote to start receiving the data */ + ret = ipc_service_send(&ep, &cmd_rxstart, sizeof(cmd_rxstart)); + zassert_equal(ret, sizeof(cmd_rxstart), "ipc_service_send failed: %d, expected: %u", ret, + sizeof(cmd_rxstart)); + /* Check current status */ + ret = ipc_service_send(&ep, &cmd_rxget, sizeof(cmd_rxget)); + zassert_equal(ret, sizeof(cmd_rxget), "ipc_service_send failed: %d, expected: %u", ret, + sizeof(cmd_rxget)); + cmd_rxstat = data_queue_get(&ipc_data_queue, &cmd_rsp_size, K_MSEC(1000)); + zassert_not_null(cmd_rxstat, "No command response on time"); + zassert_equal(cmd_rsp_size, sizeof(*cmd_rxstat), + "Unexpected response size: %u, expected: %u", cmd_rsp_size, + sizeof(cmd_rxstat)); + zassert_equal(cmd_rxstat->base.cmd, IPC_TEST_CMD_XSTAT, + "Unexpected command in response: %u", cmd_rxstat->base.cmd); + zassert_ok(cmd_rxstat->result, "RX result not ok: %d", cmd_rxstat->result); + zassert_equal(cmd_rxstat->blk_cnt, cmd_rxstart.blk_cnt, + "RX blk_cnt in status does not match start command: %u vs %u", + cmd_rxstat->blk_cnt, cmd_rxstart.blk_cnt); + data_queue_release(&ipc_data_queue, cmd_rxstat); + + /* Sending data */ + for (size_t blk = 0; blk < cmd_rxstart.blk_cnt; ++blk) { + for (size_t n = 0; n < cmd_rxstart.blk_size; ++n) { + cmd_txdata.data[n] = (uint8_t)rand_r(&seed); + } + do { + ret = ipc_service_send(&ep, &cmd_txdata, sizeof(cmd_txdata)); + } while (ret == -ENOMEM); + if ((blk % 1000) == 0) { + LOG_INF("Transfer number: %u of %u", blk, cmd_rxstart.blk_cnt); + } + zassert_equal(ret, sizeof(cmd_txdata), "ipc_service_send failed: %d, expected: %u", + ret, sizeof(cmd_txdata)); + } + + /* Check current status */ + ret = ipc_service_send(&ep, &cmd_rxget, sizeof(cmd_rxget)); + zassert_equal(ret, sizeof(cmd_rxget), "ipc_service_send failed: %d, expected: %u", ret, + sizeof(cmd_rxget)); + cmd_rxstat = data_queue_get(&ipc_data_queue, &cmd_rsp_size, K_MSEC(1000)); + zassert_not_null(cmd_rxstat, "No command response on time"); + zassert_equal(cmd_rsp_size, sizeof(*cmd_rxstat), + "Unexpected response size: %u, expected: %u", cmd_rsp_size, + sizeof(cmd_rxstat)); + zassert_equal(cmd_rxstat->base.cmd, IPC_TEST_CMD_XSTAT, + "Unexpected command in response: %u", cmd_rxstat->base.cmd); + zassert_ok(cmd_rxstat->result, "RX result not ok: %d", cmd_rxstat->result); + zassert_equal(cmd_rxstat->blk_cnt, 0, + "RX blk_cnt in status does not match start command: %u vs %u", + cmd_rxstat->blk_cnt, 0); + data_queue_release(&ipc_data_queue, cmd_rxstat); +} + +static struct { + unsigned int seed; + size_t blk_left; +} test_rx_long_data; +K_SEM_DEFINE(test_rx_long_sem, 0, 1); + +static void test_rx_long_rec_cb(const void *data, size_t len, void *priv) +{ + const struct test_cmd_xdata *cmd_rxdata = data; + + zassert_true(test_rx_long_data.blk_left > 0, "No data left to interpret"); + zassert_equal(len, sizeof(*cmd_rxdata), + "Unexpected response size: %u, expected: %u", len, sizeof(*cmd_rxdata)); + zassert_equal(cmd_rxdata->base.cmd, IPC_TEST_CMD_XDATA, + "Unexpected command in response: %u", cmd_rxdata->base.cmd); + for (size_t n = 0; n < CONFIG_IPC_TEST_BLOCK_SIZE; ++n) { + uint8_t expected = (uint8_t)rand_r(&test_rx_long_data.seed); + + zassert_equal(cmd_rxdata->data[n], expected, + "Data mismatch at %u while %u blocks left", n, + test_rx_long_data.blk_left); + } + + if (test_rx_long_data.blk_left % 1000 == 0) { + LOG_INF("Receivng left: %u", test_rx_long_data.blk_left); + } + test_rx_long_data.blk_left -= 1; + if (test_rx_long_data.blk_left <= 0) { + LOG_INF("Interpretation marked finished"); + ep_received_override_cb = NULL; + k_sem_give(&test_rx_long_sem); + } +} + +ZTEST(ipc_sessions, test_rx_long) +{ + #define SEED_RXSTART_VALUE 1 + int ret; + static const struct ipc_test_cmd_xstart cmd_txstart = { + .base = { .cmd = IPC_TEST_CMD_TXSTART }, + .blk_size = CONFIG_IPC_TEST_BLOCK_SIZE, + .blk_cnt = CONFIG_IPC_TEST_BLOCK_CNT, + .seed = SEED_RXSTART_VALUE }; + static const struct ipc_test_cmd cmd_txget = { IPC_TEST_CMD_TXGET }; + struct ipc_test_cmd_xstat *cmd_txstat; + size_t cmd_rsp_size; + + zassert_not_ok(data_queue_is_empty(&ipc_data_queue), + "IPC data queue contains unexpected data"); + + /* Configuring the callback to interpret the incoming data */ + test_rx_long_data.seed = SEED_RXSTART_VALUE; + test_rx_long_data.blk_left = cmd_txstart.blk_cnt; + ep_received_override_cb = test_rx_long_rec_cb; + + /* Sending command for the remote to start sending the data */ + ret = ipc_service_send(&ep, &cmd_txstart, sizeof(cmd_txstart)); + zassert_equal(ret, sizeof(cmd_txstart), "ipc_service_send failed: %d, expected: %u", ret, + sizeof(cmd_txstart)); + + /* Waiting for all the data */ + ret = k_sem_take(&test_rx_long_sem, K_SECONDS(30)); + LOG_INF("Interpretation finished"); + zassert_ok(ret, "Incoming packet interpretation timeout"); + zassert_is_null(ep_received_override_cb, "Seems like interpretation callback failed"); + + /* Check current status */ + ret = ipc_service_send(&ep, &cmd_txget, sizeof(cmd_txget)); + zassert_equal(ret, sizeof(cmd_txget), "ipc_service_send failed: %d, expected: %u", ret, + sizeof(cmd_txget)); + cmd_txstat = data_queue_get(&ipc_data_queue, &cmd_rsp_size, K_MSEC(1000)); + zassert_not_null(cmd_txstat, "No command response on time"); + zassert_equal(cmd_rsp_size, sizeof(*cmd_txstat), + "Unexpected response size: %u, expected: %u", cmd_rsp_size, + sizeof(cmd_txstat)); + zassert_equal(cmd_txstat->base.cmd, IPC_TEST_CMD_XSTAT, + "Unexpected command in response: %u", cmd_txstat->base.cmd); + zassert_ok(cmd_txstat->result, "RX result not ok: %d", cmd_txstat->result); + zassert_equal(cmd_txstat->blk_cnt, 0, + "RX blk_cnt in status does not match start command: %u vs %u", + cmd_txstat->blk_cnt, 0); + data_queue_release(&ipc_data_queue, cmd_txstat); +} + + +ZTEST_SUITE( + /* suite_name */ ipc_sessions, + /* ztest_suite_predicate_t */ NULL, + /* ztest_suite_setup_t */ test_suite_setup, + /* ztest_suite_before_t */ test_suite_before, + /* ztest_suite_after_t */ NULL, + /* ztest_suite_teardown_t */ NULL +); diff --git a/tests/subsys/ipc/ipc_sessions/sysbuild.cmake b/tests/subsys/ipc/ipc_sessions/sysbuild.cmake new file mode 100644 index 0000000000000..9aa0b80096b17 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/sysbuild.cmake @@ -0,0 +1,26 @@ +# +# 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() + +# Add remote project +ExternalZephyrProject_Add( + APPLICATION remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_REMOTE_BOARD} + BOARD_REVISION ${BOARD_REVISION} +) +set_property(GLOBAL APPEND PROPERTY PM_DOMAINS CPUNET) +set_property(GLOBAL APPEND PROPERTY PM_CPUNET_IMAGES remote) +set_property(GLOBAL PROPERTY DOMAIN_APP_CPUNET remote) +set(CPUNET_PM_DOMAIN_DYNAMIC_PARTITION remote CACHE INTERNAL "") + +# Add a dependency so that the remote sample will be built and flashed first +sysbuild_add_dependencies(CONFIGURE ${DEFAULT_IMAGE} remote) +# Add dependency so that the remote image is flashed first. +sysbuild_add_dependencies(FLASH ${DEFAULT_IMAGE} remote) diff --git a/tests/subsys/ipc/ipc_sessions/sysbuild_cpuppr.conf b/tests/subsys/ipc/ipc_sessions/sysbuild_cpuppr.conf new file mode 100644 index 0000000000000..3b3ca1ea91f39 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/sysbuild_cpuppr.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpuppr" diff --git a/tests/subsys/ipc/ipc_sessions/testcase.yaml b/tests/subsys/ipc/ipc_sessions/testcase.yaml new file mode 100644 index 0000000000000..f76a61b8d68e4 --- /dev/null +++ b/tests/subsys/ipc/ipc_sessions/testcase.yaml @@ -0,0 +1,50 @@ +sample: + name: IPC Service integration test + description: IPC Service integration and efficiency test + +common: + sysbuild: true + tags: ipc ipc_sessions + harness: ztest + +tests: + sample.ipc.ipc_sessions.nrf5340dk: + platform_allow: + - nrf5340dk/nrf5340/cpuapp + integration_platforms: + - nrf5340dk/nrf5340/cpuapp + sample.ipc.ipc_sessions.nrf54h20dk_cpuapp_cpurad: + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + extra_args: + - CONFIG_IPC_TEST_SKIP_CORE_RESET=y + sample.ipc.ipc_sessions.nrf54h20dk_cpuapp_cpuppr: + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + extra_args: + - FILE_SUFFIX=cpuppr + - ipc_sessions_SNIPPET=nordic-ppr + sample.ipc.ipc_sessions.nrf54h20dk_cpuapp_no_unbound_cpuppr: + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + extra_args: + - FILE_SUFFIX=cpuppr + - ipc_sessions_SNIPPET=nordic-ppr + - CONFIG_IPC_TEST_SKIP_UNBOUND=y + - CONFIG_IPC_SERVICE_BACKEND_ICMSG_V1=y + sample.ipc.ipc_sessions.nrf54h20dk_cpuapp_cpuppr_no_unbound: + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + extra_args: + - FILE_SUFFIX=cpuppr + - ipc_sessions_SNIPPET=nordic-ppr + - CONFIG_IPC_TEST_SKIP_UNBOUND=y + - remote_CONFIG_IPC_SERVICE_BACKEND_ICMSG_V1=y diff --git a/tests/subsys/ipc/pbuf/src/main.c b/tests/subsys/ipc/pbuf/src/main.c index 4af9da68c4731..4d563204cb08d 100644 --- a/tests/subsys/ipc/pbuf/src/main.c +++ b/tests/subsys/ipc/pbuf/src/main.c @@ -48,7 +48,7 @@ ZTEST(test_pbuf, test_rw) * order to avoid clang complains about memory_area not being constant * expression. */ - static PBUF_MAYBE_CONST struct pbuf_cfg cfg = PBUF_CFG_INIT(memory_area, MEM_AREA_SZ, 0); + static PBUF_MAYBE_CONST struct pbuf_cfg cfg = PBUF_CFG_INIT(memory_area, MEM_AREA_SZ, 0, 0); static struct pbuf pb = { .cfg = &cfg, @@ -115,9 +115,11 @@ ZTEST(test_pbuf, test_retcodes) * order to avoid clang complains about memory_area not being constant * expression. */ - static PBUF_MAYBE_CONST struct pbuf_cfg cfg0 = PBUF_CFG_INIT(memory_area, MEM_AREA_SZ, 32); - static PBUF_MAYBE_CONST struct pbuf_cfg cfg1 = PBUF_CFG_INIT(memory_area, MEM_AREA_SZ, 0); - static PBUF_MAYBE_CONST struct pbuf_cfg cfg2 = PBUF_CFG_INIT(memory_area, 20, 4); + static PBUF_MAYBE_CONST struct pbuf_cfg cfg0 = PBUF_CFG_INIT(memory_area, MEM_AREA_SZ, + 32, 0); + static PBUF_MAYBE_CONST struct pbuf_cfg cfg1 = PBUF_CFG_INIT(memory_area, MEM_AREA_SZ, + 0, 0); + static PBUF_MAYBE_CONST struct pbuf_cfg cfg2 = PBUF_CFG_INIT(memory_area, 20, 4, 0); static struct pbuf pb0 = { .cfg = &cfg0, @@ -268,7 +270,7 @@ ZTEST(test_pbuf, test_stress) * order to avoid clang complains about buffer not being constant * expression. */ - static PBUF_MAYBE_CONST struct pbuf_cfg cfg = PBUF_CFG_INIT(buffer, MEM_AREA_SZ, 4); + static PBUF_MAYBE_CONST struct pbuf_cfg cfg = PBUF_CFG_INIT(buffer, MEM_AREA_SZ, 4, 0); static struct pbuf pb = { .cfg = &cfg, From 65b9a7be694211f47cf28a23cecd78a9d5dec548 Mon Sep 17 00:00:00 2001 From: David Siorpaes Date: Thu, 6 Feb 2025 14:58:23 +0100 Subject: [PATCH 0193/6055] boards: st: nucleo_n657x0: added missing led aliases. Fixes 'samples/basic/threads' example build. Signed-off-by: David Siorpaes --- boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi index 3812a1381919f..6197e288a36a5 100644 --- a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi +++ b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi @@ -48,6 +48,8 @@ aliases { led0 = &green_led; + led1 = &blue_led; + led2 = &red_led; sw0 = &user_button; }; }; From fe06d5422b74ba050ccd5eab97db2316cf0704bc Mon Sep 17 00:00:00 2001 From: Yasin Ustuner Date: Sun, 9 Feb 2025 18:03:41 +0300 Subject: [PATCH 0194/6055] manifest: Add MAX32650 hal files This commit adds necessary hal files for MAX32650 board. Signed-off-by: Yasin Ustuner --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 05332b09611f5..67584f741836e 100644 --- a/west.yml +++ b/west.yml @@ -142,7 +142,7 @@ manifest: groups: - fs - name: hal_adi - revision: a5b528b49f4291aba34afefd5543889690536684 + revision: 13a3f2d44c27416846cde2fe9f23b638c7ad446d path: modules/hal/adi groups: - hal From 3efeb245a7c62fa493cd740fa2bb77a924bc6622 Mon Sep 17 00:00:00 2001 From: Yasin Ustuner Date: Fri, 7 Feb 2025 16:52:28 +0300 Subject: [PATCH 0195/6055] drivers: serial: Change Tx Status macro for MAX32 TX status macro is different for MAX32650 SoC. The common macro is added to the hal. This commit changes the tx status macro with the common one. Signed-off-by: Yasin Ustuner --- drivers/serial/uart_max32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/uart_max32.c b/drivers/serial/uart_max32.c index 9cd16a59066cc..0ed5bcf709f95 100644 --- a/drivers/serial/uart_max32.c +++ b/drivers/serial/uart_max32.c @@ -376,7 +376,7 @@ static int api_irq_tx_ready(const struct device *dev) uint32_t inten = Wrap_MXC_UART_GetRegINTEN(cfg->regs); return ((inten & (ADI_MAX32_UART_INT_TX | ADI_MAX32_UART_INT_TX_OEM)) && - !(data->status & MXC_F_UART_STATUS_TX_FULL)); + !(data->status & ADI_MAX32_UART_STATUS_TX_FULL)); } static int api_irq_tx_complete(const struct device *dev) From ee288819a0b34dbdb8ad7fc7fb2d69b33c2a4f5d Mon Sep 17 00:00:00 2001 From: Furkan Akkiz Date: Thu, 13 Feb 2025 13:11:52 +0300 Subject: [PATCH 0196/6055] drivers: hwinfo: Update driver for MAX32650 There are function mismatches for MAX32650. Because of that, created a wrap version of the function to handle these differences. Signed-off-by: Furkan Akkiz --- drivers/hwinfo/hwinfo_max32.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwinfo/hwinfo_max32.c b/drivers/hwinfo/hwinfo_max32.c index 61c841380d8a0..e0ec75dd72259 100644 --- a/drivers/hwinfo/hwinfo_max32.c +++ b/drivers/hwinfo/hwinfo_max32.c @@ -6,17 +6,16 @@ #include #include -#include +#include #include #include ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) { uint8_t usn[MXC_SYS_USN_LEN]; - uint8_t checksum[MXC_SYS_USN_CHECKSUM_LEN]; int error; - error = MXC_SYS_GetUSN(usn, checksum); + error = Wrap_MXC_SYS_GetUSN(usn); if (error != E_NO_ERROR) { /* Error reading USN */ return error; From 1db033dd62eefea6fc1bd8558f7c18d010835c52 Mon Sep 17 00:00:00 2001 From: Burak Babaoglu Date: Tue, 4 Feb 2025 13:10:54 +0300 Subject: [PATCH 0197/6055] soc: adi: Add the MAX32650 SoC This commit adds MAX32650 Kconfig and dts files for basic port. Signed-off-by: Burak Babaoglu Signed-off-by: Yasin Ustuner --- dts/arm/adi/max32/max32650-pinctrl.dtsi | 641 +++++++++++++++++++++++ dts/arm/adi/max32/max32650.dtsi | 109 ++++ soc/adi/max32/Kconfig.defconfig.max32650 | 14 + soc/adi/max32/Kconfig.soc | 5 + soc/adi/max32/soc.yml | 1 + 5 files changed, 770 insertions(+) create mode 100644 dts/arm/adi/max32/max32650-pinctrl.dtsi create mode 100644 dts/arm/adi/max32/max32650.dtsi create mode 100644 soc/adi/max32/Kconfig.defconfig.max32650 diff --git a/dts/arm/adi/max32/max32650-pinctrl.dtsi b/dts/arm/adi/max32/max32650-pinctrl.dtsi new file mode 100644 index 0000000000000..eaf39132953a2 --- /dev/null +++ b/dts/arm/adi/max32/max32650-pinctrl.dtsi @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + pinctrl: pin-controller@40008000 { + /omit-if-no-ref/ spixr_sdio0_p0_1: spixr_sdio0_p0_1 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_sdio2_p0_2: spixr_sdio2_p0_2 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_sck_p0_3: spixr_sck_p0_3 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_sdio3_p0_4: spixr_sdio3_p0_4 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_sdio1_p0_5: spixr_sdio1_p0_5 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_ss0_p0_6: spixr_ss0_p0_6 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_ss0_p0_7: spixf_ss0_p0_7 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_sck_p0_8: spixf_sck_p0_8 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_sdio1_p0_9: spixf_sdio1_p0_9 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_sdio0_p0_10: spixf_sdio0_p0_10 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_sdio2_p0_11: spixf_sdio2_p0_11 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_sdio3_p0_12: spixf_sdio3_p0_12 { + pinmux = ; + }; + + /omit-if-no-ref/ spi3_ss1_p0_13: spi3_ss1_p0_13 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_g0_p0_13: clcd_g0_p0_13 { + pinmux = ; + }; + + /omit-if-no-ref/ spi3_ss2_p0_14: spi3_ss2_p0_14 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_g1_p0_14: clcd_g1_p0_14 { + pinmux = ; + }; + + /omit-if-no-ref/ spi3_sdio3_p0_15: spi3_sdio3_p0_15 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_g2_p0_15: clcd_g2_p0_15 { + pinmux = ; + }; + + /omit-if-no-ref/ spi3_sck_p0_16: spi3_sck_p0_16 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_g3_p0_16: clcd_g3_p0_16 { + pinmux = ; + }; + + /omit-if-no-ref/ spi3_sdio2_p0_17: spi3_sdio2_p0_17 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_g4_p0_17: clcd_g4_p0_17 { + pinmux = ; + }; + + /omit-if-no-ref/ spi3_ss3_p0_18: spi3_ss3_p0_18 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_g5_p0_18: clcd_g5_p0_18 { + pinmux = ; + }; + + /omit-if-no-ref/ spi3_ss0_p0_19: spi3_ss0_p0_19 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_g6_p0_19: clcd_g6_p0_19 { + pinmux = ; + }; + + /omit-if-no-ref/ spi3_sdio1_p0_20: spi3_sdio1_p0_20 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_g7_p0_20: clcd_g7_p0_20 { + pinmux = ; + }; + + /omit-if-no-ref/ spi3_sdio0_p0_21: spi3_sdio0_p0_21 { + pinmux = ; + }; + + /omit-if-no-ref/ spi0_ss0_p0_22: spi0_ss0_p0_22 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_vden_p0_22: clcd_vden_p0_22 { + pinmux = ; + }; + + /omit-if-no-ref/ pt15_p0_23: pt15_p0_23 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_clk_p0_23: clcd_clk_p0_23 { + pinmux = ; + }; + + /omit-if-no-ref/ rxev_p0_24: rxev_p0_24 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_hsync_p0_24: clcd_hsync_p0_24 { + pinmux = ; + }; + + /omit-if-no-ref/ txev_p0_25: txev_p0_25 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_b0_p0_25: clcd_b0_p0_25 { + pinmux = ; + }; + + /omit-if-no-ref/ tdi_p0_26: tdi_p0_26 { + pinmux = ; + }; + + /omit-if-no-ref/ tdo_p0_27: tdo_p0_27 { + pinmux = ; + }; + + /omit-if-no-ref/ tms_p0_28: tms_p0_28 { + pinmux = ; + }; + + /omit-if-no-ref/ tck_p0_29: tck_p0_29 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_b0_p0_30: clcd_b0_p0_30 { + pinmux = ; + }; + + /omit-if-no-ref/ kcal32_p0_31: kcal32_p0_31 { + pinmux = ; + }; + + /omit-if-no-ref/ sdhc_cdn_p0_31: sdhc_cdn_p0_31 { + pinmux = ; + }; + + /omit-if-no-ref/ sdhc_cmd_p1_0: sdhc_cmd_p1_0 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_sdio3_p1_0: spixf_sdio3_p1_0 { + pinmux = ; + }; + + /omit-if-no-ref/ sdhc_dat2_p1_1: sdhc_dat2_p1_1 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_sdio1_p1_1: spixf_sdio1_p1_1 { + pinmux = ; + }; + + /omit-if-no-ref/ sdhc_wp_p1_2: sdhc_wp_p1_2 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_ss0_p1_2: spixf_ss0_p1_2 { + pinmux = ; + }; + + /omit-if-no-ref/ sdhc_dat3_p1_3: sdhc_dat3_p1_3 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_clk_p1_3: clcd_clk_p1_3 { + pinmux = ; + }; + + /omit-if-no-ref/ sdhc_dat0_p1_4: sdhc_dat0_p1_4 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_sdio0_p1_4: spixf_sdio0_p1_4 { + pinmux = ; + }; + + /omit-if-no-ref/ sdhc_clk_p1_5: sdhc_clk_p1_5 { + pinmux = ; + }; + + /omit-if-no-ref/ spixf_sck_p1_5: spixf_sck_p1_5 { + pinmux = ; + }; + + /omit-if-no-ref/ sdhc_dat1_p1_6: sdhc_dat1_p1_6 { + pinmux = ; + }; + + /omit-if-no-ref/ pt0_p1_6: pt0_p1_6 { + pinmux = ; + }; + + /omit-if-no-ref/ uart2_cts_p1_7: uart2_cts_p1_7 { + pinmux = ; + }; + + /omit-if-no-ref/ pt1_p1_7: pt1_p1_7 { + pinmux = ; + }; + + /omit-if-no-ref/ uart2_rts_p1_8: uart2_rts_p1_8 { + pinmux = ; + }; + + /omit-if-no-ref/ pt2_p1_8: pt2_p1_8 { + pinmux = ; + }; + + /omit-if-no-ref/ uart2_rx_p1_9: uart2_rx_p1_9 { + pinmux = ; + }; + + /omit-if-no-ref/ pt3_p1_9: pt3_p1_9 { + pinmux = ; + }; + + /omit-if-no-ref/ uart2_tx_p1_10: uart2_tx_p1_10 { + pinmux = ; + }; + + /omit-if-no-ref/ pt4_p1_10: pt4_p1_10 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_cs0_p1_11: hyp_cs0_p1_11 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_sdio_p1_11: spixr_sdio_p1_11 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_d0_p1_12: hyp_d0_p1_12 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_sdio1_p1_12: spixr_sdio1_p1_12 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_d4_p1_13: hyp_d4_p1_13 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_ss0_p1_13: spixr_ss0_p1_13 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_rwds_p1_14: hyp_rwds_p1_14 { + pinmux = ; + }; + + /omit-if-no-ref/ pt5_p1_14: pt5_p1_14 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_d1_p1_15: hyp_d1_p1_15 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_sdio2_p1_15: spixr_sdio2_p1_15 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_d5_p1_16: hyp_d5_p1_16 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_sck_p1_16: spixr_sck_p1_16 { + pinmux = ; + }; + + /omit-if-no-ref/ pt9_p1_17: pt9_p1_17 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_d6_p1_18: hyp_d6_p1_18 { + pinmux = ; + }; + + /omit-if-no-ref/ pt6_p1_18: pt6_p1_18 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_d2_p1_19: hyp_d2_p1_19 { + pinmux = ; + }; + + /omit-if-no-ref/ pt7_p1_19: pt7_p1_19 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_d3_p1_20: hyp_d3_p1_20 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_hsync_p1_20: clcd_hsync_p1_20 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_d7_p1_21: hyp_d7_p1_21 { + pinmux = ; + }; + + /omit-if-no-ref/ pt8_p1_21: pt8_p1_21 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_ss0_p1_23: spi1_ss0_p1_23 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_b1_p1_23: clcd_b1_p1_23 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_ss2_p1_24: spi1_ss2_p1_24 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_b2_p1_24: clcd_b2_p1_24 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_ss1_p1_25: spi1_ss1_p1_25 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_b3_p1_25: clcd_b3_p1_25 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_sck_p1_26: spi1_sck_p1_26 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_b4_p1_26: clcd_b4_p1_26 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_ss3_p1_27: spi1_ss3_p1_27 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_b5_p1_27: clcd_b5_p1_27 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_miso_p1_28: spi1_miso_p1_28 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_b6_p1_28: clcd_b6_p1_28 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_mosi_p1_29: spi1_mosi_p1_29 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_b7_p1_29: clcd_b7_p1_29 { + pinmux = ; + }; + + /omit-if-no-ref/ owm_pupen_p1_30: owm_pupen_p1_30 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_r0_p1_30: clcd_r0_p1_30 { + pinmux = ; + }; + + /omit-if-no-ref/ owm_io_p1_31: owm_io_p1_31 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_r1_p1_31: clcd_r1_p1_31 { + pinmux = ; + }; + + /omit-if-no-ref/ spi2_ss2_p2_0: spi2_ss2_p2_0 { + pinmux = ; + }; + + /omit-if-no-ref/ pt9_p2_0: pt9_p2_0 { + pinmux = ; + }; + + /omit-if-no-ref/ spi2_ss1_p2_1: spi2_ss1_p2_1 { + pinmux = ; + }; + + /omit-if-no-ref/ pt10_p2_1: pt10_p2_1 { + pinmux = ; + }; + + /omit-if-no-ref/ spi2_sck_p2_2: spi2_sck_p2_2 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_lend_p2_2: clcd_lend_p2_2 { + pinmux = ; + }; + + /omit-if-no-ref/ spi2_miso_p2_3: spi2_miso_p2_3 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_pwren_p2_3: clcd_pwren_p2_3 { + pinmux = ; + }; + + /omit-if-no-ref/ spi2_mosi_p2_4: spi2_mosi_p2_4 { + pinmux = ; + }; + + /omit-if-no-ref/ spi2_ss0_p2_5: spi2_ss0_p2_5 { + pinmux = ; + }; + + /omit-if-no-ref/ pt11_p2_5: pt11_p2_5 { + pinmux = ; + }; + + /omit-if-no-ref/ spi2_ss3_p2_6: spi2_ss3_p2_6 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_vsync_p2_6: clcd_vsync_p2_6 { + pinmux = ; + }; + + /omit-if-no-ref/ i2c0_sda_p2_7: i2c0_sda_p2_7 { + pinmux = ; + }; + + /omit-if-no-ref/ i2c0_scl_p2_8: i2c0_scl_p2_8 { + pinmux = ; + }; + + /omit-if-no-ref/ uart0_cts_p2_9: uart0_cts_p2_9 { + pinmux = ; + }; + + /omit-if-no-ref/ pt12_p2_9: pt12_p2_9 { + pinmux = ; + }; + + /omit-if-no-ref/ uart0_rts_p2_10: uart0_rts_p2_10 { + pinmux = ; + }; + + /omit-if-no-ref/ pt14_p2_10: pt14_p2_10 { + pinmux = ; + }; + + /omit-if-no-ref/ uart0_rx_p2_11: uart0_rx_p2_11 { + pinmux = ; + }; + + /omit-if-no-ref/ pt13_p2_11: pt13_p2_11 { + pinmux = ; + }; + + /omit-if-no-ref/ uart0_tx_p2_12: uart0_tx_p2_12 { + pinmux = ; + }; + + /omit-if-no-ref/ pt15_p2_12: pt15_p2_12 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_cts_p2_13: uart1_cts_p2_13 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_r2_p2_13: clcd_r2_p2_13 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_rx_p2_14: uart1_rx_p2_14 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_r3_p2_14: clcd_r3_p2_14 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_rts_p2_15: uart1_rts_p2_15 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_r4_p2_15: clcd_r4_p2_15 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_tx_p2_16: uart1_tx_p2_16 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_r5_p2_16: clcd_r5_p2_16 { + pinmux = ; + }; + + /omit-if-no-ref/ i2c1_sda_p2_17: i2c1_sda_p2_17 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_r6_p2_17: clcd_r6_p2_17 { + pinmux = ; + }; + + /omit-if-no-ref/ i2c1_scl_p2_18: i2c1_scl_p2_18 { + pinmux = ; + }; + + /omit-if-no-ref/ clcd_r7_p2_18: clcd_r7_p2_18 { + pinmux = ; + }; + + /omit-if-no-ref/ pt6_p2_23: pt6_p2_23 { + pinmux = ; + }; + + /omit-if-no-ref/ spixr_sdio3_p2_23: spixr_sdio3_p2_23 { + pinmux = ; + }; + + /omit-if-no-ref/ pt11_p2_25: pt11_p2_25 { + pinmux = ; + }; + + /omit-if-no-ref/ pt12_p2_26: pt12_p2_26 { + pinmux = ; + }; + + /omit-if-no-ref/ pt14_p2_28: pt14_p2_28 { + pinmux = ; + }; + + /omit-if-no-ref/ pt1_p2_30: pt1_p2_30 { + pinmux = ; + }; + + /omit-if-no-ref/ pdown_p3_0: pdown_p3_0 { + pinmux = ; + }; + + /omit-if-no-ref/ hyp_cs1_p3_0: hyp_cs1_p3_0 { + pinmux = ; + }; + + /omit-if-no-ref/ spi0_miso_p3_1: spi0_miso_p3_1 { + pinmux = ; + }; + + /omit-if-no-ref/ spi0_mosi_p3_2: spi0_mosi_p3_2 { + pinmux = ; + }; + + /omit-if-no-ref/ spi0_sck_p3_3: spi0_sck_p3_3 { + pinmux = ; + }; + + /omit-if-no-ref/ tmr0_p3_4: tmr0_p3_4 { + pinmux = ; + }; + + /omit-if-no-ref/ tmr2_p3_5: tmr2_p3_5 { + pinmux = ; + }; + + /omit-if-no-ref/ tmr4_p3_6: tmr4_p3_6 { + pinmux = ; + }; + + /omit-if-no-ref/ tmr1_p3_7: tmr1_p3_7 { + pinmux = ; + }; + + /omit-if-no-ref/ tmr3_p3_8: tmr3_p3_8 { + pinmux = ; + }; + + /omit-if-no-ref/ tmr5_p3_9: tmr5_p3_9 { + pinmux = ; + }; + }; + }; +}; diff --git a/dts/arm/adi/max32/max32650.dtsi b/dts/arm/adi/max32/max32650.dtsi new file mode 100644 index 0000000000000..e2447636d1517 --- /dev/null +++ b/dts/arm/adi/max32/max32650.dtsi @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&sram0 { + reg = <0x20000000 DT_SIZE_M(1)>; +}; + +&flash0 { + reg = <0x10000000 DT_SIZE_M(3)>; + erase-block-size = <16384>; +}; + +&clk_ipo { + clock-frequency = ; +}; + +&clk_iso { + clock-frequency = ; +}; + +/delete-node/ &clk_erfo; + +/delete-node/ &i2c2; + +/delete-node/ &trng; + +&pinctrl { + reg = <0x40008000 0x4000>; + + gpio2: gpio@4000a000 { + reg = <0x4000a000 0x1000>; + compatible = "adi,max32-gpio"; + gpio-controller; + #gpio-cells = <2>; + interrupts = <26 0>; + clocks = <&gcr ADI_MAX32_CLOCK_BUS0 2>; + status = "disabled"; + }; + + gpio3: gpio@4000b000 { + reg = <0x4000b000 0x1000>; + compatible = "adi,max32-gpio"; + gpio-controller; + #gpio-cells = <2>; + interrupts = <58 0>; + clocks = <&gcr ADI_MAX32_CLOCK_BUS1 6>; + status = "disabled"; + }; +}; + +/* MAX32650 extra peripherals. */ +/ { + soc { + trng: trng@400b5000 { + compatible = "adi,max32-trng"; + reg = <0x400b5000 0x1000>; + clocks = <&gcr ADI_MAX32_CLOCK_BUS1 2>; + status = "disabled"; + }; + + timer4: timer@40014000 { + compatible = "adi,max32-timer"; + reg = <0x40014000 0x1000>; + interrupts = <9 0>; + status = "disabled"; + clocks = <&gcr ADI_MAX32_CLOCK_BUS0 19>; + clock-source = ; + prescaler = <1>; + + counter { + compatible = "adi,max32-counter"; + status = "disabled"; + }; + + pwm { + compatible = "adi,max32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + + timer5: timer@40015000 { + compatible = "adi,max32-timer"; + reg = <0x40015000 0x1000>; + interrupts = <10 0>; + status = "disabled"; + clocks = <&gcr ADI_MAX32_CLOCK_BUS0 20>; + clock-source = ; + prescaler = <1>; + + counter { + compatible = "adi,max32-counter"; + status = "disabled"; + }; + + pwm { + compatible = "adi,max32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; + }; + }; +}; diff --git a/soc/adi/max32/Kconfig.defconfig.max32650 b/soc/adi/max32/Kconfig.defconfig.max32650 new file mode 100644 index 0000000000000..9c8608b1b775d --- /dev/null +++ b/soc/adi/max32/Kconfig.defconfig.max32650 @@ -0,0 +1,14 @@ +# Analog Devices MAX32650 MCU + +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MAX32650 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/clocks/clk_ipo,clock-frequency) + +config NUM_IRQS + default 80 + +endif # SOC_MAX32650 diff --git a/soc/adi/max32/Kconfig.soc b/soc/adi/max32/Kconfig.soc index b269a521b5cd1..700a00c3d8715 100644 --- a/soc/adi/max32/Kconfig.soc +++ b/soc/adi/max32/Kconfig.soc @@ -13,6 +13,10 @@ config SOC_FAMILY_MAX32_M4 config SOC_FAMILY default "max32" if SOC_FAMILY_MAX32 +config SOC_MAX32650 + bool + select SOC_FAMILY_MAX32_M4 + config SOC_MAX32655 bool @@ -78,6 +82,7 @@ config SOC_MAX78002_M4 select SOC_FAMILY_MAX32_M4 config SOC + default "max32650" if SOC_MAX32650 default "max32655" if SOC_MAX32655 default "max32662" if SOC_MAX32662 default "max32666" if SOC_MAX32666 diff --git a/soc/adi/max32/soc.yml b/soc/adi/max32/soc.yml index b4001bfd64e8a..b08b6e53102eb 100644 --- a/soc/adi/max32/soc.yml +++ b/soc/adi/max32/soc.yml @@ -4,6 +4,7 @@ family: - name: max32 socs: + - name: max32650 - name: max32655 cpuclusters: - name: m4 From cda8e7b619ad61fc87d53fc3cb908860a17de24f Mon Sep 17 00:00:00 2001 From: Burak Babaoglu Date: Tue, 4 Feb 2025 13:17:26 +0300 Subject: [PATCH 0198/6055] boards: adi: Add MAX32650EVKIT board This commit adds MAX32650EVKIT board basic port. Signed-off-by: Burak Babaoglu Signed-off-by: Yasin Ustuner --- .../adi/max32650evkit/Kconfig.max32650evkit | 7 ++ boards/adi/max32650evkit/board.cmake | 8 ++ boards/adi/max32650evkit/board.yml | 9 ++ .../max32650evkit/doc/img/max32650evkit.webp | Bin 0 -> 36500 bytes boards/adi/max32650evkit/doc/index.rst | 119 ++++++++++++++++++ boards/adi/max32650evkit/max32650evkit.dts | 89 +++++++++++++ boards/adi/max32650evkit/max32650evkit.yaml | 13 ++ .../adi/max32650evkit/max32650evkit_defconfig | 16 +++ boards/common/openocd-adi-max32.boards.cmake | 4 +- 9 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 boards/adi/max32650evkit/Kconfig.max32650evkit create mode 100644 boards/adi/max32650evkit/board.cmake create mode 100644 boards/adi/max32650evkit/board.yml create mode 100644 boards/adi/max32650evkit/doc/img/max32650evkit.webp create mode 100644 boards/adi/max32650evkit/doc/index.rst create mode 100644 boards/adi/max32650evkit/max32650evkit.dts create mode 100644 boards/adi/max32650evkit/max32650evkit.yaml create mode 100644 boards/adi/max32650evkit/max32650evkit_defconfig diff --git a/boards/adi/max32650evkit/Kconfig.max32650evkit b/boards/adi/max32650evkit/Kconfig.max32650evkit new file mode 100644 index 0000000000000..accb9f0e0f31b --- /dev/null +++ b/boards/adi/max32650evkit/Kconfig.max32650evkit @@ -0,0 +1,7 @@ +# MAX32650EVKIT boards configuration + +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_MAX32650EVKIT + select SOC_MAX32650 diff --git a/boards/adi/max32650evkit/board.cmake b/boards/adi/max32650evkit/board.cmake new file mode 100644 index 0000000000000..716d812146114 --- /dev/null +++ b/boards/adi/max32650evkit/board.cmake @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=MAX32650" "--reset-after-load") + +include(${ZEPHYR_BASE}/boards/common/openocd-adi-max32.boards.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/adi/max32650evkit/board.yml b/boards/adi/max32650evkit/board.yml new file mode 100644 index 0000000000000..24e70315fb5e4 --- /dev/null +++ b/boards/adi/max32650evkit/board.yml @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +board: + name: max32650evkit + full_name: MAX32650EVKIT + vendor: adi + socs: + - name: max32650 diff --git a/boards/adi/max32650evkit/doc/img/max32650evkit.webp b/boards/adi/max32650evkit/doc/img/max32650evkit.webp new file mode 100644 index 0000000000000000000000000000000000000000..1300e5e44b910b6adfd33e0b460fba59c10e76b1 GIT binary patch literal 36500 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 QSRetIqy>Q>PXGV_0B1}f-T(jq literal 0 HcmV?d00001 diff --git a/boards/adi/max32650evkit/doc/index.rst b/boards/adi/max32650evkit/doc/index.rst new file mode 100644 index 0000000000000..9d5a6ccaff39e --- /dev/null +++ b/boards/adi/max32650evkit/doc/index.rst @@ -0,0 +1,119 @@ +.. zephyr:board:: max32650evkit + +Overview +******** +The MAX32650 evaluation kit (EV kit) provides a platform for evaluating the +capabilities of the MAX32650 ultra-low power memory-scalable microcontroller +designed specifically for high performance battery powered applications. + +The Zephyr port is running on the MAX32650 MCU. + +.. image:: img/max32650evkit.webp + :align: center + :alt: MAX32650 EVKIT Front + +Hardware +******** + +- MAX32650 MCU: + + - Ultra Efficient Microcontroller for Battery-Powered Applications + + - 120MHz Arm Cortex-M4 with FPU + - SmartDMA Provides Background Memory Transfers with Programmable Data Processing + - 120MHz High-Speed and 50MHz Low-Power Oscillators + - 7.3728MHz Low Power Oscillators + - 32.768kHz and RTC Clock (Requires External Crystal) + - 8kHz, Always-on, Ultra-Low-Power Oscillator + - 3MB Internal Flash, 1MB Internal SRAM + - 104µW/MHz Executing from Cache at 1.1V + - Five Low-Power Modes: Active, Sleep, Background, Deep-Sleep, and Backup + - 1.8V and 3.3V I/O with No Level Translators + - Programming and Debugging + + - Scalable Cached External Memory Interfaces + + - 120MB/s HyperBus/Xccela DDR Interface + - SPIXF/SPIXR for External Flash/RAM Expansion + - 240Mbps SDHC/eMMC/SDIO/microSD Interface + + - Optimal Peripheral Mix Provides Platform Scalability + + - 16-Channel DMA + - Three SPI Master (60MHz)/Slave (48MHz) + - One QuadSPI Master (60MHz)/Slave (48MHz) + - Up to Three 4Mbaud UARTs with Flow Control + - Two 1MHz I2C Master/Slave + - I2S Slave + - Four-Channel, 7.8ksps, 10-bit Delta-Sigma ADC + - USB 2.0 Hi-Speed Device Interface with PHY + - 16 Pulse Train Generators + - Six 32-bit Timers with 8mA Hi-Drive + - 1-Wire® Master + + - Trust Protection Unit (TPU) for IP/Data and Security + + - Modular Arithmetic Accelerator (MAA), True Random Number Generator (TRNG) + - Secure Nonvolatile Key Storage, SHA-256, AES-128/192/256 + - Memory Decryption Integrity Unit, Secure Boot ROM + +- External devices connected to the MAX32650EVKIT: + + - 3.5in 320 x 240 Color TFT Display + - 64MB HyperRAM + - 64MB XIP Flash + - 1MB XIP RAM + - USB 2.0 Micro B + - Two General-Purpose LEDs and Two GeneralPurpose Pushbutton Switches + +Supported Features +================== + +The ``max32650evkit`` board supports the following interfaces: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | clock and reset control | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial | ++-----------+------------+-------------------------------------+ + +Programming and Debugging +************************* + +Flashing +======== +The MAX32650 MCU can be flashed by connecting an external debug probe to the +SWD port. SWD debug can be accessed through the Cortex 10-pin connector, J3. +Logic levels are fixed to VDDIO (1.8V). + +Once the debug probe is connected to your host computer, then you can simply run the +``west flash`` command to write a firmware image into flash. + +.. note:: + + This board uses OpenOCD as the default debug interface. You can also use + a Segger J-Link with Segger's native tooling by overriding the runner, + appending ``--runner jlink`` to your ``west`` command(s). The J-Link should + be connected to the standard 2*5 pin debug connector (J3) using an + appropriate adapter board and cable + +Debugging +========= +Please refer to the `Flashing`_ section and run the ``west debug`` command +instead of ``west flash``. + +References +********** + +- `MAX32650EVKIT web page`_ + +.. _MAX32650EVKIT web page: + https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650-evkit.html diff --git a/boards/adi/max32650evkit/max32650evkit.dts b/boards/adi/max32650evkit/max32650evkit.dts new file mode 100644 index 0000000000000..2292bfd8b8ac4 --- /dev/null +++ b/boards/adi/max32650evkit/max32650evkit.dts @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include + +/ { + model = "Analog Devices MAX32650EVKIT"; + compatible = "adi,max32650evkit"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + + led1: led_1 { + gpios = <&gpio2 25 GPIO_ACTIVE_HIGH>; + label = "Red LED"; + }; + + led2: led_2 { + gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + }; + + buttons { + compatible = "gpio-keys"; + + pb1: pb1 { + gpios = <&gpio2 28 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW2"; + zephyr,code = ; + }; + + pb2: pb2 { + gpios = <&gpio2 30 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW3"; + zephyr,code = ; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led1; + led1 = &led2; + }; +}; + +&uart0 { + pinctrl-0 = <&uart0_tx_p2_12 &uart0_rx_p2_11>; + pinctrl-names = "default"; + current-speed = <115200>; + data-bits = <8>; + parity = "none"; + status = "okay"; +}; + +&clk_ipo { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpio3 { + status = "okay"; +}; diff --git a/boards/adi/max32650evkit/max32650evkit.yaml b/boards/adi/max32650evkit/max32650evkit.yaml new file mode 100644 index 0000000000000..8e3ced3c43711 --- /dev/null +++ b/boards/adi/max32650evkit/max32650evkit.yaml @@ -0,0 +1,13 @@ +identifier: max32650evkit +name: max32650evkit +vendor: adi +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - serial +ram: 1024 +flash: 3072 diff --git a/boards/adi/max32650evkit/max32650evkit_defconfig b/boards/adi/max32650evkit/max32650evkit_defconfig new file mode 100644 index 0000000000000..9428e5334a08f --- /dev/null +++ b/boards/adi/max32650evkit/max32650evkit_defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable GPIO +CONFIG_GPIO=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable UART +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/boards/common/openocd-adi-max32.boards.cmake b/boards/common/openocd-adi-max32.boards.cmake index 93409dd6901f8..3f2c3829cf1ad 100644 --- a/boards/common/openocd-adi-max32.boards.cmake +++ b/boards/common/openocd-adi-max32.boards.cmake @@ -6,7 +6,9 @@ # Default cmsis-dap, it will be overwritten below if requires set(MAX32_INTERFACE_CFG "cmsis-dap.cfg") -if(CONFIG_SOC_MAX32655_M4) +if(CONFIG_SOC_MAX32650) + set(MAX32_TARGET_CFG "max32650.cfg") +elseif(CONFIG_SOC_MAX32655_M4) set(MAX32_TARGET_CFG "max32655.cfg") elseif(CONFIG_SOC_MAX32662) set(MAX32_TARGET_CFG "max32662.cfg") From 75fb7e42a9bada224b9678c889466c8b29ea82f0 Mon Sep 17 00:00:00 2001 From: Furkan Akkiz Date: Wed, 12 Feb 2025 12:04:39 +0300 Subject: [PATCH 0199/6055] boards: adi: Add AD_SWIOT1L_SL board This commit adds AD_SWIOT1L_SL board basic port. Signed-off-by: Furkan Akkiz --- .../adi/ad_swiot1l_sl/Kconfig.ad_swiot1l_sl | 7 + boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.dts | 73 +++++++++++ boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.yaml | 13 ++ .../adi/ad_swiot1l_sl/ad_swiot1l_sl_defconfig | 16 +++ boards/adi/ad_swiot1l_sl/board.cmake | 8 ++ boards/adi/ad_swiot1l_sl/board.yml | 9 ++ .../ad_swiot1l_sl/doc/img/ad_swiot1l_sl.webp | Bin 0 -> 51662 bytes boards/adi/ad_swiot1l_sl/doc/index.rst | 123 ++++++++++++++++++ 8 files changed, 249 insertions(+) create mode 100644 boards/adi/ad_swiot1l_sl/Kconfig.ad_swiot1l_sl create mode 100644 boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.dts create mode 100644 boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.yaml create mode 100644 boards/adi/ad_swiot1l_sl/ad_swiot1l_sl_defconfig create mode 100644 boards/adi/ad_swiot1l_sl/board.cmake create mode 100644 boards/adi/ad_swiot1l_sl/board.yml create mode 100644 boards/adi/ad_swiot1l_sl/doc/img/ad_swiot1l_sl.webp create mode 100644 boards/adi/ad_swiot1l_sl/doc/index.rst diff --git a/boards/adi/ad_swiot1l_sl/Kconfig.ad_swiot1l_sl b/boards/adi/ad_swiot1l_sl/Kconfig.ad_swiot1l_sl new file mode 100644 index 0000000000000..b8b2e0fed8164 --- /dev/null +++ b/boards/adi/ad_swiot1l_sl/Kconfig.ad_swiot1l_sl @@ -0,0 +1,7 @@ +# AD-SWIOT1L-SL board configuration + +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_AD_SWIOT1L_SL + select SOC_MAX32650 diff --git a/boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.dts b/boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.dts new file mode 100644 index 0000000000000..d46ad87c1cf9e --- /dev/null +++ b/boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.dts @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include + +/ { + model = "Analog Devices AD-SWIOT1L-SL"; + compatible = "adi,ad_swiot1l_sl"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + + led1: led_1 { + gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>; + label = "Red LED"; + }; + + led2: led_2 { + gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led1; + led1 = &led2; + }; +}; + +&uart0 { + pinctrl-0 = <&uart0_tx_p2_12 &uart0_rx_p2_11>; + pinctrl-names = "default"; + current-speed = <115200>; + data-bits = <8>; + parity = "none"; + status = "okay"; +}; + +&clk_ipo { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpio3 { + status = "okay"; +}; diff --git a/boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.yaml b/boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.yaml new file mode 100644 index 0000000000000..495481a989db0 --- /dev/null +++ b/boards/adi/ad_swiot1l_sl/ad_swiot1l_sl.yaml @@ -0,0 +1,13 @@ +identifier: ad_swiot1l_sl +name: ad_swiot1l_sl +vendor: adi +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - serial +ram: 1024 +flash: 3072 diff --git a/boards/adi/ad_swiot1l_sl/ad_swiot1l_sl_defconfig b/boards/adi/ad_swiot1l_sl/ad_swiot1l_sl_defconfig new file mode 100644 index 0000000000000..9428e5334a08f --- /dev/null +++ b/boards/adi/ad_swiot1l_sl/ad_swiot1l_sl_defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable GPIO +CONFIG_GPIO=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable UART +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/boards/adi/ad_swiot1l_sl/board.cmake b/boards/adi/ad_swiot1l_sl/board.cmake new file mode 100644 index 0000000000000..716d812146114 --- /dev/null +++ b/boards/adi/ad_swiot1l_sl/board.cmake @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=MAX32650" "--reset-after-load") + +include(${ZEPHYR_BASE}/boards/common/openocd-adi-max32.boards.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/adi/ad_swiot1l_sl/board.yml b/boards/adi/ad_swiot1l_sl/board.yml new file mode 100644 index 0000000000000..f458ef3b9e896 --- /dev/null +++ b/boards/adi/ad_swiot1l_sl/board.yml @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +board: + name: ad_swiot1l_sl + full_name: AD-SWIOT1L-SL + vendor: adi + socs: + - name: max32650 diff --git a/boards/adi/ad_swiot1l_sl/doc/img/ad_swiot1l_sl.webp b/boards/adi/ad_swiot1l_sl/doc/img/ad_swiot1l_sl.webp new file mode 100644 index 0000000000000000000000000000000000000000..6b734dc80b45a3325b6d02a19e9576b9f2cf9032 GIT binary patch literal 51662 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 s{nbhwFS5py@#G~RH4Q9^z=JAHg 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 literal 0 HcmV?d00001 diff --git a/boards/adi/ad_swiot1l_sl/doc/index.rst b/boards/adi/ad_swiot1l_sl/doc/index.rst new file mode 100644 index 0000000000000..47d1cbd66671b --- /dev/null +++ b/boards/adi/ad_swiot1l_sl/doc/index.rst @@ -0,0 +1,123 @@ +.. zephyr:board:: ad_swiot1l_sl + +Overview +******** +The AD-SWIOT1L-SL is a complete hardware and software platform for prototyping intelligent, +secure, network-capable field devices, with applications in factory automation, process +control, and intelligent buildings. + +The Zephyr port is running on the MAX32650 MCU. + +.. image:: img/ad_swiot1l_sl.webp + :align: center + :alt: AD-SWIOT1L-SL Front + +Hardware +******** + +- MAX32650 MCU: + + - Ultra-Efficient Microcontroller for Battery-Powered Applications + + - 120MHz Arm Cortex-M4 Processor with FPU + - SmartDMA Provides Background Memory Transfers with Programmable Data Processing + - 120MHz High-Speed and 50MHz Low-Power Oscillators + - 7.3728MHz Low-Power Oscillators + - 32.768kHz and RTC Clock (Requires External Crystal) + - 8kHz, Always-On, Ultra-Low-Power Oscillator + - 3MB Internal Flash, 1MB Internal SRAM + - 104μW/MHz Executing from Cache at 1.1V + - Five Low-Power Modes: Active, Sleep, Background, Deep Sleep, and Backup + - 1.8V and 3.3V I/O with No Level Translators + + - Scalable Cached External Memory Interfaces: + + - 120MB/s HyperBus/Xccela DDR Interface + - SPIXF/SPIXR for External Flash/RAM Expansion + - 240Mbps SDHC/eMMC/SDIO/microSD Interface + + - Optimal Peripheral Mix Provides Platform Scalability + + - 16-Channel DMA + - Three SPI Master (60MHz)/Slave (48MHz) + - One QuadSPI Master (60MHz)/Slave (48MHz) + - Up to Three 4Mbaud UARTs with Flow Control + - Two 1MHz I2C Master/Slave + - I2S Slave + - Four-Channel, 7.8ksps, 10-Bit Delta-Sigma ADC + - USB 2.0 Hi-Speed Device Interface with PHY + - 16 Pulse Train Generators + - Six 32-Bit Timers with 8mA High Drive + - 1-Wire® Master + + - Trust Protection Unit (TPU) for IP/Data Security + + - Modular Arithmetic Accelerator (MAA), True Random Number Generator (TRNG) + - Secure Nonvolatile Key Storage, SHA-256, AES-128/192/256 + - Memory Decryption Integrity Unit, Secure Boot ROM + +- External devices connected to the AD-SWIOT1L-SL: + + - On-Board HyperRAM + - On-Board QSPI Flash + - MAXQ1065 Ultralow Power Cryptographic Controller with ChipDNA + - ADIN1110 Robust, Industrial, Low Power 10BASE-T1L Ethernet MAC-PHY + - 2-Pin external power supply terminal block (24V DC) + - ADP1032 high performance, isolated micropower management unit (PMU) + - SWD 10-Pin Header + - On-Board 3.3V, 1.8V, and 1.1V voltage regulators + - AD74413R Quad-channel, Software Configurable I/O + - MAX14906 Quad-channel, Industrial Digital I/O + - Two general-purpose LEDs + +Supported Features +================== + +The ``ad_swiot1l_sl`` board supports the following interfaces: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | clock and reset control | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial | ++-----------+------------+-------------------------------------+ + +Programming and Debugging +************************* + +Flashing +======== +The MAX32650 MCU can be flashed by connecting an external debug probe to the +SWD port. SWD debug can be accessed through the Cortex 10-pin connector, J3. +Logic levels are fixed to VDDIO (1.8V). + +Once the debug probe is connected to your host computer, then you can simply run the +``west flash`` command to write a firmware image into flash. + +.. note:: + + This board uses OpenOCD as the default debug interface. You can also use + a Segger J-Link with Segger's native tooling by overriding the runner, + appending ``--runner jlink`` to your ``west`` command(s). The J-Link should + be connected to the standard 2*5 pin debug connector (J3) using an + appropriate adapter board and cable + +Debugging +========= +Please refer to the `Flashing`_ section and run the ``west debug`` command +instead of ``west flash``. + +References +********** + +- `AD-SWIOT1L-SL web page`_ + +.. _AD-SWIOT1L-SL web page: + https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/AD-SWIOT1L-SL.html From 6ce55b9a58412771339c70bc603dd88f754c6420 Mon Sep 17 00:00:00 2001 From: Yasin Ustuner Date: Wed, 12 Feb 2025 18:05:59 +0300 Subject: [PATCH 0200/6055] boards: adi: Add MAX32650FTHR board This commit adds MAX32650FTHR board basic port. Signed-off-by: Yasin Ustuner Signed-off-by: Burak Babaoglu --- boards/adi/max32650fthr/Kconfig.max32650fthr | 7 ++ boards/adi/max32650fthr/board.cmake | 8 ++ boards/adi/max32650fthr/board.yml | 9 ++ .../max32650fthr/doc/img/max32650fthr.webp | Bin 0 -> 66894 bytes boards/adi/max32650fthr/doc/index.rst | 118 ++++++++++++++++++ boards/adi/max32650fthr/max32650fthr.dts | 89 +++++++++++++ boards/adi/max32650fthr/max32650fthr.yaml | 13 ++ .../adi/max32650fthr/max32650fthr_defconfig | 16 +++ 8 files changed, 260 insertions(+) create mode 100644 boards/adi/max32650fthr/Kconfig.max32650fthr create mode 100644 boards/adi/max32650fthr/board.cmake create mode 100644 boards/adi/max32650fthr/board.yml create mode 100644 boards/adi/max32650fthr/doc/img/max32650fthr.webp create mode 100644 boards/adi/max32650fthr/doc/index.rst create mode 100644 boards/adi/max32650fthr/max32650fthr.dts create mode 100644 boards/adi/max32650fthr/max32650fthr.yaml create mode 100644 boards/adi/max32650fthr/max32650fthr_defconfig diff --git a/boards/adi/max32650fthr/Kconfig.max32650fthr b/boards/adi/max32650fthr/Kconfig.max32650fthr new file mode 100644 index 0000000000000..cf8acafe85d82 --- /dev/null +++ b/boards/adi/max32650fthr/Kconfig.max32650fthr @@ -0,0 +1,7 @@ +# MAX32650FTHR board configuration + +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_MAX32650FTHR + select SOC_MAX32650 diff --git a/boards/adi/max32650fthr/board.cmake b/boards/adi/max32650fthr/board.cmake new file mode 100644 index 0000000000000..716d812146114 --- /dev/null +++ b/boards/adi/max32650fthr/board.cmake @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=MAX32650" "--reset-after-load") + +include(${ZEPHYR_BASE}/boards/common/openocd-adi-max32.boards.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/adi/max32650fthr/board.yml b/boards/adi/max32650fthr/board.yml new file mode 100644 index 0000000000000..46dee2be23394 --- /dev/null +++ b/boards/adi/max32650fthr/board.yml @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +board: + name: max32650fthr + full_name: MAX32650FTHR + vendor: adi + socs: + - name: max32650 diff --git a/boards/adi/max32650fthr/doc/img/max32650fthr.webp b/boards/adi/max32650fthr/doc/img/max32650fthr.webp new file mode 100644 index 0000000000000000000000000000000000000000..065de009e8cfa0cfd0f7a2087766d7d90ad6b426 GIT binary patch literal 66894 zcmV(*K;FMnNk&FS1pxq8MM6+kP&gnu1pxr?Ap@NOD%S(J0X~sDnMft0BB3j`eGsq` z32bir^->4Hp4xgVyX1U)0ibq?{+s)!?vHh>bLGFle}DbC{_Xo+^C8APboqPk-{XJP ze{TK0`;`6<{lB`eAwARm=l(CcZ+tIA{g?g!_^-Piu@63yP|Ci+?Tqsrw)A-;=*Ne~|DyIo`S1GQ=RH#W zgZ&TvU-RDpKhA%=|I_~$?Z5pW4sXE!&;7Od1^$EnXaA@BpLZ|v|NDQm|9R?%>%acr z?tTP+qko6}oc8Sh|No!i2k&41|NQ?8zqh~t+;%DqdNFtOBQvBOh`oQRAVJJ7JZ>RS zW6_JhtsFdBqv)7ic-%su$D=3sl3A_;a4`H z=6rV*ojESSn>WFbJeH}r=a(-pFQ?K7bm{mv|2fk>!i$6|RnlpDg3mC_C5qPn%P=$- ziC5M4$-JPZrHLE&N zb}5agwWAd+H)b+gC+D7BW!RiNLM0)A@!o

^_M@Eno`MzYJ2EYz0JbwA!}?Z{OPG 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 AQvd(} literal 0 HcmV?d00001 diff --git a/boards/adi/max32650fthr/doc/index.rst b/boards/adi/max32650fthr/doc/index.rst new file mode 100644 index 0000000000000..b9e71d4931766 --- /dev/null +++ b/boards/adi/max32650fthr/doc/index.rst @@ -0,0 +1,118 @@ +.. zephyr:board:: max32650fthr + +Overview +******** +The MAX32650FTHR evaluation kit provides a platform for evaluating the capabilities +of the MAX32650 ultra-low-power memory-scalable microcontroller designed specifically +for high-performance, battery-powered applications. + +The Zephyr port is running on the MAX32650 MCU. + +.. image:: img/max32650fthr.webp + :align: center + :alt: MAX32650 FTHR Front + +Hardware +******** + +- MAX32650 MCU: + + - Ultra Efficient Microcontroller for Battery-Powered Applications + + - 120MHz Arm Cortex-M4 with FPU + - SmartDMA Provides Background Memory Transfers with Programmable Data Processing + - 120MHz High-Speed and 50MHz Low-Power Oscillators + - 7.3728MHz Low Power Oscillators + - 32.768kHz and RTC Clock (Requires External Crystal) + - 8kHz, Always-on, Ultra-Low-Power Oscillator + - 3MB Internal Flash, 1MB Internal SRAM + - 104µW/MHz Executing from Cache at 1.1V + - Five Low-Power Modes: Active, Sleep, Background, Deep-Sleep, and Backup + - 1.8V and 3.3V I/O with No Level Translators + - Programming and Debugging + + - Scalable Cached External Memory Interfaces + + - 120MB/s HyperBus/Xccela DDR Interface + - SPIXF/SPIXR for External Flash/RAM Expansion + - 240Mbps SDHC/eMMC/SDIO/microSD Interface + + - Optimal Peripheral Mix Provides Platform Scalability + + - 16-Channel DMA + - Three SPI Master (60MHz)/Slave (48MHz) + - One QuadSPI Master (60MHz)/Slave (48MHz) + - Up to Three 4Mbaud UARTs with Flow Control + - Two 1MHz I2C Master/Slave + - I2S Slave + - Four-Channel, 7.8ksps, 10-bit Delta-Sigma ADC + - USB 2.0 Hi-Speed Device Interface with PHY + - 16 Pulse Train Generators + - Six 32-bit Timers with 8mA Hi-Drive + - 1-Wire® Master + + - Trust Protection Unit (TPU) for IP/Data and Security + + - Modular Arithmetic Accelerator (MAA), True Random Number Generator (TRNG) + - Secure Nonvolatile Key Storage, SHA-256, AES-128/192/256 + - Memory Decryption Integrity Unit, Secure Boot ROM + +- External devices connected to the MAX32650FTHR: + + - Battery Connector and Charging Circuit + - Micro-SD Card Interface + - USB 2.0 Full-Speed Device Interface + - MAX11261 6-Channel, 24-Bit, 16ksps, ADC + - Adafruit® Feather Board Compatible + +Supported Features +================== + +The ``max32650fthr`` board supports the following interfaces: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | clock and reset control | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial | ++-----------+------------+-------------------------------------+ + +Programming and Debugging +************************* + +Flashing +======== +The MAX32650 MCU can be flashed by connecting an external debug probe to the +SWD port. SWD debug can be accessed through the Cortex 10-pin connector, J5. +Logic levels are fixed to VDDIO (1.8V). + +Once the debug probe is connected to your host computer, then you can simply run the +``west flash`` command to write a firmware image into flash. + +.. note:: + + This board uses OpenOCD as the default debug interface. You can also use + a Segger J-Link with Segger's native tooling by overriding the runner, + appending ``--runner jlink`` to your ``west`` command(s). The J-Link should + be connected to the standard 2*5 pin debug connector (J5) using an + appropriate adapter board and cable + +Debugging +========= +Please refer to the `Flashing`_ section and run the ``west debug`` command +instead of ``west flash``. + +References +********** + +- `MAX32650FTHR web page`_ + +.. _MAX32650FTHR web page: + https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650fthr.html diff --git a/boards/adi/max32650fthr/max32650fthr.dts b/boards/adi/max32650fthr/max32650fthr.dts new file mode 100644 index 0000000000000..b471e2523ce0f --- /dev/null +++ b/boards/adi/max32650fthr/max32650fthr.dts @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include + +/ { + model = "Analog Devices MAX32650FTHR"; + compatible = "adi,max32650fthr"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + + led1: led_1 { + gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; + label = "Red LED"; + }; + + led2: led_2 { + gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + }; + + buttons { + compatible = "gpio-keys"; + + pb1: pb1 { + gpios = <&gpio1 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW2"; + zephyr,code = ; + }; + + pb2: pb2 { + gpios = <&gpio1 21 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW3"; + zephyr,code = ; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led1; + led1 = &led2; + }; +}; + +&uart0 { + pinctrl-0 = <&uart0_tx_p2_12 &uart0_rx_p2_11>; + pinctrl-names = "default"; + current-speed = <115200>; + data-bits = <8>; + parity = "none"; + status = "okay"; +}; + +&clk_ipo { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpio3 { + status = "okay"; +}; diff --git a/boards/adi/max32650fthr/max32650fthr.yaml b/boards/adi/max32650fthr/max32650fthr.yaml new file mode 100644 index 0000000000000..f967621e7020c --- /dev/null +++ b/boards/adi/max32650fthr/max32650fthr.yaml @@ -0,0 +1,13 @@ +identifier: max32650fthr +name: max32650fthr +vendor: adi +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - serial +ram: 1024 +flash: 3072 diff --git a/boards/adi/max32650fthr/max32650fthr_defconfig b/boards/adi/max32650fthr/max32650fthr_defconfig new file mode 100644 index 0000000000000..9428e5334a08f --- /dev/null +++ b/boards/adi/max32650fthr/max32650fthr_defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable GPIO +CONFIG_GPIO=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable UART +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y From d043a214264bc6dab5313854a1014f7a964dceae Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Thu, 30 Jan 2025 11:17:14 +0100 Subject: [PATCH 0201/6055] llext-edk: add Kconfig option to enable EDK generation Add a new Kconfig option to make the generation of an Extension Development Kit (EDK) for the LLEXT subsystem optional. This allows to cleanly separate EDK-related configuration and build steps from the rest of the Zeprhyr build system. Signed-off-by: Luca Burelli --- CMakeLists.txt | 56 +++++++++++++++++++++++--------------------- subsys/llext/Kconfig | 13 ++++++++-- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16a471ae6ee64..0776004ef49d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2220,46 +2220,48 @@ if((CMAKE_BUILD_TYPE IN_LIST build_types) AND (NOT NO_BUILD_TYPE_WARNING)) endif() # Extension Development Kit (EDK) generation. -set(llext_edk_file ${PROJECT_BINARY_DIR}/${CONFIG_LLEXT_EDK_NAME}.tar.xz) +if(CONFIG_LLEXT_EDK) + set(llext_edk_file ${PROJECT_BINARY_DIR}/${CONFIG_LLEXT_EDK_NAME}.tar.xz) -# TODO maybe generate flags for C CXX ASM -zephyr_get_compile_definitions_for_lang(C zephyr_defs) -zephyr_get_compile_options_for_lang(C zephyr_flags) + # TODO maybe generate flags for C CXX ASM + zephyr_get_compile_definitions_for_lang(C zephyr_defs) + 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_filt_flags) -llext_filter_zephyr_flags(LLEXT_EDK_REMOVE_FLAGS ${llext_filt_flags} llext_filt_flags) + # Filter out non LLEXT and LLEXT_EDK flags - and add required ones + llext_filter_zephyr_flags(LLEXT_REMOVE_FLAGS ${zephyr_flags} llext_filt_flags) + llext_filter_zephyr_flags(LLEXT_EDK_REMOVE_FLAGS ${llext_filt_flags} llext_filt_flags) -set(llext_edk_cflags ${zephyr_defs} -DLL_EXTENSION_BUILD) -list(APPEND llext_edk_cflags ${llext_filt_flags}) -list(APPEND llext_edk_cflags ${LLEXT_APPEND_FLAGS}) -list(APPEND llext_edk_cflags ${LLEXT_EDK_APPEND_FLAGS}) + set(llext_edk_cflags ${zephyr_defs} -DLL_EXTENSION_BUILD) + list(APPEND llext_edk_cflags ${llext_filt_flags}) + list(APPEND llext_edk_cflags ${LLEXT_APPEND_FLAGS}) + list(APPEND llext_edk_cflags ${LLEXT_EDK_APPEND_FLAGS}) -build_info(llext-edk file PATH ${llext_edk_file}) -build_info(llext-edk cflags VALUE ${llext_edk_cflags}) -build_info(llext-edk include-dirs VALUE "$") + build_info(llext-edk file PATH ${llext_edk_file}) + build_info(llext-edk cflags VALUE ${llext_edk_cflags}) + build_info(llext-edk include-dirs VALUE "$") -add_custom_command( + 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/zephyr + -E make_directory edk/include/generated/zephyr COMMAND - ${PYTHON_EXECUTABLE} - ${ZEPHYR_BASE}/scripts/build/gen_syscalls.py - --json-file ${syscalls_json} # Read this file - --base-output edk/include/generated/zephyr/syscalls # Write to this dir - --syscall-dispatch edk/include/generated/zephyr/syscall_dispatch.c # Write this file - --syscall-list ${edk_syscall_list_h} - $<$:--userspace-only> - ${SYSCALL_LONG_REGISTERS_ARG} - ${SYSCALL_SPLIT_TIMEOUT_ARG} + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/build/gen_syscalls.py + --json-file ${syscalls_json} # Read this file + --base-output edk/include/generated/zephyr/syscalls # Write to this dir + --syscall-dispatch edk/include/generated/zephyr/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} -P ${ZEPHYR_BASE}/cmake/llext-edk.cmake DEPENDS ${logical_target_for_zephyr_elf} build_info_yaml_saved COMMAND_EXPAND_LISTS -) -add_custom_target(llext-edk DEPENDS ${llext_edk_file}) + ) + add_custom_target(llext-edk DEPENDS ${llext_edk_file}) +endif() # @Intent: Set compiler specific flags for standard C/C++ includes # Done at the very end, so any other system includes which may diff --git a/subsys/llext/Kconfig b/subsys/llext/Kconfig index 0125901825168..488eca671318e 100644 --- a/subsys/llext/Kconfig +++ b/subsys/llext/Kconfig @@ -126,7 +126,16 @@ source "subsys/logging/Kconfig.template.log_config" endif -menu "Linkable loadable Extension Development Kit (EDK)" +menuconfig LLEXT_EDK + bool "Linkable loadable Extension Development Kit (EDK)" + default y if LLEXT + help + Enable the generation of an Extension Development Kit (EDK) for the + Linkable Loadable Extension subsystem. The EDK is an archive that + contains the necessary files and build settings to build extensions + for Zephyr without the need to have the full Zephyr source tree. + +if LLEXT_EDK config LLEXT_EDK_NAME string "Name for llext EDK (Extension Development Kit)" @@ -145,4 +154,4 @@ config LLEXT_EDK_USERSPACE_ONLY 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 +endif From c188dee3343206de1519d551ac28bff335c578bb Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Thu, 30 Jan 2025 11:23:44 +0100 Subject: [PATCH 0202/6055] llext-edk: add support for Zstd and Zip formats This patch adds support for Zstd and Zip formats to the EDK generation process. The user can now choose between XZ, Zstd, and Zip compression and output formats for the EDK file. Signed-off-by: Luca Burelli --- CMakeLists.txt | 11 ++++++++++- cmake/llext-edk.cmake | 13 +++++++++++-- subsys/llext/Kconfig | 29 +++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0776004ef49d0..48234f675abce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2221,7 +2221,16 @@ endif() # Extension Development Kit (EDK) generation. if(CONFIG_LLEXT_EDK) - set(llext_edk_file ${PROJECT_BINARY_DIR}/${CONFIG_LLEXT_EDK_NAME}.tar.xz) + if(CONFIG_LLEXT_EDK_FORMAT_TAR_XZ) + set(llext_edk_extension "tar.xz") + elseif(CONFIG_LLEXT_EDK_FORMAT_TAR_ZSTD) + set(llext_edk_extension "tar.Z") + elseif(CONFIG_LLEXT_EDK_FORMAT_ZIP) + set(llext_edk_extension "zip") + else() + message(FATAL_ERROR "Unsupported LLEXT_EDK_FORMAT choice") + endif() + set(llext_edk_file ${PROJECT_BINARY_DIR}/${CONFIG_LLEXT_EDK_NAME}.${llext_edk_extension}) # TODO maybe generate flags for C CXX ASM zephyr_get_compile_definitions_for_lang(C zephyr_defs) diff --git a/cmake/llext-edk.cmake b/cmake/llext-edk.cmake index ff3f1660f010c..e4add3ebb2186 100644 --- a/cmake/llext-edk.cmake +++ b/cmake/llext-edk.cmake @@ -238,12 +238,21 @@ foreach(target ${edk_targets}) edk_write_var(${target} "LLEXT_GENERATED_IMACROS_CFLAGS" "${imacros_gen}") endforeach() +if(CONFIG_LLEXT_EDK_FORMAT_TAR_XZ) + set(llext_edk_format FORMAT gnutar COMPRESSION XZ) +elseif(CONFIG_LLEXT_EDK_FORMAT_TAR_ZSTD) + set(llext_edk_format FORMAT gnutar COMPRESSION Zstd) +elseif(CONFIG_LLEXT_EDK_FORMAT_ZIP) + set(llext_edk_format FORMAT zip) +else() + message(FATAL_ERROR "Unsupported LLEXT_EDK_FORMAT choice") +endif() + # Generate the tarball file(ARCHIVE_CREATE OUTPUT ${llext_edk_file} PATHS ${llext_edk} - FORMAT gnutar - COMPRESSION XZ + ${llext_edk_format} ) file(REMOVE_RECURSE ${llext_edk}) diff --git a/subsys/llext/Kconfig b/subsys/llext/Kconfig index 488eca671318e..2b0baa0c5e741 100644 --- a/subsys/llext/Kconfig +++ b/subsys/llext/Kconfig @@ -141,13 +141,38 @@ 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. + will be used when generating the EDK file; the appropriate + extension will be appended depending on the chosen output format. 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. +choice LLEXT_EDK_FORMAT +prompt "EDK compression and output format" +default LLEXT_EDK_FORMAT_TAR_XZ + +config LLEXT_EDK_FORMAT_TAR_XZ + bool ".tar.xz" + help + Use GNU tar with XZ compression for the EDK file. Highest compression + ratio, slower choice. + +config LLEXT_EDK_FORMAT_TAR_ZSTD + bool ".tar.Z" + help + Use GNU tar with Zstd compression for the EDK file. Way faster than + XZ, but still with a high compression ratio. + +config LLEXT_EDK_FORMAT_ZIP + bool ".zip" + help + Use Zip format and compression for the EDK file. This is the most + portable option, but it may not compress as well as XZ or Zstd. + +endchoice + config LLEXT_EDK_USERSPACE_ONLY - bool "Only generate the Userpace codepath on syscall stubs for the EDK" + bool "Only generate the Userspace 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 From a3474b76dc712d7f6339f19d468506459f8482ed Mon Sep 17 00:00:00 2001 From: Sean Madigan Date: Tue, 11 Feb 2025 16:01:08 +0000 Subject: [PATCH 0203/6055] dts: nordic: nrf5340: Revert nRF5340 IPC backend to rpmsg This reverts commit 70419bdee7ffd4ea7248f2b3f4c1a5a9d5a75c76. This is because there are issues around slow IPC thoughput with icbmsg, which is causing issues with BLE when lots of data is required to be exchanged, e.g. with ISO. Also there is an assert icmsg.c#L190 which occurs when initializing bluetooth and IPC in certain circumstances. Signed-off-by: Sean Madigan --- ...340_dvk_nrf5340_cpuapp_partition_conf.dtsi | 4 +-- .../bl5340_dvk_nrf5340_cpunet_common.dtsi | 4 +-- ...dvk_nrf5340_shared_sram_planning_conf.dtsi | 31 +++++++++++++++++++ dts/arm/nordic/nrf5340_cpuapp_ipc.dtsi | 10 +++--- dts/arm/nordic/nrf5340_cpunet.dtsi | 10 +++--- .../nordic/nrf5340_shared_sram_partition.dtsi | 14 +-------- 6 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_shared_sram_planning_conf.dtsi diff --git a/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_cpuapp_partition_conf.dtsi b/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_cpuapp_partition_conf.dtsi index 2fc651230f454..b85e3d03dc2d7 100644 --- a/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_cpuapp_partition_conf.dtsi +++ b/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_cpuapp_partition_conf.dtsi @@ -57,5 +57,5 @@ reg = <0x20040000 0x30000>; }; -/* Include default shared RAM configuration file */ -#include +/* Include shared RAM configuration file */ +#include "bl5340_dvk_nrf5340_shared_sram_planning_conf.dtsi" diff --git a/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_cpunet_common.dtsi b/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_cpunet_common.dtsi index 1f5fc0bb3405a..ce2e145d58753 100644 --- a/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_cpunet_common.dtsi +++ b/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_cpunet_common.dtsi @@ -63,5 +63,5 @@ }; }; -/* Include default shared RAM configuration file */ -#include +/* Include shared RAM configuration file */ +#include "bl5340_dvk_nrf5340_shared_sram_planning_conf.dtsi" diff --git a/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_shared_sram_planning_conf.dtsi b/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_shared_sram_planning_conf.dtsi new file mode 100644 index 0000000000000..fbb059494c36b --- /dev/null +++ b/boards/ezurio/bl5340_dvk/bl5340_dvk_nrf5340_shared_sram_planning_conf.dtsi @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * Copyright (c) 2021 Laird Connectivity + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Default shared SRAM planning when building for BL5340 DVK. + * This file is included by both nRF5340 CPUAPP (Application MCU) + * and nRF5340 CPUNET (Network MCU). + * - 64 kB SRAM allocated as Shared memory (sram0_shared) + * - Region defined after the image SRAM of Application MCU + */ + +/ { + chosen { + /* shared memory reserved for the inter-processor communication */ + zephyr,ipc_shm = &sram0_shared; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_shared: memory@20070000 { + /* SRAM allocated to shared memory */ + reg = <0x20070000 0x10000>; + }; + }; +}; diff --git a/dts/arm/nordic/nrf5340_cpuapp_ipc.dtsi b/dts/arm/nordic/nrf5340_cpuapp_ipc.dtsi index 3e2eb31054262..f5cda20e9613f 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_ipc.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_ipc.dtsi @@ -5,14 +5,12 @@ */ ipc0: ipc0 { - compatible = "zephyr,ipc-icbmsg"; - status = "okay"; + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&sram0_shared>; mboxes = <&mbox 0>, <&mbox 1>; mbox-names = "tx", "rx"; - tx-region = <&cpuapp_cpunet_ipc_shm>; - rx-region = <&cpunet_cpuapp_ipc_shm>; - tx-blocks = <32>; - rx-blocks = <32>; + role = "host"; + status = "okay"; bt_hci_ipc0: bt_hci_ipc0 { compatible = "zephyr,bt-hci-ipc"; diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index 4916703310945..acf95077669d5 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -347,14 +347,12 @@ /* Default IPC description */ ipc { ipc0: ipc0 { - compatible = "zephyr,ipc-icbmsg"; - status = "okay"; + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&sram0_shared>; mboxes = <&mbox 0>, <&mbox 1>; mbox-names = "rx", "tx"; - tx-region = <&cpunet_cpuapp_ipc_shm>; - rx-region = <&cpuapp_cpunet_ipc_shm>; - tx-blocks = <32>; - rx-blocks = <32>; + role = "remote"; + status = "okay"; }; }; }; diff --git a/dts/common/nordic/nrf5340_shared_sram_partition.dtsi b/dts/common/nordic/nrf5340_shared_sram_partition.dtsi index 8dc217ceae9ea..a5dc3489e893e 100644 --- a/dts/common/nordic/nrf5340_shared_sram_partition.dtsi +++ b/dts/common/nordic/nrf5340_shared_sram_partition.dtsi @@ -14,9 +14,7 @@ * the memory range allocated to the non-secure image (sram0_ns). * * By default the last 64 kB of application core SRAM is allocated as shared - * memory (sram0_shared) which is divided in: - * - 32 kB CPUAPP to CPUNET communication (cpuapp_cpunet_ipc_shm) - * - 32 kB CPUNET to CPUAPP communication (cpunet_cpuapp_ipc_shm) + * memory (sram0_shared). */ / { @@ -30,18 +28,8 @@ ranges; sram0_shared: memory@20070000 { - #address-cells = <1>; - #size-cells = <1>; /* Last 64 kB of sram0 */ reg = <0x20070000 0x10000>; - - cpuapp_cpunet_ipc_shm: memory@20070000 { - reg = <0x20070000 DT_SIZE_K(32)>; - }; - - cpunet_cpuapp_ipc_shm: memory@20078000 { - reg = <0x20078000 DT_SIZE_K(32)>; - }; }; }; }; From 9bcc89deb6a32f5e027e3bd255b5a07a257a7743 Mon Sep 17 00:00:00 2001 From: Khaoula Bidani Date: Mon, 10 Feb 2025 15:51:31 +0100 Subject: [PATCH 0204/6055] drivers : can: replace LL_RCC_GetFDCANClockFreq replace LL_RCC_GetFDCANClockFreq, remove stm32_ll_rcc.h include and use_stm32_ll_rcc from kconfig. Signed-off-by: Khaoula Bidani --- drivers/can/Kconfig.stm32 | 2 -- drivers/can/can_stm32_fdcan.c | 26 +++++++++++++++++++++----- drivers/can/can_stm32h7_fdcan.c | 28 ++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/drivers/can/Kconfig.stm32 b/drivers/can/Kconfig.stm32 index 65da04a7225f3..7a9bfae3a731f 100644 --- a/drivers/can/Kconfig.stm32 +++ b/drivers/can/Kconfig.stm32 @@ -54,7 +54,6 @@ config CAN_STM32_FDCAN depends on DT_HAS_ST_STM32_FDCAN_ENABLED select CAN_MCAN select PINCTRL - select USE_STM32_LL_RCC if CAN_STM32_FDCAN @@ -82,4 +81,3 @@ config CAN_STM32H7_FDCAN depends on DT_HAS_ST_STM32H7_FDCAN_ENABLED select CAN_MCAN select PINCTRL - select USE_STM32_LL_RCC diff --git a/drivers/can/can_stm32_fdcan.c b/drivers/can/can_stm32_fdcan.c index 44605a3237a97..ebed4c6939b64 100644 --- a/drivers/can/can_stm32_fdcan.c +++ b/drivers/can/can_stm32_fdcan.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -403,13 +402,30 @@ static int can_stm32fd_clear_mram(const struct device *dev, uint16_t offset, siz static int can_stm32fd_get_core_clock(const struct device *dev, uint32_t *rate) { - const uint32_t rate_tmp = LL_RCC_GetFDCANClockFreq(LL_RCC_FDCAN_CLKSOURCE); + uint32_t rate_tmp; + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_stm32fd_config *stm32fd_cfg = mcan_cfg->custom; + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); ARG_UNUSED(dev); + if (!device_is_ready(clk)) { + return -ENODEV; + } - if (rate_tmp == LL_RCC_PERIPH_FREQUENCY_NO) { - LOG_ERR("Can't read core clock"); - return -EIO; + if (IS_ENABLED(STM32_CANFD_DOMAIN_CLOCK_SUPPORT) && (stm32fd_cfg->pclk_len > 1)) { + if (clock_control_get_rate(clk, + (clock_control_subsys_t) &stm32fd_cfg->pclken[1], + &rate_tmp) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclk[1])"); + return -EIO; + } + } else { + if (clock_control_get_rate(clk, + (clock_control_subsys_t) &stm32fd_cfg->pclken[0], + &rate_tmp) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclk[0])"); + return -EIO; + } } if (FDCAN_CONFIG->CKDIV == 0) { diff --git a/drivers/can/can_stm32h7_fdcan.c b/drivers/can/can_stm32h7_fdcan.c index 912358b14624b..9e3c5ceb055c2 100644 --- a/drivers/can/can_stm32h7_fdcan.c +++ b/drivers/can/can_stm32h7_fdcan.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -84,16 +83,33 @@ static int can_stm32h7_clear_mram(const struct device *dev, uint16_t offset, siz static int can_stm32h7_get_core_clock(const struct device *dev, uint32_t *rate) { - const uint32_t rate_tmp = LL_RCC_GetFDCANClockFreq(LL_RCC_FDCAN_CLKSOURCE); + uint32_t rate_tmp; + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); uint32_t cdiv; ARG_UNUSED(dev); - - if (rate_tmp == LL_RCC_PERIPH_FREQUENCY_NO) { - LOG_ERR("Can't read core clock"); - return -EIO; + if (!device_is_ready(clk)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; } + if (IS_ENABLED(STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT) && (stm32h7_cfg->pclk_len > 1)) { + if (clock_control_get_rate(clk, + (clock_control_subsys_t) &stm32h7_cfg->pclken[1], + &rate_tmp) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclk[1])"); + return -EIO; + } + } else { + if (clock_control_get_rate(clk, + (clock_control_subsys_t) &stm32h7_cfg->pclken[0], + &rate_tmp) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclk[0])"); + return -EIO; + } + } cdiv = FIELD_GET(FDCANCCU_CCFG_CDIV, FDCAN_CCU->CCFG); if (cdiv == 0U) { *rate = rate_tmp; From d7eab212bc13b87b60ce35a53bf393515f6f311d Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Wed, 12 Feb 2025 13:05:28 +0300 Subject: [PATCH 0205/6055] drivers: counter: counter_max32:_rtc: Update api_start This commit removes redundant initialization. The following PR addresses the issue caused by the offset https://github.com/zephyrproject-rtos/zephyr/commit/5a2055 Signed-off-by: Okan Sahin --- drivers/counter/counter_max32_rtc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/counter/counter_max32_rtc.c b/drivers/counter/counter_max32_rtc.c index 74e5c86f3b66d..832a1394508cf 100644 --- a/drivers/counter/counter_max32_rtc.c +++ b/drivers/counter/counter_max32_rtc.c @@ -38,11 +38,6 @@ struct max32_rtc_config { static int api_start(const struct device *dev) { - /* Ensure that both sec and subsec are reset to 0 */ - while (MXC_RTC_Init(0, 0) == E_BUSY) { - ; - } - while (MXC_RTC_Start() == E_BUSY) { ; } From 68dc1b5ebf48d783b1c6b92f5167a2a980fbfd20 Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Wed, 12 Feb 2025 11:16:54 +0100 Subject: [PATCH 0206/6055] drivers: i2c: i2c_omap: Add pinctrl Extend the I2c OMAP driver to automatically mux pins require by this interfaces. Signed-off-by: Daniel Schultz --- drivers/i2c/Kconfig.omap | 1 + drivers/i2c/i2c_omap.c | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/Kconfig.omap b/drivers/i2c/Kconfig.omap index 8081cfc6ebdd9..4b7951eb0e83c 100644 --- a/drivers/i2c/Kconfig.omap +++ b/drivers/i2c/Kconfig.omap @@ -7,6 +7,7 @@ config I2C_OMAP bool "TI OMAP I2C Driver" default y depends on DT_HAS_TI_OMAP_I2C_ENABLED + select PINCTRL help Enable the I2C driver for TI OMAP SoCs. diff --git a/drivers/i2c/i2c_omap.c b/drivers/i2c/i2c_omap.c index ea953978614ac..222232d106e57 100644 --- a/drivers/i2c/i2c_omap.c +++ b/drivers/i2c/i2c_omap.c @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef CONFIG_I2C_OMAP_BUS_RECOVERY #include "i2c_bitbang.h" @@ -104,6 +105,7 @@ struct i2c_omap_cfg { DEVICE_MMIO_NAMED_ROM(base); uint32_t irq; uint32_t speed; + const struct pinctrl_dev_config *pcfg; }; enum i2c_omap_speed { @@ -680,6 +682,13 @@ static int i2c_omap_init(const struct device *dev) { struct i2c_omap_data *data = DEV_DATA(dev); const struct i2c_omap_cfg *cfg = DEV_CFG(dev); + int ret; + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("failed to apply pinctrl"); + return ret; + } k_sem_init(&data->lock, 1, 1); /* Set the speed for I2C */ @@ -692,17 +701,24 @@ static int i2c_omap_init(const struct device *dev) } #define I2C_OMAP_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ LOG_INSTANCE_REGISTER(omap_i2c, inst, CONFIG_I2C_LOG_LEVEL); \ static const struct i2c_omap_cfg i2c_omap_cfg_##inst = { \ DEVICE_MMIO_NAMED_ROM_INIT(base, DT_DRV_INST(inst)), \ .irq = DT_INST_IRQN(inst), \ .speed = DT_INST_PROP(inst, clock_frequency), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ }; \ \ static struct i2c_omap_data i2c_omap_data_##inst; \ \ - I2C_DEVICE_DT_INST_DEFINE(inst, i2c_omap_init, NULL, &i2c_omap_data_##inst, \ - &i2c_omap_cfg_##inst, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ - &i2c_omap_api); + I2C_DEVICE_DT_INST_DEFINE(inst, \ + i2c_omap_init, \ + NULL, \ + &i2c_omap_data_##inst, \ + &i2c_omap_cfg_##inst, \ + POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, \ + &i2c_omap_api); DT_INST_FOREACH_STATUS_OKAY(I2C_OMAP_INIT) From 5150e5ce4e24b0a12b231704726594570a8d2e9a Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Wed, 12 Feb 2025 10:52:44 +0100 Subject: [PATCH 0207/6055] boards: NXP MCXN947 remove cpu1 partition This commit reverts using of cpu1_partition because it is taking space from slot0 and slot1 partitions. For now use slot1 partition for cpu1. Signed-off-by: Tomas Galbicka --- boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi | 10 +++------- boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi | 2 +- boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.dts | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi b/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi index ee965dfef1a2e..3ebc13c0e9a99 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi @@ -162,15 +162,11 @@ nxp_8080_touch_panel_i2c: &flexcomm2_lpi2c2 { */ slot0_partition: partition@14000 { label = "image-0"; - reg = <0x00014000 DT_SIZE_K(888)>; + reg = <0x00014000 DT_SIZE_K(984)>; }; - slot1_partition: partition@F2000 { + slot1_partition: partition@10A000 { label = "image-1"; - reg = <0x000F2000 DT_SIZE_K(888)>; - }; - cpu1_partition: partition@1D0000 { - label = "cpu1-image"; - reg = <0x001D0000 DT_SIZE_K(192)>; + reg = <0x0010A000 DT_SIZE_K(984)>; }; /* storage_partition is placed in WINBOND flash memory*/ }; diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi index ec2880077b34b..d74efb27ac64e 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi @@ -27,7 +27,7 @@ zephyr,console = &flexcomm4_lpuart4; zephyr,shell-uart = &flexcomm4_lpuart4; zephyr,canbus = &flexcan0; - zephyr,code-cpu1-partition = &cpu1_partition; + zephyr,code-cpu1-partition = &slot1_partition; }; aliases{ diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.dts b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.dts index 456c94239fa56..78fc22c12a713 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.dts +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu1.dts @@ -21,7 +21,7 @@ zephyr,sram = &sramg; zephyr,flash = &flash; zephyr,flash-controller = &fmu; - zephyr,code-partition = &cpu1_partition; + zephyr,code-partition = &slot1_partition; zephyr,console = &flexcomm2_lpuart2; zephyr,shell-uart = &flexcomm2_lpuart2; }; From 326df4a31a296c7c5a9d6a921d4e58a227b2b8cf Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 12 Feb 2025 12:49:53 +0000 Subject: [PATCH 0208/6055] west.yml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: 346f7374ff4467e40b5594658f8ac67a5e9813c9 Brings following Zephyr relevant fixes: - 2aa6da15 boot: Add flash area ID/device ID retrieval hooks - b3ed5cc6 boot: New boot_go hook - dbbcb78b boot/zephyr: Fix SINGLE_APPLICATION_SLOT_RAM_LOAD file inclusion - 33094fc5 boot: bootutil: loader: Fix issue with stuck revert Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 67584f741836e..01fcb72d3a92d 100644 --- a/west.yml +++ b/west.yml @@ -303,7 +303,7 @@ manifest: groups: - crypto - name: mcuboot - revision: 9a02794a14fa2e539ffe039a986360590d9e025f + revision: 346f7374ff4467e40b5594658f8ac67a5e9813c9 path: bootloader/mcuboot groups: - bootloader From aa6d4830ccda8c90588cd9e0b5a3d16f42f922de Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 13 Feb 2025 12:06:22 +0100 Subject: [PATCH 0209/6055] manifest: Update nRF hw models to latest Update the HW models module to dcfcffeee5c3ad8718723df4b5297caec33c23e7 Including the following: * dcfcffe UART: Support diffent clocks, correct UART00 clock and fix BAUDRATE model Signed-off-by: Alberto Escolar Piedras --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 01fcb72d3a92d..86e16f29fce28 100644 --- a/west.yml +++ b/west.yml @@ -318,7 +318,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 5dc34b26662c6ec91edf1174d775d78590b1a05b + revision: dcfcffeee5c3ad8718723df4b5297caec33c23e7 path: modules/bsim_hw_models/nrf_hw_models - name: nrf_wifi revision: e35f707a782b7c4c0eb83a3b06ca4e6eb693f29f From 5e7df92082ccb084ba13c2abf98f8512a00ad192 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 13 Feb 2025 12:23:38 +0100 Subject: [PATCH 0210/6055] boards nrf54l15bsim: Do not work around peripheral clock issue In 923d313a04726f6475b19ef803eb8b5a080e91d7 the clock frequency in DTS for the UART00 was fixed, but not for the simulated target. This was likely due to the HW models modeling it as 16MHz instead of 128MHz for this particular one as it is in reality. Now that the HW models have been fixed, let's let this clock be configured like for real HW. Signed-off-by: Alberto Escolar Piedras --- boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts index 2cf31d1df597e..40b7e0a45bed3 100644 --- a/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts +++ b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts @@ -83,10 +83,6 @@ }; }; -&uart00 { - /delete-property/ clocks; -}; - &uart20 { status = "okay"; current-speed = <115200>; From cc50765f8ed5b3cb2bfedfb9603572969702f172 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Wed, 15 Jan 2025 14:06:01 -0800 Subject: [PATCH 0211/6055] toolchain: Add macros to disable compiler warnings These macros allow disabling compiler warnings for all compilers or only gcc or only clang. Signed-off-by: Tom Hughes --- include/zephyr/toolchain.h | 64 +++++++++++++++++++++++++++++++++ include/zephyr/toolchain/gcc.h | 15 ++++++++ include/zephyr/toolchain/llvm.h | 3 ++ 3 files changed, 82 insertions(+) diff --git a/include/zephyr/toolchain.h b/include/zephyr/toolchain.h index f8df4915736c6..bc389ae55656e 100644 --- a/include/zephyr/toolchain.h +++ b/include/zephyr/toolchain.h @@ -145,6 +145,70 @@ #define TOOLCHAIN_IGNORE_WSHADOW_END #endif +/** + * @def TOOLCHAIN_PRAGMA + * @brief Helper for using pragma in macros. + */ +#ifdef TOOLCHAIN_HAS_PRAGMA_DIAG +#define TOOLCHAIN_PRAGMA(x) _Pragma(#x) +#else +#define TOOLCHAIN_PRAGMA(x) +#endif + +/** + * @def TOOLCHAIN_DISABLE_WARNING + * @brief Disable the specified compiler warning for all compilers. + */ +#ifndef TOOLCHAIN_DISABLE_WARNING +#define TOOLCHAIN_DISABLE_WARNING(warning) +#endif + +/** + * @def TOOLCHAIN_ENABLE_WARNING + * @brief Re-enable the specified compiler warning for all compilers. + * + * Can only be used after a call to @ref TOOLCHAIN_DISABLE_WARNING. + */ +#ifndef TOOLCHAIN_ENABLE_WARNING +#define TOOLCHAIN_ENABLE_WARNING(warning) +#endif + +/** + * @def TOOLCHAIN_DISABLE_CLANG_WARNING + * @brief Disable the specified compiler warning for clang. + */ +#ifndef TOOLCHAIN_DISABLE_CLANG_WARNING +#define TOOLCHAIN_DISABLE_CLANG_WARNING(warning) +#endif + +/** + * @def TOOLCHAIN_ENABLE_CLANG_WARNING + * @brief Re-enable the specified compiler warning for clang. + * + * Can only be used after a call to @ref TOOLCHAIN_DISABLE_CLANG_WARNING. + */ +#ifndef TOOLCHAIN_ENABLE_CLANG_WARNING +#define TOOLCHAIN_ENABLE_CLANG_WARNING(warning) +#endif + +/** + * @def TOOLCHAIN_DISABLE_GCC_WARNING + * @brief Disable the specified compiler warning for gcc. + */ +#ifndef TOOLCHAIN_DISABLE_GCC_WARNING +#define TOOLCHAIN_DISABLE_GCC_WARNING(warning) +#endif + +/** + * @def TOOLCHAIN_ENABLE_GCC_WARNING + * @brief Re-enable the specified compiler warning for gcc. + * + * Can only be used after a call to @ref TOOLCHAIN_DISABLE_GCC_WARNING. + */ +#ifndef TOOLCHAIN_ENABLE_GCC_WARNING +#define TOOLCHAIN_ENABLE_GCC_WARNING(warning) +#endif + /* * Ensure that __BYTE_ORDER__ and related preprocessor definitions are defined, * and that they match the Kconfig option that is used in the code itself to diff --git a/include/zephyr/toolchain/gcc.h b/include/zephyr/toolchain/gcc.h index dbff83e8bbdae..e003cd2c26f74 100644 --- a/include/zephyr/toolchain/gcc.h +++ b/include/zephyr/toolchain/gcc.h @@ -687,4 +687,19 @@ do { \ _Pragma("GCC diagnostic pop") #endif /* !_LINKER */ + +#define _TOOLCHAIN_DISABLE_WARNING(compiler, warning) \ + TOOLCHAIN_PRAGMA(compiler diagnostic push) \ + TOOLCHAIN_PRAGMA(compiler diagnostic ignored warning) + +#define _TOOLCHAIN_ENABLE_WARNING(compiler, warning) TOOLCHAIN_PRAGMA(compiler diagnostic pop) + +#define TOOLCHAIN_DISABLE_WARNING(warning) _TOOLCHAIN_DISABLE_WARNING(GCC, warning) +#define TOOLCHAIN_ENABLE_WARNING(warning) _TOOLCHAIN_ENABLE_WARNING(GCC, warning) + +#if defined(__GNUC__) && !defined(__clang__) +#define TOOLCHAIN_DISABLE_GCC_WARNING(warning) _TOOLCHAIN_DISABLE_WARNING(GCC, warning) +#define TOOLCHAIN_ENABLE_GCC_WARNING(warning) _TOOLCHAIN_ENABLE_WARNING(GCC, warning) +#endif + #endif /* ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_ */ diff --git a/include/zephyr/toolchain/llvm.h b/include/zephyr/toolchain/llvm.h index a895680730517..7eea8347c6cd8 100644 --- a/include/zephyr/toolchain/llvm.h +++ b/include/zephyr/toolchain/llvm.h @@ -30,6 +30,9 @@ #include +#define TOOLCHAIN_DISABLE_CLANG_WARNING(warning) _TOOLCHAIN_DISABLE_WARNING(clang, warning) +#define TOOLCHAIN_ENABLE_CLANG_WARNING(warning) _TOOLCHAIN_ENABLE_WARNING(clang, warning) + /* * Provide these definitions only when minimal libc is used. * Avoid collision with defines from include/zephyr/toolchain/zephyr_stdint.h From af6d97dcf4aba71961d7de710e91d100aa78851b Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Mon, 27 Jan 2025 12:06:21 +0100 Subject: [PATCH 0212/6055] include: zephyr: dt-bindings: clock: fix missing STM32 header files Add inclusion of stm32f4_clock.h header file that is missing in stm32f410 and stm32f427 DT bindings clock header files. Signed-off-by: Etienne Carriere --- include/zephyr/dt-bindings/clock/stm32f410_clock.h | 2 ++ include/zephyr/dt-bindings/clock/stm32f427_clock.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/zephyr/dt-bindings/clock/stm32f410_clock.h b/include/zephyr/dt-bindings/clock/stm32f410_clock.h index fffd47321f6e8..40fb89ec0d1f4 100644 --- a/include/zephyr/dt-bindings/clock/stm32f410_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f410_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F410_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F410_CLOCK_H_ +#include "stm32f4_clock.h" + /** @brief RCC_DCKCFGR register offset */ #define DCKCFGR_REG 0x8C #define DCKCFGR2_REG 0x94 diff --git a/include/zephyr/dt-bindings/clock/stm32f427_clock.h b/include/zephyr/dt-bindings/clock/stm32f427_clock.h index 97d22836be512..baf62fd76c272 100644 --- a/include/zephyr/dt-bindings/clock/stm32f427_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f427_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F427_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F427_CLOCK_H_ +#include "stm32f4_clock.h" + /** @brief RCC_DCKCFGR register offset */ #define DCKCFGR_REG 0x8C From 3b8b266821ccddb9590b8b72217de5858ee08763 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Mon, 27 Jan 2025 12:06:16 +0100 Subject: [PATCH 0213/6055] include: zephyr: dt-bindings: clock: factorize STM32_* clock source macros Factorize definitions of the macros used to describe in the STM32 boards device tree the RCC register dedicated to clock source selection configuration, instead of replicating the macros per SoC header file. For that purpose, use DT cell bit fields that matches all SoCs. This change also factorizes STM32_MCO_CFGR_* macros that use the same packing layout for defining selection of the MCO clocks and for MCO pre-scaling factor on SoCs that support the feature. By the way, reorder argument description in macro inline description comment in a standard way (first argument first). Signed-off-by: Etienne Carriere --- .../dt-bindings/clock/stm32_common_clocks.h | 69 ++++++++++++------- .../zephyr/dt-bindings/clock/stm32c0_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32f0_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32f1_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32f3_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32f4_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32f7_clock.h | 29 -------- .../zephyr/dt-bindings/clock/stm32g0_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32g4_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32h5_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32h7_clock.h | 28 -------- .../dt-bindings/clock/stm32h7rs_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32l0_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32l1_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32l4_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32n6_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32u0_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32u5_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32wb0_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32wb_clock.h | 28 -------- .../zephyr/dt-bindings/clock/stm32wba_clock.h | 29 -------- .../zephyr/dt-bindings/clock/stm32wl_clock.h | 28 -------- 22 files changed, 46 insertions(+), 613 deletions(-) diff --git a/include/zephyr/dt-bindings/clock/stm32_common_clocks.h b/include/zephyr/dt-bindings/clock/stm32_common_clocks.h index 5c1015471dd1b..bd24aa2d3d9f1 100644 --- a/include/zephyr/dt-bindings/clock/stm32_common_clocks.h +++ b/include/zephyr/dt-bindings/clock/stm32_common_clocks.h @@ -20,35 +20,58 @@ /** Clock divider */ #define STM32_CLOCK_DIV(div) (((div) - 1) << STM32_CLOCK_DIV_SHIFT) -/** STM32 MCO configuration values */ -#define STM32_MCO_CFGR_REG_MASK 0xFFFFU -#define STM32_MCO_CFGR_REG_SHIFT 0U -#define STM32_MCO_CFGR_SHIFT_MASK 0x3FU -#define STM32_MCO_CFGR_SHIFT_SHIFT 16U -#define STM32_MCO_CFGR_MASK_MASK 0x1FU -#define STM32_MCO_CFGR_MASK_SHIFT 22U -#define STM32_MCO_CFGR_VAL_MASK 0x1FU -#define STM32_MCO_CFGR_VAL_SHIFT 27U +/** Helper macros to pack RCC clock source selection register info in the DT */ +#define STM32_DT_CLKSEL_REG_MASK 0xFFFFU +#define STM32_DT_CLKSEL_REG_SHIFT 0U +#define STM32_DT_CLKSEL_SHIFT_MASK 0x3FU +#define STM32_DT_CLKSEL_SHIFT_SHIFT 16U +#define STM32_DT_CLKSEL_MASK_MASK 0x1FU +#define STM32_DT_CLKSEL_MASK_SHIFT 22U +#define STM32_DT_CLKSEL_VAL_MASK 0x1FU +#define STM32_DT_CLKSEL_VAL_SHIFT 27U /** - * @brief STM32 MCO configuration register bit field + * @brief Pack STM32 source clock selection RCC register bit fields for the DT * - * @param reg Offset to RCC register holding MCO configuration - * @param shift Position of field within RCC register (= field LSB's index) - * @param mask Mask of register field in RCC register - * @param val Clock configuration field value (0~0x1F) + * @param val Clock configuration field value + * @param mask Mask of register field in RCC register + * @param shift Position of field within RCC register (= field LSB's index) + * @param reg Offset to target clock configuration register in RCC * - * @note 'reg' range: 0x0~0xFFFF [ 00 : 15 ] - * @note 'shift' range: 0~63 [ 16 : 21 ] - * @note 'mask' range: 0x00~0x1F [ 22 : 26 ] + * @note 'reg' range: 0x0~0xFFFF [ 00 : 15 ] + * @note 'shift' range: 0~63 [ 16 : 21 ] + * @note 'mask' range: 0x00~0x1F [ 22 : 26 ] * @note 'val' range: 0x00~0x1F [ 27 : 31 ] - * */ -#define STM32_MCO_CFGR(val, mask, shift, reg) \ - ((((reg) & STM32_MCO_CFGR_REG_MASK) << STM32_MCO_CFGR_REG_SHIFT) | \ - (((shift) & STM32_MCO_CFGR_SHIFT_MASK) << STM32_MCO_CFGR_SHIFT_SHIFT) | \ - (((mask) & STM32_MCO_CFGR_MASK_MASK) << STM32_MCO_CFGR_MASK_SHIFT) | \ - (((val) & STM32_MCO_CFGR_VAL_MASK) << STM32_MCO_CFGR_VAL_SHIFT)) +#define STM32_DT_CLOCK_SELECT(val, mask, shift, reg) \ + ((((reg) & STM32_DT_CLKSEL_REG_MASK) << STM32_DT_CLKSEL_REG_SHIFT) | \ + (((shift) & STM32_DT_CLKSEL_SHIFT_MASK) << STM32_DT_CLKSEL_SHIFT_SHIFT) | \ + (((mask) & STM32_DT_CLKSEL_MASK_MASK) << STM32_DT_CLKSEL_MASK_SHIFT) | \ + (((val) & STM32_DT_CLKSEL_VAL_MASK) << STM32_DT_CLKSEL_VAL_SHIFT)) + +/* STM32_CLOCK_* macros, defined for convenience */ +#define STM32_CLOCK_REG_MASK STM32_DT_CLKSEL_REG_MASK +#define STM32_CLOCK_REG_SHIFT STM32_DT_CLKSEL_REG_SHIFT +#define STM32_CLOCK_SHIFT_MASK STM32_DT_CLKSEL_SHIFT_MASK +#define STM32_CLOCK_SHIFT_SHIFT STM32_DT_CLKSEL_SHIFT_SHIFT +#define STM32_CLOCK_MASK_MASK STM32_DT_CLKSEL_MASK_MASK +#define STM32_CLOCK_MASK_SHIFT STM32_DT_CLKSEL_MASK_SHIFT +#define STM32_CLOCK_VAL_MASK STM32_DT_CLKSEL_VAL_MASK +#define STM32_CLOCK_VAL_SHIFT STM32_DT_CLKSEL_VAL_SHIFT +#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ + STM32_DT_CLOCK_SELECT((val), (mask), (shift), (reg)) + +/* STM32_MCO_CFGR_* macros, defined for convenience */ +#define STM32_MCO_CFGR_REG_MASK STM32_DT_CLKSEL_REG_MASK +#define STM32_MCO_CFGR_REG_SHIFT STM32_DT_CLKSEL_REG_SHIFT +#define STM32_MCO_CFGR_SHIFT_MASK STM32_DT_CLKSEL_SHIFT_MASK +#define STM32_MCO_CFGR_SHIFT_SHIFT STM32_DT_CLKSEL_SHIFT_SHIFT +#define STM32_MCO_CFGR_MASK_MASK STM32_DT_CLKSEL_MASK_MASK +#define STM32_MCO_CFGR_MASK_SHIFT STM32_DT_CLKSEL_MASK_SHIFT +#define STM32_MCO_CFGR_VAL_MASK STM32_DT_CLKSEL_VAL_MASK +#define STM32_MCO_CFGR_VAL_SHIFT STM32_DT_CLKSEL_VAL_SHIFT +#define STM32_MCO_CFGR(val, mask, shift, reg) \ + STM32_DT_CLOCK_SELECT((val), (mask), (shift), (reg)) /** * Pack RCC clock register offset and bit in two 32-bit values diff --git a/include/zephyr/dt-bindings/clock/stm32c0_clock.h b/include/zephyr/dt-bindings/clock/stm32c0_clock.h index 517e2cc9696b5..49aa3036266db 100644 --- a/include/zephyr/dt-bindings/clock/stm32c0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32c0_clock.h @@ -29,34 +29,6 @@ /** Peripheral bus clock */ #define STM32_SRC_PCLK (STM32_SRC_HSE + 1) -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPR register offset */ #define CCIPR_REG 0x54 diff --git a/include/zephyr/dt-bindings/clock/stm32f0_clock.h b/include/zephyr/dt-bindings/clock/stm32f0_clock.h index 7572c1c422f1c..74db2ebaa56fa 100644 --- a/include/zephyr/dt-bindings/clock/stm32f0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f0_clock.h @@ -30,34 +30,6 @@ /** PLL clock */ #define STM32_SRC_PLLCLK (STM32_SRC_PCLK + 1) -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CFGRx register offset - * @param shift Position within RCC_CFGRx. - * @param mask Mask for the RCC_CFGRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CFGRx register offset */ #define CFGR1_REG 0x04 #define CFGR3_REG 0x30 diff --git a/include/zephyr/dt-bindings/clock/stm32f1_clock.h b/include/zephyr/dt-bindings/clock/stm32f1_clock.h index f6777932c77b1..673082b0aa293 100644 --- a/include/zephyr/dt-bindings/clock/stm32f1_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f1_clock.h @@ -28,34 +28,6 @@ #define STM32_SRC_EXT_HSE (STM32_SRC_HSE + 1) #define STM32_SRC_PLLCLK (STM32_SRC_EXT_HSE + 1) -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CFGRx register offset - * @param shift Position within RCC_CFGRx. - * @param mask Mask for the RCC_CFGRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CFGRx register offset */ #define CFGR1_REG 0x04 #define CFGR2_REG 0x2C diff --git a/include/zephyr/dt-bindings/clock/stm32f3_clock.h b/include/zephyr/dt-bindings/clock/stm32f3_clock.h index c00d1dd59c38a..e880c4dcf6d9a 100644 --- a/include/zephyr/dt-bindings/clock/stm32f3_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f3_clock.h @@ -31,34 +31,6 @@ /** PLL clock */ #define STM32_SRC_PLLCLK (STM32_SRC_PCLK + 1) -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CFGRx register offset - * @param shift Position within RCC_CFGRx. - * @param mask Mask for the RCC_CFGRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CFGRx register offset */ #define CFGR_REG 0x04 #define CFGR3_REG 0x30 diff --git a/include/zephyr/dt-bindings/clock/stm32f4_clock.h b/include/zephyr/dt-bindings/clock/stm32f4_clock.h index 02290fc105104..75c7d36c790d8 100644 --- a/include/zephyr/dt-bindings/clock/stm32f4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f4_clock.h @@ -43,34 +43,6 @@ /* I2S_CKIN not supported yet */ /* #define STM32_SRC_I2S_CKIN TBD */ -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CFGRx register offset - * @param shift Position within RCC_CFGRx. - * @param mask Mask for the RCC_CFGRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CFGRx register offset */ #define CFGR_REG 0x08 /** @brief RCC_BDCR register offset */ diff --git a/include/zephyr/dt-bindings/clock/stm32f7_clock.h b/include/zephyr/dt-bindings/clock/stm32f7_clock.h index a729aea88f11a..992cb3bb32f92 100644 --- a/include/zephyr/dt-bindings/clock/stm32f7_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f7_clock.h @@ -40,35 +40,6 @@ #define STM32_SRC_PLLI2S_R (STM32_SRC_PCLK + 1) - -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CFGRx register offset - * @param shift Position within RCC_CFGRx. - * @param mask Mask for the RCC_CFGRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CFGRx register offset */ #define CFGR_REG 0x08 diff --git a/include/zephyr/dt-bindings/clock/stm32g0_clock.h b/include/zephyr/dt-bindings/clock/stm32g0_clock.h index b7d7714b1b15b..31d2f69dcb9f6 100644 --- a/include/zephyr/dt-bindings/clock/stm32g0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32g0_clock.h @@ -35,34 +35,6 @@ #define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) #define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPR register offset */ #define CCIPR_REG 0x54 #define CCIPR2_REG 0x58 diff --git a/include/zephyr/dt-bindings/clock/stm32g4_clock.h b/include/zephyr/dt-bindings/clock/stm32g4_clock.h index a7d928c801f49..5966702b154b5 100644 --- a/include/zephyr/dt-bindings/clock/stm32g4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32g4_clock.h @@ -39,34 +39,6 @@ #define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /* TODO: PLLSAI clocks */ -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPR register offset */ #define CCIPR_REG 0x88 #define CCIPR2_REG 0x9C diff --git a/include/zephyr/dt-bindings/clock/stm32h5_clock.h b/include/zephyr/dt-bindings/clock/stm32h5_clock.h index cbac2d667436a..093b6ff141ccf 100644 --- a/include/zephyr/dt-bindings/clock/stm32h5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h5_clock.h @@ -51,34 +51,6 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB1 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB3 -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32H5 clock configuration bit field. - * - * - reg (1/2/3/4/5) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPRx register offset (RM0456.pdf) */ #define CCIPR1_REG 0xD8 #define CCIPR2_REG 0xDC diff --git a/include/zephyr/dt-bindings/clock/stm32h7_clock.h b/include/zephyr/dt-bindings/clock/stm32h7_clock.h index 92c954cdc86b6..51e2bdebda419 100644 --- a/include/zephyr/dt-bindings/clock/stm32h7_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h7_clock.h @@ -58,34 +58,6 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB3 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB4 -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32H7 clock configuration bit field. - * - * - reg (0/1) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..3) [ 16 : 18 ] - * - * @param reg RCC_DxCCIP register offset - * @param shift Position within RCC_DxCCIP. - * @param mask Mask for the RCC_DxCCIP field. - * @param val Clock value (0, 1, 2 or 3). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_DxCCIP register offset (RM0399.pdf) */ #define D1CCIPR_REG 0x4C #define D2CCIP1R_REG 0x50 diff --git a/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h b/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h index 44698cbeca4b1..7abec704244be 100644 --- a/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h @@ -54,34 +54,6 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB5 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_AHB3 -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32H7RS clock configuration bit field. - * - * - reg (0/1) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..3) [ 16 : 18 ] - * - * @param reg RCC_DxCCIP register offset - * @param shift Position within RCC_DxCCIP. - * @param mask Mask for the RCC_DxCCIP field. - * @param val Clock value (0, 1, 2 or 3). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_DxCCIP register offset (RM0477.pdf) */ #define D1CCIPR_REG 0x4C #define D2CCIPR_REG 0x50 diff --git a/include/zephyr/dt-bindings/clock/stm32l0_clock.h b/include/zephyr/dt-bindings/clock/stm32l0_clock.h index c16e367a94e32..4284561bb6064 100644 --- a/include/zephyr/dt-bindings/clock/stm32l0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l0_clock.h @@ -31,34 +31,6 @@ /** Bus clock */ #define STM32_SRC_PCLK (STM32_SRC_HSI48 + 1) -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPR register offset */ #define CCIPR_REG 0x4C diff --git a/include/zephyr/dt-bindings/clock/stm32l1_clock.h b/include/zephyr/dt-bindings/clock/stm32l1_clock.h index f958f7b6bb8fa..c6276cdf54837 100644 --- a/include/zephyr/dt-bindings/clock/stm32l1_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l1_clock.h @@ -26,34 +26,6 @@ #define STM32_SRC_HSE (STM32_SRC_LSI + 1) #define STM32_SRC_HSI (STM32_SRC_HSE + 1) -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CSR register offset */ #define CSR_REG 0x34 diff --git a/include/zephyr/dt-bindings/clock/stm32l4_clock.h b/include/zephyr/dt-bindings/clock/stm32l4_clock.h index 3e865f9a880e2..31bfd4509b60c 100644 --- a/include/zephyr/dt-bindings/clock/stm32l4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l4_clock.h @@ -37,34 +37,6 @@ #define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /* TODO: PLLSAI clocks */ -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPR register offset */ #define CCIPR_REG 0x88 #define CCIPR2_REG 0x9C diff --git a/include/zephyr/dt-bindings/clock/stm32n6_clock.h b/include/zephyr/dt-bindings/clock/stm32n6_clock.h index 156ca1f27abe5..4566ed1306a68 100644 --- a/include/zephyr/dt-bindings/clock/stm32n6_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32n6_clock.h @@ -65,34 +65,6 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB1 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB5 -#define STM32_CLOCK_REG_MASK 0xFFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 12U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 17U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 20U - -/** - * @brief STM32U5 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 11 ] - * - shift (0..31) [ 12 : 16 ] - * - mask (0x1, 0x3, 0x7) [ 17 : 19 ] - * - val (0..7) [ 20 : 22 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPRx register offset (RM0468.pdf) */ #define CCIPR1_REG 0x144 #define CCIPR2_REG 0x148 diff --git a/include/zephyr/dt-bindings/clock/stm32u0_clock.h b/include/zephyr/dt-bindings/clock/stm32u0_clock.h index 476c423608256..d212e42cddf3c 100644 --- a/include/zephyr/dt-bindings/clock/stm32u0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u0_clock.h @@ -36,34 +36,6 @@ #define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) #define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPR register offset */ #define CCIPR_REG 0x88 diff --git a/include/zephyr/dt-bindings/clock/stm32u5_clock.h b/include/zephyr/dt-bindings/clock/stm32u5_clock.h index 4bb1f349cdde4..d37688291c154 100644 --- a/include/zephyr/dt-bindings/clock/stm32u5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u5_clock.h @@ -52,34 +52,6 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB1 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB3 -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32U5 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPRx register offset (RM0456.pdf) */ #define CCIPR1_REG 0xE0 #define CCIPR2_REG 0xE4 diff --git a/include/zephyr/dt-bindings/clock/stm32wb0_clock.h b/include/zephyr/dt-bindings/clock/stm32wb0_clock.h index 23ba8e996086e..3a790dc510094 100644 --- a/include/zephyr/dt-bindings/clock/stm32wb0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wb0_clock.h @@ -27,34 +27,6 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB0 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB2 -#define STM32_CLOCK_REG_MASK (0xFFFFU) -#define STM32_CLOCK_REG_SHIFT (0U) -#define STM32_CLOCK_SHIFT_MASK (0x3FU) -#define STM32_CLOCK_SHIFT_SHIFT (16U) -#define STM32_CLOCK_MASK_MASK (0x1FU) -#define STM32_CLOCK_MASK_SHIFT (22U) -#define STM32_CLOCK_VAL_MASK STM32_CLOCK_MASK_MASK -#define STM32_CLOCK_VAL_SHIFT (27U) - -/** - * @brief STM32 clock configuration bit field - * - * @param reg Offset to target configuration register in RCC - * @param shift Position of field within RCC register (= field LSB's index) - * @param mask Mask of field in RCC register - * @param val Field value - * - * @note 'reg' range: 0x0~0xFFFF [ 00 : 15 ] - * @note 'shift' range: 0~63 [ 16 : 21 ] - * @note 'mask' range: 0x00~0x1F [ 22 : 26 ] - * @note 'val' range: 0x00~0x1F [ 27 : 31 ] - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CFGR register offset */ #define CFGR_REG 0x08 diff --git a/include/zephyr/dt-bindings/clock/stm32wb_clock.h b/include/zephyr/dt-bindings/clock/stm32wb_clock.h index 31786c8675dd3..fa89141ccc513 100644 --- a/include/zephyr/dt-bindings/clock/stm32wb_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wb_clock.h @@ -38,34 +38,6 @@ #define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /* TODO: PLLSAI clocks */ -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPR register offset */ #define CCIPR_REG 0x88 diff --git a/include/zephyr/dt-bindings/clock/stm32wba_clock.h b/include/zephyr/dt-bindings/clock/stm32wba_clock.h index 51c7b398d0435..769e937897c03 100644 --- a/include/zephyr/dt-bindings/clock/stm32wba_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wba_clock.h @@ -45,35 +45,6 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB1 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB7 -/** - * @brief STM32WBA clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ - -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPRx register offset (RM0493.pdf) */ #define CCIPR1_REG 0xE0 #define CCIPR2_REG 0xE4 diff --git a/include/zephyr/dt-bindings/clock/stm32wl_clock.h b/include/zephyr/dt-bindings/clock/stm32wl_clock.h index 7384703267e43..7872fed0e828b 100644 --- a/include/zephyr/dt-bindings/clock/stm32wl_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wl_clock.h @@ -38,34 +38,6 @@ #define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) #define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) -#define STM32_CLOCK_REG_MASK 0xFFU -#define STM32_CLOCK_REG_SHIFT 0U -#define STM32_CLOCK_SHIFT_MASK 0x1FU -#define STM32_CLOCK_SHIFT_SHIFT 8U -#define STM32_CLOCK_MASK_MASK 0x7U -#define STM32_CLOCK_MASK_SHIFT 13U -#define STM32_CLOCK_VAL_MASK 0x7U -#define STM32_CLOCK_VAL_SHIFT 16U - -/** - * @brief STM32 clock configuration bit field. - * - * - reg (1/2/3) [ 0 : 7 ] - * - shift (0..31) [ 8 : 12 ] - * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] - * - val (0..7) [ 16 : 18 ] - * - * @param reg RCC_CCIPRx register offset - * @param shift Position within RCC_CCIPRx. - * @param mask Mask for the RCC_CCIPRx field. - * @param val Clock value (0, 1, ... 7). - */ -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ - (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ - (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ - (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) - /** @brief RCC_CCIPR register offset */ #define CCIPR_REG 0x88 From 7113c06acfac5d7632375fb79309397e5f1f764f Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Fri, 14 Feb 2025 11:04:52 +0100 Subject: [PATCH 0214/6055] include: zephyr: dt-bindings: clock: use STM32 common clock source macros Replace STM32_DOMAIN_CLOCK() and STM32_MCO_CFGR() macros in stm32 DT clock bindings header file with the common macro STM32_DT_CLOCK_SELECT(). By the way, add parentheses on argument where it mas missing. Signed-off-by: Etienne Carriere --- .../zephyr/dt-bindings/clock/stm32c0_clock.h | 18 +-- .../zephyr/dt-bindings/clock/stm32f0_clock.h | 18 +-- .../dt-bindings/clock/stm32f10x_clock.h | 2 +- .../zephyr/dt-bindings/clock/stm32f1_clock.h | 8 +- .../zephyr/dt-bindings/clock/stm32f3_clock.h | 40 +++--- .../dt-bindings/clock/stm32f410_clock.h | 22 ++-- .../dt-bindings/clock/stm32f427_clock.h | 14 +-- .../zephyr/dt-bindings/clock/stm32f4_clock.h | 12 +- .../zephyr/dt-bindings/clock/stm32f7_clock.h | 48 +++---- .../zephyr/dt-bindings/clock/stm32g0_clock.h | 38 +++--- .../zephyr/dt-bindings/clock/stm32g4_clock.h | 38 +++--- .../zephyr/dt-bindings/clock/stm32h5_clock.h | 98 +++++++-------- .../zephyr/dt-bindings/clock/stm32h7_clock.h | 68 +++++----- .../dt-bindings/clock/stm32h7rs_clock.h | 56 ++++----- .../zephyr/dt-bindings/clock/stm32l0_clock.h | 16 +-- .../zephyr/dt-bindings/clock/stm32l1_clock.h | 2 +- .../zephyr/dt-bindings/clock/stm32l4_clock.h | 56 ++++----- .../zephyr/dt-bindings/clock/stm32n6_clock.h | 118 +++++++++--------- .../zephyr/dt-bindings/clock/stm32u0_clock.h | 30 ++--- .../zephyr/dt-bindings/clock/stm32u5_clock.h | 80 ++++++------ .../zephyr/dt-bindings/clock/stm32wb0_clock.h | 9 +- .../zephyr/dt-bindings/clock/stm32wb_clock.h | 24 ++-- .../zephyr/dt-bindings/clock/stm32wba_clock.h | 32 ++--- .../zephyr/dt-bindings/clock/stm32wl_clock.h | 26 ++-- 24 files changed, 438 insertions(+), 435 deletions(-) diff --git a/include/zephyr/dt-bindings/clock/stm32c0_clock.h b/include/zephyr/dt-bindings/clock/stm32c0_clock.h index 49aa3036266db..00b5078ac163d 100644 --- a/include/zephyr/dt-bindings/clock/stm32c0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32c0_clock.h @@ -40,18 +40,18 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR_REG) -#define I2C2_I2S1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, CCIPR_REG) -#define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, CCIPR_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR_REG) +#define I2C2_I2S1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, CCIPR_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 30, CCIPR_REG) /** CSR1 devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CSR1_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CSR1_REG) /** CFGR1 devices */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0x7, 24, CFGR1_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 28, CFGR1_REG) -#define MCO2_SEL(val) STM32_MCO_CFGR(val, 0x7, 16, CFGR1_REG) -#define MCO2_PRE(val) STM32_MCO_CFGR(val, 0x7, 20, CFGR1_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x7, 24, CFGR1_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 28, CFGR1_REG) +#define MCO2_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x7, 16, CFGR1_REG) +#define MCO2_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 20, CFGR1_REG) /* MCO prescaler : division factor */ #define MCO_PRE_DIV_1 0 diff --git a/include/zephyr/dt-bindings/clock/stm32f0_clock.h b/include/zephyr/dt-bindings/clock/stm32f0_clock.h index 74db2ebaa56fa..56b87128e7128 100644 --- a/include/zephyr/dt-bindings/clock/stm32f0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f0_clock.h @@ -39,17 +39,17 @@ /** @brief Device domain clocks selection helpers */ /** CFGR3 devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CFGR3_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 4, CFGR3_REG) -#define CEC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 6, CFGR3_REG) -#define USB_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 7, CFGR3_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CFGR3_REG) -#define USART3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CFGR3_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CFGR3_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 4, CFGR3_REG) +#define CEC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 6, CFGR3_REG) +#define USB_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 7, CFGR3_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CFGR3_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CFGR3_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /** CFGR1 devices */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0xF, 24, CFGR1_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 28, CFGR1_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0xF, 24, CFGR1_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 28, CFGR1_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f10x_clock.h b/include/zephyr/dt-bindings/clock/stm32f10x_clock.h index 05f2b598a0552..7fe9948521961 100644 --- a/include/zephyr/dt-bindings/clock/stm32f10x_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f10x_clock.h @@ -19,7 +19,7 @@ /** CFGR1 devices */ #undef MCO1_SEL /* Need to redefine generic F1 MCO_SEL for connectivity line devices. */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0xF, 24, CFGR1_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0xF, 24, CFGR1_REG) /* No MCO prescaler support on STM32F1 series. */ #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F10X_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f1_clock.h b/include/zephyr/dt-bindings/clock/stm32f1_clock.h index 673082b0aa293..83f1a0f748ed3 100644 --- a/include/zephyr/dt-bindings/clock/stm32f1_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f1_clock.h @@ -37,13 +37,13 @@ /** @brief Device domain clocks selection helpers */ /** CFGR2 devices */ -#define I2S2_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 17, CFGR2_REG) -#define I2S3_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 18, CFGR2_REG) +#define I2S2_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 17, CFGR2_REG) +#define I2S3_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 18, CFGR2_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /** CFGR1 devices */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0x7, 24, CFGR1_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x7, 24, CFGR1_REG) /* No MCO prescaler support on STM32F1 series. */ #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F1_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f3_clock.h b/include/zephyr/dt-bindings/clock/stm32f3_clock.h index e880c4dcf6d9a..4617d6727c24f 100644 --- a/include/zephyr/dt-bindings/clock/stm32f3_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f3_clock.h @@ -40,27 +40,27 @@ /** @brief Device domain clocks selection helpers) */ /** CFGR devices */ -#define I2S_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 23, CFGR_REG) -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0x7, 24, CFGR_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 28, CFGR_REG) +#define I2S_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 23, CFGR_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x7, 24, CFGR_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 28, CFGR_REG) /** CFGR3 devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CFGR3_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 4, CFGR3_REG) -#define I2C2_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 5, CFGR3_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 6, CFGR3_REG) -#define TIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 8, CFGR3_REG) -#define TIM8_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 9, CFGR3_REG) -#define TIM15_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 10, CFGR3_REG) -#define TIM16_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 11, CFGR3_REG) -#define TIM17_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 13, CFGR3_REG) -#define TIM20_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 15, CFGR3_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CFGR3_REG) -#define USART3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CFGR3_REG) -#define USART4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CFGR3_REG) -#define USART5_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CFGR3_REG) -#define TIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 24, CFGR3_REG) -#define TIM3_4_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 25, CFGR3_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CFGR3_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 4, CFGR3_REG) +#define I2C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 5, CFGR3_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 6, CFGR3_REG) +#define TIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 8, CFGR3_REG) +#define TIM8_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 9, CFGR3_REG) +#define TIM15_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 10, CFGR3_REG) +#define TIM16_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 11, CFGR3_REG) +#define TIM17_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 13, CFGR3_REG) +#define TIM20_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 15, CFGR3_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CFGR3_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CFGR3_REG) +#define USART4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CFGR3_REG) +#define USART5_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CFGR3_REG) +#define TIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 24, CFGR3_REG) +#define TIM3_4_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 25, CFGR3_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F3_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f410_clock.h b/include/zephyr/dt-bindings/clock/stm32f410_clock.h index 40fb89ec0d1f4..eb7a39c3fb7c3 100644 --- a/include/zephyr/dt-bindings/clock/stm32f410_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f410_clock.h @@ -14,19 +14,19 @@ /** @brief Device domain clocks selection helpers */ /** DCKCFGR devices */ -#define CKDFSDM2A_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 14, DCKCFGR_REG) -#define CKDFSDM1A_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 15, DCKCFGR_REG) -#define SAI1A_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, DCKCFGR_REG) -#define SAI1B_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, DCKCFGR_REG) -#define I2S1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 25, DCKCFGR_REG) -#define I2S2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 27, DCKCFGR_REG) -#define CKDFSDM_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 31, DCKCFGR_REG) +#define CKDFSDM2A_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 14, DCKCFGR_REG) +#define CKDFSDM1A_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 15, DCKCFGR_REG) +#define SAI1A_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, DCKCFGR_REG) +#define SAI1B_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, DCKCFGR_REG) +#define I2S1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 25, DCKCFGR_REG) +#define I2S2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 27, DCKCFGR_REG) +#define CKDFSDM_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 31, DCKCFGR_REG) /** DCKCFGR2 devices */ -#define I2CFMP1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, DCKCFGR2_REG) -#define CK48M_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 27, DCKCFGR2_REG) -#define SDIO_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 28, DCKCFGR2_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, DCKCFGR2_REG) +#define I2CFMP1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, DCKCFGR2_REG) +#define CK48M_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 27, DCKCFGR2_REG) +#define SDIO_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 28, DCKCFGR2_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 30, DCKCFGR2_REG) /* F4 generic I2S_SEL is not compatible with F410 devices */ #ifdef I2S_SEL diff --git a/include/zephyr/dt-bindings/clock/stm32f427_clock.h b/include/zephyr/dt-bindings/clock/stm32f427_clock.h index baf62fd76c272..4fb2f72325f6f 100644 --- a/include/zephyr/dt-bindings/clock/stm32f427_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f427_clock.h @@ -13,12 +13,12 @@ /** @brief Device domain clocks selection helpers */ /** DCKCFGR devices */ -#define CKDFSDM2A_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 14, DCKCFGR_REG) -#define CKDFSDM1A_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 15, DCKCFGR_REG) -#define SAI1A_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, DCKCFGR_REG) -#define SAI1B_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, DCKCFGR_REG) -#define CLK48M_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 27, DCKCFGR_REG) -#define SDMMC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 28, DCKCFGR_REG) -#define DSI_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 29, DCKCFGR_REG) +#define CKDFSDM2A_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 14, DCKCFGR_REG) +#define CKDFSDM1A_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 15, DCKCFGR_REG) +#define SAI1A_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, DCKCFGR_REG) +#define SAI1B_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, DCKCFGR_REG) +#define CLK48M_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 27, DCKCFGR_REG) +#define SDMMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 28, DCKCFGR_REG) +#define DSI_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 29, DCKCFGR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F427_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f4_clock.h b/include/zephyr/dt-bindings/clock/stm32f4_clock.h index 75c7d36c790d8..98e635c4a2bc6 100644 --- a/include/zephyr/dt-bindings/clock/stm32f4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f4_clock.h @@ -50,13 +50,13 @@ /** @brief Device domain clocks selection helpers */ /** CFGR devices */ -#define I2S_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 23, CFGR_REG) -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0x3, 21, CFGR_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 24, CFGR_REG) -#define MCO2_SEL(val) STM32_MCO_CFGR(val, 0x3, 30, CFGR_REG) -#define MCO2_PRE(val) STM32_MCO_CFGR(val, 0x7, 27, CFGR_REG) +#define I2S_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 23, CFGR_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x3, 21, CFGR_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 24, CFGR_REG) +#define MCO2_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x3, 30, CFGR_REG) +#define MCO2_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 27, CFGR_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /* MCO prescaler : division factor */ #define MCO_PRE_DIV_1 0 diff --git a/include/zephyr/dt-bindings/clock/stm32f7_clock.h b/include/zephyr/dt-bindings/clock/stm32f7_clock.h index 992cb3bb32f92..4bfcfdf738647 100644 --- a/include/zephyr/dt-bindings/clock/stm32f7_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f7_clock.h @@ -48,11 +48,11 @@ /** @brief Device domain clocks selection helpers */ /** CFGR devices */ -#define I2S_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 23, CFGR_REG) -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0x3, 21, CFGR_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 24, CFGR_REG) -#define MCO2_SEL(val) STM32_MCO_CFGR(val, 0x3, 30, CFGR_REG) -#define MCO2_PRE(val) STM32_MCO_CFGR(val, 0x7, 27, CFGR_REG) +#define I2S_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 23, CFGR_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x3, 21, CFGR_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 24, CFGR_REG) +#define MCO2_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x3, 30, CFGR_REG) +#define MCO2_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 27, CFGR_REG) /* MCO prescaler : division factor */ #define MCO_PRE_DIV_1 0 @@ -62,7 +62,7 @@ #define MCO_PRE_DIV_5 7 /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /** @brief RCC_DKCFGR register offset */ #define DCKCFGR1_REG 0x8C @@ -70,23 +70,23 @@ /** @brief Dedicated clocks configuration register selection helpers */ /** DKCFGR2 devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, DCKCFGR2_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, DCKCFGR2_REG) -#define USART3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, DCKCFGR2_REG) -#define USART4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, DCKCFGR2_REG) -#define USART5_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, DCKCFGR2_REG) -#define USART6_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, DCKCFGR2_REG) -#define USART7_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, DCKCFGR2_REG) -#define USART8_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, DCKCFGR2_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, DCKCFGR2_REG) -#define I2C2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, DCKCFGR2_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, DCKCFGR2_REG) -#define I2C4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, DCKCFGR2_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 24, DCKCFGR2_REG) -#define CEC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 26, DCKCFGR2_REG) -#define CK48M_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 27, DCKCFGR2_REG) -#define SDMMC1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 28, DCKCFGR2_REG) -#define SDMMC2_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 29, DCKCFGR2_REG) -#define DSI_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 30, DCKCFGR2_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, DCKCFGR2_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, DCKCFGR2_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, DCKCFGR2_REG) +#define USART4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, DCKCFGR2_REG) +#define USART5_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, DCKCFGR2_REG) +#define USART6_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, DCKCFGR2_REG) +#define USART7_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, DCKCFGR2_REG) +#define USART8_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, DCKCFGR2_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, DCKCFGR2_REG) +#define I2C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, DCKCFGR2_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, DCKCFGR2_REG) +#define I2C4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, DCKCFGR2_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, DCKCFGR2_REG) +#define CEC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 26, DCKCFGR2_REG) +#define CK48M_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 27, DCKCFGR2_REG) +#define SDMMC1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 28, DCKCFGR2_REG) +#define SDMMC2_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 29, DCKCFGR2_REG) +#define DSI_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 30, DCKCFGR2_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F7_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32g0_clock.h b/include/zephyr/dt-bindings/clock/stm32g0_clock.h index 31d2f69dcb9f6..944f3c022efb1 100644 --- a/include/zephyr/dt-bindings/clock/stm32g0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32g0_clock.h @@ -44,26 +44,26 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR_REG) -#define USART3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, CCIPR_REG) -#define CEC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 6, CCIPR_REG) -#define LPUART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CCIPR_REG) -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR_REG) -#define I2C2_I2S1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, CCIPR_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR_REG) -#define TIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 22, CCIPR_REG) -#define TIM15_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 24, CCIPR_REG) -#define RNG_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 26, CCIPR_REG) -#define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, CCIPR_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR_REG) +#define CEC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 6, CCIPR_REG) +#define LPUART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR_REG) +#define I2C2_I2S1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, CCIPR_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR_REG) +#define TIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 22, CCIPR_REG) +#define TIM15_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 24, CCIPR_REG) +#define RNG_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 26, CCIPR_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 30, CCIPR_REG) /** CCIPR2 devices */ -#define I2S1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR2_REG) -#define I2S2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR2_REG) -#define FDCAN_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CCIPR2_REG) -#define USB_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR2_REG) +#define I2S1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR2_REG) +#define I2S2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR2_REG) +#define FDCAN_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR2_REG) +#define USB_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR2_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32g4_clock.h b/include/zephyr/dt-bindings/clock/stm32g4_clock.h index 5966702b154b5..f66d0313a33ca 100644 --- a/include/zephyr/dt-bindings/clock/stm32g4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32g4_clock.h @@ -48,26 +48,26 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR_REG) -#define USART3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, CCIPR_REG) -#define USART4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, CCIPR_REG) -#define USART5_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CCIPR_REG) -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR_REG) -#define I2C2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, CCIPR_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CCIPR_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR_REG) -#define SAI1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR_REG) -#define I2S23_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR_REG) -#define FDCAN_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 24, CCIPR_REG) -#define CLK48_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 26, CCIPR_REG) -#define ADC12_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 28, CCIPR_REG) -#define ADC34_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, CCIPR_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR_REG) +#define USART4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, CCIPR_REG) +#define USART5_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR_REG) +#define I2C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, CCIPR_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CCIPR_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR_REG) +#define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR_REG) +#define I2S23_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR_REG) +#define FDCAN_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, CCIPR_REG) +#define CLK48_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 26, CCIPR_REG) +#define ADC12_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, CCIPR_REG) +#define ADC34_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 30, CCIPR_REG) /** CCIPR2 devices */ -#define I2C4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR2_REG) -#define QSPI_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR2_REG) +#define I2C4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR2_REG) +#define QSPI_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR2_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G4_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32h5_clock.h b/include/zephyr/dt-bindings/clock/stm32h5_clock.h index 093b6ff141ccf..f3ed8289ea73c 100644 --- a/include/zephyr/dt-bindings/clock/stm32h5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h5_clock.h @@ -66,67 +66,67 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR1 devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, CCIPR1_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 3, CCIPR1_REG) -#define USART3_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 6, CCIPR1_REG) -#define USART4_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 9, CCIPR1_REG) -#define USART5_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 12, CCIPR1_REG) -#define USART6_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 15, CCIPR1_REG) -#define USART7_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 18, CCIPR1_REG) -#define USART8_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 21, CCIPR1_REG) -#define USART9_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 24, CCIPR1_REG) -#define USART10_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 27, CCIPR1_REG) -#define TIMIC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 31, CCIPR1_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR1_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 3, CCIPR1_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 6, CCIPR1_REG) +#define USART4_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 9, CCIPR1_REG) +#define USART5_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, CCIPR1_REG) +#define USART6_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 15, CCIPR1_REG) +#define USART7_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 18, CCIPR1_REG) +#define USART8_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 21, CCIPR1_REG) +#define USART9_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 24, CCIPR1_REG) +#define USART10_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 27, CCIPR1_REG) +#define TIMIC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 31, CCIPR1_REG) /** CCIPR2 devices */ -#define USART11_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, CCIPR2_REG) -#define USART12_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 4, CCIPR2_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 8, CCIPR2_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 12, CCIPR2_REG) -#define LPTIM3_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 16, CCIPR2_REG) -#define LPTIM4_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 20, CCIPR2_REG) -#define LPTIM5_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 24, CCIPR2_REG) -#define LPTIM6_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 28, CCIPR2_REG) +#define USART11_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR2_REG) +#define USART12_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 4, CCIPR2_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, CCIPR2_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, CCIPR2_REG) +#define LPTIM3_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, CCIPR2_REG) +#define LPTIM4_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 20, CCIPR2_REG) +#define LPTIM5_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 24, CCIPR2_REG) +#define LPTIM6_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 28, CCIPR2_REG) /** CCIPR3 devices */ -#define SPI1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, CCIPR3_REG) -#define SPI2_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 3, CCIPR3_REG) -#define SPI3_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 6, CCIPR3_REG) -#define SPI4_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 9, CCIPR3_REG) -#define SPI5_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 12, CCIPR3_REG) -#define SPI6_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 15, CCIPR2_REG) -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 24, CCIPR3_REG) +#define SPI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR3_REG) +#define SPI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 3, CCIPR3_REG) +#define SPI3_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 6, CCIPR3_REG) +#define SPI4_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 9, CCIPR3_REG) +#define SPI5_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, CCIPR3_REG) +#define SPI6_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 15, CCIPR2_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 24, CCIPR3_REG) /** CCIPR4 devices */ -#define OCTOSPI1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR4_REG) -#define SYSTICK_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR4_REG) -#define USB_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, CCIPR4_REG) -#define SDMMC1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 6, CCIPR4_REG) -#define SDMMC2_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 7, CCIPR4_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CCIPR4_REG) -#define I2C2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR4_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR4_REG) -#define I2C4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR4_REG) -#define I3C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 24, CCIPR4_REG) +#define OCTOSPI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR4_REG) +#define SYSTICK_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR4_REG) +#define USB_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR4_REG) +#define SDMMC1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 6, CCIPR4_REG) +#define SDMMC2_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 7, CCIPR4_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CCIPR4_REG) +#define I2C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR4_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR4_REG) +#define I2C4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR4_REG) +#define I3C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, CCIPR4_REG) /** CCIPR5 devices */ -#define ADCDAC_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, CCIPR5_REG) -#define DAC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 3, CCIPR5_REG) -#define RNG_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, CCIPR5_REG) -#define CEC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, CCIPR5_REG) -#define FDCAN_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CCIPR5_REG) -#define SAI1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 16, CCIPR5_REG) -#define SAI2_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 19, CCIPR5_REG) -#define CKPER_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, CCIPR5_REG) +#define ADCDAC_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR5_REG) +#define DAC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 3, CCIPR5_REG) +#define RNG_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR5_REG) +#define CEC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, CCIPR5_REG) +#define FDCAN_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR5_REG) +#define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, CCIPR5_REG) +#define SAI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 19, CCIPR5_REG) +#define CKPER_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 30, CCIPR5_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /** CFGR1 devices */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0x7, 22, CFGR1_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0xF, 18, CFGR1_REG) -#define MCO2_SEL(val) STM32_MCO_CFGR(val, 0x7, 25, CFGR1_REG) -#define MCO2_PRE(val) STM32_MCO_CFGR(val, 0xF, 29, CFGR1_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x7, 22, CFGR1_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0xF, 18, CFGR1_REG) +#define MCO2_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x7, 25, CFGR1_REG) +#define MCO2_PRE(val) STM32_DT_CLOCK_SELECT((val), 0xF, 29, CFGR1_REG) /* MCO prescaler : division factor */ #define MCO_PRE_DIV_1 1 diff --git a/include/zephyr/dt-bindings/clock/stm32h7_clock.h b/include/zephyr/dt-bindings/clock/stm32h7_clock.h index 51e2bdebda419..aec5ffc33b91e 100644 --- a/include/zephyr/dt-bindings/clock/stm32h7_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h7_clock.h @@ -72,46 +72,46 @@ /** @brief Device domain clocks selection helpers (RM0399.pdf) */ /** D1CCIPR devices */ -#define FMC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, D1CCIPR_REG) -#define QSPI_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, D1CCIPR_REG) -#define DSI_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 8, D1CCIPR_REG) -#define SDMMC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 16, D1CCIPR_REG) -#define CKPER_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 28, D1CCIPR_REG) +#define FMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, D1CCIPR_REG) +#define QSPI_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, D1CCIPR_REG) +#define DSI_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 8, D1CCIPR_REG) +#define SDMMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 16, D1CCIPR_REG) +#define CKPER_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, D1CCIPR_REG) /* Device domain clocks selection helpers (RM0468.pdf) */ -#define OSPI_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, D1CCIPR_REG) +#define OSPI_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, D1CCIPR_REG) /** D2CCIP1R devices */ -#define SAI1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, D2CCIP1R_REG) -#define SAI23_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 6, D2CCIP1R_REG) -#define SPI123_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 12, D2CCIP1R_REG) -#define SPI45_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 16, D2CCIP1R_REG) -#define SPDIF_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, D2CCIP1R_REG) -#define DFSDM1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 24, D2CCIP1R_REG) -#define FDCAN_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 28, D2CCIP1R_REG) -#define SWP_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 31, D2CCIP1R_REG) +#define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, D2CCIP1R_REG) +#define SAI23_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 6, D2CCIP1R_REG) +#define SPI123_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, D2CCIP1R_REG) +#define SPI45_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, D2CCIP1R_REG) +#define SPDIF_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, D2CCIP1R_REG) +#define DFSDM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 24, D2CCIP1R_REG) +#define FDCAN_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, D2CCIP1R_REG) +#define SWP_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 31, D2CCIP1R_REG) /** D2CCIP2R devices */ -#define USART2345678_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, D2CCIP2R_REG) -#define USART16_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 3, D2CCIP2R_REG) -#define RNG_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, D2CCIP2R_REG) -#define I2C123_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, D2CCIP2R_REG) -#define USB_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, D2CCIP2R_REG) -#define CEC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, D2CCIP2R_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 28, D2CCIP2R_REG) +#define USART2345678_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, D2CCIP2R_REG) +#define USART16_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 3, D2CCIP2R_REG) +#define RNG_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, D2CCIP2R_REG) +#define I2C123_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, D2CCIP2R_REG) +#define USB_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, D2CCIP2R_REG) +#define CEC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, D2CCIP2R_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 28, D2CCIP2R_REG) /** D3CCIPR devices */ -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, D3CCIPR_REG) -#define I2C4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, D3CCIPR_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 10, D3CCIPR_REG) -#define LPTIM345_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 13, D3CCIPR_REG) -#define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, D3CCIPR_REG) -#define SAI4A_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 21, D3CCIPR_REG) -#define SAI4B_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 24, D3CCIPR_REG) -#define SPI6_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 28, D3CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, D3CCIPR_REG) +#define I2C4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, D3CCIPR_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 10, D3CCIPR_REG) +#define LPTIM345_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 13, D3CCIPR_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, D3CCIPR_REG) +#define SAI4A_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 21, D3CCIPR_REG) +#define SAI4B_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 24, D3CCIPR_REG) +#define SPI6_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 28, D3CCIPR_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /** CFGR devices */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0xF, 22, CFGR_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 18, CFGR_REG) -#define MCO2_SEL(val) STM32_MCO_CFGR(val, 0xF, 29, CFGR_REG) -#define MCO2_PRE(val) STM32_MCO_CFGR(val, 0x7, 25, CFGR_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0xF, 22, CFGR_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 18, CFGR_REG) +#define MCO2_SEL(val) STM32_DT_CLOCK_SELECT((val), 0xF, 29, CFGR_REG) +#define MCO2_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 25, CFGR_REG) /* MCO prescaler : division factor */ #define MCO_PRE_DIV_1 1 diff --git a/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h b/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h index 7abec704244be..d7943dbe73bca 100644 --- a/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h7rs_clock.h @@ -71,44 +71,44 @@ /* TODO to be completed */ /** D1CCIPR devices */ -#define FMC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, D1CCIPR_REG) -#define SDMMC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 2, D1CCIPR_REG) -#define XSPI1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, D1CCIPR_REG) -#define XSPI2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, D1CCIPR_REG) -#define OTGFS_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, D1CCIPR_REG) -#define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 24, D1CCIPR_REG) -#define CKPER_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 28, D1CCIPR_REG) +#define FMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, D1CCIPR_REG) +#define SDMMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 2, D1CCIPR_REG) +#define XSPI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, D1CCIPR_REG) +#define XSPI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, D1CCIPR_REG) +#define OTGFS_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, D1CCIPR_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, D1CCIPR_REG) +#define CKPER_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, D1CCIPR_REG) /** D2CCIPR devices */ -#define USART234578_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, D2CCIPR_REG) -#define SPI23_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 4, D2CCIPR_REG) -#define I2C23_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, D2CCIPR_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, D2CCIPR_REG) -#define I3C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, D2CCIPR_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 16, D2CCIPR_REG) -#define FDCAN_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, D2CCIPR_REG) +#define USART234578_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, D2CCIPR_REG) +#define SPI23_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 4, D2CCIPR_REG) +#define I2C23_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, D2CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, D2CCIPR_REG) +#define I3C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, D2CCIPR_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, D2CCIPR_REG) +#define FDCAN_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, D2CCIPR_REG) /** D3CCIPR devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, D3CCIPR_REG) -#define SPI45_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 4, D3CCIPR_REG) -#define SPI1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 8, D3CCIPR_REG) -#define SAI1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 16, D3CCIPR_REG) -#define SAI2_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 20, D3CCIPR_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, D3CCIPR_REG) +#define SPI45_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 4, D3CCIPR_REG) +#define SPI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, D3CCIPR_REG) +#define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, D3CCIPR_REG) +#define SAI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 20, D3CCIPR_REG) /** D4CCIPR devices */ -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, D4CCIPR_REG) -#define SPI6_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 4, D4CCIPR_REG) -#define LPTIM23_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 8, D4CCIPR_REG) -#define LPTIM45_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 12, D4CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, D4CCIPR_REG) +#define SPI6_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 4, D4CCIPR_REG) +#define LPTIM23_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, D4CCIPR_REG) +#define LPTIM45_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, D4CCIPR_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /** CFGR devices */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0x7, 22, CFGR_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0xF, 18, CFGR_REG) -#define MCO2_SEL(val) STM32_MCO_CFGR(val, 0x7, 29, CFGR_REG) -#define MCO2_PRE(val) STM32_MCO_CFGR(val, 0xF, 25, CFGR_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x7, 22, CFGR_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0xF, 18, CFGR_REG) +#define MCO2_SEL(val) STM32_DT_CLOCK_SELECT((val), 0x7, 29, CFGR_REG) +#define MCO2_PRE(val) STM32_DT_CLOCK_SELECT((val), 0xF, 25, CFGR_REG) /* MCO prescaler : division factor */ #define MCO_PRE_DIV_1 1 diff --git a/include/zephyr/dt-bindings/clock/stm32l0_clock.h b/include/zephyr/dt-bindings/clock/stm32l0_clock.h index 4284561bb6064..44709e7996247 100644 --- a/include/zephyr/dt-bindings/clock/stm32l0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l0_clock.h @@ -39,14 +39,14 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR_REG) -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CCIPR_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR_REG) -#define HSI48_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 26, CCIPR_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CCIPR_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR_REG) +#define HSI48_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 26, CCIPR_REG) /** CSR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CSR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CSR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32l1_clock.h b/include/zephyr/dt-bindings/clock/stm32l1_clock.h index c6276cdf54837..9f94a18b8ff4a 100644 --- a/include/zephyr/dt-bindings/clock/stm32l1_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l1_clock.h @@ -29,6 +29,6 @@ /** @brief RCC_CSR register offset */ #define CSR_REG 0x34 -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CSR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CSR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L1_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32l4_clock.h b/include/zephyr/dt-bindings/clock/stm32l4_clock.h index 31bfd4509b60c..eabfffc9ed208 100644 --- a/include/zephyr/dt-bindings/clock/stm32l4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l4_clock.h @@ -49,36 +49,36 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR_REG) -#define USART3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, CCIPR_REG) -#define UART4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, CCIPR_REG) -#define UART5_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CCIPR_REG) -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR_REG) -#define I2C2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, CCIPR_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CCIPR_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR_REG) -#define SAI1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR_REG) -#define SAI2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 24, CCIPR_REG) -#define CLK48_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 26, CCIPR_REG) -#define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 28, CCIPR_REG) -#define SWPMI1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 30, CCIPR_REG) -#define DFSDM1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 31, CCIPR_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR_REG) +#define UART4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, CCIPR_REG) +#define UART5_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR_REG) +#define I2C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, CCIPR_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CCIPR_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR_REG) +#define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR_REG) +#define SAI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, CCIPR_REG) +#define CLK48_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 26, CCIPR_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, CCIPR_REG) +#define SWPMI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 30, CCIPR_REG) +#define DFSDM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 31, CCIPR_REG) /** CCIPR2 devices */ -#define I2C4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR2_REG) -#define DFSDM_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 2, CCIPR2_REG) -#define ADFSDM_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 3, CCIPR2_REG) -/* #define SAI1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 5, CCIPR2_REG) */ -/* #define SAI2_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 8, CCIPR2_REG) */ -#define DSI_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 12, CCIPR2_REG) -#define SDMMC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 14, CCIPR2_REG) -#define OSPI_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR2_REG) +#define I2C4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR2_REG) +#define DFSDM_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 2, CCIPR2_REG) +#define ADFSDM_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 3, CCIPR2_REG) +/* #define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 5, CCIPR2_REG) */ +/* #define SAI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, CCIPR2_REG) */ +#define DSI_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 12, CCIPR2_REG) +#define SDMMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 14, CCIPR2_REG) +#define OSPI_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR2_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /** CFGR devices */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0xF, 24, CFGR_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 28, CFGR_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0xF, 24, CFGR_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 28, CFGR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L4_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32n6_clock.h b/include/zephyr/dt-bindings/clock/stm32n6_clock.h index 4566ed1306a68..f733752c2c410 100644 --- a/include/zephyr/dt-bindings/clock/stm32n6_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32n6_clock.h @@ -81,85 +81,85 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR1 devices */ -#define ADF1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 0, CCIPR1_REG) -#define ADC12_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 4, CCIPR1_REG) -#define DCMIPP_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 20, CCIPR1_REG) +#define ADF1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR1_REG) +#define ADC12_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 4, CCIPR1_REG) +#define DCMIPP_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR1_REG) /** CCIPR2 devices */ -#define ETH1PTP_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 0, CCIPR2_REG) -#define ETH1CLK_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 12, CCIPR2_REG) -#define ETH1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 16, CCIPR2_REG) -#define ETH1REFCLK_SEL(val) STM32_DOMAIN_CLOCK((val), 1, 20, CCIPR2_REG) -#define ETH1GTXCLK_SEL(val) STM32_DOMAIN_CLOCK((val), 1, 24, CCIPR2_REG) +#define ETH1PTP_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR2_REG) +#define ETH1CLK_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR2_REG) +#define ETH1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, CCIPR2_REG) +#define ETH1REFCLK_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 20, CCIPR2_REG) +#define ETH1GTXCLK_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 24, CCIPR2_REG) /** CCIPR3 devices */ -#define FDCAN_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 0, CCIPR3_REG) -#define FMC_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 4, CCIPR3_REG) +#define FDCAN_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR3_REG) +#define FMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR3_REG) /** CCIPR4 devices */ -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 0, CCIPR4_REG) -#define I2C2_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 4, CCIPR4_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 8, CCIPR4_REG) -#define I2C4_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 12, CCIPR4_REG) -#define I3C1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 16, CCIPR4_REG) -#define I3C2_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 20, CCIPR4_REG) -#define LTDC_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 24, CCIPR4_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR4_REG) +#define I2C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 4, CCIPR4_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, CCIPR4_REG) +#define I2C4_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, CCIPR4_REG) +#define I3C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, CCIPR4_REG) +#define I3C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 20, CCIPR4_REG) +#define LTDC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, CCIPR4_REG) /** CCIPR5 devices */ -#define MCO1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 0, CCIPR5_REG) -#define MCO2_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 8, CCIPR5_REG) -#define MDF1SEL(val) STM32_DOMAIN_CLOCK((val), 7, 16, CCIPR5_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR5_REG) +#define MCO2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, CCIPR5_REG) +#define MDF1SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, CCIPR5_REG) /** CCIPR6 devices */ -#define XSPI1_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 0, CCIPR6_REG) -#define XSPI2_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 4, CCIPR6_REG) -#define XSPI3_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 8, CCIPR6_REG) -#define OTGPHY1_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 12, CCIPR6_REG) -#define OTGPHY1CKREF_SEL(val) STM32_DOMAIN_CLOCK((val), 1, 16, CCIPR6_REG) -#define OTGPHY2_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 20, CCIPR6_REG) -#define OTGPHY2CKREF_SEL(val) STM32_DOMAIN_CLOCK((val), 1, 24, CCIPR6_REG) +#define XSPI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR6_REG) +#define XSPI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR6_REG) +#define XSPI3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR6_REG) +#define OTGPHY1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR6_REG) +#define OTGPHY1CKREF_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 16, CCIPR6_REG) +#define OTGPHY2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR6_REG) +#define OTGPHY2CKREF_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 24, CCIPR6_REG) /** CCIPR7 devices */ -#define PER_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 0, CCIPR7_REG) -#define PSSI_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 4, CCIPR7_REG) -#define RTC_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 8, CCIPR7_REG) -#define SAI1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 20, CCIPR7_REG) -#define SAI2_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 24, CCIPR7_REG) +#define PER_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR7_REG) +#define PSSI_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR7_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR7_REG) +#define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 20, CCIPR7_REG) +#define SAI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 24, CCIPR7_REG) /** CCIPR8 devices */ -#define SDMMC1_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 0, CCIPR8_REG) -#define SDMMC2_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 4, CCIPR8_REG) +#define SDMMC1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR8_REG) +#define SDMMC2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR8_REG) /** CCIPR9 devices */ -#define SPDIFRX1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 0, CCIPR9_REG) -#define SPI1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 4, CCIPR9_REG) -#define SPI2_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 8, CCIPR9_REG) -#define SPI3_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 12, CCIPR9_REG) -#define SPI4_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 16, CCIPR9_REG) -#define SPI5_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 20, CCIPR9_REG) -#define SPI6_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 24, CCIPR9_REG) +#define SPDIFRX1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR9_REG) +#define SPI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 4, CCIPR9_REG) +#define SPI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, CCIPR9_REG) +#define SPI3_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, CCIPR9_REG) +#define SPI4_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, CCIPR9_REG) +#define SPI5_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 20, CCIPR9_REG) +#define SPI6_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 24, CCIPR9_REG) /** CCIPR12 devices */ -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 8, CCIPR12_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 12, CCIPR12_REG) -#define LPTIM3_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 16, CCIPR12_REG) -#define LPTIM4_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 20, CCIPR12_REG) -#define LPTIM5_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 24, CCIPR12_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, CCIPR12_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, CCIPR12_REG) +#define LPTIM3_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, CCIPR12_REG) +#define LPTIM4_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 20, CCIPR12_REG) +#define LPTIM5_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 24, CCIPR12_REG) /** CCIPR13 devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 0, CCIPR13_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 4, CCIPR13_REG) -#define USART3_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 8, CCIPR13_REG) -#define UART4_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 12, CCIPR13_REG) -#define UART5_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 16, CCIPR13_REG) -#define USART6_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 20, CCIPR13_REG) -#define UART7_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 24, CCIPR13_REG) -#define UART8_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 28, CCIPR13_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR13_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 4, CCIPR13_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, CCIPR13_REG) +#define UART4_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, CCIPR13_REG) +#define UART5_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, CCIPR13_REG) +#define USART6_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 20, CCIPR13_REG) +#define UART7_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 24, CCIPR13_REG) +#define UART8_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 28, CCIPR13_REG) /** CCIPR14 devices */ -#define UART9_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 0, CCIPR14_REG) -#define USART10_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 4, CCIPR14_REG) -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK((val), 7, 8, CCIPR14_REG) +#define UART9_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR14_REG) +#define USART10_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 4, CCIPR14_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, CCIPR14_REG) /** @brief RCC_ICxCFGR register offset (RM0468.pdf) */ #define ICxCFGR_REG(ic) (0xC4 + ((ic) - 1) * 4) /** @brief Divider ICx source selection */ -#define ICx_PLLy_SEL(ic, pll) STM32_DOMAIN_CLOCK((pll) - 1, 3, 28, ICxCFGR_REG(ic)) +#define ICx_PLLy_SEL(ic, pll) STM32_DT_CLOCK_SELECT((pll) - 1, 3, 28, ICxCFGR_REG(ic)) /** @brief RCC_CFGR1 register offset (RM0468.pdf) */ #define CFGR1_REG 0x20 /** @brief CPU clock switch selection */ -#define CPU_SEL(val) STM32_DOMAIN_CLOCK((val), 3, 16, CFGR1_REG) +#define CPU_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CFGR1_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32N6_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32u0_clock.h b/include/zephyr/dt-bindings/clock/stm32u0_clock.h index d212e42cddf3c..50e76c573d781 100644 --- a/include/zephyr/dt-bindings/clock/stm32u0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u0_clock.h @@ -44,21 +44,21 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR_REG) -#define LPUART3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, CCIPR_REG) -#define LPUART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CCIPR_REG) -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CCIPR_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR_REG) -#define LPTIM3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR_REG) -#define TIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 24, CCIPR_REG) -#define TIM15_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 25, CCIPR_REG) -#define CLK48_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 26, CCIPR_REG) -#define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 28, CCIPR_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR_REG) +#define LPUART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, CCIPR_REG) +#define LPUART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CCIPR_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR_REG) +#define LPTIM3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR_REG) +#define TIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 24, CCIPR_REG) +#define TIM15_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 25, CCIPR_REG) +#define CLK48_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 26, CCIPR_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, CCIPR_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32U0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32u5_clock.h b/include/zephyr/dt-bindings/clock/stm32u5_clock.h index d37688291c154..b284efd5d2e37 100644 --- a/include/zephyr/dt-bindings/clock/stm32u5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u5_clock.h @@ -65,51 +65,51 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR1 devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR1_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR1_REG) -#define USART3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 4, CCIPR1_REG) -#define UART4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, CCIPR1_REG) -#define UART5_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CCIPR1_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR1_REG) -#define I2C2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR1_REG) -#define I2C4_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, CCIPR1_REG) -#define SPI2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CCIPR1_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR1_REG) -#define SPI1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR1_REG) -#define SYSTICK_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR1_REG) -#define FDCAN1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 24, CCIPR1_REG) -#define ICKLK_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 26, CCIPR1_REG) -#define TIMIC_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 29, CCIPR1_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR1_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR1_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR1_REG) +#define UART4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, CCIPR1_REG) +#define UART5_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR1_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR1_REG) +#define I2C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR1_REG) +#define I2C4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, CCIPR1_REG) +#define SPI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CCIPR1_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR1_REG) +#define SPI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR1_REG) +#define SYSTICK_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR1_REG) +#define FDCAN1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, CCIPR1_REG) +#define ICKLK_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 26, CCIPR1_REG) +#define TIMIC_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 29, CCIPR1_REG) /** CCIPR2 devices */ -#define MDF1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, CCIPR2_REG) -#define SAI1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 5, CCIPR2_REG) -#define SAI2_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 8, CCIPR2_REG) -#define SAE_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 11, CCIPR2_REG) -#define RNG_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR2_REG) -#define SDMMC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 14, CCIPR2_REG) -#define DSIHOST_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 15, CCIPR2_REG) -#define USART6_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 16, CCIPR2_REG) -#define LTDC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 18, CCIPR2_REG) -#define OCTOSPI_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR2_REG) -#define HSPI_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR2_REG) -#define I2C5_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 24, CCIPR2_REG) -#define I2C6_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 26, CCIPR2_REG) -#define OTGHS_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, CCIPR2_REG) +#define MDF1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR2_REG) +#define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 5, CCIPR2_REG) +#define SAI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 8, CCIPR2_REG) +#define SAE_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 11, CCIPR2_REG) +#define RNG_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR2_REG) +#define SDMMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 14, CCIPR2_REG) +#define DSIHOST_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 15, CCIPR2_REG) +#define USART6_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 16, CCIPR2_REG) +#define LTDC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 18, CCIPR2_REG) +#define OCTOSPI_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR2_REG) +#define HSPI_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR2_REG) +#define I2C5_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, CCIPR2_REG) +#define I2C6_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 26, CCIPR2_REG) +#define OTGHS_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 30, CCIPR2_REG) /** CCIPR3 devices */ -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 0, CCIPR3_REG) -#define SPI3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 3, CCIPR3_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, CCIPR3_REG) -#define LPTIM34_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CCIPR3_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR3_REG) -#define ADCDAC_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 12, CCIPR3_REG) -#define DAC1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 15, CCIPR3_REG) -#define ADF1_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 16, CCIPR3_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 0, CCIPR3_REG) +#define SPI3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 3, CCIPR3_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, CCIPR3_REG) +#define LPTIM34_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR3_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR3_REG) +#define ADCDAC_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, CCIPR3_REG) +#define DAC1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 15, CCIPR3_REG) +#define ADF1_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 16, CCIPR3_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /** CFGR1 devices */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0xF, 24, CFGR1_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 28, CFGR1_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0xF, 24, CFGR1_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 28, CFGR1_REG) /* MCO prescaler : division factor */ #define MCO_PRE_DIV_1 0 diff --git a/include/zephyr/dt-bindings/clock/stm32wb0_clock.h b/include/zephyr/dt-bindings/clock/stm32wb0_clock.h index 3a790dc510094..d3b96b49ca4f5 100644 --- a/include/zephyr/dt-bindings/clock/stm32wb0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wb0_clock.h @@ -34,9 +34,12 @@ #define APB2ENR_REG 0x60 /** @brief Device clk sources selection helpers */ -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 13, CFGR_REG) /* WB05/WB09 only */ -#define SPI2_I2S2_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 22, CFGR_REG) /* WB06/WB07 only */ + +/* WB05/WB09 only */ +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 13, CFGR_REG) +/* WB06/WB07 only */ +#define SPI2_I2S2_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 22, CFGR_REG) /* `mask` is only 0x1 for WB06/WB07, but a single definition with mask=0x3 is acceptable */ -#define SPI3_I2S3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CFGR_REG) +#define SPI3_I2S3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CFGR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WB0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32wb_clock.h b/include/zephyr/dt-bindings/clock/stm32wb_clock.h index fa89141ccc513..f56e70e54b9fb 100644 --- a/include/zephyr/dt-bindings/clock/stm32wb_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wb_clock.h @@ -49,19 +49,19 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR_REG) -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CCIPR_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR_REG) -#define SAI1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR_REG) -#define CLK48_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 26, CCIPR_REG) -#define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 28, CCIPR_REG) -#define RNG_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, CCIPR_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CCIPR_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR_REG) +#define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR_REG) +#define CLK48_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 26, CCIPR_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, CCIPR_REG) +#define RNG_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 30, CCIPR_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) /** CSR devices */ -#define RFWKP_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, CSR_REG) +#define RFWKP_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, CSR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WB_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32wba_clock.h b/include/zephyr/dt-bindings/clock/stm32wba_clock.h index 769e937897c03..23ceac25c0119 100644 --- a/include/zephyr/dt-bindings/clock/stm32wba_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wba_clock.h @@ -54,28 +54,28 @@ /** @brief Device clk sources selection helpers */ /** CCIPR1 devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR1_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR1_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR1_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR1_REG) -#define SPI1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR1_REG) -#define SYSTICK_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR1_REG) -#define TIMIC_SEL(val) STM32_DOMAIN_CLOCK(val, 1, 31, CCIPR1_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR1_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR1_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR1_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR1_REG) +#define SPI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR1_REG) +#define SYSTICK_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR1_REG) +#define TIMIC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 31, CCIPR1_REG) /** CCIPR2 devices */ -#define RNG_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR2_REG) +#define RNG_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR2_REG) /** CCIPR3 devices */ -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR3_REG) -#define SPI3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 3, CCIPR3_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 6, CCIPR3_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR3_REG) -#define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 7, 12, CCIPR3_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR3_REG) +#define SPI3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 3, CCIPR3_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, CCIPR3_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR3_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 7, 12, CCIPR3_REG) /** BCDR1 devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BCDR1_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BCDR1_REG) /** @brief RCC_CFGRx register offset */ #define CFGR1_REG 0x1C /** CFGR1 devices */ -#define MCO1_SEL(val) STM32_MCO_CFGR(val, 0xF, 24, CFGR1_REG) -#define MCO1_PRE(val) STM32_MCO_CFGR(val, 0x7, 28, CFGR1_REG) +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0xF, 24, CFGR1_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 28, CFGR1_REG) /* MCO prescaler : division factor */ #define MCO_PRE_DIV_1 0 diff --git a/include/zephyr/dt-bindings/clock/stm32wl_clock.h b/include/zephyr/dt-bindings/clock/stm32wl_clock.h index 7872fed0e828b..fbe007f16e0d8 100644 --- a/include/zephyr/dt-bindings/clock/stm32wl_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wl_clock.h @@ -46,19 +46,19 @@ /** @brief Device domain clocks selection helpers */ /** CCIPR devices */ -#define USART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 0, CCIPR_REG) -#define USART2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 2, CCIPR_REG) -#define SPI2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, CCIPR_REG) -#define LPUART1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 10, CCIPR_REG) -#define I2C1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 12, CCIPR_REG) -#define I2C2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 14, CCIPR_REG) -#define I2C3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 16, CCIPR_REG) -#define LPTIM1_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 18, CCIPR_REG) -#define LPTIM2_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 20, CCIPR_REG) -#define LPTIM3_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 22, CCIPR_REG) -#define ADC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 28, CCIPR_REG) -#define RNG_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 30, CCIPR_REG) +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR_REG) +#define SPI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR_REG) +#define I2C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, CCIPR_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CCIPR_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR_REG) +#define LPTIM3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, CCIPR_REG) +#define RNG_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 30, CCIPR_REG) /** BDCR devices */ -#define RTC_SEL(val) STM32_DOMAIN_CLOCK(val, 3, 8, BDCR_REG) +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WL_CLOCK_H_ */ From c7c001405c1c57790d367fb387eb33752c929ea9 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 5 Feb 2025 20:14:00 +0100 Subject: [PATCH 0215/6055] drivers: clock: stm32: factorize clock selection macros Factorize STM32_CLOCK_*_GET() and STM32_MCO_CFGR_*_GET() macros into a single series of STM32_DT_CLKSEL_*_GET() macros based on recently introduced new common macros STM32_DT_CLKSEL_*_SHIFT and STM32_DT_CLKSEL_*_MASK. Signed-off-by: Etienne Carriere --- drivers/clock_control/clock_stm32_ll_common.c | 10 ++-- drivers/clock_control/clock_stm32_ll_h5.c | 5 +- drivers/clock_control/clock_stm32_ll_h7.c | 10 ++-- drivers/clock_control/clock_stm32_ll_n6.c | 10 ++-- drivers/clock_control/clock_stm32_ll_u5.c | 10 ++-- drivers/clock_control/clock_stm32_ll_wb0.c | 8 +-- drivers/clock_control/clock_stm32_ll_wba.c | 10 ++-- drivers/clock_control/clock_stm32_mco.c | 24 ++++---- .../clock_control/stm32_clock_control.h | 56 ++++--------------- 9 files changed, 61 insertions(+), 82 deletions(-) diff --git a/drivers/clock_control/clock_stm32_ll_common.c b/drivers/clock_control/clock_stm32_ll_common.c index 0e2e577b518ea..a2cff13d5711d 100644 --- a/drivers/clock_control/clock_stm32_ll_common.c +++ b/drivers/clock_control/clock_stm32_ll_common.c @@ -311,10 +311,12 @@ static inline int stm32_clock_control_configure(const struct device *dev, return 0; } - sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_MASK_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); - sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_VAL_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); + sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_MASK_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); + sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_VAL_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); return 0; } diff --git a/drivers/clock_control/clock_stm32_ll_h5.c b/drivers/clock_control/clock_stm32_ll_h5.c index 39aaa65d7c771..486861a32fd09 100644 --- a/drivers/clock_control/clock_stm32_ll_h5.c +++ b/drivers/clock_control/clock_stm32_ll_h5.c @@ -200,8 +200,9 @@ static inline int stm32_clock_control_configure(const struct device *dev, return err; } - sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_VAL_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); + sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_VAL_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); return 0; } diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index 5819eb5017bbf..49dd67ae848eb 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -448,10 +448,12 @@ static inline int stm32_clock_control_configure(const struct device *dev, z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); - sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_MASK_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); - sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_VAL_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); + sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_MASK_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); + sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_VAL_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); diff --git a/drivers/clock_control/clock_stm32_ll_n6.c b/drivers/clock_control/clock_stm32_ll_n6.c index e69faf6823d5b..3a1a9538bfd91 100644 --- a/drivers/clock_control/clock_stm32_ll_n6.c +++ b/drivers/clock_control/clock_stm32_ll_n6.c @@ -253,10 +253,12 @@ static inline int stm32_clock_control_configure(const struct device *dev, return err; } - sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_MASK_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); - sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_VAL_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); + sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_MASK_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); + sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_VAL_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); return 0; } diff --git a/drivers/clock_control/clock_stm32_ll_u5.c b/drivers/clock_control/clock_stm32_ll_u5.c index c32c72820cf2f..770c535209f78 100644 --- a/drivers/clock_control/clock_stm32_ll_u5.c +++ b/drivers/clock_control/clock_stm32_ll_u5.c @@ -206,10 +206,12 @@ static inline int stm32_clock_control_configure(const struct device *dev, return err; } - sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_MASK_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); - sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_VAL_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); + sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_MASK_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); + sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_VAL_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); return 0; } diff --git a/drivers/clock_control/clock_stm32_ll_wb0.c b/drivers/clock_control/clock_stm32_ll_wb0.c index f5375d2d8b3bc..82ae3c15abcc1 100644 --- a/drivers/clock_control/clock_stm32_ll_wb0.c +++ b/drivers/clock_control/clock_stm32_ll_wb0.c @@ -252,8 +252,8 @@ static inline int stm32_clock_control_configure(const struct device *dev, void *data) { struct stm32_pclken *pclken = (struct stm32_pclken *)sub_system; - const uint32_t shift = STM32_CLOCK_SHIFT_GET(pclken->enr); - mem_addr_t reg = RCC_REG(STM32_CLOCK_REG_GET(pclken->enr)); + const uint32_t shift = STM32_DT_CLKSEL_SHIFT_GET(pclken->enr); + mem_addr_t reg = RCC_REG(STM32_DT_CLKSEL_REG_GET(pclken->enr)); int err; ARG_UNUSED(dev); @@ -265,8 +265,8 @@ static inline int stm32_clock_control_configure(const struct device *dev, return err; } - sys_clear_bits(reg, STM32_CLOCK_MASK_GET(pclken->enr) << shift); - sys_set_bits(reg, STM32_CLOCK_VAL_GET(pclken->enr) << shift); + sys_clear_bits(reg, STM32_DT_CLKSEL_MASK_GET(pclken->enr) << shift); + sys_set_bits(reg, STM32_DT_CLKSEL_VAL_GET(pclken->enr) << shift); return 0; } diff --git a/drivers/clock_control/clock_stm32_ll_wba.c b/drivers/clock_control/clock_stm32_ll_wba.c index 323d0f1ae5fe4..4895d862b47ae 100644 --- a/drivers/clock_control/clock_stm32_ll_wba.c +++ b/drivers/clock_control/clock_stm32_ll_wba.c @@ -120,10 +120,12 @@ static inline int stm32_clock_control_configure(const struct device *dev, return err; } - sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_MASK_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); - sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), - STM32_CLOCK_VAL_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); + sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_MASK_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); + sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_VAL_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); return 0; #else diff --git a/drivers/clock_control/clock_stm32_mco.c b/drivers/clock_control/clock_stm32_mco.c index 0e8d6faec2661..1a524d74c59b2 100644 --- a/drivers/clock_control/clock_stm32_mco.c +++ b/drivers/clock_control/clock_stm32_mco.c @@ -41,24 +41,24 @@ static int stm32_mco_init(const struct device *dev) /* MCO source */ sys_clear_bits( - DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_MCO_CFGR_REG_GET(pclken->enr), - STM32_MCO_CFGR_MASK_GET(pclken->enr) << - STM32_MCO_CFGR_SHIFT_GET(pclken->enr)); + DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_MASK_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); sys_set_bits( - DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_MCO_CFGR_REG_GET(pclken->enr), - STM32_MCO_CFGR_VAL_GET(pclken->enr) << - STM32_MCO_CFGR_SHIFT_GET(pclken->enr)); + DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), + STM32_DT_CLKSEL_VAL_GET(pclken->enr) << + STM32_DT_CLKSEL_SHIFT_GET(pclken->enr)); #if defined(HAS_PRESCALER) /* MCO prescaler */ sys_clear_bits( - DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_MCO_CFGR_REG_GET(config->prescaler), - STM32_MCO_CFGR_MASK_GET(config->prescaler) << - STM32_MCO_CFGR_SHIFT_GET(config->prescaler)); + DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(config->prescaler), + STM32_DT_CLKSEL_MASK_GET(config->prescaler) << + STM32_DT_CLKSEL_SHIFT_GET(config->prescaler)); sys_set_bits( - DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_MCO_CFGR_REG_GET(config->prescaler), - STM32_MCO_CFGR_VAL_GET(config->prescaler) << - STM32_MCO_CFGR_SHIFT_GET(config->prescaler)); + DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(config->prescaler), + STM32_DT_CLKSEL_VAL_GET(config->prescaler) << + STM32_DT_CLKSEL_SHIFT_GET(config->prescaler)); #endif return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); diff --git a/include/zephyr/drivers/clock_control/stm32_clock_control.h b/include/zephyr/drivers/clock_control/stm32_clock_control.h index 4165d20c06f47..de1b9da289356 100644 --- a/include/zephyr/drivers/clock_control/stm32_clock_control.h +++ b/include/zephyr/drivers/clock_control/stm32_clock_control.h @@ -658,68 +658,36 @@ struct stm32_pclken { /** Clock source binding accessors */ /** - * @brief Obtain register field from clock configuration. + * @brief Obtain register field from clock source selection configuration. * * @param clock clock bit field value. */ -#define STM32_CLOCK_REG_GET(clock) \ - (((clock) >> STM32_CLOCK_REG_SHIFT) & STM32_CLOCK_REG_MASK) +#define STM32_DT_CLKSEL_REG_GET(clock) \ + (((clock) >> STM32_DT_CLKSEL_REG_SHIFT) & STM32_DT_CLKSEL_REG_MASK) /** - * @brief Obtain position field from clock configuration. + * @brief Obtain position field from clock source selection configuration. * * @param clock Clock bit field value. */ -#define STM32_CLOCK_SHIFT_GET(clock) \ - (((clock) >> STM32_CLOCK_SHIFT_SHIFT) & STM32_CLOCK_SHIFT_MASK) +#define STM32_DT_CLKSEL_SHIFT_GET(clock) \ + (((clock) >> STM32_DT_CLKSEL_SHIFT_SHIFT) & STM32_DT_CLKSEL_SHIFT_MASK) /** - * @brief Obtain mask field from clock configuration. + * @brief Obtain mask field from clock source selection configuration. * * @param clock Clock bit field value. */ -#define STM32_CLOCK_MASK_GET(clock) \ - (((clock) >> STM32_CLOCK_MASK_SHIFT) & STM32_CLOCK_MASK_MASK) +#define STM32_DT_CLKSEL_MASK_GET(clock) \ + (((clock) >> STM32_DT_CLKSEL_MASK_SHIFT) & STM32_DT_CLKSEL_MASK_MASK) /** - * @brief Obtain value field from clock configuration. + * @brief Obtain value field from clock source selection configuration. * * @param clock Clock bit field value. */ -#define STM32_CLOCK_VAL_GET(clock) \ - (((clock) >> STM32_CLOCK_VAL_SHIFT) & STM32_CLOCK_VAL_MASK) - -/** - * @brief Obtain register field from MCO configuration. - * - * @param mco_cfgr MCO configuration bit field value. - */ -#define STM32_MCO_CFGR_REG_GET(mco_cfgr) \ - (((mco_cfgr) >> STM32_MCO_CFGR_REG_SHIFT) & STM32_MCO_CFGR_REG_MASK) - -/** - * @brief Obtain position field from MCO configuration. - * - * @param mco_cfgr MCO configuration bit field value. - */ -#define STM32_MCO_CFGR_SHIFT_GET(mco_cfgr) \ - (((mco_cfgr) >> STM32_MCO_CFGR_SHIFT_SHIFT) & STM32_MCO_CFGR_SHIFT_MASK) - -/** - * @brief Obtain mask field from MCO configuration. - * - * @param mco_cfgr MCO configuration bit field value. - */ -#define STM32_MCO_CFGR_MASK_GET(mco_cfgr) \ - (((mco_cfgr) >> STM32_MCO_CFGR_MASK_SHIFT) & STM32_MCO_CFGR_MASK_MASK) - -/** - * @brief Obtain value field from MCO configuration. - * - * @param mco_cfgr MCO configuration bit field value. - */ -#define STM32_MCO_CFGR_VAL_GET(mco_cfgr) \ - (((mco_cfgr) >> STM32_MCO_CFGR_VAL_SHIFT) & STM32_MCO_CFGR_VAL_MASK) +#define STM32_DT_CLKSEL_VAL_GET(clock) \ + (((clock) >> STM32_DT_CLKSEL_VAL_SHIFT) & STM32_DT_CLKSEL_VAL_MASK) #if defined(STM32_HSE_CSS) /** From 10e12ba20d17f40c1b2b04b177867c610ba38d21 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 5 Feb 2025 20:08:44 +0100 Subject: [PATCH 0216/6055] include: zephyr: dt-bindings: clock remove unused STM32 macros Remove now unused macros STM32_DOMAIN_CLOCK(), STM32_CLOCK_*_SHIFT, STM32_CLOCK_*_MASK, STM32_MCO_CFGR(), STM32_MCO_CFGR_*_SHIFT and STM32_MCO_CFGR_REG_MASK macros, replaced with STM32_DT_CLOCK_SELECT(), STM32_DT_CLKSEL_*_SHIFT and STM32_DT_CLKSEL_*_MASK macros. Signed-off-by: Etienne Carriere --- .../dt-bindings/clock/stm32_common_clocks.h | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/include/zephyr/dt-bindings/clock/stm32_common_clocks.h b/include/zephyr/dt-bindings/clock/stm32_common_clocks.h index bd24aa2d3d9f1..5992fee999b80 100644 --- a/include/zephyr/dt-bindings/clock/stm32_common_clocks.h +++ b/include/zephyr/dt-bindings/clock/stm32_common_clocks.h @@ -49,30 +49,6 @@ (((mask) & STM32_DT_CLKSEL_MASK_MASK) << STM32_DT_CLKSEL_MASK_SHIFT) | \ (((val) & STM32_DT_CLKSEL_VAL_MASK) << STM32_DT_CLKSEL_VAL_SHIFT)) -/* STM32_CLOCK_* macros, defined for convenience */ -#define STM32_CLOCK_REG_MASK STM32_DT_CLKSEL_REG_MASK -#define STM32_CLOCK_REG_SHIFT STM32_DT_CLKSEL_REG_SHIFT -#define STM32_CLOCK_SHIFT_MASK STM32_DT_CLKSEL_SHIFT_MASK -#define STM32_CLOCK_SHIFT_SHIFT STM32_DT_CLKSEL_SHIFT_SHIFT -#define STM32_CLOCK_MASK_MASK STM32_DT_CLKSEL_MASK_MASK -#define STM32_CLOCK_MASK_SHIFT STM32_DT_CLKSEL_MASK_SHIFT -#define STM32_CLOCK_VAL_MASK STM32_DT_CLKSEL_VAL_MASK -#define STM32_CLOCK_VAL_SHIFT STM32_DT_CLKSEL_VAL_SHIFT -#define STM32_DOMAIN_CLOCK(val, mask, shift, reg) \ - STM32_DT_CLOCK_SELECT((val), (mask), (shift), (reg)) - -/* STM32_MCO_CFGR_* macros, defined for convenience */ -#define STM32_MCO_CFGR_REG_MASK STM32_DT_CLKSEL_REG_MASK -#define STM32_MCO_CFGR_REG_SHIFT STM32_DT_CLKSEL_REG_SHIFT -#define STM32_MCO_CFGR_SHIFT_MASK STM32_DT_CLKSEL_SHIFT_MASK -#define STM32_MCO_CFGR_SHIFT_SHIFT STM32_DT_CLKSEL_SHIFT_SHIFT -#define STM32_MCO_CFGR_MASK_MASK STM32_DT_CLKSEL_MASK_MASK -#define STM32_MCO_CFGR_MASK_SHIFT STM32_DT_CLKSEL_MASK_SHIFT -#define STM32_MCO_CFGR_VAL_MASK STM32_DT_CLKSEL_VAL_MASK -#define STM32_MCO_CFGR_VAL_SHIFT STM32_DT_CLKSEL_VAL_SHIFT -#define STM32_MCO_CFGR(val, mask, shift, reg) \ - STM32_DT_CLOCK_SELECT((val), (mask), (shift), (reg)) - /** * Pack RCC clock register offset and bit in two 32-bit values * as expected for the Device Tree `clocks` property on STM32. From f54991b7dd0b4de12d2b7303e0beae3fe6b3f9bb Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 16 Jan 2025 09:12:01 +0100 Subject: [PATCH 0217/6055] samples: Bluetooth: Broadcast sink: Refactor audio RX path Refactor everything related to RX in the sample. The existing code will moved to new files with more specific functionality, so that each file will become cleaner and use fewer #ifdefs. The USB part will be refactored a bit to follow the design used by the LE audio shell, to make it easier to maintain both in a similar way. Signed-off-by: Emil Gydesen --- .../bap_broadcast_sink/CMakeLists.txt | 4 + samples/bluetooth/bap_broadcast_sink/Kconfig | 7 + samples/bluetooth/bap_broadcast_sink/prj.conf | 4 +- .../bluetooth/bap_broadcast_sink/src/lc3.c | 495 +++++++++++++++++ .../bluetooth/bap_broadcast_sink/src/lc3.h | 92 ++++ .../bluetooth/bap_broadcast_sink/src/main.c | 511 ++---------------- .../bap_broadcast_sink/src/stream_rx.c | 157 ++++++ .../bap_broadcast_sink/src/stream_rx.h | 91 ++++ .../bluetooth/bap_broadcast_sink/src/usb.c | 350 ++++++++++++ .../bluetooth/bap_broadcast_sink/src/usb.h | 71 +++ .../bap_broadcast_sink/CMakeLists.txt | 4 + 11 files changed, 1304 insertions(+), 482 deletions(-) create mode 100644 samples/bluetooth/bap_broadcast_sink/src/lc3.c create mode 100644 samples/bluetooth/bap_broadcast_sink/src/lc3.h create mode 100644 samples/bluetooth/bap_broadcast_sink/src/stream_rx.c create mode 100644 samples/bluetooth/bap_broadcast_sink/src/stream_rx.h create mode 100644 samples/bluetooth/bap_broadcast_sink/src/usb.c create mode 100644 samples/bluetooth/bap_broadcast_sink/src/usb.h diff --git a/samples/bluetooth/bap_broadcast_sink/CMakeLists.txt b/samples/bluetooth/bap_broadcast_sink/CMakeLists.txt index 66649d87a33c8..5137eba4cb24d 100644 --- a/samples/bluetooth/bap_broadcast_sink/CMakeLists.txt +++ b/samples/bluetooth/bap_broadcast_sink/CMakeLists.txt @@ -6,6 +6,10 @@ project(bap_unicast_server) target_sources(app PRIVATE src/main.c + src/stream_rx.c ) +zephyr_sources_ifdef(CONFIG_LIBLC3 src/lc3.c) +zephyr_sources_ifdef(CONFIG_USB_DEVICE_AUDIO src/usb.c) + zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/bap_broadcast_sink/Kconfig b/samples/bluetooth/bap_broadcast_sink/Kconfig index bf46aa0f48fbf..597b54e6c9f5e 100644 --- a/samples/bluetooth/bap_broadcast_sink/Kconfig +++ b/samples/bluetooth/bap_broadcast_sink/Kconfig @@ -80,4 +80,11 @@ config TARGET_BROADCAST_CHANNEL Channel Audio Location to sync to. These corresponds to the bt_audio_location, supporting mono, left and right channels +config INFO_REPORTING_INTERVAL + int "Number of SDUs received between each information report" + default 1000 + help + Determines how often information about received data is logged. + Set to 0 to disable reporting. + source "Kconfig.zephyr" diff --git a/samples/bluetooth/bap_broadcast_sink/prj.conf b/samples/bluetooth/bap_broadcast_sink/prj.conf index 69c575267035f..7c4c9595bab63 100644 --- a/samples/bluetooth/bap_broadcast_sink/prj.conf +++ b/samples/bluetooth/bap_broadcast_sink/prj.conf @@ -12,8 +12,8 @@ CONFIG_BT_ISO_SYNC_RECEIVER=y CONFIG_BT_BAP_BROADCAST_SINK=y CONFIG_BT_BAP_SCAN_DELEGATOR=y CONFIG_BT_ISO_MAX_CHAN=2 -# Allocate 2 RX buffers per channel -CONFIG_BT_ISO_RX_BUF_COUNT=4 +# Allocate 4 RX buffers per channel +CONFIG_BT_ISO_RX_BUF_COUNT=8 CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=2 CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=2 CONFIG_BT_BAP_BASS_MAX_SUBGROUPS=2 diff --git a/samples/bluetooth/bap_broadcast_sink/src/lc3.c b/samples/bluetooth/bap_broadcast_sink/src/lc3.c new file mode 100644 index 0000000000000..9aba8a1508b0f --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/src/lc3.c @@ -0,0 +1,495 @@ +/** + * @file + * @brief Bluetooth BAP Broadcast Sink LC3 extension + * + * This files handles all the LC3 related functionality for the sample + * + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "lc3.h" +#include "stream_rx.h" +#include "usb.h" + +LOG_MODULE_REGISTER(lc3, CONFIG_LOG_DEFAULT_LEVEL); + +#define LC3_ENCODER_STACK_SIZE 4096 +#define LC3_ENCODER_PRIORITY 5 + +struct lc3_data { + void *fifo_reserved; /* 1st word reserved for use by FIFO */ + struct net_buf *buf; + struct stream_rx *stream; + uint32_t ts; + bool do_plc; +}; + +K_MEM_SLAB_DEFINE_STATIC(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 stream_rx *usb_left_stream; +static struct stream_rx *usb_right_stream; +static size_t rx_streaming_cnt; + +static int init_lc3_decoder(struct stream_rx *stream, uint32_t lc3_frame_duration_us, + uint32_t lc3_freq_hz) +{ + if (stream == NULL) { + LOG_ERR("NULL stream to init LC3 decoder"); + return -EINVAL; + } + + if (stream->lc3_decoder != NULL) { + LOG_ERR("Already initialized"); + return -EALREADY; + } + + if (lc3_freq_hz == 0U || lc3_frame_duration_us == 0U) { + LOG_ERR("Invalid freq (%u) or frame duration (%u)", lc3_freq_hz, + lc3_frame_duration_us); + + return -EINVAL; + } + + LOG_INF("Initializing the LC3 decoder with %u us duration and %u Hz frequency", + lc3_frame_duration_us, lc3_freq_hz); + /* Create the decoder instance. This shall complete before stream_started() is called. */ + stream->lc3_decoder = + lc3_setup_decoder(lc3_frame_duration_us, lc3_freq_hz, + IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) ? USB_SAMPLE_RATE_HZ : 0, + &stream->lc3_decoder_mem); + if (stream->lc3_decoder == NULL) { + LOG_ERR("Failed to setup LC3 decoder - wrong parameters?\n"); + return -EINVAL; + } + + LOG_INF("Initialized LC3 decoder for %p", stream); + rx_streaming_cnt++; + + return 0; +} + +static bool decode_frame(struct lc3_data *data, size_t frame_cnt) +{ + const struct stream_rx *stream = data->stream; + const size_t total_frames = stream->lc3_chan_cnt * stream->lc3_frame_blocks_per_sdu; + const uint16_t octets_per_frame = 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 CONFIG_INFO_REPORTING_INTERVAL > 0 + if ((stream->reporting_info.lc3_decoded_cnt % CONFIG_INFO_REPORTING_INTERVAL) == + 0) { + LOG_DBG("[%zu]: Performing PLC", stream->reporting_info.lc3_decoded_cnt); + } +#endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */ + + data->do_plc = false; /* clear flag */ + } else { + iso_data = net_buf_pull_mem(data->buf, octets_per_frame); + +#if CONFIG_INFO_REPORTING_INTERVAL > 0 + if ((stream->reporting_info.lc3_decoded_cnt % CONFIG_INFO_REPORTING_INTERVAL) == + 0) { + LOG_DBG("[%zu]: Decoding frame of size %u (%u/%u)", + stream->reporting_info.lc3_decoded_cnt, octets_per_frame, + frame_cnt + 1, total_frames); + } +#endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */ + } + + err = lc3_decode(stream->lc3_decoder, iso_data, octets_per_frame, LC3_PCM_FORMAT_S16, + lc3_rx_buf, 1); + if (err < 0) { + LOG_ERR("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 int get_lc3_chan_alloc_from_index(const struct stream_rx *stream, uint8_t index, + enum bt_audio_location *chan_alloc) +{ +#if defined(CONFIG_USB_DEVICE_AUDIO) + const bool has_left = (stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0; + const bool has_right = (stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0; + const bool is_mono = 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; +#else /* !CONFIG_USB_DEVICE_AUDIO */ + return -EINVAL; +#endif /* CONFIG_USB_DEVICE_AUDIO */ +} + +static size_t decode_frame_block(struct lc3_data *data, size_t frame_cnt) +{ + const struct stream_rx *stream = data->stream; + const uint8_t chan_cnt = 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(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 && + stream != usb_left_stream) || + (chan_alloc == BT_AUDIO_LOCATION_FRONT_RIGHT && + stream != usb_right_stream)) { + continue; + } + + /* TODO: Add support for properly support the presentation delay. + * For now we just send audio to USB as soon as we get it + */ + err = 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)) { + usb_clear_frames_to_usb(); + } + + break; + } + } + + return decoded_frames; +} + +static void do_lc3_decode(struct lc3_data *data) +{ + struct stream_rx *stream = data->stream; + + if (stream->lc3_decoder != NULL) { + const uint8_t frame_blocks_per_sdu = 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; + } + +#if CONFIG_INFO_REPORTING_INTERVAL > 0 + stream->reporting_info.lc3_decoded_cnt++; +#endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */ + } + + 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 stream_rx *stream = data->stream; + + if (stream->lc3_decoder == NULL) { + LOG_WRN("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); + } +} + +int lc3_enable(struct stream_rx *stream) +{ + const struct bt_audio_codec_cfg *codec_cfg = stream->stream.codec_cfg; + uint32_t lc3_frame_duration_us; + uint32_t lc3_freq_hz; + int ret; + + if (codec_cfg->id != BT_HCI_CODING_FORMAT_LC3) { + return -EINVAL; + } + + 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) { + if (ret == 8000 || ret == 16000 || ret == 24000 || ret == 32000 || + ret == 48000) { + lc3_freq_hz = (uint32_t)ret; + } else { + LOG_ERR("Unsupported frequency for LC3: %d", ret); + lc3_freq_hz = 0U; + } + } else { + LOG_ERR("Invalid frequency: %d", ret); + lc3_freq_hz = 0U; + } + } else { + LOG_ERR("Could not get frequency: %d", ret); + lc3_freq_hz = 0U; + } + + if (lc3_freq_hz == 0U) { + return -EINVAL; + } + + 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) { + lc3_frame_duration_us = (uint32_t)ret; + } else { + LOG_ERR("Invalid frame duration: %d", ret); + lc3_frame_duration_us = 0U; + } + } else { + LOG_ERR("Could not get frame duration: %d", ret); + lc3_frame_duration_us = 0U; + } + + if (lc3_frame_duration_us == 0U) { + return -EINVAL; + } + + ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &stream->lc3_chan_allocation, true); + if (ret == 0) { + stream->lc3_chan_cnt = bt_audio_get_chan_count(stream->lc3_chan_allocation); + } else { + LOG_DBG("Could not get channel allocation: %d", ret); + stream->lc3_chan_cnt = 0U; + } + + if (stream->lc3_chan_cnt == 0U) { + return -EINVAL; + } + + ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); + if (ret >= 0) { + stream->lc3_frame_blocks_per_sdu = (uint8_t)ret; + } else { + LOG_ERR("Could not get frame blocks per SDU: %d", ret); + stream->lc3_frame_blocks_per_sdu = 0U; + } + + if (stream->lc3_frame_blocks_per_sdu == 0U) { + return -EINVAL; + } + + ret = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); + if (ret >= 0) { + stream->lc3_octets_per_frame = (uint16_t)ret; + } else { + LOG_ERR("Could not get octets per frame: %d", ret); + stream->lc3_octets_per_frame = 0U; + } + + if (stream->lc3_octets_per_frame == 0U) { + return -EINVAL; + } + + if (stream->lc3_decoder == NULL) { + const int err = init_lc3_decoder(stream, lc3_frame_duration_us, lc3_freq_hz); + + if (err != 0) { + LOG_ERR("Failed to init LC3 decoder: %d", err); + + return err; + } + } + + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + if ((stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0) { + if (usb_left_stream == NULL) { + LOG_INF("Setting USB left stream to %p", stream); + usb_left_stream = stream; + } else { + LOG_WRN("Multiple left streams started"); + } + } + + if ((stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0) { + if (usb_right_stream == NULL) { + LOG_INF("Setting USB right stream to %p", stream); + usb_right_stream = stream; + } else { + LOG_WRN("Multiple right streams started"); + } + } + } + + return 0; +} + +int lc3_disable(struct stream_rx *stream) +{ + if (rx_streaming_cnt == 0 || stream->lc3_decoder == NULL) { + return -EINVAL; + } + + stream->lc3_decoder = NULL; + rx_streaming_cnt--; + + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + if (usb_left_stream == stream) { + usb_left_stream = NULL; + } + if (usb_right_stream == stream) { + usb_right_stream = NULL; + } + } + + return 0; +} + +void lc3_enqueue_for_decoding(struct stream_rx *stream, const struct bt_iso_recv_info *info, + struct net_buf *buf) +{ + const uint8_t frame_blocks_per_sdu = stream->lc3_frame_blocks_per_sdu; + const uint16_t octets_per_frame = stream->lc3_octets_per_frame; + const uint8_t chan_cnt = stream->lc3_chan_cnt; + struct lc3_data *data; + + if (stream->lc3_decoder == NULL) { + return; + } + + /* 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)) { + LOG_WRN("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) { + LOG_WRN("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->stream = stream; + if (info->flags & BT_ISO_FLAGS_TS) { + data->ts = info->ts; + } else { + data->ts = 0U; + } + + k_fifo_put(&lc3_in_fifo, data); +} + +int lc3_init(void) +{ + 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; + static bool initialized; + + if (initialized) { + return -EALREADY; + } + + 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"); + + LOG_INF("LC3 initialized"); + initialized = true; + + return 0; +} + +size_t lc3_get_rx_streaming_cnt(void) +{ + return rx_streaming_cnt; +} diff --git a/samples/bluetooth/bap_broadcast_sink/src/lc3.h b/samples/bluetooth/bap_broadcast_sink/src/lc3.h new file mode 100644 index 0000000000000..2b9ef3ff0c90e --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/src/lc3.h @@ -0,0 +1,92 @@ +/** + * @file + * @brief Bluetooth BAP Broadcast Sink LC3 header + * + * This files handles all the LC3 related functionality for the sample + * + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SAMPLE_BAP_BROADCAST_SINK_LC3_H +#define SAMPLE_BAP_BROADCAST_SINK_LC3_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stream_rx.h" + +#define LC3_MAX_SAMPLE_RATE_HZ 48000U +#define LC3_MAX_FRAME_DURATION_US 10000U +#define LC3_MAX_NUM_SAMPLES_MONO \ + ((LC3_MAX_FRAME_DURATION_US * LC3_MAX_SAMPLE_RATE_HZ) / USEC_PER_SEC) +#define LC3_MAX_NUM_SAMPLES_STEREO (LC3_MAX_NUM_SAMPLES_MONO * 2U) + +/** + * @brief Returns the number of active streams using an LC3 codec + * + * @return the number of active streams using an LC3 codec + */ +size_t lc3_get_rx_streaming_cnt(void); + +/** + * @brief Enables LC3 for a stream + * + * This will initialize the LC3 decoder given the @p stream codec configuration + * + * @param stream The stream to enable LC3 for + + * @retval 0 Success + * @retval -EINVAL The stream is not LC3 codec configured or the codec configuration is invalid + */ +int lc3_enable(struct stream_rx *stream); + +/** + * @brief Disabled LC3 for a stream + * + * @param stream The stream to disable LC3 for + + * @retval 0 Success + * @retval -EINVAL The stream is LC3 initialized + */ +int lc3_disable(struct stream_rx *stream); + +/** + * @brief Enqueue an SDU for decoding + * + * @param stream The stream that received the SDU + * @param info Information about the SDU + * @param buf The buffer of the SDU + */ +void lc3_enqueue_for_decoding(struct stream_rx *stream, const struct bt_iso_recv_info *info, + struct net_buf *buf); + +/** + * @brief Initialize the LC3 module + * + * This will start the thread if not already initialized + * + * @retval 0 Success + * @retval -EALREADY Already initialized + */ +int lc3_init(void); +#endif /* SAMPLE_BAP_BROADCAST_SINK_LC3_H */ diff --git a/samples/bluetooth/bap_broadcast_sink/src/main.c b/samples/bluetooth/bap_broadcast_sink/src/main.c index a5d541b420d35..e80da73d465a7 100644 --- a/samples/bluetooth/bap_broadcast_sink/src/main.c +++ b/samples/bluetooth/bap_broadcast_sink/src/main.c @@ -32,17 +32,9 @@ #include #include -#if defined(CONFIG_LIBLC3) #include "lc3.h" -#endif /* defined(CONFIG_LIBLC3) */ -#if defined(CONFIG_USB_DEVICE_AUDIO) -#include -#include -#include -#include -#include -#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ - +#include "stream_rx.h" +#include "usb.h" BUILD_ASSERT(IS_ENABLED(CONFIG_SCAN_SELF) || IS_ENABLED(CONFIG_SCAN_OFFLOAD), "Either SCAN_SELF or SCAN_OFFLOAD must be enabled"); @@ -63,27 +55,6 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_SCAN_SELF) || IS_ENABLED(CONFIG_SCAN_OFFLOAD), #define NAME_LEN sizeof(CONFIG_TARGET_BROADCAST_NAME) + 1 #define BROADCAST_DATA_ELEMENT_SIZE sizeof(int16_t) -#if defined(CONFIG_LIBLC3) -#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 * 2) - -#define LC3_ENCODER_STACK_SIZE 4096 -#define LC3_ENCODER_PRIORITY 5 -#endif /* defined(CONFIG_LIBLC3) */ - -#if defined(CONFIG_USB_DEVICE_AUDIO) -#define USB_ENQUEUE_COUNT 10U -#define USB_SAMPLE_RATE 48000U -#define USB_FRAME_DURATION_US 1000U -#define USB_MONO_SAMPLE_SIZE \ - ((USB_FRAME_DURATION_US * USB_SAMPLE_RATE * BROADCAST_DATA_ELEMENT_SIZE) / USEC_PER_SEC) -#define USB_STEREO_SAMPLE_SIZE (USB_MONO_SAMPLE_SIZE * 2) -#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); @@ -107,29 +78,7 @@ static struct bt_le_scan_recv_info broadcaster_info; static bt_addr_le_t broadcaster_addr; static struct bt_le_per_adv_sync *pa_sync; static uint32_t broadcaster_broadcast_id; -static struct broadcast_sink_stream { - struct bt_bap_stream stream; - size_t recv_cnt; - size_t loss_cnt; - size_t error_cnt; - size_t valid_cnt; -#if defined(CONFIG_LIBLC3) - struct net_buf *in_buf; - struct k_work_delayable lc3_decode_work; - - /* LC3 config values */ - enum bt_audio_location chan_allocation; - uint16_t lc3_octets_per_frame; - uint8_t lc3_frames_blocks_per_sdu; - - /* Internal lock for protecting net_buf from multiple access */ - struct k_mutex lc3_decoder_mutex; - lc3_decoder_t lc3_decoder; - lc3_decoder_mem_48k_t lc3_decoder_mem; -#endif /* defined(CONFIG_LIBLC3) */ -} streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; - -static struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)]; +static struct bt_bap_stream *bap_streams_p[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static volatile bool big_synced; static volatile bool base_received; static struct bt_conn *broadcast_assistant_conn; @@ -145,360 +94,25 @@ static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( /* Create a mask for the maximum BIS we can sync to using the number of streams * we have. Bit 0 is BIS index 1. */ -static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams)); +static const uint32_t bis_index_mask = BIT_MASK(CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT); static uint32_t requested_bis_sync; static uint32_t bis_index_bitfield; static uint8_t sink_broadcast_code[BT_ISO_BROADCAST_CODE_SIZE]; -uint64_t total_rx_iso_packet_count; /* This value is exposed to test code */ - static int stop_adv(void); -#if defined(CONFIG_USB_DEVICE_AUDIO) -RING_BUF_DECLARE(usb_ring_buf, USB_RING_BUF_SIZE); -NET_BUF_POOL_DEFINE(usb_tx_buf_pool, USB_ENQUEUE_COUNT, USB_STEREO_SAMPLE_SIZE, 0, net_buf_destroy); - -static void add_to_usb_ring_buf(const int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO]); -#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ - -#if defined(CONFIG_LIBLC3) -static K_SEM_DEFINE(lc3_decoder_sem, 0, 1); - -static void do_lc3_decode(lc3_decoder_t decoder, const void *in_data, uint8_t octets_per_frame, - int16_t out_data[LC3_MAX_NUM_SAMPLES_MONO]); -static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3); -K_THREAD_DEFINE(decoder_tid, LC3_ENCODER_STACK_SIZE, lc3_decoder_thread, - NULL, NULL, NULL, LC3_ENCODER_PRIORITY, 0, -1); - -/* Consumer thread of the decoded stream data */ -static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3) +static void stream_connected_cb(struct bt_bap_stream *bap_stream) { - while (true) { -#if defined(CONFIG_USB_DEVICE_AUDIO) - static int16_t right_frames[CONFIG_MAX_CODEC_FRAMES_PER_SDU] - [LC3_MAX_NUM_SAMPLES_MONO]; - static int16_t left_frames[CONFIG_MAX_CODEC_FRAMES_PER_SDU] - [LC3_MAX_NUM_SAMPLES_MONO]; - size_t right_frames_cnt = 0; - size_t left_frames_cnt = 0; - - memset(right_frames, 0, sizeof(right_frames)); - memset(left_frames, 0, sizeof(left_frames)); -#else - static int16_t lc3_audio_buf[LC3_MAX_NUM_SAMPLES_MONO]; -#endif /* CONFIG_USB_DEVICE_AUDIO */ - - k_sem_take(&lc3_decoder_sem, K_FOREVER); - - for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { - struct broadcast_sink_stream *stream = &streams[i]; - const uint8_t frames_blocks_per_sdu = stream->lc3_frames_blocks_per_sdu; - const uint16_t octets_per_frame = stream->lc3_octets_per_frame; - uint16_t frames_per_block; - struct net_buf *buf; - - k_mutex_lock(&stream->lc3_decoder_mutex, K_FOREVER); - - if (stream->in_buf == NULL) { - k_mutex_unlock(&stream->lc3_decoder_mutex); - - continue; - } - - buf = net_buf_ref(stream->in_buf); - net_buf_unref(stream->in_buf); - stream->in_buf = NULL; - k_mutex_unlock(&stream->lc3_decoder_mutex); - - frames_per_block = bt_audio_get_chan_count(stream->chan_allocation); - if (buf->len != - (frames_per_block * octets_per_frame * frames_blocks_per_sdu)) { - printk("Expected %u frame blocks with %u frames of size %u, but " - "length is %u\n", - frames_blocks_per_sdu, frames_per_block, octets_per_frame, - buf->len); - - net_buf_unref(buf); - - continue; - } - -#if defined(CONFIG_USB_DEVICE_AUDIO) - const bool has_left = - (stream->chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0; - const bool has_right = - (stream->chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0; - const bool is_mono = - stream->chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO; - - /* Split the SDU into frames*/ - for (uint8_t i = 0U; i < frames_blocks_per_sdu; i++) { - for (uint16_t j = 0U; j < frames_per_block; j++) { - const bool is_left = j == 0 && has_left; - const bool is_right = - has_right && (j == 0 || (j == 1 && has_left)); - const void *data = net_buf_pull_mem(buf, octets_per_frame); - int16_t *out_frame; - - if (is_left) { - out_frame = left_frames[left_frames_cnt++]; - } else if (is_right) { - out_frame = right_frames[right_frames_cnt++]; - } else if (is_mono) { - /* Use left as mono*/ - out_frame = left_frames[left_frames_cnt++]; - } else { - /* unused channel */ - break; - } - - do_lc3_decode(stream->lc3_decoder, data, octets_per_frame, - out_frame); - } - } -#else - /* Dummy behavior: Decode and discard data */ - for (uint8_t i = 0U; i < frames_blocks_per_sdu; i++) { - for (uint16_t j = 0U; j < frames_per_block; j++) { - const void *data = net_buf_pull_mem(buf, octets_per_frame); - - do_lc3_decode(stream->lc3_decoder, data, octets_per_frame, - lc3_audio_buf); - } - } -#endif /* CONFIG_USB_DEVICE_AUDIO */ - - net_buf_unref(buf); - } - -#if defined(CONFIG_USB_DEVICE_AUDIO) - const bool is_left_only = right_frames_cnt == 0U; - const bool is_right_only = left_frames_cnt == 0U; - - if (!is_left_only && !is_right_only && left_frames_cnt != right_frames_cnt) { - printk("Mismatch between number of left (%zu) and right (%zu) frames, " - "discard SDU", - left_frames_cnt, right_frames_cnt); - continue; - } - - /* Send frames to USB - If we only have a single channel we mix it to stereo */ - for (size_t i = 0U; i < MAX(left_frames_cnt, right_frames_cnt); i++) { - const bool is_single_channel = is_left_only || is_right_only; - static int16_t stereo_frame[LC3_MAX_NUM_SAMPLES_STEREO]; - int16_t *right_frame = right_frames[i]; - int16_t *left_frame = left_frames[i]; - - /* Not enough space to store data */ - if (ring_buf_space_get(&usb_ring_buf) < sizeof(stereo_frame)) { - break; - } - - memset(stereo_frame, 0, sizeof(stereo_frame)); - - /* Generate the stereo frame - * - * If we only have single channel then that is always stored in the - * left_frame, and we mix that to stereo - */ - for (int j = 0; j < LC3_MAX_NUM_SAMPLES_MONO; j++) { - if (is_single_channel) { - /* Mix to stereo */ - if (is_left_only) { - stereo_frame[j * 2] = left_frame[j]; - stereo_frame[j * 2 + 1] = left_frame[j]; - } else if (is_right_only) { - stereo_frame[j * 2] = right_frame[j]; - stereo_frame[j * 2 + 1] = right_frame[j]; - } - } else { - stereo_frame[j * 2] = left_frame[j]; - stereo_frame[j * 2 + 1] = right_frame[j]; - } - } - - add_to_usb_ring_buf(stereo_frame); - } -#endif /* CONFIG_USB_DEVICE_AUDIO */ - } -} - -/** Decode LC3 data on a stream and returns true if successful */ -static void do_lc3_decode(lc3_decoder_t decoder, const void *in_data, uint8_t octets_per_frame, - int16_t out_data[LC3_MAX_NUM_SAMPLES_MONO]) -{ - int err; - - err = lc3_decode(decoder, in_data, octets_per_frame, LC3_PCM_FORMAT_S16, out_data, 1); - if (err == 1) { - printk(" decoder performed PLC\n"); - } else if (err < 0) { - printk(" decoder failed - wrong parameters? (err = %d)\n", err); - } -} - -static int lc3_enable(struct broadcast_sink_stream *sink_stream) -{ - size_t chan_alloc_bit_cnt; - size_t sdu_size_required; - int frame_duration_us; - int freq_hz; - int ret; - - printk("Enable: stream with codec %p\n", sink_stream->stream.codec_cfg); - - ret = bt_audio_codec_cfg_get_freq(sink_stream->stream.codec_cfg); - if (ret > 0) { - freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret); - } else { - printk("Error: Codec frequency not set, cannot start codec."); - return -1; - } - - ret = bt_audio_codec_cfg_get_frame_dur(sink_stream->stream.codec_cfg); - if (ret > 0) { - frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret); - } else { - printk("Error: Frame duration not set, cannot start codec."); - return ret; - } - - ret = bt_audio_codec_cfg_get_chan_allocation(sink_stream->stream.codec_cfg, - &sink_stream->chan_allocation, true); - if (ret != 0) { - printk("Error: Channel allocation not set, invalid configuration for LC3"); - return ret; - } - - ret = bt_audio_codec_cfg_get_octets_per_frame(sink_stream->stream.codec_cfg); - if (ret > 0) { - sink_stream->lc3_octets_per_frame = (uint16_t)ret; - } else { - printk("Error: Octets per frame not set, invalid configuration for LC3"); - return ret; - } - - ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(sink_stream->stream.codec_cfg, true); - if (ret > 0) { - sink_stream->lc3_frames_blocks_per_sdu = (uint8_t)ret; - } else { - printk("Error: Frame blocks per SDU not set, invalid configuration for LC3"); - return ret; - } - - /* An SDU can consist of X frame blocks, each with Y frames (one per channel) of size Z in - * them. The minimum SDU size required for this is X * Y * Z. - */ - chan_alloc_bit_cnt = bt_audio_get_chan_count(sink_stream->chan_allocation); - sdu_size_required = chan_alloc_bit_cnt * sink_stream->lc3_octets_per_frame * - sink_stream->lc3_frames_blocks_per_sdu; - if (sdu_size_required > sink_stream->stream.qos->sdu) { - printk("With %zu channels and %u octets per frame and %u frames per block, SDUs " - "shall be at minimum %zu, but the stream has been configured for %u", - chan_alloc_bit_cnt, sink_stream->lc3_octets_per_frame, - sink_stream->lc3_frames_blocks_per_sdu, sdu_size_required, - sink_stream->stream.qos->sdu); - - return -EINVAL; - } - - printk("Enabling LC3 decoder with frame duration %uus, frequency %uHz and with channel " - "allocation 0x%08X, %u octets per frame and %u frame blocks per SDU\n", - frame_duration_us, freq_hz, sink_stream->chan_allocation, - sink_stream->lc3_octets_per_frame, sink_stream->lc3_frames_blocks_per_sdu); - -#if defined(CONFIG_USB_DEVICE_AUDIO) - sink_stream->lc3_decoder = lc3_setup_decoder(frame_duration_us, freq_hz, USB_SAMPLE_RATE, - &sink_stream->lc3_decoder_mem); -#else - sink_stream->lc3_decoder = lc3_setup_decoder(frame_duration_us, freq_hz, 0, - &sink_stream->lc3_decoder_mem); -#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ - - if (sink_stream->lc3_decoder == NULL) { - printk("ERROR: Failed to setup LC3 decoder - wrong parameters?\n"); - return -1; - } - - k_thread_start(decoder_tid); - - return 0; -} -#endif /* defined(CONFIG_LIBLC3) */ - -#if defined(CONFIG_USB_DEVICE_AUDIO) -/* Move the LC3 data to the USB ring buffer */ -static void add_to_usb_ring_buf(const int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO]) -{ - uint32_t size; - - size = ring_buf_put(&usb_ring_buf, (uint8_t *)audio_buf, - LC3_MAX_NUM_SAMPLES_STEREO * sizeof(int16_t)); - if (size != LC3_MAX_NUM_SAMPLES_STEREO) { - static int rb_put_failures; - - rb_put_failures++; - if (rb_put_failures == LOG_INTERVAL) { - printk("%s: Failure to add to usb_ring_buf %d, %u\n", __func__, - rb_put_failures, size); - } - } -} - -/* 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_SAMPLE_SIZE] = {0}; - static struct net_buf *pcm_buf; - static size_t cnt; - int err; - - ring_buf_get(&usb_ring_buf, (uint8_t *)usb_audio_data, sizeof(usb_audio_data)); - /* Ignore ring_buf_get() return value, if size is 0 we send empty PCM frames to - * not starve USB audio interface, if size is lower than USB_STEREO_SAMPLE_SIZE - * we send frames padded with 0's as usb_audio_data is 0-initialized - */ - - pcm_buf = net_buf_alloc(&usb_tx_buf_pool, K_NO_WAIT); - if (pcm_buf == NULL) { - printk("Could not allocate pcm_buf\n"); - return; - } - - net_buf_add_mem(pcm_buf, usb_audio_data, sizeof(usb_audio_data)); - - if (cnt % LOG_INTERVAL == 0) { - printk("Sending USB audio (count = %zu)\n", cnt); - } - - err = usb_audio_send(dev, pcm_buf, USB_STEREO_SAMPLE_SIZE); - if (err) { - printk("Failed to send USB audio: %d\n", err); - net_buf_unref(pcm_buf); - } - - cnt++; -} - -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); -} -#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ - -static void stream_connected_cb(struct bt_bap_stream *stream) -{ - printk("Stream %p connected\n", stream); + printk("Stream %p connected\n", bap_stream); k_sem_give(&sem_stream_connected); } -static void stream_disconnected_cb(struct bt_bap_stream *stream, uint8_t reason) +static void stream_disconnected_cb(struct bt_bap_stream *bap_stream, uint8_t reason) { int err; - printk("Stream %p disconnected with reason 0x%02X\n", stream, reason); + printk("Stream %p disconnected with reason 0x%02X\n", bap_stream, reason); err = k_sem_take(&sem_stream_connected, K_NO_WAIT); if (err != 0) { @@ -506,43 +120,30 @@ static void stream_disconnected_cb(struct bt_bap_stream *stream, uint8_t reason) } } -static void stream_started_cb(struct bt_bap_stream *stream) +static void stream_started_cb(struct bt_bap_stream *bap_stream) { - struct broadcast_sink_stream *sink_stream = - CONTAINER_OF(stream, struct broadcast_sink_stream, stream); - - printk("Stream %p started\n", stream); - - total_rx_iso_packet_count = 0U; - sink_stream->recv_cnt = 0U; - sink_stream->loss_cnt = 0U; - sink_stream->valid_cnt = 0U; - sink_stream->error_cnt = 0U; - -#if defined(CONFIG_LIBLC3) int err; - if (stream->codec_cfg != 0 && stream->codec_cfg->id != BT_HCI_CODING_FORMAT_LC3) { - /* No subgroups with LC3 was found */ - printk("Did not parse an LC3 codec\n"); - return; - } + printk("Stream %p started\n", bap_stream); - err = lc3_enable(sink_stream); - if (err < 0) { - printk("Error: cannot enable LC3 codec: %d", err); - return; + err = stream_rx_started(bap_stream); + if (err != 0) { + printk("stream_rx_started returned error: %d\n", err); } -#endif /* CONFIG_LIBLC3 */ k_sem_give(&sem_stream_started); } -static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +static void stream_stopped_cb(struct bt_bap_stream *bap_stream, uint8_t reason) { int err; - printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + printk("Stream %p stopped with reason 0x%02X\n", bap_stream, reason); + + err = stream_rx_stopped(bap_stream); + if (err != 0) { + printk("stream_rx_stopped returned error: %d\n", err); + } err = k_sem_take(&sem_stream_started, K_NO_WAIT); if (err != 0) { @@ -550,42 +151,10 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) } } -static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, +static void stream_recv_cb(struct bt_bap_stream *bap_stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { - struct broadcast_sink_stream *sink_stream = - CONTAINER_OF(stream, struct broadcast_sink_stream, stream); - - if (info->flags & BT_ISO_FLAGS_ERROR) { - sink_stream->error_cnt++; - } - - if (info->flags & BT_ISO_FLAGS_LOST) { - sink_stream->loss_cnt++; - } - - if (info->flags & BT_ISO_FLAGS_VALID) { - sink_stream->valid_cnt++; -#if defined(CONFIG_LIBLC3) - k_mutex_lock(&sink_stream->lc3_decoder_mutex, K_FOREVER); - if (sink_stream->in_buf != NULL) { - net_buf_unref(sink_stream->in_buf); - sink_stream->in_buf = NULL; - } - - sink_stream->in_buf = net_buf_ref(buf); - k_mutex_unlock(&sink_stream->lc3_decoder_mutex); - k_sem_give(&lc3_decoder_sem); -#endif /* defined(CONFIG_LIBLC3) */ - } - - total_rx_iso_packet_count++; - sink_stream->recv_cnt++; - if ((sink_stream->recv_cnt % LOG_INTERVAL) == 0U) { - printk("Stream %p: received %u total ISO packets: Valid %u | Error %u | Loss %u\n", - &sink_stream->stream, sink_stream->recv_cnt, sink_stream->valid_cnt, - sink_stream->error_cnt, sink_stream->loss_cnt); - } + stream_rx_recv(bap_stream, info, buf); } static struct bt_bap_stream_ops stream_ops = { @@ -1311,30 +880,19 @@ static int init(void) bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb); bt_le_scan_cb_register(&bap_scan_cb); - for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { - streams[i].stream.ops = &stream_ops; - } + stream_rx_get_streams(bap_streams_p); - /* Initialize ring buffers and USB */ -#if defined(CONFIG_USB_DEVICE_AUDIO) - const struct device *hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0)); - static const struct usb_audio_ops usb_ops = { - .data_request_cb = usb_data_request_cb, - .data_written_cb = usb_data_written_cb, - }; + for (size_t i = 0U; i < CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT; i++) { + bt_bap_stream_cb_register(bap_streams_p[i], &stream_ops); + } - if (!device_is_ready(hs_dev)) { - printk("Cannot get USB Headset Device\n"); - return -EIO; + if (IS_ENABLED(CONFIG_LIBLC3)) { + lc3_init(); } - usb_audio_register(hs_dev, &usb_ops); - err = usb_enable(NULL); - if (err && err != -EALREADY) { - printk("Failed to enable USB\n"); - return err; + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + usb_init(); } -#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ return 0; } @@ -1476,13 +1034,6 @@ int main(void) return 0; } - for (size_t i = 0U; i < ARRAY_SIZE(streams_p); i++) { - streams_p[i] = &streams[i].stream; -#if defined(CONFIG_LIBLC3) - k_mutex_init(&streams[i].lc3_decoder_mutex); -#endif /* defined(CONFIG_LIBLC3) */ - } - while (true) { uint32_t sync_bitfield; @@ -1645,7 +1196,7 @@ int main(void) "(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, + err = bt_bap_broadcast_sink_sync(broadcast_sink, sync_bitfield, bap_streams_p, sink_broadcast_code); if (err != 0) { printk("Unable to sync to broadcast source: %d\n", err); diff --git a/samples/bluetooth/bap_broadcast_sink/src/stream_rx.c b/samples/bluetooth/bap_broadcast_sink/src/stream_rx.c new file mode 100644 index 0000000000000..1caaec5361c2e --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/src/stream_rx.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_LIBLC3) +#include +#endif /* defined(CONFIG_LIBLC3) */ + +#include "stream_rx.h" +#include "lc3.h" + +struct stream_rx rx_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; +uint64_t total_rx_iso_packet_count; /* This value is exposed to test code */ + +LOG_MODULE_REGISTER(stream_rx, CONFIG_LOG_DEFAULT_LEVEL); + +#if CONFIG_INFO_REPORTING_INTERVAL > 0 +static void log_stream_rx(const struct stream_rx *stream, const struct bt_iso_recv_info *info, + const struct net_buf *buf) +{ + LOG_INF("[%zu]: Incoming audio on stream %p len %u, flags 0x%02X, seq_num %u and ts %u: " + "Valid %zu | Error %zu | Loss %zu | Dup TS %zu | Dup PSN %zu", + stream->reporting_info.recv_cnt, &stream->stream, buf->len, info->flags, + info->seq_num, info->ts, stream->reporting_info.valid_cnt, + stream->reporting_info.error_cnt, stream->reporting_info.loss_cnt, + stream->reporting_info.dup_ts_cnt, stream->reporting_info.dup_psn_cnt); +} +#endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */ + +void stream_rx_recv(struct bt_bap_stream *bap_stream, const struct bt_iso_recv_info *info, + struct net_buf *buf) +{ + struct stream_rx *stream = CONTAINER_OF(bap_stream, struct stream_rx, stream); + +#if CONFIG_INFO_REPORTING_INTERVAL > 0 + if ((stream->reporting_info.recv_cnt % CONFIG_INFO_REPORTING_INTERVAL) == 0U) { + log_stream_rx(stream, info, buf); + } + + if (stream->reporting_info.recv_cnt > 0U && info->ts == stream->reporting_info.last_ts) { + log_stream_rx(stream, info, buf); + LOG_WRN("Duplicated timestamp received: %u\n", stream->reporting_info.last_ts); + stream->reporting_info.dup_ts_cnt++; + } + + if (stream->reporting_info.recv_cnt > 0U && + info->seq_num == stream->reporting_info.last_seq_num) { + log_stream_rx(stream, info, buf); + LOG_WRN("Duplicated PSN received: %u\n", stream->reporting_info.last_seq_num); + stream->reporting_info.dup_psn_cnt++; + } + + if (info->flags & BT_ISO_FLAGS_ERROR) { + log_stream_rx(stream, info, buf); + LOG_DBG("ISO receive error\n"); + stream->reporting_info.error_cnt++; + } + + if (info->flags & BT_ISO_FLAGS_LOST) { + log_stream_rx(stream, info, buf); + LOG_DBG("ISO receive lost\n"); + stream->reporting_info.loss_cnt++; + } + + if (info->flags & BT_ISO_FLAGS_VALID) { + if (buf->len == 0U) { + stream->reporting_info.empty_sdu_cnt++; + } else { + stream->reporting_info.valid_cnt++; + } + } + + stream->reporting_info.last_seq_num = info->seq_num; + stream->reporting_info.last_ts = info->ts; + stream->reporting_info.recv_cnt++; +#endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */ + + total_rx_iso_packet_count++; + + if (IS_ENABLED(CONFIG_LIBLC3)) { + /* Invalid SDUs will trigger PLC */ + lc3_enqueue_for_decoding(stream, info, buf); + } +} + +int stream_rx_started(struct bt_bap_stream *bap_stream) +{ + struct stream_rx *stream = CONTAINER_OF(bap_stream, struct stream_rx, stream); + + if (stream == NULL) { + return -EINVAL; + } + +#if CONFIG_INFO_REPORTING_INTERVAL > 0 + memset(&stream->reporting_info, 0, sizeof((stream->reporting_info))); +#endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */ + + if (IS_ENABLED(CONFIG_LIBLC3) && bap_stream->codec_cfg != NULL && + bap_stream->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { + int err; + + err = lc3_enable(stream); + if (err < 0) { + LOG_ERR("Error: cannot enable LC3 codec: %d", err); + return err; + } + } + + return 0; +} + +int stream_rx_stopped(struct bt_bap_stream *bap_stream) +{ + struct stream_rx *stream = CONTAINER_OF(bap_stream, struct stream_rx, stream); + + if (bap_stream == NULL) { + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_LIBLC3) && bap_stream->codec_cfg != NULL && + bap_stream->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { + int err; + + err = lc3_disable(stream); + if (err < 0) { + LOG_ERR("Error: cannot disable LC3 codec: %d", err); + return err; + } + } + + return 0; +} + +void stream_rx_get_streams( + struct bt_bap_stream *bap_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]) +{ + for (size_t i = 0U; i < ARRAY_SIZE(rx_streams); i++) { + bap_streams[i] = &rx_streams[i].stream; + } +} diff --git a/samples/bluetooth/bap_broadcast_sink/src/stream_rx.h b/samples/bluetooth/bap_broadcast_sink/src/stream_rx.h new file mode 100644 index 0000000000000..b2afc64349237 --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/src/stream_rx.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SAMPLE_BAP_BROADCAST_SINK_STREAM_RX_H +#define SAMPLE_BAP_BROADCAST_SINK_STREAM_RX_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_LIBLC3) +#include +#endif /* defined(CONFIG_LIBLC3) */ + +struct stream_rx { + /* A BAP stream object */ + struct bt_bap_stream stream; +#if CONFIG_INFO_REPORTING_INTERVAL > 0 + /** Struct containing information useful for logging purposes */ + struct { + /** Total Number of SDUs received */ + size_t recv_cnt; + /** Number of lost SDUs */ + size_t loss_cnt; + /** Number of SDUs containing errors */ + size_t error_cnt; + /** Number of valid SDUs received */ + size_t valid_cnt; + /** Number of empty SDUs received */ + size_t empty_sdu_cnt; + /** Number of SDUs with duplicated packet sequence number received */ + size_t dup_psn_cnt; + /** Number of SDUs with duplicated timestamps received */ + size_t dup_ts_cnt; + /** The last received timestamp to track dup_ts_cnt */ + uint32_t last_ts; + /** The last received sequence number to track dup_psn_cnt */ + uint16_t last_seq_num; +#if CONFIG_LIBLC3 > 0 + /** Number of SDUs decoded */ + size_t lc3_decoded_cnt; +#endif /* CONFIG_LIBLC3 > 0 */ + } reporting_info; +#endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */ + +#if defined(CONFIG_LIBLC3) + /** Octets per frame - Used to validate that the incoming data is of correct size */ + uint16_t lc3_octets_per_frame; + /** Frame blocks per SDU - Used to split the SDU into frame blocks when decoding */ + uint8_t lc3_frame_blocks_per_sdu; + + /** Number of channels - Used to split the SDU into frame blocks when decoding */ + uint8_t lc3_chan_cnt; + + /** + * @brief The configured channels of the stream + * + * Used to determine whether to send data to USB and count number of channels + */ + enum bt_audio_location lc3_chan_allocation; + + /** Memory use for the LC3 decoder - Supports any configuration */ + lc3_decoder_mem_48k_t lc3_decoder_mem; + /** Reference to the LC3 decoder */ + lc3_decoder_t lc3_decoder; +#endif /* defined(CONFIG_LIBLC3) */ +}; + +/** + * @brief Function to call for each SDU received + * + * Will decode with LC3 and send to USB if enabled + */ +void stream_rx_recv(struct bt_bap_stream *bap_stream, const struct bt_iso_recv_info *info, + struct net_buf *buf); + +size_t stream_rx_get_streaming_cnt(void); +int stream_rx_started(struct bt_bap_stream *bap_stream); +int stream_rx_stopped(struct bt_bap_stream *bap_stream); +void stream_rx_get_streams( + struct bt_bap_stream *bap_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]); + +#endif /* SAMPLE_BAP_BROADCAST_SINK_STREAM_RX_H */ diff --git a/samples/bluetooth/bap_broadcast_sink/src/usb.c b/samples/bluetooth/bap_broadcast_sink/src/usb.c new file mode 100644 index 0000000000000..dbe5ec16a62b1 --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/src/usb.c @@ -0,0 +1,350 @@ +/** + * @file + * @brief Bluetooth BAP Broadcast Sink Sample LC3 + * + * This files handles all the USB related functionality to audio out for the Sample + * + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lc3.h" +#include "stream_rx.h" +#include "usb.h" + +LOG_MODULE_REGISTER(usb, CONFIG_LOG_DEFAULT_LEVEL); + +#define USB_ENQUEUE_COUNT 30U /* 30 times 1ms frames => 30ms */ +#define USB_FRAME_DURATION_US 1000U +#define USB_SAMPLE_CNT ((USB_FRAME_DURATION_US * USB_SAMPLE_RATE_HZ) / 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) + +struct decoded_sdu { + int16_t right_frames[CONFIG_MAX_CODEC_FRAMES_PER_SDU][LC3_MAX_NUM_SAMPLES_MONO]; + int16_t left_frames[CONFIG_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 (lc3_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 (CONFIG_INFO_REPORTING_INTERVAL > 0 && + (++cnt % (CONFIG_INFO_REPORTING_INTERVAL * 10)) == 0U) { + LOG_INF("[%zu]: Sending USB audio", cnt); + } + } else { + static size_t cnt; + + if (CONFIG_INFO_REPORTING_INTERVAL > 0 && + (++cnt % (CONFIG_INFO_REPORTING_INTERVAL * 10)) == 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 (CONFIG_INFO_REPORTING_INTERVAL > 0 && + (cnt % (CONFIG_INFO_REPORTING_INTERVAL * 10)) == 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 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 (CONFIG_INFO_REPORTING_INTERVAL > 0 && + (fail_cnt % CONFIG_INFO_REPORTING_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 (CONFIG_INFO_REPORTING_INTERVAL > 0 && (++cnt % CONFIG_INFO_REPORTING_INTERVAL) == 0U) { + LOG_INF("[%zu]: Sending %u USB audio frame", cnt, frame_cnt); + } + + 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 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 (CONFIG_INFO_REPORTING_INTERVAL > 0 && (++cnt % CONFIG_INFO_REPORTING_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 (bt_audio_get_chan_count(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 */ + 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) { + 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 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; +} + +int usb_init(void) +{ + const struct device *hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0)); + static const struct usb_audio_ops usb_ops = { + .data_request_cb = usb_data_request_cb, + .data_written_cb = usb_data_written_cb, + }; + static bool initialized; + int err; + + if (initialized) { + return -EALREADY; + } + + 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; + } + + LOG_INF("USB initialized"); + initialized = true; + + return 0; +} diff --git a/samples/bluetooth/bap_broadcast_sink/src/usb.h b/samples/bluetooth/bap_broadcast_sink/src/usb.h new file mode 100644 index 0000000000000..e05a997c2516a --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/src/usb.h @@ -0,0 +1,71 @@ +/** + * @file + * @brief Bluetooth BAP Broadcast Sink sample USB header + * + * This files handles all the USB related functionality for the sample + * + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SAMPLE_BAP_BROADCAST_SINK_USB_H +#define SAMPLE_BAP_BROADCAST_SINK_USB_H +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USB_SAMPLE_RATE_HZ 48000U + +/** + * @brief Add decoded frame to the USB buffer + * + * @param chan_allocation The channel of the frame (@ref BT_AUDIO_LOCATION_FRONT_LEFT, @ref + * BT_AUDIO_LOCATION_FRONT_RIGHT or @ref BT_AUDIO_LOCATION_MONO_AUDIO) + * @param frame The frame + * @param frame_size The size of @p in octets + * @param ts The timestamp of the frame + * + * @retval 0 Success + * @retval -EINVAL Invalid channel, frame of framesize + * @retval -ENOEXEC Old timestamp, discarded + * @retval -ENOMEM No memory to enqueue + */ +int usb_add_frame_to_usb(enum bt_audio_location chan_allocation, const int16_t *frame, + size_t frame_size, uint32_t ts); + +/** + * @brief Clear last sent SDU + * + * If only part of the SDU could be decoded, this should be called + */ +void usb_clear_frames_to_usb(void); + +/** + * @brief Initialize the USB module + * + * This will start the USB thread if not already initialized + * + * @retval 0 Success + * @retval -EALREADY Already initialized + */ +int usb_init(void); + +#endif /* SAMPLE_BAP_BROADCAST_SINK_USB_H */ diff --git a/tests/bsim/bluetooth/audio_samples/bap_broadcast_sink/CMakeLists.txt b/tests/bsim/bluetooth/audio_samples/bap_broadcast_sink/CMakeLists.txt index c30094a9c8391..f7ab4892ae67a 100644 --- a/tests/bsim/bluetooth/audio_samples/bap_broadcast_sink/CMakeLists.txt +++ b/tests/bsim/bluetooth/audio_samples/bap_broadcast_sink/CMakeLists.txt @@ -9,8 +9,12 @@ set(bap_broadcast_sink_path ${ZEPHYR_BASE}/samples/bluetooth/bap_broadcast_sink) target_sources(app PRIVATE ${bap_broadcast_sink_path}/src/main.c + ${bap_broadcast_sink_path}/src/stream_rx.c ) +zephyr_sources_ifdef(CONFIG_LIBLC3 ${bap_broadcast_sink_path}/src/lc3.c) +zephyr_sources_ifdef(CONFIG_USB_DEVICE_AUDIO ${bap_broadcast_sink_path}/src/usb.c) + target_sources(app PRIVATE src/broadcast_sink_test.c src/test_main.c From ea591272e9ce5bad1b384a27a094a57a6131b750 Mon Sep 17 00:00:00 2001 From: Yasin Ustuner Date: Thu, 13 Feb 2025 23:00:13 +0300 Subject: [PATCH 0218/6055] manifest: Add MAX32660 hal files This commit adds necessary hal files for MAX32660 board. Signed-off-by: Yasin Ustuner --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 86e16f29fce28..65d565d2ae589 100644 --- a/west.yml +++ b/west.yml @@ -142,7 +142,7 @@ manifest: groups: - fs - name: hal_adi - revision: 13a3f2d44c27416846cde2fe9f23b638c7ad446d + revision: 633fcecf3717aaa22079cf6121627a879f24df51 path: modules/hal/adi groups: - hal From de9f48ee3362c8e452632c5e56921f99667f4e3e Mon Sep 17 00:00:00 2001 From: Yasin Ustuner Date: Wed, 12 Feb 2025 11:39:35 +0300 Subject: [PATCH 0219/6055] soc: adi: Add MAX32660 SoC This commit adds MAX32660 SoC and dts files. Signed-off-by: Yasin Ustuner --- dts/arm/adi/max32/max32660-pinctrl.dtsi | 149 +++++++++++++++++++++++ dts/arm/adi/max32/max32660.dtsi | 90 ++++++++++++++ soc/adi/max32/Kconfig.defconfig.max32660 | 14 +++ soc/adi/max32/Kconfig.soc | 5 + soc/adi/max32/soc.yml | 1 + 5 files changed, 259 insertions(+) create mode 100644 dts/arm/adi/max32/max32660-pinctrl.dtsi create mode 100644 dts/arm/adi/max32/max32660.dtsi create mode 100644 soc/adi/max32/Kconfig.defconfig.max32660 diff --git a/dts/arm/adi/max32/max32660-pinctrl.dtsi b/dts/arm/adi/max32/max32660-pinctrl.dtsi new file mode 100644 index 0000000000000..cfb872c11d315 --- /dev/null +++ b/dts/arm/adi/max32/max32660-pinctrl.dtsi @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + pinctrl: pin-controller@40008000 { + /omit-if-no-ref/ swdio_p0_0: swdio_p0_0 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_miso_p0_0: spi1_miso_p0_0 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_tx_p0_0: uart1_tx_p0_0 { + pinmux = ; + }; + + /omit-if-no-ref/ swdclk_p0_1: swdclk_p0_1 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_mosi_p0_1: spi1_mosi_p0_1 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_rx_p0_1: uart1_rx_p0_1 { + pinmux = ; + }; + + /omit-if-no-ref/ i2c1_scl_p0_2: i2c1_scl_p0_2 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_sck_p0_2: spi1_sck_p0_2 { + pinmux = ; + }; + + /omit-if-no-ref/ cal32k_p0_2: cal32k_p0_2 { + pinmux = ; + }; + + /omit-if-no-ref/ i2c1_sda_p0_3: i2c1_sda_p0_3 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_ss0_p0_3: spi1_ss0_p0_3 { + pinmux = ; + }; + + /omit-if-no-ref/ tmr0_p0_3: tmr0_p0_3 { + pinmux = ; + }; + + /omit-if-no-ref/ spi0_miso_p0_4: spi0_miso_p0_4 { + pinmux = ; + }; + + /omit-if-no-ref/ uart0_tx_p0_4: uart0_tx_p0_4 { + pinmux = ; + }; + + /omit-if-no-ref/ spi0_mosi_p0_5: spi0_mosi_p0_5 { + pinmux = ; + }; + + /omit-if-no-ref/ uart0_rx_p0_5: uart0_rx_p0_5 { + pinmux = ; + }; + + /omit-if-no-ref/ spi0_sck_p0_6: spi0_sck_p0_6 { + pinmux = ; + }; + + /omit-if-no-ref/ uart0_cts_p0_6: uart0_cts_p0_6 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_tx_p0_6: uart1_tx_p0_6 { + pinmux = ; + }; + + /omit-if-no-ref/ spi0_ss0_p0_7: spi0_ss0_p0_7 { + pinmux = ; + }; + + /omit-if-no-ref/ uart0_rts_p0_7: uart0_rts_p0_7 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_rx_p0_7: uart1_rx_p0_7 { + pinmux = ; + }; + + /omit-if-no-ref/ i2c0_scl_p0_8: i2c0_scl_p0_8 { + pinmux = ; + }; + + /omit-if-no-ref/ swdio_p0_8: swdio_p0_8 { + pinmux = ; + }; + + /omit-if-no-ref/ i2c0_sda_p0_9: i2c0_sda_p0_9 { + pinmux = ; + }; + + /omit-if-no-ref/ swdclk_p0_9: swdclk_p0_9 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_miso_p0_10: spi1_miso_p0_10 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_tx_p0_10: uart1_tx_p0_10 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_mosi_p0_11: spi1_mosi_p0_11 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_rx_p0_11: uart1_rx_p0_11 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_sck_p0_12: spi1_sck_p0_12 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_cts_p0_12: uart1_cts_p0_12 { + pinmux = ; + }; + + /omit-if-no-ref/ spi1_ss0_p0_13: spi1_ss0_p0_13 { + pinmux = ; + }; + + /omit-if-no-ref/ uart1_rts_p0_13: uart1_rts_p0_13 { + pinmux = ; + }; + }; + }; +}; diff --git a/dts/arm/adi/max32/max32660.dtsi b/dts/arm/adi/max32/max32660.dtsi new file mode 100644 index 0000000000000..8c04ad592ffe7 --- /dev/null +++ b/dts/arm/adi/max32/max32660.dtsi @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&clk_ipo { + clock-frequency = ; +}; + +&sram0 { + reg = <0x20000000 DT_SIZE_K(16)>; +}; + +/delete-node/ &clk_iso; +/delete-node/ &clk_ibro; +/delete-node/ &clk_erfo; +/delete-node/ &adc; +/delete-node/ &gpio1; +/delete-node/ &i2c2; +/delete-node/ &uart2; +/delete-node/ &timer3; +/delete-node/ &trng; +/delete-node/ &flash0; + +&flc0 { + flash0: flash@0{ + compatible = "soc-nv-flash"; + reg = <0x00000000 DT_SIZE_K(256)>; + write-block-size = <16>; + erase-block-size = <8192>; + }; +}; + +/* MAX32660 extra peripherals. */ +/ { + chosen { + /delete-property/ zephyr,entropy; + }; + + soc { + sram1: memory@20004000 { + compatible = "mmio-sram"; + reg = <0x20004000 DT_SIZE_K(16)>; + }; + + sram2: memory@20008000 { + compatible = "mmio-sram"; + reg = <0x20008000 DT_SIZE_K(32)>; + }; + + sram3: memory@20010000 { + compatible = "mmio-sram"; + reg = <0x20010000 DT_SIZE_K(32)>; + }; + + dma0: dma@40028000 { + compatible = "adi,max32-dma"; + reg = <0x40028000 0x1000>; + clocks = <&gcr ADI_MAX32_CLOCK_BUS0 5>; + interrupts = <28 0>, <29 0>, <30 0>, <31 0>; + dma-channels = <4>; + status = "disabled"; + #dma-cells = <2>; + }; + + spi0: spi@40046000 { + compatible = "adi,max32-spi"; + reg = <0x40046000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&gcr ADI_MAX32_CLOCK_BUS0 6>; + interrupts = <16 0>; + status = "disabled"; + }; + + spi1: spi@40019000 { + compatible = "adi,max32-spi"; + reg = <0x40019000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&gcr ADI_MAX32_CLOCK_BUS0 7>; + interrupts = <17 0>; + status = "disabled"; + }; + }; +}; diff --git a/soc/adi/max32/Kconfig.defconfig.max32660 b/soc/adi/max32/Kconfig.defconfig.max32660 new file mode 100644 index 0000000000000..29848d44d1dc5 --- /dev/null +++ b/soc/adi/max32/Kconfig.defconfig.max32660 @@ -0,0 +1,14 @@ +# Analog Devices MAX32660 MCU + +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MAX32660 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/clocks/clk_ipo,clock-frequency) + +config NUM_IRQS + default 55 + +endif # SOC_MAX32660 diff --git a/soc/adi/max32/Kconfig.soc b/soc/adi/max32/Kconfig.soc index 700a00c3d8715..e0be0041b4b6c 100644 --- a/soc/adi/max32/Kconfig.soc +++ b/soc/adi/max32/Kconfig.soc @@ -25,6 +25,10 @@ config SOC_MAX32655_M4 select SOC_MAX32655 select SOC_FAMILY_MAX32_M4 +config SOC_MAX32660 + bool + select SOC_FAMILY_MAX32_M4 + config SOC_MAX32662 bool select SOC_FAMILY_MAX32_M4 @@ -84,6 +88,7 @@ config SOC_MAX78002_M4 config SOC default "max32650" if SOC_MAX32650 default "max32655" if SOC_MAX32655 + default "max32660" if SOC_MAX32660 default "max32662" if SOC_MAX32662 default "max32666" if SOC_MAX32666 default "max32670" if SOC_MAX32670 diff --git a/soc/adi/max32/soc.yml b/soc/adi/max32/soc.yml index b08b6e53102eb..3bf7288d120df 100644 --- a/soc/adi/max32/soc.yml +++ b/soc/adi/max32/soc.yml @@ -8,6 +8,7 @@ family: - name: max32655 cpuclusters: - name: m4 + - name: max32660 - name: max32662 - name: max32666 cpuclusters: From c62606daa74fc93314844576f63fe922dac6d4c2 Mon Sep 17 00:00:00 2001 From: Yasin Ustuner Date: Thu, 13 Feb 2025 10:55:49 +0300 Subject: [PATCH 0220/6055] include: zephyr: dt-bindings: Add MAX32660 DMA binding This commit adds binding file for DMA slots Signed-off-by: Yasin Ustuner --- dts/arm/adi/max32/max32660.dtsi | 1 + include/zephyr/dt-bindings/dma/max32660_dma.h | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 include/zephyr/dt-bindings/dma/max32660_dma.h diff --git a/dts/arm/adi/max32/max32660.dtsi b/dts/arm/adi/max32/max32660.dtsi index 8c04ad592ffe7..b93b451ffd885 100644 --- a/dts/arm/adi/max32/max32660.dtsi +++ b/dts/arm/adi/max32/max32660.dtsi @@ -6,6 +6,7 @@ #include #include +#include &clk_ipo { clock-frequency = ; diff --git a/include/zephyr/dt-bindings/dma/max32660_dma.h b/include/zephyr/dt-bindings/dma/max32660_dma.h new file mode 100644 index 0000000000000..e52805e1ab64c --- /dev/null +++ b/include/zephyr/dt-bindings/dma/max32660_dma.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_DMA_MAX32660_DMA_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_DMA_MAX32660_DMA_H_ + +#define MAX32_DMA_SLOT_MEMTOMEM 0x00U +#define MAX32_DMA_SLOT_SPI0_RX 0x01U +#define MAX32_DMA_SLOT_SPI1_RX 0x02U +#define MAX32_DMA_SLOT_UART0_RX 0x04U +#define MAX32_DMA_SLOT_UART1_RX 0x05U +#define MAX32_DMA_SLOT_I2C0_RX 0x07U +#define MAX32_DMA_SLOT_I2C1_RX 0x08U +#define MAX32_DMA_SLOT_SPI0_TX 0x21U +#define MAX32_DMA_SLOT_SPI1_TX 0x22U +#define MAX32_DMA_SLOT_UART0_TX 0x24U +#define MAX32_DMA_SLOT_UART1_TX 0x25U +#define MAX32_DMA_SLOT_I2C0_TX 0x27U +#define MAX32_DMA_SLOT_I2C1_TX 0x28U + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_DMA_MAX32660_DMA_H_ */ From 8383234c67dc7cc8330ec86cb934bbb5cca003cb Mon Sep 17 00:00:00 2001 From: Yasin Ustuner Date: Thu, 13 Feb 2025 14:28:30 +0300 Subject: [PATCH 0221/6055] drivers: clock control: Update IBRO Clock for MAX32 This commit updates ADI_MAX32_CLK_IBRO_FREQ macro because MAX32660 does not support IBRO clock. Signed-off-by: Yasin Ustuner --- include/zephyr/drivers/clock_control/adi_max32_clock_control.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/drivers/clock_control/adi_max32_clock_control.h b/include/zephyr/drivers/clock_control/adi_max32_clock_control.h index cd889d370b252..0f1e7b128823e 100644 --- a/include/zephyr/drivers/clock_control/adi_max32_clock_control.h +++ b/include/zephyr/drivers/clock_control/adi_max32_clock_control.h @@ -41,7 +41,7 @@ struct max32_perclk { #define ADI_MAX32_CLK_IPO_FREQ DT_PROP(DT_NODELABEL(clk_ipo), clock_frequency) #define ADI_MAX32_CLK_ERFO_FREQ DT_PROP_OR(DT_NODELABEL(clk_erfo), clock_frequency, 0) -#define ADI_MAX32_CLK_IBRO_FREQ DT_PROP(DT_NODELABEL(clk_ibro), clock_frequency) +#define ADI_MAX32_CLK_IBRO_FREQ DT_PROP_OR(DT_NODELABEL(clk_ibro), clock_frequency, 0) #define ADI_MAX32_CLK_ISO_FREQ DT_PROP_OR(DT_NODELABEL(clk_iso), clock_frequency, 0) #define ADI_MAX32_CLK_INRO_FREQ DT_PROP(DT_NODELABEL(clk_inro), clock_frequency) #define ADI_MAX32_CLK_ERTCO_FREQ DT_PROP(DT_NODELABEL(clk_ertco), clock_frequency) From ef1d629dc44bfd00f49323e41018bf1cc3732949 Mon Sep 17 00:00:00 2001 From: Yasin Ustuner Date: Thu, 13 Feb 2025 11:28:00 +0300 Subject: [PATCH 0222/6055] boards: adi: Add MAX32660EVSYS board This commit adds MAX32660EVSYS board basic port. Signed-off-by: Yasin Ustuner Signed-off-by: Matthew McClintock --- .../adi/max32660evsys/Kconfig.max32660evsys | 7 + boards/adi/max32660evsys/board.cmake | 5 + boards/adi/max32660evsys/board.yml | 9 ++ .../max32660evsys/doc/img/max32660evsys.webp | Bin 0 -> 37998 bytes boards/adi/max32660evsys/doc/index.rst | 123 ++++++++++++++++++ boards/adi/max32660evsys/max32660evsys.dts | 56 ++++++++ boards/adi/max32660evsys/max32660evsys.yaml | 13 ++ .../adi/max32660evsys/max32660evsys_defconfig | 16 +++ boards/common/openocd-adi-max32.boards.cmake | 2 + 9 files changed, 231 insertions(+) create mode 100644 boards/adi/max32660evsys/Kconfig.max32660evsys create mode 100644 boards/adi/max32660evsys/board.cmake create mode 100644 boards/adi/max32660evsys/board.yml create mode 100644 boards/adi/max32660evsys/doc/img/max32660evsys.webp create mode 100644 boards/adi/max32660evsys/doc/index.rst create mode 100644 boards/adi/max32660evsys/max32660evsys.dts create mode 100644 boards/adi/max32660evsys/max32660evsys.yaml create mode 100644 boards/adi/max32660evsys/max32660evsys_defconfig diff --git a/boards/adi/max32660evsys/Kconfig.max32660evsys b/boards/adi/max32660evsys/Kconfig.max32660evsys new file mode 100644 index 0000000000000..2e93639776153 --- /dev/null +++ b/boards/adi/max32660evsys/Kconfig.max32660evsys @@ -0,0 +1,7 @@ +# MAX32660EVSYS boards configuration + +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_MAX32660EVSYS + select SOC_MAX32660 diff --git a/boards/adi/max32660evsys/board.cmake b/boards/adi/max32660evsys/board.cmake new file mode 100644 index 0000000000000..617eecca8f8ea --- /dev/null +++ b/boards/adi/max32660evsys/board.cmake @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/openocd-adi-max32.boards.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/adi/max32660evsys/board.yml b/boards/adi/max32660evsys/board.yml new file mode 100644 index 0000000000000..5e7e264b04c83 --- /dev/null +++ b/boards/adi/max32660evsys/board.yml @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +board: + name: max32660evsys + full_name: MAX32660EVSYS + vendor: adi + socs: + - name: max32660 diff --git a/boards/adi/max32660evsys/doc/img/max32660evsys.webp b/boards/adi/max32660evsys/doc/img/max32660evsys.webp new file mode 100644 index 0000000000000000000000000000000000000000..b3043a033a249821857ff08fd6a67caa61009b10 GIT binary patch literal 37998 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 literal 0 HcmV?d00001 diff --git a/boards/adi/max32660evsys/doc/index.rst b/boards/adi/max32660evsys/doc/index.rst new file mode 100644 index 0000000000000..91919764c297f --- /dev/null +++ b/boards/adi/max32660evsys/doc/index.rst @@ -0,0 +1,123 @@ +.. zephyr:board:: max32660evsys + +Overview +******** +The MAX32660 evaluation system offers a compact development platform that +provides access to all the features of the MAX32660 in a tiny, easy to +use board. A MAX32625PICO-based debug adapter comes attached to the main +board. It can be snapped free when programming is complete. The debug +module supports an optional 10-pin Arm® Cortex® debug connector for DAPLink +functionality. Combined measurements are 0.65in x 2.2in, while the main board +alone measures 0.65in x 0.95in. External connections terminate in a dual-row +header footprint compatible with both thru-hole and SMT applications. This +board provides a powerful processing subsystem in a very small space that +can be easily integrated into a variety of applications. + +The Zephyr port is running on the MAX32660 MCU. + +Hardware +******** + +- MAX32660 MCU: + + - High-Efficiency Microcontroller for Wearable Devices + + - Internal Oscillator Operates Up to 96MHz + - 256KB Flash Memory + - 96KB SRAM, Optionally Preserved in Lowest Power Backup Mode + - 16KB Instruction Cache + - Memory Protection Unit (MPU) + - Low 1.1V VCORE Supply Voltage + - 3.6V GPIO Operating Range + - Internal LDO Provides Operation from Single Supply + - Wide Operating Temperature: -40°C to +105°C + + - Power Management Maximizes Uptime for Battery Applications + + - 85µA/MHz Active Executing from Flash + - 2µA Full Memory Retention Power in Backup Mode at VDD = 1.8V + - 450nA Ultra-Low Power RTC at VDD=1.8V + - Internal 80kHz Ring Oscillator + + - Optimal Peripheral Mix Provides Platform Scalability + + - Up to 14 General-Purpose I/O Pins + - Up to Two SPI + - I2S + - Up to Two UARTs + - Up to Two I2C, 3.4Mbps High Speed + - Four-Channel Standard DMA Controller + - Three 32-Bit Timers + - Watchdog Timer + - CMOS-Level 32.768kHz RTC Output + +- Benefits and Features of MAX32660-EVSYS: + + - DIP Breakout Board + + - 100mil Pitch Dual Inline Pin Headers + - Breadboard Compatible + + - Integrated Peripherals + + - Red Indicator LED + - User Pushbutton + + - MAX32625PICO-Based Debug Adapter + + - CMSIS-DAP SWD Debugger + - Virtual UART Console + +Supported Features +================== + +The ``max32660evsys`` board supports the following interfaces: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | clock and reset control | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial | ++-----------+------------+-------------------------------------+ + +Programming and Debugging +************************* + +Flashing +======== + +An Arm® debug access port (DAP) provides an external interface for debugging during application +development. The DAP is a standard Arm CoreSight® serial wire debug port, uses a two-pin serial +interface (SWDCLK and SWDIO), and is accessed through 10-pin header (J4). + +Once the debug probe is connected to your host computer, then you can simply run the +``west flash`` command to write a firmware image into flash. + +.. note:: + + This board uses OpenOCD as the default debug interface. You can also use + a Segger J-Link with Segger's native tooling by overriding the runner, + appending ``--runner jlink`` to your ``west`` command(s). The J-Link should + be connected to the standard 2*5 pin debug connector (J3) using an + appropriate adapter board and cable. + +Debugging +========= + +Please refer to the `Flashing`_ section and run the ``west debug`` command +instead of ``west flash``. + +References +********** + +- `MAX32660EVSYS web page`_ + +.. _MAX32660EVSYS web page: + https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32660-evsys.html diff --git a/boards/adi/max32660evsys/max32660evsys.dts b/boards/adi/max32660evsys/max32660evsys.dts new file mode 100644 index 0000000000000..f06645f94a1e8 --- /dev/null +++ b/boards/adi/max32660evsys/max32660evsys.dts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include + +/ { + model = "Analog Devices MAX32660EVSYS"; + compatible = "adi,max32660evsys"; + + chosen { + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + zephyr,sram = &sram2; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + + led1: led_1 { + gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + label = "Red LED"; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led1; + }; + +}; + +&uart1 { + pinctrl-0 = <&uart1_tx_p0_10 &uart1_rx_p0_11>; + pinctrl-names = "default"; + current-speed = <115200>; + data-bits = <8>; + parity = "none"; + status = "okay"; +}; + +&clk_ipo { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; diff --git a/boards/adi/max32660evsys/max32660evsys.yaml b/boards/adi/max32660evsys/max32660evsys.yaml new file mode 100644 index 0000000000000..da963ef091c68 --- /dev/null +++ b/boards/adi/max32660evsys/max32660evsys.yaml @@ -0,0 +1,13 @@ +identifier: max32660evsys +name: max32660evsys +vendor: adi +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - serial +ram: 96 +flash: 256 diff --git a/boards/adi/max32660evsys/max32660evsys_defconfig b/boards/adi/max32660evsys/max32660evsys_defconfig new file mode 100644 index 0000000000000..9428e5334a08f --- /dev/null +++ b/boards/adi/max32660evsys/max32660evsys_defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable GPIO +CONFIG_GPIO=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable UART +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/boards/common/openocd-adi-max32.boards.cmake b/boards/common/openocd-adi-max32.boards.cmake index 3f2c3829cf1ad..2c65ce974e3ff 100644 --- a/boards/common/openocd-adi-max32.boards.cmake +++ b/boards/common/openocd-adi-max32.boards.cmake @@ -10,6 +10,8 @@ if(CONFIG_SOC_MAX32650) set(MAX32_TARGET_CFG "max32650.cfg") elseif(CONFIG_SOC_MAX32655_M4) set(MAX32_TARGET_CFG "max32655.cfg") +elseif(CONFIG_SOC_MAX32660) + set(MAX32_TARGET_CFG "max32660.cfg") elseif(CONFIG_SOC_MAX32662) set(MAX32_TARGET_CFG "max32662.cfg") elseif(CONFIG_SOC_MAX32666) From ff82048124235faeeade96c31713d86a79181a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 23 Jan 2025 12:05:50 +0100 Subject: [PATCH 0223/6055] modules: hal_nordic: nrfs: dvfs: Deprecate Kconfig option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deprecate NRFS_LOCAL_DOMAIN_DVFS_SCALE_DOWN_AFTER_INIT option for scaling down CPU frequency during dvfs handler initialization. Clock control API is managing access to DVFS and DVFS should not be controlled bypassing this API. Deprecated feature will be added in the clock control. Signed-off-by: Krzysztof Chruściński --- drivers/clock_control/Kconfig.nrf | 1 - modules/hal_nordic/nrfs/dvfs/Kconfig | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index b5b066ac48ebf..d27b1ee66600f 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -179,7 +179,6 @@ config CLOCK_CONTROL_NRF2 depends on SOC_SERIES_NRF54HX && !RISCV_CORE_NORDIC_VPR select ONOFF select NRFS if HAS_NRFS - imply NRFS_LOCAL_DOMAIN_DVFS_SCALE_DOWN_AFTER_INIT if NRFS_DVFS_LOCAL_DOMAIN help Support for nRF clock control devices. diff --git a/modules/hal_nordic/nrfs/dvfs/Kconfig b/modules/hal_nordic/nrfs/dvfs/Kconfig index 45a99f8a7ad6d..a1958adea9940 100644 --- a/modules/hal_nordic/nrfs/dvfs/Kconfig +++ b/modules/hal_nordic/nrfs/dvfs/Kconfig @@ -17,6 +17,7 @@ config NRFS_LOCAL_DOMAIN_DVFS_TEST config NRFS_LOCAL_DOMAIN_DVFS_SCALE_DOWN_AFTER_INIT bool "Local domain scale down after init" + select DEPRECATED help Request lowest oppoint after DVFS initialization. From a4625c2112fad038cc4b15ac73fe047f02cd3dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 23 Jan 2025 12:07:28 +0100 Subject: [PATCH 0224/6055] drivers: clock_control: hsfll: Add option to set lowest oppoint in init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add option to set the lowest DVFS operation point during initialization. Option is by default enabled for nrf54h cores with DVFS. Signed-off-by: Krzysztof Chruściński --- drivers/clock_control/Kconfig.nrf | 6 ++++++ drivers/clock_control/clock_control_nrf2_hsfll.c | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index d27b1ee66600f..80cdeb2d1adb1 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -184,6 +184,12 @@ config CLOCK_CONTROL_NRF2 if CLOCK_CONTROL_NRF2 +config CLOCK_CONTROL_NRF2_HSFLL_REQ_LOW_FREQ + bool "Local domain scale down after init" + default y if NRFS_DVFS_LOCAL_DOMAIN + help + Request the lowest operating point after DVFS initialization. + config CLOCK_CONTROL_NRF2_NRFS_DVFS_TIMEOUT_MS int "Timeout waiting for nrfs dvfs service callback in milliseconds" default 2000 diff --git a/drivers/clock_control/clock_control_nrf2_hsfll.c b/drivers/clock_control/clock_control_nrf2_hsfll.c index 12ca616fad334..f67373070f1a4 100644 --- a/drivers/clock_control/clock_control_nrf2_hsfll.c +++ b/drivers/clock_control/clock_control_nrf2_hsfll.c @@ -218,6 +218,21 @@ static DEVICE_API(nrf_clock_control, hsfll_drv_api) = { static struct hsfll_dev_data hsfll_data; #endif +#ifdef CONFIG_CLOCK_CONTROL_NRF2_HSFLL_REQ_LOW_FREQ +static int dvfs_low_init(void) +{ + static const k_timeout_t timeout = K_MSEC(CONFIG_CLOCK_CONTROL_NRF2_NRFS_DVFS_TIMEOUT_MS); + static const struct device *hsfll_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_NODELABEL(cpu))); + static const struct nrf_clock_spec clk_spec = { + .frequency = HSFLL_FREQ_LOW + }; + + return nrf_clock_control_request_sync(hsfll_dev, &clk_spec, timeout); +} + +SYS_INIT(dvfs_low_init, APPLICATION, 0); +#endif + DEVICE_DT_INST_DEFINE(0, hsfll_init, NULL, COND_CODE_1(CONFIG_NRFS_DVFS_LOCAL_DOMAIN, (&hsfll_data), From b9c1ef910aede157e415cc83e6e5d7ba8019afb6 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 30 Jan 2025 14:34:34 +0100 Subject: [PATCH 0225/6055] tests: Bluetooth: BAP: Add deregister of services for unicast server Adds a deinit step that tests the unicast server callbacks, unicast server and pacs unregister. Signed-off-by: Emil Gydesen --- .../audio/src/bap_unicast_server_test.c | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) 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 d2415b6c8070f..980915d21b8c3 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -471,6 +471,29 @@ static void init(void) setup_connectable_adv(&ext_adv); } +static void deinit(void) +{ + int err; + + err = bt_bap_unicast_server_unregister_cb(&unicast_server_cb); + if (err != 0) { + FAIL("Failed to unregister unicast server callbacks (err %d)\n", err); + return; + } + + err = bt_bap_unicast_server_unregister(); + if (err != 0) { + FAIL("Failed to unregister unicast server (err %d)\n", err); + return; + } + + err = bt_pacs_unregister(); + if (err != 0) { + FAIL("Failed to unregister PACS (err %d)\n", err); + return; + } +} + static void test_main(void) { init(); @@ -484,6 +507,8 @@ static void test_main(void) WAIT_FOR_FLAG(flag_stream_started); transceive_test_streams(); WAIT_FOR_UNSET_FLAG(flag_connected); + + deinit(); PASS("Unicast server passed\n"); } @@ -540,6 +565,8 @@ static void test_main_acl_disconnect(void) /* The client will reconnect */ WAIT_FOR_UNSET_FLAG(flag_connected); WAIT_FOR_FLAG(flag_connected); + + deinit(); PASS("Unicast server ACL disconnect passed\n"); } From fe6f63f92d250a7b8f6f42377b919362bbec4565 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 3 Feb 2025 14:21:59 +0100 Subject: [PATCH 0226/6055] Bluetooth: PACS: Add missing break in switch for sup ctx get Add a missing break in supported_context_get, as it was not intended to fallthrough to BT_AUDIO_DIR_SOURCE or default. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/pacs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index d70442ee8a8dd..826c45d63c390 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -296,12 +296,14 @@ static uint16_t supported_context_get(enum bt_audio_dir dir) if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_PAC)) { return snk_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; } + break; #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) case BT_AUDIO_DIR_SOURCE: if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_PAC)) { return src_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; } + break; #endif /* CONFIG_BT_PAC_SRC */ default: break; From c489a0d315aa7d512514cd5eb57950416b414878 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 4 Feb 2025 13:46:33 +0100 Subject: [PATCH 0227/6055] doc: storage: move "Secure Storage" and "Settings" chapters to "Storage" Moves the "Secure Storage" and "Settings" chapters to the Storage folder. Signed-off-by: Andrej Butok --- MAINTAINERS.yml | 4 ++-- doc/_scripts/redirects.py | 4 +++- doc/services/index.rst | 2 -- doc/services/storage/index.rst | 2 ++ .../{secure_storage.rst => storage/secure_storage/index.rst} | 2 +- doc/services/{ => storage}/settings/index.rst | 0 6 files changed, 8 insertions(+), 6 deletions(-) rename doc/services/{secure_storage.rst => storage/secure_storage/index.rst} (99%) rename doc/services/{ => storage}/settings/index.rst (100%) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1eeaacf400761..45088315e969e 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3361,7 +3361,7 @@ Settings: - subsys/settings/ - tests/subsys/settings/ - samples/subsys/settings/ - - doc/services/settings/ + - doc/services/storage/settings/ labels: - "area: Settings" tests: @@ -4343,7 +4343,7 @@ Secure storage: - subsys/secure_storage/ - include/zephyr/psa/ - samples/psa/ - - doc/services/secure_storage.rst + - doc/services/storage/secure_storage/index.rst - tests/subsys/secure_storage/ labels: - "area: Secure storage" diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 87d54e5032eca..14bc2504a4971 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -210,7 +210,7 @@ ('reference/peripherals/uart', 'hardware/peripherals/uart'), ('reference/peripherals/video', 'hardware/peripherals/video'), ('reference/pm/index', 'services/pm/api/index'), - ('reference/settings/index', 'services/settings/index'), + ('reference/settings/index', 'services/storage/settings/index'), ('reference/shell/index', 'services/shell/index'), ('reference/storage/fcb/fcb', 'services/storage/fcb/fcb'), ('reference/storage/index', 'services/storage/index'), @@ -308,5 +308,7 @@ ('samples/subsys/video/video', 'samples/drivers/video/video'), ('services/crypto/tinycrypt', 'services/crypto/psa_crypto'), ('services/portability/posix', 'services/portability/posix/index'), + ('services/secure_storage', 'services/storage/secure_storage/index'), + ('services/settings/index', 'services/storage/settings/index'), # zephyr-keep-sorted-stop ] diff --git a/doc/services/index.rst b/doc/services/index.rst index d1c456151a299..69050cb784fc5 100644 --- a/doc/services/index.rst +++ b/doc/services/index.rst @@ -29,10 +29,8 @@ OS Services portability/index.rst poweroff.rst profiling/index.rst - secure_storage.rst shell/index.rst serialization/index.rst - settings/index.rst smf/index.rst storage/index.rst sensing/index.rst diff --git a/doc/services/storage/index.rst b/doc/services/storage/index.rst index f6e069ecf2ab1..0fe31e8edccb8 100644 --- a/doc/services/storage/index.rst +++ b/doc/services/storage/index.rst @@ -12,3 +12,5 @@ Storage flash_map/flash_map.rst fcb/fcb.rst stream/stream_flash.rst + secure_storage/index.rst + settings/index.rst diff --git a/doc/services/secure_storage.rst b/doc/services/storage/secure_storage/index.rst similarity index 99% rename from doc/services/secure_storage.rst rename to doc/services/storage/secure_storage/index.rst index 5f7b90943b6fd..83eb7aa4dace2 100644 --- a/doc/services/secure_storage.rst +++ b/doc/services/storage/secure_storage/index.rst @@ -1,6 +1,6 @@ .. _secure_storage: -Secure storage +Secure Storage ############## | The secure storage subsystem provides an implementation of the functions defined in the diff --git a/doc/services/settings/index.rst b/doc/services/storage/settings/index.rst similarity index 100% rename from doc/services/settings/index.rst rename to doc/services/storage/settings/index.rst From 583b92d0dac23ad61abf917679c79115b27fa156 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 5 Feb 2025 14:02:46 +0000 Subject: [PATCH 0228/6055] manifest: FAT FS module version upgrade to 0.15a The commit updates manifest entry for FAT FS driver to include update to version 0.15a Signed-off-by: Dominik Ermel --- modules/fatfs/zephyr_fatfs_config.h | 2 +- west.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/fatfs/zephyr_fatfs_config.h b/modules/fatfs/zephyr_fatfs_config.h index eb33f08f44c78..e55cdc3330271 100644 --- a/modules/fatfs/zephyr_fatfs_config.h +++ b/modules/fatfs/zephyr_fatfs_config.h @@ -4,7 +4,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#if FFCONF_DEF != 80286 +#if FFCONF_DEF != 5380 #error "Configuration version mismatch" #endif diff --git a/west.yml b/west.yml index 65d565d2ae589..487468bb44dc0 100644 --- a/west.yml +++ b/west.yml @@ -137,7 +137,7 @@ manifest: groups: - tools - name: fatfs - revision: 427159bf95ea49b7680facffaa29ad506b42709b + revision: 16245c7c41d2b79e74984f49b5202551786b8a9b path: modules/fs/fatfs groups: - fs From 20b1dddce5e4d0170cfbf3a25353cfc3ab68aa53 Mon Sep 17 00:00:00 2001 From: Armin Kessler Date: Wed, 5 Feb 2025 17:16:11 +0100 Subject: [PATCH 0229/6055] scripts: twister: fix flash to esp32 using esp32 runner Twister and pytest now flash to the device specified with board_id. Signed-off-by: Armin Kessler --- .../src/twister_harness/device/hardware_adapter.py | 3 +++ scripts/pylib/twister/twisterlib/handlers.py | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) 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 991b347b7521f..79a3a93564481 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 @@ -73,6 +73,9 @@ def _prepare_runner_args(self) -> tuple[list[str], list[str]]: if runner == 'pyocd': extra_args.append('--board-id') extra_args.append(board_id) + elif runner == "esp32": + extra_args.append("--esp-device") + extra_args.append(board_id) elif runner in ('nrfjprog', 'nrfutil'): extra_args.append('--dev-id') extra_args.append(board_id) diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index 5b3922f9de794..b9e688309328b 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -565,14 +565,13 @@ def _create_command(self, runner, hardware): board_id = hardware.probe_id or hardware.id product = hardware.product - serial_port = hardware.serial if board_id is not None: if runner in ("pyocd", "nrfjprog", "nrfutil"): command_extra_args.append("--dev-id") command_extra_args.append(board_id) elif runner == "esp32": command_extra_args.append("--esp-device") - command_extra_args.append(serial_port) + command_extra_args.append(board_id) elif ( runner == "openocd" and product == "STM32 STLink" From b03bd2ceb5097132563938cae3d2205e692d9262 Mon Sep 17 00:00:00 2001 From: Sven Ginka Date: Fri, 7 Feb 2025 13:29:07 +0100 Subject: [PATCH 0230/6055] MAINTAINERS: Add Sensry Platforms Sensry currently supports 2 boards, based on its own ganymed soc sy1xx (arch RISCV32), in Zephyr. Given the growing interest from our customers and our commitment to expanding support for Sensry platforms, I am volunteering to take over the maintenance of these boards and ganymed family socs. Signed-off-by: Sven Ginka --- MAINTAINERS.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 45088315e969e..3ee64f2333e2b 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4350,6 +4350,17 @@ Secure storage: tests: - psa.secure_storage +Sensry Platforms: + status: maintained + maintainers: + - tswaehn + files: + - boards/sensry/ + files-regex: + - .*sy1xx.* + labels: + - "platform: sensry" + Storage: status: odd fixes files: From b2ec12edc8845e1e6b4739715435db831be868b7 Mon Sep 17 00:00:00 2001 From: Nabil Elqatib Date: Sun, 9 Feb 2025 13:50:28 +0100 Subject: [PATCH 0231/6055] drivers: sensor: bosch: bmg160: replace deprecated datasheet link Use an internetarchive link instead Signed-off-by: Nabil Elqatib --- drivers/sensor/bosch/bmg160/bmg160.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/bosch/bmg160/bmg160.c b/drivers/sensor/bosch/bmg160/bmg160.c index da16a6080bdd3..463c3630f61a6 100644 --- a/drivers/sensor/bosch/bmg160/bmg160.c +++ b/drivers/sensor/bosch/bmg160/bmg160.c @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 * * Datasheet: - * http://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMG160-DS000-09.pdf + * https://web.archive.org/web/20181111220522/https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMG160-DS000-09.pdf */ #define DT_DRV_COMPAT bosch_bmg160 From 7b8a5ed6554ac799aa5615bff865be38c3d4b752 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sun, 9 Feb 2025 11:54:15 -0500 Subject: [PATCH 0232/6055] twister: platforms: fix parsing testing metadata Fix parsing of testing metadata, global defaults were being ignore in some cases. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/platform.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/platform.py b/scripts/pylib/twister/twisterlib/platform.py index 3be5ba5cc28f6..7b37941a36fcc 100644 --- a/scripts/pylib/twister/twisterlib/platform.py +++ b/scripts/pylib/twister/twisterlib/platform.py @@ -70,6 +70,7 @@ def __init__(self): # if no flash size is specified by the board, take a default of 512K self.flash = 512 self.supported = set() + self.binaries = [] self.arch = None self.vendor = "" @@ -114,15 +115,24 @@ def load(self, board, target, aliases, data): # if no flash size is specified by the board, take a default of 512K self.flash = variant_data.get("flash", data.get("flash", self.flash)) - testing = variant_data.get("testing", data.get("testing", {})) - self.timeout_multiplier = testing.get("timeout_multiplier", self.timeout_multiplier) - self.ignore_tags = testing.get("ignore_tags", self.ignore_tags) - self.only_tags = testing.get("only_tags", self.only_tags) + testing = data.get("testing", {}) + self.ignore_tags = testing.get("ignore_tags", []) + self.only_tags = testing.get("only_tags", []) self.default = testing.get("default", self.default) self.binaries = testing.get("binaries", []) + self.timeout_multiplier = testing.get("timeout_multiplier", self.timeout_multiplier) + + # testing data for variant + testing_var = variant_data.get("testing", data.get("testing", {})) + self.timeout_multiplier = testing_var.get("timeout_multiplier", self.timeout_multiplier) + self.ignore_tags = testing_var.get("ignore_tags", self.ignore_tags) + self.only_tags = testing_var.get("only_tags", self.only_tags) + self.default = testing_var.get("default", self.default) + self.binaries = testing_var.get("binaries", self.binaries) renode = testing.get("renode", {}) self.uart = renode.get("uart", "") self.resc = renode.get("resc", "") + self.supported = set() for supp_feature in variant_data.get("supported", data.get("supported", [])): for item in supp_feature.split(":"): From e36d702acdc9a1feadb2755a65aa575f61e884d3 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Fri, 10 Jan 2025 10:48:37 -0300 Subject: [PATCH 0233/6055] soc: espressif: move code start prior hw init Make sure vector table and BSS clean up is performed pior hardware initialization. Signed-off-by: Sylvio Alves --- drivers/flash/flash_esp32.c | 80 +++++++++++++++---- soc/espressif/common/loader.c | 68 ++++++++++++----- soc/espressif/esp32/esp32-mp.c | 6 ++ soc/espressif/esp32/hw_init.c | 9 +-- soc/espressif/esp32/soc.c | 106 +++++--------------------- soc/espressif/esp32/soc.h | 3 +- soc/espressif/esp32c2/default.ld | 3 +- soc/espressif/esp32c2/hw_init.c | 10 +-- soc/espressif/esp32c2/soc.c | 76 ++++--------------- soc/espressif/esp32c2/soc.h | 3 +- soc/espressif/esp32c2/vectors.S | 6 +- soc/espressif/esp32c3/hw_init.c | 9 +-- soc/espressif/esp32c3/memory.h | 2 +- soc/espressif/esp32c3/soc.c | 75 ++++-------------- soc/espressif/esp32c3/soc.h | 3 +- soc/espressif/esp32c3/vectors.S | 6 +- soc/espressif/esp32c6/hw_init.c | 7 -- soc/espressif/esp32c6/soc.c | 70 +++++------------ soc/espressif/esp32c6/soc.h | 3 +- soc/espressif/esp32c6/vectors.S | 6 +- soc/espressif/esp32s2/hw_init.c | 8 +- soc/espressif/esp32s2/soc.c | 103 ++++++------------------- soc/espressif/esp32s2/soc.h | 3 +- soc/espressif/esp32s3/esp32s3-mp.c | 6 ++ soc/espressif/esp32s3/hw_init.c | 9 +-- soc/espressif/esp32s3/soc.c | 118 +++++------------------------ soc/espressif/esp32s3/soc.h | 3 +- west.yml | 2 +- 28 files changed, 268 insertions(+), 535 deletions(-) diff --git a/drivers/flash/flash_esp32.c b/drivers/flash/flash_esp32.c index 6d947064e9d8a..4baf94bcff62e 100644 --- a/drivers/flash/flash_esp32.c +++ b/drivers/flash/flash_esp32.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -69,21 +70,49 @@ static inline void flash_esp32_sem_give(const struct device *dev) #endif /* CONFIG_MULTITHREADING */ +#include +#include +#include +#include +#include + static int flash_esp32_read(const struct device *dev, off_t address, void *buffer, size_t length) { int ret = 0; - flash_esp32_sem_take(dev); +#ifdef CONFIG_MCUBOOT + /* ensure everything is 4-byte aligned */ + size_t aligned_length = ROUND_UP(length, 4); + off_t aligned_address = ROUND_DOWN(address, 4); + size_t address_offset = address - aligned_address; + uint32_t temp_buf[aligned_length / 4]; + if (!esp_flash_encryption_enabled()) { - ret = esp_flash_read(NULL, buffer, address, length); + ret = esp_rom_flash_read(aligned_address, temp_buf, aligned_length, false); } else { + ret = esp_rom_flash_read(aligned_address, temp_buf, aligned_length, true); + } + + memcpy((void *)buffer, ((uint8_t *)temp_buf) + address_offset, length); +#else + + flash_esp32_sem_take(dev); + + if (esp_flash_encryption_enabled()) { ret = esp_flash_read_encrypted(NULL, address, buffer, length); + } else { + ret = esp_flash_read(NULL, buffer, address, length); } + flash_esp32_sem_give(dev); + +#endif + if (ret != 0) { - LOG_ERR("esp_flash_read failed %d", ret); + LOG_ERR("Flash read error: %d", ret); return -EIO; } + return 0; } @@ -94,28 +123,55 @@ static int flash_esp32_write(const struct device *dev, { int ret = 0; - flash_esp32_sem_take(dev); +#ifdef CONFIG_MCUBOOT + /* ensure everything is 4-byte aligned */ + size_t aligned_length = ROUND_UP(length, 4); + off_t aligned_address = ROUND_DOWN(address, 4); + size_t address_offset = address - aligned_address; + uint32_t temp_buf[aligned_length / 4]; + if (!esp_flash_encryption_enabled()) { - ret = esp_flash_write(NULL, buffer, address, length); + ret = esp_rom_flash_write(aligned_address, temp_buf, aligned_length, false); } else { + ret = esp_rom_flash_write(aligned_address, temp_buf, aligned_length, true); + } + + memcpy((void *)buffer, ((uint8_t *)temp_buf) + address_offset, length); +#else + + flash_esp32_sem_take(dev); + + if (esp_flash_encryption_enabled()) { ret = esp_flash_write_encrypted(NULL, address, buffer, length); + } else { + ret = esp_flash_write(NULL, buffer, address, length); } + flash_esp32_sem_give(dev); +#endif + if (ret != 0) { - LOG_ERR("esp_flash_write failed %d", ret); + LOG_ERR("Flash write error: %d", ret); return -EIO; } + return 0; } static int flash_esp32_erase(const struct device *dev, off_t start, size_t len) { + int ret = 0; + +#ifdef CONFIG_MCUBOOT + ret = esp_rom_flash_erase_range(start, len); +#else flash_esp32_sem_take(dev); - int ret = esp_flash_erase_region(NULL, start, len); + ret = esp_flash_erase_region(NULL, start, len); flash_esp32_sem_give(dev); +#endif if (ret != 0) { - LOG_ERR("esp_flash_erase_region failed %d", ret); + LOG_ERR("Flash erase error: %d", ret); return -EIO; } return 0; @@ -146,18 +202,12 @@ flash_esp32_get_parameters(const struct device *dev) static int flash_esp32_init(const struct device *dev) { - uint32_t ret = 0; - #ifdef CONFIG_MULTITHREADING struct flash_esp32_dev_data *const dev_data = dev->data; k_sem_init(&dev_data->sem, 1, 1); #endif /* CONFIG_MULTITHREADING */ - ret = esp_flash_init_default_chip(); - if (ret != 0) { - LOG_ERR("esp_flash_init_default_chip failed %d", ret); - return 0; - } + return 0; } diff --git a/soc/espressif/common/loader.c b/soc/espressif/common/loader.c index 89f6e5d98e070..b3cea05329041 100644 --- a/soc/espressif/common/loader.c +++ b/soc/espressif/common/loader.c @@ -21,9 +21,11 @@ #include #include #include - #include +#include +#include + #if CONFIG_SOC_SERIES_ESP32C6 #include #include @@ -99,13 +101,6 @@ static struct rom_segments map = { .drom_size = (uint32_t)&_image_drom_size, }; -#ifndef CONFIG_BOOTLOADER_MCUBOOT -static int spi_flash_read(uint32_t address, void *buffer, size_t length) -{ - return esp_flash_read(NULL, buffer, address, length); -} -#endif /* CONFIG_BOOTLOADER_MCUBOOT */ - void map_rom_segments(int core, struct rom_segments *map) { uint32_t app_irom_vaddr_align = map->irom_map_addr & MMU_FLASH_MASK; @@ -126,7 +121,8 @@ void map_rom_segments(int core, struct rom_segments *map) while (segments++ < 16) { - if (spi_flash_read(offset, &segment_hdr, sizeof(esp_image_segment_header_t)) != 0) { + if (esp_rom_flash_read(offset, &segment_hdr, + sizeof(esp_image_segment_header_t), true) != 0) { ESP_EARLY_LOGE(TAG, "Failed to read segment header at %x", offset); abort(); } @@ -255,6 +251,13 @@ void map_rom_segments(int core, struct rom_segments *map) void __start(void) { #ifdef CONFIG_RISCV_GP + + __asm__ __volatile__("la t0, _esp_vector_table\n" + "csrw mtvec, t0\n"); + + /* Disable normal interrupts. */ + csr_read_clear(mstatus, MSTATUS_MIE); + /* Configure the global pointer register * (This should be the first thing startup does, as any other piece of code could be * relaxed by the linker to access something relative to __global_pointer$) @@ -263,17 +266,40 @@ void __start(void) ".option norelax\n" "la gp, __global_pointer$\n" ".option pop"); -#endif -#ifndef CONFIG_BOOTLOADER_MCUBOOT - /* Init fundamental components */ + z_bss_zero(); + +#else /* xtensa */ + + extern uint32_t _init_start; + + /* Move the exception vector table to IRAM. */ + __asm__ __volatile__("wsr %0, vecbase" : : "r"(&_init_start)); + + z_bss_zero(); + + __asm__ __volatile__("" : : "g"(&__bss_start) : "memory"); + + /* Disable normal interrupts. */ + __asm__ __volatile__("wsr %0, PS" : : "r"(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE)); + + /* Initialize the architecture CPU pointer. Some of the + * initialization code wants a valid arch_current_thread() before + * arch_kernel_init() is invoked. + */ + __asm__ __volatile__("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); + +#endif /* CONFIG_RISCV_GP */ + +/* Initialize hardware only during 1st boot */ +#if defined(CONFIG_MCUBOOT) || defined(CONFIG_ESP_SIMPLE_BOOT) if (hardware_init()) { ESP_EARLY_LOGE(TAG, "HW init failed, aborting"); abort(); } #endif -#if !defined(CONFIG_MCUBOOT) +#if defined(CONFIG_ESP_SIMPLE_BOOT) || defined(CONFIG_BOOTLOADER_MCUBOOT) map_rom_segments(0, &map); /* Show map segments continue using same log format as during MCUboot phase */ @@ -282,19 +308,19 @@ void __start(void) ESP_EARLY_LOGI(TAG, "%s segment: paddr=%08xh, vaddr=%08xh, size=%05Xh (%6d) map", "DROM", map.drom_flash_offset, map.drom_map_addr, map.drom_size, map.drom_size); esp_rom_uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); -#endif -#ifndef CONFIG_SOC_SERIES_ESP32C2 /* Disable RNG entropy source as it was already used */ soc_random_disable(); -#endif -#if defined(CONFIG_SOC_SERIES_ESP32S3) || defined(CONFIG_SOC_SERIES_ESP32C3) + /* Disable glitch detection as it can be falsely triggered by EMI interference */ - ESP_EARLY_LOGI(TAG, "Disabling glitch detection"); ana_clock_glitch_reset_config(false); -#endif -#ifndef CONFIG_MCUBOOT + ESP_EARLY_LOGI(TAG, "libc heap size %d kB.", libc_heap_size / 1024); + + __esp_platform_app_start(); +#endif /* CONFIG_ESP_SIMPLE_BOOT || CONFIG_BOOTLOADER_MCUBOOT */ + +#if defined(CONFIG_MCUBOOT) + __esp_platform_mcuboot_start(); #endif - __esp_platform_start(); } diff --git a/soc/espressif/esp32/esp32-mp.c b/soc/espressif/esp32/esp32-mp.c index 8733e33340c9b..55bc5fd028e4f 100644 --- a/soc/espressif/esp32/esp32-mp.c +++ b/soc/espressif/esp32/esp32-mp.c @@ -453,4 +453,10 @@ int esp_appcpu_init(void) return 0; } + +#if !defined(CONFIG_MCUBOOT) +extern int esp_appcpu_init(void); +SYS_INIT(esp_appcpu_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif + #endif /* CONFIG_SOC_ENABLE_APPCPU */ diff --git a/soc/espressif/esp32/hw_init.c b/soc/espressif/esp32/hw_init.c index db28e5e76cb5f..0282f1706421d 100644 --- a/soc/espressif/esp32/hw_init.c +++ b/soc/espressif/esp32/hw_init.c @@ -57,14 +57,8 @@ int hardware_init(void) print_banner(); #endif /* CONFIG_ESP_CONSOLE */ - spi_flash_init_chip_state(); - err = esp_flash_init_default_chip(); - if (err != 0) { - ESP_EARLY_LOGE(TAG, "Failed to init flash chip, error %d", err); - return err; - } - reset_mmu(); + flash_update_id(); err = bootloader_flash_xmc_startup(); @@ -90,6 +84,7 @@ int hardware_init(void) check_wdt_reset(); config_wdt(); + soc_random_enable(); return 0; diff --git a/soc/espressif/esp32/soc.c b/soc/espressif/esp32/soc.c index ec1fc8c8babeb..e0f307a2d8ec6 100644 --- a/soc/espressif/esp32/soc.c +++ b/soc/espressif/esp32/soc.c @@ -1,109 +1,36 @@ /* * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2025 Espressif Systems (Shanghai) CO LTD. * * SPDX-License-Identifier: Apache-2.0 */ -/* Include esp-idf headers first to avoid redefining BIT() macro */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#if CONFIG_ESP_SPIRAM -#include "psram.h" -#endif - -#include -#include -#include -#include -#include -#include - +#include +#include +#include #include -#include -#include -#include -#include -#include -#include #include -#include -#include - -#ifndef CONFIG_SOC_ENABLE_APPCPU -#include "esp_clk_internal.h" -#endif /* CONFIG_SOC_ENABLE_APPCPU */ - +#include +#include #include -#include "esp_log.h" - -#define TAG "boot.esp32" extern void z_prep_c(void); extern void esp_reset_reason_init(void); -extern int esp_appcpu_init(void); -/* - * This is written in C rather than assembly since, during the port bring up, - * Zephyr is being booted by the Espressif bootloader. With it, the C stack - * is already set up. - */ -void IRAM_ATTR __esp_platform_start(void) +void IRAM_ATTR __esp_platform_app_start(void) { - extern uint32_t _init_start; - - /* Move the exception vector table to IRAM. */ - __asm__ __volatile__ ("wsr %0, vecbase" : : "r"(&_init_start)); - - z_bss_zero(); - - __asm__ __volatile__ ("" : : "g"(&__bss_start) : "memory"); - - /* Disable normal interrupts. */ - __asm__ __volatile__ ("wsr %0, PS" : : "r"(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE)); - - /* Initialize the architecture CPU pointer. Some of the - * initialization code wants a valid _current before - * z_prep_c() is invoked. - */ - __asm__ __volatile__("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); - esp_reset_reason_init(); -#ifndef CONFIG_MCUBOOT - /* ESP-IDF/MCUboot 2nd stage bootloader enables RTC WDT to check - * on startup sequence related issues in application. Hence disable that - * as we are about to start Zephyr environment. - */ - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); - esp_timer_early_init(); - esp_mspi_pin_init(); - - esp_flash_app_init(); + esp_flash_config(); - esp_mmu_map_init(); + esp_intr_initialize(); #if CONFIG_ESP_SPIRAM esp_init_psram(); -#endif /* CONFIG_ESP_SPIRAM */ -#endif /* !CONFIG_MCUBOOT */ - - esp_intr_initialize(); - -#if CONFIG_ESP_SPIRAM /* Init Shared Multi Heap for PSRAM */ int err = esp_psram_smh_init(); @@ -118,6 +45,16 @@ void IRAM_ATTR __esp_platform_start(void) CODE_UNREACHABLE; } +void IRAM_ATTR __esp_platform_mcuboot_start(void) +{ + esp_intr_initialize(); + + /* Start Zephyr */ + z_prep_c(); + + CODE_UNREACHABLE; +} + /* Boot-time static default printk handler, possibly to be overridden later. */ int IRAM_ATTR arch_printk_char_out(int c) { @@ -132,8 +69,3 @@ void sys_arch_reboot(int type) { esp_restart_noos(); } - -#if defined(CONFIG_SOC_ENABLE_APPCPU) && !defined(CONFIG_MCUBOOT) -extern int esp_appcpu_init(void); -SYS_INIT(esp_appcpu_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); -#endif diff --git a/soc/espressif/esp32/soc.h b/soc/espressif/esp32/soc.h index e2ea8cc50b7e6..6958a25fbd0d3 100644 --- a/soc/espressif/esp32/soc.h +++ b/soc/espressif/esp32/soc.h @@ -20,7 +20,8 @@ #include #include -void __esp_platform_start(void); +void __esp_platform_mcuboot_start(void); +void __esp_platform_app_start(void); static inline void esp32_set_mask32(uint32_t v, uint32_t mem_addr) { diff --git a/soc/espressif/esp32c2/default.ld b/soc/espressif/esp32c2/default.ld index bd72f1ea805d2..0c866ba9332d7 100644 --- a/soc/espressif/esp32c2/default.ld +++ b/soc/espressif/esp32c2/default.ld @@ -212,6 +212,7 @@ SECTIONS *libzephyr.a:console_init.*(.literal .text .literal.* .text.*) *libzephyr.a:soc_init.*(.literal .text .literal.* .text.*) *libzephyr.a:hw_init.*(.literal .text .literal.* .text.*) + *libzephyr.a:soc_random.*(.literal .text .literal.* .text.*) *libarch__riscv__core.a:(.literal .text .literal.* .text.*) *libsubsys__net__l2__ethernet.a:(.literal .text .literal.* .text.*) *libsubsys__net__lib__config.a:(.literal .text .literal.* .text.*) @@ -357,7 +358,6 @@ SECTIONS *libzephyr.a:esp_image_format.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_ops.*(.literal .text .literal.* .text.*) - *libzephyr.a:flash_ops_esp32c2.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_encrypt.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_partitions.*(.literal .text .literal.* .text.*) @@ -463,6 +463,7 @@ SECTIONS *libzephyr.a:console_init.*(.rodata .rodata.*) *libzephyr.a:soc_init.*(.rodata .rodata.*) *libzephyr.a:hw_init.*(.rodata .rodata.*) + *libzephyr.a:soc_random.*(.rodata .rodata.*) *libzephyr.a:cache_utils.*(.rodata .rodata.* .srodata .srodata.*) /* [mapping:hal] */ diff --git a/soc/espressif/esp32c2/hw_init.c b/soc/espressif/esp32c2/hw_init.c index 25c4a3b3f99ec..8222490705a06 100644 --- a/soc/espressif/esp32c2/hw_init.c +++ b/soc/espressif/esp32c2/hw_init.c @@ -57,15 +57,9 @@ int hardware_init(void) print_banner(); #endif /* CONFIG_ESP_CONSOLE */ - spi_flash_init_chip_state(); - err = esp_flash_init_default_chip(); - if (err != 0) { - ESP_EARLY_LOGE(TAG, "Failed to init flash chip, error %d", err); - return err; - } - cache_hal_init(); mmu_hal_init(); + flash_update_id(); err = bootloader_flash_xmc_startup(); @@ -92,5 +86,7 @@ int hardware_init(void) check_wdt_reset(); config_wdt(); + soc_random_enable(); + return 0; } diff --git a/soc/espressif/esp32c2/soc.c b/soc/espressif/esp32c2/soc.c index 9ed4bbcb4370f..f131f5fbfee07 100644 --- a/soc/espressif/esp32c2/soc.c +++ b/soc/espressif/esp32c2/soc.c @@ -1,83 +1,39 @@ /* - * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2024-2025 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ -/* Include esp-idf headers first to avoid redefining BIT() macro */ -#include -#include -#include -#include -#include -#include -#include "hal/wdt_hal.h" -#include "esp_cpu.h" -#include "hal/soc_hal.h" -#include "hal/cpu_hal.h" -#include "esp_timer.h" -#include "esp_private/system_internal.h" -#include "esp_clk_internal.h" -#include -#include -#include "esp_private/esp_mmu_map_private.h" -#include - +#include +#include +#include +#include +#include +#include #include - #include #include -#include -#include -#include extern void esp_reset_reason_init(void); -/* - * This is written in C rather than assembly since, during the port bring up, - * Zephyr is being booted by the Espressif bootloader. With it, the C stack - * is already set up. - */ -void __attribute__((section(".iram1"))) __esp_platform_start(void) +void IRAM_ATTR __esp_platform_app_start(void) { - __asm__ __volatile__("la t0, _esp32c2_vector_table\n" - "csrw mtvec, t0\n"); - - z_bss_zero(); - - /* Disable normal interrupts. */ - csr_read_clear(mstatus, MSTATUS_MIE); - esp_reset_reason_init(); -#ifndef CONFIG_MCUBOOT - /* ESP-IDF 2nd stage bootloader enables RTC WDT to check on startup sequence - * related issues in application. Hence disable that as we are about to start - * Zephyr environment. - */ - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); - - /* Enable wireless phy subsystem clock, - * This needs to be done before the kernel starts - */ - REG_CLR_BIT(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_SDIOSLAVE_EN); - SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_EN); - esp_timer_early_init(); - esp_mspi_pin_init(); + esp_flash_config(); - esp_flash_app_init(); + esp_intr_initialize(); - esp_mmu_map_init(); + /* Start Zephyr */ + z_cstart(); -#endif /* !CONFIG_MCUBOOT */ + CODE_UNREACHABLE; +} - /*Initialize the esp32c2 interrupt controller */ +void IRAM_ATTR __esp_platform_mcuboot_start(void) +{ esp_intr_initialize(); /* Start Zephyr */ diff --git a/soc/espressif/esp32c2/soc.h b/soc/espressif/esp32c2/soc.h index da96d9faf83ac..66a098444b2da 100644 --- a/soc/espressif/esp32c2/soc.h +++ b/soc/espressif/esp32c2/soc.h @@ -18,7 +18,8 @@ #ifndef _ASMLANGUAGE -void __esp_platform_start(void); +void __esp_platform_mcuboot_start(void); +void __esp_platform_app_start(void); static inline uint32_t esp_core_id(void) { diff --git a/soc/espressif/esp32c2/vectors.S b/soc/espressif/esp32c2/vectors.S index e8f8f0213bed2..9299750a525db 100644 --- a/soc/espressif/esp32c2/vectors.S +++ b/soc/espressif/esp32c2/vectors.S @@ -22,12 +22,12 @@ GTEXT(_isr_wrapper) * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00). */ - .global _esp32c2_vector_table + .global _esp_vector_table .section .exception_vectors.text .balign 0x100 - .type _esp32c2_vector_table, @function + .type _esp_vector_table, @function -_esp32c2_vector_table: +_esp_vector_table: .option push .option norvc .rept (32) diff --git a/soc/espressif/esp32c3/hw_init.c b/soc/espressif/esp32c3/hw_init.c index 416996ae48787..5399f6ed906a6 100644 --- a/soc/espressif/esp32c3/hw_init.c +++ b/soc/espressif/esp32c3/hw_init.c @@ -59,16 +59,9 @@ int hardware_init(void) print_banner(); #endif /* CONFIG_ESP_CONSOLE */ - - spi_flash_init_chip_state(); - err = esp_flash_init_default_chip(); - if (err != 0) { - ESP_EARLY_LOGE(TAG, "Failed to init flash chip, error %d", err); - return err; - } - cache_hal_init(); mmu_hal_init(); + flash_update_id(); err = bootloader_flash_xmc_startup(); diff --git a/soc/espressif/esp32c3/memory.h b/soc/espressif/esp32c3/memory.h index 87a832169fc79..07eab679ad301 100644 --- a/soc/espressif/esp32c3/memory.h +++ b/soc/espressif/esp32c3/memory.h @@ -47,7 +47,7 @@ #define BOOTLOADER_STACK_OVERHEAD 0x0 /* These lengths can be adjusted, if necessary: */ #define BOOTLOADER_DRAM_SEG_LEN 0x9800 -#define BOOTLOADER_IRAM_SEG_LEN 0x9800 +#define BOOTLOADER_IRAM_SEG_LEN 0x9C00 #define BOOTLOADER_IRAM_LOADER_SEG_LEN 0x1400 /* Start of the lower region is determined by region size and the end of the higher region */ diff --git a/soc/espressif/esp32c3/soc.c b/soc/espressif/esp32c3/soc.c index aa21357e72876..7541530eec02e 100644 --- a/soc/espressif/esp32c3/soc.c +++ b/soc/espressif/esp32c3/soc.c @@ -1,83 +1,40 @@ /* * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2025 Espressif Systems (Shanghai) CO LTD. * * SPDX-License-Identifier: Apache-2.0 */ -/* Include esp-idf headers first to avoid redefining BIT() macro */ -#include -#include -#include -#include -#include -#include -#include "hal/wdt_hal.h" -#include "esp_cpu.h" -#include "hal/soc_hal.h" -#include "hal/cpu_hal.h" -#include "esp_timer.h" -#include "esp_private/system_internal.h" -#include "esp_clk_internal.h" -#include -#include -#include "esp_private/esp_mmu_map_private.h" -#include - +#include +#include +#include +#include +#include +#include #include - #include #include -#include -#include -#include extern void esp_reset_reason_init(void); -/* - * This is written in C rather than assembly since, during the port bring up, - * Zephyr is being booted by the Espressif bootloader. With it, the C stack - * is already set up. - */ -void __attribute__((section(".iram1"))) __esp_platform_start(void) +void IRAM_ATTR __esp_platform_app_start(void) { - __asm__ __volatile__("la t0, _esp32c3_vector_table\n" - "csrw mtvec, t0\n"); - - z_bss_zero(); - - /* Disable normal interrupts. */ - csr_read_clear(mstatus, MSTATUS_MIE); - esp_reset_reason_init(); -#ifndef CONFIG_MCUBOOT - /* ESP-IDF 2nd stage bootloader enables RTC WDT to check on startup sequence - * related issues in application. Hence disable that as we are about to start - * Zephyr environment. - */ - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); - - /* Enable wireless phy subsystem clock, - * This needs to be done before the kernel starts - */ - REG_CLR_BIT(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_SDIOSLAVE_EN); - SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_EN); - esp_timer_early_init(); - esp_mspi_pin_init(); + esp_flash_config(); - esp_flash_app_init(); + esp_intr_initialize(); - esp_mmu_map_init(); + /* Start Zephyr */ + z_cstart(); -#endif /* !CONFIG_MCUBOOT */ + CODE_UNREACHABLE; +} - /*Initialize the esp32c3 interrupt controller */ +void IRAM_ATTR __esp_platform_mcuboot_start(void) +{ esp_intr_initialize(); /* Start Zephyr */ diff --git a/soc/espressif/esp32c3/soc.h b/soc/espressif/esp32c3/soc.h index 73e2fbfee1ead..192d0aaf6fc97 100644 --- a/soc/espressif/esp32c3/soc.h +++ b/soc/espressif/esp32c3/soc.h @@ -18,7 +18,8 @@ #ifndef _ASMLANGUAGE -void __esp_platform_start(void); +void __esp_platform_mcuboot_start(void); +void __esp_platform_app_start(void); static inline uint32_t esp_core_id(void) { diff --git a/soc/espressif/esp32c3/vectors.S b/soc/espressif/esp32c3/vectors.S index 570740469eb11..629ce21ff0d82 100644 --- a/soc/espressif/esp32c3/vectors.S +++ b/soc/espressif/esp32c3/vectors.S @@ -22,12 +22,12 @@ GTEXT(_isr_wrapper) * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00). */ - .global _esp32c3_vector_table + .global _esp_vector_table .section .exception_vectors.text .balign 0x100 - .type _esp32c3_vector_table, @function + .type _esp_vector_table, @function -_esp32c3_vector_table: +_esp_vector_table: .option push .option norvc .rept (32) diff --git a/soc/espressif/esp32c6/hw_init.c b/soc/espressif/esp32c6/hw_init.c index 83838e0778703..4d81ccc30c2d0 100644 --- a/soc/espressif/esp32c6/hw_init.c +++ b/soc/espressif/esp32c6/hw_init.c @@ -75,13 +75,6 @@ int hardware_init(void) print_banner(); #endif /* CONFIG_ESP_CONSOLE */ - spi_flash_init_chip_state(); - err = esp_flash_init_default_chip(); - if (err != 0) { - ESP_EARLY_LOGE(TAG, "Failed to init flash chip, error %d", err); - return err; - } - cache_hal_init(); mmu_hal_init(); diff --git a/soc/espressif/esp32c6/soc.c b/soc/espressif/esp32c6/soc.c index 1c8877d85416a..8fdd8b71e5fd5 100644 --- a/soc/espressif/esp32c6/soc.c +++ b/soc/espressif/esp32c6/soc.c @@ -1,73 +1,39 @@ /* - * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023-2025 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ -/* Include esp-idf headers first to avoid redefining BIT() macro */ -#include -#include -#include -#include -#include "hal/wdt_hal.h" -#include "esp_cpu.h" -#include "hal/soc_hal.h" -#include "hal/cpu_hal.h" -#include "esp_timer.h" -#include "esp_private/system_internal.h" -#include "esp_clk_internal.h" -#include -#include -#include "esp_private/esp_mmu_map_private.h" -#include - +#include +#include +#include +#include +#include +#include #include - #include #include -#include -#include -#include - -/* - * This is written in C rather than assembly since, during the port bring up, - * Zephyr is being booted by the Espressif bootloader. With it, the C stack - * is already set up. - */ -void IRAM_ATTR __esp_platform_start(void) -{ - __asm__ __volatile__("la t0, _esp32c6_vector_table\n" - "csrw mtvec, t0\n"); - - z_bss_zero(); - /* Disable normal interrupts. */ - csr_read_clear(mstatus, MSTATUS_MIE); +extern void esp_reset_reason_init(void); +void IRAM_ATTR __esp_platform_app_start(void) +{ esp_reset_reason_init(); -#ifndef CONFIG_MCUBOOT - /* ESP-IDF 2nd stage bootloader enables RTC WDT to check on startup sequence - * related issues in application. Hence disable that as we are about to start - * Zephyr environment. - */ - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &LP_WDT}; - - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); - esp_timer_early_init(); - esp_mspi_pin_init(); + esp_flash_config(); - esp_flash_app_init(); + esp_intr_initialize(); - esp_mmu_map_init(); + /* Start Zephyr */ + z_cstart(); -#endif /* !CONFIG_MCUBOOT */ + CODE_UNREACHABLE; +} - /*Initialize the esp32c6 interrupt controller */ +void IRAM_ATTR __esp_platform_mcuboot_start(void) +{ esp_intr_initialize(); /* Start Zephyr */ diff --git a/soc/espressif/esp32c6/soc.h b/soc/espressif/esp32c6/soc.h index bfa5644977751..4cbae49783564 100644 --- a/soc/espressif/esp32c6/soc.h +++ b/soc/espressif/esp32c6/soc.h @@ -27,7 +27,8 @@ #ifndef _ASMLANGUAGE -void __esp_platform_start(void); +void __esp_platform_mcuboot_start(void); +void __esp_platform_app_start(void); static inline uint32_t esp_core_id(void) { diff --git a/soc/espressif/esp32c6/vectors.S b/soc/espressif/esp32c6/vectors.S index d248c0b49b51c..3ad3ae6d79095 100644 --- a/soc/espressif/esp32c6/vectors.S +++ b/soc/espressif/esp32c6/vectors.S @@ -22,12 +22,12 @@ GTEXT(_isr_wrapper) * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00). */ - .global _esp32c6_vector_table + .global _esp_vector_table .section .exception_vectors.text .balign 0x100 - .type _esp32c6_vector_table, @function + .type _esp_vector_table, @function -_esp32c6_vector_table: +_esp_vector_table: .option push .option norvc .rept (32) diff --git a/soc/espressif/esp32s2/hw_init.c b/soc/espressif/esp32s2/hw_init.c index b9d1144f8bcc8..e144f8becf79a 100644 --- a/soc/espressif/esp32s2/hw_init.c +++ b/soc/espressif/esp32s2/hw_init.c @@ -57,14 +57,8 @@ int hardware_init(void) print_banner(); #endif /* CONFIG_ESP_CONSOLE */ - spi_flash_init_chip_state(); - err = esp_flash_init_default_chip(); - if (err != 0) { - ESP_EARLY_LOGE(TAG, "Failed to init flash chip, error %d", err); - return err; - } - cache_hal_init(); + mmu_hal_init(); /* Workaround: normal ROM bootloader exits with DROM0 cache unmasked, but 2nd bootloader diff --git a/soc/espressif/esp32s2/soc.c b/soc/espressif/esp32s2/soc.c index 02a6d1b4dc6fb..286bbe2469a67 100644 --- a/soc/espressif/esp32s2/soc.c +++ b/soc/espressif/esp32s2/soc.c @@ -1,85 +1,24 @@ /* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2021-2025 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ -/* Include esp-idf headers first to avoid redefining BIT() macro */ -#include "soc.h" -#include -#include -#include -#include -#include -#include -#include -#include -#if CONFIG_ESP_SPIRAM -#include "psram.h" -#endif - -#include -#include -#include -#include -#include - +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include #include -#include -#include +#include +#include #include -#include "esp_log.h" - -#define TAG "boot.esp32s2" -extern void rtc_clk_cpu_freq_set_xtal(void); -extern void esp_reset_reason_init(void); extern void z_prep_c(void); +extern void esp_reset_reason_init(void); -/* - * This is written in C rather than assembly since, during the port bring up, - * Zephyr is being booted by the Espressif bootloader. With it, the C stack - * is already set up. - */ -void __attribute__((section(".iram1"))) __esp_platform_start(void) +void IRAM_ATTR __esp_platform_app_start(void) { - extern uint32_t _init_start; - - /* Move the exception vector table to IRAM. */ - __asm__ __volatile__("wsr %0, vecbase" : : "r"(&_init_start)); - - /* Zero out BSS */ - z_bss_zero(); - - /* Disable normal interrupts. */ - __asm__ __volatile__("wsr %0, PS" : : "r"(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE)); - - /* Initialize the architecture CPU pointer. Some of the - * initialization code wants a valid _current before - * arch_kernel_init() is invoked. - */ - __asm__ __volatile__("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); - - esp_reset_reason_init(); - -#ifndef CONFIG_MCUBOOT - /* ESP-IDF 2nd stage bootloader enables RTC WDT to check on startup sequence - * related issues in application. Hence disable that as we are about to start - * Zephyr environment. - */ - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); - /* * Configure the mode of instruction cache : * cache size, cache associated ways, cache line size. @@ -96,23 +35,17 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) esp_config_data_cache_mode(); esp_rom_Cache_Enable_DCache(0); - esp_timer_early_init(); + esp_reset_reason_init(); - esp_mspi_pin_init(); + esp_timer_early_init(); - esp_flash_app_init(); + esp_flash_config(); - esp_mmu_map_init(); + esp_intr_initialize(); #if CONFIG_ESP_SPIRAM esp_init_psram(); -#endif /* CONFIG_ESP_SPIRAM */ - -#endif /* !CONFIG_MCUBOOT */ - esp_intr_initialize(); - -#if CONFIG_ESP_SPIRAM /* Init Shared Multi Heap for PSRAM */ int err = esp_psram_smh_init(); @@ -127,6 +60,16 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) CODE_UNREACHABLE; } +void IRAM_ATTR __esp_platform_mcuboot_start(void) +{ + esp_intr_initialize(); + + /* Start Zephyr */ + z_prep_c(); + + CODE_UNREACHABLE; +} + /* Boot-time static default printk handler, possibly to be overridden later. */ int IRAM_ATTR arch_printk_char_out(int c) { diff --git a/soc/espressif/esp32s2/soc.h b/soc/espressif/esp32s2/soc.h index 2edd0d12cc947..9a5c5e9795955 100644 --- a/soc/espressif/esp32s2/soc.h +++ b/soc/espressif/esp32s2/soc.h @@ -22,7 +22,8 @@ #include #include -void __esp_platform_start(void); +void __esp_platform_mcuboot_start(void); +void __esp_platform_app_start(void); static inline uint32_t esp_core_id(void) { diff --git a/soc/espressif/esp32s3/esp32s3-mp.c b/soc/espressif/esp32s3/esp32s3-mp.c index 80207a823d6d0..fadbd9224189e 100644 --- a/soc/espressif/esp32s3/esp32s3-mp.c +++ b/soc/espressif/esp32s3/esp32s3-mp.c @@ -191,4 +191,10 @@ int esp_appcpu_init(void) return 0; } + +#if !defined(CONFIG_MCUBOOT) +extern int esp_appcpu_init(void); +SYS_INIT(esp_appcpu_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif + #endif /* CONFIG_SOC_ENABLE_APPCPU */ diff --git a/soc/espressif/esp32s3/hw_init.c b/soc/espressif/esp32s3/hw_init.c index 9cb549119638f..8e69d41f68ef4 100644 --- a/soc/espressif/esp32s3/hw_init.c +++ b/soc/espressif/esp32s3/hw_init.c @@ -63,14 +63,8 @@ int hardware_init(void) print_banner(); #endif /* CONFIG_ESP_CONSOLE */ - spi_flash_init_chip_state(); - err = esp_flash_init_default_chip(); - if (err != 0) { - ESP_EARLY_LOGE(TAG, "Failed to init flash chip, error %d", err); - return err; - } - cache_hal_init(); + mmu_hal_init(); flash_update_id(); @@ -97,6 +91,7 @@ int hardware_init(void) } check_wdt_reset(); + config_wdt(); soc_random_enable(); diff --git a/soc/espressif/esp32s3/soc.c b/soc/espressif/esp32s3/soc.c index 763ba341940f0..881d709d7a0da 100644 --- a/soc/espressif/esp32s3/soc.c +++ b/soc/espressif/esp32s3/soc.c @@ -1,66 +1,23 @@ /* * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2025 Espressif Systems (Shanghai) CO LTD. * * SPDX-License-Identifier: Apache-2.0 */ -/* Include esp-idf headers first to avoid redefining BIT() macro */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include -#include - -#if CONFIG_ESP_SPIRAM -#include "psram.h" -#endif - -#include -#include -#include -#include -#include -#include - #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include - +#include +#include #include -#include "esp_log.h" - -#include -#include - -#define TAG "boot.esp32s3" extern void z_prep_c(void); extern void esp_reset_reason_init(void); -extern int esp_appcpu_init(void); -#ifndef CONFIG_MCUBOOT -/* - * This function is a container for SoC patches - * that needs to be applied during the startup. - */ static void IRAM_ATTR esp_errata(void) { /* Handle the clock gating fix */ @@ -77,32 +34,9 @@ static void IRAM_ATTR esp_errata(void) Cache_Occupy_Addr(SOC_DROM_LOW, 0x4000); #endif } -#endif /* CONFIG_MCUBOOT */ -/* - * This is written in C rather than assembly since, during the port bring up, - * Zephyr is being booted by the Espressif bootloader. With it, the C stack - * is already set up. - */ -void IRAM_ATTR __esp_platform_start(void) +void IRAM_ATTR __esp_platform_app_start(void) { - extern uint32_t _init_start; - - /* Move the exception vector table to IRAM. */ - __asm__ __volatile__("wsr %0, vecbase" : : "r"(&_init_start)); - - z_bss_zero(); - - /* Disable normal interrupts. */ - __asm__ __volatile__("wsr %0, PS" : : "r"(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE)); - - /* Initialize the architecture CPU pointer. Some of the - * initialization code wants a valid _current before - * arch_kernel_init() is invoked. - */ - __asm__ __volatile__("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); - -#ifndef CONFIG_MCUBOOT /* Configure the mode of instruction cache : cache size, cache line size. */ esp_config_instruction_cache_mode(); @@ -114,38 +48,17 @@ void IRAM_ATTR __esp_platform_start(void) /* Apply SoC patches */ esp_errata(); - /* ESP-IDF/MCUboot 2nd stage bootloader enables RTC WDT to check on startup sequence - * related issues in application. Hence disable that as we are about to start - * Zephyr environment. - */ - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); - esp_reset_reason_init(); esp_timer_early_init(); - esp_mspi_pin_init(); - - esp_flash_app_init(); + esp_flash_config(); - mspi_timing_flash_tuning(); - - esp_mmu_map_init(); + esp_intr_initialize(); #if CONFIG_ESP_SPIRAM esp_init_psram(); -#endif /* CONFIG_ESP_SPIRAM */ -#endif /* !CONFIG_MCUBOOT */ - - esp_intr_initialize(); - -#if CONFIG_ESP_SPIRAM - /* Init Shared Multi Heap for PSRAM */ int err = esp_psram_smh_init(); if (err) { @@ -159,6 +72,16 @@ void IRAM_ATTR __esp_platform_start(void) CODE_UNREACHABLE; } +void IRAM_ATTR __esp_platform_mcuboot_start(void) +{ + esp_intr_initialize(); + + /* Start Zephyr */ + z_prep_c(); + + CODE_UNREACHABLE; +} + /* Boot-time static default printk handler, possibly to be overridden later. */ int IRAM_ATTR arch_printk_char_out(int c) { @@ -173,8 +96,3 @@ void sys_arch_reboot(int type) { esp_restart_noos(); } - -#if defined(CONFIG_SOC_ENABLE_APPCPU) && !defined(CONFIG_MCUBOOT) -extern int esp_appcpu_init(void); -SYS_INIT(esp_appcpu_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); -#endif diff --git a/soc/espressif/esp32s3/soc.h b/soc/espressif/esp32s3/soc.h index 1d6d2204cf41c..f74376cc5ba58 100644 --- a/soc/espressif/esp32s3/soc.h +++ b/soc/espressif/esp32s3/soc.h @@ -25,7 +25,8 @@ #include #include -void __esp_platform_start(void); +void __esp_platform_mcuboot_start(void); +void __esp_platform_app_start(void); static inline void esp32_set_mask32(uint32_t v, uint32_t mem_addr) { diff --git a/west.yml b/west.yml index 487468bb44dc0..e26905d7dc1ab 100644 --- a/west.yml +++ b/west.yml @@ -162,7 +162,7 @@ manifest: groups: - hal - name: hal_espressif - revision: 970156407d42c968c50d4b2e3c85c0c548bd9a9e + revision: a459b40356f5e6fb55d92bcb458cec45365d5ec5 path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 36705c4f8ed798ed62672658e809666e95b3e858 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Mon, 10 Feb 2025 17:26:23 -0300 Subject: [PATCH 0234/6055] soc: espressif: remove vddio boost during boot Removes the VDDSDIO control during boot for some SoCs. Only ESP32 allows managing such configuration during initialization. Signed-off-by: Sylvio Alves --- soc/espressif/esp32c2/hw_init.c | 12 ------------ soc/espressif/esp32c3/hw_init.c | 12 ------------ soc/espressif/esp32c6/hw_init.c | 12 ------------ soc/espressif/esp32s2/hw_init.c | 12 ------------ soc/espressif/esp32s3/hw_init.c | 12 ------------ 5 files changed, 60 deletions(-) diff --git a/soc/espressif/esp32c2/hw_init.c b/soc/espressif/esp32c2/hw_init.c index 8222490705a06..7ca871282daad 100644 --- a/soc/espressif/esp32c2/hw_init.c +++ b/soc/espressif/esp32c2/hw_init.c @@ -36,18 +36,6 @@ int hardware_init(void) #ifdef CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE esp_cpu_configure_region_protection(); #endif -#if CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V - rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config(); - - if (cfg.enable == 1 && cfg.tieh == RTC_VDDSDIO_TIEH_1_8V) { - cfg.drefh = 3; - cfg.drefm = 3; - cfg.drefl = 3; - cfg.force = 1; - rtc_vddsdio_set_config(cfg); - esp_rom_delay_us(10); - } -#endif /* CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V */ bootloader_clock_configure(); diff --git a/soc/espressif/esp32c3/hw_init.c b/soc/espressif/esp32c3/hw_init.c index 5399f6ed906a6..f3ecc5f4f6ab7 100644 --- a/soc/espressif/esp32c3/hw_init.c +++ b/soc/espressif/esp32c3/hw_init.c @@ -38,18 +38,6 @@ int hardware_init(void) #ifdef CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE esp_cpu_configure_region_protection(); #endif -#if CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V - rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config(); - - if (cfg.enable == 1 && cfg.tieh == RTC_VDDSDIO_TIEH_1_8V) { - cfg.drefh = 3; - cfg.drefm = 3; - cfg.drefl = 3; - cfg.force = 1; - rtc_vddsdio_set_config(cfg); - esp_rom_delay_us(10); - } -#endif /* CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V */ bootloader_clock_configure(); diff --git a/soc/espressif/esp32c6/hw_init.c b/soc/espressif/esp32c6/hw_init.c index 4d81ccc30c2d0..3eaf036e68e77 100644 --- a/soc/espressif/esp32c6/hw_init.c +++ b/soc/espressif/esp32c6/hw_init.c @@ -54,18 +54,6 @@ int hardware_init(void) #ifdef CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE esp_cpu_configure_region_protection(); #endif -#if CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V - rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config(); - - if (cfg.enable == 1 && cfg.tieh == RTC_VDDSDIO_TIEH_1_8V) { - cfg.drefh = 3; - cfg.drefm = 3; - cfg.drefl = 3; - cfg.force = 1; - rtc_vddsdio_set_config(cfg); - esp_rom_delay_us(10); - } -#endif /* CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V */ bootloader_clock_configure(); diff --git a/soc/espressif/esp32s2/hw_init.c b/soc/espressif/esp32s2/hw_init.c index e144f8becf79a..abed31dd22006 100644 --- a/soc/espressif/esp32s2/hw_init.c +++ b/soc/espressif/esp32s2/hw_init.c @@ -36,18 +36,6 @@ int hardware_init(void) #ifdef CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE esp_cpu_configure_region_protection(); #endif -#if CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V - rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config(); - - if (cfg.enable == 1 && cfg.tieh == RTC_VDDSDIO_TIEH_1_8V) { - cfg.drefh = 3; - cfg.drefm = 3; - cfg.drefl = 3; - cfg.force = 1; - rtc_vddsdio_set_config(cfg); - esp_rom_delay_us(10); - } -#endif /* CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V */ bootloader_clock_configure(); diff --git a/soc/espressif/esp32s3/hw_init.c b/soc/espressif/esp32s3/hw_init.c index 8e69d41f68ef4..a53f7753148b6 100644 --- a/soc/espressif/esp32s3/hw_init.c +++ b/soc/espressif/esp32s3/hw_init.c @@ -42,18 +42,6 @@ int hardware_init(void) #ifdef CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE esp_cpu_configure_region_protection(); #endif -#if CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V - rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config(); - - if (cfg.enable == 1 && cfg.tieh == RTC_VDDSDIO_TIEH_1_8V) { - cfg.drefh = 3; - cfg.drefm = 3; - cfg.drefl = 3; - cfg.force = 1; - rtc_vddsdio_set_config(cfg); - esp_rom_delay_us(10); - } -#endif /* CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V */ bootloader_clock_configure(); From 69a6736ba137b67204e62ccfe70fd03fb477525d Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Tue, 11 Feb 2025 19:35:31 -0300 Subject: [PATCH 0235/6055] soc: espressif: use commom board runner among chips Currently, each SoC has its own CMakeLists.txt file to handle esp32 runner. This PR merged it all in a common file and fixes missing configuration such as flashing frequency, mode and size. Signed-off-by: Sylvio Alves --- soc/espressif/common/CMakeLists.txt | 75 ++++++++++++++++++++++++++ soc/espressif/esp32/CMakeLists.txt | 81 ---------------------------- soc/espressif/esp32c2/CMakeLists.txt | 68 ----------------------- soc/espressif/esp32c3/CMakeLists.txt | 60 --------------------- soc/espressif/esp32c6/CMakeLists.txt | 60 --------------------- soc/espressif/esp32s2/CMakeLists.txt | 61 --------------------- soc/espressif/esp32s3/CMakeLists.txt | 81 ---------------------------- 7 files changed, 75 insertions(+), 411 deletions(-) diff --git a/soc/espressif/common/CMakeLists.txt b/soc/espressif/common/CMakeLists.txt index 3ba79987a3bc3..a8d85bdc33525 100644 --- a/soc/espressif/common/CMakeLists.txt +++ b/soc/espressif/common/CMakeLists.txt @@ -6,3 +6,78 @@ zephyr_include_directories(include) if(NOT CONFIG_MCUBOOT AND NOT CONFIG_SOC_ESP32_APPCPU AND NOT CONFIG_SOC_ESP32S3_APPCPU) zephyr_sources_ifdef(CONFIG_ESP_SPIRAM esp_psram.c) endif() + +# Get flash size to use in esptool as string +math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") + +# Get UART baudrate from DT +dt_chosen(dts_shell_uart PROPERTY "zephyr,shell-uart") +if(${dts_shell_uart}) + dt_prop(monitor_baud PATH ${dts_shell_uart} PROPERTY "current-speed") +endif() + +message("-- Espressif HAL path: ${ESP_IDF_PATH}") + +if(CONFIG_ESP_SIMPLE_BOOT OR CONFIG_MCUBOOT) + if(CONFIG_BUILD_OUTPUT_BIN) + set(ESPTOOL_PY ${ESP_IDF_PATH}/tools/esptool_py/esptool.py) + message("-- Use the esptool.py: ${ESPTOOL_PY}") + + set(ELF2IMAGE_ARG "") + if(NOT CONFIG_MCUBOOT) + set(ELF2IMAGE_ARG "--ram-only-header") + endif() + + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND ${PYTHON_EXECUTABLE} ${ESPTOOL_PY} + ARGS --chip ${CONFIG_SOC} elf2image ${ELF2IMAGE_ARG} + --flash_mode dio + --flash_freq ${CONFIG_ESPTOOLPY_FLASHFREQ} + --flash_size ${esptoolpy_flashsize}MB + -o ${CMAKE_BINARY_DIR}/zephyr/${KERNEL_BIN_NAME} + ${CMAKE_BINARY_DIR}/zephyr/${KERNEL_ELF_NAME}) + endif() +endif() + +set_property(TARGET bintools PROPERTY disassembly_flag_inline_source) + +# Select the image origin depending on the boot configuration +if(CONFIG_SOC_ESP32_APPCPU OR CONFIG_SOC_ESP32S3_APPCPU) + dt_nodelabel(dts_partition_path NODELABEL "slot0_appcpu_partition") +elseif(CONFIG_MCUBOOT OR CONFIG_ESP_SIMPLE_BOOT) + dt_nodelabel(dts_partition_path NODELABEL "boot_partition") +else() + dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") +endif() + +dt_reg_addr(image_off PATH ${dts_partition_path}) +board_finalize_runner_args(esp32 "--esp-app-address=${image_off}") +board_finalize_runner_args(esp32 "--esp-flash-size=${esptoolpy_flashsize}MB") +board_finalize_runner_args(esp32 "--esp-flash-freq=${CONFIG_ESPTOOLPY_FLASHFREQ}") +board_finalize_runner_args(esp32 "--esp-flash-mode=${CONFIG_ESPTOOLPY_FLASHMODE}") +board_finalize_runner_args(esp32 "--esp-monitor-baud=${monitor_baud}") + +message("-- Image partition ${dts_partition_path}") + +# Look for cross references between bootloader sections +if(CONFIG_MCUBOOT) + message("check_callgraph using: ${ESP_IDF_PATH}/tools/ci/check_callgraph.py") + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND + ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/ci/check_callgraph.py + ARGS + --rtl-dirs ${CMAKE_BINARY_DIR}/zephyr + --elf-file ${CMAKE_BINARY_DIR}/zephyr/${KERNEL_ELF_NAME} + find-refs + --from-section='.iram0.loader_text' + --to-section='.iram0.text' + --exit-code) +endif() + +if(CONFIG_MCUBOOT) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/../${CONFIG_SOC}/mcuboot.ld CACHE INTERNAL "") +elseif(CONFIG_SOC_ESP32_APPCPU OR CONFIG_SOC_ESP32S3_APPCPU) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/../${CONFIG_SOC}/default_appcpu.ld CACHE INTERNAL "") +else() + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/../${CONFIG_SOC}/default.ld CACHE INTERNAL "") +endif() diff --git a/soc/espressif/esp32/CMakeLists.txt b/soc/espressif/esp32/CMakeLists.txt index 5ccc92b682ad1..36484e5875ecf 100644 --- a/soc/espressif/esp32/CMakeLists.txt +++ b/soc/espressif/esp32/CMakeLists.txt @@ -22,84 +22,3 @@ zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) zephyr_library_sources_ifdef(CONFIG_PM power.c) zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) - -# get flash size to use in esptool as string -math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") - -# Get UART baudrate from DT -dt_chosen(dts_shell_uart PROPERTY "zephyr,shell-uart") -if(${dts_shell_uart}) - dt_prop(monitor_baud PATH ${dts_shell_uart} PROPERTY "current-speed") -endif() - -board_runner_args(esp32 "--esp-monitor-baud=${monitor_baud}") - -message("-- Espressif HAL path: ${ESP_IDF_PATH}") - -# Select image processing - -if(CONFIG_ESP_SIMPLE_BOOT OR CONFIG_MCUBOOT) - - if(CONFIG_BUILD_OUTPUT_BIN) - - set(ESPTOOL_PY ${ESP_IDF_PATH}/tools/esptool_py/esptool.py) - message("-- Use the esptool.py: ${ESPTOOL_PY}") - - set(ELF2IMAGE_ARG "") - if(NOT CONFIG_MCUBOOT) - set(ELF2IMAGE_ARG "--ram-only-header") - endif() - - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESPTOOL_PY} - ARGS --chip ${CONFIG_SOC} elf2image ${ELF2IMAGE_ARG} - --flash_mode dio --flash_freq 40m - --flash_size ${esptoolpy_flashsize}MB - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf) - - endif() - -endif() - -set_property(TARGET bintools PROPERTY disassembly_flag_inline_source) - - # Select the image origin depending on the boot configuration -if(CONFIG_SOC_ESP32_APPCPU) - dt_nodelabel(dts_partition_path NODELABEL "slot0_appcpu_partition") -elseif(CONFIG_MCUBOOT) - dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -elseif(CONFIG_ESP_SIMPLE_BOOT) - dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -else() - dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") -endif() - -dt_reg_addr(image_off PATH ${dts_partition_path}) -board_finalize_runner_args(esp32 "--esp-app-address=${image_off}") - -message("-- Image partition ${dts_partition_path}") - -# Look for cross references between bootloader sections -if(CONFIG_MCUBOOT) - - message("check_callgraph using: ${ESP_IDF_PATH}/tools/ci/check_callgraph.py") - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND - ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/ci/check_callgraph.py - ARGS - --rtl-dirs ${CMAKE_BINARY_DIR}/zephyr - --elf-file ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf - find-refs - --from-section='.iram0.loader_text' - --to-section='.iram0.text' - --exit-code) -endif() - -if(CONFIG_MCUBOOT) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") -elseif(CONFIG_SOC_ESP32_APPCPU) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default_appcpu.ld CACHE INTERNAL "") -else() - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") -endif() diff --git a/soc/espressif/esp32c2/CMakeLists.txt b/soc/espressif/esp32c2/CMakeLists.txt index 2d70c8cd7de6f..bd1b0474de643 100644 --- a/soc/espressif/esp32c2/CMakeLists.txt +++ b/soc/espressif/esp32c2/CMakeLists.txt @@ -11,71 +11,3 @@ zephyr_sources( zephyr_include_directories(.) zephyr_sources_ifndef(CONFIG_BOOTLOADER_MCUBOOT hw_init.c) - -# get flash size to use in esptool as string -math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") - -if(NOT CONFIG_BOOTLOADER_MCUBOOT) - - if(CONFIG_BUILD_OUTPUT_BIN) - # make ESP ROM loader compatible image - message("ESP-IDF path: ${ESP_IDF_PATH}") - - set(ESPTOOL_PY ${ESP_IDF_PATH}/tools/esptool_py/esptool.py) - message("esptool path: ${ESPTOOL_PY}") - - set(ELF2IMAGE_ARG "") - if(NOT CONFIG_MCUBOOT) - set(ELF2IMAGE_ARG "--ram-only-header") - endif() - - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESPTOOL_PY} - ARGS --chip esp32c2 elf2image ${ELF2IMAGE_ARG} - --flash_mode dio --flash_freq 60m --flash_size ${esptoolpy_flashsize}MB - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf) - endif() - -endif() - -# get code-partition slot0 address -dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") -dt_reg_addr(img_0_off PATH ${dts_partition_path}) - -# get code-partition boot address -dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -dt_reg_addr(boot_off PATH ${dts_partition_path}) - -# get UART baudrate from DT -dt_chosen(dts_shell_uart PROPERTY "zephyr,shell-uart") -dt_prop(monitor_baud PATH ${dts_shell_uart} PROPERTY "current-speed") - -# C2 uses specific values for flash frequency and UART baudrate -board_runner_args(esp32 "--esp-flash-freq=60m") -board_runner_args(esp32 "--esp-monitor-baud=${monitor_baud}") - -if(CONFIG_BOOTLOADER_MCUBOOT) - board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") -else() - board_finalize_runner_args(esp32 "--esp-app-address=${boot_off}") -endif() - -if(CONFIG_MCUBOOT) - # search from cross references between bootloader sections - message("check_callgraph using: ${ESP_IDF_PATH}/tools/ci/check_callgraph.py") - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND - ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/ci/check_callgraph.py - ARGS - --rtl-dirs ${CMAKE_BINARY_DIR}/zephyr - --elf-file ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf - find-refs --from-section=.iram0.iram_loader --to-section=.iram0.text - --exit-code) -endif() - -if(CONFIG_MCUBOOT) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") -else() - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") -endif() diff --git a/soc/espressif/esp32c3/CMakeLists.txt b/soc/espressif/esp32c3/CMakeLists.txt index bfec91fbc4c94..186cf17af9ba1 100644 --- a/soc/espressif/esp32c3/CMakeLists.txt +++ b/soc/espressif/esp32c3/CMakeLists.txt @@ -14,63 +14,3 @@ zephyr_sources_ifndef(CONFIG_BOOTLOADER_MCUBOOT hw_init.c) zephyr_library_sources_ifdef(CONFIG_PM power.c) zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) - -# get flash size to use in esptool as string -math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") - -if(NOT CONFIG_BOOTLOADER_MCUBOOT) - - if(CONFIG_BUILD_OUTPUT_BIN) - # make ESP ROM loader compatible image - message("ESP-IDF path: ${ESP_IDF_PATH}") - - set(ESPTOOL_PY ${ESP_IDF_PATH}/tools/esptool_py/esptool.py) - message("esptool path: ${ESPTOOL_PY}") - - set(ELF2IMAGE_ARG "") - if(NOT CONFIG_MCUBOOT) - set(ELF2IMAGE_ARG "--ram-only-header") - endif() - - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESPTOOL_PY} - ARGS --chip esp32c3 elf2image ${ELF2IMAGE_ARG} - --flash_mode dio --flash_freq 40m --flash_size ${esptoolpy_flashsize}MB - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf) - endif() - -endif() - -# get code-partition slot0 address -dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") -dt_reg_addr(img_0_off PATH ${dts_partition_path}) - -# get code-partition boot address -dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -dt_reg_addr(boot_off PATH ${dts_partition_path}) - -if(CONFIG_BOOTLOADER_MCUBOOT) - board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") -else() - board_finalize_runner_args(esp32 "--esp-app-address=${boot_off}") -endif() - -if(CONFIG_MCUBOOT) - # search from cross references between bootloader sections - message("check_callgraph using: ${ESP_IDF_PATH}/tools/ci/check_callgraph.py") - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND - ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/ci/check_callgraph.py - ARGS - --rtl-dirs ${CMAKE_BINARY_DIR}/zephyr - --elf-file ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf - find-refs --from-section=.iram0.iram_loader --to-section=.iram0.text - --exit-code) -endif() - -if(CONFIG_MCUBOOT) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") -else() - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") -endif() diff --git a/soc/espressif/esp32c6/CMakeLists.txt b/soc/espressif/esp32c6/CMakeLists.txt index 6bd5b99e6ff53..186cf17af9ba1 100644 --- a/soc/espressif/esp32c6/CMakeLists.txt +++ b/soc/espressif/esp32c6/CMakeLists.txt @@ -14,63 +14,3 @@ zephyr_sources_ifndef(CONFIG_BOOTLOADER_MCUBOOT hw_init.c) zephyr_library_sources_ifdef(CONFIG_PM power.c) zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) - -# get flash size to use in esptool as string -math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") - -if(NOT CONFIG_BOOTLOADER_MCUBOOT) - - if(CONFIG_BUILD_OUTPUT_BIN) - # make ESP ROM loader compatible image - message("ESP-IDF path: ${ESP_IDF_PATH}") - - set(ESPTOOL_PY ${ESP_IDF_PATH}/tools/esptool_py/esptool.py) - message("esptool path: ${ESPTOOL_PY}") - - set(ELF2IMAGE_ARG "") - if(NOT CONFIG_MCUBOOT) - set(ELF2IMAGE_ARG "--ram-only-header") - endif() - - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESPTOOL_PY} - ARGS --chip esp32c6 elf2image ${ELF2IMAGE_ARG} - --flash_mode dio --flash_freq 40m --flash_size ${esptoolpy_flashsize}MB - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf) - endif() - -endif() - -# get code-partition slot0 address -dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") -dt_reg_addr(img_0_off PATH ${dts_partition_path}) - -# get code-partition boot address -dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -dt_reg_addr(boot_off PATH ${dts_partition_path}) - -if(CONFIG_BOOTLOADER_MCUBOOT) - board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") -else() - board_finalize_runner_args(esp32 "--esp-app-address=${boot_off}") -endif() - -if(CONFIG_MCUBOOT) - # search from cross references between bootloader sections - message("check_callgraph using: ${ESP_IDF_PATH}/tools/ci/check_callgraph.py") - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND - ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/ci/check_callgraph.py - ARGS - --rtl-dirs ${CMAKE_BINARY_DIR}/zephyr - --elf-file ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf - find-refs --from-section=.iram0.iram_loader --to-section=.iram0.text - --exit-code) -endif() - -if(CONFIG_MCUBOOT) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") -else() - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") -endif() diff --git a/soc/espressif/esp32s2/CMakeLists.txt b/soc/espressif/esp32s2/CMakeLists.txt index ef1d907a64c8b..6cae59aed5b65 100644 --- a/soc/espressif/esp32s2/CMakeLists.txt +++ b/soc/espressif/esp32s2/CMakeLists.txt @@ -14,64 +14,3 @@ zephyr_library_sources_ifdef(CONFIG_NEWLIB_LIBC newlib_fix.c) zephyr_library_sources_ifdef(CONFIG_PM power.c) zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) - -# get flash size to use in esptool as string -math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") - -if(NOT CONFIG_BOOTLOADER_MCUBOOT) - - if(CONFIG_BUILD_OUTPUT_BIN) - # make ESP ROM loader compatible image - message("ESP-IDF path: ${ESP_IDF_PATH}") - - set(ESPTOOL_PY ${ESP_IDF_PATH}/tools/esptool_py/esptool.py) - message("esptool path: ${ESPTOOL_PY}") - - set(ELF2IMAGE_ARG "") - if(NOT CONFIG_MCUBOOT) - set(ELF2IMAGE_ARG "--ram-only-header") - endif() - - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESPTOOL_PY} - ARGS --chip esp32s2 elf2image ${ELF2IMAGE_ARG} - --flash_mode dio --flash_freq 40m - --flash_size ${esptoolpy_flashsize}MB - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf) - endif() - -endif() - -# Get code-partition boot address -dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -dt_reg_addr(boot_off PATH ${dts_partition_path}) - -# Get code-partition slot0 address -dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") -dt_reg_addr(img_0_off PATH ${dts_partition_path}) - -if(CONFIG_BOOTLOADER_MCUBOOT) - board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") -else() - board_finalize_runner_args(esp32 "--esp-app-address=${boot_off}") -endif() - -if(CONFIG_MCUBOOT) - # search from cross references between bootloader sections - message("check_callgraph using: ${ESP_IDF_PATH}/tools/ci/check_callgraph.py") - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND - ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/ci/check_callgraph.py - ARGS - --rtl-dirs ${CMAKE_BINARY_DIR}/zephyr - --elf-file ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf - find-refs --from-section=.iram0.iram_loader --to-section=.iram0.text - --exit-code) -endif() - -if(CONFIG_MCUBOOT) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") -else() - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") -endif() diff --git a/soc/espressif/esp32s3/CMakeLists.txt b/soc/espressif/esp32s3/CMakeLists.txt index 4de4df54cfe61..48c6936487bac 100644 --- a/soc/espressif/esp32s3/CMakeLists.txt +++ b/soc/espressif/esp32s3/CMakeLists.txt @@ -26,84 +26,3 @@ zephyr_library_sources_ifdef(CONFIG_NEWLIB_LIBC newlib_fix.c) # Power Management zephyr_library_sources_ifdef(CONFIG_PM power.c) zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) - -# Get flash size to use in esptool as string -math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") - -# Get UART baudrate from DT -dt_chosen(dts_shell_uart PROPERTY "zephyr,shell-uart") -if(${dts_shell_uart}) - dt_prop(monitor_baud PATH ${dts_shell_uart} PROPERTY "current-speed") -endif() - -board_runner_args(esp32 "--esp-monitor-baud=${monitor_baud}") - -message("-- Espressif HAL path: ${ESP_IDF_PATH}") - -# Select image processing - -if(CONFIG_ESP_SIMPLE_BOOT OR CONFIG_MCUBOOT) - - if(CONFIG_BUILD_OUTPUT_BIN) - - set(ESPTOOL_PY ${ESP_IDF_PATH}/tools/esptool_py/esptool.py) - message("-- Use the esptool.py: ${ESPTOOL_PY}") - - set(ELF2IMAGE_ARG "") - if(NOT CONFIG_MCUBOOT) - set(ELF2IMAGE_ARG "--ram-only-header") - endif() - - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESPTOOL_PY} - ARGS --chip ${CONFIG_SOC} elf2image ${ELF2IMAGE_ARG} - --flash_mode dio --flash_freq 40m - --flash_size ${esptoolpy_flashsize}MB - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf) - - endif() - -endif() - -set_property(TARGET bintools PROPERTY disassembly_flag_inline_source) - -# Select the image origin depending on the boot configuration -if(CONFIG_SOC_ESP32S3_APPCPU) - dt_nodelabel(dts_partition_path NODELABEL "slot0_appcpu_partition") -elseif(CONFIG_MCUBOOT) - dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -elseif(CONFIG_ESP_SIMPLE_BOOT) - dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -else() - dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") -endif() - -dt_reg_addr(image_off PATH ${dts_partition_path}) -board_finalize_runner_args(esp32 "--esp-app-address=${image_off}") - -message("-- Image partition ${dts_partition_path}") - -# Look for cross references between bootloader sections -if(CONFIG_MCUBOOT) - - message("check_callgraph using: ${ESP_IDF_PATH}/tools/ci/check_callgraph.py") - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND - ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/ci/check_callgraph.py - ARGS - --rtl-dirs ${CMAKE_BINARY_DIR}/zephyr - --elf-file ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf - find-refs - --from-section='.iram0.loader_text' - --to-section='.iram0.text' - --exit-code) -endif() - -if(CONFIG_MCUBOOT) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") -elseif(CONFIG_SOC_ESP32S3_APPCPU) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default_appcpu.ld CACHE INTERNAL "") -else() - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") -endif() From 3c1e11c003018148d00cb5b1b21f1739c79bd664 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Tue, 11 Feb 2025 19:38:36 -0300 Subject: [PATCH 0236/6055] linker: espressif: clean up mcuboot iram entries As a result of flash initialization improvements and fixes, some of the mcuboot linker entries are no longer necessary. Signed-off-by: Sylvio Alves --- soc/espressif/esp32/mcuboot.ld | 11 ----------- soc/espressif/esp32c2/mcuboot.ld | 10 +--------- soc/espressif/esp32c3/mcuboot.ld | 10 +--------- soc/espressif/esp32c6/mcuboot.ld | 8 +------- soc/espressif/esp32s2/mcuboot.ld | 11 ----------- soc/espressif/esp32s3/mcuboot.ld | 11 ----------- 6 files changed, 3 insertions(+), 58 deletions(-) diff --git a/soc/espressif/esp32/mcuboot.ld b/soc/espressif/esp32/mcuboot.ld index b880e2c7b34ea..6b321111a0e06 100644 --- a/soc/espressif/esp32/mcuboot.ld +++ b/soc/espressif/esp32/mcuboot.ld @@ -44,28 +44,17 @@ SECTIONS *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) *libarch__xtensa__core.a:xtensa_asm2_util.*(.literal .text .literal.* .text.*) - *liblib__libc__common.a:abort.*(.literal .text .literal.* .text.*) - *libdrivers__timer.a:xtensa_sys_timer.*(.literal .text .literal.* .text.*) *libarch__common.a:dynamic_isr.*(.literal .text .literal.* .text.*) *libarch__common.a:sw_isr_common.*(.literal .text .literal.* .text.*) *libapp.a:flash_map_extended.*(.literal .text .literal.* .text.*) - *libzephyr.a:printk.*(.literal.printk .literal.vprintk .literal.char_out .text.printk .text.vprintk .text.char_out) *libzephyr.a:cbprintf_nano.*(.literal .text .literal.* .text.*) *libzephyr.a:cpu.*(.literal .text .literal.* .text.*) *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_map.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_rom_spiflash.*(.literal .text .literal.* .text.*) - - *libzephyr.a:heap.*(.literal .text .literal.* .text.*) - - *libkernel.a:kheap.*(.literal .text .literal.* .text.*) - *libkernel.a:mempool.*(.literal .text .literal.* .text.*) *libkernel.a:device.*(.literal .text .literal.* .text.*) - *libkernel.a:timeout.*(.literal .text .literal.* .text.*) - *libzephyr.a:esp_loader.*(.literal .text .literal.* .text.*) - *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *(.literal.esp_intr_disable .literal.esp_intr_disable.* .text.esp_intr_disable .text.esp_intr_disable.*) *(.literal.default_intr_handler .text.default_intr_handler .iram1.*.default_intr_handler) diff --git a/soc/espressif/esp32c2/mcuboot.ld b/soc/espressif/esp32c2/mcuboot.ld index 54aff6076c4b2..595fce23789e6 100644 --- a/soc/espressif/esp32c2/mcuboot.ld +++ b/soc/espressif/esp32c2/mcuboot.ld @@ -44,22 +44,14 @@ SECTIONS _loader_text_start = ABSOLUTE(.); *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) - /* TODO: cross-segments calls in the libzephyr.a:device.* */ - *libapp.a:flash_map_extended.*(.literal .text .literal.* .text.*) *libzephyr.a:cbprintf_nano.*(.literal .text .literal.* .text.*) *libzephyr.a:cpu.*(.literal .text .literal.* .text.*) *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_map.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_rom_spiflash.*(.literal .text .literal.* .text.*) - - *libzephyr.a:heap.*(.literal .text .literal.* .text.*) - - *libkernel.a:kheap.*(.literal .text .literal.* .text.*) - *libkernel.a:mempool.*(.literal .text .literal.* .text.*) - + *libkernel.a:device.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_loader.*(.literal .text .literal.* .text.*) - *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *(.literal.esp_intr_disable .literal.esp_intr_disable.* .text.esp_intr_disable .text.esp_intr_disable.*) *(.literal.default_intr_handler .text.default_intr_handler .iram1.*.default_intr_handler) diff --git a/soc/espressif/esp32c3/mcuboot.ld b/soc/espressif/esp32c3/mcuboot.ld index cbc727faf0bef..b4dee564e91e1 100644 --- a/soc/espressif/esp32c3/mcuboot.ld +++ b/soc/espressif/esp32c3/mcuboot.ld @@ -44,22 +44,14 @@ SECTIONS _loader_text_start = ABSOLUTE(.); *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) - /* TODO: cross-segments calls in the libzephyr.a:device.* */ - *libapp.a:flash_map_extended.*(.literal .text .literal.* .text.*) *libzephyr.a:cbprintf_nano.*(.literal .text .literal.* .text.*) *libzephyr.a:cpu.*(.literal .text .literal.* .text.*) *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_map.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_rom_spiflash.*(.literal .text .literal.* .text.*) - - *libzephyr.a:heap.*(.literal .text .literal.* .text.*) - - *libkernel.a:kheap.*(.literal .text .literal.* .text.*) - *libkernel.a:mempool.*(.literal .text .literal.* .text.*) - + *libkernel.a:device.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_loader.*(.literal .text .literal.* .text.*) - *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *(.literal.esp_intr_disable .literal.esp_intr_disable.* .text.esp_intr_disable .text.esp_intr_disable.*) *(.literal.default_intr_handler .text.default_intr_handler .iram1.*.default_intr_handler) diff --git a/soc/espressif/esp32c6/mcuboot.ld b/soc/espressif/esp32c6/mcuboot.ld index 8c76315ffe331..da247e2241b0c 100644 --- a/soc/espressif/esp32c6/mcuboot.ld +++ b/soc/espressif/esp32c6/mcuboot.ld @@ -50,14 +50,8 @@ SECTIONS *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_map.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_rom_spiflash.*(.literal .text .literal.* .text.*) - - *libzephyr.a:heap.*(.literal .text .literal.* .text.*) - - *libkernel.a:kheap.*(.literal .text .literal.* .text.*) - *libkernel.a:mempool.*(.literal .text .literal.* .text.*) - + *libkernel.a:device.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_loader.*(.literal .text .literal.* .text.*) - *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *(.literal.esp_intr_disable .literal.esp_intr_disable.* .text.esp_intr_disable .text.esp_intr_disable.*) *(.literal.default_intr_handler .text.default_intr_handler .iram1.*.default_intr_handler) diff --git a/soc/espressif/esp32s2/mcuboot.ld b/soc/espressif/esp32s2/mcuboot.ld index bf14afeb6a3e8..b14ad89af4a12 100644 --- a/soc/espressif/esp32s2/mcuboot.ld +++ b/soc/espressif/esp32s2/mcuboot.ld @@ -44,28 +44,17 @@ SECTIONS *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) *libarch__xtensa__core.a:xtensa_asm2_util.*(.literal .text .literal.* .text.*) - *liblib__libc__common.a:abort.*(.literal .text .literal.* .text.*) - *libdrivers__timer.a:xtensa_sys_timer.*(.literal .text .literal.* .text.*) *libarch__common.a:dynamic_isr.*(.literal .text .literal.* .text.*) *libarch__common.a:sw_isr_common.*(.literal .text .literal.* .text.*) *libapp.a:flash_map_extended.*(.literal .text .literal.* .text.*) - *libzephyr.a:printk.*(.literal.printk .literal.vprintk .literal.char_out .text.printk .text.vprintk .text.char_out) *libzephyr.a:cbprintf_nano.*(.literal .text .literal.* .text.*) *libzephyr.a:cpu.*(.literal .text .literal.* .text.*) *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_map.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_rom_spiflash.*(.literal .text .literal.* .text.*) - *libzephyr.a:heap.*(.literal .text .literal.* .text.*) - *libkernel.a:kheap.*(.literal .text .literal.* .text.*) - *libkernel.a:mempool.*(.literal .text .literal.* .text.*) *libkernel.a:device.*(.literal .text .literal.* .text.*) - *libkernel.a:timeout.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_loader.*(.literal .text .literal.* .text.*) - *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) - *libzephyr.a:rtc_time.*(.literal .literal.* .text .text.*) - *libzephyr.a:rtc_clk.*(.literal .literal.* .text .text.*) - *libzephyr.a:rtc_clk_init.*(.literal .literal.* .text .text.*) *(.literal.esp_intr_disable .literal.esp_intr_disable.* .text.esp_intr_disable .text.esp_intr_disable.*) *(.literal.default_intr_handler .text.default_intr_handler .iram1.*.default_intr_handler) diff --git a/soc/espressif/esp32s3/mcuboot.ld b/soc/espressif/esp32s3/mcuboot.ld index f0fb717d5d91b..7c5271ae50fcb 100644 --- a/soc/espressif/esp32s3/mcuboot.ld +++ b/soc/espressif/esp32s3/mcuboot.ld @@ -47,28 +47,17 @@ SECTIONS *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) *libarch__xtensa__core.a:xtensa_asm2_util.*(.literal .text .literal.* .text.*) - *liblib__libc__common.a:abort.*(.literal .text .literal.* .text.*) - *libdrivers__timer.a:xtensa_sys_timer.*(.literal .text .literal.* .text.*) *libarch__common.a:dynamic_isr.*(.literal .text .literal.* .text.*) *libarch__common.a:sw_isr_common.*(.literal .text .literal.* .text.*) *libapp.a:flash_map_extended.*(.literal .text .literal.* .text.*) - *libzephyr.a:printk.*(.literal.printk .literal.vprintk .literal.char_out .text.printk .text.vprintk .text.char_out) *libzephyr.a:cbprintf_nano.*(.literal .text .literal.* .text.*) *libzephyr.a:cpu.*(.literal .text .literal.* .text.*) *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *libzephyr.a:flash_map.*(.literal .text .literal.* .text.*) *libzephyr.a:esp_rom_spiflash.*(.literal .text .literal.* .text.*) - - *libzephyr.a:heap.*(.literal .text .literal.* .text.*) - - *libkernel.a:kheap.*(.literal .text .literal.* .text.*) - *libkernel.a:mempool.*(.literal .text .literal.* .text.*) *libkernel.a:device.*(.literal .text .literal.* .text.*) - *libkernel.a:timeout.*(.literal .text .literal.* .text.*) - *libzephyr.a:esp_loader.*(.literal .text .literal.* .text.*) - *libzephyr.a:mmu_hal.*(.literal .text .literal.* .text.*) *(.literal.esp_intr_disable .literal.esp_intr_disable.* .text.esp_intr_disable .text.esp_intr_disable.*) *(.literal.default_intr_handler .text.default_intr_handler .iram1.*.default_intr_handler) From db9dccdc8a6a4355dcbc618af7e3a8f762b426a4 Mon Sep 17 00:00:00 2001 From: Christopher Clingerman Date: Wed, 12 Feb 2025 10:50:44 +0100 Subject: [PATCH 0237/6055] shell: rtt: increase bypass buffer size If the RTT shell backend is selected and the "down" buffer size has been selected, the shell bypass functionality should instead use the buffer size specified by the configuration. Signed-off-by: Christopher Clingerman --- subsys/shell/shell.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index 8ce5f9c3afb8e..b62ef45520c08 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -975,7 +975,11 @@ static void state_collect(const struct shell *sh) shell_bypass_cb_t bypass = sh->ctx->bypass; if (bypass) { +#if defined(CONFIG_SHELL_BACKEND_RTT) && defined(CONFIG_SEGGER_RTT_BUFFER_SIZE_DOWN) + uint8_t buf[CONFIG_SEGGER_RTT_BUFFER_SIZE_DOWN]; +#else uint8_t buf[16]; +#endif (void)sh->iface->api->read(sh->iface, buf, sizeof(buf), &count); From b39a830f0a8a57517345ef69c7ff4d7fffbbda4b Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Wed, 12 Feb 2025 09:41:40 -0300 Subject: [PATCH 0238/6055] samples: blinky: add esp32s3_supermini overlay Add support for the supermini board to be build and run by default. Signed-off-by: Sylvio Alves --- .../boards/esp32c3_supermini.overlay | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 samples/basic/blinky_pwm/boards/esp32c3_supermini.overlay diff --git a/samples/basic/blinky_pwm/boards/esp32c3_supermini.overlay b/samples/basic/blinky_pwm/boards/esp32c3_supermini.overlay new file mode 100644 index 0000000000000..ed2fc7c1b7b50 --- /dev/null +++ b/samples/basic/blinky_pwm/boards/esp32c3_supermini.overlay @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2021 Andrei-Edward Popa + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + */ + + #include + +/ { + aliases { + pwm-0 = &ledc0; + pwm-led0 = &pwm_led_blue; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led_blue: pwm-led-gpio0-2 { + label = "PWM LED0"; + pwms = <&ledc0 0 1000 PWM_POLARITY_NORMAL>; + }; + }; +}; + +&pinctrl { + ledc0_default: ledc0-default { + group1 { + pinmux = ; + output-enable; + }; + }; +}; + +&ledc0 { + pinctrl-0 = <&ledc0_default>; + pinctrl-names = "default"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + channel0@0 { + reg = <0x0>; + timer = <0>; + }; +}; From dcbcbe824d079d76aac2dca29e14b50dd5bee7d3 Mon Sep 17 00:00:00 2001 From: Thomas Deppe Date: Tue, 11 Feb 2025 13:33:33 +0100 Subject: [PATCH 0239/6055] Bluetooth: Host: Add host support for Advertising Coding Selection Extends the API for Advertising Coding Selection. The API is extended to set the Advertising Coding Selection (Host Support) bit. With this feature, the primary and secondary PHY can now explicitly report S=2 or S=8 coding in the extended advertising report. Previously, the report only indicated LE Coded regardless of whether S=2 or S=8 data coding was used. The API now sets the host support bit and ensures that the advertising PHY coding scheme is conveyed to the application via the scan callback. The support is enabled by CONFIG_BT_EXT_ADV_CODING_SELECTION, and requires a controller that selects CONFIG_BT_CTLR_ADV_EXT_CODING_SELECTION_SUPPORT. Signed-off-by: Thomas Deppe --- include/zephyr/bluetooth/gap.h | 10 ++++++++- include/zephyr/bluetooth/hci_types.h | 8 +++++++ subsys/bluetooth/controller/Kconfig | 1 + subsys/bluetooth/host/hci_core.c | 8 +++++++ subsys/bluetooth/host/scan.c | 33 ++++++++++++++++++++++++++-- 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/include/zephyr/bluetooth/gap.h b/include/zephyr/bluetooth/gap.h index 1b1569e300318..2582d9fb96c2f 100644 --- a/include/zephyr/bluetooth/gap.h +++ b/include/zephyr/bluetooth/gap.h @@ -747,8 +747,16 @@ enum { BT_GAP_LE_PHY_1M = BIT(0), /** LE 2M PHY */ BT_GAP_LE_PHY_2M = BIT(1), - /** LE Coded PHY */ + /** LE Coded PHY, coding scheme not specified */ BT_GAP_LE_PHY_CODED = BIT(2), + /** LE Coded S=8 PHY. Only used for advertising reports + * when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled. + */ + BT_GAP_LE_PHY_CODED_S8 = BIT(3), + /** LE Coded S=2 PHY. Only used for advertising reports + * when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled. + */ + BT_GAP_LE_PHY_CODED_S2 = BIT(4), }; /** Advertising PDU types */ diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 3efdf6b5ac579..1a732790077f8 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -3203,6 +3203,14 @@ struct bt_hci_evt_le_phy_update_complete { #define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 #define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_RX_FAILED 0xFF +/* Advertising Coding Selection extended advertising report PHY values. + * Only used when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled. + */ +#define BT_HCI_LE_ADV_EVT_PHY_1M 0x01 +#define BT_HCI_LE_ADV_EVT_PHY_2M 0x02 +#define BT_HCI_LE_ADV_EVT_PHY_CODED_S8 0x03 +#define BT_HCI_LE_ADV_EVT_PHY_CODED_S2 0x04 + struct bt_hci_evt_le_ext_advertising_info { uint16_t evt_type; bt_addr_le_t addr; diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index a92546523fe1b..fd3f3d05a6371 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -787,6 +787,7 @@ config BT_CTLR_ADV_PERIODIC_RSP config BT_CTLR_ADV_EXT_CODING_SELECTION bool "Advertising Coding Selection support" depends on BT_CTLR_PHY_CODED && BT_CTLR_ADV_EXT_CODING_SELECTION_SUPPORT + select BT_CTLR_SET_HOST_FEATURE if BT_OBSERVER default y if BT_EXT_ADV_CODING_SELECTION help Enable support for Bluetooth 6.0 Advertising Coding Selection diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index f4f9284cdcc53..b01c49d3243bb 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -3683,6 +3683,14 @@ static int le_init(void) } } + if (IS_ENABLED(CONFIG_BT_EXT_ADV_CODING_SELECTION) && + BT_FEAT_LE_ADV_CODING_SEL(bt_dev.le.features)) { + err = le_set_host_feature(BT_LE_FEAT_BIT_ADV_CODING_SEL_HOST, 1); + if (err) { + return err; + } + } + return le_set_event_mask(); } diff --git a/subsys/bluetooth/host/scan.c b/subsys/bluetooth/host/scan.c index 05ad120fb38c4..c3551c2ef0781 100644 --- a/subsys/bluetooth/host/scan.c +++ b/subsys/bluetooth/host/scan.c @@ -741,6 +741,28 @@ static uint8_t get_adv_type(uint8_t evt_type) } } +/* Convert Extended adv report PHY to GAP PHY */ +static uint8_t get_ext_adv_coding_sel_phy(uint8_t hci_phy) +{ + /* Converts from Extended adv report PHY to BT_GAP_LE_PHY_* + * When Advertising Coding Selection (Host Support) is enabled + * the controller will return the advertising coding scheme which + * can be S=2 or S=8 data coding. + */ + switch (hci_phy) { + case BT_HCI_LE_ADV_EVT_PHY_1M: + return BT_GAP_LE_PHY_1M; + case BT_HCI_LE_ADV_EVT_PHY_2M: + return BT_GAP_LE_PHY_2M; + case BT_HCI_LE_ADV_EVT_PHY_CODED_S8: + return BT_GAP_LE_PHY_CODED_S8; + case BT_HCI_LE_ADV_EVT_PHY_CODED_S2: + return BT_GAP_LE_PHY_CODED_S2; + default: + return 0; + } +} + /* Convert extended adv report evt_type field to adv props */ static uint16_t get_adv_props_extended(uint16_t evt_type) { @@ -755,8 +777,15 @@ static uint16_t get_adv_props_extended(uint16_t evt_type) static void create_ext_adv_info(struct bt_hci_evt_le_ext_advertising_info const *const evt, struct bt_le_scan_recv_info *const scan_info) { - scan_info->primary_phy = bt_get_phy(evt->prim_phy); - scan_info->secondary_phy = bt_get_phy(evt->sec_phy); + if (IS_ENABLED(CONFIG_BT_EXT_ADV_CODING_SELECTION) && + BT_FEAT_LE_ADV_CODING_SEL(bt_dev.le.features)) { + scan_info->primary_phy = get_ext_adv_coding_sel_phy(evt->prim_phy); + scan_info->secondary_phy = get_ext_adv_coding_sel_phy(evt->sec_phy); + } else { + scan_info->primary_phy = bt_get_phy(evt->prim_phy); + scan_info->secondary_phy = bt_get_phy(evt->sec_phy); + } + scan_info->tx_power = evt->tx_power; scan_info->rssi = evt->rssi; scan_info->sid = evt->sid; From fce53922ef20c242b5f97e7e239078fca0456de4 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 12 Feb 2025 12:46:02 +0100 Subject: [PATCH 0240/6055] net: ipv6: Fix neighbor registration based on received RA message When Router Advertisement with Source Link-Layer Address option is received, host should register a new neighbor marked as STALE (RFC 4861, ch. 6.3.4). This behavior was broken however, because we always added a new neighbor in INCOMPLETE state before processing SLLA option. In result, the entry was not updated to the STALE state, and a redundant Neighbor Solicitation was sent. Fix this by moving the code responsible for adding neighbor in INCOMPLETE state after options processing, and only as a fallback behavior if the SLLA option was not present. Signed-off-by: Robert Lubos --- subsys/net/ip/ipv6_nbr.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index b3a3347f3b2a7..887ecfc8889bd 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -2598,12 +2598,6 @@ static int handle_ra_input(struct net_icmp_ctx *ctx, nd_opt_hdr = (struct net_icmpv6_nd_opt_hdr *) net_pkt_get_data(pkt, &nd_access); - /* Add neighbor cache entry using link local address, regardless of link layer address - * presence in Router Advertisement. - */ - nbr = net_ipv6_nbr_add(net_pkt_iface(pkt), (struct in6_addr *)NET_IPV6_HDR(pkt)->src, NULL, - true, NET_IPV6_NBR_STATE_INCOMPLETE); - while (nd_opt_hdr) { net_pkt_acknowledge_data(pkt, &nd_access); @@ -2704,6 +2698,15 @@ static int handle_ra_input(struct net_icmp_ctx *ctx, net_pkt_get_data(pkt, &nd_access); } + if (nbr == NULL) { + /* Add neighbor cache entry using link local address, regardless + * of link layer address presence in Router Advertisement. + */ + nbr = net_ipv6_nbr_add(net_pkt_iface(pkt), + (struct in6_addr *)NET_IPV6_HDR(pkt)->src, + NULL, true, NET_IPV6_NBR_STATE_INCOMPLETE); + } + router = net_if_ipv6_router_lookup(net_pkt_iface(pkt), (struct in6_addr *)ip_hdr->src); if (router) { From 8cd213e84612430738ad884400e1f69030fbd514 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 12 Feb 2025 12:55:48 +0100 Subject: [PATCH 0241/6055] net: ipv6: Send Neighbor Solicitations in PROBE state as unicast According to RFC 4861, ch. 7.3.3: "Upon entering the PROBE state, a node sends a unicast Neighbor Solicitation message to the neighbor using the cached link-layer address." Zephyr's implementation was not compliant with behavior, as instead of sending a unicast probe for reachability confirmation, it was sending a multicast packet instead. This commit fixes it. Signed-off-by: Robert Lubos --- subsys/net/ip/ipv6_nbr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 887ecfc8889bd..617fd4898252b 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -1577,7 +1577,7 @@ static void ipv6_nd_reachable_timeout(struct k_work *work) data->ns_count); ret = net_ipv6_send_ns(nbr->iface, NULL, NULL, - NULL, &data->addr, + &data->addr, &data->addr, false); if (ret < 0) { NET_DBG("Cannot send NS (%d)", ret); From 02c153c8b1898c21f55f5dc6d890f1534a227123 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 12 Feb 2025 13:08:41 +0100 Subject: [PATCH 0242/6055] net: ipv6: Fix Neighbor Advertisement processing w/o TLLA option According to RFC 4861, ch. 7.2.5: "If the Override flag is set, or the supplied link-layer address is the same as that in the cache, or no Target Link-Layer Address option was supplied, the received advertisement MUST update the Neighbor Cache entry as follows ... If the Solicited flag is set, the state of the entry MUST be set to REACHABLE" This indicates that Target Link-Layer Address option does not need to be present in the received solicited Neighbor Advertisement to confirm reachability. Therefore remove `tllao_offset` variable check from the if condition responsible for updating cache entry. No further changes in the logic are required because if TLLA option is missing, `lladdr_changed` will be set to false, so no LL address will be updated. Signed-off-by: Robert Lubos --- subsys/net/ip/ipv6_nbr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 617fd4898252b..7a9f03d18dac8 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -1755,7 +1755,7 @@ static inline bool handle_na_neighbor(struct net_pkt *pkt, if (na_hdr->flags & NET_ICMPV6_NA_FLAG_OVERRIDE || (!(na_hdr->flags & NET_ICMPV6_NA_FLAG_OVERRIDE) && - tllao_offset && !lladdr_changed)) { + !lladdr_changed)) { if (lladdr_changed) { dbg_update_neighbor_lladdr_raw( From e4beae15b244fb4526a5527a57529fe5086264b3 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 10 Feb 2025 12:52:27 -0600 Subject: [PATCH 0243/6055] drivers: ipm: Select MBOX from IPM_MBOX Projects using IPM will select CONFIG_IPM=y, then the appropriate driver will be enabled based on DT. For devices using the IPM over MBOX driver this will be config IPM_MBOX. But this config depends on MBOX so if the project has not also enabled that, then this driver will not be selected. To fix this, select MBOX from IPM_MBOX. This causes the correct MBOX driver to then be selected also based on DT. This allows projects using only IPM to only need to select the same as before, MBOX will be selected as needed based on DT. Signed-off-by: Andrew Davis --- drivers/ipm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ipm/Kconfig b/drivers/ipm/Kconfig index 0648cdd32c89d..8d7a3f3288e04 100644 --- a/drivers/ipm/Kconfig +++ b/drivers/ipm/Kconfig @@ -59,7 +59,7 @@ config IPM_MBOX bool "IPM over MBOX driver" default y depends on DT_HAS_ZEPHYR_MBOX_IPM_ENABLED - depends on MBOX + select MBOX help IPM driver using a MBOX driver as the backend mechanism. From 3fdb81cd1fee384939c41726484b70b0e62ebcec Mon Sep 17 00:00:00 2001 From: alperen sener Date: Wed, 12 Feb 2025 15:51:49 +0100 Subject: [PATCH 0244/6055] bluetooth: mesh: Correct callback check mesh blob client xfer_progress_complete should be checked instead of end callback Signed-off-by: alperen sener --- subsys/bluetooth/mesh/blob_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/blob_cli.c b/subsys/bluetooth/mesh/blob_cli.c index 40d3d37a6c002..f5aae195476fd 100644 --- a/subsys/bluetooth/mesh/blob_cli.c +++ b/subsys/bluetooth/mesh/blob_cli.c @@ -1086,7 +1086,7 @@ static void progress_checked(struct bt_mesh_blob_cli *cli) cli->state = BT_MESH_BLOB_CLI_STATE_NONE; - if (cli->cb && cli->cb->end) { + if (cli->cb && cli->cb->xfer_progress_complete) { cli->cb->xfer_progress_complete(cli); } } From e6b8b2a039722baec5c0eb66984485d704d2bd0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Thu, 13 Feb 2025 16:52:26 +0100 Subject: [PATCH 0245/6055] drivers: wifi: siwx91x: Fix deinitialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The issue if fixed in the HAL tree with commit "wiseconnect: Fix si91x_bus event during platform deinitialization". So this patch only update the pointer to hal_silabs. Signed-off-by: Jérôme Pouiller --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index e26905d7dc1ab..4c1dcaeb63bb3 100644 --- a/west.yml +++ b/west.yml @@ -228,7 +228,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 1e60d972b2d05de620ece65cfa48ec33c5f38bac + revision: 8a173e9e566a396a19d18da4661cb54ce098f268 path: modules/hal/silabs groups: - hal From 34575e84cd0a957887c00e4105289003a83c6411 Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Mon, 6 Jan 2025 19:09:55 +0100 Subject: [PATCH 0246/6055] dts: soc: Add DTS MBOX and CM7 boot for NXP RT1180 This commit adds MBOX device tree entry for RT1180. Adds functions to copy and boot CM7 core. Adds MPU region for shared memory without caching. Signed-off-by: Tomas Galbicka --- dts/arm/nxp/nxp_rt118x.dtsi | 2 +- dts/arm/nxp/nxp_rt118x_cm33.dtsi | 34 ++++++++-- dts/arm/nxp/nxp_rt118x_cm33_ns.dtsi | 34 ++++++++-- dts/arm/nxp/nxp_rt118x_cm7.dtsi | 28 ++++++-- soc/nxp/imxrt/Kconfig | 5 +- soc/nxp/imxrt/imxrt118x/Kconfig.defconfig | 2 +- soc/nxp/imxrt/imxrt118x/m33/mpu_regions.c | 5 ++ soc/nxp/imxrt/imxrt118x/soc.c | 82 ++++++++++++++++++++++- 8 files changed, 175 insertions(+), 17 deletions(-) diff --git a/dts/arm/nxp/nxp_rt118x.dtsi b/dts/arm/nxp/nxp_rt118x.dtsi index 4a86f8d463422..b8527a1f0f58c 100644 --- a/dts/arm/nxp/nxp_rt118x.dtsi +++ b/dts/arm/nxp/nxp_rt118x.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/dts/arm/nxp/nxp_rt118x_cm33.dtsi b/dts/arm/nxp/nxp_rt118x_cm33.dtsi index 83892d1702874..b77431936d915 100644 --- a/dts/arm/nxp/nxp_rt118x_cm33.dtsi +++ b/dts/arm/nxp/nxp_rt118x_cm33.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,6 +26,12 @@ ranges = <0x0 0x30484000 0x10000000>; }; + m7_itcm: itcm@303c0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + zephyr,memory-region = "M7_ITCM"; + reg = <0x303c0000 DT_SIZE_K(256)>; + }; + peripheral: peripheral@50000000 { ranges = <0x0 0x50000000 0x10000000>; }; @@ -48,6 +54,26 @@ }; }; +&peripheral { + mbox1_a: mbox@4220000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x4220000 0x4000>; + interrupts = <21 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + + mbox2_a: mbox@2430000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x2430000 0x4000>; + interrupts = <22 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; +}; + &nvic { arm,num-irq-priority-bits = <3>; }; @@ -60,7 +86,7 @@ &gpio1{ pinmux = <&iomuxc_aon_gpio_aon_00_gpio1_io00>, - <&iomuxc_aon_gpio_aon_01_gpio1_io01>, + <&iomuxc_aon_gpio_aon_01_gpio1_io01>, <&iomuxc_aon_gpio_aon_02_gpio1_io02>, <&iomuxc_aon_gpio_aon_03_gpio1_io03>, <&iomuxc_aon_gpio_aon_04_gpio1_io04>, @@ -91,7 +117,7 @@ &gpio2{ pinmux = <&iomuxc_gpio_emc_b1_00_gpio2_io00>, - <&iomuxc_gpio_emc_b1_01_gpio2_io01>, + <&iomuxc_gpio_emc_b1_01_gpio2_io01>, <&iomuxc_gpio_emc_b1_02_gpio2_io02>, <&iomuxc_gpio_emc_b1_03_gpio2_io03>, <&iomuxc_gpio_emc_b1_04_gpio2_io04>, @@ -126,7 +152,7 @@ &gpio3{ pinmux = <&iomuxc_gpio_emc_b1_32_gpio3_io00>, - <&iomuxc_gpio_emc_b1_33_gpio3_io01>, + <&iomuxc_gpio_emc_b1_33_gpio3_io01>, <&iomuxc_gpio_emc_b1_34_gpio3_io02>, <&iomuxc_gpio_emc_b1_35_gpio3_io03>, <&iomuxc_gpio_emc_b1_36_gpio3_io04>, diff --git a/dts/arm/nxp/nxp_rt118x_cm33_ns.dtsi b/dts/arm/nxp/nxp_rt118x_cm33_ns.dtsi index 1b082a90fe6b7..5bd64f0ea6053 100644 --- a/dts/arm/nxp/nxp_rt118x_cm33_ns.dtsi +++ b/dts/arm/nxp/nxp_rt118x_cm33_ns.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,6 +26,12 @@ ranges = <0x0 0x20484000 0x10000000>; }; + m7_itcm: itcm@203c0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + zephyr,memory-region = "M7_ITCM"; + reg = <0x203c0000 DT_SIZE_K(256)>; + }; + peripheral: peripheral@40000000 { ranges = <0x0 0x40000000 0x10000000>; }; @@ -48,6 +54,26 @@ }; }; +&peripheral { + mbox1_a: mbox@4220000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x4220000 0x4000>; + interrupts = <21 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + + mbox2_a: mbox@2430000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x2430000 0x4000>; + interrupts = <22 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; +}; + &nvic { arm,num-irq-priority-bits = <3>; }; @@ -60,7 +86,7 @@ &gpio1{ pinmux = <&iomuxc_aon_gpio_aon_00_gpio1_io00>, - <&iomuxc_aon_gpio_aon_01_gpio1_io01>, + <&iomuxc_aon_gpio_aon_01_gpio1_io01>, <&iomuxc_aon_gpio_aon_02_gpio1_io02>, <&iomuxc_aon_gpio_aon_03_gpio1_io03>, <&iomuxc_aon_gpio_aon_04_gpio1_io04>, @@ -91,7 +117,7 @@ &gpio2{ pinmux = <&iomuxc_gpio_emc_b1_00_gpio2_io00>, - <&iomuxc_gpio_emc_b1_01_gpio2_io01>, + <&iomuxc_gpio_emc_b1_01_gpio2_io01>, <&iomuxc_gpio_emc_b1_02_gpio2_io02>, <&iomuxc_gpio_emc_b1_03_gpio2_io03>, <&iomuxc_gpio_emc_b1_04_gpio2_io04>, @@ -126,7 +152,7 @@ &gpio3{ pinmux = <&iomuxc_gpio_emc_b1_32_gpio3_io00>, - <&iomuxc_gpio_emc_b1_33_gpio3_io01>, + <&iomuxc_gpio_emc_b1_33_gpio3_io01>, <&iomuxc_gpio_emc_b1_34_gpio3_io02>, <&iomuxc_gpio_emc_b1_35_gpio3_io03>, <&iomuxc_gpio_emc_b1_36_gpio3_io04>, diff --git a/dts/arm/nxp/nxp_rt118x_cm7.dtsi b/dts/arm/nxp/nxp_rt118x_cm7.dtsi index 91cfc7a95a09a..1b9cde67f4ced 100644 --- a/dts/arm/nxp/nxp_rt118x_cm7.dtsi +++ b/dts/arm/nxp/nxp_rt118x_cm7.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -47,6 +47,26 @@ }; }; +&peripheral { + mbox1_b: mbox@4230000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x4230000 0x4000>; + interrupts = <21 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + + mbox2_b: mbox@2440000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x2440000 0x4000>; + interrupts = <22 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; +}; + &nvic { arm,num-irq-priority-bits = <4>; }; @@ -59,7 +79,7 @@ &gpio1{ pinmux = <&iomuxc_aon_gpio_aon_00_gpio1_io00>, - <&iomuxc_aon_gpio_aon_01_gpio1_io01>, + <&iomuxc_aon_gpio_aon_01_gpio1_io01>, <&iomuxc_aon_gpio_aon_02_gpio1_io02>, <&iomuxc_aon_gpio_aon_03_gpio1_io03>, <&iomuxc_aon_gpio_aon_04_gpio1_io04>, @@ -90,7 +110,7 @@ &gpio2{ pinmux = <&iomuxc_gpio_emc_b1_00_gpio2_io00>, - <&iomuxc_gpio_emc_b1_01_gpio2_io01>, + <&iomuxc_gpio_emc_b1_01_gpio2_io01>, <&iomuxc_gpio_emc_b1_02_gpio2_io02>, <&iomuxc_gpio_emc_b1_03_gpio2_io03>, <&iomuxc_gpio_emc_b1_04_gpio2_io04>, @@ -125,7 +145,7 @@ &gpio3{ pinmux = <&iomuxc_gpio_emc_b1_32_gpio3_io00>, - <&iomuxc_gpio_emc_b1_33_gpio3_io01>, + <&iomuxc_gpio_emc_b1_33_gpio3_io01>, <&iomuxc_gpio_emc_b1_34_gpio3_io02>, <&iomuxc_gpio_emc_b1_35_gpio3_io03>, <&iomuxc_gpio_emc_b1_36_gpio3_io04>, diff --git a/soc/nxp/imxrt/Kconfig b/soc/nxp/imxrt/Kconfig index 648b30d750d55..c09776302e7bf 100644 --- a/soc/nxp/imxrt/Kconfig +++ b/soc/nxp/imxrt/Kconfig @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 config SOC_FAMILY_NXP_IMXRT @@ -141,9 +141,10 @@ config NXP_IMX_EXTERNAL_HYPERRAM This setting should be enabled when the application uses HYPERRAM, or an MPU region will be defined to disable cached access to the HYPERRAM memory space. + config SECOND_CORE_MCUX bool "Dual core operation on the RT11xx series" - depends on SOC_SERIES_IMXRT11XX + depends on SOC_SERIES_IMXRT11XX || SOC_SERIES_IMXRT118X help Indicates the second core will be enabled, and the part will run in dual core mode. Enables dual core operation on the RT11xx series, diff --git a/soc/nxp/imxrt/imxrt118x/Kconfig.defconfig b/soc/nxp/imxrt/imxrt118x/Kconfig.defconfig index ebdfa78693b29..228c42311dfc2 100644 --- a/soc/nxp/imxrt/imxrt118x/Kconfig.defconfig +++ b/soc/nxp/imxrt/imxrt118x/Kconfig.defconfig @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_IMXRT118X diff --git a/soc/nxp/imxrt/imxrt118x/m33/mpu_regions.c b/soc/nxp/imxrt/imxrt118x/m33/mpu_regions.c index 0e017caa56b3c..8783ad6a77edf 100644 --- a/soc/nxp/imxrt/imxrt118x/m33/mpu_regions.c +++ b/soc/nxp/imxrt/imxrt118x/m33/mpu_regions.c @@ -11,6 +11,8 @@ #define REGION_FLEXSPI2_SIZE 0x04000000 #define REGION_DTCM_BASE_ADDRESS 0x30000000 #define REGION_DTCM_SIZE 0x00020000 +#define REGION_SRAM2_SHM_BASE_ADDRESS 0x20500000 +#define REGION_SRAM2_SHM_SIZE 0x00008000 #define REGION_FLEXSPI_BASE_ADDRESS 0x38000000 #define REGION_FLEXSPI_SIZE 0x08000000 #define REGION_PERIPHERAL_BASE_ADDRESS 0x50000000 @@ -23,6 +25,9 @@ static const struct arm_mpu_region mpu_regions[] = { REGION_FLASH_ATTR(REGION_FLEXSPI_BASE_ADDRESS, REGION_FLEXSPI_SIZE)), MPU_REGION_ENTRY("DTCM", REGION_DTCM_BASE_ADDRESS, REGION_RAM_NOCACHE_ATTR(REGION_DTCM_BASE_ADDRESS, REGION_DTCM_SIZE)), + MPU_REGION_ENTRY( + "SRAM2_SHM", REGION_SRAM2_SHM_BASE_ADDRESS, + REGION_RAM_NOCACHE_ATTR(REGION_SRAM2_SHM_BASE_ADDRESS, REGION_SRAM2_SHM_SIZE)), MPU_REGION_ENTRY( "PERIPHERAL", REGION_PERIPHERAL_BASE_ADDRESS, REGION_DEVICE_ATTR(REGION_PERIPHERAL_BASE_ADDRESS, REGION_PERIPHERAL_SIZE)), diff --git a/soc/nxp/imxrt/imxrt118x/soc.c b/soc/nxp/imxrt/imxrt118x/soc.c index 261250870a9eb..1d6362447deea 100644 --- a/soc/nxp/imxrt/imxrt118x/soc.c +++ b/soc/nxp/imxrt/imxrt118x/soc.c @@ -26,6 +26,18 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); +#if defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_CPU_CORTEX_M33) +#include +/* Memcpy macro to copy segments from secondary core image stored in flash + * to RAM section that secondary core boots from. + * n is the segment number, as defined in zephyr_image_info.h + */ +#define MEMCPY_SEGMENT(n, _) \ + memcpy((uint32_t *)(((SEGMENT_LMA_ADDRESS_ ## n) - ADJUSTED_LMA) + 0x303C0000), \ + (uint32_t *)(SEGMENT_LMA_ADDRESS_ ## n), \ + (SEGMENT_SIZE_ ## n)) +#endif + /* * Set ELE_STICK_FAILED_STS to 0 when ELE status check is not required, * which is useful when debug reset, where the core has already get the @@ -46,6 +58,17 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); #define ELE_CORE_CM7_ID 0x2 #define EDMA_DID 0x7U +/* When CM33 sets TRDC, CM7 must NOT require TRDC ownership from ELE */ +#if defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_SOC_MIMXRT1189_CM33) +/* When CONFIG_SECOND_CORE_MCUX then TRDC(AON/WAKEUP) ownership cannot be released + * to CM33 and CM7 both in one ELE reset cycle. + * Only CM33 will set TRDC. + */ +#define CM33_SET_TRDC 1U +#else +#define CM33_SET_TRDC 0U +#endif + #ifdef CONFIG_INIT_ARM_PLL static const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN = { #if defined(CONFIG_SOC_MIMXRT1189_CM33) || defined(CONFIG_SOC_MIMXRT1189_CM7) @@ -507,6 +530,10 @@ __weak void clock_init(void) /* Keep core clock ungated during WFI */ CCM->LPCG[1].LPM0 = 0x33333333; CCM->LPCG[1].LPM1 = 0x33333333; + + /* Let the core clock still running in WAIT mode */ + BLK_CTRL_S_AONMIX->M7_CFG |= BLK_CTRL_S_AONMIX_M7_CFG_CORECLK_FORCE_ON_MASK; + /* Keep the system clock running so SYSTICK can wake up * the system from wfi. */ @@ -646,8 +673,12 @@ void soc_early_init_hook(void) { /* Initialize system clock */ clock_init(); + +#if (defined(CM33_SET_TRDC) && (CM33_SET_TRDC > 0U)) /* Get trdc and enable all access modes for MBC and MRC of TRDCA and TRDCW */ trdc_enable_all_access(); +#endif /* (defined(CM33_SET_TRDC) && (CM33_SET_TRDC > 0U) */ + #if defined(CONFIG_WDT_MCUX_RTWDOG) /* Unmask the watchdog reset channel */ RTWDOG_IF_SET_SRC(0, 1) @@ -660,7 +691,20 @@ void soc_early_init_hook(void) uint32_t mask = SRC_GetResetStatusFlags(SRC_GENERAL_REG); SRC_ClearGlobalSystemResetStatus(SRC_GENERAL_REG, mask); -#endif +#endif /* defined(CONFIG_WDT_MCUX_RTWDOG) */ + +#if (defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_CPU_CORTEX_M33)) + /** + * Copy CM7 core from flash to memory. Note that depending on where the + * user decided to store CM7 code, this is likely going to read from the + * flexspi while using XIP. Provided we DO NOT WRITE TO THE FLEXSPI, + * this operation is safe. + * + * Note that this copy MUST occur before enabling the M33 caching to + * ensure the data is written directly to RAM (since the M4 core will use it) + */ + LISTIFY(SEGMENT_NUM, MEMCPY_SEGMENT, (;)); +#endif /* (defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_CPU_CORTEX_M33)) */ /* Enable data cache */ sys_cache_data_enable(); @@ -673,5 +717,41 @@ void soc_early_init_hook(void) void soc_reset_hook(void) { SystemInit(); + +#if defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_CPU_CORTEX_M33) + Prepare_CM7(0); +#endif } #endif + +#if defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_CPU_CORTEX_M33) + +static int second_core_boot(void) +{ + /* + * RT1180 Specific CM7 Kick Off operation + */ + /* Trigger S401 */ + while ((MU_RT_S3MUA->TSR & MU_TSR_TE0_MASK) == 0) { + ; } /* Wait TR empty */ + MU_RT_S3MUA->TR[0] = 0x17d20106; + while ((MU_RT_S3MUA->RSR & MU_RSR_RF0_MASK) == 0) { + ; } /* Wait RR Full */ + while ((MU_RT_S3MUA->RSR & MU_RSR_RF1_MASK) == 0) { + ; } /* Wait RR Full */ + + /* Response from ELE must be always read */ + __attribute__((unused)) volatile uint32_t result1, result2; + result1 = MU_RT_S3MUA->RR[0]; + result2 = MU_RT_S3MUA->RR[1]; + + /* Deassert Wait */ + BLK_CTRL_S_AONMIX->M7_CFG = + (BLK_CTRL_S_AONMIX->M7_CFG & (~BLK_CTRL_S_AONMIX_M7_CFG_WAIT_MASK)) | + BLK_CTRL_S_AONMIX_M7_CFG_WAIT(0); + + return 0; +} + +SYS_INIT(second_core_boot, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif From fdebb1d40d6779faf36e9e8631da5a602e66c2a3 Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Wed, 4 Dec 2024 16:00:54 +0100 Subject: [PATCH 0247/6055] boards: Add multicore support for CM7 core on RT1180 This commit adds multicore support for RT1180. It enables the secondary core CM7 to be copied from flash and run from RAM. Signed-off-by: Tomas Galbicka --- boards/nxp/mimxrt1180_evk/Kconfig.defconfig | 18 ++++++++++++- boards/nxp/mimxrt1180_evk/board.cmake | 4 +-- boards/nxp/mimxrt1180_evk/doc/index.rst | 27 +++++++++++++++---- .../mimxrt1180_evk-pinctrl.dtsi | 25 ++++++++++++++++- boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi | 12 +++++++-- .../mimxrt1180_evk_mimxrt1189_cm7.dts | 13 ++++----- 6 files changed, 82 insertions(+), 17 deletions(-) diff --git a/boards/nxp/mimxrt1180_evk/Kconfig.defconfig b/boards/nxp/mimxrt1180_evk/Kconfig.defconfig index a71be9a7729ae..47c1f2f826265 100644 --- a/boards/nxp/mimxrt1180_evk/Kconfig.defconfig +++ b/boards/nxp/mimxrt1180_evk/Kconfig.defconfig @@ -1,6 +1,6 @@ # MIMXRT1180-EVK board -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 if BOARD_MIMXRT1180_EVK @@ -14,4 +14,20 @@ config NXP_IMX_EXTERNAL_HYPERRAM config BOARD_EARLY_INIT_HOOK default y + +if SECOND_CORE_MCUX && BOARD_MIMXRT1180_EVK_MIMXRT1189_CM7 + +config BUILD_OUTPUT_INFO_HEADER + default y + +DT_CHOSEN_IMAGE_M7 = nxp,m7-partition + +# Adjust the offset of the output image if building for RT18xx SOC +config BUILD_OUTPUT_ADJUST_LMA + default "($(dt_chosen_reg_addr_hex,$(DT_CHOSEN_IMAGE_M7)) + \ + $(dt_node_reg_addr_hex,/soc/spi@425e0000,1)) - \ + $(dt_node_reg_addr_hex,/soc/itcm@0)" + +endif + endif # BOARD_MIMXRT1180_EVK diff --git a/boards/nxp/mimxrt1180_evk/board.cmake b/boards/nxp/mimxrt1180_evk/board.cmake index 409077e41d4b3..b0659abddc905 100644 --- a/boards/nxp/mimxrt1180_evk/board.cmake +++ b/boards/nxp/mimxrt1180_evk/board.cmake @@ -1,5 +1,5 @@ # -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -9,7 +9,7 @@ set(RT1180_BOARD_DIR # Note1: Suggest developers use Secure Provisioning Tool(SPT) to download RT1180 image # SPT can be downloaded on NXP web: https://www.nxp.com/design/design-center/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-secure-provisioning-tool:MCUXPRESSO-SECURE-PROVISIONING # Details about the usage of SPT on MIMXRT1180-EVK board can be referred on chapter 7 of getting start with Mcuxpresso SDK for MIMXRT1180-EVK doc in SDK package. -if(CONFIG_SOC_MIMXRT1189_CM33) +if(CONFIG_SOC_MIMXRT1189_CM33 OR CONFIG_SECOND_CORE_MCUX) board_runner_args(linkserver "--device=MIMXRT1189xxxxx:MIMXRT1180-EVK") board_runner_args(jlink "--device=MIMXRT1189xxx8_M33" "--reset-after-load" "--tool-opt=-jlinkscriptfile ${RT1180_BOARD_DIR}/jlinkscript/evkmimxrt1180_cm33.jlinkscript") elseif(CONFIG_SOC_MIMXRT1189_CM7) diff --git a/boards/nxp/mimxrt1180_evk/doc/index.rst b/boards/nxp/mimxrt1180_evk/doc/index.rst index 32505399167ca..b243fb766051d 100644 --- a/boards/nxp/mimxrt1180_evk/doc/index.rst +++ b/boards/nxp/mimxrt1180_evk/doc/index.rst @@ -149,9 +149,13 @@ The MIMXRT1180 SoC has six pairs of pinmux/gpio controllers. +---------------+-----------------+---------------------------+ | GPIO_AD_27 | GPIO | LED | +---------------+-----------------+---------------------------+ -| GPIO_AON_08 | LPUART1_TX | UART Console | +| GPIO_AON_08 | LPUART1_TX | UART Console M33 core | +---------------+-----------------+---------------------------+ -| GPIO_AON_09 | LPUART1_RX | UART Console | +| GPIO_AON_09 | LPUART1_RX | UART Console M33 core | ++---------------+---------------------------------------------+ +| GPIO_AON_19 | LPUART12_TX | UART Console M7 core | ++---------------+-----------------+---------------------------+ +| GPIO_AON_20 | LPUART12_RX | UART Console M7 core | +---------------+-----------------+---------------------------+ | GPIO_SD_B1_00 | SPI1_CS0 | spi | +---------------+---------------------------------------------+ @@ -160,7 +164,10 @@ The MIMXRT1180 SoC has six pairs of pinmux/gpio controllers. | GPIO_SD_B1_02 | SPI1_SDO | spi | +---------------+---------------------------------------------+ | GPIO_SD_B1_03 | SPI1_SDI | spi | -+---------------+---------------------------------------------+ ++---------------+-----------------+---------------------------+ + +UART for M7 core is connected to USB-to-UART J60 connector. +Or user can use open JP7 Jumper to enable second UART on MCU LINK J53 connector. System Clock ============ @@ -172,8 +179,8 @@ running at 792MHz Serial Port =========== -The MIMXRT1180 SoC has 12 UARTs. One is configured for the console and the -remaining are not used. +The MIMXRT1180 SoC has 12 UARTs. LPUART1 is configured for the CM33 console, the LPUART12 is +configured for the CM7 console core and the remaining are not used. Ethernet ======== @@ -253,6 +260,16 @@ When debugging cm33 core, need to ensure the SW5 on "0100" mode. When debugging cm7 core, need to ensure the SW5 on "0001" mode. (Only support run cm7 image when debugging due to default boot core on board is cm33 core) +Dual Core samples Debugging +*************************** + +When debugging dual core samples, need to ensure the SW5 on "0100" mode. +The CM33 core is responsible for copying and starting the CM7. +To debug the CM7 it is useful to put infinite while loop either in reset vector or +into main function and attach via debugger to CM7 core. + +CM7 core can be started again only after reset, so after flashing ensure to reset board. + Configuring a Console ===================== diff --git a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk-pinctrl.dtsi b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk-pinctrl.dtsi index 9dbff25e09e84..47efc9fdda8ca 100644 --- a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * SPDX-License-Identifier: Apache-2.0 * */ @@ -155,6 +155,29 @@ }; }; + pinmux_lpuart12: pinmux_lpuart12 { + group0 { + pinmux = <&iomuxc_aon_gpio_aon_20_lpuart12_rxd>, + <&iomuxc_aon_gpio_aon_19_lpuart12_txd>; + drive-strength = "high"; + slew-rate = "fast"; + }; + }; + + pinmux_lpuart12_sleep: pinmux_lpuart12_sleep { + group0 { + pinmux = <&iomuxc_aon_gpio_aon_20_lpuart12_rxd>; + drive-strength = "high"; + bias-pull-up; + slew-rate = "fast"; + }; + group1 { + pinmux = <&iomuxc_aon_gpio_aon_19_lpuart12_txd>; + drive-strength = "high"; + slew-rate = "fast"; + }; + }; + pinmux_lpuart3: pinmux_lpuart3 { group0 { pinmux = <&iomuxc_gpio_ad_14_lpuart3_rxd>, diff --git a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi index 8b26a005810e0..0f595a96ab0b6 100644 --- a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi +++ b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,7 +19,7 @@ green_led: led-1 { gpios = <&gpio4 27 GPIO_ACTIVE_HIGH>; label = "User LED D6"; - }; + }; }; gpio_keys { @@ -143,6 +143,14 @@ pinctrl-names = "default", "sleep"; }; +&lpuart12 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&pinmux_lpuart12>; + pinctrl-1 = <&pinmux_lpuart12_sleep>; + pinctrl-names = "default", "sleep"; +}; + &lpuart3 { pinctrl-0 = <&pinmux_lpuart3>; pinctrl-1 = <&pinmux_lpuart3_sleep>; diff --git a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts index 5ac690d3c39df..81bd3a2124753 100644 --- a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts +++ b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.dts @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,14 +14,15 @@ compatible = "nxp,mimxrt1189"; chosen { - zephyr,sram = &hyperram0; + zephyr,sram = &dtcm; zephyr,dtcm = &dtcm; zephyr,itcm = &itcm; zephyr,flash-controller = &w25q128jw; - zephyr,flash = &w25q128jw; - zephyr,console = &lpuart1; - zephyr,shell-uart = &lpuart1; + zephyr,flash = &itcm; + zephyr,console = &lpuart12; + zephyr,shell-uart = &lpuart12; zephyr,canbus = &flexcan3; + nxp,m7-partition = &slot1_partition; }; hyperram0: memory@04000000 { @@ -31,7 +32,7 @@ }; }; -&lpuart1 { +&lpuart12 { status = "okay"; current-speed = <115200>; }; From 2589717852f21355cfcb61b9d218a5a567fcb53a Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Wed, 4 Dec 2024 16:04:16 +0100 Subject: [PATCH 0248/6055] samples: enable multicore samples for RT1180 board This commit adds support for these multicore samples: - samples/drivers/mbox - samples/drivers/mbox_data - samples/subsys/ipc/ipc_service/static_vrings - samples/subsys/ipc/openamp Signed-off-by: Tomas Galbicka --- samples/drivers/mbox/CMakeLists.txt | 3 +- samples/drivers/mbox/Kconfig.sysbuild | 3 +- .../mimxrt1180_evk_mimxrt1189_cm33.conf | 2 + .../mimxrt1180_evk_mimxrt1189_cm33.overlay | 13 +++++ samples/drivers/mbox/remote/CMakeLists.txt | 3 +- .../boards/mimxrt1180_evk_mimxrt1189_cm7.conf | 2 + .../mimxrt1180_evk_mimxrt1189_cm7.overlay | 13 +++++ samples/drivers/mbox/sysbuild.cmake | 3 +- samples/drivers/mbox_data/CMakeLists.txt | 3 +- samples/drivers/mbox_data/Kconfig.sysbuild | 3 +- .../mimxrt1180_evk_mimxrt1189_cm33.conf | 2 + .../mimxrt1180_evk_mimxrt1189_cm33.overlay | 13 +++++ .../drivers/mbox_data/remote/CMakeLists.txt | 3 +- .../boards/mimxrt1180_evk_mimxrt1189_cm7.conf | 2 + .../mimxrt1180_evk_mimxrt1189_cm7.overlay | 13 +++++ samples/drivers/mbox_data/sysbuild.cmake | 3 +- .../ipc_service/static_vrings/CMakeLists.txt | 5 +- .../static_vrings/Kconfig.sysbuild | 3 +- .../mimxrt1180_evk_mimxrt1189_cm33.conf | 2 + .../mimxrt1180_evk_mimxrt1189_cm33.overlay | 49 +++++++++++++++++++ .../boards/mimxrt1180_evk_mimxrt1189_cm7.conf | 2 + .../mimxrt1180_evk_mimxrt1189_cm7.overlay | 49 +++++++++++++++++++ samples/subsys/ipc/openamp/Kconfig.sysbuild | 3 +- .../mimxrt1180_evk_mimxrt1189_cm33.conf | 5 ++ .../mimxrt1180_evk_mimxrt1189_cm33.overlay | 33 +++++++++++++ .../boards/mimxrt1180_evk_mimxrt1189_cm7.conf | 5 ++ .../mimxrt1180_evk_mimxrt1189_cm7.overlay | 33 +++++++++++++ 27 files changed, 261 insertions(+), 12 deletions(-) create mode 100644 samples/drivers/mbox/boards/mimxrt1180_evk_mimxrt1189_cm33.conf create mode 100644 samples/drivers/mbox/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay create mode 100644 samples/drivers/mbox/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf create mode 100644 samples/drivers/mbox/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay create mode 100644 samples/drivers/mbox_data/boards/mimxrt1180_evk_mimxrt1189_cm33.conf create mode 100644 samples/drivers/mbox_data/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay create mode 100644 samples/drivers/mbox_data/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf create mode 100644 samples/drivers/mbox_data/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay create mode 100644 samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1180_evk_mimxrt1189_cm33.conf create mode 100644 samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay create mode 100644 samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf create mode 100644 samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay create mode 100644 samples/subsys/ipc/openamp/boards/mimxrt1180_evk_mimxrt1189_cm33.conf create mode 100644 samples/subsys/ipc/openamp/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay create mode 100644 samples/subsys/ipc/openamp/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf create mode 100644 samples/subsys/ipc/openamp/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay diff --git a/samples/drivers/mbox/CMakeLists.txt b/samples/drivers/mbox/CMakeLists.txt index 919dd6439eaf4..0d1644d418978 100644 --- a/samples/drivers/mbox/CMakeLists.txt +++ b/samples/drivers/mbox/CMakeLists.txt @@ -1,6 +1,6 @@ # # Copyright (c) 2021 Carlo Caione -# Copyright 2023-2024 NXP +# Copyright 2023-2025 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -16,6 +16,7 @@ if(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP OR CONFIG_BOARD_ADP_XC7K_AE350 OR CONFIG_BOARD_MIMXRT1170_EVK_MIMXRT1176_CM7 OR CONFIG_BOARD_MIMXRT1160_EVK_MIMXRT1166_CM7 OR + CONFIG_BOARD_MIMXRT1180_EVK_MIMXRT1189_CM33 OR CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU0 OR CONFIG_BOARD_FRDM_MCXN947_MCXN947_CPU0 OR CONFIG_BOARD_ESP32_DEVKITC_WROOM_ESP32_PROCPU OR diff --git a/samples/drivers/mbox/Kconfig.sysbuild b/samples/drivers/mbox/Kconfig.sysbuild index 8101ce82a4e62..ce58f93763baf 100644 --- a/samples/drivers/mbox/Kconfig.sysbuild +++ b/samples/drivers/mbox/Kconfig.sysbuild @@ -1,5 +1,5 @@ # Copyright 2023 Nordic Semiconductor ASA -# Copyright 2023-2024 NXP +# Copyright 2023-2025 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -13,6 +13,7 @@ config REMOTE_BOARD default "mimxrt1170_evkb/mimxrt1176/cm4" if $(BOARD) = "mimxrt1170_evkb" default "mimxrt1170_evk/mimxrt1176/cm4" if $(BOARD) = "mimxrt1170_evk" default "mimxrt1160_evk/mimxrt1166/cm4" if $(BOARD) = "mimxrt1160_evk" + default "mimxrt1180_evk/mimxrt1189/cm7" if $(BOARD) = "mimxrt1180_evk" default "lpcxpresso55s69/lpc55s69/cpu1" if $(BOARD) = "lpcxpresso55s69" default "frdm_mcxn947/mcxn947/cpu1" if $(BOARD) = "frdm_mcxn947" default "nrf54h20dk/nrf54h20/cpuapp" if "$(BOARD)${BOARD_QUALIFIERS}" = "nrf54h20dk/nrf54h20/cpurad" diff --git a/samples/drivers/mbox/boards/mimxrt1180_evk_mimxrt1189_cm33.conf b/samples/drivers/mbox/boards/mimxrt1180_evk_mimxrt1189_cm33.conf new file mode 100644 index 0000000000000..60eead5a076e4 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1180_evk_mimxrt1189_cm33.conf @@ -0,0 +1,2 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y diff --git a/samples/drivers/mbox/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay b/samples/drivers/mbox/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay new file mode 100644 index 0000000000000..9836b08ebe3d3 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + mbox-consumer { + compatible = "vnd,mbox-consumer"; + mboxes = <&mbox1_a 1>, <&mbox1_a 0>; + mbox-names = "tx", "rx"; + }; +}; diff --git a/samples/drivers/mbox/remote/CMakeLists.txt b/samples/drivers/mbox/remote/CMakeLists.txt index 2196c270628f7..7382d8ce60279 100644 --- a/samples/drivers/mbox/remote/CMakeLists.txt +++ b/samples/drivers/mbox/remote/CMakeLists.txt @@ -1,6 +1,6 @@ # # Copyright (c) 2021 Carlo Caione -# Copyright 2023-2024 NXP +# Copyright 2023-2025 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -14,6 +14,7 @@ if(CONFIG_BOARD_NRF5340DK_NRF5340_CPUNET OR CONFIG_BOARD_ADP_XC7K_AE350 OR CONFIG_BOARD_MIMXRT1170_EVK_MIMXRT1176_CM4 OR CONFIG_BOARD_MIMXRT1160_EVK_MIMXRT1166_CM4 OR + CONFIG_BOARD_MIMXRT1180_EVK_MIMXRT1189_CM7 OR CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU1 OR CONFIG_BOARD_FRDM_MCXN947_MCXN947_CPU1 OR CONFIG_BOARD_ESP32_DEVKITC_WROOM_ESP32_APPCPU OR diff --git a/samples/drivers/mbox/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf b/samples/drivers/mbox/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf new file mode 100644 index 0000000000000..77adcfa24f4e2 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf @@ -0,0 +1,2 @@ +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay b/samples/drivers/mbox/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay new file mode 100644 index 0000000000000..db51f5184fd5a --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + mbox-consumer { + compatible = "vnd,mbox-consumer"; + mboxes = <&mbox1_b 0>, <&mbox1_b 1>; + mbox-names = "tx", "rx"; + }; +}; diff --git a/samples/drivers/mbox/sysbuild.cmake b/samples/drivers/mbox/sysbuild.cmake index e2a5a03b87eb6..3180273351476 100644 --- a/samples/drivers/mbox/sysbuild.cmake +++ b/samples/drivers/mbox/sysbuild.cmake @@ -1,5 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA -# Copyright 2023-2024 NXP +# Copyright 2023-2025 NXP # SPDX-License-Identifier: Apache-2.0 if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") @@ -22,6 +22,7 @@ native_simulator_set_final_executable(${DEFAULT_IMAGE}) if(SB_CONFIG_BOARD_MIMXRT1160_EVK_MIMXRT1166_CM7 OR SB_CONFIG_BOARD_MIMXRT1170_EVK_MIMXRT1176_CM7 OR + SB_CONFIG_BOARD_MIMXRT1180_EVK_MIMXRT1189_CM33 OR SB_CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU0) # For these NXP boards the main core application is dependent on # 'zephyr_image_info.h' generated by remote application. diff --git a/samples/drivers/mbox_data/CMakeLists.txt b/samples/drivers/mbox_data/CMakeLists.txt index 077c62257e2f3..31cd00e202b1c 100644 --- a/samples/drivers/mbox_data/CMakeLists.txt +++ b/samples/drivers/mbox_data/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -12,6 +12,7 @@ set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) if(CONFIG_BOARD_MIMXRT1170_EVK_MIMXRT1176_CM7 OR CONFIG_BOARD_MIMXRT1160_EVK_MIMXRT1166_CM7 OR CONFIG_BOARD_FRDM_MCXN947_MCXN947_CPU0 OR + CONFIG_BOARD_MIMXRT1180_EVK_MIMXRT1189_CM33 OR CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU0) message(STATUS "${BOARD}${BOARD_QUALIFIERS} compile as Main in this sample") else() diff --git a/samples/drivers/mbox_data/Kconfig.sysbuild b/samples/drivers/mbox_data/Kconfig.sysbuild index 6efff4d3ad50a..106ccb1cb7d39 100644 --- a/samples/drivers/mbox_data/Kconfig.sysbuild +++ b/samples/drivers/mbox_data/Kconfig.sysbuild @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -9,5 +9,6 @@ string default "mimxrt1170_evkb/mimxrt1176/cm4" if $(BOARD) = "mimxrt1170_evkb" default "mimxrt1170_evk/mimxrt1176/cm4" if $(BOARD) = "mimxrt1170_evk" default "mimxrt1160_evk/mimxrt1166/cm4" if $(BOARD) = "mimxrt1160_evk" + default "mimxrt1180_evk/mimxrt1189/cm7" if $(BOARD) = "mimxrt1180_evk" default "lpcxpresso55s69/lpc55s69/cpu1" if $(BOARD) = "lpcxpresso55s69" default "frdm_mcxn947/mcxn947/cpu1" if $(BOARD) = "frdm_mcxn947" diff --git a/samples/drivers/mbox_data/boards/mimxrt1180_evk_mimxrt1189_cm33.conf b/samples/drivers/mbox_data/boards/mimxrt1180_evk_mimxrt1189_cm33.conf new file mode 100644 index 0000000000000..60eead5a076e4 --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1180_evk_mimxrt1189_cm33.conf @@ -0,0 +1,2 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y diff --git a/samples/drivers/mbox_data/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay b/samples/drivers/mbox_data/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay new file mode 100644 index 0000000000000..9836b08ebe3d3 --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + mbox-consumer { + compatible = "vnd,mbox-consumer"; + mboxes = <&mbox1_a 1>, <&mbox1_a 0>; + mbox-names = "tx", "rx"; + }; +}; diff --git a/samples/drivers/mbox_data/remote/CMakeLists.txt b/samples/drivers/mbox_data/remote/CMakeLists.txt index 0a708a8ed6536..5342a2c98156f 100644 --- a/samples/drivers/mbox_data/remote/CMakeLists.txt +++ b/samples/drivers/mbox_data/remote/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -10,6 +10,7 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) if(CONFIG_BOARD_MIMXRT1170_EVK_MIMXRT1176_CM4 OR CONFIG_BOARD_MIMXRT1160_EVK_MIMXRT1166_CM4 OR CONFIG_BOARD_FRDM_MCXN947_MCXN947_CPU1 OR + CONFIG_BOARD_MIMXRT1180_EVK_MIMXRT1189_CM7 OR CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU1) message(STATUS "${BOARD}${BOARD_QUALIFIERS} compile as remote in this sample") else() diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf b/samples/drivers/mbox_data/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf new file mode 100644 index 0000000000000..77adcfa24f4e2 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf @@ -0,0 +1,2 @@ +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay new file mode 100644 index 0000000000000..db51f5184fd5a --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + mbox-consumer { + compatible = "vnd,mbox-consumer"; + mboxes = <&mbox1_b 0>, <&mbox1_b 1>; + mbox-names = "tx", "rx"; + }; +}; diff --git a/samples/drivers/mbox_data/sysbuild.cmake b/samples/drivers/mbox_data/sysbuild.cmake index 0fb83fbadd3e2..dcb2509a05d57 100644 --- a/samples/drivers/mbox_data/sysbuild.cmake +++ b/samples/drivers/mbox_data/sysbuild.cmake @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -18,6 +18,7 @@ ExternalZephyrProject_Add( if(SB_CONFIG_BOARD_MIMXRT1160_EVK_MIMXRT1166_CM7 OR SB_CONFIG_BOARD_MIMXRT1170_EVK_MIMXRT1176_CM7 OR + SB_CONFIG_BOARD_MIMXRT1180_EVK_MIMXRT1189_CM33 OR SB_CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU0) # For these NXP boards the main core application is dependent on # 'zephyr_image_info.h' generated by remote application. diff --git a/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt b/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt index 29201c036641e..49384bac63057 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt +++ b/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt @@ -1,6 +1,6 @@ # # Copyright (c) 2021 Carlo Caione -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -16,7 +16,8 @@ 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 OR - CONFIG_BOARD_FRDM_MCXN947_MCXN947_CPU0 + CONFIG_BOARD_FRDM_MCXN947_MCXN947_CPU0 OR + CONFIG_BOARD_MIMXRT1180_EVK_MIMXRT1189_CM33 ) ) message(FATAL_ERROR "${BOARD} is not supported for this sample") diff --git a/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild b/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild index f00c11c4cf8da..a0a4146d396ee 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild +++ b/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild @@ -1,5 +1,5 @@ # Copyright 2023 Nordic Semiconductor ASA -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -14,3 +14,4 @@ string default "mimxrt1170_evk/mimxrt1176/cm4" if $(BOARD) = "mimxrt1170_evk" default "mimxrt1170_evkb/mimxrt1176/cm4" if $(BOARD) = "mimxrt1170_evkb" default "frdm_mcxn947/mcxn947/cpu1" if $(BOARD) = "frdm_mcxn947" + default "mimxrt1180_evk/mimxrt1189/cm7" if $(BOARD) = "mimxrt1180_evk" diff --git a/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1180_evk_mimxrt1189_cm33.conf b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1180_evk_mimxrt1189_cm33.conf new file mode 100644 index 0000000000000..60eead5a076e4 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1180_evk_mimxrt1189_cm33.conf @@ -0,0 +1,2 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y diff --git a/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay new file mode 100644 index 0000000000000..2bcb576660516 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay @@ -0,0 +1,49 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + /* Define memory regions for IPC */ + ocram2_ipc0: memory@20500000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20500000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_IPC0"; + zephyr,memory-attr = <(DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + ocram2_ipc1: memory@20504000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20504000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_IPC1"; + zephyr,memory-attr = <(DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc0>; + mboxes = <&mbox1_a 0>, <&mbox1_a 1>; + mbox-names = "tx", "rx"; + role = "host"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc1>; + mboxes = <&mbox1_a 2>, <&mbox1_a 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/mimxrt1180_evk_mimxrt1189_cm7.conf b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf new file mode 100644 index 0000000000000..77adcfa24f4e2 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf @@ -0,0 +1,2 @@ +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay new file mode 100644 index 0000000000000..d6958308790ea --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay @@ -0,0 +1,49 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + /* Define memory regions for IPC */ + ocram2_ipc0: memory@20500000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20500000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_IPC0"; + zephyr,memory-attr = <(DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + ocram2_ipc1: memory@20504000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20504000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_IPC1"; + zephyr,memory-attr = <(DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc0>; + mboxes = <&mbox1_b 0>, <&mbox1_b 1>; + mbox-names = "rx", "tx"; + role = "remote"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc1>; + mboxes = <&mbox1_b 2>, <&mbox1_b 3>; + mbox-names = "rx", "tx"; + role = "remote"; + zephyr,priority = <1 PRIO_COOP>; + zephyr,buffer-size = <128>; + status = "okay"; + }; + }; +}; diff --git a/samples/subsys/ipc/openamp/Kconfig.sysbuild b/samples/subsys/ipc/openamp/Kconfig.sysbuild index f9fb79495bff7..61dc0f4b8bf75 100644 --- a/samples/subsys/ipc/openamp/Kconfig.sysbuild +++ b/samples/subsys/ipc/openamp/Kconfig.sysbuild @@ -1,4 +1,4 @@ -# Copyright 2022-2024 NXP +# Copyright 2022-2025 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -14,3 +14,4 @@ string default "mimxrt1160_evk/mimxrt1166/cm4" if $(BOARD) = "mimxrt1160_evk" default "mimxrt1170_evkb/mimxrt1176/cm4" if $(BOARD) = "mimxrt1170_evkb" default "frdm_mcxn947/mcxn947/cpu1" if $(BOARD) = "frdm_mcxn947" + default "mimxrt1180_evk/mimxrt1189/cm7" if $(BOARD) = "mimxrt1180_evk" diff --git a/samples/subsys/ipc/openamp/boards/mimxrt1180_evk_mimxrt1189_cm33.conf b/samples/subsys/ipc/openamp/boards/mimxrt1180_evk_mimxrt1189_cm33.conf new file mode 100644 index 0000000000000..b57d6b0281ac6 --- /dev/null +++ b/samples/subsys/ipc/openamp/boards/mimxrt1180_evk_mimxrt1189_cm33.conf @@ -0,0 +1,5 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_IPM=y +CONFIG_IPM_MBOX=y +CONFIG_MBOX=y diff --git a/samples/subsys/ipc/openamp/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay b/samples/subsys/ipc/openamp/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay new file mode 100644 index 0000000000000..582c4271c5d67 --- /dev/null +++ b/samples/subsys/ipc/openamp/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay @@ -0,0 +1,33 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + chosen { + /* + * shared memory reserved for the inter-processor communication + */ + + zephyr,ipc_shm = &ocram2_sh_mem; + zephyr,ipc = &mailbox_a; + }; + + /* Define memory regions for IPC */ + ocram2_sh_mem: memory@20500000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20500000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_SH_MEM"; + zephyr,memory-attr = <(DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + mailbox_a: ipm-mbox { + compatible = "zephyr,mbox-ipm"; + mboxes = <&mbox1_a 1>, <&mbox1_a 0>; + mbox-names = "tx", "rx"; + }; +}; diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf b/samples/subsys/ipc/openamp/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf new file mode 100644 index 0000000000000..b31b3845defda --- /dev/null +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.conf @@ -0,0 +1,5 @@ +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y +CONFIG_IPM=y +CONFIG_IPM_MBOX=y +CONFIG_MBOX=y diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay b/samples/subsys/ipc/openamp/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay new file mode 100644 index 0000000000000..80831a425fc9e --- /dev/null +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1180_evk_mimxrt1189_cm7.overlay @@ -0,0 +1,33 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + chosen { + /* + * shared memory reserved for the inter-processor communication + */ + + zephyr,ipc_shm = &ocram2_sh_mem; + zephyr,ipc = &mailbox_b; + }; + + /* Define memory regions for IPC */ + ocram2_sh_mem: memory@20500000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20500000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_SH_MEM"; + zephyr,memory-attr = <(DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + mailbox_b: ipm-mbox { + compatible = "zephyr,mbox-ipm"; + mboxes = <&mbox1_b 0>, <&mbox1_b 1>; + mbox-names = "tx", "rx"; + }; +}; From cfd3985bda2a544e7405e991014131c693381fdb Mon Sep 17 00:00:00 2001 From: Tomas Galbicka Date: Mon, 6 Jan 2025 14:02:12 +0100 Subject: [PATCH 0249/6055] drivers: nxp mbox imx mu driver fix Flags This commit fixes flag handling in mbox driver. There are two MU drivers mu/ and mu1/ in nxp sdk with same API but different bit masks and register layouts. To be compatible with both add mapping table for channel index. This will use enum from relavant driver heder to select correct flag mask. Signed-off-by: Tomas Galbicka --- drivers/mbox/mbox_nxp_imx_mu.c | 35 +++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/mbox/mbox_nxp_imx_mu.c b/drivers/mbox/mbox_nxp_imx_mu.c index 762ea6670d668..8b5dfd3b73868 100644 --- a/drivers/mbox/mbox_nxp_imx_mu.c +++ b/drivers/mbox/mbox_nxp_imx_mu.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 * @@ -21,6 +21,25 @@ LOG_MODULE_REGISTER(nxp_mbox_imx_mu); #define MU_MAX_CHANNELS 4 #define MU_MBOX_SIZE sizeof(uint32_t) +/* + * Arrays to translate the channel number to Generic Interrupt Mask for mu driver. + * The kMU_GenInt[0..3]Flag comes from MU driver header mu.h. + * There are more MU drivers implementations. For the `mu` driver + * the kMU_GenInt0Flag goes from 3 to 0 relative bit for the + * `mu1` driver kMU_GenInt0Flag goes from 0 to 3. + * Same for kMU_GenInt0InterruptTrigger and kMU_Rx0FullFlag. + * Therefore use this mapping table to select correct mask based on channel index. + */ +const static uint32_t g_gen_int_pend_mask[MU_MAX_CHANNELS] = {kMU_GenInt0Flag, kMU_GenInt1Flag, + kMU_GenInt2Flag, kMU_GenInt3Flag}; + +const static uint32_t g_gen_int_trig_mask[MU_MAX_CHANNELS] = { + kMU_GenInt0InterruptTrigger, kMU_GenInt1InterruptTrigger, kMU_GenInt2InterruptTrigger, + kMU_GenInt3InterruptTrigger}; + +const static uint32_t g_rx_flag_mask[MU_MAX_CHANNELS] = {kMU_Rx0FullFlag, kMU_Rx1FullFlag, + kMU_Rx2FullFlag, kMU_Rx3FullFlag}; + struct nxp_imx_mu_data { mbox_callback_t cb[MU_MAX_CHANNELS]; void *user_data[MU_MAX_CHANNELS]; @@ -42,7 +61,7 @@ static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, const str /* Signalling mode. */ if (msg == NULL) { - return MU_TriggerInterrupts(cfg->base, kMU_GenInt0InterruptTrigger >> channel); + return MU_TriggerInterrupts(cfg->base, g_gen_int_trig_mask[channel]); } /* Data transfer mode. */ @@ -159,10 +178,13 @@ static void handle_irq(const struct device *dev) { struct nxp_imx_mu_data *data = dev->data; const struct nxp_imx_mu_config *config = dev->config; - const uint32_t flag = MU_GetStatusFlags(config->base); + const uint32_t flags = MU_GetStatusFlags(config->base); for (int i_channel = 0; i_channel < MU_MAX_CHANNELS; i_channel++) { - if ((flag & (kMU_Rx0FullFlag >> i_channel)) == (kMU_Rx0FullFlag >> i_channel)) { + const uint32_t rx_int_mask = g_rx_flag_mask[i_channel]; + const uint32_t gen_int_mask = g_gen_int_pend_mask[i_channel]; + + if ((flags & rx_int_mask) == rx_int_mask) { data->received_data = MU_ReceiveMsgNonBlocking(config->base, i_channel); struct mbox_msg msg = {(const void *)&data->received_data, MU_MBOX_SIZE}; @@ -170,9 +192,8 @@ static void handle_irq(const struct device *dev) data->cb[i_channel](dev, i_channel, data->user_data[i_channel], &msg); } - } else if ((flag & (kMU_GenInt0Flag >> i_channel)) == - (kMU_GenInt0Flag >> i_channel)) { - MU_ClearStatusFlags(config->base, (kMU_GenInt0Flag >> i_channel)); + } else if ((flags & gen_int_mask) == gen_int_mask) { + MU_ClearStatusFlags(config->base, gen_int_mask); if (data->cb[i_channel]) { data->cb[i_channel](dev, i_channel, data->user_data[i_channel], NULL); From 96c3cd6cd3302f353e7fe9ace842d66d207a4424 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 10 Feb 2025 10:40:55 +0100 Subject: [PATCH 0250/6055] drivers: adc: nrf_saadc: add pm device support Extend nrf saadc device driver with pm device runtime support. To preserve previous behavior: * if pm device is disabled, saadc is resumed on sampling start and suspended when sampling done. * if pm device is enabled only, saadc does nothing on sampling start/stop. its resumed on init. * if pm device runtime is enabled, saadc is got on sampling start, and put on sampling stop. Signed-off-by: Bjarki Arge Andreasen --- drivers/adc/adc_nrfx_saadc.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/adc/adc_nrfx_saadc.c b/drivers/adc/adc_nrfx_saadc.c index 0dde7c5bcb03b..2ce779fea0bfe 100644 --- a/drivers/adc/adc_nrfx_saadc.c +++ b/drivers/adc/adc_nrfx_saadc.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #define LOG_LEVEL CONFIG_ADC_LOG_LEVEL #include @@ -168,6 +170,26 @@ static int adc_convert_acq_time(uint16_t acquisition_time, nrf_saadc_acqtime_t * return result; } +static int saadc_pm_hook(const struct device *dev, enum pm_device_action action) +{ + ARG_UNUSED(dev); + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + nrf_saadc_disable(NRF_SAADC); + return 0; + + case PM_DEVICE_ACTION_RESUME: + nrf_saadc_enable(NRF_SAADC); + return 0; + + default: + break; + } + + return -ENOTSUP; +} + /* Implementation of the ADC driver API function: adc_channel_setup. */ static int adc_nrfx_channel_setup(const struct device *dev, const struct adc_channel_cfg *channel_cfg) @@ -320,7 +342,11 @@ static int adc_nrfx_channel_setup(const struct device *dev, static void adc_context_start_sampling(struct adc_context *ctx) { +#if defined(CONFIG_PM_DEVICE_RUNTIME) + pm_device_runtime_get(DEVICE_DT_INST_GET(0)); +#else nrf_saadc_enable(NRF_SAADC); +#endif if (ctx->sequence.calibrate) { nrf_saadc_task_trigger(NRF_SAADC, @@ -623,7 +649,12 @@ static void saadc_irq_handler(const struct device *dev) nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END); nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_STOP); + +#if defined(CONFIG_PM_DEVICE_RUNTIME) + pm_device_runtime_put(DEVICE_DT_INST_GET(0)); +#else nrf_saadc_disable(NRF_SAADC); +#endif if (has_single_ended(&m_data.ctx.sequence)) { correct_single_ended(&m_data.ctx.sequence); @@ -663,7 +694,7 @@ static int init_saadc(const struct device *dev) adc_context_unlock_unconditionally(&m_data.ctx); - return 0; + return pm_device_driver_init(dev, saadc_pm_hook); } static DEVICE_API(adc, adc_nrfx_driver_api) = { @@ -693,9 +724,10 @@ static DEVICE_API(adc, adc_nrfx_driver_api) = { #define SAADC_INIT(inst) \ BUILD_ASSERT((inst) == 0, \ "multiple instances not supported"); \ + PM_DEVICE_DT_INST_DEFINE(0, saadc_pm_hook, 1); \ DEVICE_DT_INST_DEFINE(0, \ init_saadc, \ - NULL, \ + PM_DEVICE_DT_INST_GET(0), \ NULL, \ NULL, \ POST_KERNEL, \ From d01c93c120ff6e2e3428772d7af1936f2153f91f Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 10 Feb 2025 10:39:45 +0100 Subject: [PATCH 0251/6055] dts: nordic,nrf-saadc: set pm device runtime auto Set pm device runtime runtime auto flag to ensure saadc instances are initialized correctly if pm device runtime is used. Signed-off-by: Bjarki Arge Andreasen --- dts/arm/nordic/nrf52805.dtsi | 1 + dts/arm/nordic/nrf52810.dtsi | 1 + dts/arm/nordic/nrf52811.dtsi | 1 + dts/arm/nordic/nrf52832.dtsi | 1 + dts/arm/nordic/nrf52833.dtsi | 1 + dts/arm/nordic/nrf52840.dtsi | 1 + dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi | 1 + dts/arm/nordic/nrf91_peripherals.dtsi | 1 + dts/common/nordic/nrf54h20.dtsi | 1 + dts/common/nordic/nrf54l09.dtsi | 1 + dts/common/nordic/nrf54l20.dtsi | 1 + dts/common/nordic/nrf54l_05_10_15.dtsi | 1 + dts/common/nordic/nrf9280.dtsi | 1 + 13 files changed, 13 insertions(+) diff --git a/dts/arm/nordic/nrf52805.dtsi b/dts/arm/nordic/nrf52805.dtsi index e1c8e6a2efbc8..ef47f4e5273fa 100644 --- a/dts/arm/nordic/nrf52805.dtsi +++ b/dts/arm/nordic/nrf52805.dtsi @@ -165,6 +165,7 @@ interrupts = <7 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; timer0: timer@40008000 { diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index 40d872dda4463..0da4d7ccf94c4 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -169,6 +169,7 @@ interrupts = <7 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; timer0: timer@40008000 { compatible = "nordic,nrf-timer"; diff --git a/dts/arm/nordic/nrf52811.dtsi b/dts/arm/nordic/nrf52811.dtsi index 735bfee427b26..8e65445cf5f96 100644 --- a/dts/arm/nordic/nrf52811.dtsi +++ b/dts/arm/nordic/nrf52811.dtsi @@ -200,6 +200,7 @@ interrupts = <7 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; timer0: timer@40008000 { diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index abb1aed468cb5..7e2dae5faff3d 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -212,6 +212,7 @@ interrupts = <7 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; timer0: timer@40008000 { diff --git a/dts/arm/nordic/nrf52833.dtsi b/dts/arm/nordic/nrf52833.dtsi index e8a033b40021b..93fac4a04b88d 100644 --- a/dts/arm/nordic/nrf52833.dtsi +++ b/dts/arm/nordic/nrf52833.dtsi @@ -226,6 +226,7 @@ interrupts = <7 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; timer0: timer@40008000 { diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index e2265c130b0d1..9624ae12dfbd0 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -214,6 +214,7 @@ interrupts = <7 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; timer0: timer@40008000 { diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index 75c2eb9f99f28..244459a0f16a5 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -287,6 +287,7 @@ adc: adc@e000 { interrupts = <14 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; timer0: timer@f000 { diff --git a/dts/arm/nordic/nrf91_peripherals.dtsi b/dts/arm/nordic/nrf91_peripherals.dtsi index 58cc3142bcf27..476f8415853a4 100644 --- a/dts/arm/nordic/nrf91_peripherals.dtsi +++ b/dts/arm/nordic/nrf91_peripherals.dtsi @@ -26,6 +26,7 @@ adc: adc@e000 { interrupts = <14 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; dppic0: dppic: dppic@17000 { diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index b9ec26af05d8b..f011e0474283b 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -876,6 +876,7 @@ status = "disabled"; #io-channel-cells = <1>; power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>; + zephyr,pm-device-runtime-auto; }; comp: comparator@983000 { diff --git a/dts/common/nordic/nrf54l09.dtsi b/dts/common/nordic/nrf54l09.dtsi index 8ffce7ab801cd..44bef74a33d2e 100644 --- a/dts/common/nordic/nrf54l09.dtsi +++ b/dts/common/nordic/nrf54l09.dtsi @@ -387,6 +387,7 @@ interrupts = <213 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; temp: temp@d7000 { diff --git a/dts/common/nordic/nrf54l20.dtsi b/dts/common/nordic/nrf54l20.dtsi index 808d32a716eb7..f1bed73156463 100644 --- a/dts/common/nordic/nrf54l20.dtsi +++ b/dts/common/nordic/nrf54l20.dtsi @@ -453,6 +453,7 @@ interrupts = <213 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; nfct: nfct@d6000 { diff --git a/dts/common/nordic/nrf54l_05_10_15.dtsi b/dts/common/nordic/nrf54l_05_10_15.dtsi index f080a3be61a61..5b0597fb65d21 100644 --- a/dts/common/nordic/nrf54l_05_10_15.dtsi +++ b/dts/common/nordic/nrf54l_05_10_15.dtsi @@ -493,6 +493,7 @@ interrupts = <213 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; nfct: nfct@d6000 { diff --git a/dts/common/nordic/nrf9280.dtsi b/dts/common/nordic/nrf9280.dtsi index df5f3c429319b..ee201dbacfde0 100644 --- a/dts/common/nordic/nrf9280.dtsi +++ b/dts/common/nordic/nrf9280.dtsi @@ -687,6 +687,7 @@ interrupts = <386 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; #io-channel-cells = <1>; + zephyr,pm-device-runtime-auto; }; comp: comparator@983000 { From 53bba4528179934182f23b548363cf1474e22242 Mon Sep 17 00:00:00 2001 From: Zihao Gao Date: Wed, 22 Jan 2025 18:09:27 +0800 Subject: [PATCH 0252/6055] Bluetooth: AVRCP: implementation for passthrough commands This patch alllows to send passthough command from CT to TG. Signed-off-by: Zihao Gao --- include/zephyr/bluetooth/classic/avrcp.h | 131 +++++++++++++++++- subsys/bluetooth/host/classic/avctp.c | 20 ++- subsys/bluetooth/host/classic/avrcp.c | 100 ++++++++++--- .../bluetooth/host/classic/avrcp_internal.h | 21 +-- subsys/bluetooth/host/classic/shell/avrcp.c | 64 +++++++-- 5 files changed, 281 insertions(+), 55 deletions(-) diff --git a/include/zephyr/bluetooth/classic/avrcp.h b/include/zephyr/bluetooth/classic/avrcp.h index 4c422570fb637..14678643592dd 100644 --- a/include/zephyr/bluetooth/classic/avrcp.h +++ b/include/zephyr/bluetooth/classic/avrcp.h @@ -16,6 +16,99 @@ extern "C" { #endif +/** @brief AV/C command types */ +typedef enum __packed { + BT_AVRCP_CTYPE_CONTROL = 0x0, + BT_AVRCP_CTYPE_STATUS = 0x1, + BT_AVRCP_CTYPE_SPECIFIC_INQUIRY = 0x2, + BT_AVRCP_CTYPE_NOTIFY = 0x3, + BT_AVRCP_CTYPE_GENERAL_INQUIRY = 0x4, +} bt_avrcp_ctype_t; + +/** @brief AV/C response codes */ +typedef enum __packed { + BT_AVRCP_RSP_NOT_IMPLEMENTED = 0x8, + BT_AVRCP_RSP_ACCEPTED = 0x9, + BT_AVRCP_RSP_REJECTED = 0xa, + BT_AVRCP_RSP_IN_TRANSITION = 0xb, + BT_AVRCP_RSP_IMPLEMENTED = 0xc, /**< For SPECIFIC_INQUIRY and GENERAL_INQUIRY commands */ + BT_AVRCP_RSP_STABLE = 0xc, /**< For STATUS commands */ + BT_AVRCP_RSP_CHANGED = 0xd, + BT_AVRCP_RSP_INTERIM = 0xf, +} bt_avrcp_rsp_t; + +/** @brief AV/C operation ids used in AVRCP passthrough commands */ +typedef enum __packed { + BT_AVRCP_OPID_SELECT = 0x00, + BT_AVRCP_OPID_UP = 0x01, + BT_AVRCP_OPID_DOWN = 0x02, + BT_AVRCP_OPID_LEFT = 0x03, + BT_AVRCP_OPID_RIGHT = 0x04, + BT_AVRCP_OPID_RIGHT_UP = 0x05, + BT_AVRCP_OPID_RIGHT_DOWN = 0x06, + BT_AVRCP_OPID_LEFT_UP = 0x07, + BT_AVRCP_OPID_LEFT_DOWN = 0x08, + BT_AVRCP_OPID_ROOT_MENU = 0x09, + BT_AVRCP_OPID_SETUP_MENU = 0x0a, + BT_AVRCP_OPID_CONTENTS_MENU = 0x0b, + BT_AVRCP_OPID_FAVORITE_MENU = 0x0c, + BT_AVRCP_OPID_EXIT = 0x0d, + + BT_AVRCP_OPID_0 = 0x20, + BT_AVRCP_OPID_1 = 0x21, + BT_AVRCP_OPID_2 = 0x22, + BT_AVRCP_OPID_3 = 0x23, + BT_AVRCP_OPID_4 = 0x24, + BT_AVRCP_OPID_5 = 0x25, + BT_AVRCP_OPID_6 = 0x26, + BT_AVRCP_OPID_7 = 0x27, + BT_AVRCP_OPID_8 = 0x28, + BT_AVRCP_OPID_9 = 0x29, + BT_AVRCP_OPID_DOT = 0x2a, + BT_AVRCP_OPID_ENTER = 0x2b, + BT_AVRCP_OPID_CLEAR = 0x2c, + + BT_AVRCP_OPID_CHANNEL_UP = 0x30, + BT_AVRCP_OPID_CHANNEL_DOWN = 0x31, + BT_AVRCP_OPID_PREVIOUS_CHANNEL = 0x32, + BT_AVRCP_OPID_SOUND_SELECT = 0x33, + BT_AVRCP_OPID_INPUT_SELECT = 0x34, + BT_AVRCP_OPID_DISPLAY_INFORMATION = 0x35, + BT_AVRCP_OPID_HELP = 0x36, + BT_AVRCP_OPID_PAGE_UP = 0x37, + BT_AVRCP_OPID_PAGE_DOWN = 0x38, + + BT_AVRCP_OPID_POWER = 0x40, + BT_AVRCP_OPID_VOLUME_UP = 0x41, + BT_AVRCP_OPID_VOLUME_DOWN = 0x42, + BT_AVRCP_OPID_MUTE = 0x43, + BT_AVRCP_OPID_PLAY = 0x44, + BT_AVRCP_OPID_STOP = 0x45, + BT_AVRCP_OPID_PAUSE = 0x46, + BT_AVRCP_OPID_RECORD = 0x47, + BT_AVRCP_OPID_REWIND = 0x48, + BT_AVRCP_OPID_FAST_FORWARD = 0x49, + BT_AVRCP_OPID_EJECT = 0x4a, + BT_AVRCP_OPID_FORWARD = 0x4b, + BT_AVRCP_OPID_BACKWARD = 0x4c, + + BT_AVRCP_OPID_ANGLE = 0x50, + BT_AVRCP_OPID_SUBPICTURE = 0x51, + + BT_AVRCP_OPID_F1 = 0x71, + BT_AVRCP_OPID_F2 = 0x72, + BT_AVRCP_OPID_F3 = 0x73, + BT_AVRCP_OPID_F4 = 0x74, + BT_AVRCP_OPID_F5 = 0x75, + BT_AVRCP_OPID_VENDOR_UNIQUE = 0x7e, +} bt_avrcp_opid_t; + +/** @brief AVRCP button state flag */ +typedef enum __packed { + BT_AVRCP_BUTTON_PRESSED = 0, + BT_AVRCP_BUTTON_RELEASED = 1, +} bt_avrcp_button_state_t; + /** @brief AVRCP structure */ struct bt_avrcp; @@ -28,7 +121,15 @@ struct bt_avrcp_subunit_info_rsp { uint8_t subunit_type; uint8_t max_subunit_id; const uint8_t *extended_subunit_type; /**< contains max_subunit_id items */ - const uint8_t *extended_subunit_id; /**< contains max_subunit_id items */ + const uint8_t *extended_subunit_id; /**< contains max_subunit_id items */ +}; + +struct bt_avrcp_passthrough_rsp { + uint8_t response; /**< bt_avrcp_rsp_t */ + uint8_t operation_id; /**< bt_avrcp_opid_t */ + uint8_t state; /**< bt_avrcp_button_state_t */ + uint8_t len; + const uint8_t *payload; }; struct bt_avrcp_cb { @@ -40,6 +141,7 @@ struct bt_avrcp_cb { * @param avrcp AVRCP connection object. */ void (*connected)(struct bt_avrcp *avrcp); + /** @brief An AVRCP connection has been disconnected. * * This callback notifies the application that an avrcp connection @@ -48,6 +150,7 @@ struct bt_avrcp_cb { * @param avrcp AVRCP connection object. */ void (*disconnected)(struct bt_avrcp *avrcp); + /** @brief Callback function for bt_avrcp_get_unit_info(). * * Called when the get unit info process is completed. @@ -56,6 +159,7 @@ struct bt_avrcp_cb { * @param rsp The response for UNIT INFO command. */ void (*unit_info_rsp)(struct bt_avrcp *avrcp, struct bt_avrcp_unit_info_rsp *rsp); + /** @brief Callback function for bt_avrcp_get_subunit_info(). * * Called when the get subunit info process is completed. @@ -64,6 +168,15 @@ struct bt_avrcp_cb { * @param rsp The response for SUBUNIT INFO command. */ void (*subunit_info_rsp)(struct bt_avrcp *avrcp, struct bt_avrcp_subunit_info_rsp *rsp); + + /** @brief Callback function for bt_avrcp_passthrough(). + * + * Called when a passthrough response is received. + * + * @param avrcp AVRCP connection object. + * @param rsp The response for PASS THROUGH command. + */ + void (*passthrough_rsp)(struct bt_avrcp *avrcp, struct bt_avrcp_passthrough_rsp *rsp); }; /** @brief Connect AVRCP. @@ -120,6 +233,22 @@ int bt_avrcp_get_unit_info(struct bt_avrcp *avrcp); */ int bt_avrcp_get_subunit_info(struct bt_avrcp *avrcp); +/** @brief Send AVRCP Pass Through command. + * + * This function send a pass through command to the remote device. Passsthhrough command is used + * to transfer user operation information from a CT to Panel subunit of TG. + * + * @param avrcp The AVRCP instance. + * @param operation_id The user operation id. + * @param state The button state. + * @param payload The payload of the pass through command. Should not be NULL if len is not zero. + * @param len The length of the payload. + * + * @return 0 in case of success or error code in case of error. + */ +int bt_avrcp_passthrough(struct bt_avrcp *avrcp, bt_avrcp_opid_t operation_id, + bt_avrcp_button_state_t state, const uint8_t *payload, uint8_t len); + #ifdef __cplusplus } #endif diff --git a/subsys/bluetooth/host/classic/avctp.c b/subsys/bluetooth/host/classic/avctp.c index aefe06f555cd8..19bc363f5b789 100644 --- a/subsys/bluetooth/host/classic/avctp.c +++ b/subsys/bluetooth/host/classic/avctp.c @@ -82,6 +82,7 @@ static int avctp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) uint8_t tid; bt_avctp_pkt_type_t pkt_type; bt_avctp_cr_t cr; + int err; if (buf->len < sizeof(*hdr)) { LOG_ERR("invalid AVCTP header received"); @@ -117,7 +118,13 @@ static int avctp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) if (!rsp) { return -ENOMEM; } - return bt_avctp_send(session, rsp); + + err = bt_avctp_send(session, rsp); + if (err < 0) { + net_buf_unref(rsp); + LOG_ERR("AVCTP send fail, err = %d", err); + return err; + } } return 0; /* No need to report to the upper layer */ } @@ -189,16 +196,7 @@ struct net_buf *bt_avctp_create_pdu(struct bt_avctp *session, bt_avctp_cr_t cr, int bt_avctp_send(struct bt_avctp *session, struct net_buf *buf) { - int err; - - err = bt_l2cap_chan_send(&session->br_chan.chan, buf); - if (err < 0) { - net_buf_unref(buf); - LOG_ERR("L2CAP send fail err = %d", err); - return err; - } - - return err; + return bt_l2cap_chan_send(&session->br_chan.chan, buf); } int bt_avctp_register(const struct bt_avctp_event_cb *cb) diff --git a/subsys/bluetooth/host/classic/avrcp.c b/subsys/bluetooth/host/classic/avrcp.c index 049bc84a35868..2e6bec2f0f0f4 100644 --- a/subsys/bluetooth/host/classic/avrcp.c +++ b/subsys/bluetooth/host/classic/avrcp.c @@ -260,7 +260,7 @@ static void avrcp_unit_info_handler(struct bt_avrcp *avrcp, struct net_buf *buf, if ((avrcp_cb != NULL) && (avrcp_cb->unit_info_rsp != NULL)) { net_buf_pull(buf, sizeof(*avrcp_hdr)); if (buf->len != 5) { - LOG_ERR("Invalid unit info length"); + LOG_ERR("Invalid unit info length: %d", buf->len); return; } net_buf_pull_u8(buf); /* Always 0x07 */ @@ -284,7 +284,7 @@ static void avrcp_subunit_info_handler(struct bt_avrcp *avrcp, struct net_buf *b if ((avrcp_cb != NULL) && (avrcp_cb->subunit_info_rsp != NULL)) { net_buf_pull(buf, sizeof(*avrcp_hdr)); if (buf->len < 5) { - LOG_ERR("Invalid subunit info length"); + LOG_ERR("Invalid subunit info length: %d", buf->len); return; } net_buf_pull_u8(buf); /* Always 0x07 */ @@ -305,7 +305,31 @@ static void avrcp_subunit_info_handler(struct bt_avrcp *avrcp, struct net_buf *b static void avrcp_pass_through_handler(struct bt_avrcp *avrcp, struct net_buf *buf, bt_avctp_cr_t cr) { - /* ToDo */ + struct bt_avrcp_header *avrcp_hdr; + struct bt_avrcp_passthrough_rsp rsp; + uint8_t tmp; + + if (cr == BT_AVCTP_CMD) { + /* ToDo */ + } else { /* BT_AVCTP_RESPONSE */ + if ((avrcp_cb != NULL) && (avrcp_cb->subunit_info_rsp != NULL)) { + avrcp_hdr = (struct bt_avrcp_header *)buf->data; + net_buf_pull(buf, sizeof(*avrcp_hdr)); + if (buf->len < 2) { + LOG_ERR("Invalid passthrough length: %d", buf->len); + return; + } + + rsp.response = BT_AVRCP_HDR_GET_CTYPE_OR_RSP(avrcp_hdr); + tmp = net_buf_pull_u8(buf); + rsp.operation_id = FIELD_GET(GENMASK(6, 0), tmp); + rsp.state = FIELD_GET(GENMASK(7, 7), tmp); + rsp.len = net_buf_pull_u8(buf); + rsp.payload = rsp.len ? buf->data : NULL; + + avrcp_cb->passthrough_rsp(avrcp, &rsp); + } + } } static const struct avrcp_handler handler[] = { @@ -323,7 +347,7 @@ static int avrcp_recv(struct bt_avctp *session, struct net_buf *buf) struct bt_avrcp_header *avrcp_hdr; uint8_t tid, i; bt_avctp_cr_t cr; - bt_avrcp_ctype_t ctype; + bt_avrcp_rsp_t rsp; bt_avrcp_subunit_id_t subunit_id; bt_avrcp_subunit_type_t subunit_type; @@ -337,7 +361,7 @@ static int avrcp_recv(struct bt_avctp *session, struct net_buf *buf) avrcp_hdr = (void *)buf->data; tid = BT_AVCTP_HDR_GET_TRANSACTION_LABLE(avctp_hdr); cr = BT_AVCTP_HDR_GET_CR(avctp_hdr); - ctype = BT_AVRCP_HDR_GET_CTYPE(avrcp_hdr); + rsp = BT_AVRCP_HDR_GET_CTYPE_OR_RSP(avrcp_hdr); subunit_id = BT_AVRCP_HDR_GET_SUBUNIT_ID(avrcp_hdr); subunit_type = BT_AVRCP_HDR_GET_SUBUNIT_TYPE(avrcp_hdr); @@ -345,11 +369,11 @@ static int avrcp_recv(struct bt_avctp *session, struct net_buf *buf) return -EINVAL; /* Ignore other profile */ } - LOG_DBG("AVRCP msg received, cr:0x%X, tid:0x%X, ctype: 0x%X, opc:0x%02X,", cr, tid, ctype, + LOG_DBG("AVRCP msg received, cr:0x%X, tid:0x%X, rsp: 0x%X, opc:0x%02X,", cr, tid, rsp, avrcp_hdr->opcode); if (cr == BT_AVCTP_RESPONSE) { if (avrcp_hdr->opcode == BT_AVRCP_OPC_VENDOR_DEPENDENT && - ctype == BT_AVRCP_CTYPE_CHANGED) { + rsp == BT_AVRCP_RSP_CHANGED) { /* Status changed notifiation, do not reset timer */ } else if (avrcp_hdr->opcode == BT_AVRCP_OPC_PASS_THROUGH) { /* No max response time for pass through commands */ @@ -474,17 +498,17 @@ static struct net_buf *avrcp_create_pdu(struct bt_avrcp *avrcp, bt_avctp_cr_t cr static struct net_buf *avrcp_create_unit_pdu(struct bt_avrcp *avrcp, bt_avctp_cr_t cr) { struct net_buf *buf; - struct bt_avrcp_unit_info_cmd *cmd; + struct bt_avrcp_frame *cmd; buf = avrcp_create_pdu(avrcp, cr); if (!buf) { - return buf; + return NULL; } cmd = net_buf_add(buf, sizeof(*cmd)); memset(cmd, 0, sizeof(*cmd)); - BT_AVRCP_HDR_SET_CTYPE(&cmd->hdr, cr == BT_AVCTP_CMD ? BT_AVRCP_CTYPE_STATUS - : BT_AVRCP_CTYPE_IMPLEMENTED_STABLE); + BT_AVRCP_HDR_SET_CTYPE_OR_RSP(&cmd->hdr, cr == BT_AVCTP_CMD ? BT_AVRCP_CTYPE_STATUS + : BT_AVRCP_RSP_STABLE); BT_AVRCP_HDR_SET_SUBUNIT_ID(&cmd->hdr, BT_AVRCP_SUBUNIT_ID_IGNORE); BT_AVRCP_HDR_SET_SUBUNIT_TYPE(&cmd->hdr, BT_AVRCP_SUBUNIT_TYPE_UNIT); cmd->hdr.opcode = BT_AVRCP_OPC_UNIT_INFO; @@ -495,17 +519,17 @@ static struct net_buf *avrcp_create_unit_pdu(struct bt_avrcp *avrcp, bt_avctp_cr static struct net_buf *avrcp_create_subunit_pdu(struct bt_avrcp *avrcp, bt_avctp_cr_t cr) { struct net_buf *buf; - struct bt_avrcp_unit_info_cmd *cmd; + struct bt_avrcp_frame *cmd; buf = avrcp_create_pdu(avrcp, cr); if (!buf) { - return buf; + return NULL; } cmd = net_buf_add(buf, sizeof(*cmd)); memset(cmd, 0, sizeof(*cmd)); - BT_AVRCP_HDR_SET_CTYPE(&cmd->hdr, cr == BT_AVCTP_CMD ? BT_AVRCP_CTYPE_STATUS - : BT_AVRCP_CTYPE_IMPLEMENTED_STABLE); + BT_AVRCP_HDR_SET_CTYPE_OR_RSP(&cmd->hdr, cr == BT_AVCTP_CMD ? BT_AVRCP_CTYPE_STATUS + : BT_AVRCP_RSP_STABLE); BT_AVRCP_HDR_SET_SUBUNIT_ID(&cmd->hdr, BT_AVRCP_SUBUNIT_ID_IGNORE); BT_AVRCP_HDR_SET_SUBUNIT_TYPE(&cmd->hdr, BT_AVRCP_SUBUNIT_TYPE_UNIT); cmd->hdr.opcode = BT_AVRCP_OPC_SUBUNIT_INFO; @@ -513,6 +537,27 @@ static struct net_buf *avrcp_create_subunit_pdu(struct bt_avrcp *avrcp, bt_avctp return buf; } +static struct net_buf *avrcp_create_passthrough_pdu(struct bt_avrcp *avrcp, bt_avctp_cr_t cr, + bt_avrcp_ctype_t ctype) +{ + struct net_buf *buf; + struct bt_avrcp_frame *cmd; + + buf = avrcp_create_pdu(avrcp, cr); + if (!buf) { + return NULL; + } + + cmd = net_buf_add(buf, sizeof(*cmd)); + memset(cmd, 0, sizeof(*cmd)); + BT_AVRCP_HDR_SET_CTYPE_OR_RSP(&cmd->hdr, ctype); + BT_AVRCP_HDR_SET_SUBUNIT_ID(&cmd->hdr, BT_AVRCP_SUBUNIT_ID_ZERO); + BT_AVRCP_HDR_SET_SUBUNIT_TYPE(&cmd->hdr, BT_AVRCP_SUBUNIT_TYPE_PANEL); + cmd->hdr.opcode = BT_AVRCP_OPC_PASS_THROUGH; + + return buf; +} + static int avrcp_send(struct bt_avrcp *avrcp, struct net_buf *buf) { int err; @@ -521,13 +566,15 @@ static int avrcp_send(struct bt_avrcp *avrcp, struct net_buf *buf) (struct bt_avrcp_header *)(buf->data + sizeof(*avctp_hdr)); uint8_t tid = BT_AVCTP_HDR_GET_TRANSACTION_LABLE(avctp_hdr); bt_avctp_cr_t cr = BT_AVCTP_HDR_GET_CR(avctp_hdr); - bt_avrcp_ctype_t ctype = BT_AVRCP_HDR_GET_CTYPE(avrcp_hdr); + bt_avrcp_ctype_t ctype = BT_AVRCP_HDR_GET_CTYPE_OR_RSP(avrcp_hdr); bt_avrcp_subunit_type_t subunit_type = BT_AVRCP_HDR_GET_SUBUNIT_TYPE(avrcp_hdr); LOG_DBG("AVRCP send cr:0x%X, tid:0x%X, ctype: 0x%X, opc:0x%02X\n", cr, tid, ctype, avrcp_hdr->opcode); err = bt_avctp_send(&(avrcp->session), buf); if (err < 0) { + net_buf_unref(buf); + LOG_ERR("AVCTP send fail, err = %d", err); return err; } @@ -576,6 +623,27 @@ int bt_avrcp_get_subunit_info(struct bt_avrcp *avrcp) return avrcp_send(avrcp, buf); } +int bt_avrcp_passthrough(struct bt_avrcp *avrcp, bt_avrcp_opid_t operation_id, + bt_avrcp_button_state_t state, const uint8_t *payload, uint8_t len) +{ + struct net_buf *buf; + uint8_t param[2]; + + buf = avrcp_create_passthrough_pdu(avrcp, BT_AVCTP_CMD, BT_AVRCP_CTYPE_CONTROL); + if (!buf) { + return -ENOMEM; + } + + param[0] = FIELD_PREP(GENMASK(7, 7), state) | FIELD_PREP(GENMASK(6, 0), operation_id); + param[1] = len; + net_buf_add_mem(buf, param, sizeof(param)); + if (len) { + net_buf_add_mem(buf, payload, len); + } + + return avrcp_send(avrcp, buf); +} + int bt_avrcp_register_cb(const struct bt_avrcp_cb *cb) { avrcp_cb = cb; diff --git a/subsys/bluetooth/host/classic/avrcp_internal.h b/subsys/bluetooth/host/classic/avrcp_internal.h index cbfcc8e824f79..e1e6922f8e80a 100644 --- a/subsys/bluetooth/host/classic/avrcp_internal.h +++ b/subsys/bluetooth/host/classic/avrcp_internal.h @@ -20,21 +20,6 @@ #define AVRCP_SUBUNIT_PAGE (0) /* Fixed value according to AVRCP */ #define AVRCP_SUBUNIT_EXTENSION_COED (7) /* Fixed value according to TA Document 2001012 */ -typedef enum __packed { - BT_AVRCP_CTYPE_CONTROL = 0x0, - BT_AVRCP_CTYPE_STATUS = 0x1, - BT_AVRCP_CTYPE_SPECIFIC_INQUIRY = 0x2, - BT_AVRCP_CTYPE_NOTIFY = 0x3, - BT_AVRCP_CTYPE_GENERAL_INQUIRY = 0x4, - BT_AVRCP_CTYPE_NOT_IMPLEMENTED = 0x8, - BT_AVRCP_CTYPE_ACCEPTED = 0x9, - BT_AVRCP_CTYPE_REJECTED = 0xA, - BT_AVRCP_CTYPE_IN_TRANSITION = 0xB, - BT_AVRCP_CTYPE_IMPLEMENTED_STABLE = 0xC, - BT_AVRCP_CTYPE_CHANGED = 0xD, - BT_AVRCP_CTYPE_INTERIM = 0xF, -} bt_avrcp_ctype_t; - typedef enum __packed { BT_AVRCP_SUBUNIT_ID_ZERO = 0x0, BT_AVRCP_SUBUNIT_ID_IGNORE = 0x7, @@ -65,7 +50,7 @@ struct bt_avrcp_header { } __packed; /** The 4-bit command type or the 4-bit response code. */ -#define BT_AVRCP_HDR_GET_CTYPE(hdr) FIELD_GET(GENMASK(3, 0), ((hdr)->byte0)) +#define BT_AVRCP_HDR_GET_CTYPE_OR_RSP(hdr) FIELD_GET(GENMASK(3, 0), ((hdr)->byte0)) /** Taken together, the subunit_type and subunit_ID fields define the command recipient’s address * within the target. These fields enable the target to determine whether the command is * addressed to the target unit, or to a specific subunit within the target. The values in these @@ -80,7 +65,7 @@ struct bt_avrcp_header { #define BT_AVRCP_HDR_GET_SUBUNIT_TYPE(hdr) FIELD_GET(GENMASK(7, 3), ((hdr)->byte1)) /** The 4-bit command type or the 4-bit response code. */ -#define BT_AVRCP_HDR_SET_CTYPE(hdr, ctype) \ +#define BT_AVRCP_HDR_SET_CTYPE_OR_RSP(hdr, ctype) \ (hdr)->byte0 = (((hdr)->byte0) & ~GENMASK(3, 0)) | FIELD_PREP(GENMASK(3, 0), (ctype)) /** Taken together, the subunit_type and subunit_ID fields define the command recipient’s address * within the target. These fields enable the target to determine whether the command is @@ -97,7 +82,7 @@ struct bt_avrcp_header { #define BT_AVRCP_HDR_SET_SUBUNIT_TYPE(hdr, subunit_type) \ (hdr)->byte1 = (((hdr)->byte1) & ~GENMASK(7, 3)) | FIELD_PREP(GENMASK(7, 3), (subunit_type)) -struct bt_avrcp_unit_info_cmd { +struct bt_avrcp_frame { struct bt_avrcp_header hdr; uint8_t data[0]; } __packed; diff --git a/subsys/bluetooth/host/classic/shell/avrcp.c b/subsys/bluetooth/host/classic/shell/avrcp.c index d427f2e5c75be..b3b580ab3e8e6 100644 --- a/subsys/bluetooth/host/classic/shell/avrcp.c +++ b/subsys/bluetooth/host/classic/shell/avrcp.c @@ -61,11 +61,25 @@ static void avrcp_subunit_info_rsp(struct bt_avrcp *avrcp, struct bt_avrcp_subun } } +static void avrcp_passthrough_rsp(struct bt_avrcp *avrcp, struct bt_avrcp_passthrough_rsp *rsp) +{ + if (rsp->response == BT_AVRCP_RSP_ACCEPTED) { + bt_shell_print( + "AVRCP passthough command accepted, operation id = 0x%02x, state = %d", + rsp->operation_id, rsp->state); + } else { + bt_shell_print("AVRCP passthough command rejected, operation id = 0x%02x, state = " + "%d, response = %d", + rsp->operation_id, rsp->state, rsp->response); + } +} + static struct bt_avrcp_cb avrcp_cb = { .connected = avrcp_connected, .disconnected = avrcp_disconnected, .unit_info_rsp = avrcp_unit_info_rsp, .subunit_info_rsp = avrcp_subunit_info_rsp, + .passthrough_rsp = avrcp_passthrough_rsp, }; static int register_cb(const struct shell *sh) @@ -172,15 +186,47 @@ static int cmd_get_subunit_info(const struct shell *sh, int32_t argc, char *argv return 0; } -SHELL_STATIC_SUBCMD_SET_CREATE(avrcp_cmds, - SHELL_CMD_ARG(register_cb, NULL, "register avrcp callbacks", - cmd_register_cb, 1, 0), - SHELL_CMD_ARG(connect, NULL, "

", cmd_connect, 2, 0), - SHELL_CMD_ARG(disconnect, NULL, "
", cmd_disconnect, 2, 0), - SHELL_CMD_ARG(get_unit, NULL, "
", cmd_get_unit_info, 2, 0), - SHELL_CMD_ARG(get_subunit, NULL, "
", cmd_get_subunit_info, - 2, 0), - SHELL_SUBCMD_SET_END); +static int cmd_passthrough(const struct shell *sh, bt_avrcp_opid_t operation_id, + const uint8_t *payload, uint8_t len) +{ + if (!avrcp_registered) { + if (register_cb(sh) != 0) { + return -ENOEXEC; + } + } + + if (default_avrcp != NULL) { + bt_avrcp_passthrough(default_avrcp, operation_id, BT_AVRCP_BUTTON_PRESSED, payload, + len); + bt_avrcp_passthrough(default_avrcp, operation_id, BT_AVRCP_BUTTON_RELEASED, payload, + len); + } else { + shell_error(sh, "AVRCP is not connected"); + } + + return 0; +} + +static int cmd_play(const struct shell *sh, int32_t argc, char *argv[]) +{ + return cmd_passthrough(sh, BT_AVRCP_OPID_PLAY, NULL, 0); +} + +static int cmd_pause(const struct shell *sh, int32_t argc, char *argv[]) +{ + return cmd_passthrough(sh, BT_AVRCP_OPID_PAUSE, NULL, 0); +} + +SHELL_STATIC_SUBCMD_SET_CREATE( + avrcp_cmds, + SHELL_CMD_ARG(register_cb, NULL, "register avrcp callbacks", cmd_register_cb, 1, 0), + SHELL_CMD_ARG(connect, NULL, "connect AVRCP", cmd_connect, 1, 0), + SHELL_CMD_ARG(disconnect, NULL, "disconnect AVRCP", cmd_disconnect, 1, 0), + SHELL_CMD_ARG(get_unit, NULL, "get unit info", cmd_get_unit_info, 1, 0), + SHELL_CMD_ARG(get_subunit, NULL, "get subunit info", cmd_get_subunit_info, 1, 0), + SHELL_CMD_ARG(play, NULL, "request a play at the remote player", cmd_play, 1, 0), + SHELL_CMD_ARG(pause, NULL, "request a pause at the remote player", cmd_pause, 1, 0), + SHELL_SUBCMD_SET_END); static int cmd_avrcp(const struct shell *sh, size_t argc, char **argv) { From eb93df219703754753d542f668e404db44700cfa Mon Sep 17 00:00:00 2001 From: "Bansidhar P.M" Date: Mon, 10 Feb 2025 12:44:02 +0530 Subject: [PATCH 0253/6055] dts: nordic: Add wifi_spi label Add wifi_spi label to nRF54h and nRF54l dts files to help in shield overlay files Signed-off-by: Bansidhar P.M --- boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi | 3 +++ boards/nordic/nrf54l15dk/nrf54l15dk_common.dtsi | 3 +++ 2 files changed, 6 insertions(+) diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi index 0c5307c4c8c25..b0cb997de9477 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi @@ -16,3 +16,6 @@ &lfxo { status = "okay"; }; + +/* Get a node label for wi-fi spi to use in shield files */ +wifi_spi: &spi130 {}; diff --git a/boards/nordic/nrf54l15dk/nrf54l15dk_common.dtsi b/boards/nordic/nrf54l15dk/nrf54l15dk_common.dtsi index 33cfebb55d6e6..6a40af0ee95d7 100644 --- a/boards/nordic/nrf54l15dk/nrf54l15dk_common.dtsi +++ b/boards/nordic/nrf54l15dk/nrf54l15dk_common.dtsi @@ -98,3 +98,6 @@ pinctrl-1 = <&pwm20_sleep>; pinctrl-names = "default", "sleep"; }; + +/* Get a node label for wi-fi spi to use in shield files */ +wifi_spi: &spi22 {}; From 22b52879051823d039e1da73fbcca1b75ffa897d Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Mon, 3 Feb 2025 15:04:37 +0700 Subject: [PATCH 0254/6055] manifest: Update commit for hal_renesas support RA4L1 Update commit ID for hal_renesas to support RA4L1 Signed-off-by: Thao Luong --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 4c1dcaeb63bb3..1df4665d7c0c7 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: - hal - name: hal_renesas path: modules/hal/renesas - revision: 3237c5db010a3137c67ebc9bcdb911f07557fb3c + revision: bcbd9fe909b9da739a2e61adddcc1a30fba7774d groups: - hal - name: hal_rpi_pico From 0b97890163dec2b7c16c3aeda7cfe5d0cbd556e0 Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Sun, 12 Jan 2025 23:35:48 +0700 Subject: [PATCH 0255/6055] soc: renesas: ra: Add minimal support for ra4l1 Add minimal support for RA4L1 SoC and devicetree Signed-off-by: Thao Luong --- dts/arm/renesas/ra/ra4/r7fa4l1bd4cfp.dtsi | 33 + dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi | 746 ++++++++++++++++++++++ soc/renesas/ra/ra4l1/CMakeLists.txt | 12 + soc/renesas/ra/ra4l1/Kconfig | 16 + soc/renesas/ra/ra4l1/Kconfig.defconfig | 20 + soc/renesas/ra/ra4l1/Kconfig.soc | 20 + soc/renesas/ra/ra4l1/sections.ld | 77 +++ soc/renesas/ra/ra4l1/soc.c | 62 ++ soc/renesas/ra/ra4l1/soc.h | 16 + soc/renesas/ra/soc.yml | 3 + 10 files changed, 1005 insertions(+) create mode 100644 dts/arm/renesas/ra/ra4/r7fa4l1bd4cfp.dtsi create mode 100644 dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi create mode 100644 soc/renesas/ra/ra4l1/CMakeLists.txt create mode 100644 soc/renesas/ra/ra4l1/Kconfig create mode 100644 soc/renesas/ra/ra4l1/Kconfig.defconfig create mode 100644 soc/renesas/ra/ra4l1/Kconfig.soc create mode 100644 soc/renesas/ra/ra4l1/sections.ld create mode 100644 soc/renesas/ra/ra4l1/soc.c create mode 100644 soc/renesas/ra/ra4l1/soc.h diff --git a/dts/arm/renesas/ra/ra4/r7fa4l1bd4cfp.dtsi b/dts/arm/renesas/ra/ra4/r7fa4l1bd4cfp.dtsi new file mode 100644 index 0000000000000..af5aa03a53dac --- /dev/null +++ b/dts/arm/renesas/ra/ra4/r7fa4l1bd4cfp.dtsi @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + flash-controller@407e0000 { + reg = <0x407e0000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "renesas,ra-nv-flash"; + reg = <0x0 DT_SIZE_K(512)>; + write-block-size = <8>; + erase-block-size = <2048>; + renesas,programming-enable; + }; + + flash1: flash@8000000 { + compatible = "renesas,ra-nv-flash"; + reg = <0x8000000 DT_SIZE_K(8)>; + write-block-size = <1>; + erase-block-size = <256>; + renesas,programming-enable; + }; + }; + }; +}; diff --git a/dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi b/dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi new file mode 100644 index 0000000000000..197144ab337be --- /dev/null +++ b/dts/arm/renesas/ra/ra4/r7fa4l1bx.dtsi @@ -0,0 +1,746 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m33"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + + mpu: mpu@e000ed90 { + compatible = "arm,armv8m-mpu"; + reg = <0xe000ed90 0x40>; + }; + }; + }; + + soc { + interrupt-parent = <&nvic>; + + system: system@4001e000 { + compatible = "renesas,ra-system"; + reg = <0x4001e000 0x1000>; + status = "okay"; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(64)>; + }; + + ioport0: gpio@4001f000 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x4001f000 0x20>; + port = <0>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport1: gpio@4001f020 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x4001f020 0x20>; + port = <1>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport2: gpio@4001f040 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x4001f040 0x20>; + port = <2>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport3: gpio@4001f060 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x4001f060 0x20>; + port = <3>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport4: gpio@4001f080 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x4001f080 0x20>; + port = <4>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport5: gpio@4001f0a0 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x4001f0a0 0x20>; + port = <5>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport6: gpio@4001f0c0 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x4001f0c0 0x20>; + port = <6>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport7: gpio@4001f0e0 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x4001f0e0 0x20>; + port = <7>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport8: gpio@4001f100 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x4001f100 0x20>; + port = <8>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + pinctrl: pin-controller@4001F800 { + compatible = "renesas,ra-pinctrl-pfs"; + reg = <0x4001F800 0x3c0>; + status = "okay"; + }; + + sci0: sci@40118000 { + compatible = "renesas,ra-sci"; + reg = <0x40118000 0x100>; + clocks = <&pclka MSTPB 31>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <0>; + status = "disabled"; + }; + }; + + sci1: sci@40118100 { + compatible = "renesas,ra-sci"; + reg = <0x40118100 0x100>; + clocks = <&pclka MSTPB 30>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <1>; + status = "disabled"; + }; + }; + + sci3: sci@40118300 { + compatible = "renesas,ra-sci"; + reg = <0x40118300 0x100>; + clocks = <&pclka MSTPB 38>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <3>; + status = "disabled"; + }; + }; + + sci4: sci@40118400 { + compatible = "renesas,ra-sci"; + reg = <0x40118400 0x100>; + clocks = <&pclka MSTPB 27>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <4>; + status = "disabled"; + }; + }; + + sci5: sci@40118500 { + compatible = "renesas,ra-sci"; + interrupts = <4 1>, <5 1>, <6 1>, <7 1>; + interrupt-names = "rxi", "txi", "tei", "eri"; + reg = <0x40118500 0x100>; + clocks = <&pclka MSTPB 26>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <5>; + status = "disabled"; + }; + }; + + sci9: sci@40118900 { + compatible = "renesas,ra-sci"; + interrupts = <24 1>, <25 1>, <26 1>, <27 1>; + interrupt-names = "rxi", "txi", "tei", "eri"; + reg = <0x40118900 0x100>; + clocks = <&pclka MSTPB 22>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <9>; + status = "disabled"; + }; + }; + + spi0: spi@4011a000 { + compatible = "renesas,ra-spi"; + #address-cells = <1>; + #size-cells = <0>; + channel = <0>; + interrupts = <28 1>, <29 1>, <30 1>, <31 1>; + interrupt-names = "rxi", "txi", "tei", "eri"; + reg = <0x4011a000 0x100>; + status = "disabled"; + }; + + adc0: adc@40170000 { + compatible = "renesas,ra-adc"; + interrupts = <38 1>; + interrupt-names = "scanend"; + reg = <0x40170000 0x100>; + #io-channel-cells = <1>; + vref-mv = <3300>; + channel-count = <16>; + channel-available-mask = <0x3fe007f>; + status = "disabled"; + }; + + iic0: iic0@4009f000 { + compatible = "renesas,ra-iic"; + channel = <0>; + reg = <0x4009f000 0x100>; + status = "disabled"; + }; + + pwm0: pwm0@40169000 { + compatible = "renesas,ra-pwm"; + divider = ; + channel = ; + clocks = <&pclkd MSTPE 31>; + reg = <0x40169000 0x100>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm1: pwm1@40169100 { + compatible = "renesas,ra-pwm"; + divider = ; + channel = ; + clocks = <&pclkd MSTPE 30>; + reg = <0x40169100 0x100>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm2: pwm2@40169200 { + compatible = "renesas,ra-pwm"; + divider = ; + channel = ; + clocks = <&pclkd MSTPE 29>; + reg = <0x40169200 0x100>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm3: pwm3@40169300 { + compatible = "renesas,ra-pwm"; + divider = ; + channel = ; + clocks = <&pclkd MSTPE 28>; + reg = <0x40169300 0x100>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm4: pwm4@40169400 { + compatible = "renesas,ra-pwm"; + divider = ; + channel = ; + clocks = <&pclkd MSTPE 27>; + reg = <0x40169400 0x100>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm5: pwm5@40169500 { + compatible = "renesas,ra-pwm"; + divider = ; + channel = ; + clocks = <&pclkd MSTPE 26>; + reg = <0x40169500 0x100>; + #pwm-cells = <3>; + status = "disabled"; + }; + + canfd_global: canfd_global@400b0000 { + compatible = "renesas,ra-canfd-global"; + interrupts = <40 1>, <41 1>; + interrupt-names = "rxf", "glerr"; + clocks = <&pclkb 0 0>, <&pclka 0 0>; + clock-names = "opclk", "ramclk"; + reg = <0x400b0000 0x2000>; + status = "disabled"; + + canfd0: canfd0 { + compatible = "renesas,ra-canfd"; + channel = <0>; + interrupts = <43 12>, <44 12>, <45 12>; + interrupt-names = "err", "tx", "rx"; + clocks = <&canfdclk MSTPC 27>; + clock-names = "dllclk"; + status = "disabled"; + }; + }; + + option_setting_ofs: option_setting_ofs@100a100 { + compatible = "zephyr,memory-region"; + reg = <0x0100a100 0x18>; + zephyr,memory-region = "OPTION_SETTING_OFS"; + status = "okay"; + }; + + option_setting_sas: option_setting_sas@100a134 { + compatible = "zephyr,memory-region"; + reg = <0x0100a134 0xcc>; + zephyr,memory-region = "OPTION_SETTING_SAS"; + status = "okay"; + }; + + option_setting_s: option_setting_s@100a200 { + compatible = "zephyr,memory-region"; + reg = <0x0100a200 0x100>; + zephyr,memory-region = "OPTION_SETTING_S"; + status = "okay"; + }; + + port_irq0: external-interrupt@40006000 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006000 0x1>; + channel = <0>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq1: external-interrupt@40006001 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006001 0x1>; + channel = <1>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq2: external-interrupt@40006002 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006002 0x1>; + channel = <2>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq3: external-interrupt@40006003 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006003 0x1>; + channel = <3>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq4: external-interrupt@40006004 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006004 0x1>; + channel = <4>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq5: external-interrupt@40006005 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006005 0x1>; + channel = <5>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq6: external-interrupt@40006006 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006006 0x1>; + channel = <6>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq7: external-interrupt@40006007 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006007 0x1>; + channel = <7>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq8: external-interrupt@40006008 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006008 0x1>; + channel = <8>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq9: external-interrupt@40006009 { + compatible = "renesas,ra-external-interrupt"; + reg = <0x40006009 0x1>; + channel = <9>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq10: external-interrupt@4000600a { + compatible = "renesas,ra-external-interrupt"; + reg = <0x4000600a 0x1>; + channel = <10>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq11: external-interrupt@4000600b { + compatible = "renesas,ra-external-interrupt"; + reg = <0x4000600b 0x1>; + channel = <11>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq12: external-interrupt@4000600c { + compatible = "renesas,ra-external-interrupt"; + reg = <0x4000600c 0x1>; + channel = <12>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq13: external-interrupt@4000600d { + compatible = "renesas,ra-external-interrupt"; + reg = <0x4000600d 0x1>; + channel = <13>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq14: external-interrupt@4000600e { + compatible = "renesas,ra-external-interrupt"; + reg = <0x4000600e 0x1>; + channel = <14>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + port_irq15: external-interrupt@4000600f { + compatible = "renesas,ra-external-interrupt"; + reg = <0x4000600f 0x1>; + channel = <15>; + renesas,sample-clock-div = <64>; + #port-irq-cells = <0>; + status = "disabled"; + }; + + }; + + clocks: clocks { + #address-cells = <1>; + #size-cells = <1>; + + xtal: clock-main-osc { + compatible = "renesas,ra-cgc-external-clock"; + clock-frequency = ; + #clock-cells = <0>; + status = "disabled"; + }; + + hoco: clock-hoco { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + loco: clock-loco { + compatible = "fixed-clock"; + clock-frequency = <32768>; + #clock-cells = <0>; + }; + + moco: clock-moco { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + subclk: clock-subclk { + compatible = "renesas,ra-cgc-subclk"; + clock-frequency = <32768>; + #clock-cells = <0>; + status = "disabled"; + }; + + pll: pll { + compatible = "renesas,ra-cgc-pll"; + #clock-cells = <0>; + + /* PLL */ + clocks = <&xtal>; + div = <1>; + mul = <10 0>; + status = "disabled"; + }; + + pclkblock: pclkblock@40084000 { + compatible = "renesas,ra-cgc-pclk-block"; + reg = <0x40084000 4>, <0x40084004 4>, <0x40084008 4>, + <0x4008400c 4>, <0x40084010 4>; + reg-names = "MSTPA", "MSTPB","MSTPC", + "MSTPD", "MSTPE"; + #clock-cells = <0>; + clocks = <&pll>; + status = "okay"; + + iclk: iclk { + compatible = "renesas,ra-cgc-pclk"; + clock-frequency = <80000000>; + div = <1>; + #clock-cells = <2>; + status = "okay"; + }; + + pclka: pclka { + compatible = "renesas,ra-cgc-pclk"; + div = <1>; + #clock-cells = <2>; + status = "okay"; + }; + + pclkb: pclkb { + compatible = "renesas,ra-cgc-pclk"; + div = <2>; + #clock-cells = <2>; + status = "okay"; + }; + + pclkc: pclkc { + compatible = "renesas,ra-cgc-pclk"; + div = <2>; + #clock-cells = <2>; + status = "okay"; + }; + + pclkd: pclkd { + compatible = "renesas,ra-cgc-pclk"; + div = <1>; + #clock-cells = <2>; + status = "okay"; + }; + + fclk: fclk { + compatible = "renesas,ra-cgc-pclk"; + div = <2>; + #clock-cells = <2>; + status = "okay"; + }; + + clkout: clkout { + compatible = "renesas,ra-cgc-pclk"; + #clock-cells = <2>; + status = "disabled"; + }; + + uclk: uclk { + compatible = "renesas,ra-cgc-pclk"; + #clock-cells = <2>; + status = "disabled"; + }; + + canfdclk: canfdclk { + compatible = "renesas,ra-cgc-pclk"; + #clock-cells = <2>; + status = "disabled"; + }; + + i3cclk: i3cclk { + compatible = "renesas,ra-cgc-pclk"; + #clock-cells = <2>; + status = "disabled"; + }; + + uarta0: uarta0 { + compatible = "renesas,ra-cgc-pclk"; + #clock-cells = <2>; + status = "disabled"; + }; + + uarta1: uarta1 { + compatible = "renesas,ra-cgc-pclk"; + #clock-cells = <2>; + status = "disabled"; + }; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; + +&ioport0 { + port-irqs = <&port_irq6 &port_irq7 &port_irq8 + &port_irq9 &port_irq10 &port_irq11>; + port-irq-names = "port-irq6", + "port-irq7", + "port-irq8", + "port-irq9", + "port-irq10", + "port-irq11"; + port-irq6-pins = <0>; + port-irq7-pins = <1>; + port-irq8-pins = <2>; + port-irq9-pins = <4>; + port-irq10-pins = <10>; + port-irq11-pins = <11>; +}; + +&ioport1 { + port-irqs = <&port_irq0 &port_irq1 &port_irq2 + &port_irq3 &port_irq4>; + port-irq-names = "port-irq0", + "port-irq1", + "port-irq2", + "port-irq3", + "port-irq4"; + port-irq0-pins = <5>; + port-irq1-pins = <1 4>; + port-irq2-pins = <0>; + port-irq3-pins = <10>; + port-irq4-pins = <11>; +}; + +&ioport2 { + port-irqs = <&port_irq0 &port_irq1 &port_irq2 + &port_irq3 &port_irq12>; + port-irq-names = "port-irq0", + "port-irq1", + "port-irq2", + "port-irq3", + "port-irq12"; + port-irq0-pins = <6>; + port-irq1-pins = <5>; + port-irq2-pins = <13>; + port-irq3-pins = <12>; + port-irq12-pins = <8>; +}; + +&ioport3 { + port-irqs = <&port_irq5 &port_irq6 + &port_irq8 &port_irq9>; + port-irq-names = "port-irq5", + "port-irq6", + "port-irq8", + "port-irq9"; + port-irq5-pins = <2>; + port-irq6-pins = <1>; + port-irq8-pins = <5>; + port-irq9-pins = <4>; +}; + +&ioport4 { + port-irqs = <&port_irq0 &port_irq4 &port_irq5 + &port_irq6 &port_irq7 &port_irq8 + &port_irq9 &port_irq14 &port_irq15>; + port-irq-names = "port-irq0", + "port-irq4", + "port-irq5", + "port-irq6", + "port-irq7", + "port-irq8", + "port-irq9", + "port-irq14", + "port-irq15"; + port-irq0-pins = <0>; + port-irq4-pins = <2 11>; + port-irq5-pins = <1 10>; + port-irq6-pins = <9>; + port-irq7-pins = <8>; + port-irq8-pins = <15>; + port-irq9-pins = <14>; + port-irq14-pins = <3>; + port-irq15-pins = <4>; +}; + +&ioport5 { + port-irqs = <&port_irq11 &port_irq12 &port_irq13 + &port_irq14>; + port-irq-names = "port-irq11", + "port-irq12", + "port-irq13", + "port-irq14"; + port-irq11-pins = <1>; + port-irq12-pins = <2>; + port-irq13-pins = <6>; + port-irq14-pins = <5>; +}; + +&ioport7 { + port-irqs = <&port_irq11>; + port-irq-names = "port-irq11"; + port-irq11-pins = <8>; +}; diff --git a/soc/renesas/ra/ra4l1/CMakeLists.txt b/soc/renesas/ra/ra4l1/CMakeLists.txt new file mode 100644 index 0000000000000..e6758812e492e --- /dev/null +++ b/soc/renesas/ra/ra4l1/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_sources( + soc.c +) + +zephyr_linker_sources(SECTIONS sections.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/renesas/ra/ra4l1/Kconfig b/soc/renesas/ra/ra4l1/Kconfig new file mode 100644 index 0000000000000..314e037d34e7b --- /dev/null +++ b/soc/renesas/ra/ra4l1/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RA4L1 + select ARM + select CPU_CORTEX_M33 + select CPU_HAS_ARM_MPU + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select FPU + select ARMV8_M_DSP + select HAS_SWO + select HAS_RENESAS_RA_FSP + select CLOCK_CONTROL_RENESAS_RA_CGC if CLOCK_CONTROL + select XIP + select SOC_EARLY_INIT_HOOK diff --git a/soc/renesas/ra/ra4l1/Kconfig.defconfig b/soc/renesas/ra/ra4l1/Kconfig.defconfig new file mode 100644 index 0000000000000..afa4ac00fd333 --- /dev/null +++ b/soc/renesas/ra/ra4l1/Kconfig.defconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RA4L1 + +config NUM_IRQS + default 64 + +DT_ICLK_PATH := $(dt_nodelabel_path,iclk) + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,$(DT_ICLK_PATH),clock-frequency) + +config BUILD_OUTPUT_HEX + default y + +config CLOCK_CONTROL + default y + +endif # SOC_SERIES_RA4L1 diff --git a/soc/renesas/ra/ra4l1/Kconfig.soc b/soc/renesas/ra/ra4l1/Kconfig.soc new file mode 100644 index 0000000000000..b7a8acf6714ac --- /dev/null +++ b/soc/renesas/ra/ra4l1/Kconfig.soc @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RA4L1 + bool + select SOC_FAMILY_RENESAS_RA + help + Renesas RA4L1 series + +config SOC_R7FA4L1BD4CFP + bool + select SOC_SERIES_RA4L1 + help + R7FA4L1BD4CFP + +config SOC_SERIES + default "ra4l1" if SOC_SERIES_RA4L1 + +config SOC + default "r7fa4l1bd4cfp" if SOC_R7FA4L1BD4CFP diff --git a/soc/renesas/ra/ra4l1/sections.ld b/soc/renesas/ra/ra4l1/sections.ld new file mode 100644 index 0000000000000..d9eb2cd4a9a34 --- /dev/null +++ b/soc/renesas/ra/ra4l1/sections.ld @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +SECTION_DATA_PROLOGUE(.fsp_dtc_vector_table,(NOLOAD),) +{ + /* If DTC is used, put the DTC vector table at the start of SRAM. + This avoids memory holes due to 1K alignment required by it. */ + *(.fsp_dtc_vector_table) +} GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_ofs), okay) +SECTION_PROLOGUE(.option_setting_ofs,,) +{ + __OPTION_SETTING_OFS_Start = .; + KEEP(*(.option_setting_ofs0)) + . = __OPTION_SETTING_OFS_Start + 0x04; + KEEP(*(.option_setting_ofs2)) + . = __OPTION_SETTING_OFS_Start + 0x10; + KEEP(*(.option_setting_dualsel)) + __OPTION_SETTING_OFS_End = .; +} GROUP_LINK_IN(OPTION_SETTING_OFS) = 0xFF +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_sas), okay) +SECTION_PROLOGUE(.option_setting_sas,,) +{ + __OPTION_SETTING_SAS_Start = .; + KEEP(*(.option_setting_sas)) + __OPTION_SETTING_SAS_End = .; +} GROUP_LINK_IN(OPTION_SETTING_SAS) = 0xFF +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_s), okay) +SECTION_PROLOGUE(.option_setting_s,,) +{ + __OPTION_SETTING_S_Start = .; + KEEP(*(.option_setting_ofs1_sec)) + . = __OPTION_SETTING_S_Start + 0x04; + KEEP(*(.option_setting_ofs3_sec)) + . = __OPTION_SETTING_S_Start + 0x10; + KEEP(*(.option_setting_banksel_sec)) + . = __OPTION_SETTING_S_Start + 0x40; + KEEP(*(.option_setting_bps_sec0)) + . = __OPTION_SETTING_S_Start + 0x44; + KEEP(*(.option_setting_bps_sec1)) + . = __OPTION_SETTING_S_Start + 0x48; + KEEP(*(.option_setting_bps_sec2)) + . = __OPTION_SETTING_S_Start + 0x4C; + KEEP(*(.option_setting_bps_sec3)) + . = __OPTION_SETTING_S_Start + 0x60; + KEEP(*(.option_setting_pbps_sec0)) + . = __OPTION_SETTING_S_Start + 0x64; + KEEP(*(.option_setting_pbps_sec1)) + . = __OPTION_SETTING_S_Start + 0x68; + KEEP(*(.option_setting_pbps_sec2)) + . = __OPTION_SETTING_S_Start + 0x6C; + KEEP(*(.option_setting_pbps_sec3)) + . = __OPTION_SETTING_S_Start + 0x80; + KEEP(*(.option_setting_ofs1_sel)) + . = __OPTION_SETTING_S_Start + 0x84; + KEEP(*(.option_setting_ofs3_sel)) + . = __OPTION_SETTING_S_Start + 0x90; + KEEP(*(.option_setting_banksel_sel)) + . = __OPTION_SETTING_S_Start + 0xC0; + KEEP(*(.option_setting_bps_sel0)) + . = __OPTION_SETTING_S_Start + 0xC4; + KEEP(*(.option_setting_bps_sel1)) + . = __OPTION_SETTING_S_Start + 0xC8; + KEEP(*(.option_setting_bps_sel2)) + . = __OPTION_SETTING_S_Start + 0xCC; + KEEP(*(.option_setting_bps_sel3)) + __OPTION_SETTING_S_End = .; +} GROUP_LINK_IN(OPTION_SETTING_S) = 0xFF +#endif diff --git a/soc/renesas/ra/ra4l1/soc.c b/soc/renesas/ra/ra4l1/soc.c new file mode 100644 index 0000000000000..b207d99c65fd0 --- /dev/null +++ b/soc/renesas/ra/ra4l1/soc.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System/hardware module for Renesas RA4L1 family processor + */ + +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + +#include "bsp_cfg.h" +#include "bsp_api.h" + +uint32_t SystemCoreClock BSP_SECTION_EARLY_INIT; + +volatile uint32_t g_protect_pfswe_counter BSP_SECTION_EARLY_INIT; + +/** + * @brief Perform basic hardware initialization at boot. + * + * This needs to be run from the very beginning. + */ +void soc_early_init_hook(void) +{ + extern volatile uint16_t g_protect_counters[]; + + for (uint32_t i = 0; i < 4; i++) { + g_protect_counters[i] = 0; + } + +#if FSP_PRIV_TZ_USE_SECURE_REGS + /* Disable protection using PRCR register. */ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_SAR); + + /* Initialize peripherals to secure mode for flat projects */ + R_PSCU->PSARB = 0; + R_PSCU->PSARC = 0; + R_PSCU->PSARD = 0; + R_PSCU->PSARE = 0; + + R_CPSCU->ICUSARG = 0; + R_CPSCU->ICUSARH = 0; + R_CPSCU->ICUSARI = 0; + + /* Enable protection using PRCR register. */ + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SAR); +#endif + + SystemCoreClock = BSP_MOCO_HZ; + g_protect_pfswe_counter = 0; +} diff --git a/soc/renesas/ra/ra4l1/soc.h b/soc/renesas/ra/ra4l1/soc.h new file mode 100644 index 0000000000000..cf99273edd374 --- /dev/null +++ b/soc/renesas/ra/ra4l1/soc.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the Renesas RA4L1 family MCU + */ + +#ifndef ZEPHYR_SOC_RENESAS_RA4L1_SOC_H_ +#define ZEPHYR_SOC_RENESAS_RA4L1_SOC_H_ + +#include + +#endif /* ZEPHYR_SOC_RENESAS_RA4L1_SOC_H_ */ diff --git a/soc/renesas/ra/soc.yml b/soc/renesas/ra/soc.yml index 29f0fc26ba9cf..7d73ed9269258 100644 --- a/soc/renesas/ra/soc.yml +++ b/soc/renesas/ra/soc.yml @@ -11,6 +11,9 @@ family: - name: ra4e2 socs: - name: r7fa4e2b93cfm + - name: ra4l1 + socs: + - name: r7fa4l1bd4cfp - name: ra4m1 socs: - name: r7fa4m1ab3cfm From 66cb6c6ff5c269651d6a1c0bd1fb3e0a1d98bc44 Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Mon, 13 Jan 2025 00:19:07 +0700 Subject: [PATCH 0256/6055] boards: renesas: Add minimal support for ek_ra4l1 Add minimal support for EK-RA4L1 Signed-off-by: Thao Luong --- boards/renesas/ek_ra4l1/Kconfig.ek_ra4l1 | 5 + boards/renesas/ek_ra4l1/board.cmake | 6 + boards/renesas/ek_ra4l1/board.yml | 6 + boards/renesas/ek_ra4l1/doc/ek_ra4l1.webp | Bin 0 -> 27824 bytes boards/renesas/ek_ra4l1/doc/index.rst | 151 +++++++++++++++ boards/renesas/ek_ra4l1/ek_ra4l1-pinctrl.dtsi | 58 ++++++ boards/renesas/ek_ra4l1/ek_ra4l1.dts | 182 ++++++++++++++++++ boards/renesas/ek_ra4l1/ek_ra4l1.yaml | 12 ++ boards/renesas/ek_ra4l1/ek_ra4l1_defconfig | 11 ++ 9 files changed, 431 insertions(+) create mode 100644 boards/renesas/ek_ra4l1/Kconfig.ek_ra4l1 create mode 100644 boards/renesas/ek_ra4l1/board.cmake create mode 100644 boards/renesas/ek_ra4l1/board.yml create mode 100644 boards/renesas/ek_ra4l1/doc/ek_ra4l1.webp create mode 100644 boards/renesas/ek_ra4l1/doc/index.rst create mode 100644 boards/renesas/ek_ra4l1/ek_ra4l1-pinctrl.dtsi create mode 100644 boards/renesas/ek_ra4l1/ek_ra4l1.dts create mode 100644 boards/renesas/ek_ra4l1/ek_ra4l1.yaml create mode 100644 boards/renesas/ek_ra4l1/ek_ra4l1_defconfig diff --git a/boards/renesas/ek_ra4l1/Kconfig.ek_ra4l1 b/boards/renesas/ek_ra4l1/Kconfig.ek_ra4l1 new file mode 100644 index 0000000000000..136246af8c750 --- /dev/null +++ b/boards/renesas/ek_ra4l1/Kconfig.ek_ra4l1 @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_EK_RA4L1 + select SOC_R7FA4L1BD4CFP diff --git a/boards/renesas/ek_ra4l1/board.cmake b/boards/renesas/ek_ra4l1/board.cmake new file mode 100644 index 0000000000000..ede2ff300bbcc --- /dev/null +++ b/boards/renesas/ek_ra4l1/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=R7FA4L1BD") + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/renesas/ek_ra4l1/board.yml b/boards/renesas/ek_ra4l1/board.yml new file mode 100644 index 0000000000000..d2e6b1bf6cbf7 --- /dev/null +++ b/boards/renesas/ek_ra4l1/board.yml @@ -0,0 +1,6 @@ +board: + name: ek_ra4l1 + full_name: RA4L1 Evaluation Kit + vendor: renesas + socs: + - name: r7fa4l1bd4cfp diff --git a/boards/renesas/ek_ra4l1/doc/ek_ra4l1.webp b/boards/renesas/ek_ra4l1/doc/ek_ra4l1.webp new file mode 100644 index 0000000000000000000000000000000000000000..219105795b04a91d9d55b54540e86afab5c5f4c4 GIT binary patch literal 27824 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 T-*Gd*_K0rj^6foH00000OUoK2 literal 0 HcmV?d00001 diff --git a/boards/renesas/ek_ra4l1/doc/index.rst b/boards/renesas/ek_ra4l1/doc/index.rst new file mode 100644 index 0000000000000..ffbeaedebfbe3 --- /dev/null +++ b/boards/renesas/ek_ra4l1/doc/index.rst @@ -0,0 +1,151 @@ +.. zephyr:board:: ek_ra4l1 + +RA4L1 Evaluation Kit +#################### + +Overview +******** + +The Renesas RA4L1 group of 32-bit microcontrollers (MCUs) uses the high-performance Arm +Cortex®-M33 core. Share a common set of Renesas peripherals to facilitate design scalability +and efficient platform-based product development. + +The MCU in this series incorporates a high-performance Arm Cortex®-M33 core running up to +80 MHz with the following features: + +**MCU Native Pin Access** + +- R7FA4L1BD4CFP MCU (referred to as RA MCU) +- 80 MHz, Arm® Cortex®-M33 core +- 512 KB Code Flash, 64 KB SRAM +- 100-pin LQFP package + +**System Control and Ecosystem Access** + +- USB Full Speed Host and Device (USB-C connector) +- Three 5 V input sources + + - USB (Debug, Full Speed) + - External power supply (using surface mount clamp test points and power input vias) + +- Three Debug modes + + - Debug on-board (SWD) + - Debug in (SWD) + - Debug out (SWD, SW0 and JTAG) + +- User LEDs and buttons + + - Three User LEDs (red, blue, green) + - Power LED (white) indicating availability of regulated power + - Debug LED (yellow) indicating the debug connection + - Two User buttons + - One Reset button + +- Five most popular ecosystems expansions + + - 1 Seeed Grove® system (I3C) connector + - 1 Seeed Grove® system (I2C/Analog) connector + - 2 Digilent PmodTM (SPI, UART and I2C) connectors + - ArduinoTM (Uno R3) connector + - MikroElektronikaTM mikroBUS connector + +- MCU boot configuration jumper + +**Special Feature Access** + +- 256 Mb (32 MB) External QUAD-SPI Flash +- CAN FD (3-pin header) +- Segment LCD Board Interface (50-pin header) + +Hardware +******** + +Detailed hardware features can be found at: + +- RA4L1 MCU: `RA4L1 Group User's Manual Hardware`_ +- EK-RA4L1 board: `EK-RA4L1 - User's Manual`_ + +Debug on-board: + + - Connector Used: USB-C (J10) + ++----------------+------+------+--------------------+------+--------------------------------------+ +| Debug Modes | J6 | J6-A | J8 | J9 | J29 | ++================+======+======+====================+======+======================================+ +| Debug on-board | Open | Open | Jumper on pins 1-2 | Open | Jumpers on pins 1-2, 3-4, 5-6, 7-8 | ++----------------+------+------+--------------------+------+--------------------------------------+ + +Supported Features +================== + +The below features are currently supported on Zephyr for the ``ek_ra4l1`` board: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| UART | on-chip | serial | ++-----------+------------+----------------------+ +| SPI | on-chip | spi | ++-----------+------------+----------------------+ +| CLOCK | on-chip | clock control | ++-----------+------------+----------------------+ +| CAN | on-chip | canfd | ++-----------+------------+----------------------+ +| ADC | on-chip | adc | ++-----------+------------+----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+----------------------+ +| I2C | on-chip | i2c | ++-----------+------------+----------------------+ + +Other hardware features are currently not supported by the port. + +Programming and Debugging +************************* + +Applications for the ``ek_ra4l1`` board configuration can be +built, flashed, and debugged in the usual way. See +:ref:`build_an_application` and :ref:`application_run` for more details on +building and running. + +Flashing +======== + +Program can be flashed to EK-RA4L1 via the on-board SEGGER J-Link debugger. +SEGGER J-link's drivers are avaialbe at https://www.segger.com/downloads/jlink/ + +To flash the program to board + +1. Connect to J-Link OB via USB port to host PC + +2. Make sure J-Link OB jumper is in default configuration as describe in `EK-RA4L1 - User's Manual`_ + +3. Execute west command + + .. code-block:: console + + west flash -r jlink + +References +********** +- `EK-RA4L1 Website`_ +- `RA4L1 MCU group Website`_ + +.. _EK-RA4L1 Website: + https://www.renesas.com/en/products/microcontrollers-microprocessors/ra-cortex-m-mcus/ek-ra4l1-evaluation-kit-ra4l1-mcu-group + +.. _RA4L1 MCU group Website: + https://www.renesas.com/en/products/microcontrollers-microprocessors/ra-cortex-m-mcus/ra4l1-80mhz-arm-cortex-m33-based-low-power-mcu-trustzone-segment-lcd-controller-and-advanced-security + +.. _EK-RA4L1 - User's Manual: + https://www.renesas.com/en/document/mat/ek-ra4l1-v1-users-manual?r=25570359 + +.. _RA4L1 Group User's Manual Hardware: + https://www.renesas.com/en/document/mah/ra4l1-group-users-manual-hardware?r=25568281 diff --git a/boards/renesas/ek_ra4l1/ek_ra4l1-pinctrl.dtsi b/boards/renesas/ek_ra4l1/ek_ra4l1-pinctrl.dtsi new file mode 100644 index 0000000000000..c967c97b44269 --- /dev/null +++ b/boards/renesas/ek_ra4l1/ek_ra4l1-pinctrl.dtsi @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + sci5_default: sci5_default { + group1 { + /* tx rx */ + psels = , + ; + }; + }; + + spi0_default: spi0_default { + group1 { + /* MISO MOSI RSPCK SSL */ + psels = , + , + , + ; + }; + }; + + adc0_default: adc0_default { + group1 { + /* input */ + psels = ; + renesas,analog-enable; + }; + }; + + pwm1_default: pwm1_default { + group1 { + /* GTIOC1A GTIOC1B */ + psels = , + ; + }; + }; + + iic0_default: iic0_default { + group1 { + /* SCL0 SDA0 */ + psels = , + ; + drive-strength = "medium"; + }; + }; + + canfd0_default: canfd0_default { + group1 { + /* CRX0 CTX0 */ + psels = , + ; + drive-strength = "high"; + }; + }; +}; diff --git a/boards/renesas/ek_ra4l1/ek_ra4l1.dts b/boards/renesas/ek_ra4l1/ek_ra4l1.dts new file mode 100644 index 0000000000000..a85a694c12a02 --- /dev/null +++ b/boards/renesas/ek_ra4l1/ek_ra4l1.dts @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include +#include "ek_ra4l1-pinctrl.dtsi" + +/ { + model = "Renesas EK-RA4L1"; + compatible = "renesas,ra4l1", "renesas,ra"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash-controller = &flash1; + zephyr,flash = &flash0; + zephyr,console = &uart5; + zephyr,shell-uart = &uart5; + zephyr,canbus = &canfd0; + }; + + leds { + compatible = "gpio-leds"; + + led1: led1 { + gpios = <&ioport6 9 GPIO_ACTIVE_HIGH>; + label = "LED1"; + }; + + led2: led2 { + gpios = <&ioport6 10 GPIO_ACTIVE_HIGH>; + label = "LED2"; + }; + + led3: led3 { + gpios = <&ioport6 1 GPIO_ACTIVE_HIGH>; + label = "LED3"; + }; + }; + + buttons { + compatible = "gpio-keys"; + + button0: s1 { + gpios = <&ioport0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button switch 1"; + zephyr,code = ; + }; + + button1: s2 { + gpios = <&ioport0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button switch 2"; + zephyr,code = ; + }; + }; + + aliases { + led0 = &led1; + sw0 = &button0; + sw1 = &button1; + }; + + transceiver0: can-phy0 { + compatible = "microchip,mcp2562fd", "can-transceiver-gpio"; + standby-gpios = <&ioport1 6 GPIO_ACTIVE_LOW>; + max-bitrate = <5000000>; + #phy-cells = <0>; + }; +}; + +&xtal { + clock-frequency = ; + mosel = <0>; + #clock-cells = <0>; + status = "okay"; +}; + +&subclk { + status = "okay"; +}; + +&pll { + clocks = <&xtal>; + div = <1>; + mul = <10 0>; + status = "okay"; +}; + +&canfdclk { + clocks = <&pll>; + div = <2>; + status = "okay"; +}; + +&sci5 { + pinctrl-0 = <&sci5_default>; + pinctrl-names = "default"; + status = "okay"; + + uart5: uart { + current-speed = <115200>; + status = "okay"; + }; +}; + +&ioport0 { + status = "okay"; +}; + +&ioport1 { + status = "okay"; +}; + +&ioport4 { + status = "okay"; +}; + +&ioport5 { + status = "okay"; +}; + +&ioport6 { + status = "okay"; +}; + +&spi0 { + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&adc0 { + status = "okay"; + pinctrl-0 = <&adc0_default>; + pinctrl-names = "default"; +}; + +&port_irq6 { + interrupts = <14 12>; + status = "okay"; +}; + +&port_irq7 { + interrupts = <15 12>; + status = "okay"; +}; + +&pwm1 { + pinctrl-0 = <&pwm1_default>; + pinctrl-names = "default"; + interrupts = <8 1>, <9 1>; + interrupt-names = "gtioca", "overflow"; + status = "okay"; +}; + +&iic0 { + pinctrl-0 = <&iic0_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + interrupts = <10 1>, <11 1>, <12 1>, <13 1>; + interrupt-names = "rxi", "txi", "tei", "eri"; + status = "okay"; +}; + +&canfd_global { + status = "okay"; + + canfd0 { + pinctrl-0 = <&canfd0_default>; + pinctrl-names = "default"; + phys = <&transceiver0>; + rx-max-filters = <16>; + status = "okay"; + }; +}; diff --git a/boards/renesas/ek_ra4l1/ek_ra4l1.yaml b/boards/renesas/ek_ra4l1/ek_ra4l1.yaml new file mode 100644 index 0000000000000..edcac7c0fa722 --- /dev/null +++ b/boards/renesas/ek_ra4l1/ek_ra4l1.yaml @@ -0,0 +1,12 @@ +identifier: ek_ra4l1 +name: Renesas EK-RA4L1 +type: mcu +arch: arm +ram: 64 +flash: 512 +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - uart diff --git a/boards/renesas/ek_ra4l1/ek_ra4l1_defconfig b/boards/renesas/ek_ra4l1/ek_ra4l1_defconfig new file mode 100644 index 0000000000000..f26066de3e521 --- /dev/null +++ b/boards/renesas/ek_ra4l1/ek_ra4l1_defconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Enable GPIO +CONFIG_GPIO=y + +# Enable Console +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_CONSOLE=y +CONFIG_CONSOLE=y From e139d936cb0d89fa2bd2448e94c92d936cfffd46 Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Mon, 10 Feb 2025 18:24:01 +0700 Subject: [PATCH 0257/6055] drivers: gpio: Only configs for VBATT pin when RA MCU support Update GPIO driver for RA: Only configs for VBATT pin when RA MCU support. Signed-off-by: Thao Luong --- drivers/gpio/Kconfig.renesas_ra_ioport | 5 +++++ drivers/gpio/gpio_renesas_ra_ioport.c | 2 ++ soc/renesas/ra/ra4e1/Kconfig | 1 + soc/renesas/ra/ra4m1/Kconfig | 1 + soc/renesas/ra/ra4m2/Kconfig | 1 + soc/renesas/ra/ra4m3/Kconfig | 1 + soc/renesas/ra/ra4w1/Kconfig | 1 + soc/renesas/ra/ra6e1/Kconfig | 1 + soc/renesas/ra/ra6m1/Kconfig | 1 + soc/renesas/ra/ra6m2/Kconfig | 1 + soc/renesas/ra/ra6m3/Kconfig | 1 + soc/renesas/ra/ra6m4/Kconfig | 1 + soc/renesas/ra/ra6m5/Kconfig | 1 + soc/renesas/ra/ra8d1/Kconfig | 1 + soc/renesas/ra/ra8m1/Kconfig | 1 + soc/renesas/ra/ra8t1/Kconfig | 1 + 16 files changed, 21 insertions(+) diff --git a/drivers/gpio/Kconfig.renesas_ra_ioport b/drivers/gpio/Kconfig.renesas_ra_ioport index c09361cb1cad9..257475b4f60bc 100644 --- a/drivers/gpio/Kconfig.renesas_ra_ioport +++ b/drivers/gpio/Kconfig.renesas_ra_ioport @@ -7,3 +7,8 @@ config GPIO_RA_IOPORT depends on DT_HAS_RENESAS_RA_GPIO_IOPORT_ENABLED help Enable the Renesas RA GPIO IO port driver. + +config GPIO_RA_HAS_VBTICTLR + bool "Support VBATT input control" + help + Enable for Renesas RA which support VBATT input control. diff --git a/drivers/gpio/gpio_renesas_ra_ioport.c b/drivers/gpio/gpio_renesas_ra_ioport.c index fec5f8c43493a..68d5334c67595 100644 --- a/drivers/gpio/gpio_renesas_ra_ioport.c +++ b/drivers/gpio/gpio_renesas_ra_ioport.c @@ -78,6 +78,7 @@ static int gpio_ra_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ return -ENOTSUP; } +#if CONFIG_GPIO_RA_HAS_VBTICTLR if (config->vbatt_pins[0] != 0xFF) { uint32_t clear = 0; @@ -93,6 +94,7 @@ static int gpio_ra_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT); } +#endif pincfg.port_num = config->port_num; pincfg.pin_num = pin; diff --git a/soc/renesas/ra/ra4e1/Kconfig b/soc/renesas/ra/ra4e1/Kconfig index 24613396e3b06..dd5a14ef2bf43 100644 --- a/soc/renesas/ra/ra4e1/Kconfig +++ b/soc/renesas/ra/ra4e1/Kconfig @@ -14,3 +14,4 @@ config SOC_SERIES_RA4E1 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra4m1/Kconfig b/soc/renesas/ra/ra4m1/Kconfig index bcc26d4d04750..5d071b7f9fceb 100644 --- a/soc/renesas/ra/ra4m1/Kconfig +++ b/soc/renesas/ra/ra4m1/Kconfig @@ -14,6 +14,7 @@ config SOC_SERIES_RA4M1 select XIP select SOC_EARLY_INIT_HOOK select DYNAMIC_INTERRUPTS if SOC_R7FA4M1AB3CFM + select GPIO_RA_HAS_VBTICTLR if SOC_SERIES_RA4M1 diff --git a/soc/renesas/ra/ra4m2/Kconfig b/soc/renesas/ra/ra4m2/Kconfig index a4b6d2c7c50fe..5058fde961655 100644 --- a/soc/renesas/ra/ra4m2/Kconfig +++ b/soc/renesas/ra/ra4m2/Kconfig @@ -14,3 +14,4 @@ config SOC_SERIES_RA4M2 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra4m3/Kconfig b/soc/renesas/ra/ra4m3/Kconfig index 0898c3796bce1..dfa3719068650 100644 --- a/soc/renesas/ra/ra4m3/Kconfig +++ b/soc/renesas/ra/ra4m3/Kconfig @@ -14,3 +14,4 @@ config SOC_SERIES_RA4M3 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra4w1/Kconfig b/soc/renesas/ra/ra4w1/Kconfig index c9d1fbb37033e..34f44bf6d0742 100644 --- a/soc/renesas/ra/ra4w1/Kconfig +++ b/soc/renesas/ra/ra4w1/Kconfig @@ -13,3 +13,4 @@ config SOC_SERIES_RA4W1 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra6e1/Kconfig b/soc/renesas/ra/ra6e1/Kconfig index accd57e26a069..097baa6241484 100644 --- a/soc/renesas/ra/ra6e1/Kconfig +++ b/soc/renesas/ra/ra6e1/Kconfig @@ -14,3 +14,4 @@ config SOC_SERIES_RA6E1 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra6m1/Kconfig b/soc/renesas/ra/ra6m1/Kconfig index 649b6702629d3..ffe573117178b 100644 --- a/soc/renesas/ra/ra6m1/Kconfig +++ b/soc/renesas/ra/ra6m1/Kconfig @@ -13,3 +13,4 @@ config SOC_SERIES_RA6M1 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra6m2/Kconfig b/soc/renesas/ra/ra6m2/Kconfig index 680e649349d7a..09c6427a52ea8 100644 --- a/soc/renesas/ra/ra6m2/Kconfig +++ b/soc/renesas/ra/ra6m2/Kconfig @@ -13,3 +13,4 @@ config SOC_SERIES_RA6M2 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra6m3/Kconfig b/soc/renesas/ra/ra6m3/Kconfig index bebd78f1babbf..3dea36935aeaf 100644 --- a/soc/renesas/ra/ra6m3/Kconfig +++ b/soc/renesas/ra/ra6m3/Kconfig @@ -13,3 +13,4 @@ config SOC_SERIES_RA6M3 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra6m4/Kconfig b/soc/renesas/ra/ra6m4/Kconfig index ee2acc2855fd4..dec6aba2581e9 100644 --- a/soc/renesas/ra/ra6m4/Kconfig +++ b/soc/renesas/ra/ra6m4/Kconfig @@ -14,3 +14,4 @@ config SOC_SERIES_RA6M4 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra6m5/Kconfig b/soc/renesas/ra/ra6m5/Kconfig index 4a8f750eab60a..792239394c72c 100644 --- a/soc/renesas/ra/ra6m5/Kconfig +++ b/soc/renesas/ra/ra6m5/Kconfig @@ -14,3 +14,4 @@ config SOC_SERIES_RA6M5 select HAS_SWO select XIP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra8d1/Kconfig b/soc/renesas/ra/ra8d1/Kconfig index 968c60343c6d8..50907d2be70c9 100644 --- a/soc/renesas/ra/ra8d1/Kconfig +++ b/soc/renesas/ra/ra8d1/Kconfig @@ -14,3 +14,4 @@ config SOC_SERIES_RA8D1 select CLOCK_CONTROL_RENESAS_RA_CGC if CLOCK_CONTROL select HAS_RENESAS_RA_FSP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR diff --git a/soc/renesas/ra/ra8m1/Kconfig b/soc/renesas/ra/ra8m1/Kconfig index f1fd9d9967e6e..31d4aaefda5ee 100644 --- a/soc/renesas/ra/ra8m1/Kconfig +++ b/soc/renesas/ra/ra8m1/Kconfig @@ -14,5 +14,6 @@ config SOC_SERIES_RA8M1 select CLOCK_CONTROL_RENESAS_RA_CGC if CLOCK_CONTROL select HAS_RENESAS_RA_FSP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR help Enable support for Renesas RA8M1 MCU series diff --git a/soc/renesas/ra/ra8t1/Kconfig b/soc/renesas/ra/ra8t1/Kconfig index 426e72be95d11..5fe21152ad401 100644 --- a/soc/renesas/ra/ra8t1/Kconfig +++ b/soc/renesas/ra/ra8t1/Kconfig @@ -14,3 +14,4 @@ config SOC_SERIES_RA8T1 select CLOCK_CONTROL_RENESAS_RA_CGC if CLOCK_CONTROL select HAS_RENESAS_RA_FSP select SOC_EARLY_INIT_HOOK + select GPIO_RA_HAS_VBTICTLR From b0b1394ff78092c9af24d3aa822c637e0f2f7fcf Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Tue, 4 Feb 2025 11:32:21 +0700 Subject: [PATCH 0258/6055] tests: drivers: spi: Add configs and dts node for ek_ra4l1 Add configs and dts node for ek_ra4l1 run on spi_loopback Signed-off-by: Thao Luong --- .../spi/spi_loopback/boards/ek_ra4l1.conf | 6 ++++++ .../spi/spi_loopback/boards/ek_ra4l1.overlay | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/drivers/spi/spi_loopback/boards/ek_ra4l1.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/ek_ra4l1.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/ek_ra4l1.conf b/tests/drivers/spi/spi_loopback/boards/ek_ra4l1.conf new file mode 100644 index 0000000000000..a231e084368be --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/ek_ra4l1.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SPI_LOOPBACK_MODE_LOOP=y +CONFIG_SPI_INTERRUPT=y +CONFIG_SPI_RA_DTC=y diff --git a/tests/drivers/spi/spi_loopback/boards/ek_ra4l1.overlay b/tests/drivers/spi/spi_loopback/boards/ek_ra4l1.overlay new file mode 100644 index 0000000000000..59314554dc355 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/ek_ra4l1.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&spi0 { + rx-dtc; + tx-dtc; + + slow@0 { + compatible = "test-spi-loopback-slow"; + reg = <0>; + spi-max-frequency = <2000000>; + }; + + fast@0 { + compatible = "test-spi-loopback-fast"; + reg = <0>; + spi-max-frequency = <3000000>; + }; +}; From cf9aa0fdd3b254829d9abdd9deec1ad9f7bcaf1a Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Tue, 4 Feb 2025 11:59:08 +0700 Subject: [PATCH 0259/6055] tests: drivers: adc: Add dts nodes for ek_ra4l1 Add dts nodes for ek_ra4l1 run on adc_accuracy_test and adc_api Signed-off-by: Thao Luong --- .../adc_accuracy_test/boards/ek_ra4l1.overlay | 28 +++++++++++++++ .../adc/adc_api/boards/ek_ra4l1.overlay | 36 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/drivers/adc/adc_accuracy_test/boards/ek_ra4l1.overlay create mode 100644 tests/drivers/adc/adc_api/boards/ek_ra4l1.overlay diff --git a/tests/drivers/adc/adc_accuracy_test/boards/ek_ra4l1.overlay b/tests/drivers/adc/adc_accuracy_test/boards/ek_ra4l1.overlay new file mode 100644 index 0000000000000..71c6e206e6146 --- /dev/null +++ b/tests/drivers/adc/adc_accuracy_test/boards/ek_ra4l1.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + io-channels = <&adc0 0>; + reference-mv = <3300>; + expected-accuracy = <32>; + }; +}; + +&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>; + zephyr,vref-mv = <3300>; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/ek_ra4l1.overlay b/tests/drivers/adc/adc_api/boards/ek_ra4l1.overlay new file mode 100644 index 0000000000000..9aab1db0db5d2 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/ek_ra4l1.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +/ { + zephyr,user { + io-channels = <&adc0 0>, <&adc0 2>; + }; +}; + +&adc0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + zephyr,acquisition-time = ; + zephyr,vref-mv = <3300>; + }; + + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + zephyr,acquisition-time = ; + zephyr,vref-mv = <3300>; + }; +}; From 48c46179e74aeafe424f2c1c3844b4540d650025 Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Tue, 4 Feb 2025 13:10:34 +0700 Subject: [PATCH 0260/6055] tests: drivers: pwm: Add dts nodes for ek_ra4l1 Add dts nodes for ek_ra4l1 run on pwm_loopback Signed-off-by: Thao Luong --- .../pwm/pwm_loopback/boards/ek_ra4l1.overlay | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/drivers/pwm/pwm_loopback/boards/ek_ra4l1.overlay diff --git a/tests/drivers/pwm/pwm_loopback/boards/ek_ra4l1.overlay b/tests/drivers/pwm/pwm_loopback/boards/ek_ra4l1.overlay new file mode 100644 index 0000000000000..4c16fb9739065 --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/ek_ra4l1.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + pwm_loopback_0 { + compatible = "test-pwm-loopback"; + /* first index must be a 32-Bit timer */ + pwms = <&pwm1 0 0 PWM_POLARITY_NORMAL>, + <&pwm4 0 0 PWM_POLARITY_NORMAL>; + }; +}; + +&pinctrl { + pwm4_default: pwm4_default { + group1 { + /* GTIOC4A*/ + psels = ; + }; + }; +}; + +&pwm4 { + pinctrl-0 = <&pwm4_default>; + pinctrl-names = "default"; + interrupts = <63 1>, <62 1>; + interrupt-names = "gtioca", "overflow"; + status = "okay"; +}; From 5a2ee872913a3ff62ef0173468907c9bb33ab1f4 Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Tue, 4 Feb 2025 13:15:48 +0700 Subject: [PATCH 0261/6055] tests: drivers: i2c: Add config and dts node for ek_ra4l1 Add config and dts node for ek_ra4l1 run on i2c_api Signed-off-by: Thao Luong --- tests/drivers/i2c/i2c_api/boards/ek_ra4l1.conf | 4 ++++ tests/drivers/i2c/i2c_api/boards/ek_ra4l1.overlay | 12 ++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/drivers/i2c/i2c_api/boards/ek_ra4l1.conf create mode 100644 tests/drivers/i2c/i2c_api/boards/ek_ra4l1.overlay diff --git a/tests/drivers/i2c/i2c_api/boards/ek_ra4l1.conf b/tests/drivers/i2c/i2c_api/boards/ek_ra4l1.conf new file mode 100644 index 0000000000000..3b626dd7fad28 --- /dev/null +++ b/tests/drivers/i2c/i2c_api/boards/ek_ra4l1.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SENSOR_GY271_QMC=y diff --git a/tests/drivers/i2c/i2c_api/boards/ek_ra4l1.overlay b/tests/drivers/i2c/i2c_api/boards/ek_ra4l1.overlay new file mode 100644 index 0000000000000..c629e87a6e272 --- /dev/null +++ b/tests/drivers/i2c/i2c_api/boards/ek_ra4l1.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2c-0 = &iic0; + gy271 = &iic0; + }; +}; From e44a7684d088b60cc19384c5b11fc36cc5f6d32a Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Thu, 6 Feb 2025 17:13:18 +0700 Subject: [PATCH 0262/6055] tests: drivers: uart: Add dts node for ek_ra4l1 Add dts node for ek_ra4l1 run on uart_async_api Signed-off-by: Thao Luong --- .../uart_async_api/boards/ek_ra4l1.overlay | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/drivers/uart/uart_async_api/boards/ek_ra4l1.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/ek_ra4l1.overlay b/tests/drivers/uart/uart_async_api/boards/ek_ra4l1.overlay new file mode 100644 index 0000000000000..e8343b61c6c74 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/ek_ra4l1.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + sci9_default: sci9_default { + group1 { + /* tx rx */ + psels = , + ; + }; + }; +}; + +&sci9 { + pinctrl-0 = <&sci9_default>; + pinctrl-names = "default"; + status = "okay"; + + dut: uart { + current-speed = <115200>; + status = "okay"; + }; +}; From f378a8c7ccc97cbc0b351cd8bdd44afbe44d62f2 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Fri, 6 Sep 2024 14:04:37 +0800 Subject: [PATCH 0263/6055] dts: arm: nxp: rt118x: add two usdhc instances enable clock in soc.c register two usdhc instances Signed-off-by: Lucien Zhao --- dts/arm/nxp/nxp_rt118x.dtsi | 24 ++++++++++++++++++++++++ soc/nxp/imxrt/imxrt118x/soc.c | 18 ++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/dts/arm/nxp/nxp_rt118x.dtsi b/dts/arm/nxp/nxp_rt118x.dtsi index b8527a1f0f58c..dc25cfb24ecb4 100644 --- a/dts/arm/nxp/nxp_rt118x.dtsi +++ b/dts/arm/nxp/nxp_rt118x.dtsi @@ -1019,6 +1019,30 @@ #size-cells = <0>; }; + usdhc1: usdhc@2850000 { + compatible = "nxp,imx-usdhc"; + reg = <0x2850000 0x4000>; + status = "disabled"; + interrupts = <86 0>; + clocks = <&ccm IMX_CCM_USDHC1_CLK 0 0>; + max-current-330 = <1020>; + max-current-180 = <1020>; + max-bus-freq = <208000000>; + min-bus-freq = <400000>; + }; + + usdhc2: usdhc@2860000 { + compatible = "nxp,imx-usdhc"; + reg = <0x2860000 0x4000>; + status = "disabled"; + interrupts = <87 0>; + clocks = <&ccm IMX_CCM_USDHC2_CLK 0 0>; + max-current-330 = <1020>; + max-current-180 = <1020>; + max-bus-freq = <208000000>; + min-bus-freq = <400000>; + }; + edma3: dma-controller@4000000 { #dma-cells = <2>; compatible = "nxp,mcux-edma"; diff --git a/soc/nxp/imxrt/imxrt118x/soc.c b/soc/nxp/imxrt/imxrt118x/soc.c index 1d6362447deea..3aad5b6ee3e5b 100644 --- a/soc/nxp/imxrt/imxrt118x/soc.c +++ b/soc/nxp/imxrt/imxrt118x/soc.c @@ -527,6 +527,24 @@ __weak void clock_init(void) DT_PROP_BY_PHANDLE(DT_NODELABEL(usb1), clocks, clock_frequency)); #endif +#ifdef CONFIG_IMX_USDHC + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usdhc1), okay) + /* Configure USDHC1 using SysPll2Pfd2 */ + rootCfg.mux = kCLOCK_USDHC1_ClockRoot_MuxSysPll2Pfd2; + rootCfg.div = 2; + CLOCK_SetRootClock(kCLOCK_Root_Usdhc1, &rootCfg); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usdhc2), okay) + /* Configure USDHC2 using SysPll2Pfd2 */ + rootCfg.mux = kCLOCK_USDHC2_ClockRoot_MuxSysPll2Pfd2; + rootCfg.div = 2; + CLOCK_SetRootClock(kCLOCK_Root_Usdhc2, &rootCfg); +#endif + +#endif /* CONFIG_IMX_USDHC */ + /* Keep core clock ungated during WFI */ CCM->LPCG[1].LPM0 = 0x33333333; CCM->LPCG[1].LPM1 = 0x33333333; From f026faee3ddebacd25a0dae01cb485506effaec2 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Fri, 6 Sep 2024 14:07:24 +0800 Subject: [PATCH 0264/6055] boards: nxp: mimxrt1180_evk: add usdhc1 support add usdhc1 pinctrl test passed for tests/drivers/sdhc case on cm33/cm7 case Signed-off-by: Lucien Zhao --- boards/nxp/mimxrt1180_evk/doc/index.rst | 2 + .../mimxrt1180_evk-pinctrl.dtsi | 57 +++++++++++++++++++ boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi | 16 ++++++ .../mimxrt1180_evk_mimxrt1189_cm33.yaml | 1 + .../mimxrt1180_evk_mimxrt1189_cm7.yaml | 1 + 5 files changed, 77 insertions(+) diff --git a/boards/nxp/mimxrt1180_evk/doc/index.rst b/boards/nxp/mimxrt1180_evk/doc/index.rst index b243fb766051d..27f46447ca621 100644 --- a/boards/nxp/mimxrt1180_evk/doc/index.rst +++ b/boards/nxp/mimxrt1180_evk/doc/index.rst @@ -130,6 +130,8 @@ configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | USB | on-chip | USB device | +-----------+------------+-------------------------------------+ +| SDHC | on-chip | SD host controller | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: :zephyr_file:`boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm33_defconfig` diff --git a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk-pinctrl.dtsi b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk-pinctrl.dtsi index 47efc9fdda8ca..a0ee4993f68b9 100644 --- a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk-pinctrl.dtsi @@ -290,4 +290,61 @@ drive-strength = "high"; }; }; + + pinmux_usdhc1: pinmux_usdhc1 { + group0 { + pinmux = <&iomuxc_gpio_sd_b1_00_usdhc1_cmd>, + <&iomuxc_gpio_sd_b1_01_usdhc1_clk>, + <&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>; + bias-pull-up; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_ad_34_usdhc1_vselect>, + <&iomuxc_gpio_ad_15_gpio4_io15>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + }; + group2 { + pinmux = <&iomuxc_gpio_ad_14_gpio4_io14>; + drive-strength = "high"; + bias-pull-up; + slew-rate = "fast"; + }; + }; + + /* removes pull on dat3 for card detect */ + pinmux_usdhc1_dat3_nopull: pinmux_usdhc1_dat3_nopull { + group0 { + pinmux = <&iomuxc_gpio_sd_b1_05_usdhc1_data3>; + bias-disable; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_sd_b1_00_usdhc1_cmd>, + <&iomuxc_gpio_sd_b1_01_usdhc1_clk>, + <&iomuxc_gpio_sd_b1_02_usdhc1_data0>, + <&iomuxc_gpio_sd_b1_03_usdhc1_data1>, + <&iomuxc_gpio_sd_b1_04_usdhc1_data2>; + bias-pull-up; + input-enable; + }; + group2 { + pinmux = <&iomuxc_gpio_ad_34_usdhc1_vselect>, + <&iomuxc_gpio_ad_15_gpio4_io15>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + }; + group3 { + pinmux = <&iomuxc_gpio_ad_14_gpio4_io14>; + drive-strength = "high"; + bias-pull-up; + slew-rate = "fast"; + }; + }; }; diff --git a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi index 0f595a96ab0b6..8da2b53518594 100644 --- a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi +++ b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi @@ -12,6 +12,7 @@ led0 = &green_led; sw0 = &user_button; pwm-led0 = &green_pwm_led; + sdhc0 = &usdhc1; }; leds { @@ -269,3 +270,18 @@ p3t1755dp_ard_i2c_interface: &lpi2c2 {}; pinctrl-0 = <&pinmux_lpspi3>; pinctrl-names = "default"; }; + +&usdhc1 { + status = "okay"; + detect-dat3; + no-1-8-v; + pwr-gpios = <&gpio4 14 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pinmux_usdhc1>; + pinctrl-1 = <&pinmux_usdhc1_dat3_nopull>; + pinctrl-names = "default", "nopull"; + sdmmc { + compatible = "zephyr,sdmmc-disk"; + disk-name = "SD"; + status = "okay"; + }; +}; diff --git a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm33.yaml b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm33.yaml index 50e7ae40e454f..e291f38a9fac3 100644 --- a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm33.yaml +++ b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm33.yaml @@ -28,4 +28,5 @@ supported: - spi - watchdog - usb_device + - sdhc vendor: nxp diff --git a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.yaml b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.yaml index 5366ba8f9aff1..a733aad8b7df6 100644 --- a/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.yaml +++ b/boards/nxp/mimxrt1180_evk/mimxrt1180_evk_mimxrt1189_cm7.yaml @@ -25,4 +25,5 @@ supported: - i3c - dma - spi + - sdhc vendor: nxp From ba982a0f85eb381bcc58bae1aa9b411d28322053 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Wed, 12 Feb 2025 16:44:52 +0800 Subject: [PATCH 0265/6055] dts: arm: nxp: register ostimer for cm33_cpu0/1 register ostimer for cm33_cpu0/1 disable systick set ostimer per sec 1000000 times Signed-off-by: Lucien Zhao --- dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi | 15 +++++++++++++++ dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi | 15 +++++++++++++++ soc/nxp/imxrt/imxrt7xx/Kconfig.defconfig | 4 +++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi index 614c946684161..6413efbfda7f8 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi @@ -1011,6 +1011,21 @@ interrupts = <55 0>; clocks = <&clkctl4 MCUX_FLEXIO0_CLK>; }; + + os_timer_cpu0: timers@207000 { + compatible = "nxp,os-timer"; + reg = <0x207000 0x1000>; + interrupts = <34 0>; + status = "disabled"; + }; +}; + +&systick { + /* + * RT700 cm33_cpu0 relies by default on the OS Timer for system + * clock implementation, so the SysTick node is not to be enabled. + */ + status = "disabled"; }; &xspi0 { diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi index 1088538099372..23baca895d4ec 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi @@ -418,8 +418,23 @@ clocks = <&clkctl4 MCUX_LPI2C15_CLK>; status = "disabled"; }; + + os_timer_cpu1: timers@209000 { + compatible = "nxp,os-timer"; + reg = <0x209000 0x1000>; + interrupts = <30 0>; + status = "disabled"; + }; }; &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* + * RT700 cm33_cpu1 relies by default on the OS Timer for system + * clock implementation, so the SysTick node is not to be enabled. + */ + status = "disabled"; +}; diff --git a/soc/nxp/imxrt/imxrt7xx/Kconfig.defconfig b/soc/nxp/imxrt/imxrt7xx/Kconfig.defconfig index c7b1d1d4b0557..2b7904f630f28 100644 --- a/soc/nxp/imxrt/imxrt7xx/Kconfig.defconfig +++ b/soc/nxp/imxrt/imxrt7xx/Kconfig.defconfig @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_MIMXRT798S_CM33_CPU0 @@ -11,6 +11,7 @@ config NUM_IRQS config SYS_CLOCK_HW_CYCLES_PER_SEC default 237500000 if CORTEX_M_SYSTICK + default 1000000 if MCUX_OS_TIMER choice CACHE_TYPE default EXTERNAL_CACHE @@ -25,6 +26,7 @@ config NUM_IRQS config SYS_CLOCK_HW_CYCLES_PER_SEC default 100000000 if CORTEX_M_SYSTICK + default 1000000 if MCUX_OS_TIMER endif # SOC_MIMXRT798S_CM33_CPU1 From d39d420c5482f369e41d77c4fe77d70a2c02ca61 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Wed, 12 Feb 2025 16:48:07 +0800 Subject: [PATCH 0266/6055] boards: nxp: mimxrt700_evk: use ostimer as kernel tick for cm33_cpu0/1 enable ostimer clock enable os_timer_cpu0/1 for cm33_cpu0/1 Signed-off-by: Lucien Zhao --- boards/nxp/mimxrt700_evk/board.c | 6 ++++++ boards/nxp/mimxrt700_evk/doc/index.rst | 2 ++ .../mimxrt700_evk_mimxrt798s_cm33_cpu0.dts | 8 +++++++- .../mimxrt700_evk_mimxrt798s_cm33_cpu1.dts | 10 ++++++++-- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/boards/nxp/mimxrt700_evk/board.c b/boards/nxp/mimxrt700_evk/board.c index 49e49083abb7d..43e029b32e2ff 100644 --- a/boards/nxp/mimxrt700_evk/board.c +++ b/boards/nxp/mimxrt700_evk/board.c @@ -400,6 +400,12 @@ void board_early_init_hook(void) CLOCK_AttachClk(kSENSE_BASE_to_ADC); CLOCK_SetClkDiv(kCLOCK_DivAdcClk, 1U); #endif + +#if (DT_NODE_HAS_STATUS(DT_NODELABEL(os_timer_cpu0), okay) || \ + DT_NODE_HAS_STATUS(DT_NODELABEL(os_timer_cpu1), okay)) + CLOCK_AttachClk(kLPOSC_to_OSTIMER); + CLOCK_SetClkDiv(kCLOCK_DivOstimerClk, 1U); +#endif } static void GlikeyWriteEnable(GLIKEY_Type *base, uint8_t idx) diff --git a/boards/nxp/mimxrt700_evk/doc/index.rst b/boards/nxp/mimxrt700_evk/doc/index.rst index 467ff3c87d841..52ace6399aefb 100644 --- a/boards/nxp/mimxrt700_evk/doc/index.rst +++ b/boards/nxp/mimxrt700_evk/doc/index.rst @@ -81,6 +81,8 @@ the hardware features below. +-----------+------------+-------------------------------------+ | ADC | on-chip | adc | +-----------+------------+-------------------------------------+ +| OS_TIMER | on-chip | os timer | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts index cf079cfc343e7..1e4e0ee72e3ce 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts @@ -65,8 +65,14 @@ status = "okay"; }; -&systick { +/* + * RT700-EVK board cm33_cpu0 uses OS timer as the kernel timer + * In case we need to switch to SYSTICK timer, then + * replace &os_timer with &systick + */ +&os_timer_cpu0 { status = "okay"; + wakeup-source; }; &flexcomm0{ diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts index 7486247bb0045..92ecdc41aafb0 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -56,8 +56,14 @@ pinctrl-names = "default"; }; -&systick { +/* + * RT700-EVK board cm33_cpu1 uses OS timer as the kernel timer + * In case we need to switch to SYSTICK timer, then + * replace &os_timer with &systick + */ +&os_timer_cpu1 { status = "okay"; + wakeup-source; }; &flexcomm19{ From e9a0d146cfa5aebe92d1c420b0ef5876fb67a731 Mon Sep 17 00:00:00 2001 From: Robin Kastberg Date: Wed, 5 Feb 2025 21:24:47 +0000 Subject: [PATCH 0267/6055] toolchain: move some hardcoded flags to properties Some basic flags that were hardcoded needed to be moved to properties to be able to implement alternative toolchains. Signed-off-by: Robin Kastberg --- arch/arm/core/cortex_m/tz/CMakeLists.txt | 5 ++++- cmake/compiler/compiler_flags_template.cmake | 8 ++++++++ cmake/compiler/gcc/compiler_flags.cmake | 7 +++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/arm/core/cortex_m/tz/CMakeLists.txt b/arch/arm/core/cortex_m/tz/CMakeLists.txt index 19c67476e40ee..aac4f65161941 100644 --- a/arch/arm/core/cortex_m/tz/CMakeLists.txt +++ b/arch/arm/core/cortex_m/tz/CMakeLists.txt @@ -2,7 +2,10 @@ # '-mcmse' enables the generation of code for the Secure state of the ARMv8-M # Security Extensions. This option is required when building a Secure firmware. -zephyr_compile_options_ifdef(CONFIG_ARM_SECURE_FIRMWARE -mcmse) + +zephyr_compile_options_ifdef(CONFIG_ARM_SECURE_FIRMWARE $<$:$>) +zephyr_compile_options_ifdef(CONFIG_ARM_SECURE_FIRMWARE $<$:$>) +zephyr_compile_options_ifdef(CONFIG_ARM_SECURE_FIRMWARE $<$:$>) if(CONFIG_ARM_FIRMWARE_HAS_SECURE_ENTRY_FUNCS) diff --git a/cmake/compiler/compiler_flags_template.cmake b/cmake/compiler/compiler_flags_template.cmake index 447db04a2d307..bea8027bb0f43 100644 --- a/cmake/compiler/compiler_flags_template.cmake +++ b/cmake/compiler/compiler_flags_template.cmake @@ -125,6 +125,9 @@ set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics) # Required ASM flags when compiling set_property(TARGET asm PROPERTY required) +# GCC compiler flags for imacros. The specific header must be appended by user. +set_property(TARGET asm PROPERTY imacros) + # Compiler flag for disabling pointer arithmetic warnings set_compiler_property(PROPERTY warning_no_pointer_arithmetic) @@ -149,3 +152,8 @@ set_compiler_property(PROPERTY specs) # Compiler flag for defining preinclude files. set_compiler_property(PROPERTY include_file) + +# Compiler flag for trustzone +set_compiler_property(PROPERTY cmse) + +set_property(TARGET asm PROPERTY cmse) diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index 830d479ee6693..3ff29a4b30cfe 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -231,6 +231,9 @@ set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics "-fno-threadsafe # Required ASM flags when using gcc set_property(TARGET asm PROPERTY required "-xassembler-with-cpp") +# GCC compiler flags for imacros. The specific header must be appended by user. +set_property(TARGET asm PROPERTY imacros "-imacros") + # gcc flag for colourful diagnostic messages check_set_compiler_property(PROPERTY diagnostic -fdiagnostics-color=always) @@ -253,3 +256,7 @@ set_compiler_property(PROPERTY no_builtin_malloc -fno-builtin-malloc) set_compiler_property(PROPERTY specs -specs=) set_compiler_property(PROPERTY include_file -include) + +set_compiler_property(PROPERTY cmse -mcmse) + +set_property(TARGET asm PROPERTY cmse -mcmse) From 65471a6095fd46d537dd4b7ad0667b4f1018a1c2 Mon Sep 17 00:00:00 2001 From: Robin Kastberg Date: Wed, 5 Feb 2025 21:24:48 +0000 Subject: [PATCH 0268/6055] toolchain: stop C flags from leaking to the assembler Currently the compiler and assembler shares many properties. This can be problematic for non-GNU toolchains that takes different parameters to the assembler and compiler. Signed-off-by: Robin Kastberg --- CMakeLists.txt | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48234f675abce..cd141c12dea6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,13 +174,17 @@ endif() # @Intent: Set compiler flags to detect general stack overflows across all functions if(CONFIG_STACK_CANARIES) - zephyr_compile_options($) + zephyr_compile_options("$<$:$>") + zephyr_compile_options("$<$:$>") elseif(CONFIG_STACK_CANARIES_STRONG) - zephyr_compile_options($) + zephyr_compile_options("$<$:$>") + zephyr_compile_options("$<$:$>") elseif(CONFIG_STACK_CANARIES_ALL) - zephyr_compile_options($) + zephyr_compile_options("$<$:$>") + zephyr_compile_options("$<$:$>") elseif(CONFIG_STACK_CANARIES_EXPLICIT) - zephyr_compile_options($) + zephyr_compile_options("$<$:$>") + zephyr_compile_options("$<$:$>") endif() # @Intent: Obtain compiler optimizations flags and store in variables @@ -227,7 +231,8 @@ SOC_* symbol.") endif() # Apply the final optimization flag(s) -zephyr_compile_options(${OPTIMIZATION_FLAG}) +zephyr_compile_options($<$:${OPTIMIZATION_FLAG}>) +zephyr_compile_options($<$:${OPTIMIZATION_FLAG}>) if(CONFIG_LTO) zephyr_compile_options($) @@ -315,7 +320,9 @@ if(CONFIG_CODING_GUIDELINE_CHECK) endif() # @Intent: Set compiler specific macro inclusion of AUTOCONF_H -zephyr_compile_options("SHELL: $ ${AUTOCONF_H}") +zephyr_compile_options("SHELL: $<$:$ ${AUTOCONF_H}>") +zephyr_compile_options("SHELL: $<$:$ ${AUTOCONF_H}>") +zephyr_compile_options("SHELL: $<$:$ ${AUTOCONF_H}>") if(CONFIG_COMPILER_FREESTANDING) # @Intent: Set compiler specific flag for bare metal freestanding option @@ -360,7 +367,9 @@ zephyr_compile_options($<$:$ # @Intent: Enforce standard integer type correspondence to match Zephyr usage. # (must be after compiler specific flags) if(CONFIG_ENFORCE_ZEPHYR_STDINT) - zephyr_compile_options("SHELL: $ ${ZEPHYR_BASE}/include/zephyr/toolchain/zephyr_stdint.h") + zephyr_compile_options("SHELL:$<$:$ ${ZEPHYR_BASE}/include/zephyr/toolchain/zephyr_stdint.h>") + zephyr_compile_options("SHELL:$<$:$ ${ZEPHYR_BASE}/include/zephyr/toolchain/zephyr_stdint.h>") + zephyr_compile_options("SHELL:$<$:$ ${ZEPHYR_BASE}/include/zephyr/toolchain/zephyr_stdint.h>") endif() # Common toolchain-agnostic assembly flags From f5a1585426e348afb72b8615d0f1a70d07fbf2f6 Mon Sep 17 00:00:00 2001 From: Robin Kastberg Date: Wed, 5 Feb 2025 21:24:48 +0000 Subject: [PATCH 0269/6055] toolchain: iar: tls: no tls pointer offset in IAR The IAR Toolchain currently doesn't use the two pointer offset. Signed-off-by: Robin Kastberg --- arch/arm/core/tls.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/core/tls.c b/arch/arm/core/tls.c index 9b731286c7da8..0dc21285a916d 100644 --- a/arch/arm/core/tls.c +++ b/arch/arm/core/tls.c @@ -40,8 +40,10 @@ size_t arch_tls_stack_setup(struct k_thread *new_thread, char *stack_ptr) stack_ptr -= z_tls_data_size(); z_tls_copy(stack_ptr); +#ifndef __IAR_SYSTEMS_ICC__ /* Skip two pointers due to toolchain */ stack_ptr -= sizeof(uintptr_t) * 2; +#endif /* * Set thread TLS pointer which is used in From d41da75ac4831ed46d3b34549493b4450332c072 Mon Sep 17 00:00:00 2001 From: Robin Kastberg Date: Tue, 4 Feb 2025 15:40:12 +0000 Subject: [PATCH 0270/6055] checkpatch: Allow __BYTE_ORDER__ and __aligned__ in toolchain files Checkpatch needs to allow toolchain headers where these macros are defined. Signed-off-by: Robin Kastberg --- scripts/checkpatch.pl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 27c1f54e54f1d..25b09073bdb33 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -6050,6 +6050,7 @@ sub process { # Check for __attribute__ aligned, prefer __aligned if ($realfile !~ m@\binclude/uapi/@ && + $realfile !~ m@\binclude/zephyr/toolchain@ && $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { WARN("PREFER_ALIGNED", "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); @@ -6565,9 +6566,10 @@ sub process { } # check for uses of __BYTE_ORDER__ - while ($line =~ /\b(__BYTE_ORDER__)\b/g) { - ERROR("BYTE_ORDER", - "Use of the '$1' macro is disallowed. Use CONFIG_(BIG|LITTLE)_ENDIAN instead\n" . $herecurr); + while ($realfile !~ m@^include/zephyr/toolchain@ && + $line =~ /\b(__BYTE_ORDER__)\b/g) { + ERROR("BYTE_ORDER", + "Use of the '$1' macro is disallowed. Use CONFIG_(BIG|LITTLE)_ENDIAN instead\n" . $herecurr); } # check for use of yield() From 9ab06ec667e42d67925e7f589e31e832f1acc892 Mon Sep 17 00:00:00 2001 From: Robin Kastberg Date: Wed, 5 Feb 2025 21:24:48 +0000 Subject: [PATCH 0271/6055] toolchain: iar: Add experimental IAR support This adds experimental support for the IAR toolchain. Signed-off-by: Robin Kastberg --- arch/common/CMakeLists.txt | 21 +- cmake/bintools/iar/target.cmake | 44 + cmake/bintools/iar/target_bintools.cmake | 135 +++ cmake/compiler/iar/compiler_flags.cmake | 178 ++++ cmake/compiler/iar/generic.cmake | 15 + cmake/compiler/iar/iccarm-cpu.cmake | 89 ++ cmake/compiler/iar/iccarm-fpu.cmake | 53 + cmake/compiler/iar/target.cmake | 146 +++ cmake/linker/iar/config_file_script.cmake | 922 ++++++++++++++++++ cmake/linker/iar/linker_flags.cmake | 14 + cmake/linker/iar/target.cmake | 135 +++ cmake/toolchain/iar/Kconfig | 40 + cmake/toolchain/iar/Kconfig.defconfig | 53 + cmake/toolchain/iar/generic.cmake | 46 + cmake/toolchain/iar/target.cmake | 5 + include/zephyr/arch/arm/asm_inline.h | 4 +- include/zephyr/toolchain.h | 2 + include/zephyr/toolchain/iar.h | 25 + .../zephyr/toolchain/iar/iar_missing_defs.h | 161 +++ include/zephyr/toolchain/iar/iccarm.h | 456 +++++++++ lib/libc/CMakeLists.txt | 1 + lib/libc/Kconfig | 19 + lib/libc/iar/CMakeLists.txt | 6 + lib/libc/iar/include/errno.h | 96 ++ lib/libc/iar/include/limits.h | 22 + lib/libc/iar/include/sys/_timespec.h | 7 + lib/libc/iar/include/sys/_timeval.h | 27 + lib/libc/iar/include/sys/cdefs.h | 7 + lib/libc/iar/include/sys/timespec.h | 18 + lib/libc/iar/include/sys/types.h | 21 + lib/libc/iar/include/time.h | 31 + lib/libc/iar/src/libc-hooks.c | 53 + scripts/ci/check_compliance.py | 3 + .../fpu_sharing/generic/src/load_store.c | 2 +- 34 files changed, 2848 insertions(+), 9 deletions(-) create mode 100644 cmake/bintools/iar/target.cmake create mode 100644 cmake/bintools/iar/target_bintools.cmake create mode 100644 cmake/compiler/iar/compiler_flags.cmake create mode 100644 cmake/compiler/iar/generic.cmake create mode 100644 cmake/compiler/iar/iccarm-cpu.cmake create mode 100644 cmake/compiler/iar/iccarm-fpu.cmake create mode 100644 cmake/compiler/iar/target.cmake create mode 100644 cmake/linker/iar/config_file_script.cmake create mode 100644 cmake/linker/iar/linker_flags.cmake create mode 100644 cmake/linker/iar/target.cmake create mode 100644 cmake/toolchain/iar/Kconfig create mode 100644 cmake/toolchain/iar/Kconfig.defconfig create mode 100644 cmake/toolchain/iar/generic.cmake create mode 100644 cmake/toolchain/iar/target.cmake create mode 100644 include/zephyr/toolchain/iar.h create mode 100644 include/zephyr/toolchain/iar/iar_missing_defs.h create mode 100644 include/zephyr/toolchain/iar/iccarm.h create mode 100644 lib/libc/iar/CMakeLists.txt create mode 100644 lib/libc/iar/include/errno.h create mode 100644 lib/libc/iar/include/limits.h create mode 100644 lib/libc/iar/include/sys/_timespec.h create mode 100644 lib/libc/iar/include/sys/_timeval.h create mode 100644 lib/libc/iar/include/sys/cdefs.h create mode 100644 lib/libc/iar/include/sys/timespec.h create mode 100644 lib/libc/iar/include/sys/types.h create mode 100644 lib/libc/iar/include/time.h create mode 100644 lib/libc/iar/src/libc-hooks.c diff --git a/arch/common/CMakeLists.txt b/arch/common/CMakeLists.txt index e79b7cd0abfa6..6f84bb9635123 100644 --- a/arch/common/CMakeLists.txt +++ b/arch/common/CMakeLists.txt @@ -56,12 +56,21 @@ zephyr_linker_sources_ifdef(CONFIG_GEN_IRQ_VECTOR_TABLE ) if(CONFIG_GEN_ISR_TABLES) - zephyr_linker_section(NAME .intList VMA IDT_LIST LMA IDT_LIST NOINPUT PASS NOT LINKER_ZEPHYR_FINAL) - zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".irq_info" FIRST) - zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".intList") - - zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".irq_info" PASS LINKER_ZEPHYR_FINAL) - zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".intList" PASS LINKER_ZEPHYR_FINAL) + # IAR Toolchain is having problems with discarding .intList + # This will always keep .intList in a harmless location + # until we can implement a proper DISCARD. + if(ZEPHYR_TOOLCHAIN_VARIANT STREQUAL "iar") + zephyr_linker_section(NAME .intList GROUP RODATA_REGION NOINPUT) + zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".irq_info" FIRST) + zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".intList") + else() + zephyr_linker_section(NAME .intList VMA IDT_LIST LMA IDT_LIST NOINPUT PASS NOT LINKER_ZEPHYR_FINAL) + zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".irq_info" FIRST) + zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".intList") + + zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".irq_info" PASS LINKER_ZEPHYR_FINAL) + zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".intList" PASS LINKER_ZEPHYR_FINAL) + endif() endif() zephyr_linker_sources_ifdef(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT diff --git a/cmake/bintools/iar/target.cmake b/cmake/bintools/iar/target.cmake new file mode 100644 index 0000000000000..0ea594503cc36 --- /dev/null +++ b/cmake/bintools/iar/target.cmake @@ -0,0 +1,44 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Configures binary tools as GNU binutils +include(extensions) + +# Specifically choose arm-zephyr-eabi from the zephyr sdk for objcopy and friends + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + set(IAR_ZEPHYR_HOME ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin) + set(IAR_GNU_PREFIX arm-zephyr-eabi-) +else() + message(ERROR "IAR_TOOLCHAIN_VARIANT not set") +endif() +find_program(CMAKE_OBJCOPY ${IAR_GNU_PREFIX}objcopy PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_OBJDUMP ${IAR_GNU_PREFIX}objdump PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_AS ${IAR_GNU_PREFIX}as PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_AR ${IAR_GNU_PREFIX}ar PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_RANLIB ${IAR_GNU_PREFIX}ranlib PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_READELF ${IAR_GNU_PREFIX}readelf PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_NM ${IAR_GNU_PREFIX}nm PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_STRIP ${IAR_GNU_PREFIX}strip PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_GDB ${IAR_GNU_PREFIX}gdb-py PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) + +if(CMAKE_GDB) + execute_process( + COMMAND ${CMAKE_GDB} --configuration + RESULTS_VARIABLE GDB_CFG_ERR + OUTPUT_QUIET + ERROR_QUIET + ) +endif() + +if(NOT CMAKE_GDB OR GDB_CFG_ERR) + find_program(CMAKE_GDB_NO_PY ${CROSS_COMPILE}gdb PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) + + if(CMAKE_GDB_NO_PY) + set(CMAKE_GDB ${CMAKE_GDB_NO_PY} CACHE FILEPATH "Path to a program." FORCE) + endif() +endif() + +# Include bin tool properties +include(${ZEPHYR_BASE}/cmake/bintools/iar/target_bintools.cmake) diff --git a/cmake/bintools/iar/target_bintools.cmake b/cmake/bintools/iar/target_bintools.cmake new file mode 100644 index 0000000000000..087bd518df136 --- /dev/null +++ b/cmake/bintools/iar/target_bintools.cmake @@ -0,0 +1,135 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 +# +# - elfconvert : Name of command for elf file conversion. +# In this implementation `objcopy` is used +# elfconvert_formats : Formats supported: ihex, srec, binary +# elfconvert_flag : empty +# elfconvert_flag_final : empty +# elfconvert_flag_strip_all : -S +# elfconvert_flag_strip_debug : -g +# elfconvert_flag_intarget : --input-target= +# elfconvert_flag_outtarget : --output-target= +# elfconvert_flag_section_remove: --remove-section= +# elfconvert_flag_section_only : --only-section= +# elfconvert_flag_section_rename: --rename-section; +# elfconvert_flag_gapfill : --gap-fill; +# Note: The ';' will be transformed into an +# empty space when executed +# elfconvert_flag_srec_len : --srec-len= +# elfconvert_flag_infile : empty, objcopy doesn't take arguments for filenames +# elfconvert_flag_outfile : empty, objcopy doesn't take arguments for filenames +# + +# elfconvert to use for transforming an elf file into another format, +# such as intel hex, s-rec, binary, etc. +set_property(TARGET bintools PROPERTY elfconvert_command ${CMAKE_OBJCOPY}) + +# List of format the tool supports for converting, for example, +# GNU tools uses objectcopy, which supports the following: ihex, srec, binary +set_property(TARGET bintools PROPERTY elfconvert_formats ihex srec binary) + +set_property(TARGET bintools PROPERTY elfconvert_flag "") +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_intarget "--input-target=") +set_property(TARGET bintools PROPERTY elfconvert_flag_outtarget "--output-target=") + +set_property(TARGET bintools PROPERTY elfconvert_flag_section_remove "--remove-section=") +set_property(TARGET bintools PROPERTY elfconvert_flag_section_only "--only-section=") +set_property(TARGET bintools PROPERTY elfconvert_flag_section_rename "--rename-section;") + +set_property(TARGET bintools PROPERTY elfconvert_flag_lma_adjust "--change-section-lma;") + +# Note, placing a ';' at the end results in the following param to be a list, +# and hence space separated. +# Thus the command line argument becomes: +# `--gap-file ` instead of `--gap-fill` (The latter would result in an error) +set_property(TARGET bintools PROPERTY elfconvert_flag_gapfill "--gap-fill;") +set_property(TARGET bintools PROPERTY elfconvert_flag_srec_len "--srec-len=") + +set_property(TARGET bintools PROPERTY elfconvert_flag_infile "") +set_property(TARGET bintools PROPERTY elfconvert_flag_outfile "") + +# +# - disassembly : Name of command for disassembly of files +# In this implementation `objdump` is used +# disassembly_flag : -d +# disassembly_flag_final : empty +# disassembly_flag_inline_source : -S +# disassembly_flag_all : -SDz +# disassembly_flag_infile : empty, objdump doesn't take arguments for filenames +# disassembly_flag_outfile : '>', objdump doesn't take arguments for output file, but result is printed to standard out, and is redirected. + +set_property(TARGET bintools PROPERTY disassembly_command ${CMAKE_OBJDUMP}) +set_property(TARGET bintools PROPERTY disassembly_flag -d) +set_property(TARGET bintools PROPERTY disassembly_flag_final "") +set_property(TARGET bintools PROPERTY disassembly_flag_inline_source -S) +set_property(TARGET bintools PROPERTY disassembly_flag_all -SDz) + +set_property(TARGET bintools PROPERTY disassembly_flag_infile "") +set_property(TARGET bintools PROPERTY disassembly_flag_outfile ">;" ) + +# +# - strip: Name of command for stripping symbols +# In this implementation `strip` is used +# strip_flag : empty +# strip_flag_final : empty +# strip_flag_all : --strip-all +# strip_flag_debug : --strip-debug +# strip_flag_dwo : --strip-dwo +# strip_flag_infile : empty, strip doesn't take arguments for input file +# strip_flag_outfile : -o + +# This is using strip from bintools. +set_property(TARGET bintools PROPERTY strip_command ${CMAKE_STRIP}) + +# Any flag the strip command requires for processing +set_property(TARGET bintools PROPERTY strip_flag "") +set_property(TARGET bintools PROPERTY strip_flag_final "") + +set_property(TARGET bintools PROPERTY strip_flag_all --strip-all) +set_property(TARGET bintools PROPERTY strip_flag_debug --strip-debug) +set_property(TARGET bintools PROPERTY strip_flag_dwo --strip-dwo) +set_property(TARGET bintools PROPERTY strip_flag_remove_section -R ) + +set_property(TARGET bintools PROPERTY strip_flag_infile "") +set_property(TARGET bintools PROPERTY strip_flag_outfile -o ) + +# +# - readelf : Name of command for reading elf files. +# In this implementation `readelf` is used +# readelf_flag : empty +# readelf_flag_final : empty +# readelf_flag_headers : -e +# readelf_flag_infile : empty, readelf doesn't take arguments for filenames +# readelf_flag_outfile : '>', readelf doesn't take arguments for output +# file, but result is printed to standard out, and +# is redirected. + +# This is using readelf from bintools. +set_property(TARGET bintools PROPERTY readelf_command ${CMAKE_READELF}) + +set_property(TARGET bintools PROPERTY readelf_flag "") +set_property(TARGET bintools PROPERTY readelf_flag_final "") +set_property(TARGET bintools PROPERTY readelf_flag_headers -e) + +set_property(TARGET bintools PROPERTY readelf_flag_infile "") +set_property(TARGET bintools PROPERTY readelf_flag_outfile ">;" ) + +# Example on how to support dwarfdump instead of readelf +#set_property(TARGET bintools PROPERTY readelf_command dwarfdump) +#set_property(TARGET bintools PROPERTY readelf_flag "") +#set_property(TARGET bintools PROPERTY readelf_flag_headers -E) +#set_property(TARGET bintools PROPERTY readelf_flag_infile "") +#set_property(TARGET bintools PROPERTY readelf_flag_outfile "-O file=" ) + +set_property(TARGET bintools PROPERTY symbols_command ${CMAKE_NM}) +set_property(TARGET bintools PROPERTY symbols_flag "") +set_property(TARGET bintools PROPERTY symbols_final "") +set_property(TARGET bintools PROPERTY symbols_infile "") +set_property(TARGET bintools PROPERTY symbols_outfile ">;" ) diff --git a/cmake/compiler/iar/compiler_flags.cmake b/cmake/compiler/iar/compiler_flags.cmake new file mode 100644 index 0000000000000..49cd7bfd33ea2 --- /dev/null +++ b/cmake/compiler/iar/compiler_flags.cmake @@ -0,0 +1,178 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Compiler options for the IAR C/C++ Compiler for Arm + +##################################################### +# This section covers flags related to optimization # +##################################################### +set_compiler_property(PROPERTY no_optimization -On) + +set_compiler_property(PROPERTY optimization_debug -Ol) + +set_compiler_property(PROPERTY optimization_speed -Ohs) + +set_compiler_property(PROPERTY optimization_size -Ohz) + +set_compiler_property(PROPERTY optimization_size_aggressive -Ohz) + +####################################################### +# This section covers flags related to warning levels # +####################################################### + +# Property for standard warning base in Zephyr, this will always be set when +# compiling. +set_compiler_property(PROPERTY warning_base + --diag_error=Pe223 # function "xxx" declared implicitly + --diag_warning=Pe054 # too few arguments in invocation of macro + --diag_warning=Pe144 # a value of type "void *" cannot be used to initialize an entity of type [...] "void (*)(struct onoff_manager *, int)" + --diag_warning=Pe167 # argument of type "void *" is incompatible with [...] "void (*)(void *, void *, void *)" + --diag_suppress=Pe1675 # unrecognized GCC pragma + --diag_suppress=Pe111 # statement is unreachable + --diag_suppress=Pe1143 # arithmetic on pointer to void or function type + --diag_suppress=Pe068) # integer conversion resulted in a change of sign) + + +set(IAR_WARNING_DW_1 + --diag_suppress=Pe188 # enumerated type mixed with another type + --diag_suppress=Pe128 # loop is not reachable + --diag_suppress=Pe550 # variable "res" was set but never used + --diag_suppress=Pe546 # transfer of control bypasses initialization + --diag_suppress=Pe186) # pointless comparison of unsigned integer with zero + +set(IAR_WARNING_DW2 + --diag_suppress=Pe1097 # unknown attribute + --diag_suppress=Pe381 # extra ";" ignored + --diag_suppress=Pa082 # undefined behavior: the order of volatile accesses is undefined + --diag_suppress=Pa084 # pointless integer comparison, the result is always false + --diag_suppress=Pe185 # dynamic initialization in unreachable code ) + --diag_suppress=Pe167 # argument of type "onoff_notify_fn" is incompatible with... + --diag_suppress=Pe144 # a value of type "void *" cannot be used to initialize... + --diag_suppress=Pe177 # function "xxx" was declared but never referenced + --diag_suppress=Pe513) # a value of type "void *" cannot be assigned to an entity of type "int (*)(int)" + +set(IAR_WARNING_DW3) + +set_compiler_property(PROPERTY warning_dw_1 + ${IAR_WARNING_DW_3} + ${IAR_WARNING_DW_2} + ${IAR_WARNING_DW_1}) + +set_compiler_property(PROPERTY warning_dw_2 + ${IAR_WARNING_DW3} + ${IAR_WARNING_DW2}) + +# no suppressions +set_compiler_property(PROPERTY warning_dw_3 ${IAR_WARNING_DW3}) + +# Extended warning set supported by the compiler +set_compiler_property(PROPERTY warning_extended) + +# Compiler property that will issue error if a declaration does not specify a type +set_compiler_property(PROPERTY warning_error_implicit_int) + +# Compiler flags to use when compiling according to MISRA +set_compiler_property(PROPERTY warning_error_misra_sane) + +set_property(TARGET compiler PROPERTY warnings_as_errors --warnings_are_errors) + +########################################################################### +# This section covers flags related to C or C++ standards / standard libs # +########################################################################### + +# Compiler flags for C standard. The specific standard must be appended by user. +# For example, gcc specifies this as: set_compiler_property(PROPERTY cstd -std=) +# TC-WG: the `cstd99` is used regardless of this flag being useful for iccarm +# This flag will make it a symbol. Works for C,CXX,ASM +# Since ICCARM does not use C standard flags, we just make them a defined symbol +# instead +set_compiler_property(PROPERTY cstd -D__IAR_CSTD_) + +# Compiler flags for disabling C standard include and instead specify include +# dirs in nostdinc_include to use. +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) + +# Required C++ flags when compiling C++ code +set_property(TARGET compiler-cpp PROPERTY required --c++) + +# Compiler flags to use for specific C++ dialects +set_property(TARGET compiler-cpp PROPERTY dialect_cpp98) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp11) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp14) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp17 --libc++) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp2a --libc++) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp20 --libc++) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp2b --libc++) + +# Flag for disabling strict aliasing rule in C and C++ +set_compiler_property(PROPERTY no_strict_aliasing) + +# Flag for disabling exceptions in C++ +set_property(TARGET compiler-cpp PROPERTY no_exceptions --no_exceptions) + +# Flag for disabling rtti in C++ +set_property(TARGET compiler-cpp PROPERTY no_rtti --no_rtti) + +################################################### +# This section covers all remaining C / C++ flags # +################################################### + +# Flags for coverage generation +set_compiler_property(PROPERTY coverage) + +# Security canaries flags. +set_compiler_property(PROPERTY security_canaries --stack_protection) +set_compiler_property(PROPERTY security_canaries_strong --stack_protection) +set_compiler_property(PROPERTY security_canaries_all --security_canaries_all_is_not_supported) +set_compiler_property(PROPERTY security_canaries_explicit --security_canaries_explicit_is_not_supported) + +if(CONFIG_STACK_CANARIES_TLS) + check_set_compiler_property(APPEND PROPERTY security_canaries --stack_protector_guard=tls) + check_set_compiler_property(APPEND PROPERTY security_canaries_strong --stack_protector_guard=tls) + check_set_compiler_property(APPEND PROPERTY security_canaries_all --stack_protector_guard=tls) + check_set_compiler_property(APPEND PROPERTY security_canaries_explicit --stack_protector_guard=tls) +endif() + +set_compiler_property(PROPERTY security_fortify) + +# Flag for a hosted (no-freestanding) application +set_compiler_property(PROPERTY hosted) + +# gcc flag for a freestanding application +set_compiler_property(PROPERTY freestanding) + +# Flag to include debugging symbol in compilation +set_property(TARGET compiler PROPERTY debug --debug) +set_property(TARGET compiler-cpp PROPERTY debug --debug) +set_property(TARGET asm PROPERTY debug -gdwarf-4) + +set_compiler_property(PROPERTY no_common) + +# Flags for imacros. The specific header must be appended by user. +set_property(TARGET compiler PROPERTY imacros --preinclude) +set_property(TARGET compiler-cpp PROPERTY imacros --preinclude) +set_property(TARGET asm PROPERTY imacros -imacros) + +# Compiler flag for turning off thread-safe initialization of local statics +set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics) + +# Required ASM flags when compiling +set_property(TARGET asm PROPERTY required) + +# Compiler flag for disabling pointer arithmetic warnings +set_compiler_property(PROPERTY warning_no_pointer_arithmetic) + +# Compiler flags for disabling position independent code / executable +set_compiler_property(PROPERTY no_position_independent) + +# Compiler flag for defining preinclude files. +set_compiler_property(PROPERTY include_file --preinclude) + +set_compiler_property(PROPERTY cmse --cmse) + +set_property(TARGET asm PROPERTY cmse -mcmse) diff --git a/cmake/compiler/iar/generic.cmake b/cmake/compiler/iar/generic.cmake new file mode 100644 index 0000000000000..5d46412770d77 --- /dev/null +++ b/cmake/compiler/iar/generic.cmake @@ -0,0 +1,15 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +if(NOT CMAKE_DTS_PREPROCESSOR) + find_program(CMAKE_DTS_PREPROCESSOR arm-zephyr-eabi-gcc PATHS ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin NO_DEFAULT_PATH) +endif() + +if(NOT CMAKE_DTS_PREPROCESSOR) + message(FATAL_ERROR "Zephyr was unable to find \`arm-zephyr-eabi-gcc\` for DTS preprocessing") +endif() + +if(CMAKE_C_COMPILER STREQUAL CMAKE_C_COMPILER-NOTFOUND) + message(FATAL_ERROR "Zephyr was unable to find the IAR toolchain. Was the environment misconfigured?") +endif() diff --git a/cmake/compiler/iar/iccarm-cpu.cmake b/cmake/compiler/iar/iccarm-cpu.cmake new file mode 100644 index 0000000000000..70eee9240b654 --- /dev/null +++ b/cmake/compiler/iar/iccarm-cpu.cmake @@ -0,0 +1,89 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Determines what argument to give to --cpu= based on the +# KConfig'uration and sets this to ICCARM_CPU + +if("${ARCH}" STREQUAL "arm") + if(CONFIG_CPU_CORTEX_M0) + set(ICCARM_CPU Cortex-M0) + elseif(CONFIG_CPU_CORTEX_M0PLUS) + set(ICCARM_CPU Cortex-M0+) + elseif(CONFIG_CPU_CORTEX_M1) + set(ICCARM_CPU Cortex-M1) + elseif(CONFIG_CPU_CORTEX_M3) + set(ICCARM_CPU Cortex-M3) + elseif(CONFIG_CPU_CORTEX_M4) + set(ICCARM_CPU Cortex-M4) + elseif(CONFIG_CPU_CORTEX_M7) + set(ICCARM_CPU Cortex-M7) + elseif(CONFIG_CPU_CORTEX_M23) + set(ICCARM_CPU Cortex-M23) + elseif(CONFIG_CPU_CORTEX_M33) + if(CONFIG_ARMV8_M_DSP) + set(ICCARM_CPU Cortex-M33) + else() + set(ICCARM_CPU Cortex-M33.no_dsp) + endif() + elseif(CONFIG_CPU_CORTEX_M55) + if(CONFIG_ARMV8_1_M_MVEF) + set(ICCARM_CPU Cortex-M55) + elseif(CONFIG_ARMV8_1_M_MVEI) + set(ICCARM_CPU Cortex-M55.no_mve) + elseif(CONFIG_ARMV8_M_DSP) + set(ICCARM_CPU Cortex-M55.no_mve) + else() + set(ICCARM_CPU Cortex-M55.no_dsp) + endif() + elseif(CONFIG_CPU_CORTEX_R4) + if(CONFIG_FPU AND CONFIG_CPU_HAS_VFP) + set(ICCARM_CPU Cortex-R4F) + else() + set(ICCARM_CPU Cortex-R4) + endif() + elseif(CONFIG_CPU_CORTEX_R5) + set(ICCARM_CPU Cortex-R5) + if(CONFIG_FPU AND CONFIG_CPU_HAS_VFP) + if(NOT CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_CPU ${ICCARM_CPU}+fp.sp) + endif() + else() + set(ICCARM_CPU ${ICCARM_CPU}+fp.dp) + endif() + elseif(CONFIG_CPU_CORTEX_R7) + set(ICCARM_CPU Cortex-R7) + if(CONFIG_FPU AND CONFIG_CPU_HAS_VFP) + if(NOT CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_CPU ${ICCARM_CPU}+fp.sp) + endif() + else() + set(ICCARM_CPU ${ICCARM_CPU}+fp.dp) + endif() + elseif(CONFIG_CPU_CORTEX_R52) + set(ICCARM_CPU Cortex-R52) + if(CONFIG_FPU AND CONFIG_CPU_HAS_VFP) + if(NOT CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_CPU ${ICCARM_CPU}+fp.sp) + endif() + endif() + elseif(CONFIG_CPU_CORTEX_A9) + set(ICCARM_CPU Cortex-A9) + else() + message(FATAL_ERROR "Expected CONFIG_CPU_CORTEX_x to be defined") + endif() +elseif("${ARCH}" STREQUAL "arm64") + if(CONFIG_CPU_CORTEX_A53) + set(ICCARM_CPU Cortex-A53) + elseif(CONFIG_CPU_CORTEX_A55) + set(ICCARM_CPU Cortex-A55) + elseif(CONFIG_CPU_CORTEX_A76) + set(ICCARM_CPU cortex-a76) + elseif(CONFIG_CPU_CORTEX_A76_A55) + set(ICCARM_CPU cortex-a76) + elseif(CONFIG_CPU_CORTEX_A72) + set(ICCARM_CPU Cortex-A72) + elseif(CONFIG_CPU_CORTEX_R82) + set(ICCARM_CPU Cortex-R82) + endif() +endif() diff --git a/cmake/compiler/iar/iccarm-fpu.cmake b/cmake/compiler/iar/iccarm-fpu.cmake new file mode 100644 index 0000000000000..2435d77254bf8 --- /dev/null +++ b/cmake/compiler/iar/iccarm-fpu.cmake @@ -0,0 +1,53 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Determines what argument to give to --fpu= based on the +# KConfiguration and sets this to ICCARM_FPU + +if(CONFIG_FPU) + + # 32-bit + if("${ARCH}" STREQUAL "arm") + if(CONFIG_CPU_AARCH32_CORTEX_R) + if(CONFIG_CPU_CORTEX_R4 OR CONFIG_CPU_CORTEX_R5) # VFPv3 + if(CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_FPU VFPv3_D16) + elseif(CONFIG_VFP_FEATURE_SINGLE_PRECISION) + set(ICCARM_FPU VFPv3-SP) + endif() + if(CONFIG_VFP_FEATURE_HALF_PRECISION) + set(ICCARM_FPU ${ICCARM_FPU}_Fp16) + endif() + elseif(CONFIG_CPU_CORTEX_R52) + if(CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_FPU VFPv5_D16) + elseif(CONFIG_VFP_FEATURE_SINGLE_PRECISION) + set(ICCARM_FPU VFPv5-SP) + endif() + endif() + elseif(CONFIG_CPU_CORTEX_M) + # Defines a mapping from ICCARM_CPU to FPU + if(CONFIG_CPU_HAS_FPU_DOUBLE_PRECISION) + set(PRECISION_TOKEN _D16) + else() + set(PRECISION_TOKEN -SP) + endif() + + set(FPU_FOR_Cortex-M4 FPv4${PRECISION_TOKEN}) + set(FPU_FOR_Cortex-M7 FPv5${PRECISION_TOKEN}) + set(FPU_FOR_Cortex-M33 FPv5${PRECISION_TOKEN}) + set(FPU_FOR_Cortex-M33.no_dsp FPv5${PRECISION_TOKEN}) + set(FPU_FOR_Cortex-M55 auto) + set(FPU_FOR_Cortex-M55.no_mve auto) + # We don't have this one? + set(FPU_FOR_Cortex-M55.no_dsp auto) + + set(ICCARM_FPU ${FPU_FOR_${ICCARM_CPU}}) + endif() + # 64-bit + else() + set(ICCARM_FPU none) + endif() + +endif() #CONFIG_FPU diff --git a/cmake/compiler/iar/target.cmake b/cmake/compiler/iar/target.cmake new file mode 100644 index 0000000000000..94422739e1696 --- /dev/null +++ b/cmake/compiler/iar/target.cmake @@ -0,0 +1,146 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Avoids running the linker during try_compile() +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +set(NO_BUILD_TYPE_WARNING 1) +set(CMAKE_NOT_USING_CONFIG_FLAGS 1) + +find_program(CMAKE_C_COMPILER + NAMES ${IAR_COMPILER} + PATHS ${TOOLCHAIN_HOME} + PATH_SUFFIXES bin + NO_DEFAULT_PATH + REQUIRED ) + +message(STATUS "Found C Compiler ${CMAKE_C_COMPILER}") + +find_program(CMAKE_CXX_COMPILER + NAMES ${IAR_COMPILER} + PATHS ${TOOLCHAIN_HOME} + PATH_SUFFIXES bin + NO_DEFAULT_PATH + REQUIRED ) + +find_program(CMAKE_AR + NAMES iarchive + PATHS ${TOOLCHAIN_HOME} + PATH_SUFFIXES bin + NO_DEFAULT_PATH + REQUIRED ) + +set(CMAKE_ASM_COMPILER) +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + find_program(CMAKE_ASM_COMPILER + arm-zephyr-eabi-gcc + PATHS ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin + NO_DEFAULT_PATH ) +else() + find_program(CMAKE_ASM_COMPILER + riscv64-zephyr-elf-gcc + PATHS ${ZEPHYR_SDK_INSTALL_DIR}/riscv64-zephyr-elf/bin + NO_DEFAULT_PATH ) +endif() + +message(STATUS "Found assembler ${CMAKE_ASM_COMPILER}") + +set(ICC_BASE ${ZEPHYR_BASE}/cmake/compiler/iar) + + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + # Used for settings correct cpu/fpu option for gnu assembler + include(${ZEPHYR_BASE}/cmake/gcc-m-cpu.cmake) + include(${ZEPHYR_BASE}/cmake/gcc-m-fpu.cmake) + + # Map KConfig option to icc cpu/fpu + include(${ICC_BASE}/iccarm-cpu.cmake) + include(${ICC_BASE}/iccarm-fpu.cmake) +endif() + +set(IAR_COMMON_FLAGS) +# Minimal C compiler flags + +list(APPEND IAR_COMMON_FLAGS + "SHELL: --preinclude" + "${ZEPHYR_BASE}/include/zephyr/toolchain/iar/iar_missing_defs.h" + # Enable both IAR and GNU extensions + -e + --language gnu + --do_explicit_init_in_named_sections + --macro_positions_in_diagnostics + --no_wrap_diagnostics +) + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + list(APPEND IAR_COMMON_FLAGS + --endian=little + --cpu=${ICCARM_CPU} + -DRTT_USE_ASM=0 #WA for VAAK-232 + --diag_suppress=Ta184 # Using zero sized arrays except for as last member of a struct is discouraged and dereferencing elements in such an array has undefined behavior + ) +endif() + +# Minimal ASM compiler flags +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + list(APPEND IAR_ASM_FLAGS + -mcpu=${GCC_M_CPU} + -mabi=aapcs + -DRTT_USE_ASM=0 #WA for VAAK-232 + ) +endif() + +if(CONFIG_DEBUG) + # GCC defaults to Dwarf 5 output + list(APPEND IAR_ASM_FLAGS -gdwarf-4) +endif() + +if(DEFINED CONFIG_ARM_SECURE_FIRMWARE) + list(APPEND IAR_COMMON_FLAGS --cmse) + list(APPEND IAR_ASM_FLAGS -mcmse) +endif() + +# 64-bit +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + if(CONFIG_ARM64) + list(APPEND IAR_COMMON_FLAGS --abi=lp64) + list(APPEND TOOLCHAIN_LD_FLAGS --abi=lp64) + # 32-bit + else() + list(APPEND IAR_COMMON_FLAGS --aeabi) + if(CONFIG_COMPILER_ISA_THUMB2) + list(APPEND IAR_COMMON_FLAGS --thumb) + list(APPEND IAR_ASM_FLAGS -mthumb) + endif() + + if(CONFIG_FPU) + list(APPEND IAR_COMMON_FLAGS --fpu=${ICCARM_FPU}) + list(APPEND IAR_ASM_FLAGS -mfpu=${GCC_M_FPU}) + endif() + endif() +endif() + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + if(CONFIG_IAR_LIBC) + # Zephyr requires AEABI portability to ensure correct functioning of the C + # library, for example error numbers, errno.h. + list(APPEND IAR_COMMON_FLAGS -D__AEABI_PORTABILITY_LEVEL=1) + endif() +endif() + +if(CONFIG_IAR_LIBC) + message(STATUS "IAR C library used") + # Zephyr uses the type FILE for normal LIBC while IAR + # only has it for full LIBC support, so always choose + # full libc when using IAR C libraries. + list(APPEND IAR_COMMON_FLAGS --dlib_config full) +endif() + +foreach(F ${IAR_COMMON_FLAGS}) + list(APPEND TOOLCHAIN_C_FLAGS $<$:${F}>) + list(APPEND TOOLCHAIN_C_FLAGS $<$:${F}>) +endforeach() + +foreach(F ${IAR_ASM_FLAGS}) + list(APPEND TOOLCHAIN_C_FLAGS $<$:${F}>) +endforeach() diff --git a/cmake/linker/iar/config_file_script.cmake b/cmake/linker/iar/config_file_script.cmake new file mode 100644 index 0000000000000..be11bbac8a38a --- /dev/null +++ b/cmake/linker/iar/config_file_script.cmake @@ -0,0 +1,922 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.17) + +set(SORT_TYPE_NAME Lexical) + +set_property(GLOBAL PROPERTY ILINK_REGION_SYMBOL_ICF) + +# This function post process the region for easier use. +# +# Tasks: +# - Symbol translation using a steering file is configured. +function(process_region) + cmake_parse_arguments(REGION "" "OBJECT" "" ${ARGN}) + + process_region_common(${ARGN}) + + get_property(empty GLOBAL PROPERTY ${REGION_OBJECT}_EMPTY) + if(NOT empty) + # For scatter files we move any system symbols into first non-empty load section. + get_parent(OBJECT ${REGION_OBJECT} PARENT parent TYPE SYSTEM) + get_property(symbols GLOBAL PROPERTY ${parent}_SYMBOLS) + set_property(GLOBAL APPEND PROPERTY ${REGION_OBJECT}_SYMBOLS ${symbols}) + set_property(GLOBAL PROPERTY ${parent}_SYMBOLS) + endif() + + get_property(sections GLOBAL PROPERTY ${REGION_OBJECT}_SECTION_LIST_ORDERED) + foreach(section ${sections}) + + get_property(name GLOBAL PROPERTY ${section}_NAME) + get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN) + get_property(noinput GLOBAL PROPERTY ${section}_NOINPUT) + get_property(type GLOBAL PROPERTY ${section}_TYPE) + get_property(nosymbols GLOBAL PROPERTY ${section}_NOSYMBOLS) + + if(NOT nosymbols) + if(${name} STREQUAL .ramfunc) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_load_start + EXPR "@ADDR(.ramfunc_init)@" + ) + else() + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_load_start + EXPR "@LOADADDR(${name_clean})@" + ) + endif() + endif() + + get_property(indicies GLOBAL PROPERTY ${section}_SETTINGS_INDICIES) + list(LENGTH indicies length) + foreach(idx ${indicies}) + set(steering_postfixes Base Limit) + get_property(symbols GLOBAL PROPERTY ${section}_SETTING_${idx}_SYMBOLS) + get_property(sort GLOBAL PROPERTY ${section}_SETTING_${idx}_SORT) + get_property(offset GLOBAL PROPERTY ${section}_SETTING_${idx}_OFFSET) + if(DEFINED offset AND NOT offset EQUAL 0 ) + # Same behavior as in section_to_string + elseif(DEFINED offset AND offset STREQUAL 0 ) + # Same behavior as in section_to_string + elseif(sort) + # Treated by labels in the icf or image symbols. + elseif(DEFINED symbols AND ${length} EQUAL 1 AND noinput) + endif() + endforeach() + + # Symbols translation here. + + get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_end) + + if("${symbol_val}" STREQUAL "${name_clean}") + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_size + EXPR "@SIZE(${name_clean})@" + ) + else() + # These seem to be thing that can't be transformed to $$Length + set_property(GLOBAL APPEND PROPERTY ILINK_REGION_SYMBOL_ICF + "define image symbol __${name_clean}_size = (__${symbol_val} - ADDR(${name_clean}))") + endif() + set(ZI) + + if(${name_clean} STREQUAL last_ram_section) + # A trick to add the symbol for the nxp devices + # _flash_used = LOADADDR(.last_section) + SIZEOF(.last_section) - __rom_region_start; + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL _flash_used + EXPR "(@LOADADDR(last_section)@ + @SIZE(last_section)@ - @__rom_region_start@)" + ) + endif() + + if(${name_clean} STREQUAL rom_start) + # The below two symbols is meant to make aliases to the _vector_table symbol. + list(GET symbols 0 symbol_start) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __Vectors + EXPR "@ADDR(${symbol_start})@" + ) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __vector_table + EXPR "@ADDR(${symbol_start})@" + ) + endif() + + endforeach() + + get_property(groups GLOBAL PROPERTY ${REGION_OBJECT}_GROUP_LIST_ORDERED) + foreach(group ${groups}) + get_property(name GLOBAL PROPERTY ${group}_NAME) + string(TOLOWER ${name} name) + + get_property(group_type GLOBAL PROPERTY ${group}_OBJ_TYPE) + get_property(parent GLOBAL PROPERTY ${group}_PARENT) + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + # Need to find the init manually group or parent + if(${parent_type} STREQUAL GROUP) + get_property(vma GLOBAL PROPERTY ${parent}_VMA) + get_property(lma GLOBAL PROPERTY ${parent}_LMA) + else() + get_property(vma GLOBAL PROPERTY ${group}_VMA) + get_property(lma GLOBAL PROPERTY ${group}_LMA) + endif() + + get_objects(LIST sections OBJECT ${group} TYPE SECTION) + list(GET sections 0 section) + get_property(first_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN) + list(POP_BACK sections section) + get_property(last_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN) + + if(DEFINED vma AND DEFINED lma) + # Something to init + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_load_start + EXPR "@ADDR(${first_section_name}_init)@" + ) + else() + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_load_start + EXPR "@LOADADDR(${first_section_name})@" + ) + endif() + + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_start + EXPR "@ADDR(${first_section_name})@" + ) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_end + EXPR "@END(${last_section_name})@" + ) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_size + EXPR "(@(__${name}_end)@ - @(__${name}_start)@)" + ) + + endforeach() + + get_property(symbols GLOBAL PROPERTY ${REGION_OBJECT}_SYMBOLS) + foreach(symbol ${symbols}) + get_property(name GLOBAL PROPERTY ${symbol}_NAME) + get_property(expr GLOBAL PROPERTY ${symbol}_EXPR) + if(NOT DEFINED expr) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_size + EXPR "@(ADDR(${name})@" + ) + endif() + endforeach() + + # This is only a trick to get the memories + set(groups) + get_objects(LIST groups OBJECT ${REGION_OBJECT} TYPE GROUP) + foreach(group ${groups}) + get_property(group_type GLOBAL PROPERTY ${group}_OBJ_TYPE) + get_property(parent GLOBAL PROPERTY ${group}_PARENT) + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + + if(${group_type} STREQUAL GROUP) + get_property(group_name GLOBAL PROPERTY ${group}_NAME) + get_property(group_lma GLOBAL PROPERTY ${group}_LMA) + if(${group_name} STREQUAL ROM_REGION) + set_property(GLOBAL PROPERTY ILINK_ROM_REGION_NAME ${group_lma}) + endif() + endif() + + if(${parent_type} STREQUAL GROUP) + get_property(vma GLOBAL PROPERTY ${parent}_VMA) + get_property(lma GLOBAL PROPERTY ${parent}_LMA) + + set_property(GLOBAL PROPERTY ${group}_VMA ${vma}) + set_property(GLOBAL PROPERTY ${group}_LMA ${lma}) + endif() + endforeach() + +endfunction() + +# +# String functions - start +# + +function(system_to_string) + cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) + + get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) + get_property(regions GLOBAL PROPERTY ${STRING_OBJECT}_REGIONS) + get_property(format GLOBAL PROPERTY ${STRING_OBJECT}_FORMAT) + + # Ilink specials + # set(${STRING_STRING} "build for rom;\n") + set(${STRING_STRING} "build for ram;\n") + if("${format}" MATCHES "aarch64") + set(${STRING_STRING} "${${STRING_STRING}}define memory mem with size = 16E;\n") + else() + set(${STRING_STRING} "${${STRING_STRING}}define memory mem with size = 4G;\n") + endif() + + foreach(region ${regions}) + get_property(name GLOBAL PROPERTY ${region}_NAME) + get_property(address GLOBAL PROPERTY ${region}_ADDRESS) + get_property(flags GLOBAL PROPERTY ${region}_FLAGS) + get_property(size GLOBAL PROPERTY ${region}_SIZE) + + if(DEFINED flags) + if(${flags} STREQUAL rx) + set(flags " rom") + elseif(${flags} STREQUAL ro) + set(flags " rom") + elseif(${flags} STREQUAL wx) + set(flags " ram") + elseif(${flags} STREQUAL rw) + set(flags " ram") + endif() + endif() + + if(${name} STREQUAL IDT_LIST) + # Need to use a untyped region for IDT_LIST + set(flags "") + endif() + + if(DEFINED address) + set(start "${address}") + endif() + + if(DEFINED size) + set(size "${size}") + endif() + # define rom region FLASH = mem:[from 0x0 size 0x40000]; + set(memory_region "define${flags} region ${name} = mem:[from ${start} size ${size}];") + + set(${STRING_STRING} "${${STRING_STRING}}${memory_region}\n") + set(flags) + endforeach() + + set(${STRING_STRING} "${${STRING_STRING}}\n\n") + set_property(GLOBAL PROPERTY ILINK_SYMBOL_ICF) + + set(${STRING_STRING} "${${STRING_STRING}}\n") + foreach(region ${regions}) + get_property(empty GLOBAL PROPERTY ${region}_EMPTY) + if(NOT empty) + get_property(name GLOBAL PROPERTY ${region}_NAME) + set(ILINK_CURRENT_NAME ${name}) + to_string(OBJECT ${region} STRING ${STRING_STRING}) + set(ILINK_CURRENT_NAME) + endif() + endforeach() + set(${STRING_STRING} "${${STRING_STRING}}\n") + + get_property(symbols_icf GLOBAL PROPERTY ILINK_SYMBOL_ICF) + foreach(image_symbol ${symbols_icf}) + set(${STRING_STRING} "${${STRING_STRING}}define image symbol ${image_symbol};\n") + endforeach() + + get_property(symbols_icf GLOBAL PROPERTY ILINK_REGION_SYMBOL_ICF) + set(${STRING_STRING} "${${STRING_STRING}}\n") + foreach(image_symbol ${symbols_icf}) + set(${STRING_STRING} "${${STRING_STRING}}${image_symbol};\n") + endforeach() + + if(IAR_LIBC) + set(${STRING_STRING} "${${STRING_STRING}}if (K_HEAP_MEM_POOL_SIZE>0)\n{\n") + set(${STRING_STRING} "${${STRING_STRING}} define block HEAP with alignment=8 { symbol kheap__system_heap };\n") + set(${STRING_STRING} "${${STRING_STRING}}}\nelse\n{\n") + set(${STRING_STRING} "${${STRING_STRING}} define block HEAP with alignment=8, expanding size { };\n") + set(${STRING_STRING} "${${STRING_STRING}}}\n") + set(${STRING_STRING} "${${STRING_STRING}}\"DLib heap\": place in RAM { block HEAP };\n") +# set(${STRING_STRING} "${${STRING_STRING}}define exported symbol HEAP$$Base=kheap__system_heap;\n") +# set(${STRING_STRING} "${${STRING_STRING}}define exported symbol HEAP$$Limit=END(kheap__system_heap);\n") + endif() + + set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) +endfunction() + +function(group_to_string) + cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) + + get_property(type GLOBAL PROPERTY ${STRING_OBJECT}_OBJ_TYPE) + if(${type} STREQUAL REGION) + get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) + get_property(address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS) + get_property(size GLOBAL PROPERTY ${STRING_OBJECT}_SIZE) + + get_property(empty GLOBAL PROPERTY ${STRING_OBJECT}_EMPTY) + if(empty) + return() + endif() + + else() + get_property(else_name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) + get_property(else_symbol GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOL) + string(TOLOWER ${else_name} else_name) + + get_objects(LIST sections OBJECT ${STRING_OBJECT} TYPE SECTION) + list(GET sections 0 section) + get_property(first_section_name GLOBAL PROPERTY ${section}_NAME) + + endif() + + if(${type} STREQUAL GROUP) + get_property(group_name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) + get_property(group_address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS) + get_property(group_vma GLOBAL PROPERTY ${STRING_OBJECT}_VMA) + get_property(group_lma GLOBAL PROPERTY ${STRING_OBJECT}_LMA) + endif() + + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED) + foreach(section ${sections}) + to_string(OBJECT ${section} STRING ${STRING_STRING}) + get_property(name GLOBAL PROPERTY ${section}_NAME) + get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN) + set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place at address mem:${address} { block ${name_clean} };\n") + endforeach() + + get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS) + foreach(group ${groups}) + to_string(OBJECT ${group} STRING ${STRING_STRING}) + endforeach() + + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS) + foreach(section ${sections}) + to_string(OBJECT ${section} STRING ${STRING_STRING}) + + get_property(name GLOBAL PROPERTY ${section}_NAME) + + get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN) + + get_property(parent GLOBAL PROPERTY ${section}_PARENT) + # This is only a trick to get the memories + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + if(${parent_type} STREQUAL GROUP) + get_property(vma GLOBAL PROPERTY ${parent}_VMA) + get_property(lma GLOBAL PROPERTY ${parent}_LMA) + endif() + + if(DEFINED vma) + set(ILINK_CURRENT_NAME ${vma}) + elseif(DEFINED lma) + set(ILINK_CURRENT_NAME ${lma}) + else() + # message(FATAL_ERROR "Need either vma or lma") + endif() + + set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place in ${ILINK_CURRENT_NAME} { block ${name_clean} };\n") + if(DEFINED vma AND DEFINED lma) + set(${STRING_STRING} "${${STRING_STRING}}\"${name}_init\": place in ${lma} { block ${name_clean}_init };\n") + endif() + + endforeach() + + get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM) + get_property(regions GLOBAL PROPERTY ${parent}_REGIONS) + list(REMOVE_ITEM regions ${STRING_OBJECT}) + + foreach(region ${regions}) + get_property(vma GLOBAL PROPERTY ${region}_NAME) + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED) + + foreach(section ${sections}) + to_string(OBJECT ${section} STRING ${STRING_STRING}) + endforeach() + + get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS) + foreach(group ${groups}) + to_string(OBJECT ${group} STRING ${STRING_STRING}) + endforeach() + + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS) + foreach(section ${sections}) + to_string(OBJECT ${section} STRING ${STRING_STRING}) + get_property(name GLOBAL PROPERTY ${section}_NAME) + string(REGEX REPLACE "^[\.]" "" name_clean "${name}") + string(REPLACE "." "_" name_clean "${name_clean}") + set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place in ${vma} { block ${name_clean} };\n") + + # Insert 'do not initialize' here + get_property(current_sections GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) + if(${name} STREQUAL .bss) + if(DEFINED current_sections) + set(${STRING_STRING} "${${STRING_STRING}}do not initialize\n") + set(${STRING_STRING} "${${STRING_STRING}}{\n") + foreach(section ${current_sections}) + set(${STRING_STRING} "${${STRING_STRING}} ${section},\n") + endforeach() + set(${STRING_STRING} "${${STRING_STRING}}};\n") + set(current_sections) + set_property(GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) + endif() + endif() + + if(${name_clean} STREQUAL last_ram_section) + get_property(group_name_lma GLOBAL PROPERTY ILINK_ROM_REGION_NAME) + set(${STRING_STRING} "${${STRING_STRING}}\n") + if(${CONFIG_LINKER_LAST_SECTION_ID}) + set(${STRING_STRING} "${${STRING_STRING}}define section last_section_id { udata32 ${CONFIG_LINKER_LAST_SECTION_ID_PATTERN}; };\n") + set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { section last_section_id };\n") + else() + set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { };\n") + endif() + # Not really the right place, we want the last used flash bytes not end of the world! + # set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place at end of ${group_name_lma} { block last_section };\n") + set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place in ${group_name_lma} { block last_section };\n") + set(${STRING_STRING} "${${STRING_STRING}}keep { block last_section };\n") + endif() + + endforeach() + endforeach() + + get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS) + set(${STRING_STRING} "${${STRING_STRING}}\n") + foreach(symbol ${symbols}) + to_string(OBJECT ${symbol} STRING ${STRING_STRING}) + endforeach() + + set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) +endfunction() + + +function(section_to_string) + cmake_parse_arguments(STRING "" "SECTION;STRING" "" ${ARGN}) + + get_property(name GLOBAL PROPERTY ${STRING_SECTION}_NAME) + get_property(address GLOBAL PROPERTY ${STRING_SECTION}_ADDRESS) + get_property(type GLOBAL PROPERTY ${STRING_SECTION}_TYPE) + get_property(align GLOBAL PROPERTY ${STRING_SECTION}_ALIGN) + get_property(subalign GLOBAL PROPERTY ${STRING_SECTION}_SUBALIGN) + get_property(endalign GLOBAL PROPERTY ${STRING_SECTION}_ENDALIGN) + get_property(vma GLOBAL PROPERTY ${STRING_SECTION}_VMA) + get_property(lma GLOBAL PROPERTY ${STRING_SECTION}_LMA) + get_property(noinput GLOBAL PROPERTY ${STRING_SECTION}_NOINPUT) + get_property(noinit GLOBAL PROPERTY ${STRING_SECTION}_NOINIT) + + get_property(nosymbols GLOBAL PROPERTY ${STRING_SECTION}_NOSYMBOLS) + get_property(start_syms GLOBAL PROPERTY ${STRING_SECTION}_START_SYMBOLS) + get_property(end_syms GLOBAL PROPERTY ${STRING_SECTION}_END_SYMBOLS) + + get_property(parent GLOBAL PROPERTY ${STRING_SECTION}_PARENT) + + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + if(${parent_type} STREQUAL GROUP) + get_property(group_parent_vma GLOBAL PROPERTY ${parent}_VMA) + get_property(group_parent_lma GLOBAL PROPERTY ${parent}_LMA) + if(NOT DEFINED vma) + get_property(vma GLOBAL PROPERTY ${parent}_VMA) + endif() + if(NOT DEFINED lma) + get_property(lma GLOBAL PROPERTY ${parent}_LMA) + endif() + endif() + + if(DEFINED group_parent_vma AND DEFINED group_parent_lma) + # Something to init + set(part "rw ") + else() + set(part) + endif() + + + set_property(GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) + + string(REGEX REPLACE "^[\.]" "" name_clean "${name}") + string(REPLACE "." "_" name_clean "${name_clean}") + + # WA for 'Error[Lc036]: no block or place matches the pattern "ro data section .tdata_init"' + if("${name_clean}" STREQUAL "tdata") + set(TEMP "${TEMP}define block ${name_clean}_init { ro section .tdata_init };\n") + set(TEMP "${TEMP}\"${name_clean}_init\": place in ${ILINK_CURRENT_NAME} { block ${name_clean}_init };\n\n") + endif() + + get_property(indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES) + # ZIP_LISTS partner + get_property(next_indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES) + list(POP_FRONT next_indicies first_index) + + set(first_index_section) + set(first_index_section_name) + if(DEFINED first_index) + # Handle case where the first section has an offset + get_property(first_index_offset + GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${first_index}_OFFSET) + get_property(keep GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${first_index}_KEEP) + if(DEFINED keep) + set(root "root ") + else() + set(root) + endif() + if(DEFINED first_index_offset AND NOT first_index_offset EQUAL 0 ) + set(first_index_section_name "${name_clean}_${first_index}_offset") + set(first_index_section + "define ${root}section ${first_index_section_name} {};") + else() + set(first_index) + endif() + endif() + + foreach(start_symbol ${start_syms}) + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${start_symbol} = ADDR(${name_clean})") + endforeach() + foreach(end_symbol ${end_syms}) + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${end_symbol} = END(${name_clean})") + endforeach() + + if(NOT nosymbols) + if("${name_clean}" STREQUAL "tdata") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_start = (__iar_tls$$INIT_DATA$$Base)") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_end = (__iar_tls$$INIT_DATA$$Limit)") + else() + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_start = ADDR(${name_clean})") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_end = END(${name_clean})") + endif() + endif() + + # Add keep to the sections that have 'KEEP:TRUE' + foreach(idx ${indicies}) + get_property(keep GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP) + get_property(input GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT) + foreach(setting ${input}) + if(keep) + # keep { section .abc* }; + set(TEMP "${TEMP}keep { section ${setting} };\n") + endif() + endforeach() + endforeach() + + if(DEFINED first_index_section) + set(TEMP "${TEMP}${first_index_section}\n") + endif() + + set(TEMP "${TEMP}define block ${name_clean} with fixed order") + + if(align) + set(TEMP "${TEMP}, alignment=${align}") + elseif(subalign) + set(TEMP "${TEMP}, alignment = ${subalign}") + elseif(part) + set(TEMP "${TEMP}, alignment = input") + else() + set(TEMP "${TEMP}, alignment=4") + endif() + if(endalign) + set(TEMP "${TEMP}, end alignment=${endalign}") + endif() + + set(TEMP "${TEMP}\n{") + + # foreach(start_symbol ${start_syms}) + # set(TEMP "${TEMP}\n section ${start_symbol},") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${start_symbol}") + # endforeach() + + # if(NOT nosymbols) + # set(TEMP "${TEMP}\n section __${name_clean}_start,") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section __${name_clean}_start") + # endif() + + list(GET indicies -1 last_index) + list(LENGTH indicies length) + + if(NOT noinput) + + set(TEMP "${TEMP}\n block ${name_clean}_winput") + if(align) + list(APPEND block_attr "alignment = ${align}") + elseif(subalign) + list(APPEND block_attr "alignment = ${subalign}") + elseif(part) + # list(APPEND block_attr "alignment = input") + else() + list(APPEND block_attr "alignment=4") + endif() + list(APPEND block_attr "fixed order") + + list(JOIN block_attr ", " block_attr_str) + if(block_attr_str) + set(TEMP "${TEMP} with ${block_attr_str}") + endif() + set(block_attr) + set(block_attr_str) + + set(TEMP "${TEMP} { ${part}section ${name}, ${part}section ${name}.* }") + if(${length} GREATER 0) + set(TEMP "${TEMP},") + endif() + set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${name}") + set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${name}.*") + endif() + + foreach(idx idx_next IN ZIP_LISTS indicies next_indicies) + get_property(align GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ALIGN) + get_property(any GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ANY) + get_property(first GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FIRST) + get_property(keep GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP) + get_property(sort GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SORT) + get_property(flags GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FLAGS) + get_property(input GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT) + get_property(symbols GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SYMBOLS) + # Get the next offset and use that as this ones size! + get_property(offset GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx_next}_OFFSET) + + if(DEFINED symbols) + list(LENGTH symbols symbols_count) + if(${symbols_count} GREATER 0) + list(GET symbols 0 symbol_start) + endif() + if(${symbols_count} GREATER 1) + list(GET symbols 1 symbol_end) + endif() + endif() + + if(DEFINED symbol_start) + # set(TEMP "${TEMP}\n section ${symbol_start},") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${symbol_start}") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${symbol_start} = ADDR(${name_clean}_${idx})") + endif() + + if(DEFINED first_index AND first_index EQUAL ${idx}) + # Create the offset + set(TEMP "${TEMP}\n block ${first_index_section_name}") + list(APPEND block_attr "size = ${first_index_offset}") + if(sort) + if(${sort} STREQUAL NAME) + list(APPEND block_attr "alphabetical order") + endif() + endif() + if(align) + list(APPEND block_attr "alignment = ${align}") + elseif(subalign) + list(APPEND block_attr "alignment = ${subalign}") + elseif(part) + # list(APPEND block_attr "alignment = input") + else() + list(APPEND block_attr "alignment=4") + endif() + list(APPEND block_attr "fixed order") + + list(JOIN block_attr ", " block_attr_str) + if(block_attr_str) + set(TEMP "${TEMP} with ${block_attr_str}") + endif() + set(block_attr) + set(block_attr_str) + + set(TEMP "${TEMP} { section ${first_index_section_name} },\n") + endif() + + # block init_100 with alphabetical order { section .z_init_EARLY?_} + set(TEMP "${TEMP}\n block ${name_clean}_${idx}") + if(DEFINED offset AND NOT offset EQUAL 0 ) + list(APPEND block_attr "size = ${offset}") + elseif(DEFINED offset AND offset STREQUAL 0 ) + # Do nothing + endif() + if(sort) + if(${sort} STREQUAL NAME) + list(APPEND block_attr "alphabetical order") + endif() + endif() + if(align) + list(APPEND block_attr "alignment = ${align}") + elseif(subalign) + list(APPEND block_attr "alignment = ${subalign}") + elseif(part) + # list(APPEND block_attr "alignment = input") + else() + list(APPEND block_attr "alignment=4") + endif() + + # LD + # There are two ways to include more than one section: + # + # *(.text .rdata) + # *(.text) *(.rdata) + # + # The difference between these is the order in which + # the `.text' and `.rdata' input sections will appear in the output section. + # In the first example, they will be intermingled, + # appearing in the same order as they are found in the linker input. + # In the second example, all `.text' input sections will appear first, + # followed by all `.rdata' input sections. + # + # ILINK solved by adding 'fixed order' + if(NOT sort AND NOT first) + list(APPEND block_attr "fixed order") + endif() + + list(JOIN block_attr ", " block_attr_str) + if(block_attr_str) + set(TEMP "${TEMP} with ${block_attr_str}") + endif() + set(block_attr) + set(block_attr_str) + + if(empty) + set(TEMP "${TEMP}\n {") + set(empty FALSE) + endif() + + list(GET input -1 last_input) + + set(TEMP "${TEMP} {") + if(NOT DEFINED input AND NOT any) + set(TEMP "${TEMP} }") + endif() + + foreach(setting ${input}) + if(first) + set(TEMP "${TEMP} first") + set(first "") + endif() + + set(section_type "") + + # build for ram, no section_type + # if("${lma}" STREQUAL "${vma}") + # # if("${vma}" STREQUAL "") + # set(section_type "") + # # else() + # # set(section_type " readwrite") + # # endif() + # elseif(NOT "${vma}" STREQUAL "") + # set(section_type " readwrite") + # elseif(NOT "${lma}" STREQUAL "") + # set(section_type " readonly") + # else() + # message(FATAL_ERROR "How to handle this? lma=${lma} vma=${vma}") + # endif() + + set(TEMP "${TEMP}${section_type} ${part}section ${setting}") + set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${setting}") + set(section_type "") + + if("${setting}" STREQUAL "${last_input}") + set(TEMP "${TEMP} }") + else() + set(TEMP "${TEMP}, ") + endif() + + # set(TEMP "${TEMP}\n *.o(${setting})") + endforeach() + + if(any) + if(NOT flags) + message(FATAL_ERROR ".ANY requires flags to be set.") + endif() + set(ANY_FLAG "") + foreach(flag ${flags}) + # if("${flag}" STREQUAL +RO OR "${flag}" STREQUAL +XO) + # set(ANY_FLAG "readonly") + # # elseif("${flag}" STREQUAL +RW) + # # set(ANY_FLAG "readwrite") + # else + if("${flag}" STREQUAL +ZI) + set(ANY_FLAG "zeroinit") + set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "${ANY_FLAG}") + endif() + endforeach() + set(TEMP "${TEMP} ${ANY_FLAG} }") + endif() + + if(DEFINED symbol_end) + # set(TEMP "${TEMP},\n section ${symbol_end}") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${symbol_end}") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${symbol_end} = END(${name_clean}_${idx})") + endif() + if(${length} GREATER 0) + if(NOT "${idx}" STREQUAL "${last_index}") + set(TEMP "${TEMP},") + elseif() + endif() + endif() + + set(symbol_start) + set(symbol_end) + endforeach() + set(next_indicies) + + set(last_index) + set(last_input) + set(TEMP "${TEMP}") + + # if(NOT nosymbols) + # set(TEMP "${TEMP},\n section __${name_clean}_end") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section __${name_clean}_end") + # endif() + + # foreach(end_symbol ${end_syms}) + # set(TEMP "${TEMP},\n section ${end_symbol}") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${end_symbol}") + # endforeach() + + set(TEMP "${TEMP}\n};") + + get_property(type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + if(${type} STREQUAL REGION) + get_property(name GLOBAL PROPERTY ${parent}_NAME) + get_property(address GLOBAL PROPERTY ${parent}_ADDRESS) + get_property(size GLOBAL PROPERTY ${parent}_SIZE) + + endif() + + get_property(current_sections GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) + + if(DEFINED group_parent_vma AND DEFINED group_parent_lma) + if(DEFINED current_sections) + # "${TEMP}" is there too keep the ';' else it will be a list + string(REGEX REPLACE "(block[ \t\r\n]+)([^ \t\r\n]+)" "\\1\\2_init" INIT_TEMP "${TEMP}") + string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)([^ \t\r\n,]+)" "\\1\\2\\3\\4_init" INIT_TEMP "${INIT_TEMP}") + string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)" "ro\\2\\3" INIT_TEMP "${INIT_TEMP}") + string(REGEX REPLACE "alphabetical order, " "" INIT_TEMP "${INIT_TEMP}") + string(REGEX REPLACE "{ readwrite }" "{ }" INIT_TEMP "${INIT_TEMP}") + + set(TEMP "${TEMP}\n${INIT_TEMP}\n") + set(TEMP "${TEMP}\ninitialize manually with copy friendly\n") + set(TEMP "${TEMP}{\n") + foreach(section ${current_sections}) + set(TEMP "${TEMP} ${section},\n") + endforeach() + set(TEMP "${TEMP}};") + set(current_sections) + + endif() + endif() + + set(${STRING_STRING} "${${STRING_STRING}}\n${TEMP}\n" PARENT_SCOPE) +endfunction() + +function(symbol_to_string) + cmake_parse_arguments(STRING "" "SYMBOL;STRING" "" ${ARGN}) + + get_property(name GLOBAL PROPERTY ${STRING_SYMBOL}_NAME) + get_property(expr GLOBAL PROPERTY ${STRING_SYMBOL}_EXPR) + get_property(size GLOBAL PROPERTY ${STRING_SYMBOL}_SIZE) + get_property(symbol GLOBAL PROPERTY ${STRING_SYMBOL}_SYMBOL) + get_property(subalign GLOBAL PROPERTY ${STRING_SYMBOL}_SUBALIGN) + + string(REPLACE "\\" "" expr "${expr}") + string(REGEX MATCHALL "@([^@]*)@" match_res ${expr}) + + foreach(match ${match_res}) + string(REPLACE "@" "" match ${match}) + get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE_${match}) + string(REPLACE "@${match}@" "${match}" expr ${expr}) + endforeach() + + list(LENGTH match_res match_res_count) + + if(match_res_count) + if(${match_res_count} GREATER 1) + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n" + ) + else() + if((expr MATCHES "Base|Limit|Length") OR (expr MATCHES "ADDR\\(|END\\(|SIZE\\(")) + # Anything like $$Base/$$Limit/$$Length should be an image symbol + if( "${symbol}" STREQUAL "__tdata_size") + # This will handle the alignment of the TBSS block + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol}=(__iar_tls$$INIT_DATA$$Limit-__iar_tls$$INIT_DATA$$Base);\n" + ) + elseif( "${symbol}" STREQUAL "__tbss_size") + # This will handle the alignment of the TBSS block by + # pre-padding bytes + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol}=((tbss$$Limit-__iar_tls$$DATA$$Base)-(__iar_tls$$INIT_DATA$$Limit-__iar_tls$$INIT_DATA$$Base));\n" + ) + else() + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n" + ) + endif() + else() + list(GET match_res 0 match) + string(REPLACE "@" "" match ${match}) + get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE_${match}) + if(symbol_val) + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n" + ) + else() + # Treatmen of "zephyr_linker_symbol(SYMBOL z_arm_platform_init EXPR "@SystemInit@")" + set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE + "--redirect ${symbol}=${expr}\n" + ) + endif() + endif() + endif() + else() + # Handle things like ADDR(.ramfunc) + if(${expr} MATCHES "^[A-Za-z]?ADDR\\(.+\\)") + # string(REGEX REPLACE "^[A-Za-z]?ADDR\\((.+)\\)" "(\\1$$Base)" expr ${expr}) + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n" + ) + else() + set(${STRING_STRING} + "${${STRING_STRING}}define exported symbol ${symbol} = ${expr};\n" + ) + endif() + endif() + + set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) +endfunction() + +include(${CMAKE_CURRENT_LIST_DIR}/../linker_script_common.cmake) + +if(DEFINED STEERING_FILE) + get_property(steering_content GLOBAL PROPERTY SYMBOL_STEERING_FILE) + file(WRITE ${STEERING_FILE} "/* AUTO-GENERATED - Do not modify\n") + file(APPEND ${STEERING_FILE} " * AUTO-GENERATED - All changes will be lost\n") + file(APPEND ${STEERING_FILE} " */\n") + + file(APPEND ${STEERING_FILE} ${steering_content}) +endif() diff --git a/cmake/linker/iar/linker_flags.cmake b/cmake/linker/iar/linker_flags.cmake new file mode 100644 index 0000000000000..f65925ff8a894 --- /dev/null +++ b/cmake/linker/iar/linker_flags.cmake @@ -0,0 +1,14 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Override the default CMake's IAR ILINK linker signature + +string(APPEND CMAKE_C_LINK_FLAGS --no-wrap-diagnostics ) + +foreach(lang C CXX ASM) + set(commands "--log modules,libraries,initialization,redirects,sections") + set(CMAKE_${lang}_LINK_EXECUTABLE + " ${commands} -o ") + set(commands) +endforeach() diff --git a/cmake/linker/iar/target.cmake b/cmake/linker/iar/target.cmake new file mode 100644 index 0000000000000..f2326b60491aa --- /dev/null +++ b/cmake/linker/iar/target.cmake @@ -0,0 +1,135 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +set_property(TARGET linker PROPERTY devices_start_symbol "_device_list_start") +find_program(CMAKE_LINKER + NAMES ${CROSS_COMPILE}${IAR_LINKER} + PATHS ${TOOLCHAIN_HOME} + PATH_SUFFIXES bin + NO_DEFAULT_PATH +) + +add_custom_target(${IAR_LINKER}) +set(ILINK_THUMB_CALLS_WARNING_SUPPRESSED) +set(IAR_LIB_USED) +function(toolchain_ld_force_undefined_symbols "") +# foreach(symbol ${ARGN}) +# zephyr_link_libraries(--place_holder=${symbol}) +# endforeach() +endfunction() + +# NOTE: ${linker_script_gen} will be produced at build-time; not at configure-time +macro(configure_linker_script linker_script_gen linker_pass_define) + set(extra_dependencies ${ARGN}) + set(STEERING_FILE "${CMAKE_CURRENT_BINARY_DIR}/${linker_script_gen}.xcl") + set(STEERING_FILE_ARG "-DSTEERING_FILE=${STEERING_FILE}") + set(cmake_linker_script_settings + ${PROJECT_BINARY_DIR}/include/generated/ld_script_settings_${linker_pass_define}.cmake + ) + if("${linker_pass_define}" STREQUAL "LINKER_ZEPHYR_PREBUILT") + set(ILINK_THUMB_CALLS_WARNING_SUPPRESSED "--diag_suppress=Lt056") + else() + set(ILINK_THUMB_CALLS_WARNING_SUPPRESSED "") + endif() + if(CONFIG_IAR_LIBC OR CONFIG_IAR_LIBCPP) + set(IAR_LIB_USED "-DIAR_LIBC=1") + else() + set(IAR_LIB_USED "") + endif() + + file(GENERATE OUTPUT ${cmake_linker_script_settings} CONTENT + "set(FORMAT \"$\" CACHE INTERNAL \"\")\n + set(ENTRY \"$\" CACHE INTERNAL \"\")\n + set(MEMORY_REGIONS \"$\" CACHE INTERNAL \"\")\n + set(GROUPS \"$\" CACHE INTERNAL \"\")\n + set(SECTIONS \"$\" CACHE INTERNAL \"\")\n + set(SECTION_SETTINGS \"$\" CACHE INTERNAL \"\")\n + set(SYMBOLS \"$\" CACHE INTERNAL \"\")\n + " + ) + add_custom_command( + OUTPUT ${linker_script_gen} + ${STEERING_FILE} + DEPENDS + ${extra_dependencies} + ${DEVICE_API_LD_TARGET} + COMMAND ${CMAKE_COMMAND} + -C ${DEVICE_API_LINKER_SECTIONS_CMAKE} + -C ${cmake_linker_script_settings} + -DPASS="${linker_pass_define}" + ${STEERING_FILE_ARG} + -DCONFIG_LINKER_LAST_SECTION_ID=${CONFIG_LINKER_LAST_SECTION_ID} + -DCONFIG_LINKER_LAST_SECTION_ID_PATTERN=${CONFIG_LINKER_LAST_SECTION_ID_PATTERN} + -DOUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/${linker_script_gen} + ${IAR_LIB_USED} + -P ${ZEPHYR_BASE}/cmake/linker/iar/config_file_script.cmake + ) + +endmacro() + +function(toolchain_ld_link_elf) + cmake_parse_arguments( + TOOLCHAIN_LD_LINK_ELF # prefix of output variables + "" # list of names of the boolean arguments + "TARGET_ELF;OUTPUT_MAP;LINKER_SCRIPT" # list of names of scalar arguments + "LIBRARIES_PRE_SCRIPT;LIBRARIES_POST_SCRIPT;DEPENDENCIES" # list of names of list arguments + ${ARGN} # input args to parse + ) + + foreach(lib ${ZEPHYR_LIBS_PROPERTY}) + list(APPEND ZEPHYR_LIBS_OBJECTS $) + list(APPEND ZEPHYR_LIBS_OBJECTS $) + endforeach() + + set(ILINK_SEMIHOSTING) + set(ILINK_BUFFERED_WRITE) + if(${CONFIG_IAR_SEMIHOSTING}) + set(ILINK_SEMIHOSTING "--semihosting") + endif() + if(${CONFIG_IAR_BUFFERED_WRITE}) + set(ILINK_BUFFERED_WRITE "--redirect __write=__write_buffered") + endif() + + set(ILINK_XCL "-f ${TOOLCHAIN_LD_LINK_ELF_LINKER_SCRIPT}.xcl") + + set(ILINK_TLS_LIBRARY) + if(${CONFIG_THREAD_LOCAL_STORAGE}) + set(ILINK_TLS_LIBRARY "--threaded_lib=manual") + endif() + + set(ILINK_TZONE_LIBRARY) + # if(${CONFIG_IAR_LIBC}) + # set(ILINK_TZONE_LIBRARY "--timezone_lib") + # endif() + + target_link_libraries( + ${TOOLCHAIN_LD_LINK_ELF_TARGET_ELF} + ${TOOLCHAIN_LD_LINK_ELF_LIBRARIES_PRE_SCRIPT} + --config=${TOOLCHAIN_LD_LINK_ELF_LINKER_SCRIPT} + ${TOOLCHAIN_LD_LINK_ELF_LIBRARIES_POST_SCRIPT} + --map=${TOOLCHAIN_LD_LINK_ELF_OUTPUT_MAP} + --log_file=${TOOLCHAIN_LD_LINK_ELF_OUTPUT_MAP}.log + + ${ZEPHYR_LIBS_OBJECTS} + kernel + $ + --entry=$ + + ${ILINK_SEMIHOSTING} + ${ILINK_BUFFERED_WRITE} + ${ILINK_TLS_LIBRARY} + ${ILINK_TZONE_LIBRARY} + ${ILINK_THUMB_CALLS_WARNING_SUPPRESSED} + # Do not remove symbols + #--no_remove + ${ILINK_XCL} + + ${TOOLCHAIN_LIBS_OBJECTS} + + ${TOOLCHAIN_LD_LINK_ELF_DEPENDENCIES} + ) +endfunction(toolchain_ld_link_elf) + +include(${ZEPHYR_BASE}/cmake/linker/ld/target_relocation.cmake) +include(${ZEPHYR_BASE}/cmake/linker/ld/target_configure.cmake) diff --git a/cmake/toolchain/iar/Kconfig b/cmake/toolchain/iar/Kconfig new file mode 100644 index 0000000000000..056fa5d499f4d --- /dev/null +++ b/cmake/toolchain/iar/Kconfig @@ -0,0 +1,40 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +config LD_LINKER_SCRIPT_SUPPORTED + default n + +choice LINKER_SCRIPT + default CMAKE_LINKER_GENERATOR +endchoice + +menu "IAR library options" + +config IAR_SEMIHOSTING + bool "Use the IAR semihosting implementation." + depends on IAR_LIBC + help + Use the semihosting implementation in the IAR library + instead of the Zephyr implementation. + +config IAR_BUFFERED_WRITE + bool "Use buffered write" + depends on IAR_SEMIHOSTING + help + Instead of printing one character at a time + this option uses a buffer to print a line + at a time instead, increasing speed of printout. + +endmenu + +config TOOLCHAIN_IAR_SUPPORTS_THREAD_LOCAL_STORAGE + def_bool y + select TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE + +# Should we set this? It doesn't seem to be used +# We support most but don't set __GNUC__ +# +config TOOLCHAIN_IAR_SUPPORTS_GNU_EXTENSIONS + def_bool y + select TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS diff --git a/cmake/toolchain/iar/Kconfig.defconfig b/cmake/toolchain/iar/Kconfig.defconfig new file mode 100644 index 0000000000000..506e81b87ba9a --- /dev/null +++ b/cmake/toolchain/iar/Kconfig.defconfig @@ -0,0 +1,53 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + + +config MISRA_SANE + default y + +config PICOLIBC_SUPPORTED + default n + +config TOOLCHAIN_HAS_BUILTIN_FFS + default n + +config FP16 + default y + +config IAR_LIBC_SUPPORTED + default y + +config COMPILER_FREESTANDING + default y + +config CBPRINTF_LIBC_SUBSTS + default y + +# IAR has slightly different types +config ENFORCE_ZEPHYR_STDINT + default n + +# IAR uses a little bit more stack than GCC +config TEST_EXTRA_STACK_SIZE + default 64 + +# ICCARM does not support relaxation +config LINKER_USE_NO_RELAX + default y + +# ICCARM support C17 with some additional features from C23 +config REQUIRES_STD_C17 + default y + +config CODING_GUIDELINE_CHECK + default n + help + Not applicable to ICCARM + +config TC_PROVIDES_POSIX_C_LANG_SUPPORT_R + default n + +# ICCARM does not support +config COMMON_LIBC_THRD + default n diff --git a/cmake/toolchain/iar/generic.cmake b/cmake/toolchain/iar/generic.cmake new file mode 100644 index 0000000000000..645ba19ecb989 --- /dev/null +++ b/cmake/toolchain/iar/generic.cmake @@ -0,0 +1,46 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_get(IAR_TOOLCHAIN_PATH) +assert(IAR_TOOLCHAIN_PATH "IAR_TOOLCHAIN_PATH is not set") + +set(IAR_TOOLCHAIN_VARIANT none) +if(NOT EXISTS ${IAR_TOOLCHAIN_PATH}) + message(FATAL_ERROR "Nothing found at IAR_TOOLCHAIN_PATH: '${IAR_TOOLCHAIN_PATH}'") +endif() + +if(EXISTS ${IAR_TOOLCHAIN_PATH}/bin/iccarm) + message(STATUS "Found toolchain: IAR C/C++ Compiler for Arm (${IAR_TOOLCHAIN_PATH})") + set(IAR_COMPILER iccarm) + set(IAR_LINKER ilinkarm) +elseif(EXISTS ${IAR_TOOLCHAIN_PATH}/bin/iccarm.exe) + message(STATUS "Found toolchain: IAR C/C++ Compiler for Arm (${IAR_TOOLCHAIN_PATH})") + set(IAR_COMPILER iccarm) + set(IAR_LINKER ilinkarm) +endif() + +set(IAR_TOOLCHAIN_VARIANT ${IAR_COMPILER}) + +# iar relies on Zephyr SDK for the use of C preprocessor (devicetree) and objcopy +find_package(Zephyr-sdk 0.16 REQUIRED) +message(STATUS "Found Zephyr SDK at ${ZEPHYR_SDK_INSTALL_DIR}") + +set(TOOLCHAIN_HOME ${IAR_TOOLCHAIN_PATH}) + +# Handling to be improved in Zephyr SDK, to avoid overriding ZEPHYR_TOOLCHAIN_VARIANT by +# find_package(Zephyr-sdk) if it's already set +set(ZEPHYR_TOOLCHAIN_VARIANT iar) + +set(COMPILER iar) +set(LINKER iar) +set(BINTOOLS iar) + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + set(SYSROOT_TARGET arm) +else() + set(SYSROOT_TARGET riscv) +endif() +set(CROSS_COMPILE ${TOOLCHAIN_HOME}/bin/) + +set(TOOLCHAIN_HAS_NEWLIB OFF CACHE BOOL "True if toolchain supports NewLib") diff --git a/cmake/toolchain/iar/target.cmake b/cmake/toolchain/iar/target.cmake new file mode 100644 index 0000000000000..b11635894a639 --- /dev/null +++ b/cmake/toolchain/iar/target.cmake @@ -0,0 +1,5 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Intentionally left blank. diff --git a/include/zephyr/arch/arm/asm_inline.h b/include/zephyr/arch/arm/asm_inline.h index fe36fb2d0e196..54bf2a6f4594e 100644 --- a/include/zephyr/arch/arm/asm_inline.h +++ b/include/zephyr/arch/arm/asm_inline.h @@ -14,10 +14,10 @@ * Include kernel.h instead */ -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__ICCARM__) #include #else -#include +#error Unknown toolchain in asm_inline.h #endif #endif /* ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_H_ */ diff --git a/include/zephyr/toolchain.h b/include/zephyr/toolchain.h index bc389ae55656e..93ace9520f8a1 100644 --- a/include/zephyr/toolchain.h +++ b/include/zephyr/toolchain.h @@ -44,6 +44,8 @@ #include #elif defined(__ARMCOMPILER_VERSION) #include +#elif defined(__IAR_SYSTEMS_ICC__) +#include #elif defined(__llvm__) || (defined(_LINKER) && defined(__LLD_LINKER_CMD__)) #include #elif defined(__GNUC__) || (defined(_LINKER) && defined(__GCC_LINKER_CMD__)) diff --git a/include/zephyr/toolchain/iar.h b/include/zephyr/toolchain/iar.h new file mode 100644 index 0000000000000..76738c528fe2d --- /dev/null +++ b/include/zephyr/toolchain/iar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_IAR_H_ +#define ZEPHYR_INCLUDE_TOOLCHAIN_IAR_H_ + +#ifdef TOOLCHAIN_PRAGMA +#define _TOOLCHAIN_DISABLE_WARNING(warning) TOOLCHAIN_PRAGMA(diag_suppress = warning) +#define _TOOLCHAIN_ENABLE_WARNING(warning) TOOLCHAIN_PRAGMA(diag_default = warning) + +#define TOOLCHAIN_DISABLE_WARNING(warning) _TOOLCHAIN_DISABLE_WARNING(warning) +#define TOOLCHAIN_ENABLE_WARNING(warning) _TOOLCHAIN_ENABLE_WARNING(warning) +#endif + +#ifdef __ICCARM__ +#include "iar/iccarm.h" +#endif +#ifdef __ICCRISCV__ +#include "iar/iccriscv.h" +#endif + +#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_H_ */ diff --git a/include/zephyr/toolchain/iar/iar_missing_defs.h b/include/zephyr/toolchain/iar/iar_missing_defs.h new file mode 100644 index 0000000000000..44541adaccd53 --- /dev/null +++ b/include/zephyr/toolchain/iar/iar_missing_defs.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Basic macro definitions that gcc and clang provide on their own + * but that iccarm lacks. Only those that Zephyr requires are provided here. + */ + +#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_MISSING_DEFS_H_ +#define ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_MISSING_DEFS_H_ + + /* We need to define NULL with a parenthesis around _NULL + * otherwise the DEBRACE macros won't work correctly + */ + +#undef NULL +#define NULL (_NULL) + +#if defined(__IAR_SYSTEMS_ICC__) +#ifndef __CHAR_BIT__ +#define __CHAR_BIT__ __CHAR_BITS__ +#endif +#define __SCHAR_MAX__ __SIGNED_CHAR_MAX__ + +#define __INT_MAX__ __SIGNED_INT_MAX__ +#define __INT_WIDTH__ (__INT_SIZE__*8) +#define __SIZEOF_INT__ __INT_SIZE__ + +#define __SHRT_MAX__ __SIGNED_SHORT_MAX__ +#define __SHRT_WIDTH__ (__SHORT_SIZE__*8) +#define __SIZEOF_SHORT__ __SHORT_SIZE__ + +#define __LONG_MAX__ __SIGNED_LONG_MAX__ +#define __LONG_WIDTH__ (__LONG_SIZE__*8) +#define __SIZEOF_LONG__ __LONG_SIZE__ + +#define __LONG_LONG_MAX__ __SIGNED_LONG_LONG_MAX__ +#define __LONG_LONG_WIDTH__ (__LONG_LONG_SIZE__*8) +#define __SIZEOF_LONG_LONG__ __LONG_LONG_SIZE__ + +#define __INTMAX_MAX__ __INTMAX_T_MAX__ +#define __SIZEOF_INTMAX__ sizeof(__INTMAX_T_TYPE__) +#define __INTMAX_WIDTH__ (__SIZEOF_INTMAX__*8) +#define __UINTMAX_MAX__ __UINTMAX_T_MAX__ +#define __SIZEOF_UINTMAX__ sizeof(__UINTMAX_T_TYPE__) +#define __UINTMAX_WIDTH__ (__SIZEOF_UINTMAX__*8) + +#define __INTPTR_MAX__ __INTPTR_T_MAX__ +#define __INTPTR_TYPE__ __INTPTR_T_TYPE__ +#define __INTPTR_WIDTH__ (__INTPTR_T_SIZE__*8) +#define __SIZEOF_POINTER__ __INTPTR_T_SIZE__ + +#define __PTRDIFF_MAX__ __PTRDIFF_T_MAX__ +#define __PTRDIFF_WIDTH__ (__PTRDIFF_T_SIZE__*8) +#define __SIZEOF_PTRDIFF_T__ __PTRDIFF_T_SIZE__ + +#define __UINTPTR_MAX__ __UINTPTR_T_MAX__ +#define __UINTPTR_TYPE__ __UINTPTR_T_TYPE__ + +/* + * ICCARM already defines __SIZE_T_MAX__ as "unsigned int" but there is no way + * to safeguard that here with preprocessor equality. + */ + +#define __SIZE_TYPE__ __SIZE_T_TYPE__ +#define __SIZE_MAX__ __SIZE_T_MAX__ +#define __SIZE_WIDTH__ ((__SIZEOF_SIZE_T__)*8) +/* #define __SIZEOF_SIZE_T__ 4 */ + +/* + * The following defines are inferred from the ICCARM provided defines + * already tested above. + */ + + +#define __INT8_MAX__ __INT8_T_MAX__ +#define __INT8_TYPE__ __INT8_T_TYPE__ + +#define __UINT8_MAX__ __UINT8_T_MAX__ +#define __UINT8_TYPE__ __UINT8_T_TYPE__ + +#define __INT16_MAX__ __INT16_T_MAX__ +#define __INT16_TYPE__ __INT16_T_TYPE__ + +#define __UINT16_MAX__ __UINT16_T_MAX__ +#define __UINT16_TYPE__ __UINT16_T_TYPE__ + +#define __INT32_MAX__ __INT32_T_MAX__ +#define __INT32_TYPE__ __INT32_T_TYPE__ + +#define __UINT32_MAX__ __UINT32_T_MAX__ +#define __UINT32_TYPE__ __UINT32_T_TYPE__ + +#define __INT64_MAX__ __INT64_T_MAX__ +#define __INT64_TYPE__ __INT64_T_TYPE__ + +#define __UINT64_MAX__ __UINT64_T_MAX__ +#define __UINT64_TYPE__ __UINT64_T_TYPE__ + +#define __INT_FAST8_MAX__ __INT_FAST8_T_MAX__ +#define __INT_FAST8_TYPE__ __INT_FAST8_T_TYPE__ +#define __INT_FAST8_WIDTH__ (__INT_FAST8_T_SIZE__*8) + +#define __INT_FAST16_MAX__ __INT_FAST16_T_MAX__ +#define __INT_FAST16_TYPE__ __INT_FAST16_T_TYPE__ +#define __INT_FAST16_WIDTH__ (__INT_FAST16_T_SIZE__*8) + +#define __INT_FAST32_MAX__ __INT_FAST32_T_MAX__ +#define __INT_FAST32_TYPE__ __INT_FAST32_T_TYPE__ +#define __INT_FAST32_WIDTH__ (__INT_FAST32_T_SIZE__*8) + +#define __INT_FAST64_MAX__ __INT_FAST64_T_MAX__ +#define __INT_FAST64_TYPE__ __INT_FAST64_T_TYPE__ +#define __INT_FAST64_WIDTH__ (__INT_FAST64_T_SIZE__*8) + +#define __INT_LEAST8_MAX__ __INT_LEAST8_T_MAX__ +#define __INT_LEAST8_TYPE__ __INT_LEAST8_T_TYPE__ +#define __INT_LEAST8_WIDTH__ (__INT_LEAST8_T_SIZE__*8) + +#define __INT_LEAST16_MAX__ __INT_LEAST16_T_MAX__ +#define __INT_LEAST16_TYPE__ __INT_LEAST16_T_TYPE__ +#define __INT_LEAST16_WIDTH__ (__INT_LEAST16_T_SIZE__*8) + +#define __INT_LEAST32_MAX__ __INT_LEAST32_T_MAX__ +#define __INT_LEAST32_TYPE__ __INT_LEAST32_T_TYPE__ +#define __INT_LEAST32_WIDTH__ (__INT_LEAST32_T_SIZE__*8) + +#define __INT_LEAST64_MAX__ __INT_LEAST64_T_MAX__ +#define __INT_LEAST64_TYPE__ __INT_LEAST64_T_TYPE__ +#define __INT_LEAST64_WIDTH__ (__INT_LEAST64_T_SIZE__*8) + +#define __UINT_FAST8_MAX__ __UINT_FAST8_T_MAX__ +#define __UINT_FAST8_TYPE__ __UINT_FAST8_T_TYPE__ + +#define __UINT_FAST16_MAX__ __UINT_FAST16_T_MAX__ +#define __UINT_FAST16_TYPE__ __UINT_FAST16_T_TYPE__ + +#define __UINT_FAST32_MAX__ __UINT_FAST32_T_MAX__ +#define __UINT_FAST32_TYPE__ __UINT_FAST32_T_TYPE__ + +#define __UINT_FAST64_MAX__ __UINT_FAST64_T_MAX__ +#define __UINT_FAST64_TYPE__ __UINT_FAST64_T_TYPE__ + +#define __UINT_LEAST8_MAX__ __UINT_LEAST8_T_MAX__ +#define __UINT_LEAST8_TYPE__ __UINT_LEAST8_T_TYPE__ + +#define __UINT_LEAST16_MAX__ __UINT_LEAST16_T_MAX__ +#define __UINT_LEAST16_TYPE__ __UINT_LEAST16_T_TYPE__ + +#define __UINT_LEAST32_MAX__ __UINT_LEAST32_T_MAX__ +#define __UINT_LEAST32_TYPE__ __UINT_LEAST32_T_TYPE__ + +#define __UINT_LEAST64_MAX__ __UINT_LEAST64_T_MAX__ +#define __UINT_LEAST64_TYPE__ __UINT_LEAST64_T_TYPE__ + +#endif /* __IAR_SYSTEMS_ICC__ */ + +#endif diff --git a/include/zephyr/toolchain/iar/iccarm.h b/include/zephyr/toolchain/iar/iccarm.h new file mode 100644 index 0000000000000..cc79102332979 --- /dev/null +++ b/include/zephyr/toolchain/iar/iccarm.h @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_H_ +#define ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_H_ + +/** + * @file + * @brief ICCARM toolchain abstraction + * + * Macros to abstract compiler capabilities for ICCARM toolchain. + */ + +/* ICCARM supports its own #pragma diag_{warning,default,error,warning}. */ +/* #define TOOLCHAIN_HAS_PRAGMA_DIAG 0 */ + +#define TOOLCHAIN_HAS_C_GENERIC 1 + +#define TOOLCHAIN_HAS_C_AUTO_TYPE 1 + +/* #define TOOLCHAIN_HAS_ZLA 1 */ + +/* + * IAR do not define __BYTE_ORDER__, so it must be manually + * detected and defined using arch-specific definitions. + */ + +#ifndef _LINKER + +#ifndef __ORDER_BIG_ENDIAN__ +#define __ORDER_BIG_ENDIAN__ (1) +#endif /* __ORDER_BIG_ENDIAN__ */ + +#ifndef __ORDER_LITTLE_ENDIAN__ +#define __ORDER_LITTLE_ENDIAN__ (2) +#endif /* __ORDER_LITTLE_ENDIAN__ */ + +#ifndef __ORDER_PDP_ENDIAN__ +#define __ORDER_PDP_ENDIAN__ (3) +#endif /* __ORDER_PDP_ENDIAN__ */ + +#ifndef __BYTE_ORDER__ + +#if __LITTLE_ENDIAN__ == 1 +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#else +#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__ +#endif /* __LITTLE_ENDIAN__ == 1 */ + +#endif /* __BYTE_ORDER__ */ + + +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define BUILD_ASSERT(EXPR, MSG...) static_assert(EXPR, "" MSG) +#elif defined(__ICCARM__) +#define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG) +#endif + +/* Zephyr makes use of __ATOMIC_SEQ_CST */ +#ifdef __STDC_NO_ATOMICS__ +#ifndef __ATOMIC_SEQ_CST +#define __MEMORY_ORDER_SEQ_CST__ 5 +#endif +#endif +#ifndef __ATOMIC_SEQ_CST +#define __ATOMIC_SEQ_CST __MEMORY_ORDER_SEQ_CST__ +#endif + +/* By default, restrict is recognized in Standard C + * __restrict is always recognized + */ +#define ZRESTRICT __restrict + +#include +#include + +#define ALIAS_OF(of) __attribute__((alias(#of))) + +#define FUNC_ALIAS(real_func, new_alias, return_type) \ + return_type new_alias() ALIAS_OF(real_func) + +#define CODE_UNREACHABLE __builtin_unreachable() +#define FUNC_NORETURN __attribute__((__noreturn__)) + +#define _NODATA_SECTION(segment) __attribute__((section(#segment))) + +/* Unaligned access */ +#define UNALIGNED_GET(p) \ +__extension__ ({ \ + struct __attribute__((__packed__)) { \ + __typeof__(*(p)) __v; \ + } *__p = (__typeof__(__p)) (p); \ + __p->__v; \ +}) + +#define UNALIGNED_PUT(v, p) \ +do { \ + struct __attribute__((__packed__)) { \ + __typeof__(*p) __v; \ + } *__p = (__typeof__(__p)) (p); \ + __p->__v = (v); \ +} while (false) + + +/* Double indirection to ensure section names are expanded before + * stringification + */ +#define __GENERIC_SECTION(segment) __attribute__((section(STRINGIFY(segment)))) +#define Z_GENERIC_SECTION(segment) __GENERIC_SECTION(segment) + +#define __GENERIC_DOT_SECTION(segment) \ + __attribute__((section("." STRINGIFY(segment)))) +#define Z_GENERIC_DOT_SECTION(segment) __GENERIC_DOT_SECTION(segment) + +#define ___in_section(a, b, c) \ + __attribute__((section("." Z_STRINGIFY(a) \ + "." Z_STRINGIFY(b) \ + "." Z_STRINGIFY(c)))) +#define __in_section(a, b, c) ___in_section(a, b, c) + +#define __in_section_unique(seg) ___in_section(seg, __FILE__, __COUNTER__) + +#define __in_section_unique_named(seg, name) \ + ___in_section(seg, __FILE__, name) + +/* When using XIP, using '__ramfunc' places a function into RAM instead + * of FLASH. Make sure '__ramfunc' is defined only when + * CONFIG_ARCH_HAS_RAMFUNC_SUPPORT is defined, so that the compiler can + * report an error if '__ramfunc' is used but the architecture does not + * support it. + */ +#if !defined(CONFIG_XIP) +#define __ramfunc +#elif defined(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT) +/* Use this instead of the IAR keyword __ramfunc to make sure it + * ends up in the correct section. + */ +#define __ramfunc __attribute__((noinline, section(".ramfunc"))) +#endif /* !CONFIG_XIP */ + +/* TG-WG: ICCARM does not support __fallthrough */ +#define __fallthrough [[fallthrough]] + +#ifndef __packed +#define __packed __attribute__((__packed__)) +#endif + +#ifndef __aligned +#define __aligned(x) __attribute__((__aligned__(x))) +#endif + +#ifndef __noinline +#define __noinline __attribute__((noinline)) +#endif + +#if defined(__cplusplus) +#define __alignof(x) alignof(x) +#else +#define __alignof(x) _Alignof(x) +#endif + +#define __may_alias __attribute__((__may_alias__)) + +#ifndef __printf_like +/* + * The Zephyr stdint convention enforces int32_t = int, int64_t = long long, + * and intptr_t = long so that short string format length modifiers can be + * used universally across ILP32 and LP64 architectures. Without that it + * is possible for ILP32 toolchains to have int32_t = long and intptr_t = int + * clashing with the Zephyr convention and generating pointless warnings + * as they're still the same size. Inhibit the format argument type + * validation in that case and let the other configs do it. + */ +#define __printf_like(f, a) +#endif + +#define __used __attribute__((__used__)) +#define __unused __attribute__((__unused__)) +#define __maybe_unused __attribute__((__unused__)) + +#ifndef __deprecated +#define __deprecated __attribute__((deprecated)) +#endif + +#define FUNC_NO_STACK_PROTECTOR _Pragma("no_stack_protect") + +#ifndef __attribute_const__ +#if __VER__ > 0x09000000 +#define __attribute_const__ __attribute__((const)) +#else +#define __attribute_const__ +#endif +#endif + +#ifndef __must_check +/* #warning "The attribute __warn_unused_result is not supported in ICCARM". */ +#define __must_check +/* #define __must_check __attribute__((warn_unused_result)) */ +#endif + +#define __PRAGMA(...) _Pragma(#__VA_ARGS__) +#define ARG_UNUSED(x) (void)(x) + +#define likely(x) (__builtin_expect((bool)!!(x), true) != 0L) +#define unlikely(x) (__builtin_expect((bool)!!(x), false) != 0L) +#define POPCOUNT(x) __builtin_popcount(x) + +#ifndef __no_optimization +#define __no_optimization __PRAGMA(optimize = none) +#endif + +#ifndef __attribute_nonnull + #define __attribute_nonnull(...) __attribute__((nonnull(__VA_ARGS__))) +#endif + +/* __weak is an ICCARM built-in, but it doesn't work in all positions */ +/* the Zephyr uses it so we replace it with an attribute((weak)) */ +#define __weak __attribute__((__weak__)) + +/* Builtins */ + +#include + +/* + * Be *very* careful with these. You cannot filter out __DEPRECATED_MACRO with + * -wno-deprecated, which has implications for -Werror. + */ + + +/* + * Expands to nothing and generates a warning. Used like + * + * #define FOO __WARN("Please use BAR instead") ... + * + * The warning points to the location where the macro is expanded. + */ +#define __WARN(s) __PRAGMA(message = #s) +#define __WARN1(s) __PRAGMA(message = #s) + +/* Generic message */ +#ifndef __DEPRECATED_MACRO +#define __DEPRECATED_MACRO __WARN("Macro is deprecated") +#endif + +/* These macros allow having ARM asm functions callable from thumb */ + +#if defined(_ASMLANGUAGE) + +#if defined(CONFIG_ASSEMBLER_ISA_THUMB2) +#define FUNC_CODE() .code 32 +#define FUNC_INSTR(a) +/* '.syntax unified' is a gcc-ism used in thumb-2 asm files */ +#define _ASM_FILE_PROLOGUE .text; .syntax unified; .thumb +#else +#define FUNC_CODE() +#define FUNC_INSTR(a) +#define _ASM_FILE_PROLOGUE .text; .code 32 +#endif /* CONFIG_ASSEMBLER_ISA_THUMB2 */ + +/* + * These macros are used to declare assembly language symbols that need + * to be typed properly(func or data) to be visible to the OMF tool. + * So that the build tool could mark them as an entry point to be linked + * correctly. This is an elfism. Use #if 0 for a.out. + */ + +/* This is not implemented yet for IAR */ +#define GTEXT(sym) +#define GDATA(sym) +#define WTEXT(sym) +#define WDATA(sym) + +#define SECTION_VAR(sect, sym) +#define SECTION_FUNC(sect, sym) +#define SECTION_SUBSEC_FUNC(sect, subsec, sym) + +#endif /* _ASMLANGUAGE */ + + +/* + * These macros generate absolute symbols for IAR + */ + +/* create an extern reference to the absolute symbol */ + +#define GEN_OFFSET_EXTERN(name) extern const char name[] + +#define GEN_ABS_SYM_BEGIN(name) \ + EXTERN_C void name(void); \ + void name(void) \ + { + +#define GEN_ABS_SYM_END } + +/* + * Note that GEN_ABSOLUTE_SYM(), depending on the architecture + * and toolchain, may restrict the range of values permitted + * for assignment to the named symbol. + */ +#define GEN_ABSOLUTE_SYM(name, value) \ + __PRAGMA(public_equ = #name, (unsigned int)value) + +/* + * GEN_ABSOLUTE_SYM_KCONFIG() is outputted by the build system + * to generate named symbol/value pairs for kconfigs. + */ +#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ + __PRAGMA(public_equ = #name, (unsigned int)value) + +#define compiler_barrier() do { \ + __asm volatile("" ::: "memory"); \ +} while (false) + +/** @brief Return larger value of two provided expressions. + * + * Macro ensures that expressions are evaluated only once. + * + * @note Macro has limited usage compared to the standard macro as it cannot be + * used: + * - to generate constant integer, e.g. __aligned(Z_MAX(4,5)) + * - static variable, e.g. array like static uint8_t array[Z_MAX(...)]; + */ +#define Z_MAX(a, b) ({ \ + /* random suffix to avoid naming conflict */ \ + __typeof__(a) _value_a_ = (a); \ + __typeof__(b) _value_b_ = (b); \ + _value_a_ > _value_b_ ? _value_a_ : _value_b_; \ + }) + +/** @brief Return smaller value of two provided expressions. + * + * Macro ensures that expressions are evaluated only once. See @ref Z_MAX for + * macro limitations. + */ +#define Z_MIN(a, b) ({ \ + /* random suffix to avoid naming conflict */ \ + __typeof__(a) _value_a_ = (a); \ + __typeof__(b) _value_b_ = (b); \ + _value_a_ < _value_b_ ? _value_a_ : _value_b_; \ + }) + +/** @brief Return a value clamped to a given range. + * + * Macro ensures that expressions are evaluated only once. See @ref Z_MAX for + * macro limitations. + */ +#define Z_CLAMP(val, low, high) ({ \ + /* random suffix to avoid naming conflict */ \ + __typeof__(val) _value_val_ = (val); \ + __typeof__(low) _value_low_ = (low); \ + __typeof__(high) _value_high_ = (high); \ + (_value_val_ < _value_low_) ? _value_low_ : \ + (_value_val_ > _value_high_) ? _value_high_ : \ + _value_val_; \ + }) + +/** + * @brief Calculate power of two ceiling for some nonzero value + * + * @param x Nonzero unsigned long value + * @return X rounded up to the next power of two + */ +#define Z_POW2_CEIL(x) \ + ((x) <= 2UL ? (x) : (1UL << (8 * sizeof(long) - __builtin_clzl((x) - 1)))) + +/** + * @brief Check whether or not a value is a power of 2 + * + * @param x The value to check + * @return true if x is a power of 2, false otherwise + */ +#define Z_IS_POW2(x) (((x) != 0) && (((x) & ((x)-1)) == 0)) + +#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 +#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 ## LL +#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 + +/* Convenience macros */ +#undef _GLUE_B +#undef _GLUE +#define _GLUE_B(x, y) x##y +#define _GLUE(x, y) _GLUE_B(x, y) + +#ifndef INTMAX_C +#define INTMAX_C(x) _GLUE(x, __INTMAX_C_SUFFIX__) +#endif + +#ifndef UINTMAX_C +#define UINTMAX_C(x) _GLUE(x, __UINTMAX_C_SUFFIX__) +#endif + +#endif /* !_LINKER */ +#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_H_ */ diff --git a/lib/libc/CMakeLists.txt b/lib/libc/CMakeLists.txt index a6fecf09d66c4..075e066d59b4b 100644 --- a/lib/libc/CMakeLists.txt +++ b/lib/libc/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_syscall_header( add_subdirectory_ifdef(CONFIG_ARCMWDT_LIBC arcmwdt) add_subdirectory_ifdef(CONFIG_ARMCLANG_STD_LIBC armstdc) +add_subdirectory_ifdef(CONFIG_IAR_LIBC iar) add_subdirectory_ifdef(CONFIG_MINIMAL_LIBC minimal) add_subdirectory_ifdef(CONFIG_NEWLIB_LIBC newlib) add_subdirectory_ifdef(CONFIG_PICOLIBC picolibc) diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index eb3c19247ce7a..5d981e4719b0b 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -51,6 +51,13 @@ config PICOLIBC_SUPPORTED help Selected when the target has support for picolibc. +config IAR_LIBC_SUPPORTED + bool + default n + select FULL_LIBC_SUPPORTED + help + Selected if the target is an IAR Systems compiler + config NATIVE_LIBC_INCOMPATIBLE bool help @@ -65,6 +72,7 @@ choice LIBC_IMPLEMENTATION default PICOLIBC default NEWLIB_LIBC if REQUIRES_FULL_LIBC default MINIMAL_LIBC + default IAR_LIBC config MINIMAL_LIBC bool "Minimal C library" @@ -124,6 +132,17 @@ config EXTERNAL_LIBC help Build with external/user provided C library. +config IAR_LIBC + bool "IAR C Runtime Library" + depends on IAR_LIBC_SUPPORTED + depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "iar" + select COMMON_LIBC_STRNLEN + select COMMON_LIBC_TIME if POSIX_TIMERS + help + Use the full IAR Compiler runtime libraries. + A reduced Zephyr minimal libc will be used for library functionality + not provided by the IAR C Runtime Library. + endchoice # LIBC_IMPLEMENTATION config HAS_NEWLIB_LIBC_NANO diff --git a/lib/libc/iar/CMakeLists.txt b/lib/libc/iar/CMakeLists.txt new file mode 100644 index 0000000000000..f57ab75d2d303 --- /dev/null +++ b/lib/libc/iar/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(src/libc-hooks.c) +zephyr_system_include_directories(include) diff --git a/lib/libc/iar/include/errno.h b/lib/libc/iar/include/errno.h new file mode 100644 index 0000000000000..6310531a75c03 --- /dev/null +++ b/lib/libc/iar/include/errno.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Defines additional error numbers based on POSIX + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_ERRNO_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_ERRNO_H_ + +#include_next + +#ifndef __cplusplus +#define EPERM 1 /**< Not owner */ +#define ENOENT 2 /**< No such file or directory */ +#define ESRCH 3 /**< No such context */ +#define EINTR 4 /**< Interrupted system call */ +#define EIO 5 /**< I/O error */ +#define ENXIO 6 /**< No such device or address */ +#define E2BIG 7 /**< Arg list too long */ +#define ENOEXEC 8 /**< Exec format error */ +#define EBADF 9 /**< Bad file number */ +#define ECHILD 10 /**< No children */ +#define EAGAIN 11 /**< No more contexts */ +#define ENOMEM 12 /**< Not enough core */ +#define EACCES 13 /**< Permission denied */ +#define EFAULT 14 /**< Bad address */ +#define ENOTBLK 15 /**< Block device required */ +#define EBUSY 16 /**< Mount device busy */ +#define EEXIST 17 /**< File exists */ +#define EXDEV 18 /**< Cross-device link */ +#define ENODEV 19 /**< No such device */ +#define ENOTDIR 20 /**< Not a directory */ +#define EISDIR 21 /**< Is a directory */ +#define EINVAL 22 /**< Invalid argument */ +#define ENFILE 23 /**< File table overflow */ +#define EMFILE 24 /**< Too many open files */ +#define ENOTTY 25 /**< Not a typewriter */ +#define ETXTBSY 26 /**< Text file busy */ +#define EFBIG 27 /**< File too large */ +#define ENOSPC 28 /**< No space left on device */ +#define ESPIPE 29 /**< Illegal seek */ +#define EROFS 30 /**< Read-only file system */ +#define EMLINK 31 /**< Too many links */ +#define EPIPE 32 /**< Broken pipe */ +#define ENOMSG 35 /**< Unexpected message type */ +#define EDEADLK 45 /**< Resource deadlock avoided */ +#define ENOLCK 46 /**< No locks available */ +#define ENOSTR 60 /**< STREAMS device required */ +#define ENODATA 61 /**< Missing expected message data */ +#define ETIME 62 /**< STREAMS timeout occurred */ +#define ENOSR 63 /**< Insufficient memory */ +#define EPROTO 71 /**< Generic STREAMS error */ +#define EBADMSG 77 /**< Invalid STREAMS message */ +#define ENOSYS 88 /**< Function not implemented */ +#define ENOTEMPTY 90 /**< Directory not empty */ +#define ENAMETOOLONG 91 /**< File name too long */ +#define ELOOP 92 /**< Too many levels of symbolic links */ +#define EOPNOTSUPP 95 /**< Operation not supported on socket */ +#define EPFNOSUPPORT 96 /**< Protocol family not supported */ +#define ECONNRESET 104 /**< Connection reset by peer */ +#define ENOBUFS 105 /**< No buffer space available */ +#define EAFNOSUPPORT 106 /**< Addr family not supported */ +#define EPROTOTYPE 107 /**< Protocol wrong type for socket */ +#define ENOTSOCK 108 /**< Socket operation on non-socket */ +#define ENOPROTOOPT 109 /**< Protocol not available */ +#define ESHUTDOWN 110 /**< Can't send after socket shutdown */ +#define ECONNREFUSED 111 /**< Connection refused */ +#define EADDRINUSE 112 /**< Address already in use */ +#define ECONNABORTED 113 /**< Software caused connection abort */ +#define ENETUNREACH 114 /**< Network is unreachable */ +#define ENETDOWN 115 /**< Network is down */ +#define ETIMEDOUT 116 /**< Connection timed out */ +#define EHOSTDOWN 117 /**< Host is down */ +#define EHOSTUNREACH 118 /**< No route to host */ +#define EINPROGRESS 119 /**< Operation now in progress */ +#define EALREADY 120 /**< Operation already in progress */ +#define EDESTADDRREQ 121 /**< Destination address required */ +#define EMSGSIZE 122 /**< Message size */ +#define EPROTONOSUPPORT 123 /**< Protocol not supported */ +#define ESOCKTNOSUPPORT 124 /**< Socket type not supported */ +#define EADDRNOTAVAIL 125 /**< Can't assign requested address */ +#define ENETRESET 126 /**< Network dropped connection on reset */ +#define EISCONN 127 /**< Socket is already connected */ +#define ENOTCONN 128 /**< Socket is not connected */ +#define ETOOMANYREFS 129 /**< Too many references: can't splice */ +#define ENOTSUP 134 /**< Unsupported value */ +#define EOVERFLOW 139 /**< Value overflow */ +#define ECANCELED 140 /**< Operation canceled */ +#define EWOULDBLOCK EAGAIN /**< Operation would block */ +#endif /* __cplusplus */ +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_ERRNO_H_ */ diff --git a/lib/libc/iar/include/limits.h b/lib/libc/iar/include/limits.h new file mode 100644 index 0000000000000..50decad13ad18 --- /dev/null +++ b/lib/libc/iar/include/limits.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_LIMITS_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_LIMITS_H_ + +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +#define PATH_MAX 256 + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_LIMITS_H_ */ diff --git a/lib/libc/iar/include/sys/_timespec.h b/lib/libc/iar/include/sys/_timespec.h new file mode 100644 index 0000000000000..1ea3b4da5bff8 --- /dev/null +++ b/lib/libc/iar/include/sys/_timespec.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* file is intentionally empty */ diff --git a/lib/libc/iar/include/sys/_timeval.h b/lib/libc/iar/include/sys/_timeval.h new file mode 100644 index 0000000000000..43f8f7f8c8973 --- /dev/null +++ b/lib/libc/iar/include/sys/_timeval.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS__TIMEVAL_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS__TIMEVAL_H_ + +#include + +#if !defined(__time_t_defined) +#define __time_t_defined +typedef long long time_t; +#endif + +#if !defined(__suseconds_t_defined) +#define __suseconds_t_defined +typedef int32_t suseconds_t; +#endif + +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS__TIMEVAL_H_ */ diff --git a/lib/libc/iar/include/sys/cdefs.h b/lib/libc/iar/include/sys/cdefs.h new file mode 100644 index 0000000000000..1ea3b4da5bff8 --- /dev/null +++ b/lib/libc/iar/include/sys/cdefs.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* file is intentionally empty */ diff --git a/lib/libc/iar/include/sys/timespec.h b/lib/libc/iar/include/sys/timespec.h new file mode 100644 index 0000000000000..d5c0549dbc9da --- /dev/null +++ b/lib/libc/iar/include/sys/timespec.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TIMESPEC_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TIMESPEC_H_ + +#include +#include + +struct itimerspec { + struct timespec it_interval; /* Timer interval */ + struct timespec it_value; /* Timer expiration */ +}; + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TIMESPEC_H_ */ diff --git a/lib/libc/iar/include/sys/types.h b/lib/libc/iar/include/sys/types.h new file mode 100644 index 0000000000000..9654efc25ee25 --- /dev/null +++ b/lib/libc/iar/include/sys/types.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TYPES_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TYPES_H_ + +typedef unsigned int mode_t; +typedef signed long ssize_t; +typedef int off_t; +typedef __INT64_TYPE__ time_t; + +#if !defined(_CLOCK_T_DECLARED) && !defined(__clock_t_defined) +typedef unsigned int clock_t; +#define _CLOCK_T_DECLARED +#define __clock_t_defined +#endif + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TYPES_H_ */ diff --git a/lib/libc/iar/include/time.h b/lib/libc/iar/include/time.h new file mode 100644 index 0000000000000..b095987857418 --- /dev/null +++ b/lib/libc/iar/include/time.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Declares additional time related functions based on POSIX + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_TIME_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_TIME_H_ + +#include +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +char *asctime_r(const struct tm *ZRESTRICT tp, char *ZRESTRICT buf); +char *ctime_r(const time_t *clock, char *buf); +struct tm *gmtime_r(const time_t *ZRESTRICT timep, struct tm *ZRESTRICT result); +struct tm *localtime_r(const time_t *ZRESTRICT timer, struct tm *ZRESTRICT result); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_TIME_H_ */ diff --git a/lib/libc/iar/src/libc-hooks.c b/lib/libc/iar/src/libc-hooks.c new file mode 100644 index 0000000000000..d3deea9658a48 --- /dev/null +++ b/lib/libc/iar/src/libc-hooks.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static int _stdout_hook_default(int c) +{ + (void)(c); /* Prevent warning about unused argument */ + + return EOF; +} + +static int (*_stdout_hook)(int) = _stdout_hook_default; + +void __stdout_hook_install(int (*hook)(int)) +{ + _stdout_hook = hook; +} + +int fputc(int c, FILE *f) +{ + return (_stdout_hook)(c); +} + +#pragma weak __write +size_t __write(int handle, const unsigned char *buf, size_t bufSize) +{ + size_t nChars = 0; + /* Check for the command to flush all handles */ + if (handle == -1) { + return 0; + } + /* Check for stdout and stderr + * (only necessary if FILE descriptors are enabled.) + */ + if (handle != 1 && handle != 2) { + return -1; + } + for (/* Empty */; bufSize > 0; --bufSize) { + int ret = (_stdout_hook)(*buf); + + if (ret == EOF) { + break; + } + ++buf; + ++nChars; + } + return nChars; +} diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 81ebf8733929f..9b2c610d390c9 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -1059,6 +1059,9 @@ def check_no_undef_outside_kconfig(self, kconf): "FOO_SETTING_2", "HEAP_MEM_POOL_ADD_SIZE_", # Used as an option matching prefix "HUGETLBFS", # Linux, in boards/xtensa/intel_adsp_cavs25/doc + "IAR_BUFFERED_WRITE", + "IAR_LIBCPP", + "IAR_SEMIHOSTING", "IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS", # Used in ICMsg tests for intercompatibility # with older versions of the ICMsg. "LIBGCC_RTLIB", diff --git a/tests/kernel/fpu_sharing/generic/src/load_store.c b/tests/kernel/fpu_sharing/generic/src/load_store.c index 1193297eb4152..67e6cb54129c4 100644 --- a/tests/kernel/fpu_sharing/generic/src/load_store.c +++ b/tests/kernel/fpu_sharing/generic/src/load_store.c @@ -46,7 +46,7 @@ #endif /* __GNUC__ */ #elif defined(CONFIG_ARM) #if defined(CONFIG_ARMV7_M_ARMV8_M_FP) || defined(CONFIG_ARMV7_R_FP) || defined(CONFIG_CPU_HAS_VFP) -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__ICCARM__) #include "float_regs_arm_gcc.h" #else #include "float_regs_arm_other.h" From 6e1d953f28e93f8419c85a5e4baf24bb08303099 Mon Sep 17 00:00:00 2001 From: Robin Kastberg Date: Wed, 5 Feb 2025 21:24:48 +0000 Subject: [PATCH 0272/6055] MAINTAINERS: add the `Toolchain IAR` area This commit adds the `Toolchain IAR` area of maintenance. Signed-off-by: Robin Kastberg --- MAINTAINERS.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 3ee64f2333e2b..d6c325249abb2 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4492,6 +4492,18 @@ TDK Sensors: labels: - "area: Toolchains" +"Toolchain IAR": + status: maintained + maintainers: + - RobinKastberg + files: + - cmake/*/iar/ + - include/zephyr/toolchain/iar.h + - include/zephyr/toolchain/iar/* + - lib/libc/iar/* + labels: + - "area: Toolchains" + "Toolchain oneApi": status: maintained maintainers: From c3c5333db51f08d9d096a5c70bfdd54e84567946 Mon Sep 17 00:00:00 2001 From: Robin Kastberg Date: Wed, 5 Feb 2025 21:24:48 +0000 Subject: [PATCH 0273/6055] toolchain: doc: Add toolchain information about IAR This commit adds documentation information about the IAR toolchain. Signed-off-by: Robin Kastberg --- doc/develop/toolchains/iar_arm_toolchain.rst | 60 ++++++++++++++++++++ doc/develop/toolchains/index.rst | 1 + 2 files changed, 61 insertions(+) create mode 100644 doc/develop/toolchains/iar_arm_toolchain.rst diff --git a/doc/develop/toolchains/iar_arm_toolchain.rst b/doc/develop/toolchains/iar_arm_toolchain.rst new file mode 100644 index 0000000000000..8b854dd20da74 --- /dev/null +++ b/doc/develop/toolchains/iar_arm_toolchain.rst @@ -0,0 +1,60 @@ +IAR Arm Toolchain +################# + +#. Download and install a release of `IAR Arm Toolchain`_ (EWARM/CXARM) on your host. + +.. note:: + As of now, a Development version of the IAR build tools for Arm is required to work with Zephyr. + It is distributed to selected partners and customers for evaluation. If you are interested in being + part of this program, please send a request to the IAR FAE team at fae.emea@iar.com. + +#. Make sure you have :ref:`Zephyr SDK ` installed on your host. + +.. note:: + A Zephyr SDK is used as a source of tools like device tree compiler (DTC), QEMU, etc… Even though + IAR Arm toolchain is used for Zephyr RTOS build, still the GNU preprocessor & GNU objcopy might + be used for some steps like device tree preprocessing and .bin file generation. + +#. :ref:`Set these environment variables `: + + - Set :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` to ``iar``. + - Set :envvar:`IAR_TOOLCHAIN_PATH` to the toolchain installation directory. + +#. The IAR Toolchain needs the :envvar:`IAR_LMS_BEARER_TOKEN` environment + variable to be set to a valid ``license bearer token``. + +For example: + + .. code-block:: bash + + # Linux (default installation path): + export IAR_TOOLCHAIN_PATH=/opt/iarsystems/bxarm/arm + export ZEPHYR_TOOLCHAIN_VARIANT=iar + export IAR_LMS_BEARER_TOKEN="" + + .. code-block:: batch + + # Windows: + set IAR_TOOLCHAIN_PATH=c:\\arm + set ZEPHYR_TOOLCHAIN_VARIANT=iar + set IAR_LMS_BEARER_TOKEN="" + +.. note:: + + The IAR Toolchain uses ``ilink`` for linking. This is incompatible with Zephyr’s + linker script template, which works with GNU ld. Zephyr’s IAR Arm Toolchain depends on + Zephyr’s CMake linker script generator, which supports generating icf-files. + Basic icf-file support is in place, but there are still areas which are not fully + supported by the CMake linker script generator. + +.. note:: + + The IAR Toolchain uses the GNU Assembler which is distributed with the Zephyr SDK + for ``.S-files``. + +.. note:: + + Some Zephyr subsystems or modules may also contain C or assembly code that relies + on GNU intrinsics and have not yet been updated to work fully with ``iar``. + +.. _IAR Arm Toolchain: https://www.iar.com/products/architectures/arm/ diff --git a/doc/develop/toolchains/index.rst b/doc/develop/toolchains/index.rst index 7f1f605e6e368..e085a1fbe1c3c 100644 --- a/doc/develop/toolchains/index.rst +++ b/doc/develop/toolchains/index.rst @@ -14,6 +14,7 @@ Guides on how to set up toolchains for Zephyr development. cadence_xcc.rst designware_arc_mwdt.rst gnu_arm_embedded.rst + iar_arm_toolchain.rst intel_oneapi_toolkit.rst host.rst From 302089f311a354073e5e67f897e9df55213cf539 Mon Sep 17 00:00:00 2001 From: Rex Chen Date: Thu, 13 Feb 2025 12:18:03 +0900 Subject: [PATCH 0274/6055] drivers: wifi: nxp: support set override calibration data Add OVERRIDE_CALIBRATION_DATA macro to support set specific calibration data. Signed-off-by: Rex Chen --- drivers/wifi/nxp/Kconfig.nxp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/wifi/nxp/Kconfig.nxp b/drivers/wifi/nxp/Kconfig.nxp index 01052cf3059fc..a84d4fcde79fc 100644 --- a/drivers/wifi/nxp/Kconfig.nxp +++ b/drivers/wifi/nxp/Kconfig.nxp @@ -838,6 +838,11 @@ config NXP_WIFI_WLAN_CALDATA_3ANT_DIVERSITY help This option is used to enable three antenna diversity. +config NXP_OVERRIDE_CALIBRATION_DATA + bool "override default calibriation data" + help + This option is used to override default calibration data. + endif # NXP_RW610 config NXP_WIFI_11AX_TWT From ecd53f9e8a3ad19b6590a4dcdc1a21f767884690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C5=82=C4=85b?= Date: Thu, 13 Feb 2025 11:10:05 +0100 Subject: [PATCH 0275/6055] boards: nordic: nrf54l20pdk: Add PWM to the list of supported peripherals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable Twister tests of PWM driver on nrf54l20pdk. Overlays were already added to PWM tests. Signed-off-by: Sebastian Głąb --- boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20_cpuapp.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20_cpuapp.yaml b/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20_cpuapp.yaml index 4cabfbc4eec6c..c582f38348253 100644 --- a/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20_cpuapp.yaml +++ b/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20_cpuapp.yaml @@ -15,4 +15,5 @@ supported: - counter - gpio - i2c + - pwm - watchdog From 23e6854e7c14d03f6d5544e67f1b74cb03b4b4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C5=82=C4=85b?= Date: Thu, 13 Feb 2025 11:55:28 +0100 Subject: [PATCH 0276/6055] boards: nordic: nrf54l20pdk: Define PWM LED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define PWM LED at nRF54L20pdk board definition. Set status=okay for pwm20 node. Add pincontrol for pwm20:OUT0 at P1.07 (LED1). Add pwm_led1 node. Add alias pwm-led0. Signed-off-by: Sebastian Głąb --- .../nrf54l20pdk_nrf54l20-common.dtsi | 21 +++++++++++++++++++ .../nrf54l20pdk_nrf54l20-pinctrl.dtsi | 13 ++++++++++++ 2 files changed, 34 insertions(+) diff --git a/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20-common.dtsi b/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20-common.dtsi index c188cd39e93da..35a434cda4b44 100644 --- a/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20-common.dtsi +++ b/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20-common.dtsi @@ -27,6 +27,19 @@ }; }; + pwmleds { + compatible = "pwm-leds"; + /* + * PWM signal can be exposed on GPIO pin only within same domain. + * There is only one domain which contains both PWM and GPIO: + * PWM20/21/22 and GPIO Port P1/P3. + * Only LEDs connected to P1/P3 can work with PWM, for example LED1. + */ + pwm_led1: pwm_led_1 { + pwms = <&pwm20 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + buttons { compatible = "gpio-keys"; button0: button_0 { @@ -56,6 +69,7 @@ led1 = &led1; led2 = &led2; led3 = &led3; + pwm-led0 = &pwm_led1; sw0 = &button0; sw1 = &button1; sw2 = &button2; @@ -70,3 +84,10 @@ pinctrl-1 = <&uart20_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/nrf54l20pdk/nrf54l20pdk_nrf54l20-pinctrl.dtsi b/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20-pinctrl.dtsi index 83aa91d8a34a1..7dc2b77ae8336 100644 --- a/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20-pinctrl.dtsi +++ b/boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20-pinctrl.dtsi @@ -21,4 +21,17 @@ 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; + }; + }; }; From 8f39cea7052af4c3d9c80be724bdbb3be4f80643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C5=82=C4=85b?= Date: Thu, 13 Feb 2025 12:01:33 +0100 Subject: [PATCH 0277/6055] tests: drivers: pwm: Remove overlay for nRF54L20pdk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All needed configuration was moved to the board definition. Signed-off-by: Sebastian Głąb --- .../nrf54l20pdk_nrf54l20_cpuapp.overlay | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 tests/drivers/pwm/pwm_api/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay diff --git a/tests/drivers/pwm/pwm_api/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay b/tests/drivers/pwm/pwm_api/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay deleted file mode 100644 index 6d9ec96d77d0b..0000000000000 --- a/tests/drivers/pwm/pwm_api/boards/nrf54l20pdk_nrf54l20_cpuapp.overlay +++ /dev/null @@ -1,20 +0,0 @@ -&pinctrl { - pwm_default: pwm_default { - group1 { - psels = ; - }; - }; - pwm_sleep: pwm_sleep { - group1 { - psels = ; - low-power-enable; - }; - }; -}; - -&pwm20 { - status = "okay"; - pinctrl-0 = <&pwm_default>; - pinctrl-1 = <&pwm_sleep>; - pinctrl-names = "default", "sleep"; -}; From af07184d9be71508778849a589eee9de6d4b8904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Feb 2025 16:27:32 +0100 Subject: [PATCH 0278/6055] doc: releases: refresh list of new boards, drivers, and samples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Synchronize the list of new boards, drivers, and code samples. Signed-off-by: Benjamin Cabé --- doc/releases/release-notes-4.1.rst | 122 +++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 5 deletions(-) diff --git a/doc/releases/release-notes-4.1.rst b/doc/releases/release-notes-4.1.rst index ebbac0e320ab7..dd67060aced38 100644 --- a/doc/releases/release-notes-4.1.rst +++ b/doc/releases/release-notes-4.1.rst @@ -220,6 +220,7 @@ New Boards * Adafruit Industries, LLC * :zephyr:board:`adafruit_feather_m4_express` (``adafruit_feather_m4_express``) + * :zephyr:board:`adafruit_macropad_rp2040` (``adafruit_macropad_rp2040``) * :zephyr:board:`adafruit_qt_py_esp32s3` (``adafruit_qt_py_esp32s3``) * Advanced Micro Devices (AMD), Inc. @@ -228,6 +229,10 @@ New Boards * Analog Devices, Inc. + * :zephyr:board:`ad_swiot1l_sl` (``ad_swiot1l_sl``) + * :zephyr:board:`max32650evkit` (``max32650evkit``) + * :zephyr:board:`max32650fthr` (``max32650fthr``) + * :zephyr:board:`max32660evsys` (``max32660evsys``) * :zephyr:board:`max78000evkit` (``max78000evkit``) * :zephyr:board:`max78000fthr` (``max78000fthr``) * :zephyr:board:`max78002evkit` (``max78002evkit``) @@ -253,6 +258,10 @@ New Boards * :zephyr:board:`cy8ckit_062s2_ai` (``cy8ckit_062s2_ai``) +* Khadas + + * :zephyr:board:`khadas_edge2` (``khadas_edge2``) + * Lilygo Shenzhen Xinyuan Electronic Technology Co., Ltd * :zephyr:board:`ttgo_t7v1_5` (``ttgo_t7v1_5``) @@ -274,6 +283,9 @@ New Boards * NXP Semiconductors + * :zephyr:board:`frdm_mcxw72` (``frdm_mcxw72``) + * :zephyr:board:`imx91_evk` (``imx91_evk``) + * :zephyr:board:`mcxw72_evk` (``mcxw72_evk``) * :zephyr:board:`mimxrt700_evk` (``mimxrt700_evk``) * Nordic Semiconductor @@ -285,10 +297,22 @@ New Boards * :zephyr:board:`octopus_io_board` (``octopus_io_board``) * :zephyr:board:`octopus_som` (``octopus_som``) +* Panasonic Corporation + + * :zephyr:board:`panb511evb` (``panb511evb``) + +* Peregrine Consultoria e Servicos + + * :zephyr:board:`sam4l_wm400_cape` (``sam4l_wm400_cape``) + * Qorvo, Inc. * :zephyr:board:`decawave_dwm3001cdk` (``decawave_dwm3001cdk``) +* RAKwireless Technology Limited + + * :zephyr:board:`rak3172` (``rak3172``) + * Raspberry Pi Foundation * :zephyr:board:`rpi_pico2` (``rpi_pico2``) @@ -299,6 +323,8 @@ New Boards * Renesas Electronics Corporation + * :zephyr:board:`ek_ra4l1` (``ek_ra4l1``) + * :zephyr:board:`ek_ra4m1` (``ek_ra4m1``) * :zephyr:board:`fpb_ra4e1` (``fpb_ra4e1``) * :zephyr:board:`rzg3s_smarc` (``rzg3s_smarc``) * :zephyr:board:`voice_ra4e1` (``voice_ra4e1``) @@ -323,10 +349,15 @@ New Boards * Silicon Laboratories + * :zephyr:board:`siwx917_rb4338a` (``siwx917_rb4338a``) * :zephyr:board:`xg23_rb4210a` (``xg23_rb4210a``) * :zephyr:board:`xg24_ek2703a` (``xg24_ek2703a``) * :zephyr:board:`xg29_rb4412a` (``xg29_rb4412a``) +* Texas Instruments + + * :zephyr:board:`lp_em_cc2340r5` (``lp_em_cc2340r5``) + * Toradex AG * :zephyr:board:`verdin_imx8mm` (``verdin_imx8mm``) @@ -338,6 +369,7 @@ New Boards * WeAct Studio * :zephyr:board:`mini_stm32h7b0` (``mini_stm32h7b0``) + * :zephyr:board:`weact_stm32h5_core` (``weact_stm32h5_core``) * WinChipHead @@ -365,22 +397,34 @@ New Drivers * :abbr:`ADC (Analog to Digital Converter)` * :dtcompatible:`adi,ad4114-adc` - * :dtcompatible:`ti,ads131m02` - * :dtcompatible:`ti,tla2022` - * :dtcompatible:`ti,tla2024` + * :dtcompatible:`adi,ad7124-adc` + * :dtcompatible:`st,stm32n6-adc` * :dtcompatible:`ti,ads114s06` * :dtcompatible:`ti,ads124s06` * :dtcompatible:`ti,ads124s08` + * :dtcompatible:`ti,ads131m02` + * :dtcompatible:`ti,tla2022` + * :dtcompatible:`ti,tla2024` * ARM architecture * :dtcompatible:`nxp,nbu` +* Audio + + * :dtcompatible:`cirrus,cs43l22` + * :dtcompatible:`intel,adsp-mic-privacy` + * Bluetooth * :dtcompatible:`renesas,bt-hci-da1453x` + * :dtcompatible:`silabs,siwx91x-bt-hci` * :dtcompatible:`st,hci-stm32wb0` +* Charger + + * :dtcompatible:`nxp,pf1550-charger` + * Clock control * :dtcompatible:`atmel,sam0-gclk` @@ -389,14 +433,24 @@ New Drivers * :dtcompatible:`nordic,nrf-hsfll-global` * :dtcompatible:`nuvoton,npcm-pcc` * :dtcompatible:`realtek,rts5912-sccon` + * :dtcompatible:`st,stm32n6-cpu-clock-mux` + * :dtcompatible:`st,stm32n6-hse-clock` + * :dtcompatible:`st,stm32n6-ic-clock-mux` + * :dtcompatible:`st,stm32n6-pll-clock` + * :dtcompatible:`st,stm32n6-rcc` * :dtcompatible:`wch,ch32v00x-hse-clock` * :dtcompatible:`wch,ch32v00x-hsi-clock` * :dtcompatible:`wch,ch32v00x-pll-clock` * :dtcompatible:`wch,rcc` +* comparator + + * :dtcompatible:`silabs,acmp` + * Counter * :dtcompatible:`adi,max32-rtc-counter` + * :dtcompatible:`renesas,rz-gtm-counter` * CPU @@ -405,10 +459,13 @@ New Drivers * :abbr:`DAC (Digital to Analog Converter)` * :dtcompatible:`adi,max22017-dac` + * :dtcompatible:`renesas,ra-dac` + * :dtcompatible:`renesas,ra-dac-global` * :abbr:`DAI (Digital Audio Interface)` * :dtcompatible:`mediatek,afe` + * :dtcompatible:`nxp,dai-micfil` * Display @@ -421,9 +478,14 @@ New Drivers * :dtcompatible:`infineon,cat1-dma` * :dtcompatible:`nxp,sdma` * :dtcompatible:`silabs,ldma` + * :dtcompatible:`silabs,siwx91x-dma` * :dtcompatible:`xlnx,axi-dma-1.00.a` * :dtcompatible:`xlnx,eth-dma` +* :abbr:`DSA (Distributed Switch Architecture)` + + * :dtcompatible:`nxp,netc-switch` + * Ethernet * :dtcompatible:`davicom,dm8806-phy` @@ -431,11 +493,17 @@ New Drivers * :dtcompatible:`microchip,t1s-phy` * :dtcompatible:`microchip,vsc8541` * :dtcompatible:`renesas,ra-ethernet` + * :dtcompatible:`sensry,sy1xx-mac` * Firmware * :dtcompatible:`arm,scmi-power` +* Flash controller + + * :dtcompatible:`silabs,siwx91x-flash-controller` + * :dtcompatible:`ti,cc23x0-flash-controller` + * :abbr:`FPGA (Field Programmable Gate Array)` * :dtcompatible:`lattice,ice40-fpga-base` @@ -449,14 +517,20 @@ New Drivers * :dtcompatible:`ite,it8801-gpio` * :dtcompatible:`microchip,mec5-gpio` * :dtcompatible:`nordic,npm2100-gpio` + * :dtcompatible:`nxp,pca6416` * :dtcompatible:`raspberrypi,rp1-gpio` * :dtcompatible:`realtek,rts5912-gpio` * :dtcompatible:`renesas,ra-gpio-mipi-header` * :dtcompatible:`renesas,rz-gpio` * :dtcompatible:`renesas,rz-gpio-int` * :dtcompatible:`sensry,sy1xx-gpio` + * :dtcompatible:`silabs,siwx91x-gpio` + * :dtcompatible:`silabs,siwx91x-gpio-port` + * :dtcompatible:`silabs,siwx91x-gpio-uulp` + * :dtcompatible:`st,dcmi-camera-fpu-330zh` * :dtcompatible:`st,mfxstm32l152` * :dtcompatible:`stemma-qt-connector` + * :dtcompatible:`ti,cc23x0-gpio` * :dtcompatible:`wch,gpio` * IEEE 802.15.4 HDLC RCP interface @@ -472,16 +546,23 @@ New Drivers * :abbr:`I3C (Improved Inter-Integrated Circuit)` + * :dtcompatible:`snps,designware-i3c` * :dtcompatible:`st,stm32-i3c` +* IEEE 802.15.4 + + * :dtcompatible:`nxp,mcxw-ieee802154` + * Input + * :dtcompatible:`cypress,cy8cmbr3xxx` * :dtcompatible:`ite,it8801-kbd` * :dtcompatible:`microchip,cap12xx` * :dtcompatible:`nintendo,nunchuk` * Interrupt controller + * :dtcompatible:`renesas,rz-ext-irq` * :dtcompatible:`wch,pfic` * Mailbox @@ -493,6 +574,7 @@ New Drivers * :dtcompatible:`microchip,lan865x-mdio` * :dtcompatible:`renesas,ra-mdio` + * :dtcompatible:`sensry,sy1xx-mdio` * Memory controller @@ -507,6 +589,7 @@ New Drivers * :dtcompatible:`ite,it8801-mfd-map` * :dtcompatible:`maxim,ds3231-mfd` * :dtcompatible:`nordic,npm2100` + * :dtcompatible:`nxp,pf1550` * :abbr:`MIPI DSI (Mobile Industry Processor Interface Display Serial Interface)` @@ -527,6 +610,11 @@ New Drivers * :dtcompatible:`fujitsu,mb85rsxx` * :dtcompatible:`nxp,s32-qspi-hyperflash` * :dtcompatible:`nxp,xspi-mx25um51345g` + * :dtcompatible:`ti,cc23x0-ccfg-flash` + +* Networking + + * :dtcompatible:`silabs,series2-radio` * :abbr:`PCIe (Peripheral Component Interconnect Express)` @@ -543,12 +631,15 @@ New Drivers * :dtcompatible:`renesas,rzg-pinctrl` * :dtcompatible:`sensry,sy1xx-pinctrl` * :dtcompatible:`silabs,dbus-pinctrl` + * :dtcompatible:`silabs,siwx91x-pinctrl` + * :dtcompatible:`ti,cc23x0-pinctrl` * :dtcompatible:`wch,afio` * :abbr:`PWM (Pulse Width Modulation)` * :dtcompatible:`atmel,sam0-tc-pwm` * :dtcompatible:`ite,it8801-pwm` + * :dtcompatible:`renesas,rz-gpt-pwm` * :dtcompatible:`zephyr,fake-pwm` * Quad SPI @@ -559,20 +650,27 @@ New Drivers * Regulator * :dtcompatible:`nordic,npm2100-regulator` + * :dtcompatible:`nxp,pf1550-regulator` * :abbr:`RNG (Random Number Generator)` * :dtcompatible:`nordic,nrf-cracen-ctrdrbg` + * :dtcompatible:`nxp,ele-trng` * :dtcompatible:`renesas,ra-sce5-rng` * :dtcompatible:`renesas,ra-sce7-rng` * :dtcompatible:`renesas,ra-sce9-rng` * :dtcompatible:`renesas,ra-trng` + * :dtcompatible:`sensry,sy1xx-trng` + * :dtcompatible:`silabs,siwx91x-rng` * :dtcompatible:`st,stm32-rng-noirq` * :abbr:`RTC (Real Time Clock)` + * :dtcompatible:`epson,rx8130ce-rtc` + * :dtcompatible:`maxim,ds1337` * :dtcompatible:`maxim,ds3231-rtc` * :dtcompatible:`microcrystal,rv8803` + * :dtcompatible:`ti,bq32002` * SDHC @@ -582,11 +680,13 @@ New Drivers * :dtcompatible:`adi,adxl366` * :dtcompatible:`hc-sr04` + * :dtcompatible:`invensense,icm42370p` * :dtcompatible:`invensense,icm42670s` - * :dtcompatible:`invensense,icm42370` + * :dtcompatible:`invensense,icp101xx` * :dtcompatible:`maxim,ds3231-sensor` * :dtcompatible:`melexis,mlx90394` * :dtcompatible:`nordic,npm2100-vbat` + * :dtcompatible:`phosense,xbr818` * :dtcompatible:`renesas,hs400x` * :dtcompatible:`sensirion,scd40` * :dtcompatible:`sensirion,scd41` @@ -606,11 +706,13 @@ New Drivers * :dtcompatible:`renesas,rz-scif-uart` * :dtcompatible:`silabs,eusart-uart` * :dtcompatible:`silabs,usart-uart` + * :dtcompatible:`ti,cc23x0-uart` * :dtcompatible:`wch,usart` * :abbr:`SPI (Serial Peripheral Interface)` * :dtcompatible:`ite,it8xxx2-spi` + * :dtcompatible:`nxp,lpspi` * :dtcompatible:`nxp,xspi` * :dtcompatible:`renesas,ra-spi` @@ -628,14 +730,19 @@ New Drivers * :dtcompatible:`mediatek,ostimer64` * :dtcompatible:`realtek,rts5912-rtmr` * :dtcompatible:`realtek,rts5912-slwtimer` + * :dtcompatible:`renesas,rz-gpt` + * :dtcompatible:`renesas,rz-gtm` * :dtcompatible:`riscv,machine-timer` + * :dtcompatible:`ti,cc23x0-systim-timer` * :dtcompatible:`wch,systick` * USB * :dtcompatible:`ambiq,usb` * :dtcompatible:`renesas,ra-udc` - * :dtcompatible:`renesas,ra-usb` + * :dtcompatible:`renesas,ra-usbfs` + * :dtcompatible:`renesas,ra-usbhs` + * :dtcompatible:`zephyr,midi2-device` * Video @@ -651,6 +758,7 @@ New Drivers * Wi-Fi * :dtcompatible:`infineon,airoc-wifi` + * :dtcompatible:`silabs,siwx91x-wifi` New Samples *********** @@ -664,6 +772,7 @@ New Samples * :zephyr:code-sample:`bluetooth_ccp_call_control_client` * :zephyr:code-sample:`bluetooth_ccp_call_control_server` * :zephyr:code-sample:`coresight_stm_sample` +* :zephyr:code-sample:`dfu-next` * :zephyr:code-sample:`i2c-rtio-loopback` * :zephyr:code-sample:`lvgl-screen-transparency` * :zephyr:code-sample:`mctp_endpoint_sample` @@ -675,7 +784,10 @@ New Samples * :zephyr:code-sample:`sensor_clock` * :zephyr:code-sample:`stream_fifo` * :zephyr:code-sample:`tdk_apex` +* :zephyr:code-sample:`tmc50xx` * :zephyr:code-sample:`uart` +* :zephyr:code-sample:`usb-midi2-device` +* :zephyr:code-sample:`usbd-cdc-acm-console` * :zephyr:code-sample:`webusb-next` Other notable changes From 02aa01ddcf3ff8813b2e7e5b7e107051e6a350f9 Mon Sep 17 00:00:00 2001 From: Riku Karjalainen Date: Thu, 13 Feb 2025 09:02:56 +0000 Subject: [PATCH 0279/6055] drivers: usb: stm32: fix for stm32u5 embedded hs phy Select embedded high speed phy if "st,stm32u5-otghs-phy" is enabled in the device tree. Signed-off-by: Riku Karjalainen --- drivers/usb/device/usb_dc_stm32.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index 6dee87dddfbc1..509bffdd2a3b6 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -75,7 +75,10 @@ PINCTRL_DT_INST_DEFINE(0); static const struct pinctrl_dev_config *usb_pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0); -#define USB_OTG_HS_EMB_PHY (DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) && \ +#define USB_OTG_HS_EMB_PHYC (DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) && \ + DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs)) + +#define USB_OTG_HS_EMB_PHY (DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_otghs_phy) && \ DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs)) #define USB_OTG_HS_ULPI_PHY (DT_HAS_COMPAT_STATUS_OKAY(usb_ulpi_phy) && \ @@ -406,7 +409,7 @@ static int usb_dc_stm32_clock_enable(void) LL_AHB1_GRP1_DisableClockLowPower(LL_AHB1_GRP1_PERIPH_OTGHSULPI); #endif -#if USB_OTG_HS_EMB_PHY +#if USB_OTG_HS_EMB_PHYC LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_OTGPHYC); #endif #endif /* USB_OTG_HS_ULPI_PHY */ @@ -436,7 +439,7 @@ static uint32_t usb_dc_stm32_get_maximum_speed(void) * If max-speed is not passed via DT, set it to USB controller's * maximum hardware capability. */ -#if USB_OTG_HS_EMB_PHY || USB_OTG_HS_ULPI_PHY +#if USB_OTG_HS_EMB_PHYC || USB_OTG_HS_EMB_PHY || USB_OTG_HS_ULPI_PHY uint32_t speed = USB_OTG_SPEED_HIGH; #else uint32_t speed = USB_OTG_SPEED_FULL; @@ -447,7 +450,8 @@ static uint32_t usb_dc_stm32_get_maximum_speed(void) if (!strncmp(USB_MAXIMUM_SPEED, "high-speed", 10)) { speed = USB_OTG_SPEED_HIGH; } else if (!strncmp(USB_MAXIMUM_SPEED, "full-speed", 10)) { -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(USB_OTG_HS_EMB_PHY) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(USB_OTG_HS_EMB_PHYC) || \ + defined(USB_OTG_HS_EMB_PHY) speed = USB_OTG_SPEED_HIGH_IN_FULL; #else speed = USB_OTG_SPEED_FULL; @@ -488,7 +492,7 @@ static int usb_dc_stm32_init(void) #endif usb_dc_stm32_state.pcd.Init.dev_endpoints = USB_NUM_BIDIR_ENDPOINTS; usb_dc_stm32_state.pcd.Init.speed = usb_dc_stm32_get_maximum_speed(); -#if USB_OTG_HS_EMB_PHY +#if USB_OTG_HS_EMB_PHYC || USB_OTG_HS_EMB_PHY usb_dc_stm32_state.pcd.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; #elif USB_OTG_HS_ULPI_PHY usb_dc_stm32_state.pcd.Init.phy_itface = USB_OTG_ULPI_PHY; From 5e1aaa539568dc59e8616f64cea39c43674f340f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 14 Feb 2025 12:47:32 +0000 Subject: [PATCH 0280/6055] scripts: ci: check_compliance: Fix paths for disallowed Kconfigs Fixes using the wrong path for checking if disallowed Kconfigs are present, to use the zephyr base instead of the git top level folder which caused issues for downstream manifests Signed-off-by: Jamie McCrae --- scripts/ci/check_compliance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 9b2c610d390c9..34073348ff97c 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -715,10 +715,10 @@ def check_disallowed_defconfigs(self, kconf): grep_stdout_boards = git("grep", "--line-number", "-I", "--null", "--perl-regexp", regex_boards, "--", ":boards", - cwd=Path(GIT_TOP)) + cwd=ZEPHYR_BASE) grep_stdout_socs = git("grep", "--line-number", "-I", "--null", "--perl-regexp", regex_socs, "--", ":soc", - cwd=Path(GIT_TOP)) + cwd=ZEPHYR_BASE) # Board processing # splitlines() supports various line terminators From 682478d74b2979b393c0070593f90abe8d1f12fb Mon Sep 17 00:00:00 2001 From: Nicolas Munnich Date: Sat, 1 Feb 2025 01:52:05 +0100 Subject: [PATCH 0281/6055] boards: raspberrypi: rp2040-zero,xiao_rp2040: fixed inconsistencies There were some inconsistencies in flash memory for both of these boards where they do not match their stated specs. This commit fixes the inconsistencies. Signed-off-by: Nicolas Munnich --- boards/seeed/xiao_rp2040/xiao_rp2040.dts | 12 ++++++++++++ boards/seeed/xiao_rp2040/xiao_rp2040.yaml | 2 +- boards/waveshare/rp2040_zero/rp2040_zero.dts | 6 +++--- boards/waveshare/rp2040_zero/rp2040_zero.yaml | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/boards/seeed/xiao_rp2040/xiao_rp2040.dts b/boards/seeed/xiao_rp2040/xiao_rp2040.dts index 98a700f242f36..c0f96c5fdabf6 100644 --- a/boards/seeed/xiao_rp2040/xiao_rp2040.dts +++ b/boards/seeed/xiao_rp2040/xiao_rp2040.dts @@ -78,6 +78,18 @@ compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + /* + * Usable flash. Starts at 0x100, after the bootloader. The partition + * size is 2MB minus the 0x100 bytes taken by the bootloader. + */ code_partition: partition@100 { label = "code"; reg = <0x100 (DT_SIZE_M(2) - 0x100)>; diff --git a/boards/seeed/xiao_rp2040/xiao_rp2040.yaml b/boards/seeed/xiao_rp2040/xiao_rp2040.yaml index a55cc0f361dd4..c91e45a1e2c97 100644 --- a/boards/seeed/xiao_rp2040/xiao_rp2040.yaml +++ b/boards/seeed/xiao_rp2040/xiao_rp2040.yaml @@ -3,7 +3,7 @@ name: XIAO RP2040 type: mcu arch: arm flash: 2048 -ram: 256 +ram: 264 toolchain: - zephyr - gnuarmemb diff --git a/boards/waveshare/rp2040_zero/rp2040_zero.dts b/boards/waveshare/rp2040_zero/rp2040_zero.dts index 88c41f55d2e87..6e593f9a5ab43 100644 --- a/boards/waveshare/rp2040_zero/rp2040_zero.dts +++ b/boards/waveshare/rp2040_zero/rp2040_zero.dts @@ -28,7 +28,7 @@ }; &flash0 { - reg = <0x10000000 DT_SIZE_M(16)>; + reg = <0x10000000 DT_SIZE_M(2)>; partitions { compatible = "fixed-partitions"; @@ -44,11 +44,11 @@ /* * Usable flash. Starts at 0x100, after the bootloader. The partition - * size is 16MB minus the 0x100 bytes taken by the bootloader. + * size is 2MB minus the 0x100 bytes taken by the bootloader. */ code_partition: partition@100 { label = "code-partition"; - reg = <0x100 (DT_SIZE_M(16) - 0x100)>; + reg = <0x100 (DT_SIZE_M(2) - 0x100)>; read-only; }; }; diff --git a/boards/waveshare/rp2040_zero/rp2040_zero.yaml b/boards/waveshare/rp2040_zero/rp2040_zero.yaml index 36434dbb72a2c..409dd03975fdc 100644 --- a/boards/waveshare/rp2040_zero/rp2040_zero.yaml +++ b/boards/waveshare/rp2040_zero/rp2040_zero.yaml @@ -2,7 +2,7 @@ identifier: rp2040_zero name: Waveshare RP2040-Zero type: mcu arch: arm -flash: 16384 +flash: 2048 ram: 264 toolchain: - zephyr From 271bb8b7b0076ff8fb3627cc9c8c77fbd5c4bf19 Mon Sep 17 00:00:00 2001 From: Arunmani Alagarsamy Date: Fri, 31 Jan 2025 17:29:15 +0530 Subject: [PATCH 0282/6055] driver: wifi: siwx91x: Add direct ssid scan support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces support for direct SSID scans The feature allows the device to send the probe requests and listen the beacon frame on the specified SSID. Co-authored-by: Arunmani Alagarsamy Signed-off-by: Arunmani Alagarsamy Signed-off-by: Jérôme Pouiller --- drivers/wifi/siwx91x/Kconfig.siwx91x | 5 +++++ drivers/wifi/siwx91x/siwx91x_wifi.c | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/wifi/siwx91x/Kconfig.siwx91x b/drivers/wifi/siwx91x/Kconfig.siwx91x index ad059a072a7b3..80e312d0f9e5e 100644 --- a/drivers/wifi/siwx91x/Kconfig.siwx91x +++ b/drivers/wifi/siwx91x/Kconfig.siwx91x @@ -45,4 +45,9 @@ config NET_MGMT_EVENT_STACK_SIZE config NET_MGMT_EVENT_QUEUE_SIZE default 10 +# Override the WIFI_MGMT_SCAN_SSID_FILT_MAX parameter for the Wi-Fi subsystem. +# This device supports filtering scan results for only one SSID. +config WIFI_MGMT_SCAN_SSID_FILT_MAX + default 1 + endif diff --git a/drivers/wifi/siwx91x/siwx91x_wifi.c b/drivers/wifi/siwx91x/siwx91x_wifi.c index 6a446e39c5cc6..38a4327a5b741 100644 --- a/drivers/wifi/siwx91x/siwx91x_wifi.c +++ b/drivers/wifi/siwx91x/siwx91x_wifi.c @@ -197,6 +197,7 @@ static int siwx91x_scan(const struct device *dev, struct wifi_scan_params *z_sca { sl_wifi_scan_configuration_t sl_scan_config = { }; struct siwx91x_dev *sidev = dev->data; + sl_wifi_ssid_t ssid = {}; int ret; __ASSERT(z_scan_config, "z_scan_config cannot be NULL"); @@ -210,9 +211,16 @@ static int siwx91x_scan(const struct device *dev, struct wifi_scan_params *z_sca sl_scan_config.channel_bitmap_2g4 = 0xFFFF; memset(sl_scan_config.channel_bitmap_5g, 0xFF, sizeof(sl_scan_config.channel_bitmap_5g)); + if (IS_ENABLED(CONFIG_WIFI_MGMT_SCAN_SSID_FILT_MAX)) { + if (z_scan_config->ssids[0]) { + strncpy(ssid.value, z_scan_config->ssids[0], WIFI_SSID_MAX_LEN); + ssid.length = strlen(z_scan_config->ssids[0]); + } + } sidev->scan_res_cb = cb; - ret = sl_wifi_start_scan(SL_WIFI_CLIENT_INTERFACE, NULL, &sl_scan_config); + ret = sl_wifi_start_scan(SL_WIFI_CLIENT_2_4GHZ_INTERFACE, (ssid.length > 0) ? &ssid : NULL, + &sl_scan_config); if (ret != SL_STATUS_IN_PROGRESS) { return -EIO; } From 4ee4cc39a3e7b3885f0825971385370e5351866e Mon Sep 17 00:00:00 2001 From: Arunmani Alagarsamy Date: Fri, 31 Jan 2025 17:52:15 +0530 Subject: [PATCH 0283/6055] driver: wifi: siwx91x: Add configurable maximum BSS scan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces support for limiting the number of BSS scan results returned by the siwx91x Wi-Fi driver. If scan_max_bss_cnt is specified, the driver will return up to the specified count of BSS results. If not specified, the driver defaults to returning all available results. Co-authored-by: Arunmani Alagarsamy Signed-off-by: Arunmani Alagarsamy Signed-off-by: Jérôme Pouiller --- drivers/wifi/siwx91x/siwx91x_wifi.c | 12 ++++++++++-- drivers/wifi/siwx91x/siwx91x_wifi.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/wifi/siwx91x/siwx91x_wifi.c b/drivers/wifi/siwx91x/siwx91x_wifi.c index 38a4327a5b741..7a1eb801fa624 100644 --- a/drivers/wifi/siwx91x/siwx91x_wifi.c +++ b/drivers/wifi/siwx91x/siwx91x_wifi.c @@ -179,12 +179,19 @@ static unsigned int siwx91x_on_scan(sl_wifi_event_t event, sl_wifi_scan_result_t uint32_t result_size, void *arg) { struct siwx91x_dev *sidev = arg; - int i; + int i, scan_count; if (!sidev->scan_res_cb) { return -EFAULT; } - for (i = 0; i < result->scan_count; i++) { + + if (sidev->scan_max_bss_cnt) { + scan_count = MIN(result->scan_count, sidev->scan_max_bss_cnt); + } else { + scan_count = result->scan_count; + } + + for (i = 0; i < scan_count; i++) { siwx91x_report_scan_res(sidev, result, i); } sidev->scan_res_cb(sidev->iface, 0, NULL); @@ -218,6 +225,7 @@ static int siwx91x_scan(const struct device *dev, struct wifi_scan_params *z_sca } } + sidev->scan_max_bss_cnt = z_scan_config->max_bss_cnt; sidev->scan_res_cb = cb; ret = sl_wifi_start_scan(SL_WIFI_CLIENT_2_4GHZ_INTERFACE, (ssid.length > 0) ? &ssid : NULL, &sl_scan_config); diff --git a/drivers/wifi/siwx91x/siwx91x_wifi.h b/drivers/wifi/siwx91x/siwx91x_wifi.h index e08f4e7f7ebc5..30e740e280112 100644 --- a/drivers/wifi/siwx91x/siwx91x_wifi.h +++ b/drivers/wifi/siwx91x/siwx91x_wifi.h @@ -19,6 +19,7 @@ struct siwx91x_dev { sl_mac_address_t macaddr; enum wifi_iface_state state; scan_result_cb_t scan_res_cb; + uint16_t scan_max_bss_cnt; #ifdef CONFIG_WIFI_SILABS_SIWX91X_NET_STACK_OFFLOAD struct k_event fds_recv_event; From 2e668cfc1e21c116ad0f2fa78088d2a51292bcc9 Mon Sep 17 00:00:00 2001 From: Arunmani Alagarsamy Date: Fri, 31 Jan 2025 18:21:15 +0530 Subject: [PATCH 0284/6055] driver: wifi: siwx91x: Add single and multi-channel scan support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces support for single and multi-channel Wi-Fi scans. The device can now scan one specific channel or multiple specified channels. Co-authored-by: Arunmani Alagarsamy Signed-off-by: Arunmani Alagarsamy Signed-off-by: Jérôme Pouiller --- drivers/wifi/siwx91x/siwx91x_wifi.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/wifi/siwx91x/siwx91x_wifi.c b/drivers/wifi/siwx91x/siwx91x_wifi.c index 7a1eb801fa624..04083284a8377 100644 --- a/drivers/wifi/siwx91x/siwx91x_wifi.c +++ b/drivers/wifi/siwx91x/siwx91x_wifi.c @@ -155,6 +155,7 @@ static void siwx91x_report_scan_res(struct siwx91x_dev *sidev, sl_wifi_scan_resu { SL_WIFI_WPA_ENTERPRISE, WIFI_SECURITY_TYPE_EAP }, { SL_WIFI_WPA2_ENTERPRISE, WIFI_SECURITY_TYPE_EAP }, }; + struct wifi_scan_result tmp = { .channel = result->scan_info[item].rf_channel, .rssi = result->scan_info[item].rssi_val, @@ -162,16 +163,27 @@ static void siwx91x_report_scan_res(struct siwx91x_dev *sidev, sl_wifi_scan_resu .mac_length = sizeof(result->scan_info[item].bssid), .security = WIFI_SECURITY_TYPE_UNKNOWN, .mfp = WIFI_MFP_UNKNOWN, - /* FIXME: fill .mfp, .band and .channel */ + .band = WIFI_FREQ_BAND_2_4_GHZ, }; + if (result->scan_count == 0) { + return; + } + + if (result->scan_info[item].rf_channel <= 0 || result->scan_info[item].rf_channel > 14) { + LOG_WRN("Unexpected scan result"); + tmp.band = WIFI_FREQ_BAND_UNKNOWN; + } + memcpy(tmp.ssid, result->scan_info[item].ssid, tmp.ssid_length); memcpy(tmp.mac, result->scan_info[item].bssid, tmp.mac_length); + ARRAY_FOR_EACH(security_convert, i) { if (security_convert[i].sl_val == result->scan_info[item].security_mode) { tmp.security = security_convert[i].z_val; } } + sidev->scan_res_cb(sidev->iface, 0, &tmp); } @@ -185,6 +197,10 @@ static unsigned int siwx91x_on_scan(sl_wifi_event_t event, sl_wifi_scan_result_t return -EFAULT; } + if (event & SL_WIFI_EVENT_FAIL_INDICATION) { + memset(result, 0, sizeof(*result)); + } + if (sidev->scan_max_bss_cnt) { scan_count = MIN(result->scan_count, sidev->scan_max_bss_cnt); } else { @@ -194,8 +210,10 @@ static unsigned int siwx91x_on_scan(sl_wifi_event_t event, sl_wifi_scan_result_t for (i = 0; i < scan_count; i++) { siwx91x_report_scan_res(sidev, result, i); } + sidev->scan_res_cb(sidev->iface, 0, NULL); sidev->state = WIFI_STATE_INACTIVE; + return 0; } @@ -216,7 +234,10 @@ static int siwx91x_scan(const struct device *dev, struct wifi_scan_params *z_sca /* The enum values are same, no conversion needed */ sl_scan_config.type = z_scan_config->scan_type; - sl_scan_config.channel_bitmap_2g4 = 0xFFFF; + for (int i = 0; i < WIFI_MGMT_SCAN_CHAN_MAX_MANUAL; i++) { + sl_scan_config.channel_bitmap_2g4 |= BIT(z_scan_config->band_chan[i].channel - 1); + } + memset(sl_scan_config.channel_bitmap_5g, 0xFF, sizeof(sl_scan_config.channel_bitmap_5g)); if (IS_ENABLED(CONFIG_WIFI_MGMT_SCAN_SSID_FILT_MAX)) { if (z_scan_config->ssids[0]) { From 9d64cb418646b4ebdade4fb1c204c24ffeed0bba Mon Sep 17 00:00:00 2001 From: Arunmani Alagarsamy Date: Mon, 3 Feb 2025 13:25:25 +0530 Subject: [PATCH 0285/6055] driver: wifi: siwx91x: Add active and passive dwell time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds support for configuring dwell times for both active and passive Wi-Fi scans. The dwell time specifies the duration the device spends on each channel during a scan. Co-authored-by: Arunmani Alagarsamy Signed-off-by: Arunmani Alagarsamy Signed-off-by: Jérôme Pouiller --- drivers/wifi/siwx91x/siwx91x_wifi.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/wifi/siwx91x/siwx91x_wifi.c b/drivers/wifi/siwx91x/siwx91x_wifi.c index 04083284a8377..0e6b210acd1bb 100644 --- a/drivers/wifi/siwx91x/siwx91x_wifi.c +++ b/drivers/wifi/siwx91x/siwx91x_wifi.c @@ -231,8 +231,27 @@ static int siwx91x_scan(const struct device *dev, struct wifi_scan_params *z_sca return -EBUSY; } - /* The enum values are same, no conversion needed */ - sl_scan_config.type = z_scan_config->scan_type; + if (z_scan_config->scan_type == WIFI_SCAN_TYPE_ACTIVE) { + sl_scan_config.type = SL_WIFI_SCAN_TYPE_ACTIVE; + if (!z_scan_config->dwell_time_active) { + ret = sl_si91x_configure_timeout(SL_SI91X_CHANNEL_ACTIVE_SCAN_TIMEOUT, + SL_WIFI_DEFAULT_ACTIVE_CHANNEL_SCAN_TIME); + } else { + ret = sl_si91x_configure_timeout(SL_SI91X_CHANNEL_ACTIVE_SCAN_TIMEOUT, + z_scan_config->dwell_time_active); + } + + if (ret) { + return -EINVAL; + } + } else { + sl_scan_config.type = SL_WIFI_SCAN_TYPE_PASSIVE; + ret = sl_si91x_configure_timeout(SL_SI91X_CHANNEL_PASSIVE_SCAN_TIMEOUT, + z_scan_config->dwell_time_passive); + if (ret) { + return -EINVAL; + } + } for (int i = 0; i < WIFI_MGMT_SCAN_CHAN_MAX_MANUAL; i++) { sl_scan_config.channel_bitmap_2g4 |= BIT(z_scan_config->band_chan[i].channel - 1); From 18acd4ce40f29a6f5c33d857a4393b0861244c36 Mon Sep 17 00:00:00 2001 From: Egill Sigurdur Date: Tue, 4 Feb 2025 11:25:18 +0000 Subject: [PATCH 0286/6055] drivers: sdhc: Fix acronym expansion for SD Host Controller in Kconfig Fixes an issue in which "SDHC" had been incorrectly expanded to "Secure Digital High Capacity" instead of "SD Host Controller". Signed-off-by: Egill Sigurdur --- drivers/sdhc/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sdhc/Kconfig b/drivers/sdhc/Kconfig index 89fa669a5e522..63628d1efba2b 100644 --- a/drivers/sdhc/Kconfig +++ b/drivers/sdhc/Kconfig @@ -2,9 +2,9 @@ # SPDX-License-Identifier: Apache-2.0 menuconfig SDHC - bool "Secure Digital High Capacity (SDHC) drivers" + bool "Secure Digital (SD card) host controller drivers" help - Include drivers for SD host controller + Include drivers for interacting with SD cards if SDHC From 168284a8cca91460c5b498901f22714353cda281 Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Tue, 14 Jan 2025 23:15:32 +0700 Subject: [PATCH 0287/6055] soc: renesas: ra2l1: Add initial support for Renesas RA2L1 SOC series Add basic support for Renesas RA2L1 SOC series. Signed-off-by: Khoa Nguyen Signed-off-by: Thao Luong --- dts/arm/renesas/ra/ra2/r7fa2l1x9.dtsi | 12 ++ dts/arm/renesas/ra/ra2/r7fa2l1xb.dtsi | 11 + dts/arm/renesas/ra/ra2/r7fa2l1xxxxfp.dtsi | 88 ++++++++ dts/arm/renesas/ra/ra2/ra2l1.dtsi | 234 ++++++++++++++++++++++ soc/renesas/ra/ra2l1/CMakeLists.txt | 15 ++ soc/renesas/ra/ra2l1/Kconfig | 14 ++ soc/renesas/ra/ra2l1/Kconfig.defconfig | 20 ++ soc/renesas/ra/ra2l1/Kconfig.soc | 21 ++ soc/renesas/ra/ra2l1/opt_set_mem.ld | 11 + soc/renesas/ra/ra2l1/sections.ld | 123 ++++++++++++ soc/renesas/ra/ra2l1/soc.c | 41 ++++ soc/renesas/ra/ra2l1/soc.h | 17 ++ soc/renesas/ra/soc.yml | 4 + 13 files changed, 611 insertions(+) create mode 100644 dts/arm/renesas/ra/ra2/r7fa2l1x9.dtsi create mode 100644 dts/arm/renesas/ra/ra2/r7fa2l1xb.dtsi create mode 100644 dts/arm/renesas/ra/ra2/r7fa2l1xxxxfp.dtsi create mode 100644 dts/arm/renesas/ra/ra2/ra2l1.dtsi create mode 100644 soc/renesas/ra/ra2l1/CMakeLists.txt create mode 100644 soc/renesas/ra/ra2l1/Kconfig create mode 100644 soc/renesas/ra/ra2l1/Kconfig.defconfig create mode 100644 soc/renesas/ra/ra2l1/Kconfig.soc create mode 100644 soc/renesas/ra/ra2l1/opt_set_mem.ld create mode 100644 soc/renesas/ra/ra2l1/sections.ld create mode 100644 soc/renesas/ra/ra2l1/soc.c create mode 100644 soc/renesas/ra/ra2l1/soc.h diff --git a/dts/arm/renesas/ra/ra2/r7fa2l1x9.dtsi b/dts/arm/renesas/ra/ra2/r7fa2l1x9.dtsi new file mode 100644 index 0000000000000..e20c050133579 --- /dev/null +++ b/dts/arm/renesas/ra/ra2/r7fa2l1x9.dtsi @@ -0,0 +1,12 @@ +/** + * Copyright (c) 2024 MUNIC SA + * + * Renesas R7FA2AL1x9 MCU device tree + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +&flash0 { + reg = <0x0 DT_SIZE_K(128)>; +}; diff --git a/dts/arm/renesas/ra/ra2/r7fa2l1xb.dtsi b/dts/arm/renesas/ra/ra2/r7fa2l1xb.dtsi new file mode 100644 index 0000000000000..b148a4337eb80 --- /dev/null +++ b/dts/arm/renesas/ra/ra2/r7fa2l1xb.dtsi @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2024 MUNIC SA + * + * Renesas R7FA2AL1AB MCU device tree + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + reg = <0x0 DT_SIZE_K(256)>; +}; diff --git a/dts/arm/renesas/ra/ra2/r7fa2l1xxxxfp.dtsi b/dts/arm/renesas/ra/ra2/r7fa2l1xxxxfp.dtsi new file mode 100644 index 0000000000000..a55ae8fa6f9d4 --- /dev/null +++ b/dts/arm/renesas/ra/ra2/r7fa2l1xxxxfp.dtsi @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2024 MUNIC SA + * Copyright (c) 2024-2025 Renesas Electronics Corporation + * + * Renesas R7FA2AL1AxxxFP MCU device tree for 100 pins socket + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/ { + clocks: clocks { + #address-cells = <1>; + #size-cells = <1>; + + xtal: clock-main-osc { + compatible = "renesas,ra-cgc-external-clock"; + clock-frequency = ; + #clock-cells = <0>; + status = "disabled"; + }; + + hoco: clock-hoco { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + moco: clock-moco { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + loco: clock-loco { + compatible = "fixed-clock"; + clock-frequency = <32768>; + #clock-cells = <0>; + }; + + subclk: clock-subclk { + compatible = "renesas,ra-cgc-subclk"; + clock-frequency = <32768>; + #clock-cells = <0>; + status = "disabled"; + }; + + pclkblock: pclkblock@4001e01c { + compatible = "renesas,ra-cgc-pclk-block"; + reg = <0x4001e01c 4>, <0x40047000 4>, <0x40047004 4>, + <0x40047008 4>; + reg-names = "MSTPA", "MSTPB","MSTPC", + "MSTPD"; + #clock-cells = <0>; + clocks = <&hoco>; + status = "okay"; + + iclk: iclk { + compatible = "renesas,ra-cgc-pclk"; + clock-frequency = <48000000>; + div = <1>; + #clock-cells = <2>; + status = "okay"; + }; + + pclkb: pclkb { + compatible = "renesas,ra-cgc-pclk"; + div = <2>; + #clock-cells = <2>; + status = "okay"; + }; + + pclkd: pclkd { + compatible = "renesas,ra-cgc-pclk"; + div = <1>; + #clock-cells = <2>; + status = "okay"; + }; + + clkout: clkout { + compatible = "renesas,ra-cgc-pclk"; + #clock-cells = <2>; + status = "disabled"; + }; + + }; + }; +}; diff --git a/dts/arm/renesas/ra/ra2/ra2l1.dtsi b/dts/arm/renesas/ra/ra2/ra2l1.dtsi new file mode 100644 index 0000000000000..91a19de082583 --- /dev/null +++ b/dts/arm/renesas/ra/ra2/ra2l1.dtsi @@ -0,0 +1,234 @@ +/** + * Copyright (c) 2021-2024 MUNIC SA + * Copyright (c) 2024 Renesas Electronics Corporation + * + * Renesas RA2L1 MCU series device tree + * + * 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-m23"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + + mpu: mpu@e000ed90 { + compatible = "arm,armv8m-mpu"; + reg = <0xe000ed90 0x40>; + }; + }; + }; + + soc { + interrupt-parent = <&nvic>; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x8000>; + }; + + system: system@4001e000 { + compatible = "renesas,ra-system"; + reg = <0x4001e000 0x1000>; + status = "okay"; + }; + + flcn: flash-controller@407ec000 { + reg = <0x407ec000 0x10000>; + + #address-cells = <1>; + #size-cells = <1>; + + flash0: code@0 { + compatible = "soc-nv-flash"; + /* "reg" property should be defined in the + * chip specific .dtsi file + */ + }; + + flash1: data@40100000 { + compatible = "soc-nv-flash"; + reg = <0x40100000 DT_SIZE_K(8)>; + }; + }; + + ioport0: gpio@40040000 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x40040000 0x20>; + port = <0>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport1: gpio@40040020 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x40040020 0x20>; + port = <1>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport2: gpio@40040040 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x40040040 0x20>; + port = <2>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport3: gpio@40040060 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x40040060 0x20>; + port = <3>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport4: gpio@40040080 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x40040080 0x20>; + port = <4>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport5: gpio@400400a0 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x400400a0 0x20>; + port = <5>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport6: gpio@400400c0 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x400400c0 0x20>; + port = <6>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport7: gpio@400400e0 { + compatible = "renesas,ra-gpio-ioport"; + reg = <0x400400e0 0x20>; + port = <7>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + pinctrl: pin-controller@40040800 { + compatible = "renesas,ra-pinctrl-pfs"; + reg = <0x40040800 0x3c0>; + status = "okay"; + }; + + sci0: sci0@40070000 { + compatible = "renesas,ra-sci"; + interrupts = <0 1>, <1 1>, <2 1>, <3 1>; + interrupt-names = "rxi", "txi", "tei", "eri"; + reg = <0x40070000 0x100>; + clocks = <&pclkb MSTPB 31>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <0>; + status = "disabled"; + }; + }; + + sci1: sci1@40070020 { + compatible = "renesas,ra-sci"; + reg = <0x40070020 0x100>; + clocks = <&pclkb MSTPB 30>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <1>; + status = "disabled"; + }; + }; + + sci2: sci2@40070040 { + compatible = "renesas,ra-sci"; + reg = <0x40070040 0x100>; + clocks = <&pclkb MSTPB 29>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <2>; + status = "disabled"; + }; + }; + + sci3: sci3@40070060 { + compatible = "renesas,ra-sci"; + reg = <0x40070060 0x100>; + clocks = <&pclkb MSTPB 28>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <3>; + status = "disabled"; + }; + }; + + sci9: sci9@40070120 { + compatible = "renesas,ra-sci"; + interrupts = <4 1>, <5 1>, <6 1>, <7 1>; + interrupt-names = "rxi", "txi", "tei", "eri"; + reg = <0x40070120 0x100>; + clocks = <&pclkb MSTPB 22>; + status = "disabled"; + + uart { + compatible = "renesas,ra-sci-uart"; + channel = <9>; + status = "disabled"; + }; + }; + + id_code: id_code@1010018 { + compatible = "zephyr,memory-region"; + reg = <0x01010018 0x20>; + zephyr,memory-region = "ID_CODE"; + status = "okay"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <2>; +}; diff --git a/soc/renesas/ra/ra2l1/CMakeLists.txt b/soc/renesas/ra/ra2l1/CMakeLists.txt new file mode 100644 index 0000000000000..240342ab88d24 --- /dev/null +++ b/soc/renesas/ra/ra2l1/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2022-2024 MUNIC SA +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_sources( + soc.c +) + +zephyr_linker_sources(ROM_START opt_set_mem.ld) + +zephyr_linker_sources(SECTIONS sections.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/renesas/ra/ra2l1/Kconfig b/soc/renesas/ra/ra2l1/Kconfig new file mode 100644 index 0000000000000..e3a0ab7ceabe0 --- /dev/null +++ b/soc/renesas/ra/ra2l1/Kconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 MUNIC SA +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RA2L1 + select ARM + select CPU_CORTEX_M23 + select CPU_HAS_ARM_MPU + select HAS_RENESAS_RA_FSP + select CPU_CORTEX_M_HAS_VTOR + select CPU_CORTEX_M_HAS_SYSTICK + select CLOCK_CONTROL_RENESAS_RA_CGC if CLOCK_CONTROL + select HAS_SWO + select SOC_EARLY_INIT_HOOK diff --git a/soc/renesas/ra/ra2l1/Kconfig.defconfig b/soc/renesas/ra/ra2l1/Kconfig.defconfig new file mode 100644 index 0000000000000..ccfd393a9f5ac --- /dev/null +++ b/soc/renesas/ra/ra2l1/Kconfig.defconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2024 MUNIC SA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RA2L1 + +config NUM_IRQS + default 32 + +DT_ICLK_PATH := $(dt_nodelabel_path,iclk) + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,$(DT_ICLK_PATH),clock-frequency) + +config BUILD_OUTPUT_HEX + default y + +config CLOCK_CONTROL + default y + +endif # SOC_SERIES_RA2L1 diff --git a/soc/renesas/ra/ra2l1/Kconfig.soc b/soc/renesas/ra/ra2l1/Kconfig.soc new file mode 100644 index 0000000000000..5a4fdb1cfd7a3 --- /dev/null +++ b/soc/renesas/ra/ra2l1/Kconfig.soc @@ -0,0 +1,21 @@ +# Copyright (c) 2024 MUNIC SA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RA2L1 + bool + select SOC_FAMILY_RENESAS_RA + +config SOC_R7FA2L1A9XXFP + bool + select SOC_SERIES_RA2L1 + +config SOC_R7FA2L1ABXXFP + bool + select SOC_SERIES_RA2L1 + +config SOC_SERIES + default "ra2l1" if SOC_SERIES_RA2L1 + +config SOC + default "r7fa2l1a9xxfp" if SOC_R7FA2L1A9XXFP + default "r7fa2l1abxxfp" if SOC_R7FA2L1ABXXFP diff --git a/soc/renesas/ra/ra2l1/opt_set_mem.ld b/soc/renesas/ra/ra2l1/opt_set_mem.ld new file mode 100644 index 0000000000000..07aef9e92d838 --- /dev/null +++ b/soc/renesas/ra/ra2l1/opt_set_mem.ld @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* ROM Registers start at address 0x00000400 */ +. = 0x400; +KEEP(*(.rom_registers*)) +/* Reserving 0x100 bytes of space for ROM registers. */ +. = 0x500; diff --git a/soc/renesas/ra/ra2l1/sections.ld b/soc/renesas/ra/ra2l1/sections.ld new file mode 100644 index 0000000000000..5e7aad11ed7c3 --- /dev/null +++ b/soc/renesas/ra/ra2l1/sections.ld @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +SECTION_DATA_PROLOGUE(.fsp_dtc_vector_table,(NOLOAD),) +{ + /* If DTC is used, put the DTC vector table at the start of SRAM. + This avoids memory holes due to 1K alignment required by it. */ + *(.fsp_dtc_vector_table) +} GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_ofs), okay) + +SECTION_PROLOGUE(.option_setting_ofs,,) +{ + __OPTION_SETTING_OFS_Start = .; + KEEP(*(.option_setting_ofs0)) + . = __OPTION_SETTING_OFS_Start + 0x04; + KEEP(*(.option_setting_ofs2)) + . = __OPTION_SETTING_OFS_Start + 0x10; + KEEP(*(.option_setting_dualsel)) + __OPTION_SETTING_OFS_End = .; +} GROUP_LINK_IN(OPTION_SETTING_OFS) = 0xFF + +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_sas), okay) + +SECTION_PROLOGUE(.option_setting_sas,,) +{ + __OPTION_SETTING_SAS_Start = .; + KEEP(*(.option_setting_sas)) + __OPTION_SETTING_SAS_End = .; +} GROUP_LINK_IN(OPTION_SETTING_SAS) = 0xFF + +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_ns), okay) + +SECTION_PROLOGUE(.option_setting_ns,,) +{ + __OPTION_SETTING_NS_Start = .; + KEEP(*(.option_setting_ofs1)) + . = __OPTION_SETTING_NS_Start + 0x04; + KEEP(*(.option_setting_ofs3)) + . = __OPTION_SETTING_NS_Start + 0x10; + KEEP(*(.option_setting_banksel)) + . = __OPTION_SETTING_NS_Start + 0x40; + KEEP(*(.option_setting_bps0)) + . = __OPTION_SETTING_NS_Start + 0x44; + KEEP(*(.option_setting_bps1)) + . = __OPTION_SETTING_NS_Start + 0x48; + KEEP(*(.option_setting_bps2)) + . = __OPTION_SETTING_NS_Start + 0x4C; + KEEP(*(.option_setting_bps3)) + . = __OPTION_SETTING_NS_Start + 0x60; + KEEP(*(.option_setting_pbps0)) + . = __OPTION_SETTING_NS_Start + 0x64; + KEEP(*(.option_setting_pbps1)) + . = __OPTION_SETTING_NS_Start + 0x68; + KEEP(*(.option_setting_pbps2)) + . = __OPTION_SETTING_NS_Start + 0x6C; + KEEP(*(.option_setting_pbps3)) + __OPTION_SETTING_NS_End = .; +} GROUP_LINK_IN(OPTION_SETTING) = 0xFF + +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_s), okay) + +SECTION_PROLOGUE(.option_setting_s,,) +{ + __OPTION_SETTING_S_Start = .; + KEEP(*(.option_setting_ofs1_sec)) + . = __OPTION_SETTING_S_Start + 0x04; + KEEP(*(.option_setting_ofs3_sec)) + . = __OPTION_SETTING_S_Start + 0x10; + KEEP(*(.option_setting_banksel_sec)) + . = __OPTION_SETTING_S_Start + 0x40; + KEEP(*(.option_setting_bps_sec0)) + . = __OPTION_SETTING_S_Start + 0x44; + KEEP(*(.option_setting_bps_sec1)) + . = __OPTION_SETTING_S_Start + 0x48; + KEEP(*(.option_setting_bps_sec2)) + . = __OPTION_SETTING_S_Start + 0x4C; + KEEP(*(.option_setting_bps_sec3)) + . = __OPTION_SETTING_S_Start + 0x60; + KEEP(*(.option_setting_pbps_sec0)) + . = __OPTION_SETTING_S_Start + 0x64; + KEEP(*(.option_setting_pbps_sec1)) + . = __OPTION_SETTING_S_Start + 0x68; + KEEP(*(.option_setting_pbps_sec2)) + . = __OPTION_SETTING_S_Start + 0x6C; + KEEP(*(.option_setting_pbps_sec3)) + . = __OPTION_SETTING_S_Start + 0x80; + KEEP(*(.option_setting_ofs1_sel)) + . = __OPTION_SETTING_S_Start + 0x84; + KEEP(*(.option_setting_ofs3_sel)) + . = __OPTION_SETTING_S_Start + 0x90; + KEEP(*(.option_setting_banksel_sel)) + . = __OPTION_SETTING_S_Start + 0xC0; + KEEP(*(.option_setting_bps_sel0)) + . = __OPTION_SETTING_S_Start + 0xC4; + KEEP(*(.option_setting_bps_sel1)) + . = __OPTION_SETTING_S_Start + 0xC8; + KEEP(*(.option_setting_bps_sel2)) + . = __OPTION_SETTING_S_Start + 0xCC; + KEEP(*(.option_setting_bps_sel3)) + __OPTION_SETTING_S_End = .; +} GROUP_LINK_IN(OPTION_SETTING_S) = 0xFF + +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(id_code), okay) + +SECTION_PROLOGUE(.id_code,,) +{ + KEEP(*(.id_code*)) +} GROUP_LINK_IN(ID_CODE) + +#endif diff --git a/soc/renesas/ra/ra2l1/soc.c b/soc/renesas/ra/ra2l1/soc.c new file mode 100644 index 0000000000000..9e1cdb3930284 --- /dev/null +++ b/soc/renesas/ra/ra2l1/soc.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023-2024 MUNIC SA + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System/hardware module for Renesas RA2L1 family processor + */ + +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + +#include "bsp_cfg.h" +#include + +uint32_t SystemCoreClock BSP_SECTION_EARLY_INIT; + +volatile uint32_t g_protect_pfswe_counter BSP_SECTION_EARLY_INIT; + +/** + * @brief Perform basic hardware initialization at boot. + * + * This needs to be run from the very beginning. + */ +void soc_early_init_hook(void) +{ + + SystemCoreClock = BSP_MOCO_HZ; + g_protect_pfswe_counter = 0; + +} diff --git a/soc/renesas/ra/ra2l1/soc.h b/soc/renesas/ra/ra2l1/soc.h new file mode 100644 index 0000000000000..2fa588a6c0c3f --- /dev/null +++ b/soc/renesas/ra/ra2l1/soc.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021-2024 MUNIC SA + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the Renesas RA2L1 family MCU + */ + +#ifndef ZEPHYR_SOC_RENESAS_RA2L1_SOC_H_ +#define ZEPHYR_SOC_RENESAS_RA2L1_SOC_H_ + +#include + +#endif /* ZEPHYR_SOC_RENESAS_RA2L1_SOC_H_ */ diff --git a/soc/renesas/ra/soc.yml b/soc/renesas/ra/soc.yml index 7d73ed9269258..e923db71a671d 100644 --- a/soc/renesas/ra/soc.yml +++ b/soc/renesas/ra/soc.yml @@ -4,6 +4,10 @@ family: - name: ra2a1 socs: - name: r7fa2a1ab3cfm + - name: ra2l1 + socs: + - name: r7fa2l1a9xxfp + - name: r7fa2l1abxxfp - name: ra4e1 socs: - name: r7fa4e10d2cfm From 493ba5c1149f2c5f30b11829f3d75401ee4cf099 Mon Sep 17 00:00:00 2001 From: Thao Luong Date: Tue, 14 Jan 2025 23:17:17 +0700 Subject: [PATCH 0288/6055] boards: arm: renesas: ek-ra2l1: Add initial support for Renesas EK-RA2L1 Add inital support for the Renesas EK-RA2L1 evaluation board. Signed-off-by: Khoa Nguyen Signed-off-by: Thao Luong --- boards/renesas/ek_ra2l1/Kconfig.ek_ra2l1 | 5 + boards/renesas/ek_ra2l1/board.cmake | 12 ++ boards/renesas/ek_ra2l1/board.yml | 5 + boards/renesas/ek_ra2l1/doc/ek_ra2l1.webp | Bin 0 -> 46270 bytes boards/renesas/ek_ra2l1/doc/index.rst | 122 ++++++++++++++++++ boards/renesas/ek_ra2l1/ek_ra2l1-pinctrl.dtsi | 14 ++ boards/renesas/ek_ra2l1/ek_ra2l1.dts | 57 ++++++++ boards/renesas/ek_ra2l1/ek_ra2l1.yaml | 16 +++ boards/renesas/ek_ra2l1/ek_ra2l1_defconfig | 12 ++ 9 files changed, 243 insertions(+) create mode 100644 boards/renesas/ek_ra2l1/Kconfig.ek_ra2l1 create mode 100644 boards/renesas/ek_ra2l1/board.cmake create mode 100644 boards/renesas/ek_ra2l1/board.yml create mode 100644 boards/renesas/ek_ra2l1/doc/ek_ra2l1.webp create mode 100644 boards/renesas/ek_ra2l1/doc/index.rst create mode 100644 boards/renesas/ek_ra2l1/ek_ra2l1-pinctrl.dtsi create mode 100644 boards/renesas/ek_ra2l1/ek_ra2l1.dts create mode 100644 boards/renesas/ek_ra2l1/ek_ra2l1.yaml create mode 100644 boards/renesas/ek_ra2l1/ek_ra2l1_defconfig diff --git a/boards/renesas/ek_ra2l1/Kconfig.ek_ra2l1 b/boards/renesas/ek_ra2l1/Kconfig.ek_ra2l1 new file mode 100644 index 0000000000000..53479a895c85a --- /dev/null +++ b/boards/renesas/ek_ra2l1/Kconfig.ek_ra2l1 @@ -0,0 +1,5 @@ +# Copyright (c) 2021-2024 MUNIC SA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_EK_RA2L1 + select SOC_R7FA2L1ABXXFP diff --git a/boards/renesas/ek_ra2l1/board.cmake b/boards/renesas/ek_ra2l1/board.cmake new file mode 100644 index 0000000000000..e39493b726b6a --- /dev/null +++ b/boards/renesas/ek_ra2l1/board.cmake @@ -0,0 +1,12 @@ +# Copyright (c) 2021-2024 MUNIC SA +# SPDX-License-Identifier: Apache-2.0 + +board_set_debugger_ifnset(jlink) +board_set_flasher_ifnset(jlink) + +board_runner_args(jlink "--device=r7fa2l1ab") +board_runner_args(pyocd "--target=r7fa2l1ab") + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/renesas/ek_ra2l1/board.yml b/boards/renesas/ek_ra2l1/board.yml new file mode 100644 index 0000000000000..181a338410b97 --- /dev/null +++ b/boards/renesas/ek_ra2l1/board.yml @@ -0,0 +1,5 @@ +board: + name: ek_ra2l1 + vendor: renesas + socs: + - name: r7fa2l1abxxfp diff --git a/boards/renesas/ek_ra2l1/doc/ek_ra2l1.webp b/boards/renesas/ek_ra2l1/doc/ek_ra2l1.webp new file mode 100644 index 0000000000000000000000000000000000000000..54da291633055e764d40ca0916267872e23477d6 GIT binary patch literal 46270 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