From 3be2956b866e3edfed4ad7617e8ca01e16d98065 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Mon, 6 Nov 2023 12:26:12 +0100 Subject: [PATCH 0001/1049] drivers: ethernet: fix adin set_config lock Use correct argument to lock/unlock the MAC. Signed-off-by: Georgij Cernysiov --- drivers/ethernet/eth_adin2111.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ethernet/eth_adin2111.c b/drivers/ethernet/eth_adin2111.c index 070b8698c10afd0..e73beb891d4bb68 100644 --- a/drivers/ethernet/eth_adin2111.c +++ b/drivers/ethernet/eth_adin2111.c @@ -700,7 +700,7 @@ static int adin2111_port_set_config(const struct device *dev, const struct device *adin = cfg->adin; int ret = -ENOTSUP; - (void)eth_adin2111_lock(dev, K_FOREVER); + (void)eth_adin2111_lock(adin, K_FOREVER); if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) { ret = adin2111_filter_unicast(adin, (uint8_t *)&config->mac_address.addr[0], @@ -716,7 +716,7 @@ static int adin2111_port_set_config(const struct device *dev, } end_unlock: - (void)eth_adin2111_unlock(dev); + (void)eth_adin2111_unlock(adin); return ret; } From 8bec2d7b37e14b5605f786f3ea6c0d3749fc96ab Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 7 Nov 2023 20:32:18 +0000 Subject: [PATCH 0002/1049] boards: roc_rk3568: do not use as default test platform Only qemu boards are used as default in CI, drop the default property from this one. Signed-off-by: Fabio Baltieri --- boards/arm64/roc_rk3568_pc/roc_rk3568_pc.yaml | 1 - boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.yaml b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.yaml index 6a303ded9fa5d17..82f35f567d5dfe8 100644 --- a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.yaml +++ b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.yaml @@ -7,7 +7,6 @@ toolchain: - cross-compile ram: 1024 testing: - default: true ignore_tags: - net - bluetooth diff --git a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.yaml b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.yaml index abc5dddabda4392..07120b871fa5812 100644 --- a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.yaml +++ b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.yaml @@ -9,7 +9,6 @@ ram: 1024 supported: - smp testing: - default: true ignore_tags: - net - bluetooth From 386b65800896262779336e83552c8a44ba96f7a2 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Fri, 1 Sep 2023 11:20:03 +0200 Subject: [PATCH 0003/1049] boards: arm: add nrf9131ek_nrf9131 This patch adds the nRF9131-EK board. Signed-off-by: Maximilian Deubel --- boards/arm/nrf9131ek_nrf9131/Kconfig.board | 14 ++ .../arm/nrf9131ek_nrf9131/Kconfig.defconfig | 38 +++ boards/arm/nrf9131ek_nrf9131/board.cmake | 14 ++ .../nrf9131ek_nrf9131/nrf9131ek_nrf9131.dts | 19 ++ .../nrf9131ek_nrf9131/nrf9131ek_nrf9131.yaml | 17 ++ .../nrf9131ek_nrf9131_common-pinctrl.dtsi | 100 ++++++++ .../nrf9131ek_nrf9131_common.dtsi | 227 ++++++++++++++++++ .../nrf9131ek_nrf9131_defconfig | 26 ++ .../nrf9131ek_nrf9131_ns.dts | 22 ++ .../nrf9131ek_nrf9131_ns.yaml | 15 ++ .../nrf9131ek_nrf9131_ns_defconfig | 35 +++ .../nrf9131ek_nrf9131_partition_conf.dtsi | 60 +++++ .../arm/nrf9131ek_nrf9131/pre_dt_board.cmake | 7 + tests/lib/devicetree/devices/testcase.yaml | 2 + 14 files changed, 596 insertions(+) create mode 100644 boards/arm/nrf9131ek_nrf9131/Kconfig.board create mode 100644 boards/arm/nrf9131ek_nrf9131/Kconfig.defconfig create mode 100644 boards/arm/nrf9131ek_nrf9131/board.cmake create mode 100644 boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.dts create mode 100644 boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.yaml create mode 100644 boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common-pinctrl.dtsi create mode 100644 boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi create mode 100644 boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_defconfig create mode 100644 boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.dts create mode 100644 boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.yaml create mode 100644 boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns_defconfig create mode 100644 boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_partition_conf.dtsi create mode 100644 boards/arm/nrf9131ek_nrf9131/pre_dt_board.cmake diff --git a/boards/arm/nrf9131ek_nrf9131/Kconfig.board b/boards/arm/nrf9131ek_nrf9131/Kconfig.board new file mode 100644 index 000000000000000..4a237e3fb617a7f --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/Kconfig.board @@ -0,0 +1,14 @@ +# nRF9131-EK board configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF9131_LACA + +config BOARD_NRF9131EK_NRF9131 + bool "nRF9131 EK NRF9131" + +config BOARD_NRF9131EK_NRF9131_NS + bool "nRF9131 EK NRF9131 non-secure" + +endif # SOC_NRF9131_LACA diff --git a/boards/arm/nrf9131ek_nrf9131/Kconfig.defconfig b/boards/arm/nrf9131ek_nrf9131/Kconfig.defconfig new file mode 100644 index 000000000000000..0ece4f9a2ac1cff --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/Kconfig.defconfig @@ -0,0 +1,38 @@ +# nRF9131 EK NRF9131 board configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NRF9131EK_NRF9131 || BOARD_NRF9131EK_NRF9131_NS + +config BOARD + default "nrf9131ek_nrf9131" + +# For the secure version of the board the firmware is linked at the beginning +# of the flash, or into the code-partition defined in DT if it is intended to +# be loaded by MCUboot. If the secure firmware is to be combined with a non- +# secure image (TRUSTED_EXECUTION_SECURE=y), the secure FW image shall always +# be restricted to the size of its code partition. +# For the non-secure version of the board, the firmware +# must be linked into the code-partition (non-secure) defined in DT, regardless. +# Apply this configuration below by setting the Kconfig symbols used by +# the linker according to the information extracted from DT partitions. + +# Workaround for not being able to have commas in macro arguments +DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition + +config FLASH_LOAD_SIZE + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + depends on BOARD_NRF9131EK_NRF9131 && TRUSTED_EXECUTION_SECURE + +if BOARD_NRF9131EK_NRF9131_NS + +config FLASH_LOAD_OFFSET + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +config FLASH_LOAD_SIZE + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +endif # BOARD_NRF9131EK_NRF9131_NS + +endif # BOARD_NRF9131EK_NRF9131 || BOARD_NRF9131EK_NRF9131_NS diff --git a/boards/arm/nrf9131ek_nrf9131/board.cmake b/boards/arm/nrf9131ek_nrf9131/board.cmake new file mode 100644 index 000000000000000..8293a428b401347 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/board.cmake @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_NRF9131EK_NRF9131_NS) + set(TFM_PUBLIC_KEY_FORMAT "full") +endif() + +if(CONFIG_TFM_FLASH_MERGED_BINARY) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file tfm_merged.hex) +endif() + +# TODO: change to nRF9131_xxAA when such device is available in JLink +board_runner_args(jlink "--device=nRF9160_xxAA" "--speed=4000") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.dts b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.dts new file mode 100644 index 000000000000000..4b66e5348a0509a --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.dts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf9131ek_nrf9131_common.dtsi" + +/ { + chosen { + zephyr,sram = &sram0_s; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + zephyr,sram-non-secure-partition = &sram0_ns; + }; +}; diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.yaml b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.yaml new file mode 100644 index 000000000000000..d1b04054ce8914a --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.yaml @@ -0,0 +1,17 @@ +identifier: nrf9131ek_nrf9131 +name: nRF9131-EK-NRF9131 +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 88 +flash: 1024 +supported: + - gpio + - i2c + - pwm + - spi + - watchdog + - counter diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common-pinctrl.dtsi b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common-pinctrl.dtsi new file mode 100644 index 000000000000000..419e7c8d70ce975 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common-pinctrl.dtsi @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + uart1_default: uart1_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + i2c2_default: i2c2_default { + group1 { + psels = , + ; + }; + }; + + i2c2_sleep: i2c2_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = , + , + ; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + spi3_default: spi3_default { + group1 { + psels = , + , + ; + nordic,drive-mode = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi new file mode 100644 index 000000000000000..35314cd0784f777 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "nrf9131ek_nrf9131_common-pinctrl.dtsi" +#include + +/ { + model = "Nordic nRF9131 EK NRF9131"; + compatible = "nordic,nrf9131-ek-nrf9131"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + led1: led_1 { + gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + label = "Green LED 2"; + }; + led2: led_2 { + gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + label = "Green LED 3"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led0: pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(8) PWM_POLARITY_NORMAL>; + }; + pwm_led1: pwm_led_1 { + pwms = <&pwm0 1 PWM_MSEC(8) PWM_POLARITY_NORMAL>; + }; + pwm_led2: pwm_led_2 { + pwms = <&pwm0 2 PWM_MSEC(8) PWM_POLARITY_NORMAL>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 28 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + pwm-led0 = &pwm_led0; + pwm-led1 = &pwm_led1; + pwm-led2 = &pwm_led2; + sw0 = &button0; + bootloader-led0 = &led0; + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; + watchdog0 = &wdt0; + spi-flash0 = &gd25wb256; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&i2c2 { + compatible = "nordic,nrf-twim"; + status = "okay"; + pinctrl-0 = <&i2c2_default>; + pinctrl-1 = <&i2c2_sleep>; + pinctrl-names = "default", "sleep"; + clock-frequency = ; + + pmic_main: npm1300@6b { + compatible = "nordic,npm1300"; + reg = <0x6b>; + pmic_charger: charger { + compatible = "nordic,npm1300-charger"; + term-microvolt = <4150000>; + term-warm-microvolt = <4000000>; + current-microamp = <150000>; + dischg-limit-microamp = <1000000>; + vbus-limit-microamp = <500000>; + thermistor-ohms = <10000>; + thermistor-beta = <3380>; + charging-enable; + }; + regulators { + compatible = "nordic,npm1300-regulator"; + BUCK1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + BUCK2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + }; + }; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + cs-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + gd25wb256: gd25wb256e3ir@0 { + compatible = "jedec,spi-nor"; + status = "disabled"; + reg = <0>; + spi-max-frequency = <8000000>; + size = <268435456>; + has-dpd; + t-enter-dpd = <3000>; + t-exit-dpd = <40000>; + sfdp-bfp = [ + e5 20 f3 ff ff ff ff 0f 44 eb 08 6b 08 3b 42 bb + ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 + 10 d8 00 ff 44 7a c9 fe 83 67 26 62 ec 82 18 44 + 7a 75 7a 75 04 c4 d5 5c 00 06 74 00 08 50 00 01 + ]; + jedec-id = [c8 65 19]; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x10000>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + }; + slot0_ns_partition: partition@50000 { + label = "image-0-nonsecure"; + }; + slot1_partition: partition@85000 { + label = "image-1"; + }; + slot1_ns_partition: partition@c5000 { + label = "image-1-nonsecure"; + }; + storage_partition: partition@fa000 { + label = "storage"; + reg = <0x000fa000 0x00006000>; + }; + }; +}; + + + +/ { + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_s: image_s@20000000 { + /* Secure image memory */ + }; + + sram0_modem: image_modem@20016000 { + /* Modem (shared) memory */ + }; + + sram0_ns: image_ns@20020000 { + /* Non-Secure image memory */ + }; + }; +}; + +/* Include partition configuration file */ +#include "nrf9131ek_nrf9131_partition_conf.dtsi" diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_defconfig b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_defconfig new file mode 100644 index 000000000000000..fc77ffe0d13a856 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF91X=y +CONFIG_SOC_NRF9131_LACA=y +CONFIG_BOARD_NRF9131EK_NRF9131=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +CONFIG_PINCTRL=y diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.dts b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.dts new file mode 100644 index 000000000000000..9a652cd0aed8bfb --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf9131ek_nrf9131_common.dtsi" + +/ { + chosen { + zephyr,flash = &flash0; + zephyr,sram = &sram0_ns; + zephyr,code-partition = &slot0_ns_partition; + }; +}; + +/* Disable UART1, because it is used by default in TF-M */ +&uart1 { + status = "disabled"; +}; diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.yaml b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.yaml new file mode 100644 index 000000000000000..cf33abd55da3c03 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.yaml @@ -0,0 +1,15 @@ +identifier: nrf9131ek_nrf9131_ns +name: nRF9131-EK-NRF9131-Non-Secure +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 128 +flash: 212 +supported: + - i2c + - pwm + - watchdog + - netif:modem diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns_defconfig b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns_defconfig new file mode 100644 index 000000000000000..83af1cf6b74ad11 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns_defconfig @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF91X=y +CONFIG_SOC_NRF9131_LACA=y +CONFIG_BOARD_NRF9131EK_NRF9131_NS=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# This Board implies building Non-Secure firmware +CONFIG_TRUSTED_EXECUTION_NONSECURE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +CONFIG_PINCTRL=y + +# enable PMIC +CONFIG_I2C=y +CONFIG_REGULATOR=y +CONFIG_SENSOR=y +CONFIG_NPM1300_CHARGER=y diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_partition_conf.dtsi b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_partition_conf.dtsi new file mode 100644 index 000000000000000..d14d8d95f75855b --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_partition_conf.dtsi @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Default Flash planning for nRF9131ek_nrf9131. + * + * Zephyr build for nRF9131 with ARM TrustZone-M support, + * implies building Secure and Non-Secure Zephyr images. + * + * Secure image will be placed, by default, in flash0 + * (or in slot0, if MCUboot is present). + * Secure image will use sram0 for system memory. + * + * Non-Secure image will be placed in slot0_ns, and use + * sram0_ns for system memory. + * + * Note that the Secure image only requires knowledge of + * the beginning of the Non-Secure image (not its size). + */ + +&slot0_partition { + reg = <0x00010000 0x40000>; +}; + +&slot0_ns_partition { + reg = <0x00050000 0x35000>; +}; + +&slot1_partition { + reg = <0x00085000 0x40000>; +}; + +&slot1_ns_partition { + reg = <0x000c5000 0x35000>; +}; + +/* Default SRAM planning when building for nRF9131 with + * ARM TrustZone-M support + * - Lowest 88 kB SRAM allocated to Secure image (sram0_s). + * - 40 kB SRAM reserved for and used by the modem library + * (sram0_modem). This memory is Non-Secure. + * - Upper 128 kB allocated to Non-Secure image (sram0_ns). + * When building with TF-M, both sram0_modem and sram0_ns + * are allocated to the Non-Secure image. + */ + +&sram0_s { + reg = <0x20000000 DT_SIZE_K(88)>; +}; + +&sram0_modem { + reg = <0x20016000 DT_SIZE_K(40)>; +}; + +&sram0_ns { + reg = <0x20020000 DT_SIZE_K(128)>; +}; diff --git a/boards/arm/nrf9131ek_nrf9131/pre_dt_board.cmake b/boards/arm/nrf9131ek_nrf9131/pre_dt_board.cmake new file mode 100644 index 000000000000000..c8267afd1b470a1 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2021 Linaro Limited +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - flash-controller@39000 & kmu@39000 +# - power@5000 & clock@5000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/tests/lib/devicetree/devices/testcase.yaml b/tests/lib/devicetree/devices/testcase.yaml index d7695220b8bdcb0..07c99fcdb629acc 100644 --- a/tests/lib/devicetree/devices/testcase.yaml +++ b/tests/lib/devicetree/devices/testcase.yaml @@ -16,3 +16,5 @@ tests: - bl5340_dvk_cpuapp_ns - m5stack_core2 - mimxrt595_evk_cm33 + - nrf9131ek_nrf9131 + - nrf9131ek_nrf9131_ns From 84bfb4a63b13a5062c7a9bd3fc458a4d97d224e5 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Thu, 14 Sep 2023 13:03:43 +0200 Subject: [PATCH 0004/1049] boards: arm: nrf9161dk: remove scratch partition This patch removes the now unused scratch partition and enlarges the application slots instead. Signed-off-by: Maximilian Deubel --- .../arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_common.dtsi | 8 ++------ .../nrf9161dk_nrf9161_partition_conf.dtsi | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_common.dtsi b/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_common.dtsi index a6aeccf34b99d51..8168a8317e417e7 100644 --- a/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_common.dtsi +++ b/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_common.dtsi @@ -230,16 +230,12 @@ arduino_spi: &spi3 { slot0_ns_partition: partition@50000 { label = "image-0-nonsecure"; }; - slot1_partition: partition@80000 { + slot1_partition: partition@85000 { label = "image-1"; }; - slot1_ns_partition: partition@c0000 { + slot1_ns_partition: partition@c5000 { label = "image-1-nonsecure"; }; - scratch_partition: partition@f0000 { - label = "image-scratch"; - reg = <0x000f0000 0xa000>; - }; storage_partition: partition@fa000 { label = "storage"; reg = <0x000fa000 0x00006000>; diff --git a/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_partition_conf.dtsi b/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_partition_conf.dtsi index 80b4c5f6b3abf36..9e378cb94e060aa 100644 --- a/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_partition_conf.dtsi +++ b/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_partition_conf.dtsi @@ -26,15 +26,15 @@ }; &slot0_ns_partition { - reg = <0x00050000 0x30000>; + reg = <0x00050000 0x35000>; }; &slot1_partition { - reg = <0x00080000 0x40000>; + reg = <0x00085000 0x40000>; }; &slot1_ns_partition { - reg = <0x000c0000 0x30000>; + reg = <0x000c5000 0x35000>; }; /* Default SRAM planning when building for nRF9161 with From 13ca0dc806426aefed6efec1180f5a5e358bd196 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 13 Oct 2023 12:04:57 +0200 Subject: [PATCH 0005/1049] drivers: adc: stm32: refactor calibration Refactor calibration code in anticipation of PM addition. Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 281 +++++++++++++++++++++------------------- 1 file changed, 147 insertions(+), 134 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 53562734bd0dc39..a4f0d585b477562 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -341,6 +341,52 @@ static int check_buffer(const struct adc_sequence *sequence, return 0; } +/* + * Enable ADC peripheral, and wait until ready if required by SOC. + */ +static int adc_stm32_enable(ADC_TypeDef *adc) +{ + if (LL_ADC_IsEnabled(adc) == 1UL) { + return 0; + } + +#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) + LL_ADC_ClearFlag_ADRDY(adc); + LL_ADC_Enable(adc); + + /* + * Enabling ADC modules in many series may fail if they are + * still not stabilized, this will wait for a short time (about 1ms) + * to ensure ADC modules are properly enabled. + */ + uint32_t count_timeout = 0; + + while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) { +#ifdef CONFIG_SOC_SERIES_STM32F0X + /* For F0, continue to write ADEN=1 until ADRDY=1 */ + if (LL_ADC_IsEnabled(adc) == 0UL) { + LL_ADC_Enable(adc); + } +#endif /* CONFIG_SOC_SERIES_STM32F0X */ + count_timeout++; + k_busy_wait(100); + if (count_timeout >= 10) { + return -ETIMEDOUT; + } + } +#else + /* + * On STM32F1, F2, F37x, F4, F7 and L1, do not re-enable the ADC. + * On F1 and F37x if ADON holds 1 (LL_ADC_IsEnabled is true) and 1 is + * written, then conversion starts. That's not what is expected. + */ + LL_ADC_Enable(adc); +#endif + + return 0; +} + static void adc_stm32_start_conversion(const struct device *dev) { const struct adc_stm32_cfg *config = dev->config; @@ -356,6 +402,53 @@ static void adc_stm32_start_conversion(const struct device *dev) #endif } +/* + * Disable ADC peripheral, and wait until it is disabled + */ +static void adc_stm32_disable(ADC_TypeDef *adc) +{ + if (LL_ADC_IsEnabled(adc) != 1UL) { + return; + } + + /* Stop ongoing conversion if any + * Software must poll ADSTART (or JADSTART) until the bit is reset before assuming + * the ADC is completely stopped. + */ + +#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) + if (LL_ADC_REG_IsConversionOngoing(adc)) { + LL_ADC_REG_StopConversion(adc); + while (LL_ADC_REG_IsConversionOngoing(adc)) { + } + } +#endif + +#if !defined(CONFIG_SOC_SERIES_STM32C0X) && \ + !defined(CONFIG_SOC_SERIES_STM32F0X) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) && \ + !defined(CONFIG_SOC_SERIES_STM32G0X) && \ + !defined(CONFIG_SOC_SERIES_STM32L0X) && \ + !defined(CONFIG_SOC_SERIES_STM32WBAX) && \ + !defined(CONFIG_SOC_SERIES_STM32WLX) + if (LL_ADC_INJ_IsConversionOngoing(adc)) { + LL_ADC_INJ_StopConversion(adc); + while (LL_ADC_INJ_IsConversionOngoing(adc)) { + } + } +#endif + + LL_ADC_Disable(adc); + + /* Wait ADC is fully disabled so that we don't leave the driver into intermediate state + * which could prevent enabling the peripheral + */ + while (LL_ADC_IsEnabled(adc) == 1UL) { + } +} + #if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) #define HAS_CALIBRATION @@ -369,7 +462,7 @@ static void adc_stm32_start_conversion(const struct device *dev) #define ADC_DELAY_CALIB_ADC_CYCLES LL_ADC_DELAY_DISABLE_CALIB_ADC_CYCLES #endif -static void adc_stm32_calib_delay(const struct device *dev) +static void adc_stm32_calibration_delay(const struct device *dev) { /* * Calibration of F1 and F3 (ADC1_V2_5) must start two cycles after ADON @@ -397,7 +490,7 @@ static void adc_stm32_calib_delay(const struct device *dev) } } -static void adc_stm32_calib(const struct device *dev) +static void adc_stm32_calibration_start(const struct device *dev) { const struct adc_stm32_cfg *config = (const struct adc_stm32_cfg *)dev->config; @@ -429,54 +522,60 @@ static void adc_stm32_calib(const struct device *dev) while (LL_ADC_IsCalibrationOnGoing(adc)) { } } -#endif -/* - * Disable ADC peripheral, and wait until it is disabled - */ -static void adc_stm32_disable(ADC_TypeDef *adc) +static int adc_stm32_calibrate(const struct device *dev) { - if (LL_ADC_IsEnabled(adc) != 1UL) { - return; - } - - /* Stop ongoing conversion if any - * Software must poll ADSTART (or JADSTART) until the bit is reset before assuming - * the ADC is completely stopped. - */ + const struct adc_stm32_cfg *config = + (const struct adc_stm32_cfg *)dev->config; + ADC_TypeDef *adc = config->base; + int err; -#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) - if (LL_ADC_REG_IsConversionOngoing(adc)) { - LL_ADC_REG_StopConversion(adc); - while (LL_ADC_REG_IsConversionOngoing(adc)) { - } - } -#endif +#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) + adc_stm32_disable(adc); + adc_stm32_calibration_start(dev); + adc_stm32_calibration_delay(dev); +#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ -#if !defined(CONFIG_SOC_SERIES_STM32C0X) && \ - !defined(CONFIG_SOC_SERIES_STM32F0X) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) && \ - !defined(CONFIG_SOC_SERIES_STM32G0X) && \ - !defined(CONFIG_SOC_SERIES_STM32L0X) && \ - !defined(CONFIG_SOC_SERIES_STM32WBAX) && \ - !defined(CONFIG_SOC_SERIES_STM32WLX) - if (LL_ADC_INJ_IsConversionOngoing(adc)) { - LL_ADC_INJ_StopConversion(adc); - while (LL_ADC_INJ_IsConversionOngoing(adc)) { - } + err = adc_stm32_enable(adc); + if (err < 0) { + return err; } -#endif - LL_ADC_Disable(adc); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) + adc_stm32_calibration_delay(dev); + adc_stm32_calibration_start(dev); +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ - /* Wait ADC is fully disabled so that we don't leave the driver into intermediate state - * which could prevent enabling the peripheral +#ifdef CONFIG_SOC_SERIES_STM32H7X + /* + * To ensure linearity the factory calibration values + * should be loaded on initialization. */ - while (LL_ADC_IsEnabled(adc) == 1UL) { + uint32_t channel_offset = 0U; + uint32_t linear_calib_buffer = 0U; + + if (adc == ADC1) { + channel_offset = 0UL; + } else if (adc == ADC2) { + channel_offset = 8UL; + } else /*Case ADC3*/ { + channel_offset = 16UL; } + /* Read factory calibration factors */ + for (uint32_t count = 0UL; count < ADC_LINEAR_CALIB_REG_COUNT; count++) { + linear_calib_buffer = *(uint32_t *)( + ADC_LINEAR_CALIB_REG_1_ADDR + channel_offset + count + ); + LL_ADC_SetCalibrationLinearFactor( + adc, LL_ADC_CALIB_LINEARITY_WORD1 << count, + linear_calib_buffer + ); + } +#endif /* CONFIG_SOC_SERIES_STM32H7X */ + + return 0; } +#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) */ #if !defined(CONFIG_SOC_SERIES_STM32F0X) && \ !defined(CONFIG_SOC_SERIES_STM32F1X) && \ @@ -609,52 +708,6 @@ static int adc_stm32_oversampling(ADC_TypeDef *adc, uint8_t ratio) } #endif /* CONFIG_SOC_SERIES_STM32xxx */ -/* - * Enable ADC peripheral, and wait until ready if required by SOC. - */ -static int adc_stm32_enable(ADC_TypeDef *adc) -{ - if (LL_ADC_IsEnabled(adc) == 1UL) { - return 0; - } - -#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) - LL_ADC_ClearFlag_ADRDY(adc); - LL_ADC_Enable(adc); - - /* - * Enabling ADC modules in many series may fail if they are - * still not stabilized, this will wait for a short time (about 1ms) - * to ensure ADC modules are properly enabled. - */ - uint32_t count_timeout = 0; - - while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) { -#ifdef CONFIG_SOC_SERIES_STM32F0X - /* For F0, continue to write ADEN=1 until ADRDY=1 */ - if (LL_ADC_IsEnabled(adc) == 0UL) { - LL_ADC_Enable(adc); - } -#endif /* CONFIG_SOC_SERIES_STM32F0X */ - count_timeout++; - k_busy_wait(100); - if (count_timeout >= 10) { - return -ETIMEDOUT; - } - } -#else - /* - * On STM32F1, F2, F37x, F4, F7 and L1, do not re-enable the ADC. - * On F1 and F37x if ADON holds 1 (LL_ADC_IsEnabled is true) and 1 is - * written, then conversion starts. That's not what is expected. - */ - LL_ADC_Enable(adc); -#endif - - return 0; -} - #ifdef CONFIG_ADC_STM32_DMA static void dma_callback(const struct device *dev, void *user_data, uint32_t channel, int status) @@ -899,12 +952,8 @@ static int start_read(const struct device *dev, #endif /* HAS_OVERSAMPLING */ if (sequence->calibrate) { -#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) - - /* we cannot calibrate the ADC while the ADC is enabled */ - adc_stm32_disable(adc); - adc_stm32_calib(dev); +#if defined(HAS_CALIBRATION) + adc_stm32_calibrate(dev); #else LOG_ERR("Calibration not supported"); return -ENOTSUP; @@ -1236,6 +1285,8 @@ static int adc_stm32_init(const struct device *dev) ADC_TypeDef *adc = (ADC_TypeDef *)config->base; int err; + ARG_UNUSED(adc); /* Necessary to avoid warnings on some series */ + LOG_DBG("Initializing %s", dev->name); if (!device_is_ready(clk)) { @@ -1264,6 +1315,7 @@ static int adc_stm32_init(const struct device *dev) LOG_ERR("ADC pinctrl setup failed (%d)", err); return err; } + #if defined(CONFIG_SOC_SERIES_STM32U5X) /* Enable the independent analog supply */ LL_PWR_EnableVDDA(); @@ -1306,51 +1358,12 @@ static int adc_stm32_init(const struct device *dev) k_busy_wait(LL_ADC_DELAY_INTERNAL_REGUL_STAB_US); #endif -#if defined(HAS_CALIBRATION) && !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) - adc_stm32_disable(adc); - adc_stm32_calib(dev); - adc_stm32_calib_delay(dev); -#endif /* HAS_CALIBRATION && !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ - - err = adc_stm32_enable(adc); - if (err < 0) { - return err; - } - config->irq_cfg_func(); -#if defined(HAS_CALIBRATION) && DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) - adc_stm32_calib_delay(dev); - adc_stm32_calib(dev); - LL_ADC_REG_SetTriggerSource(adc, LL_ADC_REG_TRIG_SOFTWARE); -#endif /* HAS_CALIBRATION && DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ - -#ifdef CONFIG_SOC_SERIES_STM32H7X - /* - * To ensure linearity the factory calibration values - * should be loaded on initialization. - */ - uint32_t channel_offset = 0U; - uint32_t linear_calib_buffer = 0U; +#if defined(HAS_CALIBRATION) + adc_stm32_calibrate(dev); +#endif /* HAS_CALIBRATION */ - if (adc == ADC1) { - channel_offset = 0UL; - } else if (adc == ADC2) { - channel_offset = 8UL; - } else /*Case ADC3*/ { - channel_offset = 16UL; - } - /* Read factory calibration factors */ - for (uint32_t count = 0UL; count < ADC_LINEAR_CALIB_REG_COUNT; count++) { - linear_calib_buffer = *(uint32_t *)( - ADC_LINEAR_CALIB_REG_1_ADDR + channel_offset + count - ); - LL_ADC_SetCalibrationLinearFactor( - adc, LL_ADC_CALIB_LINEARITY_WORD1 << count, - linear_calib_buffer - ); - } -#endif adc_context_unlock_unconditionally(&data->ctx); return 0; From 479ba144a7d832f46982c04d3823c058690d02ea Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 13 Oct 2023 12:08:31 +0200 Subject: [PATCH 0006/1049] drivers: adc: stm32: enable PM Enable PM for STM32 ADC. Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 89 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index a4f0d585b477562..12a38c415fda868 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #if defined(CONFIG_SOC_SERIES_STM32U5X) #include @@ -1341,12 +1342,9 @@ static int adc_stm32_init(const struct device *dev) * mode, and restore its calibration parameters if there are some * previously stored calibration parameters. */ - LL_ADC_DisableDeepPowerDown(adc); -#elif defined(CONFIG_SOC_SERIES_STM32WLX) - /* The ADC clock must be disabled by clock gating during CPU1 sleep/stop */ - LL_APB2_GRP1_DisableClockSleep(LL_APB2_GRP1_PERIPH_ADC); #endif + /* * Many ADC modules need some time to be stabilized before performing * any enable or calibration actions. @@ -1369,6 +1367,85 @@ static int adc_stm32_init(const struct device *dev) return 0; } +#ifdef CONFIG_PM_DEVICE +static int adc_stm32_suspend_setup(const struct device *dev) +{ + const struct adc_stm32_cfg *config = dev->config; + ADC_TypeDef *adc = (ADC_TypeDef *)config->base; + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + int err; + + /* Disable ADC */ + adc_stm32_disable(adc); + +#if !defined(CONFIG_SOC_SERIES_STM32F0X) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) + /* Disable ADC internal voltage regulator */ + LL_ADC_DisableInternalRegulator(adc); + while (LL_ADC_IsInternalRegulatorEnabled(adc) == 1U) { + } +#endif + +#if defined(CONFIG_SOC_SERIES_STM32L4X) || \ + defined(CONFIG_SOC_SERIES_STM32L5X) || \ + defined(CONFIG_SOC_SERIES_STM32WBX) || \ + defined(CONFIG_SOC_SERIES_STM32G4X) || \ + defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_SOC_SERIES_STM32H7X) || \ + defined(CONFIG_SOC_SERIES_STM32U5X) + /* + * L4, WB, G4, H5, H7 and U5 series STM32 needs to be put into + * deep sleep mode. + */ + + LL_ADC_EnableDeepPowerDown(adc); +#endif + +#if defined(CONFIG_SOC_SERIES_STM32U5X) + /* Disable the independent analog supply */ + LL_PWR_DisableVDDA(); +#endif /* CONFIG_SOC_SERIES_STM32U5X */ + + /* Stop device clock. Note: fixed clocks are not handled yet. */ + err = clock_control_off(clk, (clock_control_subsys_t)&config->pclken[0]); + if (err != 0) { + LOG_ERR("Could not disable ADC clock"); + return err; + } + + /* Move pins to sleep state */ + err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); + if ((err < 0) && (err != -ENOENT)) { + /* + * If returning -ENOENT, no pins where defined for sleep mode : + * Do not output on console (might sleep already) when going to sleep, + * "ADC pinctrl sleep state not available" + * and don't block PM suspend. + * Else return the error. + */ + return err; + } + + return 0; +} + +static int adc_stm32_pm_action(const struct device *dev, + enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_RESUME: + return adc_stm32_init(dev); + case PM_DEVICE_ACTION_SUSPEND: + return adc_stm32_suspend_setup(dev); + default: + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ + static const struct adc_driver_api api_stm32_driver_api = { .channel_setup = adc_stm32_channel_setup, .read = adc_stm32_read, @@ -1531,8 +1608,10 @@ static struct adc_stm32_data adc_stm32_data_##index = { \ ADC_DMA_CHANNEL(index, dmamux, NULL, PERIPHERAL, MEMORY) \ }; \ \ +PM_DEVICE_DT_INST_DEFINE(index, adc_stm32_pm_action); \ + \ DEVICE_DT_INST_DEFINE(index, \ - &adc_stm32_init, NULL, \ + &adc_stm32_init, PM_DEVICE_DT_INST_GET(index), \ &adc_stm32_data_##index, &adc_stm32_cfg_##index, \ POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ &api_stm32_driver_api); From 2caf720c51c459864636ba2fd43d08fb78acbe74 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 20 Oct 2023 11:10:22 +0200 Subject: [PATCH 0007/1049] samples: board: stm32 pm: add adc power management sample Add a sample for STM32 ADC power management Signed-off-by: Guillaume Gautier --- .../stm32/power_mgmt/adc/CMakeLists.txt | 7 ++ .../boards/stm32/power_mgmt/adc/README.rst | 42 ++++++++ .../adc/boards/nucleo_g474re.overlay | 27 ++++++ .../adc/boards/nucleo_wb55rg.overlay | 26 +++++ .../adc/boards/nucleo_wba52cg.overlay | 12 +++ samples/boards/stm32/power_mgmt/adc/prj.conf | 6 ++ .../boards/stm32/power_mgmt/adc/sample.yaml | 17 ++++ .../boards/stm32/power_mgmt/adc/src/main.c | 97 +++++++++++++++++++ 8 files changed, 234 insertions(+) create mode 100644 samples/boards/stm32/power_mgmt/adc/CMakeLists.txt create mode 100644 samples/boards/stm32/power_mgmt/adc/README.rst create mode 100644 samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay create mode 100644 samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay create mode 100644 samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay create mode 100644 samples/boards/stm32/power_mgmt/adc/prj.conf create mode 100644 samples/boards/stm32/power_mgmt/adc/sample.yaml create mode 100644 samples/boards/stm32/power_mgmt/adc/src/main.c diff --git a/samples/boards/stm32/power_mgmt/adc/CMakeLists.txt b/samples/boards/stm32/power_mgmt/adc/CMakeLists.txt new file mode 100644 index 000000000000000..b0eea852bf52b75 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(stm32_pm_adc) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/stm32/power_mgmt/adc/README.rst b/samples/boards/stm32/power_mgmt/adc/README.rst new file mode 100644 index 000000000000000..2ec694884fadf5c --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/README.rst @@ -0,0 +1,42 @@ +.. _stm32-pm-adc-sample: + +STM32 PM ADC +############ + +Overview +******** + +This sample is a minimum application to demonstrate basic power management +behavior in a basic ADC set up in low power context. + +.. _stm32-pm-adc-sample-requirements: + +Requirements +************ + +The board should support enabling PM. For a STM32 based target, it means that +it should support a clock source alternative to Cortex Systick that can be used +in core sleep states, as LPTIM (:dtcompatible:`st,stm32-lptim`). + +Building and Running +******************** + +Build and flash as follows, changing ``nucleo_wb55rg`` for your board: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/stm32/power_mgmt/adc + :board: nucleo_wb55rg + :goals: build flash + :compact: + +After flashing, the console shows the ADC measurement in the form: +``ADC reading[0]:`` +``- adc@50040000, channel 3: 1158 = 932 mV`` + +PM configurations +***************** + +By default, :kconfig:option:`CONFIG_PM_DEVICE` and :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME` are +enabled. +On STM32WB, we can observe a power consumption of about 25µA with both kconfig +enabled, 27.5µA without (each time with :kconfig:option:`CONFIG_PM` enabled). diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay new file mode 100644 index 000000000000000..bde07e0f2d621f4 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 1>; + }; +}; + +&adc1 { + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay new file mode 100644 index 000000000000000..6a39f681c454ea2 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 3>; + }; +}; + +&adc1 { + pinctrl-0 = <&adc1_in3_pc2>; + #address-cells = <1>; + #size-cells = <0>; + + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay new file mode 100644 index 000000000000000..3cd6cb64bf5a697 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc4 8>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/adc/prj.conf b/samples/boards/stm32/power_mgmt/adc/prj.conf new file mode 100644 index 000000000000000..c5359fe02387d41 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/prj.conf @@ -0,0 +1,6 @@ +CONFIG_PM=y +CONFIG_PM_DEVICE=y +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_ADC=y +#CONFIG_DEBUG=y diff --git a/samples/boards/stm32/power_mgmt/adc/sample.yaml b/samples/boards/stm32/power_mgmt/adc/sample.yaml new file mode 100644 index 000000000000000..e27cc5b268da14d --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/sample.yaml @@ -0,0 +1,17 @@ +sample: + name: STM32 ADC Power Management +tests: + sample.boards.stm32.power_mgmt.adc: + tags: + - ADC + - power + harness: console + harness_config: + type: one_line + regex: + - "Device ready" + filter: dt_compat_enabled("zephyr,power-state") and + dt_compat_enabled("st,stm32-adc") and + dt_compat_enabled("st,stm32-lptim") + extra_args: "CONFIG_DEBUG=y" + platform_allow: nucleo_wb55rg diff --git a/samples/boards/stm32/power_mgmt/adc/src/main.c b/samples/boards/stm32/power_mgmt/adc/src/main.c new file mode 100644 index 000000000000000..b75ab4a9af2ce70 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/src/main.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define SLEEP_TIME_MS 2000 + +#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \ + !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels) +#error "No suitable devicetree overlay specified" +#endif + +#define DT_SPEC_AND_COMMA(node_id, prop, idx) \ + ADC_DT_SPEC_GET_BY_IDX(node_id, idx), + +/* Data of ADC io-channels specified in devicetree. */ +static const struct adc_dt_spec adc_channels[] = { + DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, + DT_SPEC_AND_COMMA) +}; + +int main(void) +{ + int err; + uint32_t count = 0; + uint16_t buf; + struct adc_sequence sequence = { + .buffer = &buf, + /* buffer size in bytes, not number of samples */ + .buffer_size = sizeof(buf), + }; + + /* Configure channels individually prior to sampling. */ + for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) { + if (!adc_is_ready_dt(&adc_channels[i])) { + printk("ADC controller device %s not ready\n", adc_channels[i].dev->name); + return 0; + } + + err = adc_channel_setup_dt(&adc_channels[i]); + if (err < 0) { + printk("Could not setup channel #%d (%d)\n", i, err); + return 0; + } + } + + printk("Device ready\n"); + + while (true) { + printk("ADC reading[%u]:\n", count++); + for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) { + int32_t val_mv; + + printk("- %s, channel %d: ", + adc_channels[i].dev->name, + adc_channels[i].channel_id); + + (void)adc_sequence_init_dt(&adc_channels[i], &sequence); + + err = adc_read_dt(&adc_channels[i], &sequence); + if (err < 0) { + printk("Could not read (%d)\n", err); + continue; + } + + /* + * If using differential mode, the 16 bit value + * in the ADC sample buffer should be a signed 2's + * complement value. + */ + if (adc_channels[i].channel_cfg.differential) { + val_mv = (int32_t)((int16_t)buf); + } else { + val_mv = (int32_t)buf; + } + printk("%"PRId32, val_mv); + err = adc_raw_to_millivolts_dt(&adc_channels[i], + &val_mv); + /* conversion to mV may not be supported, skip if not */ + if (err < 0) { + printk(" (value in mV not available)\n"); + } else { + printk(" = %"PRId32" mV\n", val_mv); + } + } + + k_msleep(SLEEP_TIME_MS); + } + return 0; +} From bda3b101d321fd3e087485c085d7f3336b5a7e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sat, 4 Nov 2023 09:08:15 +0700 Subject: [PATCH 0008/1049] serial: nxp_s32: use instance-based DT macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At present, many of the NXP S32 shim drivers do not make use of devicetree instance-based macros because the NXP S32 HAL relies on an index-based approach, requiring knowledge of the peripheral instance index during both compilation and runtime, and this index might not align with the devicetree instance index. The proposed solution in this patch eliminates this limitation by determining the peripheral instance index during compilation through macrobatics and defining the driver's ISR within the shim driver itself. Note that for some peripheral instances is needed to redefine the HAL macros of the peripheral base address, since the naming is not uniform for all instances. Signed-off-by: Manuel Argüelles --- drivers/serial/uart_nxp_s32_linflexd.c | 313 +++++++------------------ drivers/serial/uart_nxp_s32_linflexd.h | 10 +- soc/arm/nxp_s32/s32ze/soc.h | 3 + 3 files changed, 88 insertions(+), 238 deletions(-) diff --git a/drivers/serial/uart_nxp_s32_linflexd.c b/drivers/serial/uart_nxp_s32_linflexd.c index fe1c6c51f8659c8..aeb8925da9f5d44 100644 --- a/drivers/serial/uart_nxp_s32_linflexd.c +++ b/drivers/serial/uart_nxp_s32_linflexd.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_linflexd + #include #include #include @@ -243,45 +245,54 @@ static void uart_nxp_s32_irq_callback_set(const struct device *dev, data->cb_data = cb_data; } -/** - * @brief Interrupt service routine. - * - * This simply calls the callback function, if one exists. - * - * Note: s32 UART Tx interrupts when ready to send; Rx interrupts when char - * received. - * - * @param arg Argument to ISR. - * - * @return N/A - */ - void uart_nxp_s32_isr(const struct device *dev) { + const struct uart_nxp_s32_config *config = dev->config; + + Linflexd_Uart_Ip_IRQHandler(config->instance); +} + +static void uart_nxp_s32_event_handler(const uint8 instance, + Linflexd_Uart_Ip_EventType event, + void *user_data) +{ + const struct device *dev = (const struct device *)user_data; + const struct uart_nxp_s32_config *config = dev->config; struct uart_nxp_s32_data *data = dev->data; + struct uart_nxp_s32_int *int_data = &(data->int_data); + Linflexd_Uart_Ip_StatusType status; - if (data->callback) { - data->callback(dev, data->cb_data); + if (event == LINFLEXD_UART_IP_EVENT_END_TRANSFER) { + /* + * Check the previous UART transmit has finished + * because Rx may also trigger this event + */ + status = Linflexd_Uart_Ip_GetTransmitStatus(config->instance, NULL); + if (status != LINFLEXD_UART_IP_STATUS_BUSY) { + int_data->tx_fifo_busy = false; + if (data->callback) { + data->callback(dev, data->cb_data); + } + } + } else if (event == LINFLEXD_UART_IP_EVENT_RX_FULL) { + int_data->rx_fifo_busy = false; + if (data->callback) { + data->callback(dev, data->cb_data); + } + } else if (event == LINFLEXD_UART_IP_EVENT_ERROR) { + if (data->callback) { + data->callback(dev, data->cb_data); + } + } else { + /* Other events are not used */ } } + #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ -/** - * @brief Initialize UART channel - * - * This routine is called to reset the chip in a quiescent state. - * It is assumed that this function is called only once per UART. - * - * @param dev UART device struct - * - * @return 0 - */ static int uart_nxp_s32_init(const struct device *dev) { const struct uart_nxp_s32_config *config = dev->config; - struct uart_nxp_s32_data *data = dev->data; - static uint8_t state_idx; - uint8_t key; int err; err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); @@ -289,24 +300,7 @@ static int uart_nxp_s32_init(const struct device *dev) return err; } - key = irq_lock(); - - /* Initialize UART with default configuration */ - data->hw_cfg.BaudRate = 115200; - data->hw_cfg.BaudRateMantissa = 26U; - data->hw_cfg.BaudRateFractionalDivisor = 1U; - data->hw_cfg.ParityCheck = false; - data->hw_cfg.ParityType = LINFLEXD_UART_IP_PARITY_EVEN; - data->hw_cfg.StopBitsCount = LINFLEXD_UART_IP_ONE_STOP_BIT; - data->hw_cfg.WordLength = LINFLEXD_UART_IP_8_BITS; - data->hw_cfg.TransferType = LINFLEXD_UART_IP_USING_INTERRUPTS; - data->hw_cfg.Callback = s32_uart_callback; - data->hw_cfg.CallbackParam = NULL; - data->hw_cfg.StateStruct = &Linflexd_Uart_Ip_apStateStructure[state_idx++]; - - Linflexd_Uart_Ip_Init(config->instance, &data->hw_cfg); - - irq_unlock(key); + Linflexd_Uart_Ip_Init(config->instance, &config->hw_cfg); return 0; } @@ -334,207 +328,62 @@ static const struct uart_driver_api uart_nxp_s32_driver_api = { }; -#define UART_NXP_S32_NODE(n) DT_NODELABEL(uart##n) - -#if defined(CONFIG_UART_INTERRUPT_DRIVEN) -#define UART_NXP_S32_INTERRUPT_DEFINE(n, isr_handler, parameter) \ - do { \ - IRQ_CONNECT(DT_IRQN(UART_NXP_S32_NODE(n)), \ - DT_IRQ(UART_NXP_S32_NODE(n), priority), \ - isr_handler, \ - parameter, \ - DT_IRQ(UART_NXP_S32_NODE(n), flags)); \ - \ - irq_enable(DT_IRQN(UART_NXP_S32_NODE(n))); \ +#define UART_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_LINFLEX_##i##_BASE) ? i : 0) + +#define UART_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET LINFLEXD_INSTANCE_COUNT, UART_NXP_S32_HW_INSTANCE_CHECK, (|), n) + +#define UART_NXP_S32_INTERRUPT_DEFINE(n) \ + do { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + uart_nxp_s32_isr, DEVICE_DT_INST_GET(n), \ + DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ } while (0) -#else -#define UART_NXP_S32_INTERRUPT_DEFINE(n, isr_handler, parameter) -#endif +#define UART_NXP_S32_HW_CONFIG(n) \ + { \ + .BaudRate = 115200, \ + .BaudRateMantissa = 26U, \ + .BaudRateFractionalDivisor = 1U, \ + .ParityCheck = false, \ + .ParityType = LINFLEXD_UART_IP_PARITY_EVEN, \ + .StopBitsCount = LINFLEXD_UART_IP_ONE_STOP_BIT, \ + .WordLength = LINFLEXD_UART_IP_8_BITS, \ + .TransferType = LINFLEXD_UART_IP_USING_INTERRUPTS, \ + .StateStruct = &Linflexd_Uart_Ip_apStateStructure[n], \ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, ( \ + .Callback = uart_nxp_s32_event_handler, \ + .CallbackParam = (void *)DEVICE_DT_INST_GET(n), \ + )) \ + } #define UART_NXP_S32_INIT_DEVICE(n) \ - PINCTRL_DT_DEFINE(UART_NXP_S32_NODE(n)); \ - static struct uart_nxp_s32_data uart_nxp_s32_data_##n; \ + PINCTRL_DT_INST_DEFINE(n); \ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ + (static struct uart_nxp_s32_data uart_nxp_s32_data_##n;)) \ static const struct uart_nxp_s32_config uart_nxp_s32_config_##n = { \ - .instance = n, \ - .base = (LINFLEXD_Type *)DT_REG_ADDR(UART_NXP_S32_NODE(n)), \ - .pincfg = PINCTRL_DT_DEV_CONFIG_GET(UART_NXP_S32_NODE(n)), \ + .instance = UART_NXP_S32_HW_INSTANCE(n), \ + .base = (LINFLEXD_Type *)DT_INST_REG_ADDR(n), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .hw_cfg = UART_NXP_S32_HW_CONFIG(n), \ }; \ static int uart_nxp_s32_init_##n(const struct device *dev) \ { \ - UART_NXP_S32_INTERRUPT_DEFINE(n, Linflexd_Uart_Ip_IRQHandler, n);\ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ + (UART_NXP_S32_INTERRUPT_DEFINE(n);)) \ \ return uart_nxp_s32_init(dev); \ } \ - DEVICE_DT_DEFINE(UART_NXP_S32_NODE(n), \ + DEVICE_DT_INST_DEFINE(n, \ &uart_nxp_s32_init_##n, \ NULL, \ - &uart_nxp_s32_data_##n, \ + COND_CODE_1(CONFIG_UART_INTERRUPT_DRIVEN, \ + (&uart_nxp_s32_data_##n), (NULL)), \ &uart_nxp_s32_config_##n, \ PRE_KERNEL_1, \ CONFIG_SERIAL_INIT_PRIORITY, \ &uart_nxp_s32_driver_api); -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(0), okay) -UART_NXP_S32_INIT_DEVICE(0) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(1), okay) -UART_NXP_S32_INIT_DEVICE(1) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(2), okay) -UART_NXP_S32_INIT_DEVICE(2) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(3), okay) -UART_NXP_S32_INIT_DEVICE(3) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(4), okay) -UART_NXP_S32_INIT_DEVICE(4) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(5), okay) -UART_NXP_S32_INIT_DEVICE(5) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(6), okay) -UART_NXP_S32_INIT_DEVICE(6) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(7), okay) -UART_NXP_S32_INIT_DEVICE(7) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(8), okay) -UART_NXP_S32_INIT_DEVICE(8) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(9), okay) -UART_NXP_S32_INIT_DEVICE(9) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(10), okay) -UART_NXP_S32_INIT_DEVICE(10) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(11), okay) -UART_NXP_S32_INIT_DEVICE(11) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(12), okay) -UART_NXP_S32_INIT_DEVICE(12) -#endif - -#ifdef CONFIG_UART_INTERRUPT_DRIVEN -static void s32_uart_device_event(const struct device *dev, Linflexd_Uart_Ip_EventType event, - void *user_data) -{ - const struct uart_nxp_s32_config *config = dev->config; - struct uart_nxp_s32_data *data = dev->data; - struct uart_nxp_s32_int *int_data = &(data->int_data); - Linflexd_Uart_Ip_StatusType status; - - ARG_UNUSED(user_data); - - if (event == LINFLEXD_UART_IP_EVENT_END_TRANSFER) { - /* - * Check the previous UART transmit has finished - * because Rx may also trigger this event - */ - status = Linflexd_Uart_Ip_GetTransmitStatus(config->instance, NULL); - if (status != LINFLEXD_UART_IP_STATUS_BUSY) { - int_data->tx_fifo_busy = false; - uart_nxp_s32_isr(dev); - } - } else if (event == LINFLEXD_UART_IP_EVENT_RX_FULL) { - int_data->rx_fifo_busy = false; - uart_nxp_s32_isr(dev); - } else if (event == LINFLEXD_UART_IP_EVENT_ERROR) { - uart_nxp_s32_isr(dev); - } else { - /* Other events are not used */ - } -} - -void s32_uart_callback(const uint8 instance, Linflexd_Uart_Ip_EventType event, void *user_data) -{ - const struct device *dev; - - switch (instance) { -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(0), okay) - case 0: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(0)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(1), okay) - case 1: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(1)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(2), okay) - case 2: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(2)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(3), okay) - case 3: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(3)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(4), okay) - case 4: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(4)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(5), okay) - case 5: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(5)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(6), okay) - case 6: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(6)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(7), okay) - case 7: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(7)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(8), okay) - case 8: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(8)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(9), okay) - case 9: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(9)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(10), okay) - case 10: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(10)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(11), okay) - case 11: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(11)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(12), okay) - case 12: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(12)); - break; -#endif - default: - dev = NULL; - break; - } - - if (dev != NULL) { - s32_uart_device_event(dev, event, user_data); - } -} -#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +DT_INST_FOREACH_STATUS_OKAY(UART_NXP_S32_INIT_DEVICE) diff --git a/drivers/serial/uart_nxp_s32_linflexd.h b/drivers/serial/uart_nxp_s32_linflexd.h index ce5180c26c190f2..997cd1e9112cfdb 100644 --- a/drivers/serial/uart_nxp_s32_linflexd.h +++ b/drivers/serial/uart_nxp_s32_linflexd.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ struct uart_nxp_s32_config { uint32_t instance; LINFLEXD_Type *base; const struct pinctrl_dev_config *pincfg; + Linflexd_Uart_Ip_UserConfigType hw_cfg; }; #ifdef CONFIG_UART_INTERRUPT_DRIVEN @@ -23,16 +24,13 @@ struct uart_nxp_s32_int { }; #endif -struct uart_nxp_s32_data { - Linflexd_Uart_Ip_UserConfigType hw_cfg; - #ifdef CONFIG_UART_INTERRUPT_DRIVEN +struct uart_nxp_s32_data { struct uart_nxp_s32_int int_data; uart_irq_callback_user_data_t callback; void *cb_data; -#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ - }; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ extern Linflexd_Uart_Ip_StateStructureType Linflexd_Uart_Ip_apStateStructure[LINFLEXD_UART_IP_NUMBER_OF_INSTANCES]; diff --git a/soc/arm/nxp_s32/s32ze/soc.h b/soc/arm/nxp_s32/s32ze/soc.h index cc13dfcc6aab608..cdee74ad54c4fe9 100644 --- a/soc/arm/nxp_s32/s32ze/soc.h +++ b/soc/arm/nxp_s32/s32ze/soc.h @@ -15,4 +15,7 @@ /* SIUL2 */ #define IP_SIUL2_2_BASE 0U /* instance does not exist on this SoC */ +/* LINFlexD*/ +#define IP_LINFLEX_12_BASE IP_MSC_0_LIN_BASE + #endif /* _NXP_S32_S32ZE_SOC_H_ */ From 8816852c2cf0f74c17ce0ede8a402bec823d35e1 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 26 Oct 2023 19:40:59 +0100 Subject: [PATCH 0009/1049] doc: dts: api: update the inter-node dependencies documentation Update the inter-node dependencies documentation to clarify the child node dependency inheritance recently introduced in 403640b75e. Signed-off-by: Fabio Baltieri --- doc/build/dts/api/api.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/build/dts/api/api.rst b/doc/build/dts/api/api.rst index 7d802838041d3ee..f452d0f52812ebb 100644 --- a/doc/build/dts/api/api.rst +++ b/doc/build/dts/api/api.rst @@ -140,6 +140,7 @@ depends on" relation: - a node directly depends on any nodes its properties refer to by phandle - a node directly depends on its ``interrupt-parent`` if it has an ``interrupts`` property +- a parent node inherits all dependencies from its child nodes A *dependency ordering* of a devicetree is a list of its nodes, where each node ``n`` appears earlier in the list than any nodes that depend on ``n``. A node's From d2c101d466f5260e68054e6fd37c16fd19291833 Mon Sep 17 00:00:00 2001 From: Alexander Razinkov Date: Fri, 27 Oct 2023 18:33:15 +0300 Subject: [PATCH 0010/1049] kernel: init: conditional .bss section zeroing Some platforms already have .bss section zeroed-out externally before the Zephyr initialization and there is no sence to zero it out the second time from the SW. Such boot-time optimization could be critical e.g. for RTL Simulation. Signed-off-by: Alexander Razinkov --- arch/Kconfig | 2 ++ kernel/Kconfig | 10 ++++++++++ kernel/init.c | 7 +------ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 65b73557f7b678d..0a108702ad96217 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -139,6 +139,8 @@ config ARCH_POSIX select NATIVE_BUILD select HAS_COVERAGE_SUPPORT select BARRIER_OPERATIONS_BUILTIN + # native_posix gets its memory cleared on entry by the host OS + select SKIP_BSS_CLEAR help POSIX (native) architecture diff --git a/kernel/Kconfig b/kernel/Kconfig index 4cdd62092647cbc..6280e80a400b4be 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -382,6 +382,16 @@ config INIT_STACKS water mark can be easily determined. This applies to the stack areas for threads, as well as to the interrupt stack. +config SKIP_BSS_CLEAR + bool + help + This option disables software .bss section zeroing during Zephyr + initialization. Such boot-time optimization could be used for + platforms where .bss section is zeroed-out externally. + Please pay attention that when this option is enabled + the responsibility for .bss zeroing in all possible scenarios + (mind e.g. SW reset) is delegated to the external SW or HW. + config BOOT_BANNER bool "Boot banner" default y diff --git a/kernel/init.c b/kernel/init.c index c2109499a078fbc..e4637d3aff19aef 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -165,12 +165,7 @@ void __weak z_early_memcpy(void *dst, const void *src, size_t n) __boot_func void z_bss_zero(void) { - if (IS_ENABLED(CONFIG_ARCH_POSIX)) { - /* native_posix gets its memory cleared on entry by - * the host OS, and in any case the host clang/lld - * doesn't emit the __bss_end symbol this code expects - * to see - */ + if (IS_ENABLED(CONFIG_SKIP_BSS_CLEAR)) { return; } From 9bdff044f06ed7062d171b54f223649724b592ce Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Mon, 30 Oct 2023 20:35:32 +0100 Subject: [PATCH 0011/1049] drivers: mfd: add AD5592 MFD driver This commit introduces a driver for Analog AD5592 8-channel, configurable ADC/DAC/GPIO chip. Signed-off-by: Bartosz Bilas --- CODEOWNERS | 1 + drivers/mfd/CMakeLists.txt | 1 + drivers/mfd/Kconfig | 1 + drivers/mfd/Kconfig.ad5592 | 10 ++ drivers/mfd/mfd_ad5592.c | 169 ++++++++++++++++++++++++++++ dts/bindings/mfd/adi,ad5592.yaml | 13 +++ include/zephyr/drivers/mfd/ad5592.h | 91 +++++++++++++++ 7 files changed, 286 insertions(+) create mode 100644 drivers/mfd/Kconfig.ad5592 create mode 100644 drivers/mfd/mfd_ad5592.c create mode 100644 dts/bindings/mfd/adi,ad5592.yaml create mode 100644 include/zephyr/drivers/mfd/ad5592.h diff --git a/CODEOWNERS b/CODEOWNERS index 8172acd9c902318..335e9191c6e3e72 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -373,6 +373,7 @@ /drivers/led_strip/ @mbolivar-ampere /drivers/lora/ @Mani-Sadhasivam /drivers/mbox/ @carlocaione +/drivers/mfd/mfd_ad5592.c @bbilas /drivers/mfd/mfd_max20335.c @bbilas /drivers/misc/ @tejlmand /drivers/misc/ft8xx/ @hubertmis diff --git a/drivers/mfd/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index 7c5e048fcc6181b..5141a86c2eeb744 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -8,3 +8,4 @@ zephyr_library_sources_ifdef(CONFIG_MFD_NCT38XX mfd_nct38xx.c) zephyr_library_sources_ifdef(CONFIG_MFD_NPM1300 mfd_npm1300.c) zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c) zephyr_library_sources_ifdef(CONFIG_MFD_AXP192 mfd_axp192.c) +zephyr_library_sources_ifdef(CONFIG_MFD_AD5592 mfd_ad5592.c) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1a80cf446f5f16f..1a400d6383edc6c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -18,6 +18,7 @@ config MFD_INIT_PRIORITY help Multi-function devices initialization priority. +source "drivers/mfd/Kconfig.ad5592" source "drivers/mfd/Kconfig.axp192" source "drivers/mfd/Kconfig.max20335" source "drivers/mfd/Kconfig.nct38xx" diff --git a/drivers/mfd/Kconfig.ad5592 b/drivers/mfd/Kconfig.ad5592 new file mode 100644 index 000000000000000..8b94f5517cb3377 --- /dev/null +++ b/drivers/mfd/Kconfig.ad5592 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +config MFD_AD5592 + bool "Analog AD5592 SPI configurable ADC/DAC/GPIO chip" + default y + depends on DT_HAS_ADI_AD5592_ENABLED + depends on SPI + help + Enable driver for Analog AD5592. diff --git a/drivers/mfd/mfd_ad5592.c b/drivers/mfd/mfd_ad5592.c new file mode 100644 index 000000000000000..d8f8f60de39a04d --- /dev/null +++ b/drivers/mfd/mfd_ad5592.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad5592 + +#include +#include +#include +#include + +#include + +#define AD5592_GPIO_READBACK_EN BIT(10) +#define AD5592_LDAC_READBACK_EN BIT(6) +#define AD5592_REG_SOFTWARE_RESET 0x0FU +#define AD5592_SOFTWARE_RESET_MAGIC_VAL 0xDAC +#define AD5592_REV_VAL_MASK 0x3FF +#define AD5592_REG_SHIFT_VAL 11 +#define AD5592_REG_READBACK_SHIFT_VAL 2 + +#define AD5592_SPI_SPEC_CONF (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | \ + SPI_OP_MODE_MASTER | SPI_MODE_CPOL) + +struct mfd_ad5592_config { + struct gpio_dt_spec reset_gpio; + struct spi_dt_spec bus; +}; + +int mfd_ad5592_read_raw(const struct device *dev, uint16_t *val) +{ + const struct mfd_ad5592_config *config = dev->config; + uint16_t nop_msg = 0; + + struct spi_buf tx_buf[] = { + { + .buf = &nop_msg, + .len = sizeof(nop_msg) + } + }; + + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = 1 + }; + + struct spi_buf rx_buf[] = { + { + .buf = val, + .len = sizeof(uint16_t) + } + }; + + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = 1 + }; + + return spi_transceive_dt(&config->bus, &tx, &rx); +} + +int mfd_ad5592_write_raw(const struct device *dev, uint16_t val) +{ + const struct mfd_ad5592_config *config = dev->config; + + struct spi_buf tx_buf[] = { + { + .buf = &val, + .len = sizeof(val) + } + }; + + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = 1 + }; + + return spi_write_dt(&config->bus, &tx); +} + +int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val) +{ + uint16_t data; + uint16_t msg; + int ret; + + switch (reg) { + case AD5592_REG_GPIO_INPUT_EN: + msg = sys_cpu_to_be16(AD5592_GPIO_READBACK_EN | + (AD5592_REG_GPIO_INPUT_EN << AD5592_REG_SHIFT_VAL) | + reg_data); + break; + default: + msg = sys_cpu_to_be16(AD5592_LDAC_READBACK_EN | + (AD5592_REG_READ_AND_LDAC << AD5592_REG_SHIFT_VAL) | + reg << AD5592_REG_READBACK_SHIFT_VAL); + break; + } + + ret = mfd_ad5592_write_raw(dev, msg); + if (ret < 0) { + return ret; + } + + ret = mfd_ad5592_read_raw(dev, &data); + if (ret < 0) { + return ret; + } + + *val = sys_be16_to_cpu(data); + + return 0; +} + +int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val) +{ + uint16_t msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & AD5592_REV_VAL_MASK)); + + return mfd_ad5592_write_raw(dev, msg); +} + +static int mfd_add592_software_reset(const struct device *dev) +{ + return mfd_ad5592_write_reg(dev, + AD5592_REG_SOFTWARE_RESET, + AD5592_SOFTWARE_RESET_MAGIC_VAL); +} + +static int mfd_ad5592_init(const struct device *dev) +{ + const struct mfd_ad5592_config *config = dev->config; + int ret; + + if (!spi_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + if (!gpio_is_ready_dt(&config->reset_gpio)) { + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + return ret; + } + + ret = mfd_add592_software_reset(dev); + if (ret < 0) { + return ret; + } + + return 0; +} + +#define MFD_AD5592_DEFINE(inst) \ + static const struct mfd_ad5592_config mfd_ad5592_config_##inst = { \ + .reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \ + .bus = SPI_DT_SPEC_INST_GET(inst, AD5592_SPI_SPEC_CONF, 0), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mfd_ad5592_init, NULL, \ + NULL, \ + &mfd_ad5592_config_##inst, \ + POST_KERNEL, \ + CONFIG_MFD_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(MFD_AD5592_DEFINE); diff --git a/dts/bindings/mfd/adi,ad5592.yaml b/dts/bindings/mfd/adi,ad5592.yaml new file mode 100644 index 000000000000000..d3e404ec1433f06 --- /dev/null +++ b/dts/bindings/mfd/adi,ad5592.yaml @@ -0,0 +1,13 @@ +# Copyright (C) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +description: Analog AD5592 ADC/DAC/GPIO chip + +compatible: "adi,ad5592" + +include: spi-device.yaml + +properties: + reset-gpios: + type: phandle-array + description: RESET pin diff --git a/include/zephyr/drivers/mfd/ad5592.h b/include/zephyr/drivers/mfd/ad5592.h new file mode 100644 index 000000000000000..014ccdd02baf86b --- /dev/null +++ b/include/zephyr/drivers/mfd/ad5592.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_AD5592_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MFD_AD5592_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define AD5592_REG_SEQ_ADC 0x02U +#define AD5592_REG_ADC_CONFIG 0x04U +#define AD5592_REG_LDAC_EN 0x05U +#define AD5592_REG_GPIO_PULLDOWN 0x06U +#define AD5592_REG_READ_AND_LDAC 0x07U +#define AD5592_REG_GPIO_OUTPUT_EN 0x08U +#define AD5592_REG_GPIO_SET 0x09U +#define AD5592_REG_GPIO_INPUT_EN 0x0AU +#define AD5592_REG_PD_REF_CTRL 0x0BU + +#define AD5592_EN_REF BIT(9) + +#define AD5592_PIN_MAX 8U + +/** + * @defgroup mdf_interface_ad5592 MFD AD5592 interface + * @ingroup mfd_interfaces + * @{ + */ + +/** + * @brief Read raw data from the chip + * + * @param[in] dev Pointer to MFD device + * @param[in] val Pointer to data buffer + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad5592_read_raw(const struct device *dev, uint16_t *val); + +/** + * @brief Write raw data to chip + * + * @param[in] dev Pointer to MFD device + * @param[in] val Data to be written + * + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad5592_write_raw(const struct device *dev, uint16_t val); + +/** + * @brief Read data from provided register + * + * @param[in] dev Pointer to MFD device + * @param[in] reg Register to be read + * @param[in] reg_data Additional data passed to selected register + * @param[in] val Pointer to data buffer + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val); + +/** + * @brief Write data to provided register + * + * @param[in] dev Pointer to MFD device + * @param[in] reg Register to be written + * @param[in] val Data to be written + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_AD5952_H_ */ From ad3c5a27b407614cc3500074c451f88b1c3dcbc9 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Mon, 30 Oct 2023 20:38:59 +0100 Subject: [PATCH 0012/1049] drivers: adc: add driver for AD5592 Add MFD subdriver for the built-in ADC controller in AD5592 chip. Signed-off-by: Bartosz Bilas --- CODEOWNERS | 1 + drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.ad5592 | 25 +++ drivers/adc/adc_ad5592.c | 255 ++++++++++++++++++++++++ drivers/adc/adc_shell.c | 1 + dts/bindings/adc/adi,ad5592-adc.yaml | 15 ++ tests/drivers/build_all/adc/app.overlay | 50 +++++ tests/drivers/build_all/adc/prj.conf | 1 + 9 files changed, 351 insertions(+) create mode 100644 drivers/adc/Kconfig.ad5592 create mode 100644 drivers/adc/adc_ad5592.c create mode 100644 dts/bindings/adc/adi,ad5592-adc.yaml create mode 100644 tests/drivers/build_all/adc/app.overlay diff --git a/CODEOWNERS b/CODEOWNERS index 335e9191c6e3e72..63fc8876a966be3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -245,6 +245,7 @@ /drivers/adc/adc_rpi_pico.c @soburi /drivers/adc/*ads114s0x* @benediktibk /drivers/adc/*max11102_17* @benediktibk +/drivers/adc/adc_ad5592.c @bbilas /drivers/audio/*nrfx* @anangl /drivers/auxdisplay/*pt6314* @xingrz /drivers/auxdisplay/* @thedjnK diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index a22af9a53365d0c..4738aaa891c922b 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -46,3 +46,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_TLA2021 adc_tla2021.c) zephyr_library_sources_ifdef(CONFIG_ADC_NXP_S32_ADC_SAR adc_nxp_s32_adc_sar.c) zephyr_library_sources_ifdef(CONFIG_ADC_MAX1125X adc_max1125x.c) zephyr_library_sources_ifdef(CONFIG_ADC_MAX11102_17 adc_max11102_17.c) +zephyr_library_sources_ifdef(CONFIG_ADC_AD5592 adc_ad5592.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 32cf7601e8df1d9..14f4d89657e4a65 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -116,4 +116,6 @@ source "drivers/adc/Kconfig.max1125x" source "drivers/adc/Kconfig.max11102_17" +source "drivers/adc/Kconfig.ad5592" + endif # ADC diff --git a/drivers/adc/Kconfig.ad5592 b/drivers/adc/Kconfig.ad5592 new file mode 100644 index 000000000000000..92b80f34217229a --- /dev/null +++ b/drivers/adc/Kconfig.ad5592 @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +config ADC_AD5592 + bool "AD5592 ADC driver" + default y + depends on DT_HAS_ADI_AD5592_ADC_ENABLED + select MFD + help + Enable the AD5592 ADC driver. + +config ADC_AD5592_ACQUISITION_THREAD_STACK_SIZE + int "Stack size for the ADC data acquisition thread" + depends on ADC_AD5592 + default 384 + help + Size of the stack used for the internal data acquisition + thread. + +config ADC_AD5592_ACQUISITION_THREAD_PRIO + int "Priority for the ADC data acquisition thread" + depends on ADC_AD5592 + default 0 + help + Priority level for the internal ADC data acquisition thread. diff --git a/drivers/adc/adc_ad5592.c b/drivers/adc/adc_ad5592.c new file mode 100644 index 000000000000000..422fd549868e6d8 --- /dev/null +++ b/drivers/adc/adc_ad5592.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad5592_adc + +#include +#include +#include + +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#include +LOG_MODULE_REGISTER(adc_ad5592, CONFIG_ADC_LOG_LEVEL); + +#define AD5592_ADC_RESOLUTION 12U +#define AD5592_ADC_MAX_VAL 4096 + +struct adc_ad5592_config { + const struct device *mfd_dev; +}; + +struct adc_ad5592_data { + struct adc_context ctx; + const struct device *dev; + uint8_t adc_conf; + uint16_t *buffer; + uint16_t *repeat_buffer; + uint8_t channels; + struct k_thread thread; + struct k_sem sem; + + K_KERNEL_STACK_MEMBER(stack, CONFIG_ADC_AD5592_ACQUISITION_THREAD_STACK_SIZE); +}; + +static int adc_ad5592_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + const struct adc_ad5592_config *config = dev->config; + struct adc_ad5592_data *data = dev->data; + + if (channel_cfg->channel_id >= AD5592_PIN_MAX) { + LOG_ERR("invalid channel id %d", channel_cfg->channel_id); + return -EINVAL; + } + + data->adc_conf |= BIT(channel_cfg->channel_id); + + return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_ADC_CONFIG, data->adc_conf); +} + +static int adc_ad5592_validate_buffer_size(const struct device *dev, + const struct adc_sequence *sequence) +{ + uint8_t channels; + size_t needed; + + channels = POPCOUNT(sequence->channels); + needed = channels * sizeof(uint16_t); + + if (sequence->buffer_size < needed) { + return -ENOMEM; + } + + return 0; +} + +static int adc_ad5592_start_read(const struct device *dev, const struct adc_sequence *sequence) +{ + struct adc_ad5592_data *data = dev->data; + int ret; + + if (sequence->resolution != AD5592_ADC_RESOLUTION) { + LOG_ERR("invalid resolution %d", sequence->resolution); + return -EINVAL; + } + + if (find_msb_set(sequence->channels) > AD5592_PIN_MAX) { + LOG_ERR("invalid channels in mask: 0x%08x", sequence->channels); + return -EINVAL; + } + + ret = adc_ad5592_validate_buffer_size(dev, sequence); + if (ret < 0) { + LOG_ERR("insufficient buffer size"); + return ret; + } + + data->buffer = sequence->buffer; + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +static int adc_ad5592_read_channel(const struct device *dev, uint8_t channel, uint16_t *result) +{ + const struct adc_ad5592_config *config = dev->config; + uint16_t val; + int ret; + + ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_SEQ_ADC, BIT(channel)); + if (ret < 0) { + return ret; + } + + /* + * Invalid data: + * See Figure 46. Single-Channel ADC Conversion Sequence. + * The first conversion result always returns invalid data. + */ + (void) mfd_ad5592_read_raw(config->mfd_dev, &val); + + ret = mfd_ad5592_read_raw(config->mfd_dev, &val); + if (ret < 0) { + return ret; + } + + val = sys_be16_to_cpu(val); + if (channel >= 1) { + val -= channel * AD5592_ADC_MAX_VAL; + } + + *result = val; + + return 0; +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_ad5592_data *data = CONTAINER_OF(ctx, struct adc_ad5592_data, ctx); + + data->channels = ctx->sequence.channels; + data->repeat_buffer = data->buffer; + + k_sem_give(&data->sem); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct adc_ad5592_data *data = CONTAINER_OF(ctx, struct adc_ad5592_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static void adc_ad5592_acquisition_thread(struct adc_ad5592_data *data) +{ + uint16_t result; + uint8_t channel; + int ret; + + while (true) { + k_sem_take(&data->sem, K_FOREVER); + + while (data->channels != 0) { + channel = find_lsb_set(data->channels) - 1; + + ret = adc_ad5592_read_channel(data->dev, channel, &result); + if (ret < 0) { + LOG_ERR("failed to read channel %d (ret %d)", channel, ret); + adc_context_complete(&data->ctx, ret); + break; + } + + *data->buffer++ = result; + WRITE_BIT(data->channels, channel, 0); + } + + adc_context_on_sampling_done(&data->ctx, data->dev); + } +} + +static int adc_ad5592_read_async(const struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_ad5592_data *data = dev->data; + int ret; + + adc_context_lock(&data->ctx, async ? true : false, async); + ret = adc_ad5592_start_read(dev, sequence); + adc_context_release(&data->ctx, ret); + + return ret; +} + +static int adc_ad5592_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + return adc_ad5592_read_async(dev, sequence, NULL); +} + +static int adc_ad5592_init(const struct device *dev) +{ + const struct adc_ad5592_config *config = dev->config; + struct adc_ad5592_data *data = dev->data; + k_tid_t tid; + int ret; + + if (!device_is_ready(config->mfd_dev)) { + return -ENODEV; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_PD_REF_CTRL, AD5592_EN_REF); + if (ret < 0) { + return ret; + } + + data->dev = dev; + + k_sem_init(&data->sem, 0, 1); + adc_context_init(&data->ctx); + + tid = k_thread_create(&data->thread, data->stack, + CONFIG_ADC_AD5592_ACQUISITION_THREAD_STACK_SIZE, + (k_thread_entry_t)adc_ad5592_acquisition_thread, data, NULL, NULL, + CONFIG_ADC_AD5592_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); + + ret = k_thread_name_set(tid, "adc_ad5592"); + if (ret < 0) { + return ret; + } + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +static const struct adc_driver_api adc_ad5592_api = { + .channel_setup = adc_ad5592_channel_setup, + .read = adc_ad5592_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_ad5592_read_async, +#endif +}; + +#define ADC_AD5592_DEFINE(inst) \ + static const struct adc_ad5592_config adc_ad5592_config##inst = { \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + struct adc_ad5592_data adc_ad5592_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, adc_ad5592_init, NULL, \ + &adc_ad5592_data##inst, &adc_ad5592_config##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &adc_ad5592_api); + +DT_INST_FOREACH_STATUS_OKAY(ADC_AD5592_DEFINE) diff --git a/drivers/adc/adc_shell.c b/drivers/adc/adc_shell.c index 2069b97b5ece31d..81b0d0d3d2f0620 100644 --- a/drivers/adc/adc_shell.c +++ b/drivers/adc/adc_shell.c @@ -104,6 +104,7 @@ static struct adc_hdl { DT_FOREACH_STATUS_OKAY(maxim_max11115, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(maxim_max11116, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(maxim_max11117, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(adi_ad5592_adc, ADC_HDL_LIST_ENTRY) }; static struct adc_hdl *get_adc(const char *device_label) diff --git a/dts/bindings/adc/adi,ad5592-adc.yaml b/dts/bindings/adc/adi,ad5592-adc.yaml new file mode 100644 index 000000000000000..2432b55d25a68c3 --- /dev/null +++ b/dts/bindings/adc/adi,ad5592-adc.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +description: AD5592 ADC Controller + +compatible: "adi,ad5592-adc" + +include: adc-controller.yaml + +properties: + "#io-channel-cells": + const: 1 + +io-channel-cells: + - input diff --git a/tests/drivers/build_all/adc/app.overlay b/tests/drivers/build_all/adc/app.overlay new file mode 100644 index 000000000000000..82634f87df474bf --- /dev/null +++ b/tests/drivers/build_all/adc/app.overlay @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Grinn + * + * SPDX-License-Identifier: Apache-2.0 + * + * Application overlay for testing driver builds + * + * Names in this file should be chosen in a way that won't conflict + * with real-world devicetree nodes, to allow these tests to run on + * (and be extended to test) real hardware. + */ + +/ { + test { + #address-cells = <1>; + #size-cells = <1>; + + test_gpio: gpio@deadbeef { + compatible = "vnd,gpio"; + gpio-controller; + reg = <0xdeadbeef 0x1000>; + #gpio-cells = <0x2>; + status = "okay"; + }; + + test_spi: spi@33334444 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,spi"; + reg = <0x33334444 0x1000>; + status = "okay"; + clock-frequency = <2000000>; + + cs-gpios = <&test_gpio 0 0>; + + test_spi_ad5592: ad5592@0 { + compatible = "adi,ad5592"; + status = "okay"; + reg = <0x0>; + spi-max-frequency = <0>; + reset-gpios = <&test_gpio 0 0>; + + ad5592_adc: adc-controller { + compatible = "adi,ad5592-adc"; + #io-channel-cells = <1>; + }; + }; + }; + }; +}; diff --git a/tests/drivers/build_all/adc/prj.conf b/tests/drivers/build_all/adc/prj.conf index c5d1cb3b04f812f..cdf8b3151685dfe 100644 --- a/tests/drivers/build_all/adc/prj.conf +++ b/tests/drivers/build_all/adc/prj.conf @@ -4,3 +4,4 @@ CONFIG_ADC=y CONFIG_MAX_THREAD_BYTES=4 CONFIG_ADC_INIT_PRIORITY=80 CONFIG_KOBJECT_RODATA_AREA_EXTRA_BYTES=256 +CONFIG_SPI=y From 0689d3dc1145fea9c872571bbba8b102db026fbc Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Mon, 30 Oct 2023 20:43:46 +0100 Subject: [PATCH 0013/1049] drivers: gpio: add driver for AD5592 Add MFD subdriver for the built-in GPIO controller in AD5592 chip. Signed-off-by: Bartosz Bilas --- CODEOWNERS | 1 + drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.ad5592 | 10 + drivers/gpio/gpio_ad5592.c | 227 +++++++++++++++++++++++ dts/bindings/gpio/adi,ad5592-gpio.yaml | 12 ++ tests/drivers/build_all/gpio/app.overlay | 21 ++- 7 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 drivers/gpio/Kconfig.ad5592 create mode 100644 drivers/gpio/gpio_ad5592.c create mode 100644 dts/bindings/gpio/adi,ad5592-gpio.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 63fc8876a966be3..3314e8c26b41c2b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -330,6 +330,7 @@ /drivers/gpio/*bd8lb600fs* @benediktibk /drivers/gpio/*pcal64xxa* @benediktibk /drivers/gpio/gpio_altera_pio.c @shilinte +/drivers/gpio/gpio_ad5592.c @bbilas /drivers/hwinfo/ @alexanderwachter /drivers/i2c/i2c_common.c @sjg20 /drivers/i2c/i2c_emul.c @sjg20 diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index e82a815fcce4149..19c9d3e976cb0d8 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/gpio.h) zephyr_library() +zephyr_library_sources_ifdef(CONFIG_GPIO_AD5592 gpio_ad5592.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AXP192 gpio_axp192.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c) zephyr_library_sources_ifdef(CONFIG_GPIO_INFINEON_CAT1 gpio_ifx_cat1.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index fc09ef2994dbd1d..92d7b0587e9e78a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -69,6 +69,8 @@ config GPIO_ENABLE_DISABLE_INTERRUPT pending register, etc. The driver must implement it to work. +source "drivers/gpio/Kconfig.ad5592" + source "drivers/gpio/Kconfig.axp192" source "drivers/gpio/Kconfig.b91" diff --git a/drivers/gpio/Kconfig.ad5592 b/drivers/gpio/Kconfig.ad5592 new file mode 100644 index 000000000000000..c2654d1857bdea8 --- /dev/null +++ b/drivers/gpio/Kconfig.ad5592 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_AD5592 + bool "AD5592 GPIO driver" + default y + depends on DT_HAS_ADI_AD5592_GPIO_ENABLED + select MFD + help + Enable the AD5592 GPIO driver. diff --git a/drivers/gpio/gpio_ad5592.c b/drivers/gpio/gpio_ad5592.c new file mode 100644 index 000000000000000..a8b30ddcee4d063 --- /dev/null +++ b/drivers/gpio/gpio_ad5592.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad5592_gpio + +#include +#include +#include +#include + +#include + +struct gpio_ad5592_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + const struct device *mfd_dev; +}; + +struct gpio_ad5592_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + uint8_t gpio_val; + uint8_t gpio_out; + uint8_t gpio_in; + uint8_t gpio_pull_down; +}; + +static int gpio_ad5592_port_get_raw(const struct device *dev, uint32_t *value) +{ + const struct gpio_ad5592_config *config = dev->config; + struct gpio_ad5592_data *drv_data = dev->data; + uint16_t data; + int ret; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + ret = mfd_ad5592_read_reg(config->mfd_dev, + AD5592_REG_GPIO_INPUT_EN, drv_data->gpio_in, &data); + if (ret < 0) { + return ret; + } + + *value = (uint32_t)data; + + return 0; +} + +static int gpio_ad5592_port_set_bits_raw(const struct device *dev, + gpio_port_pins_t pins) +{ + struct gpio_ad5592_data *data = dev->data; + const struct gpio_ad5592_config *config = dev->config; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + data->gpio_val |= (uint8_t)pins; + + return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_GPIO_SET, data->gpio_val); +} + +static int gpio_ad5592_port_clear_bits_raw(const struct device *dev, + gpio_port_pins_t pins) +{ + struct gpio_ad5592_data *data = dev->data; + const struct gpio_ad5592_config *config = dev->config; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + data->gpio_val &= ~(uint8_t)pins; + + return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_GPIO_SET, data->gpio_val); +} + +static inline int gpio_ad5592_configure(const struct device *dev, + gpio_pin_t pin, gpio_flags_t flags) +{ + struct gpio_ad5592_data *data = dev->data; + const struct gpio_ad5592_config *config = dev->config; + uint8_t val; + int ret; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + if (pin >= AD5592_PIN_MAX) { + return -EINVAL; + } + + val = BIT(pin); + if ((flags & GPIO_OUTPUT) != 0U) { + data->gpio_in &= ~val; + data->gpio_out |= val; + + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { + ret = gpio_ad5592_port_set_bits_raw( + dev, (gpio_port_pins_t)BIT(pin)); + if (ret < 0) { + return ret; + } + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) { + ret = gpio_ad5592_port_clear_bits_raw( + dev, (gpio_port_pins_t)BIT(pin)); + if (ret < 0) { + return ret; + } + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_OUTPUT_EN, data->gpio_out); + if (ret < 0) { + return ret; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_INPUT_EN, data->gpio_in); + } else if ((flags & GPIO_INPUT) != 0U) { + data->gpio_in |= val; + data->gpio_out &= ~val; + + if ((flags & GPIO_PULL_DOWN) != 0U) { + data->gpio_pull_down |= val; + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_PULLDOWN, + data->gpio_pull_down); + if (ret < 0) { + return ret; + } + } else if ((flags & GPIO_PULL_UP) != 0U) { + return -ENOTSUP; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_OUTPUT_EN, data->gpio_out); + if (ret < 0) { + return ret; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_INPUT_EN, data->gpio_in); + } else { + return -ENOTSUP; + } + + return ret; +} + +static int gpio_ad5592_port_set_masked_raw(const struct device *dev, + gpio_port_pins_t mask, + gpio_port_value_t value) +{ + ARG_UNUSED(dev); + ARG_UNUSED(mask); + ARG_UNUSED(value); + + return -ENOTSUP; +} + +static int gpio_ad5592_port_toggle_bits(const struct device *dev, + gpio_port_pins_t pins) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pins); + + return -ENOTSUP; +} + +static int gpio_ad5592_pin_interrupt_configure(const struct device *dev, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pin); + ARG_UNUSED(mode); + ARG_UNUSED(trig); + + return -ENOTSUP; +} + +static const struct gpio_driver_api gpio_ad5592_api = { + .pin_configure = gpio_ad5592_configure, + .port_get_raw = gpio_ad5592_port_get_raw, + .port_set_masked_raw = gpio_ad5592_port_set_masked_raw, + .port_set_bits_raw = gpio_ad5592_port_set_bits_raw, + .port_clear_bits_raw = gpio_ad5592_port_clear_bits_raw, + .port_toggle_bits = gpio_ad5592_port_toggle_bits, + .pin_interrupt_configure = gpio_ad5592_pin_interrupt_configure, +}; + +static int gpio_ad5592_init(const struct device *dev) +{ + const struct gpio_ad5592_config *config = dev->config; + + if (!device_is_ready(config->mfd_dev)) { + return -ENODEV; + } + + return 0; +} + +#define GPIO_AD5592_DEFINE(inst) \ + static const struct gpio_ad5592_config gpio_ad5592_config##inst = { \ + .common = { \ + .port_pin_mask = \ + GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \ + }, \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + static struct gpio_ad5592_data gpio_ad5592_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, gpio_ad5592_init, NULL, \ + &gpio_ad5592_data##inst, &gpio_ad5592_config##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &gpio_ad5592_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_AD5592_DEFINE) diff --git a/dts/bindings/gpio/adi,ad5592-gpio.yaml b/dts/bindings/gpio/adi,ad5592-gpio.yaml new file mode 100644 index 000000000000000..b815f557c51877e --- /dev/null +++ b/dts/bindings/gpio/adi,ad5592-gpio.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +description: AD5592 GPIO Controller + +compatible: "adi,ad5592-gpio" + +include: gpio-controller.yaml + +gpio-cells: + - pin + - flags diff --git a/tests/drivers/build_all/gpio/app.overlay b/tests/drivers/build_all/gpio/app.overlay index b6a315cedfa3e61..715480a94f0ac81 100644 --- a/tests/drivers/build_all/gpio/app.overlay +++ b/tests/drivers/build_all/gpio/app.overlay @@ -210,7 +210,11 @@ clock-frequency = <2000000>; /* one entry for every devices at spi.dtsi */ - cs-gpios = <&test_gpio 0 0 &test_gpio 0 0 &test_gpio 0 0>; + cs-gpios = <&test_gpio 0 0 + &test_gpio 0 0 + &test_gpio 0 0 + &test_gpio 0 0 + &test_gpio 0 0>; test_spi_mcp23s17: mcp23s17@0 { compatible = "microchip,mcp23s17"; @@ -259,6 +263,21 @@ #gpio-cells = <2>; }; }; + + test_spi_ad5592: ad5592@4 { + compatible = "adi,ad5592"; + status = "okay"; + reg = <0x04>; + spi-max-frequency = <0>; + reset-gpios = <&test_gpio 0 0>; + + ad5592_gpio: gpio-controller { + compatible = "adi,ad5592-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + }; }; }; }; From 2c09999d247824cbcdf23b0bd84c2f1bef040a6f Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Mon, 30 Oct 2023 20:44:27 +0100 Subject: [PATCH 0014/1049] drivers: dac: add driver for AD5592 Add MFD subdriver for the built-in DAC controller in AD5592 chip. Signed-off-by: Bartosz Bilas --- CODEOWNERS | 1 + drivers/dac/CMakeLists.txt | 1 + drivers/dac/Kconfig | 2 + drivers/dac/Kconfig.ad5592 | 10 +++ drivers/dac/dac_ad5592.c | 107 ++++++++++++++++++++++++ dts/bindings/dac/adi,ad5592-dac.yaml | 15 ++++ tests/drivers/build_all/dac/app.overlay | 14 ++++ 7 files changed, 150 insertions(+) create mode 100644 drivers/dac/Kconfig.ad5592 create mode 100644 drivers/dac/dac_ad5592.c create mode 100644 dts/bindings/dac/adi,ad5592-dac.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 3314e8c26b41c2b..f339c8958fee913 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -275,6 +275,7 @@ /drivers/display/display_ili9342c.* @extremegtx /drivers/dac/ @martinjaeger /drivers/dac/*ad56xx* @benediktibk +/drivers/dac/dac_ad5592.c @bbilas /drivers/dai/ @kv2019i @marcinszkudlinski @abonislawski /drivers/dai/intel/ @kv2019i @marcinszkudlinski @abonislawski /drivers/dai/intel/ssp/ @kv2019i @marcinszkudlinski @abonislawski diff --git a/drivers/dac/CMakeLists.txt b/drivers/dac/CMakeLists.txt index d2164f92d7ebda1..c84b0d9d78e5662 100644 --- a/drivers/dac/CMakeLists.txt +++ b/drivers/dac/CMakeLists.txt @@ -18,5 +18,6 @@ zephyr_library_sources_ifdef(CONFIG_DAC_MCP4725 dac_mcp4725.c) zephyr_library_sources_ifdef(CONFIG_DAC_MCP4728 dac_mcp4728.c) zephyr_library_sources_ifdef(CONFIG_DAC_GD32 dac_gd32.c) zephyr_library_sources_ifdef(CONFIG_DAC_ESP32 dac_esp32.c) +zephyr_library_sources_ifdef(CONFIG_DAC_AD5592 dac_ad5592.c) zephyr_library_sources_ifdef(CONFIG_DAC_AD56XX dac_ad56xx.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE dac_handlers.c) diff --git a/drivers/dac/Kconfig b/drivers/dac/Kconfig index 6449032fa4822e9..553d9f05355d9d9 100644 --- a/drivers/dac/Kconfig +++ b/drivers/dac/Kconfig @@ -54,4 +54,6 @@ source "drivers/dac/Kconfig.esp32" source "drivers/dac/Kconfig.ad56xx" +source "drivers/dac/Kconfig.ad5592" + endif # DAC diff --git a/drivers/dac/Kconfig.ad5592 b/drivers/dac/Kconfig.ad5592 new file mode 100644 index 000000000000000..1010992fb7fad3e --- /dev/null +++ b/drivers/dac/Kconfig.ad5592 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +config DAC_AD5592 + bool "AD5592 DAC driver" + default y + depends on DT_HAS_ADI_AD5592_DAC_ENABLED + select MFD + help + Enable the AD5592 DAC driver. diff --git a/drivers/dac/dac_ad5592.c b/drivers/dac/dac_ad5592.c new file mode 100644 index 000000000000000..653df85dd566a1f --- /dev/null +++ b/drivers/dac/dac_ad5592.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad5592_dac + +#include +#include +#include + +#include + +#include +LOG_MODULE_REGISTER(dac_ad5592, CONFIG_DAC_LOG_LEVEL); + +#define AD5592_DAC_RESOLUTION 12 +#define AD5592_DAC_WR_MSB_BIT BIT(15) +#define AD5592_DAC_CHANNEL_SHIFT_VAL 12 + +struct dac_ad5592_config { + const struct device *mfd_dev; +}; + +struct dac_ad5592_data { + uint8_t dac_conf; +}; + +static int dac_ad5592_channel_setup(const struct device *dev, + const struct dac_channel_cfg *channel_cfg) +{ + const struct dac_ad5592_config *config = dev->config; + struct dac_ad5592_data *data = dev->data; + + if (channel_cfg->channel_id >= AD5592_PIN_MAX) { + LOG_ERR("Invalid channel number %d", channel_cfg->channel_id); + return -EINVAL; + } + + if (channel_cfg->resolution != AD5592_DAC_RESOLUTION) { + LOG_ERR("Invalid resolution %d", channel_cfg->resolution); + return -EINVAL; + } + + data->dac_conf |= BIT(channel_cfg->channel_id); + + return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_LDAC_EN, data->dac_conf); +} + +static int dac_ad5592_write_value(const struct device *dev, uint8_t channel, + uint32_t value) +{ + const struct dac_ad5592_config *config = dev->config; + uint16_t msg; + + if (channel >= AD5592_PIN_MAX) { + LOG_ERR("Invalid channel number %d", channel); + return -EINVAL; + } + + if (value >= (1 << AD5592_DAC_RESOLUTION)) { + LOG_ERR("Value %d out of range", value); + return -EINVAL; + } + + msg = sys_cpu_to_be16(AD5592_DAC_WR_MSB_BIT | + channel << AD5592_DAC_CHANNEL_SHIFT_VAL | + value); + + return mfd_ad5592_write_raw(config->mfd_dev, msg); +} + +static const struct dac_driver_api dac_ad5592_api = { + .channel_setup = dac_ad5592_channel_setup, + .write_value = dac_ad5592_write_value, +}; + +static int dac_ad5592_init(const struct device *dev) +{ + const struct dac_ad5592_config *config = dev->config; + int ret; + + if (!device_is_ready(config->mfd_dev)) { + return -ENODEV; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_PD_REF_CTRL, AD5592_EN_REF); + if (ret < 0) { + return ret; + } + + return 0; +} + +#define DAC_AD5592_DEFINE(inst) \ + static const struct dac_ad5592_config dac_ad5592_config##inst = { \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + struct dac_ad5592_data dac_ad5592_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, dac_ad5592_init, NULL, \ + &dac_ad5592_data##inst, &dac_ad5592_config##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &dac_ad5592_api); + +DT_INST_FOREACH_STATUS_OKAY(DAC_AD5592_DEFINE) diff --git a/dts/bindings/dac/adi,ad5592-dac.yaml b/dts/bindings/dac/adi,ad5592-dac.yaml new file mode 100644 index 000000000000000..3ac8087b91da562 --- /dev/null +++ b/dts/bindings/dac/adi,ad5592-dac.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +description: AD5592 DAC Controller + +compatible: "adi,ad5592-dac" + +include: dac-controller.yaml + +properties: + "#io-channel-cells": + const: 1 + +io-channel-cells: + - output diff --git a/tests/drivers/build_all/dac/app.overlay b/tests/drivers/build_all/dac/app.overlay index 40218f7949df03b..ee82a5e8b86bf07 100644 --- a/tests/drivers/build_all/dac/app.overlay +++ b/tests/drivers/build_all/dac/app.overlay @@ -82,6 +82,7 @@ <&test_gpio 0 0>, <&test_gpio 0 0>, <&test_gpio 0 0>, + <&test_gpio 0 0>, <&test_gpio 0 0>; test_spi_dac60508: dac60508@0 { @@ -233,6 +234,19 @@ #io-channel-cells = <1>; reset-gpios = <&test_gpio 0 0>; }; + + test_spi_ad5592: ad5592@10 { + compatible = "adi,ad5592"; + status = "okay"; + reg = <0x10>; + spi-max-frequency = <0>; + reset-gpios = <&test_gpio 0 0>; + + ad5592_dac: dac-controller { + compatible = "adi,ad5592-dac"; + #io-channel-cells = <1>; + }; + }; }; }; }; From 79c9f17320c43a718d0dc2745f4869a86726d243 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Wed, 1 Nov 2023 15:29:22 -0500 Subject: [PATCH 0015/1049] samples: llext shell_loader reduced size Reduce the heap and stack sizes needed for the shell loader sample app so more devices may try it out. Tried on a mimxrt1010_evk and noted the total ram usage was approximately 44000 bytes. Prior to this change the mimxrt1010_evk was unable to run the sample as the bss section overflowed the ram size. Signed-off-by: Tom Burdick --- samples/subsys/llext/shell_loader/prj.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/subsys/llext/shell_loader/prj.conf b/samples/subsys/llext/shell_loader/prj.conf index 678e5eb55ae28be..0e0d38fdcf45e14 100644 --- a/samples/subsys/llext/shell_loader/prj.conf +++ b/samples/subsys/llext/shell_loader/prj.conf @@ -2,11 +2,11 @@ CONFIG_LOG=y CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_SHELL=y -CONFIG_SHELL_CMD_BUFF_SIZE=32768 +CONFIG_SHELL_CMD_BUFF_SIZE=8192 CONFIG_SHELL_LOG_LEVEL_INF=y -CONFIG_SHELL_STACK_SIZE=8192 +CONFIG_SHELL_STACK_SIZE=4096 CONFIG_LLEXT=y CONFIG_LLEXT_LOG_LEVEL_DBG=y -CONFIG_LLEXT_HEAP_SIZE=32 +CONFIG_LLEXT_HEAP_SIZE=8 CONFIG_LLEXT_SHELL=y From 6d651e37a32354161ceccf9ff22d7e643464a08d Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Wed, 1 Nov 2023 15:33:24 -0500 Subject: [PATCH 0016/1049] llext: Track module memory usage The memory usage shown in the shell was 0 which is obviously incorrect. At some point the memory allocation tracking was dropped from llext.c mistakenly. Add it back. Signed-off-by: Tom Burdick --- subsys/llext/llext.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index b94d6ae1183f781..9e3cbd79990f2bc 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -252,6 +252,7 @@ static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, if (!ext->mem[mem_idx]) { return -ENOMEM; } + ext->mem_size += ldr->sects[sect_idx].sh_size; ret = llext_seek(ldr, ldr->sects[sect_idx].sh_offset); if (ret != 0) { @@ -347,11 +348,13 @@ static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) static inline int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) { int ret = 0; + size_t syms_size = ldr->sym_cnt * sizeof(struct llext_symbol); - ext->sym_tab.syms = k_heap_alloc(&llext_heap, ldr->sym_cnt * sizeof(struct llext_symbol), + ext->sym_tab.syms = k_heap_alloc(&llext_heap, syms_size, K_NO_WAIT); ext->sym_tab.sym_cnt = ldr->sym_cnt; memset(ext->sym_tab.syms, 0, ldr->sym_cnt * sizeof(struct llext_symbol)); + ext->mem_size += syms_size; return ret; } @@ -551,6 +554,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) } memset(ldr->sect_map, 0, ldr->hdr.e_shnum*sizeof(uint32_t)); ldr->sect_cnt = ldr->hdr.e_shnum; + ext->mem_size += sect_map_sz; LOG_DBG("Finding ELF tables..."); ret = llext_find_tables(ldr); From 982cc794e3dd5db1089dc37dacfad7f3dc69e5d3 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Wed, 1 Nov 2023 15:39:54 -0500 Subject: [PATCH 0017/1049] llext: Make the shell list command output nicer Remove unnecessary newline characters from shell_print, it already adds them. Align the table pipe characters better in the list of modules. Signed-off-by: Tom Burdick --- subsys/llext/shell.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subsys/llext/shell.c b/subsys/llext/shell.c index 370fd83405f42f4..b9a4121acc609a7 100644 --- a/subsys/llext/shell.c +++ b/subsys/llext/shell.c @@ -43,9 +43,9 @@ static int cmd_llext_list_symbols(const struct shell *sh, size_t argc, char *arg } shell_print(sh, "Extension: %s symbols", m->name); - shell_print(sh, "| Symbol | Address |\n"); + shell_print(sh, "| Symbol | Address |"); for (elf_word i = 0; i < m->sym_tab.sym_cnt; i++) { - shell_print(sh, "| %16s | %p |\n", m->sym_tab.syms[i].name, + shell_print(sh, "| %16s | %p |", m->sym_tab.syms[i].name, m->sym_tab.syms[i].addr); } @@ -84,10 +84,10 @@ static int cmd_llext_list(const struct shell *sh, size_t argc, char *argv[]) sys_snode_t *node; struct llext *ext; - shell_print(sh, "| Name | Size |\n"); + shell_print(sh, "| Name | Size |"); SYS_SLIST_FOR_EACH_NODE(llext_list(), node) { ext = CONTAINER_OF(node, struct llext, _llext_list); - shell_print(sh, "| %16s | %12d |\n", ext->name, ext->mem_size); + shell_print(sh, "| %16s | %12d |", ext->name, ext->mem_size); } return 0; From 2c5f5bfd0af4435cdb266f8e9f3b37838131ff2b Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Fri, 3 Nov 2023 16:17:52 -0400 Subject: [PATCH 0018/1049] samples: fs: fat_fs: support on stm32h747i-disco board This patch allow demonstrating fat_fs sample application on stm32h747i-disco board with SD card. Build fs_sample using following command west build -p always -b stm32h747i_disco_m7 \ samples/subsys/fs/fs_sample Signed-off-by: Murali Karicheri --- .../fs/fs_sample/boards/stm32h747i_disco_m7.conf | 1 + .../fs/fs_sample/boards/stm32h747i_disco_m7.overlay | 11 +++++++++++ samples/subsys/fs/fs_sample/sample.yaml | 5 +++++ 3 files changed, 17 insertions(+) create mode 100644 samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.conf create mode 100644 samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.overlay diff --git a/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.conf b/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.conf new file mode 100644 index 000000000000000..857d2e8ddfd888d --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.conf @@ -0,0 +1 @@ +CONFIG_SDMMC_STM32_HWFC=y diff --git a/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.overlay b/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.overlay new file mode 100644 index 000000000000000..d80aa5114fc39fb --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 S&C Electric Company + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&sdmmc1 { + sdmmc { + compatible = "zephyr,sdmmc-disk"; + }; +}; diff --git a/samples/subsys/fs/fs_sample/sample.yaml b/samples/subsys/fs/fs_sample/sample.yaml index e022ca1e4c164bf..375bacf4f8facb9 100644 --- a/samples/subsys/fs/fs_sample/sample.yaml +++ b/samples/subsys/fs/fs_sample/sample.yaml @@ -45,3 +45,8 @@ tests: sample.filesystem.ext2: extra_args: CONF_FILE="prj_ext.conf" platform_allow: hifive_unmatched bl5340_dvk_cpuapp + sample.filesystem.fat_fs.stm32h747i_disco_m7_sdmmc: + build_only: true + platform_allow: stm32h747i_disco_m7 + extra_args: + - OVERLAY_CONFIG=boards/stm32h747i_disco_m7.conf From f1dc11174c9dda97c142eee35a2d21bc417bc775 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Mon, 6 Nov 2023 14:08:27 +0800 Subject: [PATCH 0019/1049] ITE: drivers/i2c: Add a property for I2C located channel Add a property for I2C channel switch selection. This property will write to the SMBxxCHS register according to the I2C node you selected, which can make channel swapping. Signed-off-by: Tim Lin --- drivers/i2c/i2c_ite_enhance.c | 23 ++++++++++ drivers/i2c/i2c_ite_it8xxx2.c | 14 ++++++ dts/bindings/i2c/ite,common-i2c.yaml | 48 ++++++++++++++++++++ dts/riscv/ite/it81xx2.dtsi | 6 +++ dts/riscv/ite/it82xx2.dtsi | 6 +++ include/zephyr/dt-bindings/i2c/it8xxx2-i2c.h | 8 ++++ soc/riscv/riscv-ite/common/chip_chipregs.h | 8 ++-- 7 files changed, 109 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c_ite_enhance.c b/drivers/i2c/i2c_ite_enhance.c index 93187ff940aac46..1d26ade56c1f356 100644 --- a/drivers/i2c/i2c_ite_enhance.c +++ b/drivers/i2c/i2c_ite_enhance.c @@ -63,6 +63,7 @@ struct i2c_enhance_config { uint8_t *base; uint8_t i2c_irq_base; uint8_t port; + uint8_t channel_switch_sel; /* SCL GPIO cells */ struct gpio_dt_spec scl_gpios; /* SDA GPIO cells */ @@ -1174,6 +1175,27 @@ static int i2c_enhance_init(const struct device *dev) enhanced_i2c_set_cmd_addr_regs(dev); #endif + /* ChannelA-F switch selection of I2C pin */ + if (config->port == SMB_CHANNEL_A) { + IT8XXX2_SMB_SMB01CHS = (IT8XXX2_SMB_SMB01CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } else if (config->port == SMB_CHANNEL_B) { + IT8XXX2_SMB_SMB01CHS = (config->channel_switch_sel << 4) | + (IT8XXX2_SMB_SMB01CHS &= ~GENMASK(6, 4)); + } else if (config->port == SMB_CHANNEL_C) { + IT8XXX2_SMB_SMB23CHS = (IT8XXX2_SMB_SMB23CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } else if (config->port == I2C_CHANNEL_D) { + IT8XXX2_SMB_SMB23CHS = (config->channel_switch_sel << 4) | + (IT8XXX2_SMB_SMB23CHS &= ~GENMASK(6, 4)); + } else if (config->port == I2C_CHANNEL_E) { + IT8XXX2_SMB_SMB45CHS = (IT8XXX2_SMB_SMB45CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } else if (config->port == I2C_CHANNEL_F) { + IT8XXX2_SMB_SMB45CHS = (config->channel_switch_sel << 4) | + (IT8XXX2_SMB_SMB45CHS &= ~GENMASK(6, 4)); + } + /* Set clock frequency for I2C ports */ if (config->bitrate == I2C_BITRATE_STANDARD || config->bitrate == I2C_BITRATE_FAST || @@ -1427,6 +1449,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_I2C_TARGET_BUFFER_MODE), .bitrate = DT_INST_PROP(inst, clock_frequency), \ .i2c_irq_base = DT_INST_IRQN(inst), \ .port = DT_INST_PROP(inst, port_num), \ + .channel_switch_sel = DT_INST_PROP(inst, channel_switch_sel), \ .scl_gpios = GPIO_DT_SPEC_INST_GET(inst, scl_gpios), \ .sda_gpios = GPIO_DT_SPEC_INST_GET(inst, sda_gpios), \ .prescale_scl_low = DT_INST_PROP_OR(inst, prescale_scl_low, 0), \ diff --git a/drivers/i2c/i2c_ite_it8xxx2.c b/drivers/i2c/i2c_ite_it8xxx2.c index 2a55576ef5b7560..57f69a6aaeb2bd9 100644 --- a/drivers/i2c/i2c_ite_it8xxx2.c +++ b/drivers/i2c/i2c_ite_it8xxx2.c @@ -44,6 +44,7 @@ struct i2c_it8xxx2_config { uint8_t *reg_mstfctrl; uint8_t i2c_irq_base; uint8_t port; + uint8_t channel_switch_sel; /* SCL GPIO cells */ struct gpio_dt_spec scl_gpios; /* SDA GPIO cells */ @@ -1134,6 +1135,18 @@ static int i2c_it8xxx2_init(const struct device *dev) } #endif + /* ChannelA-C switch selection of I2C pin */ + if (config->port == SMB_CHANNEL_A) { + IT8XXX2_SMB_SMB01CHS = (IT8XXX2_SMB_SMB01CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } else if (config->port == SMB_CHANNEL_B) { + IT8XXX2_SMB_SMB01CHS = (config->channel_switch_sel << 4) | + (IT8XXX2_SMB_SMB01CHS &= ~GENMASK(6, 4)); + } else if (config->port == SMB_CHANNEL_C) { + IT8XXX2_SMB_SMB23CHS = (IT8XXX2_SMB_SMB23CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } + /* Set clock frequency for I2C ports */ if (config->bitrate == I2C_BITRATE_STANDARD || config->bitrate == I2C_BITRATE_FAST || @@ -1265,6 +1278,7 @@ BUILD_ASSERT((DT_INST_PROP(SMB_CHANNEL_C, fifo_enable) == false), .bitrate = DT_INST_PROP(inst, clock_frequency), \ .i2c_irq_base = DT_INST_IRQN(inst), \ .port = DT_INST_PROP(inst, port_num), \ + .channel_switch_sel = DT_INST_PROP(inst, channel_switch_sel), \ .scl_gpios = GPIO_DT_SPEC_INST_GET(inst, scl_gpios), \ .sda_gpios = GPIO_DT_SPEC_INST_GET(inst, sda_gpios), \ .clock_gate_offset = DT_INST_PROP(inst, clock_gate_offset), \ diff --git a/dts/bindings/i2c/ite,common-i2c.yaml b/dts/bindings/i2c/ite,common-i2c.yaml index 251903efafcc4bf..1e4e90793da162e 100644 --- a/dts/bindings/i2c/ite,common-i2c.yaml +++ b/dts/bindings/i2c/ite,common-i2c.yaml @@ -30,6 +30,54 @@ properties: 4 = I2C_CHANNEL_E, 5 = I2C_CHANNEL_F, + channel-switch-sel: + type: int + required: true + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + description: | + The default setting is as described below + 0 = I2C_CHA_LOCATE: Channel A is located at SMCLK0/SMDAT0 + 1 = I2C_CHB_LOCATE: Channel B is located at SMCLK1/SMDAT1 + 2 = I2C_CHC_LOCATE: Channel C is located at SMCLK2/SMDAT2 + 3 = I2C_CHD_LOCATE: Channel D is located at SMCLK3/SMDAT3 + 4 = I2C_CHE_LOCATE: Channel E is located at SMCLK4/SMDAT4 + 5 = I2C_CHF_LOCATE: Channel F is located at SMCLK5/SMDAT5 + + The following is an example of the 'channel-switch-sel' property + being swapped between node &i2c0 and &i2c2 in the application: + Note: The property of 'port-num' cannot be changed in the + application. + + Channel C is located at SMCLK0/SMDAT0: + &i2c0 { + channel-switch-sel = ; + pinctrl-0 = <&i2c2_clk_gpf6_default + &i2c2_data_gpf7_default>; + pinctrl-names = "default"; + scl-gpios = <&gpiof 6 0>; + sda-gpios = <&gpiof 7 0>; + }; + + Channel A is located at SMCLK2/SMDAT2: + &i2c2 { + channel-switch-sel = ; + pinctrl-0 = <&i2c0_clk_gpb3_default + &i2c0_data_gpb4_default>; + pinctrl-names = "default"; + scl-gpios = <&gpiob 3 0>; + sda-gpios = <&gpiob 4 0>; + }; + + If the property of 'channel-switch-sel' is changed, the pinctrl + setting and recovery pin in &i2c0 and &i2c2 nodes must also be + modified accordingly. + scl-gpios: type: phandle-array required: true diff --git a/dts/riscv/ite/it81xx2.dtsi b/dts/riscv/ite/it81xx2.dtsi index 939e1672bfcc160..32d47861ee7cc24 100644 --- a/dts/riscv/ite/it81xx2.dtsi +++ b/dts/riscv/ite/it81xx2.dtsi @@ -347,6 +347,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpiob 3 0>; sda-gpios = <&gpiob 4 0>; clock-gate-offset = ; @@ -363,6 +364,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioc 1 0>; sda-gpios = <&gpioc 2 0>; clock-gate-offset = ; @@ -379,6 +381,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpiof 6 0>; sda-gpios = <&gpiof 7 0>; clock-gate-offset = ; @@ -394,6 +397,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioh 1 0>; sda-gpios = <&gpioh 2 0>; clock-gate-offset = ; @@ -408,6 +412,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioe 0 0>; sda-gpios = <&gpioe 7 0>; clock-gate-offset = ; @@ -422,6 +427,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioa 4 0>; sda-gpios = <&gpioa 5 0>; clock-gate-offset = ; diff --git a/dts/riscv/ite/it82xx2.dtsi b/dts/riscv/ite/it82xx2.dtsi index 810b77f8d8a5e72..6b3eea97aa91ecb 100644 --- a/dts/riscv/ite/it82xx2.dtsi +++ b/dts/riscv/ite/it82xx2.dtsi @@ -885,6 +885,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpiob 3 0>; sda-gpios = <&gpiob 4 0>; clock-gate-offset = ; @@ -899,6 +900,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioc 1 0>; sda-gpios = <&gpioc 2 0>; clock-gate-offset = ; @@ -913,6 +915,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpiof 6 0>; sda-gpios = <&gpiof 7 0>; clock-gate-offset = ; @@ -927,6 +930,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioh 1 0>; sda-gpios = <&gpioh 2 0>; clock-gate-offset = ; @@ -941,6 +945,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioe 0 0>; sda-gpios = <&gpioe 7 0>; clock-gate-offset = ; @@ -955,6 +960,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioa 4 0>; sda-gpios = <&gpioa 5 0>; clock-gate-offset = ; diff --git a/include/zephyr/dt-bindings/i2c/it8xxx2-i2c.h b/include/zephyr/dt-bindings/i2c/it8xxx2-i2c.h index a42879d1331354f..199e813308ec5a2 100644 --- a/include/zephyr/dt-bindings/i2c/it8xxx2-i2c.h +++ b/include/zephyr/dt-bindings/i2c/it8xxx2-i2c.h @@ -20,4 +20,12 @@ #define CGC_OFFSET_SMBB ((IT8XXX2_ECPM_CGCTRL4R_OFF << 8) | 0x08) #define CGC_OFFSET_SMBA ((IT8XXX2_ECPM_CGCTRL4R_OFF << 8) | 0x04) +/* I2C channel switch selection */ +#define I2C_CHA_LOCATE 0 +#define I2C_CHB_LOCATE 1 +#define I2C_CHC_LOCATE 2 +#define I2C_CHD_LOCATE 3 +#define I2C_CHE_LOCATE 4 +#define I2C_CHF_LOCATE 5 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_I2C_IT8XXX2_H_ */ diff --git a/soc/riscv/riscv-ite/common/chip_chipregs.h b/soc/riscv/riscv-ite/common/chip_chipregs.h index 17e1fa11b7ae0f1..b1009e3eee5d7cb 100644 --- a/soc/riscv/riscv-ite/common/chip_chipregs.h +++ b/soc/riscv/riscv-ite/common/chip_chipregs.h @@ -1203,11 +1203,11 @@ enum chip_pll_mode { #define IT8XXX2_SMB_MSTFSTS1 ECREG(IT8XXX2_SMB_BASE + 0x0E) #define IT8XXX2_SMB_MSTFCTRL2 ECREG(IT8XXX2_SMB_BASE + 0x0F) #define IT8XXX2_SMB_MSTFSTS2 ECREG(IT8XXX2_SMB_BASE + 0x10) -#define IT8XXX2_SMB_CHSEF ECREG(IT8XXX2_SMB_BASE + 0x11) +#define IT8XXX2_SMB_SMB45CHS ECREG(IT8XXX2_SMB_BASE + 0x11) #define IT8XXX2_SMB_I2CW2RF ECREG(IT8XXX2_SMB_BASE + 0x12) #define IT8XXX2_SMB_IWRFISTA ECREG(IT8XXX2_SMB_BASE + 0x13) -#define IT8XXX2_SMB_CHSAB ECREG(IT8XXX2_SMB_BASE + 0x20) -#define IT8XXX2_SMB_CHSCD ECREG(IT8XXX2_SMB_BASE + 0x21) +#define IT8XXX2_SMB_SMB01CHS ECREG(IT8XXX2_SMB_BASE + 0x20) +#define IT8XXX2_SMB_SMB23CHS ECREG(IT8XXX2_SMB_BASE + 0x21) #define IT8XXX2_SMB_SFFCTL ECREG(IT8XXX2_SMB_BASE + 0x55) #define IT8XXX2_SMB_HOSTA(base) ECREG(base + 0x00) #define IT8XXX2_SMB_HOCTL(base) ECREG(base + 0x01) @@ -1223,7 +1223,7 @@ enum chip_pll_mode { #define IT8XXX2_SMB_SLVISEL ECREG(IT8XXX2_SMB_BASE + 0x08) #define IT8XXX2_SMB_SMB01CHS ECREG(IT8XXX2_SMB_BASE + 0x09) #define IT8XXX2_SMB_SMB23CHS ECREG(IT8XXX2_SMB_BASE + 0x0A) -#define IT8XXX2_SMB_SMB4CHS ECREG(IT8XXX2_SMB_BASE + 0x0B) +#define IT8XXX2_SMB_SMB45CHS ECREG(IT8XXX2_SMB_BASE + 0x0B) #define IT8XXX2_SMB_SCLKTS_BRGS ECREG(IT8XXX2_SMB_BASE + 0x80) #define IT8XXX2_SMB_SCLKTS_BRGM ECREG(IT8XXX2_SMB_BASE + 0x81) #define IT8XXX2_SMB_CHSBRG ECREG(IT8XXX2_SMB_BASE + 0x82) From 50d17a0d52410290da788a7de9a027fd28478896 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Mon, 6 Nov 2023 12:51:48 +0100 Subject: [PATCH 0020/1049] Bluetooth: Mesh: split gatt client and solicitation pdu sending The ability to send the solicitation PDU doesn't depend on GATT Client role. Commit makes independent one functionality from another. Signed-off-by: Aleksandr Khromykh --- doc/connectivity/bluetooth/api/mesh/proxy.rst | 2 +- include/zephyr/bluetooth/mesh/proxy.h | 4 ++-- subsys/bluetooth/mesh/Kconfig | 5 ++--- subsys/bluetooth/mesh/shell/shell.c | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/doc/connectivity/bluetooth/api/mesh/proxy.rst b/doc/connectivity/bluetooth/api/mesh/proxy.rst index d9212e24bc07df2..823401c9571ea1b 100644 --- a/doc/connectivity/bluetooth/api/mesh/proxy.rst +++ b/doc/connectivity/bluetooth/api/mesh/proxy.rst @@ -31,7 +31,7 @@ In the case where both GATT Proxy and Private GATT Proxy states are disabled on device cannot connect to it. A node supporting the :ref:`bluetooth_mesh_od_srv` may however be solicited to advertise connectable advertising events without enabling the Private GATT Proxy state. To solicit the node, the legacy device can send a Solicitation PDU by calling the -:func:`bt_mesh_proxy_solicit` function. To enable this feature, the client must to be compiled with +:func:`bt_mesh_proxy_solicit` function. To enable this feature, the device must to be compiled with the :kconfig:option:`CONFIG_BT_MESH_PROXY_SOLICITATION` option set. Solicitation PDUs are non-mesh, non-connectable, undirected advertising messages containing Proxy diff --git a/include/zephyr/bluetooth/mesh/proxy.h b/include/zephyr/bluetooth/mesh/proxy.h index 60a397b9484cb98..03576acf9bf945e 100644 --- a/include/zephyr/bluetooth/mesh/proxy.h +++ b/include/zephyr/bluetooth/mesh/proxy.h @@ -97,9 +97,9 @@ int bt_mesh_proxy_connect(uint16_t net_idx); */ int bt_mesh_proxy_disconnect(uint16_t net_idx); -/** @brief Schedule advertising of Solicitation PDUs on Proxy Client . +/** @brief Schedule advertising of Solicitation PDUs. * - * Once called Proxy Client will schedule advertising Solicitation PDUs for the amount of time + * Once called, the device will schedule advertising Solicitation PDUs for the amount of time * defined by @c adv_int * (@c CONFIG_BT_MESH_SOL_ADV_XMIT + 1), where @c adv_int is 20ms * for Bluetooth v5.0 or higher, or 100ms otherwise. * diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index a7155d8e5140d69..de409e9c53cb02e 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1439,11 +1439,10 @@ config BT_MESH_SOLICITATION bool config BT_MESH_PROXY_SOLICITATION - bool "Proxy solicitation feature for Proxy Client support" - depends on BT_MESH_PROXY_CLIENT + bool "Proxy solicitation feature" select BT_MESH_SOLICITATION help - This option enables support for sending Solicitation PDUs for Proxy Client. + This option enables support for sending Solicitation PDUs. config BT_MESH_SOL_ADV_XMIT int "Solicitation PDU retransmission count" diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index c5592db02cfa51f..6ee825d4c09aafc 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -387,6 +387,7 @@ static int cmd_proxy_disconnect(const struct shell *sh, size_t argc, return 0; } +#endif /* CONFIG_BT_MESH_PROXY_CLIENT */ #if defined(CONFIG_BT_MESH_PROXY_SOLICITATION) static int cmd_proxy_solicit(const struct shell *sh, size_t argc, @@ -410,7 +411,6 @@ static int cmd_proxy_solicit(const struct shell *sh, size_t argc, return err; } #endif /* CONFIG_BT_MESH_PROXY_SOLICITATION */ -#endif /* CONFIG_BT_MESH_PROXY_CLIENT */ #endif /* CONFIG_BT_MESH_SHELL_GATT_PROXY */ #if defined(CONFIG_BT_MESH_SHELL_PROV) @@ -1739,11 +1739,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(proxy_cmds, #if defined(CONFIG_BT_MESH_PROXY_CLIENT) SHELL_CMD_ARG(connect, NULL, "", cmd_proxy_connect, 2, 0), SHELL_CMD_ARG(disconnect, NULL, "", cmd_proxy_disconnect, 2, 0), +#endif #if defined(CONFIG_BT_MESH_PROXY_SOLICITATION) SHELL_CMD_ARG(solicit, NULL, "", cmd_proxy_solicit, 2, 0), -#endif #endif SHELL_SUBCMD_SET_END); #endif /* CONFIG_BT_MESH_SHELL_GATT_PROXY */ From b6f20d67c2deb5e46de30b9f7ca0101c5c8cb4aa Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Mon, 6 Nov 2023 13:40:55 +0100 Subject: [PATCH 0021/1049] Bluetooth: Mesh: fix On-Demand API usage On-Demand proxy client API has been changed but usage of this API in shell test was missed. Commit fixes this API usage. Signed-off-by: Aleksandr Khromykh --- subsys/bluetooth/mesh/shell/od_priv_proxy.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/mesh/shell/od_priv_proxy.c b/subsys/bluetooth/mesh/shell/od_priv_proxy.c index da353b9e95b7684..517fcfcaea34399 100644 --- a/subsys/bluetooth/mesh/shell/od_priv_proxy.c +++ b/subsys/bluetooth/mesh/shell/od_priv_proxy.c @@ -15,13 +15,12 @@ static int cmd_od_priv_gatt_proxy_set(const struct shell *sh, size_t argc, char *argv[]) { uint8_t val, val_rsp; + uint16_t net_idx = bt_mesh_shell_target_ctx.net_idx; + uint16_t addr = bt_mesh_shell_target_ctx.dst; int err = 0; - struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(bt_mesh_shell_target_ctx.net_idx, - bt_mesh_shell_target_ctx.dst); - if (argc < 2) { - err = bt_mesh_od_priv_proxy_cli_get(&ctx, &val_rsp); + err = bt_mesh_od_priv_proxy_cli_get(net_idx, addr, &val_rsp); } else { val = shell_strtoul(argv[1], 0, &err); @@ -30,7 +29,7 @@ static int cmd_od_priv_gatt_proxy_set(const struct shell *sh, size_t argc, return err; } - err = bt_mesh_od_priv_proxy_cli_set(&ctx, val, &val_rsp); + err = bt_mesh_od_priv_proxy_cli_set(net_idx, addr, val, &val_rsp); } if (err) { From 56816ceb526854625760106d7dad4e505f2b01d6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 7 Nov 2023 10:03:49 +0100 Subject: [PATCH 0022/1049] manifest: Update nrf hw models to latest * Update the HW models module to a715dcc179f1a71f51c574165958b72fe932ae3f Including the following: * a715dcc irq_ctrl: Fix interrupt name getter * b9e1f00 Makefile: For 5340 build both HAL versions as separate libraries * 68aa50b Makefile: Set default target to compile and fix makefiles rules * 0cf5ea9 nrfx_glue: Provide a stubbed NRFX_DELAY for builds without Zephyr * b0d95c2 doc: Update required Nordic nrfx version to 3.2 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 14907f79ef9fc6c..bde31c3303e3da2 100644 --- a/west.yml +++ b/west.yml @@ -295,7 +295,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 90f4484cbaec986ed253b4fe9649aa75e632de15 + revision: a715dcc179f1a71f51c574165958b72fe932ae3f path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 From 2a4350dfd2b27c9ca14889c81023be4d6bfa0139 Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Tue, 7 Nov 2023 10:24:36 +0100 Subject: [PATCH 0023/1049] net: openthread: Adding snoop entries kconfig. Adding missing `CONFIG_OPENTHREAD_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES` to thread kconfig file. Signed-off-by: Przemyslaw Bida --- .../platform/openthread-core-zephyr-config.h | 12 ++++++++++++ subsys/net/l2/openthread/Kconfig | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index 8d6b5e54fd0857d..881585e55789a50 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -60,6 +60,18 @@ CONFIG_OPENTHREAD_TMF_ADDRESS_CACHE_ENTRIES #endif +/** + * @def CONFIG_OPENTHREAD_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES + * + * The maximum number of EID-to-RLOC cache entries that can be used for + * "snoop optimization" where an entry is created by inspecting a received message. + * + */ +#ifdef CONFIG_OPENTHREAD_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES +#define OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES \ + CONFIG_OPENTHREAD_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES +#endif + /** * @def OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL * diff --git a/subsys/net/l2/openthread/Kconfig b/subsys/net/l2/openthread/Kconfig index f8803b316de1dba..70c7d642674a065 100644 --- a/subsys/net/l2/openthread/Kconfig +++ b/subsys/net/l2/openthread/Kconfig @@ -289,6 +289,14 @@ config OPENTHREAD_TMF_ADDRESS_CACHE_ENTRIES help The number of EID-to-RLOC cache entries. +config OPENTHREAD_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES + int "The maximum number of EID-to-RLOC cache entries" + default 2 + help + The maximum number of EID-to-RLOC cache entries that can be used for + "snoop optimization" where an entry is created by inspecting a received + message. + config OPENTHREAD_LOG_PREPEND_LEVEL_ENABLE bool "Prepending the log level to all OpenThread log messages" help From e60878e7eb9d8e37dd7334d600ff1d7a40fdf861 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 7 Nov 2023 10:58:49 +0100 Subject: [PATCH 0024/1049] nrf52_bsim: Remove nfct peripheral from DT This board HW models do not yet support the NFCT peripheral, let's remove the DT node to avoid the driver being selected. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/nrf52_bsim.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/posix/nrf_bsim/nrf52_bsim.dts b/boards/posix/nrf_bsim/nrf52_bsim.dts index 9c01240540eb7b8..a408ceb0eee3aaa 100644 --- a/boards/posix/nrf_bsim/nrf52_bsim.dts +++ b/boards/posix/nrf_bsim/nrf52_bsim.dts @@ -54,6 +54,7 @@ /delete-node/ spi@40004000; /delete-node/ spi@40023000; /delete-node/ spi@4002f000; + /delete-node/ nfct@40005000; /delete-node/ watchdog@40010000; /delete-node/ acl@4001e000; /delete-node/ usbd@40027000; From 38060ea2a009f2c807c1122f4912347928ec1803 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 7 Nov 2023 11:18:35 +0000 Subject: [PATCH 0025/1049] tests: boot: mcuboot_recovery_retention: Move USB CDC to USB device Moves the USB CDC device to the USB CDC port instead of wrongly using the serial port, this was not used but is needed to prevent a build error added to MCUboot which prevents using the same device for console and serial recovery chosen nodes Signed-off-by: Jamie McCrae --- .../boards/nrf52840dk_nrf52840.overlay | 9 +++++++++ .../boards/nrf52840dk_nrf52840_mem.overlay | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/tests/boot/mcuboot_recovery_retention/boards/nrf52840dk_nrf52840.overlay b/tests/boot/mcuboot_recovery_retention/boards/nrf52840dk_nrf52840.overlay index 2257c1a88885031..bd69d21527d93e9 100644 --- a/tests/boot/mcuboot_recovery_retention/boards/nrf52840dk_nrf52840.overlay +++ b/tests/boot/mcuboot_recovery_retention/boards/nrf52840dk_nrf52840.overlay @@ -3,6 +3,7 @@ / { chosen { zephyr,boot-mode = &boot_mode0; + zephyr,uart-mcumgr = &cdc_acm_uart; }; }; @@ -16,6 +17,14 @@ }; }; +&zephyr_udc0 { + status = "okay"; + + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + /delete-node/ &boot_partition; /delete-node/ &slot0_partition; /delete-node/ &slot1_partition; diff --git a/tests/boot/mcuboot_recovery_retention/boards/nrf52840dk_nrf52840_mem.overlay b/tests/boot/mcuboot_recovery_retention/boards/nrf52840dk_nrf52840_mem.overlay index 907b1c0cb509904..a6b9dc2e5288212 100644 --- a/tests/boot/mcuboot_recovery_retention/boards/nrf52840dk_nrf52840_mem.overlay +++ b/tests/boot/mcuboot_recovery_retention/boards/nrf52840dk_nrf52840_mem.overlay @@ -26,6 +26,15 @@ chosen { zephyr,boot-mode = &boot_mode0; + zephyr,uart-mcumgr = &cdc_acm_uart; + }; +}; + +&zephyr_udc0 { + status = "okay"; + + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; }; }; From 5d3ae7690a7d6075f4ec1594f70e2e34a9b2f136 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 7 Nov 2023 10:26:14 +0000 Subject: [PATCH 0026/1049] west.yml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: 0c0470e294dcfb52aab92299356a5f3caa0aa52b Brings following Zephyr relevant fixes: - e9fccef5 boot_serial: Fix missing response if echo command disabled - 013c9e76 boot: zephyr: board: various: Remove size optimisation - 0a8bbbf4 boot: zephyr: Fix USB configs - d5c963c5 boot: zephyr: serial_adapter: Add error if main thread not preemptible - 822b6cb7 boot: zephyr: serial_adapter: Fail if USB CDC enabled with console Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index bde31c3303e3da2..9326bd857222d38 100644 --- a/west.yml +++ b/west.yml @@ -282,7 +282,7 @@ manifest: groups: - crypto - name: mcuboot - revision: 4a1effbc301fc302ecbaf40d4eb2be520b53010d + revision: 0c0470e294dcfb52aab92299356a5f3caa0aa52b path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From 5730dd6fb75e4b405e40580d8f1562a2a9352516 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 7 Nov 2023 12:39:49 +0100 Subject: [PATCH 0027/1049] doc: fix typos Add missed "space". Add missed "been". Signed-off-by: Andrej Butok --- doc/develop/env_vars.rst | 2 +- doc/kernel/services/synchronization/mutexes.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/env_vars.rst b/doc/develop/env_vars.rst index 459c62b580ae75f..fba31b7735e22e2 100644 --- a/doc/develop/env_vars.rst +++ b/doc/develop/env_vars.rst @@ -72,7 +72,7 @@ Option 2: In all Terminals You can then run ``rapidee`` from your terminal to launch the program and set environment variables. Make sure to use the "User" environment variables area -- otherwise, you have to run RapidEE as administrator. Also make sure to save - your changes by clicking the Save button at top left before exiting.Settings + your changes by clicking the Save button at top left before exiting. Settings you make in RapidEE will be available whenever you open a new terminal window. .. _env_vars_zephyrrc: diff --git a/doc/kernel/services/synchronization/mutexes.rst b/doc/kernel/services/synchronization/mutexes.rst index b813fec2d685ca3..8fa7d1504229429 100644 --- a/doc/kernel/services/synchronization/mutexes.rst +++ b/doc/kernel/services/synchronization/mutexes.rst @@ -20,7 +20,7 @@ is referenced by its memory address. A mutex has the following key properties: -* A **lock count** that indicates the number of times the mutex has be locked +* A **lock count** that indicates the number of times the mutex has been locked by the thread that has locked it. A count of zero indicates that the mutex is unlocked. From dc92b32ceb5d41d722249057219f9983c7e8f5de Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 7 Nov 2023 13:11:42 +0100 Subject: [PATCH 0028/1049] doc: fix link to extensions.cmake "cmake/extensions.cmake" does not exist. The link is broken. Fix it to correct one "cmake/modules/extensions.cmake". Signed-off-by: Andrej Butok --- doc/develop/application/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/application/index.rst b/doc/develop/application/index.rst index 148cb50f93627cc..f2be0d8b5518a31 100644 --- a/doc/develop/application/index.rst +++ b/doc/develop/application/index.rst @@ -702,7 +702,7 @@ be useful for glue code to have access to Zephyr kernel header files. To make it easier to integrate third-party components, the Zephyr build system has defined CMake functions that give application build scripts access to the zephyr compiler options. The functions are -documented and defined in :zephyr_file:`cmake/extensions.cmake` +documented and defined in :zephyr_file:`cmake/modules/extensions.cmake` and follow the naming convention ``zephyr_get__``. The following variables will often need to be exported to the From 583fd8a79e74e5f59f938bde53fec0a53a80f79a Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 7 Nov 2023 14:30:28 +0100 Subject: [PATCH 0029/1049] doc: slist: fix duplicated sys_sfnode_flags_get() Replace duplicated sys_sfnode_flags_get() by sys_sfnode_flags_set(). Signed-off-by: Andrej Butok --- doc/kernel/data_structures/slist.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/kernel/data_structures/slist.rst b/doc/kernel/data_structures/slist.rst index add76e869a61164..c1eb062ff83dfdf 100644 --- a/doc/kernel/data_structures/slist.rst +++ b/doc/kernel/data_structures/slist.rst @@ -108,7 +108,7 @@ ways identically to the slist API. It adds the ability to associate exactly two bits of user defined "flags" with each list node. These can be accessed and modified with -:c:func:`sys_sfnode_flags_get` and :c:func:`sys_sfnode_flags_get`. +:c:func:`sys_sfnode_flags_get` and :c:func:`sys_sfnode_flags_set`. Internally, the flags are stored unioned with the bottom bits of the next pointer and incur no SRAM storage overhead when compared with the simpler slist code. From 07328c4afaf1545e6814799ae9fb3b32458c7ef0 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 7 Nov 2023 14:41:25 +0000 Subject: [PATCH 0030/1049] doc: migration-guide: 3.6: Add note on MCUboot Kconfig Adds a note about how to replicate the functionality of the now removed MCUboot mass erase Kconfig option Signed-off-by: Jamie McCrae --- doc/releases/migration-guide-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 9c2cc98c2aed80d..ca73ed0ae82091e 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -59,6 +59,10 @@ Power Management Bootloader ========== +* MCUboot's deprecated ``CONFIG_ZEPHYR_TRY_MASS_ERASE`` Kconfig option has been removed. If an + erase is needed when flashing MCUboot, this should now be provided directly to the ``west`` + command e.g. ``west flash --erase``. + Bluetooth ========= From 09be84eb77eda34c4fd5559c9a2ca25663b1b20d Mon Sep 17 00:00:00 2001 From: Dat Nguyen Duy Date: Tue, 7 Nov 2023 18:45:05 +0700 Subject: [PATCH 0031/1049] drivers: nxp_s32_netc: remove dependency to NET_TEST There is no require to prevent building nxp s32 netc shim driver if NET_TEST is set, so just remove this unnecessary dependency Fix #64944 Signed-off-by: Dat Nguyen Duy --- drivers/ethernet/Kconfig.nxp_s32_netc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ethernet/Kconfig.nxp_s32_netc b/drivers/ethernet/Kconfig.nxp_s32_netc index e73f65502a31dec..6c568ca211efb7e 100644 --- a/drivers/ethernet/Kconfig.nxp_s32_netc +++ b/drivers/ethernet/Kconfig.nxp_s32_netc @@ -1,11 +1,10 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 menuconfig ETH_NXP_S32_NETC bool "NXP S32 Ethernet Switch and Controller (NETC) driver" default y depends on (DT_HAS_NXP_S32_NETC_PSI_ENABLED || DT_HAS_NXP_S32_NETC_VSI_ENABLED) - depends on !NET_TEST select MBOX select MDIO if DT_HAS_NXP_S32_NETC_PSI_ENABLED select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT From c6b86d5b1bc1d23f8cdc600283f9614cc168f539 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Duy Date: Tue, 7 Nov 2023 21:00:51 +0700 Subject: [PATCH 0032/1049] drivers: mdio: mdio nxp s32 netc should depend on eth netc driver MDIO is currently initialized in the ETH NXP S32 NETC driver for Physical Station Interface (PSI), so do not try to build the MDIO driver if the ETH driver is not built Signed-off-by: Dat Nguyen Duy --- drivers/mdio/Kconfig.nxp_s32 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mdio/Kconfig.nxp_s32 b/drivers/mdio/Kconfig.nxp_s32 index 07674f7a57dc117..61b02d53809f27f 100644 --- a/drivers/mdio/Kconfig.nxp_s32 +++ b/drivers/mdio/Kconfig.nxp_s32 @@ -1,10 +1,11 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 config MDIO_NXP_S32_NETC bool "NXP S32 NETC External MDIO driver" default y depends on DT_HAS_NXP_S32_NETC_EMDIO_ENABLED + depends on ETH_NXP_S32_NETC && DT_HAS_NXP_S32_NETC_PSI_ENABLED select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT help Enable NETC External MDIO Controller driver for NXP S32 SoCs. From 4df07224f8dcca5c882be94e28faeb91df5455ca Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 7 Nov 2023 08:49:28 +0100 Subject: [PATCH 0033/1049] drivers ieee802154_nrf5: Fix infinite loop for simulation on stop With CSL enabled, when nrf5_stop is called, nrf_802154_sleep_if_idle() will be called, and if the radio is busy with another task, another IEEE802154_EVENT_RX_OFF event will be pended right away, resulting in another call to nrf5_stop(), effectively busy waiting until the radio has reached idle. In simulation, this whole operation (busy wait loop) is done without letting the CPU sleep, in an infinite loop, and therefore without letting any time pass (note that in the POSIX architecture, no time passes if the CPU does not go to sleep). And therefore the radio will never be done with whatever it is doing, resulting in the simulation being stuck in this loop. Let's add a very minor delay to this loop, which is conditionally compiled only for the POSIX architecture. Which effectively mimics the time it takes for the CPU to loop thru, let's time pass, and allows the radio to eventually be done. Signed-off-by: Alberto Escolar Piedras --- drivers/ieee802154/ieee802154_nrf5.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 891a220e07f3418..9a02aef7e4ce7f0 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -668,6 +668,7 @@ static int nrf5_stop(const struct device *dev) } else { LOG_WRN("Transition to radio sleep cannot be handled."); } + Z_SPIN_DELAY(1); return 0; } #else From cf053d07e37e9ee59c444af3c635317e17123a76 Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Wed, 8 Nov 2023 11:06:20 +0800 Subject: [PATCH 0034/1049] test: twister: test_runner remove line number check in log 1. remove the line number check in test vector 2. log_info is not a static method anymore, change test Signed-off-by: Hake Huang --- scripts/tests/twister/test_runner.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/scripts/tests/twister/test_runner.py b/scripts/tests/twister/test_runner.py index ed0533937b66ebb..50732bf42287e42 100644 --- a/scripts/tests/twister/test_runner.py +++ b/scripts/tests/twister/test_runner.py @@ -785,6 +785,7 @@ def mock_pickle(datafile): ) def test_projectbuilder_log_info( caplog, + mocked_jobserver, inline_logs, read_exception, expected_logs @@ -802,10 +803,14 @@ def mock_abspath(filename, *args, **kwargs): filename = 'dummy_file.log' + env_mock = mock.Mock() + instance_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) with mock.patch('builtins.open', mock_open), \ mock.patch('os.path.realpath', mock_realpath), \ mock.patch('os.path.abspath', mock_abspath): - ProjectBuilder.log_info(filename, inline_logs) + pb.log_info(filename, inline_logs) assert all([log in caplog.text for log in expected_logs]) @@ -1876,14 +1881,14 @@ def mock_open(fname, *args, **kwargs): TESTDATA_13 = [ ( 'error', True, True, False, - ['INFO twister:runner.py:950 20/25 dummy platform' \ + ['INFO 20/25 dummy platform' \ ' dummy.testsuite.name' \ ' ERROR dummy reason (cmake)'], None ), ( 'failed', False, False, False, - ['ERROR twister:runner.py:904 dummy platform' \ + ['ERROR dummy platform' \ ' dummy.testsuite.name' \ ' FAILED : dummy reason'], 'INFO - Total complete: 20/ 25 80% skipped: 3,' \ @@ -1891,7 +1896,7 @@ def mock_open(fname, *args, **kwargs): ), ( 'skipped', True, False, False, - ['INFO twister:runner.py:950 20/25 dummy platform' \ + ['INFO 20/25 dummy platform' \ ' dummy.testsuite.name' \ ' SKIPPED (dummy reason)'], None @@ -1904,7 +1909,7 @@ def mock_open(fname, *args, **kwargs): ), ( 'passed', True, False, True, - ['INFO twister:runner.py:950 20/25 dummy platform' \ + ['INFO 20/25 dummy platform' \ ' dummy.testsuite.name' \ ' PASSED' \ ' (dummy handler type: dummy dut, 60.000s)'], @@ -1912,7 +1917,7 @@ def mock_open(fname, *args, **kwargs): ), ( 'passed', True, False, False, - ['INFO twister:runner.py:950 20/25 dummy platform' \ + ['INFO 20/25 dummy platform' \ ' dummy.testsuite.name' \ ' PASSED (build)'], None @@ -1925,7 +1930,7 @@ def mock_open(fname, *args, **kwargs): ), ( 'timeout', True, False, True, - ['INFO twister:runner.py:950 20/25 dummy platform' \ + ['INFO 20/25 dummy platform' \ ' dummy.testsuite.name' \ ' UNKNOWN' \ ' (dummy handler type: dummy dut, 60.000s/seed: 123)'], @@ -1988,11 +1993,13 @@ def test_projectbuilder_report_out( assert results_mock.cases == 25 - assert all([log in re.sub( + trim_actual_log = re.sub( r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])', '', caplog.text - ) for log in expected_logs]) + ) + trim_actual_log = re.sub(r'twister:runner.py:\d+', '', trim_actual_log) + assert all([log in trim_actual_log for log in expected_logs]) if expected_out: out, err = capfd.readouterr() From 1fd080b8cff68276297fc19525a9ccff8a0c5c39 Mon Sep 17 00:00:00 2001 From: Nazar Palamar Date: Tue, 20 Jun 2023 14:45:39 +0300 Subject: [PATCH 0035/1049] drivers: sdhc: added Infineon CAT1 SDHC/SDIO driver Added initial version of Infineon CAT1 SDHC/SDIO driver Added initial version of binding file for Infineon CAT1 SDHC/SDIO driver Signed-off-by: Nazar Palamar --- drivers/sdhc/CMakeLists.txt | 1 + drivers/sdhc/Kconfig | 1 + drivers/sdhc/Kconfig.ifx_cat1 | 22 ++ drivers/sdhc/ifx_cat1_sdio.c | 332 ++++++++++++++++++ dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi | 7 + dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi | 7 + dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi | 6 + dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi | 6 + .../sdhc/infineon,cat1-sdhc-sdio.yaml | 20 ++ modules/hal_infineon/Kconfig | 7 +- 10 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 drivers/sdhc/Kconfig.ifx_cat1 create mode 100644 drivers/sdhc/ifx_cat1_sdio.c create mode 100644 dts/bindings/sdhc/infineon,cat1-sdhc-sdio.yaml diff --git a/drivers/sdhc/CMakeLists.txt b/drivers/sdhc/CMakeLists.txt index a43e3f54806f9ea..431867fb2b8cd76 100644 --- a/drivers/sdhc/CMakeLists.txt +++ b/drivers/sdhc/CMakeLists.txt @@ -8,4 +8,5 @@ zephyr_library_sources_ifdef(CONFIG_SPI_SDHC sdhc_spi.c) zephyr_library_sources_ifdef(CONFIG_MCUX_SDIF mcux_sdif.c) zephyr_library_sources_ifdef(CONFIG_SAM_HSMCI sam_hsmci.c) zephyr_library_sources_ifdef(CONFIG_INTEL_EMMC_HOST intel_emmc_host.c) +zephyr_library_sources_ifdef(CONFIG_SDHC_INFINEON_CAT1 ifx_cat1_sdio.c) endif() diff --git a/drivers/sdhc/Kconfig b/drivers/sdhc/Kconfig index 69a942238e4aaf8..7e75e03a024b5b8 100644 --- a/drivers/sdhc/Kconfig +++ b/drivers/sdhc/Kconfig @@ -8,6 +8,7 @@ menuconfig SDHC if SDHC +source "drivers/sdhc/Kconfig.ifx_cat1" source "drivers/sdhc/Kconfig.imx" source "drivers/sdhc/Kconfig.spi" source "drivers/sdhc/Kconfig.mcux_sdif" diff --git a/drivers/sdhc/Kconfig.ifx_cat1 b/drivers/sdhc/Kconfig.ifx_cat1 new file mode 100644 index 000000000000000..13dde4cf18fbd07 --- /dev/null +++ b/drivers/sdhc/Kconfig.ifx_cat1 @@ -0,0 +1,22 @@ +# Infineon CAT1 SDHC configuration options + +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +config SDHC_INFINEON_CAT1 + bool "Infineon CAT1 SDHC driver" + default y + depends on DT_HAS_INFINEON_CAT1_SDHC_SDIO_ENABLED + select USE_INFINEON_SDIO + select SDHC_SUPPORTS_NATIVE_MODE + help + This option enables the SDHC driver for Infineon CAT1 family. + +if SDHC_INFINEON_CAT1 + +config SDHC_INIT_PRIORITY + default 70 + +endif diff --git a/drivers/sdhc/ifx_cat1_sdio.c b/drivers/sdhc/ifx_cat1_sdio.c new file mode 100644 index 000000000000000..d298e1d7b6b9da5 --- /dev/null +++ b/drivers/sdhc/ifx_cat1_sdio.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/** + * @brief SDIO driver for Infineon CAT1 MCU family. + * + * This driver support only SDIO protocol of the SD interface for general + * I/O functions. + * + * Refer to the SD Specifications Part 1 SDIO Specifications Version 4.10 for more + * information on the SDIO protocol and specifications. + * + * Features + * - Supports 4-bit interface + * - Supports Ultra High Speed (UHS-I) mode + * - Supports Default Speed (DS), High Speed (HS), SDR12, SDR25 and SDR50 speed modes + * - Supports SDIO card interrupts in both 1-bit SD and 4-bit SD modes + * - Supports Standard capacity (SDSC), High capacity (SDHC) and + * Extended capacity (SDXC) memory + * + * Note (limitations): + * - current version of ifx_cat1_sdio supports only following set of commands: + * > GO_IDLE_STATE (CMD0) + * > SEND_RELATIVE_ADDR (CMD3) + * > IO_SEND_OP_COND (CMD5) + * > SELECT_CARD (CMD7) + * > VOLTAGE_SWITCH (CMD11) + * > GO_INACTIVE_STATE (CMD15) + * > IO_RW_DIRECT (CMD52) + * > IO_RW_EXTENDED (CMD53) + */ + +#define DT_DRV_COMPAT infineon_cat1_sdhc_sdio + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_REGISTER(ifx_cat1_sdio, CONFIG_SDHC_LOG_LEVEL); + +#include + +#define IFX_CAT1_SDIO_F_MIN (SDMMC_CLOCK_400KHZ) +#define IFX_CAT1_SDIO_F_MAX (SD_CLOCK_50MHZ) + +struct ifx_cat1_sdio_config { + const struct pinctrl_dev_config *pincfg; + SDHC_Type *reg_addr; + uint8_t irq_priority; +}; + +struct ifx_cat1_sdio_data { + cyhal_sdio_t sdio_obj; + cyhal_resource_inst_t hw_resource; + cyhal_sdio_configurator_t cyhal_sdio_config; + enum sdhc_clock_speed clock_speed; + enum sdhc_bus_width bus_width; + + void *sdio_cb_user_data; + sdhc_interrupt_cb_t sdio_cb; +}; + +static uint32_t sdio_rca; +static const cy_stc_sd_host_init_config_t host_config = {false, CY_SD_HOST_DMA_ADMA2, false}; +static cy_en_sd_host_card_capacity_t sd_host_card_capacity = CY_SD_HOST_SDSC; +static cy_en_sd_host_card_type_t sd_host_card_type = CY_SD_HOST_NOT_EMMC; +static cy_stc_sd_host_sd_card_config_t sd_host_sd_card_config = { + .lowVoltageSignaling = false, + .busWidth = CY_SD_HOST_BUS_WIDTH_4_BIT, + .cardType = &sd_host_card_type, + .rca = &sdio_rca, + .cardCapacity = &sd_host_card_capacity, +}; + +/* List of available SDHC instances */ +static SDHC_Type *const IFX_CAT1_SDHC_BASE_ADDRESSES[CY_IP_MXSDHC_INSTANCES] = { +#ifdef SDHC0 + SDHC0, +#endif /* ifdef SDHC0 */ + +#ifdef SDHC1 + SDHC1, +#endif /* ifdef SDHC1 */ +}; + +static int32_t _get_hw_block_num(SDHC_Type *reg_addr) +{ + uint32_t i; + + for (i = 0u; i < CY_IP_MXSDHC_INSTANCES; i++) { + if (IFX_CAT1_SDHC_BASE_ADDRESSES[i] == reg_addr) { + return i; + } + } + + return -EINVAL; +} + +static int ifx_cat1_sdio_reset(const struct device *dev) +{ + struct ifx_cat1_sdio_data *dev_data = dev->data; + + cyhal_sdhc_software_reset((cyhal_sdhc_t *)&dev_data->sdio_obj); + + return 0; +} + +static int ifx_cat1_sdio_set_io(const struct device *dev, struct sdhc_io *ios) +{ + cy_rslt_t ret; + struct ifx_cat1_sdio_data *dev_data = dev->data; + cyhal_sdio_cfg_t config = {.frequencyhal_hz = ios->clock}; + + /* NOTE: Set bus width, set card power, set host signal voltage, + * set I/O timing does not support in current version of driver + */ + + /* Set host clock */ + if ((dev_data->clock_speed != ios->clock) && (ios->clock != 0)) { + + if ((ios->clock > IFX_CAT1_SDIO_F_MAX) || (ios->clock < IFX_CAT1_SDIO_F_MIN)) { + return -EINVAL; + } + + ret = cyhal_sdio_configure(&dev_data->sdio_obj, &config); + if (ret != CY_RSLT_SUCCESS) { + return -ENOTSUP; + } + + dev_data->clock_speed = ios->clock; + } + + return 0; +} + +static int ifx_cat1_sdio_card_busy(const struct device *dev) +{ + struct ifx_cat1_sdio_data *dev_data = dev->data; + + return cyhal_sdio_is_busy(&dev_data->sdio_obj) ? 1 : 0; +} + +static int ifx_cat1_sdio_request(const struct device *dev, struct sdhc_command *cmd, + struct sdhc_data *data) +{ + struct ifx_cat1_sdio_data *dev_data = dev->data; + int ret; + + switch (cmd->opcode) { + case CYHAL_SDIO_CMD_GO_IDLE_STATE: + case CYHAL_SDIO_CMD_SEND_RELATIVE_ADDR: + case CYHAL_SDIO_CMD_IO_SEND_OP_COND: + case CYHAL_SDIO_CMD_SELECT_CARD: + case CYHAL_SDIO_CMD_VOLTAGE_SWITCH: + case CYHAL_SDIO_CMD_GO_INACTIVE_STATE: + case CYHAL_SDIO_CMD_IO_RW_DIRECT: + ret = cyhal_sdio_send_cmd(&dev_data->sdio_obj, CYHAL_SDIO_XFER_TYPE_READ, + cmd->opcode, cmd->arg, cmd->response); + if (ret != CY_RSLT_SUCCESS) { + LOG_ERR("cyhal_sdio_send_cmd failed ret = %d \r\n", ret); + } + break; + + case CYHAL_SDIO_CMD_IO_RW_EXTENDED: + cyhal_sdio_transfer_type_t direction; + + direction = (cmd->arg & BIT(SDIO_CMD_ARG_RW_SHIFT)) ? CYHAL_SDIO_XFER_TYPE_WRITE + : CYHAL_SDIO_XFER_TYPE_READ; + + ret = cyhal_sdio_bulk_transfer(&dev_data->sdio_obj, direction, cmd->arg, data->data, + data->blocks * data->block_size, cmd->response); + + if (ret != CY_RSLT_SUCCESS) { + LOG_ERR("cyhal_sdio_bulk_transfer failed ret = %d \r\n", ret); + } + break; + + default: + ret = -ENOTSUP; + } + + return ret; +} + +static int ifx_cat1_sdio_get_card_present(const struct device *dev) +{ + return 1; +} + +static int ifx_cat1_sdio_get_host_props(const struct device *dev, struct sdhc_host_props *props) +{ + memset(props, 0, sizeof(*props)); + props->f_max = IFX_CAT1_SDIO_F_MAX; + props->f_min = IFX_CAT1_SDIO_F_MIN; + props->host_caps.bus_4_bit_support = true; + props->host_caps.high_spd_support = true; + props->host_caps.sdr50_support = true; + props->host_caps.sdio_async_interrupt_support = true; + props->host_caps.vol_330_support = true; + + return 0; +} + +static int ifx_cat1_sdio_enable_interrupt(const struct device *dev, sdhc_interrupt_cb_t callback, + int sources, void *user_data) +{ + struct ifx_cat1_sdio_data *data = dev->data; + const struct ifx_cat1_sdio_config *cfg = dev->config; + + if (sources != SDHC_INT_SDIO) { + return -ENOTSUP; + } + + if (callback == NULL) { + return -EINVAL; + } + + /* Record SDIO callback parameters */ + data->sdio_cb = callback; + data->sdio_cb_user_data = user_data; + + /* Enable CARD INTERRUPT event */ + cyhal_sdio_enable_event(&data->sdio_obj, CYHAL_SDIO_CARD_INTERRUPT, + cfg->irq_priority, true); + + return 0; +} + +static int ifx_cat1_sdio_disable_interrupt(const struct device *dev, int sources) +{ + struct ifx_cat1_sdio_data *data = dev->data; + const struct ifx_cat1_sdio_config *cfg = dev->config; + + if (sources != SDHC_INT_SDIO) { + return -ENOTSUP; + } + + data->sdio_cb = NULL; + data->sdio_cb_user_data = NULL; + + /* Disable CARD INTERRUPT event */ + cyhal_sdio_enable_event(&data->sdio_obj, CYHAL_SDIO_CARD_INTERRUPT, + cfg->irq_priority, false); + + return 0; +} + +static void ifx_cat1_sdio_event_callback(void *callback_arg, cyhal_sdio_event_t event) +{ + const struct device *dev = callback_arg; + struct ifx_cat1_sdio_data *data = dev->data; + + if ((event == CYHAL_SDIO_CARD_INTERRUPT) && (data->sdio_cb != NULL)) { + data->sdio_cb(dev, SDHC_INT_SDIO, data->sdio_cb_user_data); + } +} + +static int ifx_cat1_sdio_init(const struct device *dev) +{ + cy_rslt_t ret; + struct ifx_cat1_sdio_data *data = dev->data; + const struct ifx_cat1_sdio_config *config = dev->config; + + /* Configure dt provided device signals when available */ + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + /* Dedicate SDIO HW resource */ + data->hw_resource.type = CYHAL_RSC_SDIODEV; + data->hw_resource.block_num = _get_hw_block_num(config->reg_addr); + + /* Initialize the SDIO peripheral */ + data->cyhal_sdio_config.resource = &data->hw_resource; + data->cyhal_sdio_config.host_config = &host_config, + data->cyhal_sdio_config.card_config = &sd_host_sd_card_config, + + ret = cyhal_sdio_init_cfg(&data->sdio_obj, &data->cyhal_sdio_config); + if (ret != CY_RSLT_SUCCESS) { + LOG_ERR("cyhal_sdio_init_cfg failed ret = %d \r\n", ret); + return ret; + } + + /* Register callback for SDIO events */ + cyhal_sdio_register_callback(&data->sdio_obj, ifx_cat1_sdio_event_callback, (void *)dev); + + return 0; +} + +static const struct sdhc_driver_api ifx_cat1_sdio_api = { + .reset = ifx_cat1_sdio_reset, + .request = ifx_cat1_sdio_request, + .set_io = ifx_cat1_sdio_set_io, + .get_card_present = ifx_cat1_sdio_get_card_present, + .card_busy = ifx_cat1_sdio_card_busy, + .get_host_props = ifx_cat1_sdio_get_host_props, + .enable_interrupt = ifx_cat1_sdio_enable_interrupt, + .disable_interrupt = ifx_cat1_sdio_disable_interrupt, +}; + +#define IFX_CAT1_SDHC_INIT(n) \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static const struct ifx_cat1_sdio_config ifx_cat1_sdio_##n##_config = { \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .reg_addr = (SDHC_Type *)DT_INST_REG_ADDR(n), \ + .irq_priority = DT_INST_IRQ(n, priority)}; \ + \ + static struct ifx_cat1_sdio_data ifx_cat1_sdio_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &ifx_cat1_sdio_init, NULL, &ifx_cat1_sdio_##n##_data, \ + &ifx_cat1_sdio_##n##_config, POST_KERNEL, CONFIG_SDHC_INIT_PRIORITY, \ + &ifx_cat1_sdio_api); + +DT_INST_FOREACH_STATUS_OKAY(IFX_CAT1_SDHC_INIT) diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi index 4f3b420d3e5b28b..56957dddab0315c 100644 --- a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi @@ -537,5 +537,12 @@ resolution = <16>; status = "disabled"; }; + + sdhc0: sdhc@40460000 { + compatible = "infineon,cat1-sdhc-sdio"; + reg = <0x40460000 0x2000>; + interrupts = <164 6>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi b/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi index a4109291dfd2894..c61ba9e0ca42323 100644 --- a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi @@ -541,5 +541,12 @@ resolution = <16>; status = "disabled"; }; + + sdhc0: sdhc@40460000 { + compatible = "infineon,cat1-sdhc-sdio"; + reg = <0x40460000 0x2000>; + interrupts = <164 6>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi b/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi index 8e8ada040d2c84e..14aefdc5ada5bc0 100644 --- a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi @@ -241,6 +241,12 @@ interrupts = <18 6>; status = "disabled"; }; + sdhc0: sdhc@40460000 { + compatible = "infineon,cat1-sdhc-sdio"; + reg = <0x40460000 0x2000>; + interrupts = <164 6>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi b/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi index 73282624e3f9406..d44b0583f70b8d1 100644 --- a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi @@ -247,6 +247,12 @@ interrupts = <18 6>; status = "disabled"; }; + sdhc0: sdhc@40460000 { + compatible = "infineon,cat1-sdhc-sdio"; + reg = <0x40460000 0x2000>; + interrupts = <164 6>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/sdhc/infineon,cat1-sdhc-sdio.yaml b/dts/bindings/sdhc/infineon,cat1-sdhc-sdio.yaml new file mode 100644 index 000000000000000..8bb1071b02b3cd5 --- /dev/null +++ b/dts/bindings/sdhc/infineon,cat1-sdhc-sdio.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Infineon CAT1 SDHC/SDIO controller + +compatible: "infineon,cat1-sdhc-sdio" + +include: [sdhc.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/modules/hal_infineon/Kconfig b/modules/hal_infineon/Kconfig index 0522c96769c3a2e..83d24bfacd5ca1e 100644 --- a/modules/hal_infineon/Kconfig +++ b/modules/hal_infineon/Kconfig @@ -27,6 +27,12 @@ config USE_INFINEON_SDIO Enable Secure Digital Input/Output interface (SDIO) HAL module for Infineon devices driver +config USE_INFINEON_SDHC + bool + help + Enable SDHC HAL module for Infineon devices + driver + config USE_INFINEON_SPI bool help @@ -68,7 +74,6 @@ config USE_INFINEON_WDT config ABSTRACTION_RTOS_COMPONENT_ZEPHYR bool "Abstraction RTOS component (Zephyr support)" - default n help Enable Abstraction RTOS component with Zephyr support From 5c3abe9197445547820e65e6ac01c86551a37e17 Mon Sep 17 00:00:00 2001 From: Nazar Palamar Date: Wed, 4 Oct 2023 09:54:18 +0300 Subject: [PATCH 0036/1049] drivers: bluetooth: rename BT_CYW43XXX to BT_AIROC rename BT_CYW43XXX to BT_AIROC to be compatible with WIFI_AIROC Signed-off-by: Nazar Palamar --- boards/arm/arduino_giga_r1/Kconfig.defconfig | 2 +- drivers/bluetooth/hci/CMakeLists.txt | 2 +- drivers/bluetooth/hci/Kconfig | 4 ++-- drivers/bluetooth/hci/Kconfig.infineon | 20 +++++++++---------- modules/hal_infineon/CMakeLists.txt | 4 ++-- .../btstack-integration/CMakeLists.txt | 10 +++++----- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/boards/arm/arduino_giga_r1/Kconfig.defconfig b/boards/arm/arduino_giga_r1/Kconfig.defconfig index 5880f88f7e0447e..e72fb499055f5ac 100644 --- a/boards/arm/arduino_giga_r1/Kconfig.defconfig +++ b/boards/arm/arduino_giga_r1/Kconfig.defconfig @@ -9,7 +9,7 @@ config BOARD if BT -choice CYW43XXX_PART +choice AIROC_PART default CYW4343W endchoice diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index b4417a72e8fd465..6aaf5205b0dd7f3 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -14,7 +14,7 @@ if(CONFIG_BT_HCI_IPC) endif() zephyr_library_sources_ifdef(CONFIG_BT_B91 hci_b91.c) -zephyr_library_sources_ifdef(CONFIG_BT_CYW43XXX cyw43xxx.c) +zephyr_library_sources_ifdef(CONFIG_BT_AIROC cyw43xxx.c) zephyr_library_sources_ifdef(CONFIG_BT_ESP32 hci_esp32.c) zephyr_library_sources_ifdef(CONFIG_BT_H4 h4.c) zephyr_library_sources_ifdef(CONFIG_BT_H5 h5.c) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 9c02c1a61c36112..835b90edd545986 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -137,8 +137,8 @@ config BT_STM32_IPM_RX_STACK_SIZE depends on BT_STM32_IPM default 512 -menuconfig BT_CYW43XXX - bool "CYW43XXX BT connectivity" +menuconfig BT_AIROC + bool "AIROC BT connectivity" default y select BT_HCI_SETUP depends on GPIO diff --git a/drivers/bluetooth/hci/Kconfig.infineon b/drivers/bluetooth/hci/Kconfig.infineon index d0e4478ac3439fd..1f4193bd28a4753 100644 --- a/drivers/bluetooth/hci/Kconfig.infineon +++ b/drivers/bluetooth/hci/Kconfig.infineon @@ -2,10 +2,10 @@ # an affiliate of Cypress Semiconductor Corporation # SPDX-License-Identifier: Apache-2.0 -if BT_CYW43XXX +if BT_AIROC -choice CYW43XXX_PART - prompt "Select CYW43XXX part" +choice AIROC_PART + prompt "Select AIROC part" config CYW4343W bool "CYW4343W" @@ -42,12 +42,12 @@ config CYW43439 More information about CYW43439 device you can find on https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw43439/ -config BT_CYW43XXX_CUSTOM - bool "Custom CYW43xx device/module" +config BT_AIROC_CUSTOM + bool "Custom AIROC device/module" help - Select Custom CYW43xx device/module. For this option, + Select Custom AIROC device/module. For this option, user must to provide path to BT firmware HCD file for - custom or vendor CYW43xx modules in CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB. + custom or vendor AIROC modules in AIROC_CUSTOM_FIRMWARE_HCD_BLOB. endchoice @@ -117,8 +117,8 @@ config CYW43439_MURATA_1YN endchoice -config CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB - depends on BT_CYW43XXX_CUSTOM +config AIROC_CUSTOM_FIRMWARE_HCD_BLOB + depends on BT_AIROC_CUSTOM string "Path to user BT firmware HCD file" help Path to BT firmware HCD file for custom or vendor CYW43xx modules. @@ -134,7 +134,7 @@ config BT_BUF_CMD_TX_SIZE config BT_ATT_ENFORCE_FLOW default n -endif # BT_CYW43XXX +endif # BT_AIROC if BT_PSOC6_BLESS diff --git a/modules/hal_infineon/CMakeLists.txt b/modules/hal_infineon/CMakeLists.txt index aff4d21f0aaf6eb..1db3cf57a6af3b2 100644 --- a/modules/hal_infineon/CMakeLists.txt +++ b/modules/hal_infineon/CMakeLists.txt @@ -36,8 +36,8 @@ if (CONFIG_SOC_FAMILY_INFINEON_CAT1A) add_subdirectory(abstraction-rtos) endif() -## Add btstack-integration for CYW43xx BT devices -if (CONFIG_BT_CYW43XXX) +## Add BT assets for AIROC devices +if (CONFIG_BT_AIROC) add_subdirectory(btstack-integration) endif() diff --git a/modules/hal_infineon/btstack-integration/CMakeLists.txt b/modules/hal_infineon/btstack-integration/CMakeLists.txt index ef6a64cff3ddb35..d82fe10662ddafb 100644 --- a/modules/hal_infineon/btstack-integration/CMakeLists.txt +++ b/modules/hal_infineon/btstack-integration/CMakeLists.txt @@ -30,13 +30,13 @@ if(CONFIG_CYW4373_STERLING_LWB5PLUS) set(blob_hcd_file ${hal_blobs_dir}/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/bt_firmware.hcd) endif() -# use user provided FIRMWARE HCD file (path must be defined in CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB) -if(CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB) +# use user provided FIRMWARE HCD file (path must be defined in CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB) +if(CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB) # Allowed to pass absolute path to HCD blob file, or relative path from Application folder. - if(IS_ABSOLUTE ${CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB}) - set(blob_hcd_file ${CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB}) + if(IS_ABSOLUTE ${CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB}) + set(blob_hcd_file ${CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB}) else() - set(blob_hcd_file ${APPLICATION_SOURCE_DIR}/${CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB}) + set(blob_hcd_file ${APPLICATION_SOURCE_DIR}/${CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB}) endif() endif() From 4fd732a7387524a18b10fd0657bf37cd66153e09 Mon Sep 17 00:00:00 2001 From: Nazar Palamar Date: Wed, 4 Oct 2023 09:29:17 +0300 Subject: [PATCH 0037/1049] drivers: wifi: added Infineon AIROC WIFI driver Added initial version of Infineon AIROC WIFI driver Added initial version of binding file for Infineon AIROC WIFI driver Rename CONFIG_ABSTRACTION_RTOS_COMPONENT_ZEPHYR to CONFIG_USE_INFINEON_ABSTRACTION_RTOS Exclude cy8cproto_062_4343w platform from drivers.modem.esp_at.build test Change revision hal_infineon to 69c883d3bd9fac8a18dd8384624b8c472a68d06f Signed-off-by: Nazar Palamar --- drivers/wifi/CMakeLists.txt | 1 + drivers/wifi/Kconfig | 1 + drivers/wifi/infineon/CMakeLists.txt | 13 + drivers/wifi/infineon/Kconfig.airoc | 150 ++++ drivers/wifi/infineon/airoc_whd_hal.c | 438 ++++++++++ drivers/wifi/infineon/airoc_wifi.c | 772 ++++++++++++++++++ drivers/wifi/infineon/airoc_wifi.h | 50 ++ drivers/wifi/infineon/cybsp.h | 8 + dts/bindings/wifi/infineon,airoc-wifi.yaml | 50 ++ modules/hal_infineon/CMakeLists.txt | 5 + modules/hal_infineon/Kconfig | 2 +- .../abstraction-rtos/CMakeLists.txt | 4 +- .../wifi-host-driver/CMakeLists.txt | 216 +++++ .../net/wifi/boards/cy8cproto_062_4343w.conf | 3 + tests/drivers/build_all/modem/testcase.yaml | 4 +- west.yml | 2 +- 16 files changed, 1714 insertions(+), 5 deletions(-) create mode 100644 drivers/wifi/infineon/CMakeLists.txt create mode 100644 drivers/wifi/infineon/Kconfig.airoc create mode 100644 drivers/wifi/infineon/airoc_whd_hal.c create mode 100644 drivers/wifi/infineon/airoc_wifi.c create mode 100644 drivers/wifi/infineon/airoc_wifi.h create mode 100644 drivers/wifi/infineon/cybsp.h create mode 100644 dts/bindings/wifi/infineon,airoc-wifi.yaml create mode 100644 modules/hal_infineon/wifi-host-driver/CMakeLists.txt create mode 100644 samples/net/wifi/boards/cy8cproto_062_4343w.conf diff --git a/drivers/wifi/CMakeLists.txt b/drivers/wifi/CMakeLists.txt index b12ecf88a3ed917..df1e7c394653479 100644 --- a/drivers/wifi/CMakeLists.txt +++ b/drivers/wifi/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory_ifdef(CONFIG_WIFI_ESP32 esp32) add_subdirectory_ifdef(CONFIG_WIFI_ESWIFI eswifi) add_subdirectory_ifdef(CONFIG_WIFI_SIMPLELINK simplelink) add_subdirectory_ifdef(CONFIG_WIFI_WINC1500 winc1500) +add_subdirectory_ifdef(CONFIG_WIFI_AIROC infineon) diff --git a/drivers/wifi/Kconfig b/drivers/wifi/Kconfig index 4bb4197bedebb26..d7133f5be04011e 100644 --- a/drivers/wifi/Kconfig +++ b/drivers/wifi/Kconfig @@ -40,5 +40,6 @@ source "drivers/wifi/simplelink/Kconfig.simplelink" source "drivers/wifi/eswifi/Kconfig.eswifi" source "drivers/wifi/esp_at/Kconfig.esp_at" source "drivers/wifi/esp32/Kconfig.esp32" +source "drivers/wifi/infineon/Kconfig.airoc" endif # WIFI diff --git a/drivers/wifi/infineon/CMakeLists.txt b/drivers/wifi/infineon/CMakeLists.txt new file mode 100644 index 000000000000000..20f69f181117fc8 --- /dev/null +++ b/drivers/wifi/infineon/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(./) + +zephyr_library_sources_ifdef(CONFIG_WIFI_AIROC airoc_wifi.c) +zephyr_library_sources_ifdef(CONFIG_WIFI_AIROC airoc_whd_hal.c) + +zephyr_compile_definitions(CYBSP_WIFI_CAPABLE) +zephyr_compile_definitions(CY_RTOS_AWARE) +zephyr_compile_definitions(WHD_USE_CUSTOM_MALLOC_IMPL) +zephyr_compile_definitions(WHD_USE_CUSTOM_HAL_IMPL) diff --git a/drivers/wifi/infineon/Kconfig.airoc b/drivers/wifi/infineon/Kconfig.airoc new file mode 100644 index 000000000000000..993fbdad21268c3 --- /dev/null +++ b/drivers/wifi/infineon/Kconfig.airoc @@ -0,0 +1,150 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +menuconfig WIFI_AIROC + bool "Infineon AIROC SoC Wi-Fi support" + select THREAD_CUSTOM_DATA + select WIFI_OFFLOAD + select NET_L2_WIFI_MGMT + select SDIO_STACK + select SDHC + select WIFI_USE_NATIVE_NETWORKING + select USE_INFINEON_ABSTRACTION_RTOS + depends on DT_HAS_INFINEON_AIROC_WIFI_ENABLED + help + Enable Infineon AIROC SoC Wi-Fi support. + +if WIFI_AIROC + +if SHELL +config SHELL_STACK_SIZE + default 4096 +endif # SHELL + +config SYSTEM_WORKQUEUE_STACK_SIZE + default 4096 + +config AIROC_WIFI_EVENT_TASK_STACK_SIZE + int "Event Task Stack Size" + default 4096 + +config AIROC_WIFI_EVENT_TASK_PRIO + int "Event Task Priority" + default 4 + +config AIROC_WLAN_MFG_FIRMWARE + bool "WLAN Manufacturing Firmware" + help + Enable WLAN Manufacturing Firmware. + +config AIROC_WIFI_CUSTOM + bool "Custom CYW43xx device/module" + help + Select Custom CYW43xx device/module. For this option, + user must to provide path to FW, CLM and NVRAM for + custom or vendor CYW43xx modules. + +choice AIROC_PART + prompt "Select AIROC part" + depends on !AIROC_WIFI_CUSTOM + +config CYW4343W + bool "CYW4343W" + help + Enable Infineon AIROC CYW4343W Wi-Fi connectivity, + More information about CYW4343W device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw4343w/ + +config CYW4373 + bool "CYW4373" + help + Enable Infineon AIROC CYW4373 Wi-Fi connectivity, + More information about CYW4373 device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw4373/ + +config CYW43012 + bool "CYW43012" + help + Enable Infineon AIROC CYW43012 Wi-Fi connectivity, + More information about CYW43012 device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw43012/ + +config CYW43438 + bool "CYW43438" + help + Enable Infineon AIROC CYW43438 Wi-Fi connectivity, + More information about CYW43438 device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw43438/ + +config CYW43439 + bool "CYW43439" + help + Enable Infineon AIROC CYW43439 Wi-Fi connectivity, + More information about CYW43439 device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw43439/ +endchoice + +choice CYW43012_MODULE + prompt "Select CYW43012 module" + depends on CYW43012 && !AIROC_WIFI_CUSTOM + +config CYW43012_MURATA_1LV + bool "MURATA-1LV" + help + Murata Type 1LV module based on Infineon CYW43012 combo chipset + which supports Wi-Fi® 802.11a/b/g/n + Bluetooth® 5.0 BR/EDR/LE + up to 72.2Mbps PHY data rate on Wi-fi® and 3Mbps PHY data rate + on Bluetooth®. 2Mbps LE PHY is also supported. + + Detailed information about Murata Type 1LV module you can find on + https://www.murata.com/en-us/products/connectivitymodule/wi-fi-bluetooth/overview/lineup/type1lv +endchoice + +choice CYW4343W_MODULE + prompt "Select CYW4343W module" + depends on CYW4343W && !AIROC_WIFI_CUSTOM + +config CYW4343W_MURATA_1DX + bool "MURATA-1DX" + help + Murata Type 1DX modules based on Infineon CYW4343W combo chipset + which supports Wi-Fi® 802.11b/g/n + Bluetooth® 5.1 BR/EDR/LE + up to 65Mbps PHY data rate on Wi-fi® and 3Mbps PHY data rate + on Bluetooth®. + + Detailed information about Type 1DX module you can find on + https://www.murata.com/en-us/products/connectivitymodule/wi-fi-bluetooth/overview/lineup/type1dx +endchoice + +choice CYW4373_MODULE + prompt "Select CYW4373 module" + depends on CYW4373 && !AIROC_WIFI_CUSTOM + +config CYW4373_STERLING_LWB5PLUS + bool "STERLING-LWB5plus" + help + Laird Sterling LWB5+ 802.11ac / Bluetooth 5.0 M.2 Carrier Board + (E-Type Key w/ SDIO/UART) + + Detailed information about Type Sterling LWB5+ module you can find on + https://www.lairdconnect.com/wireless-modules/wifi-modules-bluetooth/sterling-lwb5-plus-wifi-5-bluetooth-5-module +endchoice + +choice CYW43439_MODULE + prompt "Select CYW43439 module" + depends on CYW43439 && !AIROC_WIFI_CUSTOM + +config CYW43439_MURATA_1YN + bool "MURATA_1YN" + help + Murata Type 1YN module based on Infineon CYW43439 combo chipset + which supports Wi-Fi® 802.11b/g/n + Bluetooth® 5.2 BR/EDR/LE + up to 65Mbps PHY data rate on Wi-fi® and 3Mbps PHY data rate on + Bluetooth®. + + Detailed information about Murata Type 1YN module you can find on + https://www.murata.com/en-us/products/connectivitymodule/wi-fi-bluetooth/overview/lineup/type1yn +endchoice + +endif # AIROC_WIFI diff --git a/drivers/wifi/infineon/airoc_whd_hal.c b/drivers/wifi/infineon/airoc_whd_hal.c new file mode 100644 index 000000000000000..5b02d0bba4950f3 --- /dev/null +++ b/drivers/wifi/infineon/airoc_whd_hal.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +#define DT_DRV_COMPAT infineon_airoc_wifi + +LOG_MODULE_REGISTER(infineon_airoc, CONFIG_WIFI_LOG_LEVEL); + +#ifdef __cplusplus +extern "C" { +#endif + +/** Defines the amount of stack memory available for the wifi thread. */ +#if !defined(CY_WIFI_THREAD_STACK_SIZE) +#define CY_WIFI_THREAD_STACK_SIZE (5120) +#endif + +/** Defines the priority of the thread that services wifi packets. Legal values are defined by the + * RTOS being used. + */ +#if !defined(CY_WIFI_THREAD_PRIORITY) +#define CY_WIFI_THREAD_PRIORITY (CY_RTOS_PRIORITY_HIGH) +#endif + +/** Defines the country this will operate in for wifi initialization parameters. See the + * wifi-host-driver's whd_country_code_t for legal options. + */ +#if !defined(CY_WIFI_COUNTRY) +#define CY_WIFI_COUNTRY (WHD_COUNTRY_AUSTRALIA) +#endif + +/** Defines the priority of the interrupt that handles out-of-band notifications from the wifi + * chip. Legal values are defined by the MCU running this code. + */ +#if !defined(CY_WIFI_OOB_INTR_PRIORITY) +#define CY_WIFI_OOB_INTR_PRIORITY (2) +#endif + +/** Defines whether to use the out-of-band pin to allow the WIFI chip to wake up the MCU. */ +#if defined(CY_WIFI_HOST_WAKE_SW_FORCE) +#define CY_USE_OOB_INTR (CY_WIFI_HOST_WAKE_SW_FORCE) +#else +#define CY_USE_OOB_INTR (1u) +#endif /* defined(CY_WIFI_HOST_WAKE_SW_FORCE) */ + +#define CY_WIFI_HOST_WAKE_IRQ_EVENT GPIO_INT_TRIG_LOW +#define DEFAULT_OOB_PIN (0) +#define WLAN_POWER_UP_DELAY_MS (250) +#define WLAN_CBUCK_DISCHARGE_MS (10) + +extern whd_resource_source_t resource_ops; + +struct whd_bus_priv { + whd_sdio_config_t sdio_config; + whd_bus_stats_t whd_bus_stats; + whd_sdio_t sdio_obj; +}; + +static whd_init_config_t init_config_default = { + .thread_stack_size = CY_WIFI_THREAD_STACK_SIZE, + .thread_stack_start = NULL, + .thread_priority = (uint32_t)CY_WIFI_THREAD_PRIORITY, + .country = CY_WIFI_COUNTRY +}; + +/****************************************************** + * Function + ******************************************************/ + +int airoc_wifi_power_on(const struct device *dev) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_reg_on_gpios) + int ret; + const struct airoc_wifi_config *config = dev->config; + + /* Check WIFI REG_ON gpio instance */ + if (!device_is_ready(config->wifi_reg_on_gpio.port)) { + LOG_ERR("Error: failed to configure wifi_reg_on %s pin %d", + config->wifi_reg_on_gpio.port->name, config->wifi_reg_on_gpio.pin); + return -EIO; + } + + /* Configure wifi_reg_on as output */ + ret = gpio_pin_configure_dt(&config->wifi_reg_on_gpio, GPIO_OUTPUT); + if (ret) { + LOG_ERR("Error %d: failed to configure wifi_reg_on %s pin %d", ret, + config->wifi_reg_on_gpio.port->name, config->wifi_reg_on_gpio.pin); + return ret; + } + ret = gpio_pin_set_dt(&config->wifi_reg_on_gpio, 0); + if (ret) { + return ret; + } + + /* Allow CBUCK regulator to discharge */ + (void)cyhal_system_delay_ms(WLAN_CBUCK_DISCHARGE_MS); + + /* WIFI power on */ + ret = gpio_pin_set_dt(&config->wifi_reg_on_gpio, 1); + if (ret) { + return ret; + } + (void)cyhal_system_delay_ms(WLAN_POWER_UP_DELAY_MS); +#endif /* DT_INST_NODE_HAS_PROP(0, reg_on_gpios) */ + + return 0; +} + +int airoc_wifi_init_primary(const struct device *dev, whd_interface_t *interface, + whd_netif_funcs_t *netif_funcs, whd_buffer_funcs_t *buffer_if) +{ + int ret; + struct airoc_wifi_data *data = dev->data; + const struct airoc_wifi_config *config = dev->config; + + whd_sdio_config_t whd_sdio_config = { + .sdio_1bit_mode = WHD_FALSE, + .high_speed_sdio_clock = WHD_FALSE, + }; + +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + whd_oob_config_t oob_config = { + .host_oob_pin = (void *)&config->wifi_host_wake_gpio, + .dev_gpio_sel = DEFAULT_OOB_PIN, + .is_falling_edge = + (CY_WIFI_HOST_WAKE_IRQ_EVENT == GPIO_INT_TRIG_LOW) ? WHD_TRUE : WHD_FALSE, + .intr_priority = CY_WIFI_OOB_INTR_PRIORITY}; + whd_sdio_config.oob_config = oob_config; +#endif + + if (airoc_wifi_power_on(dev)) { + LOG_ERR("airoc_wifi_power_on retuens fail"); + return -ENODEV; + } + + if (!device_is_ready(config->sdhc_dev)) { + LOG_ERR("SDHC device is not ready"); + return -ENODEV; + } + + ret = sd_init(config->sdhc_dev, &data->card); + if (ret) { + return ret; + } + + /* Init SDIO functions */ + ret = sdio_init_func(&data->card, &data->sdio_func1, BACKPLANE_FUNCTION); + if (ret) { + LOG_ERR("sdio_enable_func BACKPLANE_FUNCTION, error: %x", ret); + return ret; + } + ret = sdio_init_func(&data->card, &data->sdio_func2, WLAN_FUNCTION); + if (ret) { + LOG_ERR("sdio_enable_func WLAN_FUNCTION, error: %x", ret); + return ret; + } + ret = sdio_set_block_size(&data->sdio_func1, SDIO_64B_BLOCK); + if (ret) { + LOG_ERR("Can't set block size for BACKPLANE_FUNCTION, error: %x", ret); + return ret; + } + ret = sdio_set_block_size(&data->sdio_func2, SDIO_64B_BLOCK); + if (ret) { + LOG_ERR("Can't set block size for WLAN_FUNCTION, error: %x", ret); + return ret; + } + + /* Init wifi host driver (whd) */ + cy_rslt_t whd_ret = whd_init(&data->whd_drv, &init_config_default, &resource_ops, buffer_if, + netif_funcs); + if (whd_ret == CY_RSLT_SUCCESS) { + whd_ret = whd_bus_sdio_attach(data->whd_drv, &whd_sdio_config, + (whd_sdio_t)&data->card); + + if (whd_ret == CY_RSLT_SUCCESS) { + whd_ret = whd_wifi_on(data->whd_drv, interface); + } + + if (whd_ret != CY_RSLT_SUCCESS) { + whd_deinit(*interface); + return -ENODEV; + } + } + return 0; +} + +/* + * Implement SDIO CMD52/53 wrappers + */ + +static struct sdio_func *airoc_wifi_get_sdio_func(struct sd_card *sd, whd_bus_function_t function) +{ + struct airoc_wifi_data *data = CONTAINER_OF(sd, struct airoc_wifi_data, card); + struct sdio_func *func[] = {&sd->func0, &data->sdio_func1, &data->sdio_func2}; + + if (function > WLAN_FUNCTION) { + return NULL; + } + + return func[function]; +} + +whd_result_t whd_bus_sdio_cmd52(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction, + whd_bus_function_t function, uint32_t address, uint8_t value, + sdio_response_needed_t response_expected, uint8_t *response) +{ + int ret; + struct sd_card *sd = whd_driver->bus_priv->sdio_obj; + struct sdio_func *func = airoc_wifi_get_sdio_func(sd, function); + + WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, cmd52); + + if (direction == BUS_WRITE) { + ret = sdio_rw_byte(func, address, value, response); + } else { + ret = sdio_read_byte(func, address, response); + } + WHD_BUS_STATS_CONDITIONAL_INCREMENT_VARIABLE(whd_driver->bus_priv, (ret != WHD_SUCCESS), + cmd52_fail); + + /* Possibly device might not respond to this cmd. So, don't check return value here */ + if ((ret != WHD_SUCCESS) && (address == SDIO_SLEEP_CSR)) { + return ret; + } + + CHECK_RETURN(ret); + return WHD_SUCCESS; +} + +whd_result_t whd_bus_sdio_cmd53(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction, + whd_bus_function_t function, sdio_transfer_mode_t mode, + uint32_t address, uint16_t data_size, uint8_t *data, + sdio_response_needed_t response_expected, uint32_t *response) +{ + whd_result_t ret; + struct sd_card *sd = whd_driver->bus_priv->sdio_obj; + struct sdio_func *func = airoc_wifi_get_sdio_func(sd, function); + + if (direction == BUS_WRITE) { + WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, cmd53_write); + ret = sdio_write_addr(func, address, data, data_size); + } else { + WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, cmd53_read); + ret = sdio_read_addr(func, address, data, data_size); + } + + WHD_BUS_STATS_CONDITIONAL_INCREMENT_VARIABLE( + whd_driver->bus_priv, ((ret != WHD_SUCCESS) && (direction == BUS_READ)), + cmd53_read_fail); + WHD_BUS_STATS_CONDITIONAL_INCREMENT_VARIABLE( + whd_driver->bus_priv, ((ret != WHD_SUCCESS) && (direction == BUS_WRITE)), + cmd53_write_fail); + + CHECK_RETURN(ret); + return WHD_SUCCESS; +} + +/* + * Implement SDIO Card interrupt + */ + +void whd_bus_sdio_irq_handler(const struct device *dev, int reason, const void *user_data) +{ + if (reason == SDHC_INT_SDIO) { + whd_driver_t whd_driver = (whd_driver_t)user_data; + + WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, sdio_intrs); + + /* call thread notify to wake up WHD thread */ + whd_thread_notify_irq(whd_driver); + } +} + +whd_result_t whd_bus_sdio_irq_register(whd_driver_t whd_driver) +{ + /* Nothing to do here, all handles by whd_bus_sdio_irq_enable function */ + return WHD_SUCCESS; +} + +whd_result_t whd_bus_sdio_irq_enable(whd_driver_t whd_driver, whd_bool_t enable) +{ + int ret; + struct sd_card *sd = whd_driver->bus_priv->sdio_obj; + + /* Enable/disable SDIO Card interrupts */ + if (enable) { + ret = sdhc_enable_interrupt(sd->sdhc, whd_bus_sdio_irq_handler, SDHC_INT_SDIO, + whd_driver); + } else { + ret = sdhc_disable_interrupt(sd->sdhc, SDHC_INT_SDIO); + } + return ret; +} + +/* + * Implement OOB functionality + */ + +void whd_bus_sdio_oob_irq_handler(const struct device *port, struct gpio_callback *cb, + gpio_port_pins_t pins) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + struct airoc_wifi_data *data = CONTAINER_OF(cb, struct airoc_wifi_data, host_oob_pin_cb); + + /* Get OOB pin info */ + const whd_oob_config_t *oob_config = &data->whd_drv->bus_priv->sdio_config.oob_config; + const struct gpio_dt_spec *host_oob_pin = oob_config->host_oob_pin; + + /* Check OOB state is correct */ + int expected_event = (oob_config->is_falling_edge == WHD_TRUE) ? 0 : 1; + + if (!(pins & BIT(host_oob_pin->pin)) || (gpio_pin_get_dt(host_oob_pin) != expected_event)) { + WPRINT_WHD_ERROR(("Unexpected interrupt event %d\n", expected_event)); + WHD_BUS_STATS_INCREMENT_VARIABLE(data->whd_drv->bus_priv, error_intrs); + return; + } + + WHD_BUS_STATS_INCREMENT_VARIABLE(data->whd_drv->bus_priv, oob_intrs); + + /* Call thread notify to wake up WHD thread */ + whd_thread_notify_irq(data->whd_drv); + +#endif /* DT_INST_NODE_HAS_PROP(0, wifi-host-wake-gpios) */ +} + +whd_result_t whd_bus_sdio_register_oob_intr(whd_driver_t whd_driver) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + int ret; + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); + struct airoc_wifi_data *data = dev->data; + + /* Get OOB pin info */ + const whd_oob_config_t *oob_config = &whd_driver->bus_priv->sdio_config.oob_config; + const struct gpio_dt_spec *host_oob_pin = oob_config->host_oob_pin; + + /* Check if OOB pin is ready */ + if (!gpio_is_ready_dt(host_oob_pin)) { + WPRINT_WHD_ERROR(("%s: Failed at gpio_is_ready_dt for host_oob_pin\n", __func__)); + return WHD_HAL_ERROR; + } + + /* Configure OOB pin as output */ + ret = gpio_pin_configure_dt(host_oob_pin, GPIO_INPUT); + if (ret != 0) { + WPRINT_WHD_ERROR(( + " %s: Failed at gpio_pin_configure_dt for host_oob_pin, result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } + + /* Initialize/add OOB pin callback */ + gpio_init_callback(&data->host_oob_pin_cb, whd_bus_sdio_oob_irq_handler, + BIT(host_oob_pin->pin)); + + ret = gpio_add_callback_dt(host_oob_pin, &data->host_oob_pin_cb); + if (ret != 0) { + WPRINT_WHD_ERROR( + ("%s: Failed at gpio_add_callback_dt for host_oob_pin, result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } +#endif /* DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) */ + + return WHD_SUCCESS; +} + +whd_result_t whd_bus_sdio_unregister_oob_intr(whd_driver_t whd_driver) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + int ret; + const whd_oob_config_t *oob_config = &whd_driver->bus_priv->sdio_config.oob_config; + + /* Disable OOB pin interrupts */ + ret = gpio_pin_interrupt_configure_dt(oob_config->host_oob_pin, GPIO_INT_DISABLE); + if (ret != 0) { + WPRINT_WHD_ERROR(("%s: Failed at gpio_pin_interrupt_configure_dt for host_oob_pin, " + "result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } +#endif /* DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) */ + return WHD_SUCCESS; +} + +whd_result_t whd_bus_sdio_enable_oob_intr(whd_driver_t whd_driver, whd_bool_t enable) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + int ret; + const whd_oob_config_t *oob_config = &whd_driver->bus_priv->sdio_config.oob_config; + uint32_t trig_conf = + (oob_config->is_falling_edge == WHD_TRUE) ? GPIO_INT_TRIG_LOW : GPIO_INT_TRIG_HIGH; + + /* Enable OOB pin interrupts */ + ret = gpio_pin_interrupt_configure_dt(oob_config->host_oob_pin, + GPIO_INT_ENABLE | GPIO_INT_EDGE | trig_conf); + if (ret != 0) { + WPRINT_WHD_ERROR(("%s: Failed at gpio_pin_interrupt_configure_dt for host_oob_pin, " + "result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } +#endif /* DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) */ + return WHD_SUCCESS; +} + +/* + * Implement WHD memory wrappers + */ + +void *whd_mem_malloc(size_t size) +{ + return k_malloc(size); +} + +void *whd_mem_calloc(size_t nitems, size_t size) +{ + return k_calloc(nitems, size); +} + +void whd_mem_free(void *ptr) +{ + k_free(ptr); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/drivers/wifi/infineon/airoc_wifi.c b/drivers/wifi/infineon/airoc_wifi.c new file mode 100644 index 000000000000000..c0c780822d8e664 --- /dev/null +++ b/drivers/wifi/infineon/airoc_wifi.c @@ -0,0 +1,772 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief AIROC Wi-Fi driver. + */ + +#define DT_DRV_COMPAT infineon_airoc_wifi + +#include +#include + +LOG_MODULE_REGISTER(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL); + +#ifndef AIROC_WIFI_TX_PACKET_POOL_COUNT +#define AIROC_WIFI_TX_PACKET_POOL_COUNT (10) +#endif + +#ifndef AIROC_WIFI_RX_PACKET_POOL_COUNT +#define AIROC_WIFI_RX_PACKET_POOL_COUNT (10) +#endif + +#ifndef AIROC_WIFI_PACKET_POOL_SIZE +#define AIROC_WIFI_PACKET_POOL_SIZE (1600) +#endif + +#define AIROC_WIFI_PACKET_POOL_COUNT \ + (AIROC_WIFI_TX_PACKET_POOL_COUNT + AIROC_WIFI_RX_PACKET_POOL_COUNT) + +#define AIROC_WIFI_WAIT_SEMA_MS (30 * 1000) +#define AIROC_WIFI_SCAN_TIMEOUT_MS (12 * 1000) + +/* AIROC private functions */ +static whd_result_t airoc_wifi_host_buffer_get(whd_buffer_t *buffer, whd_buffer_dir_t direction, + uint16_t size, uint32_t timeout_ms); +static void airoc_wifi_buffer_release(whd_buffer_t buffer, whd_buffer_dir_t direction); +static uint8_t *airoc_wifi_buffer_get_current_piece_data_pointer(whd_buffer_t buffer); +static uint16_t airoc_wifi_buffer_get_current_piece_size(whd_buffer_t buffer); +static whd_result_t airoc_wifi_buffer_set_size(whd_buffer_t buffer, unsigned short size); +static whd_result_t airoc_wifi_buffer_add_remove_at_front(whd_buffer_t *buffer, + int32_t add_remove_amount); +static void airoc_wifi_network_process_ethernet_data(whd_interface_t interface, + whd_buffer_t buffer); +int airoc_wifi_init_primary(const struct device *dev, whd_interface_t *interface, + whd_netif_funcs_t *netif_funcs, whd_buffer_funcs_t *buffer_if); + +/* Allocate network pool */ +NET_BUF_POOL_FIXED_DEFINE(airoc_pool, AIROC_WIFI_PACKET_POOL_COUNT, + AIROC_WIFI_PACKET_POOL_SIZE, 0, NULL); + +/* AIROC globals */ +static uint16_t ap_event_handler_index = 0xFF; + +/* Use global iface pointer to support any Ethernet driver */ +/* necessary for wifi callback functions */ +static struct net_if *airoc_wifi_iface; + +static whd_interface_t airoc_if; +static whd_interface_t airoc_sta_if; +static whd_interface_t airoc_ap_if; + +static const whd_event_num_t sta_link_events[] = { + WLC_E_LINK, WLC_E_DEAUTH_IND, WLC_E_DISASSOC_IND, + WLC_E_PSK_SUP, WLC_E_CSA_COMPLETE_IND, WLC_E_NONE}; + +static const whd_event_num_t ap_link_events[] = {WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND, + WLC_E_ASSOC_IND, WLC_E_REASSOC_IND, + WLC_E_AUTHORIZED, WLC_E_NONE}; + +static uint16_t sta_event_handler_index = 0xFF; +static void airoc_event_task(void); +static struct airoc_wifi_data airoc_wifi_data = {0}; + +static struct airoc_wifi_config airoc_wifi_config = { + .sdhc_dev = DEVICE_DT_GET(DT_INST_PARENT(0)), + .wifi_reg_on_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_reg_on_gpios, {0}), + .wifi_host_wake_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_host_wake_gpios, {0}), + .wifi_dev_wake_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_dev_wake_gpios, {0}), +}; + +static whd_buffer_funcs_t airoc_wifi_buffer_if_default = { + .whd_host_buffer_get = airoc_wifi_host_buffer_get, + .whd_buffer_release = airoc_wifi_buffer_release, + .whd_buffer_get_current_piece_data_pointer = + airoc_wifi_buffer_get_current_piece_data_pointer, + .whd_buffer_get_current_piece_size = airoc_wifi_buffer_get_current_piece_size, + .whd_buffer_set_size = airoc_wifi_buffer_set_size, + .whd_buffer_add_remove_at_front = airoc_wifi_buffer_add_remove_at_front, +}; + +static whd_netif_funcs_t airoc_wifi_netif_if_default = { + .whd_network_process_ethernet_data = airoc_wifi_network_process_ethernet_data, +}; + +K_MSGQ_DEFINE(airoc_wifi_msgq, sizeof(whd_event_header_t), 10, 4); +K_THREAD_STACK_DEFINE(airoc_wifi_event_stack, CONFIG_AIROC_WIFI_EVENT_TASK_STACK_SIZE); +static struct k_thread airoc_wifi_event_thread; + +struct airoc_wifi_event_t { + uint8_t is_ap_event; + uint32_t event_type; +}; + +/* + * AIROC Wi-Fi helper functions + */ +whd_interface_t airoc_wifi_get_whd_interface(void) +{ + return airoc_if; +} + +static void airoc_wifi_scan_cb_search(whd_scan_result_t **result_ptr, void *user_data, + whd_scan_status_t status) +{ + if (status == WHD_SCAN_ABORTED) { + k_sem_give(&airoc_wifi_data.sema_scan); + return; + } + + if (status == WHD_SCAN_COMPLETED_SUCCESSFULLY) { + k_sem_give(&airoc_wifi_data.sema_scan); + } else if ((status == WHD_SCAN_INCOMPLETE) && (user_data != NULL) && + ((**result_ptr).SSID.length > 0)) { + + if (strncmp(((whd_scan_result_t *)user_data)->SSID.value, (**result_ptr).SSID.value, + (**result_ptr).SSID.length) == 0) { + memcpy(user_data, *result_ptr, sizeof(whd_scan_result_t)); + } + } +} + +static int convert_whd_security_to_zephyr(whd_security_t security) +{ + int zephyr_security = WIFI_SECURITY_TYPE_UNKNOWN; + + switch (security) { + case WHD_SECURITY_OPEN: + zephyr_security = WIFI_SECURITY_TYPE_NONE; + break; + case WHD_SECURITY_WEP_PSK: + zephyr_security = WIFI_SECURITY_TYPE_WEP; + break; + + case WHD_SECURITY_WPA3_WPA2_PSK: + case WHD_SECURITY_WPA2_AES_PSK: + zephyr_security = WIFI_SECURITY_TYPE_PSK; + break; + + case WHD_SECURITY_WPA2_AES_PSK_SHA256: + zephyr_security = WIFI_SECURITY_TYPE_PSK_SHA256; + break; + + case WHD_SECURITY_WPA3_SAE: + zephyr_security = WIFI_SECURITY_TYPE_SAE; + break; + + case WHD_SECURITY_WPA_AES_PSK: + zephyr_security = WIFI_SECURITY_TYPE_WPA_PSK; + break; + + default: + if ((security & ENTERPRISE_ENABLED) != 0) { + zephyr_security = WIFI_SECURITY_TYPE_EAP; + } + break; + } + return zephyr_security; +} + +static void parse_scan_result(whd_scan_result_t *p_whd_result, struct wifi_scan_result *p_zy_result) +{ + if (p_whd_result->SSID.length != 0) { + p_zy_result->ssid_length = p_whd_result->SSID.length; + strncpy(p_zy_result->ssid, p_whd_result->SSID.value, p_whd_result->SSID.length); + p_zy_result->channel = p_whd_result->channel; + p_zy_result->security = convert_whd_security_to_zephyr(p_whd_result->security); + p_zy_result->rssi = (int8_t)p_whd_result->signal_strength; + p_zy_result->mac_length = 6; + memcpy(p_zy_result->mac, &p_whd_result->BSSID, 6); + } +} + +static void scan_callback(whd_scan_result_t **result_ptr, void *user_data, whd_scan_status_t status) +{ + struct airoc_wifi_data *data = user_data; + whd_scan_result_t whd_scan_result; + struct wifi_scan_result zephyr_scan_result; + + if (status == WHD_SCAN_COMPLETED_SUCCESSFULLY || status == WHD_SCAN_ABORTED) { + data->scan_rslt_cb(data->iface, 0, NULL); + data->scan_rslt_cb = NULL; + /* NOTE: It is complete of scan packet, do not need to clean result_ptr, + * WHD will release result_ptr buffer + */ + return; + } + + /* We recived scan data so process it */ + if ((result_ptr != NULL) && (*result_ptr != NULL)) { + memcpy(&whd_scan_result, *result_ptr, sizeof(whd_scan_result_t)); + parse_scan_result(&whd_scan_result, &zephyr_scan_result); + data->scan_rslt_cb(data->iface, 0, &zephyr_scan_result); + } + memset(*result_ptr, 0, sizeof(whd_scan_result_t)); +} + +/* + * Implement WHD network buffers functions + */ +static whd_result_t airoc_wifi_host_buffer_get(whd_buffer_t *buffer, whd_buffer_dir_t direction, + uint16_t size, uint32_t timeout_ms) +{ + ARG_UNUSED(direction); + ARG_UNUSED(timeout_ms); + struct net_buf *buf; + + buf = net_buf_alloc_len(&airoc_pool, size, K_NO_WAIT); + if (buf == NULL) { + return WHD_BUFFER_ALLOC_FAIL; + } + *buffer = buf; + return WHD_SUCCESS; +} + +static void airoc_wifi_buffer_release(whd_buffer_t buffer, whd_buffer_dir_t direction) +{ + CY_UNUSED_PARAMETER(direction); + (void)net_buf_destroy((struct net_buf *)buffer); +} + +static uint8_t *airoc_wifi_buffer_get_current_piece_data_pointer(whd_buffer_t buffer) +{ + CY_ASSERT(buffer != NULL); + struct net_buf *buf = (struct net_buf *)buffer; + + return (uint8_t *)buf->data; +} + +static uint16_t airoc_wifi_buffer_get_current_piece_size(whd_buffer_t buffer) +{ + CY_ASSERT(buffer != NULL); + struct net_buf *buf = (struct net_buf *)buffer; + + return (uint16_t)buf->size; +} + +static whd_result_t airoc_wifi_buffer_set_size(whd_buffer_t buffer, unsigned short size) +{ + CY_ASSERT(buffer != NULL); + struct net_buf *buf = (struct net_buf *)buffer; + + buf->size = size; + return CY_RSLT_SUCCESS; +} + +static whd_result_t airoc_wifi_buffer_add_remove_at_front(whd_buffer_t *buffer, + int32_t add_remove_amount) +{ + CY_ASSERT(buffer != NULL); + struct net_buf **buf = (struct net_buf **)buffer; + + if (add_remove_amount > 0) { + (*buf)->len = (*buf)->size; + (*buf)->data = net_buf_pull(*buf, add_remove_amount); + } else { + (*buf)->data = net_buf_push(*buf, -add_remove_amount); + (*buf)->len = (*buf)->size; + } + return WHD_SUCCESS; +} + +static int airoc_mgmt_send(const struct device *dev, struct net_pkt *pkt) +{ + struct airoc_wifi_data *data = dev->data; + cy_rslt_t ret; + size_t pkt_len = net_pkt_get_len(pkt); + struct net_buf *buf = NULL; + + /* Read the packet payload */ + if (net_pkt_read(pkt, data->frame_buf, pkt_len) < 0) { + LOG_ERR("net_pkt_read failed"); + return -EIO; + } + + /* Allocate Network Buffer from pool with Packet Length + Data Header */ + buf = net_buf_alloc_len(&airoc_pool, pkt_len + sizeof(data_header_t), K_NO_WAIT); + if (buf == NULL) { + return -EIO; + } + + /* Reserve the buffer Headroom for WHD Data header */ + net_buf_reserve(buf, sizeof(data_header_t)); + + /* Copy the buffer to network Buffer pointer */ + (void)memcpy(buf->data, data->frame_buf, pkt_len); + + /* Call WHD API to send out the Packet */ + ret = whd_network_send_ethernet_data(airoc_if, (void *)buf); + if (ret != CY_RSLT_SUCCESS) { + LOG_ERR("whd_network_send_ethernet_data failed"); +#if defined(CONFIG_NET_STATISTICS_WIFI) + data->stats.errors.tx++; +#endif + return -EIO; + } + +#if defined(CONFIG_NET_STATISTICS_WIFI) + data->stats.bytes.sent += pkt_len; + data->stats.pkts.tx++; +#endif + + return 0; +} + +static void airoc_wifi_network_process_ethernet_data(whd_interface_t interface, whd_buffer_t buffer) +{ + struct net_pkt *pkt; + uint8_t *data = whd_buffer_get_current_piece_data_pointer(interface->whd_driver, buffer); + uint32_t len = whd_buffer_get_current_piece_size(interface->whd_driver, buffer); + bool net_pkt_unref_flag = false; + + if ((airoc_wifi_iface != NULL) && net_if_flag_is_set(airoc_wifi_iface, NET_IF_UP)) { + + pkt = net_pkt_rx_alloc_with_buffer(airoc_wifi_iface, len, AF_UNSPEC, 0, K_NO_WAIT); + + if (pkt != NULL) { + if (net_pkt_write(pkt, data, len) < 0) { + LOG_ERR("Failed to write pkt"); + net_pkt_unref_flag = true; + } + + if ((net_pkt_unref_flag) || (net_recv_data(airoc_wifi_iface, pkt) < 0)) { + LOG_ERR("Failed to push received data"); + net_pkt_unref_flag = true; + } + } else { + LOG_ERR("Failed to get net buffer"); + } + } + + /* Release a packet buffer */ + airoc_wifi_buffer_release(buffer, WHD_NETWORK_RX); + +#if defined(CONFIG_NET_STATISTICS_WIFI) + airoc_wifi_data.stats.bytes.received += len; + airoc_wifi_data.stats.pkts.rx++; +#endif + + if (net_pkt_unref_flag) { + net_pkt_unref(pkt); +#if defined(CONFIG_NET_STATISTICS_WIFI) + airoc_wifi_data.stats.errors.rx++; +#endif + } +} + +static void *link_events_handler(whd_interface_t ifp, const whd_event_header_t *event_header, + const uint8_t *event_data, void *handler_user_data) +{ + ARG_UNUSED(ifp); + ARG_UNUSED(event_data); + ARG_UNUSED(handler_user_data); + + k_msgq_put(&airoc_wifi_msgq, event_header, K_FOREVER); + return NULL; +} + +static void airoc_event_task(void) +{ + whd_event_header_t event_header; + + while (1) { + k_msgq_get(&airoc_wifi_msgq, &event_header, K_FOREVER); + + switch ((whd_event_num_t)event_header.event_type) { + case WLC_E_LINK: + break; + + case WLC_E_DEAUTH_IND: + case WLC_E_DISASSOC_IND: + net_if_dormant_on(airoc_wifi_iface); + break; + + default: + break; + } + } +} + +static void airoc_mgmt_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct airoc_wifi_data *data = dev->data; + struct ethernet_context *eth_ctx = net_if_l2_data(iface); + + eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; + data->iface = iface; + airoc_wifi_iface = iface; + + /* Read WLAN MAC Address */ + if (whd_wifi_get_mac_address(airoc_sta_if, &airoc_sta_if->mac_addr) != WHD_SUCCESS) { + LOG_ERR("Failed to get mac address"); + } else { + (void)memcpy(&data->mac_addr, &airoc_sta_if->mac_addr, + sizeof(airoc_sta_if->mac_addr)); + } + + /* Assign link local address. */ + if (net_if_set_link_addr(iface, data->mac_addr, 6, NET_LINK_ETHERNET)) { + LOG_ERR("Failed to set link addr"); + } + + /* Initialize Ethernet L2 stack */ + ethernet_init(iface); + + /* Not currently connected to a network */ + net_if_dormant_on(iface); + + /* L1 network layer (physical layer) is up */ + net_if_carrier_on(data->iface); +} + +static int airoc_mgmt_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) +{ + struct airoc_wifi_data *data = dev->data; + + if (data->scan_rslt_cb != NULL) { + LOG_INF("Scan callback in progress"); + return -EINPROGRESS; + } + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + data->scan_rslt_cb = cb; + + /* Connect to the network */ + if (whd_wifi_scan(airoc_sta_if, params->scan_type, WHD_BSS_TYPE_ANY, &(data->ssid), NULL, + NULL, NULL, scan_callback, &(data->scan_result), data) != WHD_SUCCESS) { + LOG_ERR("Failed to start scan"); + k_sem_give(&data->sema_common); + return -EAGAIN; + } + + k_sem_give(&data->sema_common); + return 0; +} + +static int airoc_mgmt_connect(const struct device *dev, struct wifi_connect_req_params *params) +{ + struct airoc_wifi_data *data = (struct airoc_wifi_data *)dev->data; + whd_ssid_t ssid = {0}; + int ret = 0; + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + if (data->is_sta_connected) { + LOG_ERR("Already connected"); + ret = -EALREADY; + goto error; + } + + if (data->is_ap_up) { + LOG_ERR("Network interface is busy AP. Please first disable AP."); + ret = -EBUSY; + goto error; + } + + ssid.length = params->ssid_length; + memcpy(ssid.value, params->ssid, params->ssid_length); + + whd_scan_result_t scan_result; + whd_scan_result_t usr_result = {0}; + + usr_result.SSID.length = ssid.length; + memcpy(usr_result.SSID.value, ssid.value, ssid.length); + + if (whd_wifi_scan(airoc_sta_if, WHD_SCAN_TYPE_ACTIVE, WHD_BSS_TYPE_ANY, NULL, NULL, NULL, + NULL, airoc_wifi_scan_cb_search, &scan_result, + &(usr_result)) != WHD_SUCCESS) { + LOG_ERR("Failed start scan"); + ret = -EAGAIN; + goto error; + } + + if (k_sem_take(&airoc_wifi_data.sema_scan, K_MSEC(AIROC_WIFI_SCAN_TIMEOUT_MS)) != 0) { + whd_wifi_stop_scan(airoc_sta_if); + ret = -EAGAIN; + goto error; + } + + if (usr_result.security == 0) { + ret = -EAGAIN; + LOG_ERR("Could not scan device"); + goto error; + } + + /* Connect to the network */ + if (whd_wifi_join(airoc_sta_if, &usr_result.SSID, usr_result.security, params->psk, + params->psk_length) != WHD_SUCCESS) { + LOG_ERR("Failed to connect with network"); + + ret = -EAGAIN; + goto error; + } + +error: + if (ret < 0) { + net_if_dormant_on(data->iface); + } else { + net_if_dormant_off(data->iface); + data->is_sta_connected = true; +#if defined(CONFIG_NET_DHCPV4) + net_dhcpv4_restart(data->iface); +#endif /* defined(CONFIG_NET_DHCPV4) */ + } + + wifi_mgmt_raise_connect_result_event(data->iface, ret); + k_sem_give(&data->sema_common); + return ret; +} + +static int airoc_mgmt_disconnect(const struct device *dev) +{ + int ret = 0; + struct airoc_wifi_data *data = (struct airoc_wifi_data *)dev->data; + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + if (whd_wifi_leave(airoc_sta_if) != WHD_SUCCESS) { + k_sem_give(&data->sema_common); + ret = -EAGAIN; + } else { + data->is_sta_connected = false; + net_if_dormant_on(data->iface); + } + + wifi_mgmt_raise_disconnect_result_event(data->iface, ret); + k_sem_give(&data->sema_common); + + return ret; +} + +static void *airoc_wifi_ap_link_events_handler(whd_interface_t ifp, + const whd_event_header_t *event_header, + const uint8_t *event_data, void *handler_user_data) +{ + struct airoc_wifi_event_t airoc_event = { + .is_ap_event = 1, + .event_type = event_header->event_type + }; + + k_msgq_put(&airoc_wifi_msgq, &airoc_event, K_FOREVER); + + return NULL; +} + +static int airoc_mgmt_ap_enable(const struct device *dev, struct wifi_connect_req_params *params) +{ + struct airoc_wifi_data *data = dev->data; + whd_security_t security; + whd_ssid_t ssid; + uint8_t channel; + int ret = 0; + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + if (data->is_sta_connected) { + LOG_ERR("Network interface is busy in STA mode. Please first disconnect STA."); + ret = -EBUSY; + goto error; + } + + if (data->is_ap_up) { + LOG_ERR("Already AP is on - first disable"); + ret = -EAGAIN; + goto error; + } + + if (!data->second_interface_init) { + if (whd_add_secondary_interface(data->whd_drv, NULL, &airoc_ap_if) != + CY_RSLT_SUCCESS) { + LOG_ERR("Error Unable to bring up the whd secondary interface"); + ret = -EAGAIN; + goto error; + } + data->second_interface_init = true; + } + + ssid.length = params->ssid_length; + memcpy(ssid.value, params->ssid, ssid.length); + + /* make sure to set valid channels for 2G and 5G: + * - 2G channels from 1 to 11, + * - 5G channels from 36 to 165 + */ + if (((params->channel > 0) && (params->channel < 12)) || + ((params->channel > 35) && (params->channel < 166))) { + channel = params->channel; + } else { + channel = 1; + LOG_WRN("Discard of setting unsupported channel: %u (will set 1)", + params->channel); + } + + if (params->psk_length == 0) { + security = WHD_SECURITY_OPEN; + } else { + security = WHD_SECURITY_WPA2_AES_PSK; + } + + if (whd_wifi_init_ap(airoc_ap_if, &ssid, security, (const uint8_t *)params->psk, + params->psk_length, channel) != 0) { + LOG_ERR("Failed to init whd ap interface"); + ret = -EAGAIN; + goto error; + } + + if (whd_wifi_start_ap(airoc_ap_if) != 0) { + LOG_ERR("Failed to start whd ap interface"); + ret = -EAGAIN; + goto error; + } + + /* set event handler */ + if (whd_management_set_event_handler(airoc_ap_if, ap_link_events, + airoc_wifi_ap_link_events_handler, NULL, + &ap_event_handler_index) != 0) { + whd_wifi_stop_ap(airoc_ap_if); + ret = -EAGAIN; + goto error; + } + + data->is_ap_up = true; + airoc_if = airoc_ap_if; +error: + + k_sem_give(&data->sema_common); + return ret; +} + +#if defined(CONFIG_NET_STATISTICS_WIFI) +static int airoc_mgmt_wifi_stats(const struct device *dev, struct net_stats_wifi *stats) +{ + struct airoc_wifi_data *data = dev->data; + + stats->bytes.received = data->stats.bytes.received; + stats->bytes.sent = data->stats.bytes.sent; + stats->pkts.rx = data->stats.pkts.rx; + stats->pkts.tx = data->stats.pkts.tx; + stats->errors.rx = data->stats.errors.rx; + stats->errors.tx = data->stats.errors.tx; + stats->broadcast.rx = data->stats.broadcast.rx; + stats->broadcast.tx = data->stats.broadcast.tx; + stats->multicast.rx = data->stats.multicast.rx; + stats->multicast.tx = data->stats.multicast.tx; + stats->sta_mgmt.beacons_rx = data->stats.sta_mgmt.beacons_rx; + stats->sta_mgmt.beacons_miss = data->stats.sta_mgmt.beacons_miss; + + return 0; +} +#endif + +static int airoc_mgmt_ap_disable(const struct device *dev) +{ + cy_rslt_t whd_ret; + struct airoc_wifi_data *data = dev->data; + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + if (whd_wifi_deregister_event_handler(airoc_ap_if, ap_event_handler_index)) { + LOG_ERR("Can't whd_wifi_deregister_event_handler"); + } + + whd_ret = whd_wifi_stop_ap(airoc_ap_if); + if (whd_ret == CY_RSLT_SUCCESS) { + data->is_ap_up = false; + airoc_if = airoc_sta_if; + } else { + LOG_ERR("Can't stop wifi ap: %u", whd_ret); + } + + k_sem_give(&data->sema_common); + + if (whd_ret != CY_RSLT_SUCCESS) { + return -ENODEV; + } + + return 0; +} + +static int airoc_init(const struct device *dev) +{ + int ret; + cy_rslt_t whd_ret; + struct airoc_wifi_data *data = dev->data; + + k_tid_t tid = k_thread_create( + &airoc_wifi_event_thread, airoc_wifi_event_stack, + CONFIG_AIROC_WIFI_EVENT_TASK_STACK_SIZE, (k_thread_entry_t)airoc_event_task, NULL, + NULL, NULL, CONFIG_AIROC_WIFI_EVENT_TASK_PRIO, K_INHERIT_PERMS, K_NO_WAIT); + + if (!tid) { + LOG_ERR("ERROR spawning tx thread"); + return -EAGAIN; + } + k_thread_name_set(tid, "airoc_event"); + + whd_ret = airoc_wifi_init_primary(dev, &airoc_sta_if, &airoc_wifi_netif_if_default, + &airoc_wifi_buffer_if_default); + if (whd_ret != CY_RSLT_SUCCESS) { + LOG_ERR("airoc_wifi_init_primary failed ret = %d \r\n", whd_ret); + return -EAGAIN; + } + airoc_if = airoc_sta_if; + + whd_ret = whd_management_set_event_handler(airoc_sta_if, sta_link_events, + link_events_handler, NULL, &sta_event_handler_index); + if (whd_ret != CY_RSLT_SUCCESS) { + LOG_ERR("whd_management_set_event_handler failed ret = %d \r\n", whd_ret); + return -EAGAIN; + } + + ret = k_sem_init(&data->sema_common, 1, 1); + if (ret != 0) { + LOG_ERR("k_sem_init(sema_common) failure"); + return ret; + } + + ret = k_sem_init(&data->sema_scan, 0, 1); + if (ret != 0) { + LOG_ERR("k_sem_init(sema_scan) failure"); + return ret; + } + + return 0; +} + +static const struct wifi_mgmt_ops airoc_wifi_mgmt = { + .scan = airoc_mgmt_scan, + .connect = airoc_mgmt_connect, + .disconnect = airoc_mgmt_disconnect, + .ap_enable = airoc_mgmt_ap_enable, + .ap_disable = airoc_mgmt_ap_disable, +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + .get_stats = airoc_mgmt_wifi_stats, +#endif +}; + +static const struct net_wifi_mgmt_offload airoc_api = { + .wifi_iface.iface_api.init = airoc_mgmt_init, + .wifi_iface.send = airoc_mgmt_send, + .wifi_mgmt_api = &airoc_wifi_mgmt, +}; + +NET_DEVICE_DT_INST_DEFINE(0, airoc_init, NULL, &airoc_wifi_data, &airoc_wifi_config, + CONFIG_WIFI_INIT_PRIORITY, &airoc_api, ETHERNET_L2, + NET_L2_GET_CTX_TYPE(ETHERNET_L2), WHD_LINK_MTU); diff --git a/drivers/wifi/infineon/airoc_wifi.h b/drivers/wifi/infineon/airoc_wifi.h new file mode 100644 index 000000000000000..648423ab109a104 --- /dev/null +++ b/drivers/wifi/infineon/airoc_wifi.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +struct airoc_wifi_data { + struct sd_card card; + struct sdio_func sdio_func1; + struct sdio_func sdio_func2; + struct net_if *iface; + bool second_interface_init; + bool is_ap_up; + bool is_sta_connected; + uint8_t mac_addr[6]; + scan_result_cb_t scan_rslt_cb; + whd_ssid_t ssid; + whd_scan_result_t scan_result; + struct k_sem sema_common; + struct k_sem sema_scan; +#if defined(CONFIG_NET_STATISTICS_WIFI) + struct net_stats_wifi stats; +#endif + whd_driver_t whd_drv; + struct gpio_callback host_oob_pin_cb; + uint8_t frame_buf[NET_ETH_MAX_FRAME_SIZE]; +}; + +struct airoc_wifi_config { + const struct device *sdhc_dev; + struct gpio_dt_spec wifi_reg_on_gpio; + struct gpio_dt_spec wifi_host_wake_gpio; + struct gpio_dt_spec wifi_dev_wake_gpio; +}; + +/** + * \brief This function returns pointer type to handle instance + * of whd interface (whd_interface_t) which allocated in + * Zephyr AIROC driver (drivers/wifi/infineon/airoc_wifi.c) + */ + +whd_interface_t airoc_wifi_get_whd_interface(void); diff --git a/drivers/wifi/infineon/cybsp.h b/drivers/wifi/infineon/cybsp.h new file mode 100644 index 000000000000000..dfa23ffbae53f6e --- /dev/null +++ b/drivers/wifi/infineon/cybsp.h @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This is enpty/stub file used in WHD */ diff --git a/dts/bindings/wifi/infineon,airoc-wifi.yaml b/dts/bindings/wifi/infineon,airoc-wifi.yaml new file mode 100644 index 000000000000000..9c93b238a4edbe7 --- /dev/null +++ b/dts/bindings/wifi/infineon,airoc-wifi.yaml @@ -0,0 +1,50 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: | + AIROC Wi-Fi Connectivity. + + Example of enabling AIROC Wi-Fi device (for SDIO): + &sdhc0 { + status = "okay"; + + /* SDIO pins */ + pinctrl-0 = <&p2_4_sdio_cmd &p2_5_sdio_clk &p2_0_sdio_data0 + &p2_1_sdio_data1 &p2_2_sdio_data2 &p2_3_sdio_data3>; + pinctrl-names = "default"; + + /* Wifi configuration */ + airoc-wifi { + status = "okay"; + compatible = "infineon,airoc-wifi-sdio"; + + /* Wi-Fi control gpios */ + wifi-reg-on-gpios = <&gpio_prt2 6 GPIO_ACTIVE_HIGH>; + wifi-host-wake-gpios = <&gpio_prt0 4 GPIO_ACTIVE_HIGH>; + }; + }; + +compatible: "infineon,airoc-wifi" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + wifi-reg-on-gpios: + description: | + Power-up/down gpio to control the internal regulators used + by the WiFi section of AIROC Wi-Fi device. + type: phandle-array + + wifi-host-wake-gpios: + description: | + Host wake-up gpio. Signal from the AIROC Wi-Fi device + to the host indicating that the device requires attention. + type: phandle-array + + wifi-dev-wake-gpios: + description: | + WiFi device wake-up gpio. Signal from the host to the + AIROC Wi-Fi device indicating that the host requires attention. + type: phandle-array diff --git a/modules/hal_infineon/CMakeLists.txt b/modules/hal_infineon/CMakeLists.txt index 1db3cf57a6af3b2..27dbd71897f63f8 100644 --- a/modules/hal_infineon/CMakeLists.txt +++ b/modules/hal_infineon/CMakeLists.txt @@ -36,6 +36,11 @@ if (CONFIG_SOC_FAMILY_INFINEON_CAT1A) add_subdirectory(abstraction-rtos) endif() +## Add Wi-Fi assets for AIROC devices +if (CONFIG_WIFI_AIROC) + add_subdirectory(wifi-host-driver) +endif() + ## Add BT assets for AIROC devices if (CONFIG_BT_AIROC) add_subdirectory(btstack-integration) diff --git a/modules/hal_infineon/Kconfig b/modules/hal_infineon/Kconfig index 83d24bfacd5ca1e..af92b98b3dc492e 100644 --- a/modules/hal_infineon/Kconfig +++ b/modules/hal_infineon/Kconfig @@ -72,7 +72,7 @@ config USE_INFINEON_WDT Enable WATCHDOG TIMER (WDT) HAL module driver for Infineon devices -config ABSTRACTION_RTOS_COMPONENT_ZEPHYR +config USE_INFINEON_ABSTRACTION_RTOS bool "Abstraction RTOS component (Zephyr support)" help Enable Abstraction RTOS component with Zephyr support diff --git a/modules/hal_infineon/abstraction-rtos/CMakeLists.txt b/modules/hal_infineon/abstraction-rtos/CMakeLists.txt index cd61908659f2f5a..6b2b0e6449f8e50 100644 --- a/modules/hal_infineon/abstraction-rtos/CMakeLists.txt +++ b/modules/hal_infineon/abstraction-rtos/CMakeLists.txt @@ -5,7 +5,7 @@ zephyr_include_directories(${ZEPHYR_HAL_INFINEON_MODULE_DIR}/abstraction-rtos/include) # Enable Zephyr support -zephyr_include_directories_ifdef(CONFIG_ABSTRACTION_RTOS_COMPONENT_ZEPHYR +zephyr_include_directories_ifdef(CONFIG_USE_INFINEON_ABSTRACTION_RTOS include/COMPONENT_ZEPHYR) -zephyr_library_sources_ifdef(CONFIG_ABSTRACTION_RTOS_COMPONENT_ZEPHYR +zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_ABSTRACTION_RTOS source/COMPONENT_ZEPHYR/cyabs_rtos_zephyr.c) diff --git a/modules/hal_infineon/wifi-host-driver/CMakeLists.txt b/modules/hal_infineon/wifi-host-driver/CMakeLists.txt new file mode 100644 index 000000000000000..afdb147676d6a5e --- /dev/null +++ b/modules/hal_infineon/wifi-host-driver/CMakeLists.txt @@ -0,0 +1,216 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +set(hal_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}) +set(hal_wifi_dir ${hal_dir}/wifi-host-driver) +set(hal_wifi_dir_resources ${hal_dir}/wifi-host-driver/WiFi_Host_Driver/resources) + +set(hal_blobs_dir ${hal_dir}/zephyr/blobs/img/whd/resources) +set(blob_gen_dir ${ZEPHYR_BINARY_DIR}/include/generated) + +set(cyw43xx_fw_bin_gen_inc ${blob_gen_dir}/cyw43xx_fw_blob.inc) +set(cyw43xx_clm_bin_gen_inc ${blob_gen_dir}/cyw43xx_clm_blob.inc) + +######################################################################################### +# Wi-Fi Host driver +######################################################################################### +if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + zephyr_compile_definitions(WLAN_MFG_FIRMWARE) +endif() + +# Add WHD includes +zephyr_include_directories(${hal_wifi_dir}) +zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/inc) +zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/src) +zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/src/include) +zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/resources/resource_imp) + +# src +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_ap.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_buffer_api.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_cdc_bdc.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_chip.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_chip_constants.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_clm.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_debug.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_events.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_logging.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_management.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_network_if.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_resource_if.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_sdpcm.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_thread.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_utils.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_wifi.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_wifi_api.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_wifi_p2p.c) + +# src/bus_protocols +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus_common.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus_sdio_protocol.c) + +# resources/resource_imp +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/resources/resource_imp/whd_resources.c) + +# CYW43012 firmware +if(CONFIG_CYW43012 AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/resources/firmware/COMPONENT_43012) + + # firmware + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43012/43012C0-mfgtest.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43012/43012C0-mfgtest_bin.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43012/43012C0.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43012/43012C0_bin.c) + endif() +endif() + +# CYW4343W firmware +if(CONFIG_CYW4343W AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/firmware/COMPONENT_4343W) + + # firmware + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_4343W/4343WA1-mfgtest.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_4343W/4343WA1-mfgtest_bin.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_4343W/4343WA1.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_4343W/4343WA1_bin.c) + endif() +endif() + +# CYW43438 firmware/clm +if(CONFIG_CYW43438 AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/firmware/COMPONENT_43438) + zephyr_include_directories(${hal_wifi_dir_resources}/clm/COMPONENT_43438) + + # firmware/clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43438/43438A1-mfgtest.bin) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43438/43438A1-mfgtest.clm_blob) + + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43438/43438A1-mfgtest_bin.c) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43438/43438A1-mfgtest_clm_blob.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43438/43438A1.bin) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43438/43438A1.clm_blob) + + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43438/43438A1_bin.c) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43438/43438A1_clm_blob.c) + endif() + +endif() + +# CYW43439 firmware +if(CONFIG_CYW43439 AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/firmware/COMPONENT_43439) + + # firmware + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43439/43439A0-mfgtest.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43439/43439A0-mfgtest_bin.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43439/43439A0.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43439/43439A0_bin.c) + endif() +endif() + +# CYW4373 firmware +if(CONFIG_CYW4373 AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/firmware/COMPONENT_4373) + + # firmware + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_4373/4373A0-mfgtest.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_4373/4373A0-mfgtest_bin.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_4373/4373A0.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_4373/4373A0_bin.c) + endif() +endif() + + +# CYW43012_MURATA_1LV clm/nvram +if(CONFIG_CYW43012_MURATA_1LV AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/resources/clm/COMPONENT_43012) + + # clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43012/43012C0-mfgtest.clm_blob) + + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43012/43012C0-mfgtest_clm_blob.c) + else() + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43012/43012C0.clm_blob) + + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43012/43012C0_clm_blob.c) + endif() + + # nvram + zephyr_include_directories(${hal_wifi_dir_resources}/nvram/COMPONENT_43012/COMPONENT_MURATA-1LV) +endif() + +# CYW4343W_MURATA_1DX clm/nvram +if(CONFIG_CYW4343W_MURATA_1DX AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/clm/COMPONENT_4343W) + + # clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_4343W/4343WA1-mfgtest.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_4343W/4343WA1-mfgtest_clm_blob.c) + else() + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_4343W/4343WA1.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_4343W/4343WA1_clm_blob.c) + endif() + + # nvram + zephyr_include_directories(${hal_wifi_dir_resources}/nvram/COMPONENT_4343W/COMPONENT_MURATA-1DX) +endif() + +# CYW43439_MURATA_1YN +if(CONFIG_CYW43439_MURATA_1YN AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/clm/COMPONENT_43439) + + # clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43439/43439A0-mfgtest.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43439/43439A0-mfgtest_clm_blob.c) + else() + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43439/43439A0.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43439/43439A0_clm_blob.c) + endif() + + # nvram + zephyr_include_directories(${hal_wifi_dir_resources}/nvram/COMPONENT_43439/COMPONENT_MURATA-1YN) +endif() + +# CYW4373_STERLING_LWB5PLUS +if(CONFIG_CYW4373_STERLING_LWB5PLUS AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus) + + # clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/4373A0-mfgtest.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/4373A0-mfgtest_clm_blob.c) + else() + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/4373A0.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/4373A0_clm_blob.c) + endif() + + # nvram + zephyr_include_directories_ifdef(${hal_wifi_dir_resources}/nvram/COMPONENT_4373/COMPONENT_STERLING-LWB5plus) +endif() + +# generate FW inc_blob from fw_bin +if(EXISTS ${cyw43xx_fw_bin}) + message(INFO " generate include of blob FW file: ${cyw43xx_fw_bin}") + generate_inc_file_for_target(app ${cyw43xx_fw_bin} ${cyw43xx_fw_bin_gen_inc}) +endif() + +# generate CLM inc_blob from clm_bin +if(EXISTS ${cyw43xx_clm_bin}) + message(INFO " generate include of blob CLM file: ${cyw43xx_clm_bin}") + generate_inc_file_for_target(app ${cyw43xx_clm_bin} ${cyw43xx_clm_bin_gen_inc}) +endif() diff --git a/samples/net/wifi/boards/cy8cproto_062_4343w.conf b/samples/net/wifi/boards/cy8cproto_062_4343w.conf new file mode 100644 index 000000000000000..943db317fadc422 --- /dev/null +++ b/samples/net/wifi/boards/cy8cproto_062_4343w.conf @@ -0,0 +1,3 @@ +CONFIG_NET_IF_MAX_IPV4_COUNT=2 +CONFIG_NET_MGMT_EVENT_QUEUE_TIMEOUT=20 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 diff --git a/tests/drivers/build_all/modem/testcase.yaml b/tests/drivers/build_all/modem/testcase.yaml index 8b42363b4ff83a1..89abfbd79dfe2d6 100644 --- a/tests/drivers/build_all/modem/testcase.yaml +++ b/tests/drivers/build_all/modem/testcase.yaml @@ -63,7 +63,9 @@ tests: - CONFIG_UART_MUX=y drivers.modem.esp_at.build: extra_args: CONF_FILE=modem_esp_at.conf - platform_exclude: ip_k66f + platform_exclude: + - ip_k66f + - cy8cproto_062_4343w filter: CONFIG_SERIAL min_ram: 36 drivers.modem.esp_at.async.build: diff --git a/west.yml b/west.yml index 9326bd857222d38..6b4391cb3806cb0 100644 --- a/west.yml +++ b/west.yml @@ -168,7 +168,7 @@ manifest: groups: - hal - name: hal_infineon - revision: 815e84a5150f95627201f192779a0180d5052de7 + revision: 69c883d3bd9fac8a18dd8384624b8c472a68d06f path: modules/hal/infineon groups: - hal From d8606727df5e3fc9754de87dc0dcfc786f87e1a5 Mon Sep 17 00:00:00 2001 From: Nazar Palamar Date: Wed, 4 Oct 2023 09:28:04 +0300 Subject: [PATCH 0038/1049] boards: arm: cy8cproto-062-4343w: enable WIFI feature Enable WIFI feature for cy8cproto-062-4343w board. Signed-off-by: Nazar Palamar --- .../arm/cy8cproto_062_4343w/Kconfig.defconfig | 19 ++++++++- .../cy8cproto_062_4343w-common.dtsi | 4 ++ .../cy8cproto_062_4343w-pinctrl.dtsi | 41 ++++++++++++++++++- .../cy8cproto_062_4343w.dts | 22 +++++++++- .../cy8cproto_062_4343w.yaml | 4 ++ .../cy8cproto_062_4343w_defconfig | 3 ++ 6 files changed, 89 insertions(+), 4 deletions(-) diff --git a/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig b/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig index 14c47a06e584d0c..ba117ace6655297 100644 --- a/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig +++ b/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig @@ -10,8 +10,8 @@ config BOARD if WIFI || BT -# Select CYW43XXX part and module -choice CYW43XXX_PART +# Select AIROC part and module +choice AIROC_PART default CYW4343W endchoice @@ -21,6 +21,16 @@ endchoice endif # WIFI || BT +if WIFI + +config WIFI_AIROC + default y + +# Enable L2 Ethernet +config NET_L2_ETHERNET + default y + +endif # WIFI if BT @@ -38,4 +48,9 @@ endchoice endif # BT +# Heap Pool Size +config HEAP_MEM_POOL_SIZE + default 15000 if WIFI + default 4096 + endif # BOARD_CY8CPROTO_062_4343W diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi index 3676cdbb471e398..75012f88ffc7a52 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi @@ -34,6 +34,10 @@ status = "okay"; }; +&gpio_prt2 { + status = "okay"; +}; + &gpio_prt3 { status = "okay"; }; diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi index d86f9b67bfa7566..14202d8fbcdf95a 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Rtone. + * Copyright (c) 2023 Cypress Semiconductor Corporation. * SPDX-License-Identifier: Apache-2.0 */ @@ -28,3 +28,42 @@ &p5_0_scb5_uart_rx { input-enable; }; + +&pinctrl { + /* Configure pin control bias mode for SDIO */ + p2_5_sdio_clk: p2_5_sdio_clk { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_4_sdio_cmd: p2_4_sdio_cmd { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_0_sdio_data0: p2_0_sdio_data0 { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_1_sdio_data1: p2_1_sdio_data1 { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_2_sdio_data2: p2_2_sdio_data2 { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_3_sdio_data3: p2_3_sdio_data3 { + pinmux = ; + drive-push-pull; + input-enable; + }; +}; diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts index 4d9149b198aaf74..cc793184b143e63 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts @@ -17,6 +17,7 @@ uart-5 = &uart5; i2c-0 = &i2c3; watchdog0 = &watchdog0; + sdhc0 = &sdhc0; }; chosen { @@ -50,7 +51,7 @@ uart2: &scb2 { current-speed = <115200>; - /* HCI-UART pins*/ + /* HCI-UART pins */ pinctrl-0 = <&p3_1_scb2_uart_tx &p3_0_scb2_uart_rx &p3_2_scb2_uart_rts &p3_3_scb2_uart_cts>; pinctrl-names = "default"; @@ -68,6 +69,25 @@ uart2: &scb2 { }; }; +&sdhc0 { + status = "okay"; + + /* SDIO pins */ + pinctrl-0 = <&p2_4_sdio_cmd &p2_5_sdio_clk &p2_0_sdio_data0 + &p2_1_sdio_data1 &p2_2_sdio_data2 &p2_3_sdio_data3>; + pinctrl-names = "default"; + + /* Wi-Fi configuration */ + airoc-wifi { + status = "okay"; + compatible = "infineon,airoc-wifi"; + + /* Wi-Fi control gpios */ + wifi-reg-on-gpios = <&gpio_prt2 6 GPIO_ACTIVE_HIGH>; + wifi-host-wake-gpios = <&gpio_prt0 4 GPIO_ACTIVE_HIGH>; + }; +}; + /* System clock configuration */ &fll0 { status = "okay"; diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml index 36d08b2a4d0576f..b6d565772093301 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml @@ -14,6 +14,10 @@ toolchain: - gnuarmemb supported: - adc + - bluetooth + - wifi + - airoc + - cyw4343w - counter - gpio - uart diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig index c36ce13e1a878f7..3dd8e0eac78a017 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig @@ -29,3 +29,6 @@ CONFIG_GPIO=y # Enable clock controller CONFIG_CLOCK_CONTROL=y + +# Main Stack Size +CONFIG_MAIN_STACK_SIZE=2048 From 950e25578a539d47a4619e92f0ded2080ab65b53 Mon Sep 17 00:00:00 2001 From: Bernt Johan Damslora Date: Mon, 2 Oct 2023 17:06:54 +0200 Subject: [PATCH 0039/1049] drivers: mfd: npm6001: Add separate initialization priority Enables setting the initialization priority of the nPM6001 independently from other MFDs. Signed-off-by: Bernt Johan Damslora --- drivers/mfd/Kconfig.npm6001 | 10 ++++++++++ drivers/mfd/mfd_npm6001.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/Kconfig.npm6001 b/drivers/mfd/Kconfig.npm6001 index 10360aa2347c14c..be549ff96c11b33 100644 --- a/drivers/mfd/Kconfig.npm6001 +++ b/drivers/mfd/Kconfig.npm6001 @@ -8,3 +8,13 @@ config MFD_NPM6001 select I2C help Enable the Nordic nPM6001 PMIC multi-function device driver + +if MFD_NPM6001 + +config MFD_NPM6001_INIT_PRIORITY + int "nPM6001 MFD initialization priority" + default MFD_INIT_PRIORITY + help + Multi-function device initialization priority for nPM6001. + +endif # MFD_NPM6001 diff --git a/drivers/mfd/mfd_npm6001.c b/drivers/mfd/mfd_npm6001.c index 4bed77c49587b6e..1a0777918162640 100644 --- a/drivers/mfd/mfd_npm6001.c +++ b/drivers/mfd/mfd_npm6001.c @@ -87,6 +87,6 @@ static int mfd_npm6001_init(const struct device *dev) }; \ \ DEVICE_DT_INST_DEFINE(inst, mfd_npm6001_init, NULL, NULL, &config##inst, POST_KERNEL, \ - CONFIG_MFD_INIT_PRIORITY, NULL); + CONFIG_MFD_NPM6001_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(MFD_NPM6001_DEFINE) From 5fc7304878eb1ffeeb74de0b4821b4680927f988 Mon Sep 17 00:00:00 2001 From: Bernt Johan Damslora Date: Mon, 2 Oct 2023 17:10:00 +0200 Subject: [PATCH 0040/1049] drivers: mfd: npm1300: Add separate initialization priority Enables setting the initialization priority of the nPM1300 independently from other MFDs. Signed-off-by: Bernt Johan Damslora --- drivers/mfd/Kconfig.npm1300 | 7 +++++++ drivers/mfd/Kconfig.npm6001 | 5 +---- drivers/mfd/mfd_npm1300.c | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/Kconfig.npm1300 b/drivers/mfd/Kconfig.npm1300 index cc3eb0ef30332ac..506508bd9021033 100644 --- a/drivers/mfd/Kconfig.npm1300 +++ b/drivers/mfd/Kconfig.npm1300 @@ -8,3 +8,10 @@ config MFD_NPM1300 select I2C help Enable the Nordic nPM1300 PMIC multi-function device driver + +config MFD_NPM1300_INIT_PRIORITY + int "nPM1300 MFD initialization priority" + default MFD_INIT_PRIORITY + depends on MFD_NPM1300 + help + Multi-function device initialization priority for nPM1300. diff --git a/drivers/mfd/Kconfig.npm6001 b/drivers/mfd/Kconfig.npm6001 index be549ff96c11b33..b81c942f2d63c2c 100644 --- a/drivers/mfd/Kconfig.npm6001 +++ b/drivers/mfd/Kconfig.npm6001 @@ -9,12 +9,9 @@ config MFD_NPM6001 help Enable the Nordic nPM6001 PMIC multi-function device driver -if MFD_NPM6001 - config MFD_NPM6001_INIT_PRIORITY int "nPM6001 MFD initialization priority" default MFD_INIT_PRIORITY + depends on MFD_NPM6001 help Multi-function device initialization priority for nPM6001. - -endif # MFD_NPM6001 diff --git a/drivers/mfd/mfd_npm1300.c b/drivers/mfd/mfd_npm1300.c index 678d3572a24d540..ef06b6da7f000f9 100644 --- a/drivers/mfd/mfd_npm1300.c +++ b/drivers/mfd/mfd_npm1300.c @@ -297,6 +297,6 @@ int mfd_npm1300_remove_callback(const struct device *dev, struct gpio_callback * }; \ \ DEVICE_DT_INST_DEFINE(inst, mfd_npm1300_init, NULL, &data_##inst, &config##inst, \ - POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL); + POST_KERNEL, CONFIG_MFD_NPM1300_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(MFD_NPM1300_DEFINE) From 29a67338d12a298baeb85c68a53d255e1ddf2fa3 Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Thu, 26 Oct 2023 13:24:13 +0200 Subject: [PATCH 0041/1049] bluetooth: id: fix uninitialized RPA for non-default identities This change fixes uninitialized RPA values for advertising sets of non-default Bluetooth identities. The regression has been introduced in the following commit: https://github.com/zephyrproject-rtos/zephyr/commit/8d6b206064c915316245616a718ae29eb157a717 The follow-up fix for the default Bluetooth identity has been introduced in a separate commit: https://github.com/zephyrproject-rtos/zephyr/commit/88c20b9cddf0bd5e5d6c163611b2563f9266be6f Non-default Bluetooth identities can be loaded from the Settings subsystem. In this case, RPAs of related advertising sets to these identities are left uninitialized as the bt_id_create() function context is not executed. As a result, the RPA is not created for advertising sets of non-default Bluetooth identities, and the advertising is started with the 00:00:00:00:00:00 address. Signed-off-by: Kamil Piszczek --- subsys/bluetooth/host/id.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index 4bbc5e23192a233..cf07418dd020140 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -2064,7 +2064,9 @@ int bt_id_init(void) int err; #if defined(CONFIG_BT_PRIVACY) - bt_addr_copy(&bt_dev.rpa[BT_ID_DEFAULT], BT_ADDR_NONE); + for (uint8_t id = 0U; id < ARRAY_SIZE(bt_dev.rpa); id++) { + bt_addr_copy(&bt_dev.rpa[id], BT_ADDR_NONE); + } k_work_init_delayable(&bt_dev.rpa_update, rpa_timeout); #endif From 069bd8376c125cd7229d36756d2c92464eefcb4f Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Fri, 27 Oct 2023 09:14:23 +0200 Subject: [PATCH 0042/1049] tests: bsim: bluetooth: host: privacy: peripheral: test after reboot Extended the scope of the BabbleSim test for the Bluetooth test under the host/privacy/peripheral category. The tests ensures correct RPA advertising after the system a reboot when the Bluetooth identities are preloaded from the Settings subsystem. Signed-off-by: Kamil Piszczek --- .../host/privacy/peripheral/prj.conf | 12 ++++++ .../host/privacy/peripheral/src/dut.c | 43 ++++++++++++++----- .../host/privacy/peripheral/src/tester.c | 6 +++ .../peripheral/test_scripts/run_test.sh | 23 +++++++++- 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/prj.conf b/tests/bsim/bluetooth/host/privacy/peripheral/prj.conf index bd5bf844bd08c14..9113a44382bf74e 100644 --- a/tests/bsim/bluetooth/host/privacy/peripheral/prj.conf +++ b/tests/bsim/bluetooth/host/privacy/peripheral/prj.conf @@ -8,4 +8,16 @@ CONFIG_BT_EXT_ADV=y CONFIG_BT_PRIVACY=y CONFIG_BT_RPA_TIMEOUT=10 CONFIG_BT_EXT_ADV_MAX_ADV_SET=3 +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=3 CONFIG_BT_ID_MAX=3 + +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y +CONFIG_BT_SETTINGS=y + +# Increased stack due to settings API usage +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/src/dut.c b/tests/bsim/bluetooth/host/privacy/peripheral/src/dut.c index 3000a3e0f9e9b37..9d72b5368b29036 100644 --- a/tests/bsim/bluetooth/host/privacy/peripheral/src/dut.c +++ b/tests/bsim/bluetooth/host/privacy/peripheral/src/dut.c @@ -13,9 +13,13 @@ #include #include #include +#include #include "common/bt_str.h" +#define ID_A_INDEX 1 +#define ID_B_INDEX 2 + #define ADV_SET_INDEX_ONE 0x00 #define ADV_SET_INDEX_TWO 0x01 #define ADV_SET_INDEX_THREE 0x02 @@ -66,8 +70,7 @@ static void create_adv(struct bt_le_ext_adv **adv, int id) void start_advertising(void) { int err; - int id_a; - int id_b; + size_t bt_id_count; /* Enable bluetooth */ err = bt_enable(NULL); @@ -75,24 +78,44 @@ void start_advertising(void) FAIL("Failed to enable bluetooth (err %d\n)", err); } - id_a = bt_id_create(NULL, NULL); - if (id_a < 0) { - FAIL("bt_id_create id_a failed (err %d)\n", id_a); + err = settings_load(); + if (err) { + FAIL("Failed to enable settings (err %d\n)", err); + } + + bt_id_get(NULL, &bt_id_count); + if (bt_id_count == 1) { + int id_a; + int id_b; + + printk("No extra identity found in settings, creating new ones...\n"); + + id_a = bt_id_create(NULL, NULL); + if (id_a != ID_A_INDEX) { + FAIL("bt_id_create id_a failed (err %d)\n", id_a); + } + + id_b = bt_id_create(NULL, NULL); + if (id_b != ID_B_INDEX) { + FAIL("bt_id_create id_b failed (err %d)\n", id_b); + } + } else { + printk("Extra identities loaded from settings\n"); } - id_b = bt_id_create(NULL, NULL); - if (id_b < 0) { - FAIL("bt_id_create id_b failed (err %d)\n", id_b); + bt_id_get(NULL, &bt_id_count); + if (bt_id_count != CONFIG_BT_ID_MAX) { + FAIL("bt_id_get returned incorrect number of identities %u\n", bt_id_count); } for (int i = 0; i < CONFIG_BT_EXT_ADV_MAX_ADV_SET; i++) { if (i != ADV_SET_INDEX_THREE) { /* Create advertising set 1 and 2 with same id */ - create_adv(&adv_set[i], id_a); + create_adv(&adv_set[i], ID_A_INDEX); } else { /* Create advertising set 3 with different id */ - create_adv(&adv_set[i], id_b); + create_adv(&adv_set[i], ID_B_INDEX); } /* Set extended advertising data */ diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c b/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c index b553ee74b25baff..da94207387cf27b 100644 --- a/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c +++ b/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c @@ -9,6 +9,7 @@ #include #include #include +#include #define EXPECTED_NUM_ROTATIONS 5 @@ -128,6 +129,11 @@ void tester_procedure(void) FAIL("Failed to enable bluetooth (err %d\n)", err); } + err = settings_load(); + if (err) { + FAIL("Failed to enable settings (err %d\n)", err); + } + start_scanning(); /* The rest of the test is driven by the callback */ diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test.sh b/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test.sh index ccbe6e844f2e93d..37929a4efb2c2fc 100755 --- a/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test.sh +++ b/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test.sh @@ -15,10 +15,29 @@ EXECUTE_TIMEOUT=30 cd ${BSIM_OUT_PATH}/bin Execute "$central_exe" \ - -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -RealEncryption=1 + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -RealEncryption=1 \ + -flash="${simulation_id}.central.log.bin" + Execute "$peripheral_exe" \ - -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1 + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1 \ + -flash="${simulation_id}.peripheral.log.bin" + + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=70e6 $@ + +wait_for_background_jobs + +Execute "$central_exe" \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -RealEncryption=1 \ + -flash="${simulation_id}.central.log.bin" -flash_rm + + +Execute "$peripheral_exe" \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1 \ + -flash="${simulation_id}.peripheral.log.bin" -flash_rm + Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ -D=2 -sim_length=70e6 $@ From b182c92af5ae76b09a090e87010e4501c01ce2ad Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Mon, 30 Oct 2023 09:14:28 +0100 Subject: [PATCH 0043/1049] tests: bsim: bluetooth: host: privacy: peripheral: add RPA check Modified the BabbleSim test for the Bluetooth test under the host/privacy/peripheral category. Added the RPA check in the scan callback context of the scanning tester device to validate if the DUT advertising address is correct. Signed-off-by: Kamil Piszczek --- tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c b/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c index da94207387cf27b..deaa001ddbe5070 100644 --- a/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c +++ b/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c @@ -60,6 +60,10 @@ static void test_address(bt_addr_le_t *addr) { int64_t diff_ms, rpa_timeout_ms; + if (!BT_ADDR_IS_RPA(&addr->a)) { + FAIL("Bluetooth address is not RPA\n"); + } + /* Only save the address + time if this is the first scan */ if (bt_addr_le_eq(&adv_set_data[adv_index].old_addr, BT_ADDR_LE_ANY)) { bt_addr_le_copy(&adv_set_data[adv_index].old_addr, addr); From 98b46340f23fcb6e0a5aa43d3ab3f2486454a7b8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 11 Oct 2023 16:34:30 +0200 Subject: [PATCH 0044/1049] net: pkt: Add flag indicating checksum status Add new net_pkt checksum, which indicate checksum status on the packet (i. e. whether it has already been calculated or not). Signed-off-by: Robert Lubos --- include/zephyr/net/net_pkt.h | 14 ++++++++++++++ subsys/net/ip/net_pkt.c | 1 + 2 files changed, 15 insertions(+) diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index 4931f95009d5ec8..98646b25b2651b8 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -194,6 +194,9 @@ struct net_pkt { uint8_t l2_processed : 1; /* Set to 1 if this packet has already been * processed by the L2 */ + uint8_t chksum_done : 1; /* Checksum has already been computed for + * the packet. + */ /* bitfield byte alignment boundary */ @@ -398,6 +401,17 @@ static inline void net_pkt_set_l2_processed(struct net_pkt *pkt, pkt->l2_processed = is_l2_processed; } +static inline bool net_pkt_is_chksum_done(struct net_pkt *pkt) +{ + return !!(pkt->chksum_done); +} + +static inline void net_pkt_set_chksum_done(struct net_pkt *pkt, + bool is_chksum_done) +{ + pkt->chksum_done = is_chksum_done; +} + static inline uint8_t net_pkt_ip_hdr_len(struct net_pkt *pkt) { #if defined(CONFIG_NET_IP) diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 944ea8499f1695b..cef7cbcd1076d69 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -1812,6 +1812,7 @@ static void clone_pkt_attributes(struct net_pkt *pkt, struct net_pkt *clone_pkt) net_pkt_set_eof(clone_pkt, net_pkt_eof(pkt)); net_pkt_set_ptp(clone_pkt, net_pkt_is_ptp(pkt)); net_pkt_set_forwarding(clone_pkt, net_pkt_forwarding(pkt)); + net_pkt_set_chksum_done(clone_pkt, net_pkt_is_chksum_done(pkt)); net_pkt_set_l2_bridged(clone_pkt, net_pkt_is_l2_bridged(pkt)); net_pkt_set_l2_processed(clone_pkt, net_pkt_is_l2_processed(pkt)); From eadd9336077c88aa0051fe89430c8b23e824d120 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 11 Oct 2023 16:45:36 +0200 Subject: [PATCH 0045/1049] net: Set a flag when checksum has been computed Set checksum flag on the net_pkt, when checksum is calculated in software. Signed-off-by: Robert Lubos --- subsys/net/ip/icmpv4.c | 1 + subsys/net/ip/icmpv6.c | 1 + subsys/net/ip/tcp.c | 1 + subsys/net/ip/udp.c | 1 + 4 files changed, 4 insertions(+) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 7133ca16ee7d583..205ca5627544946 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -67,6 +67,7 @@ int net_icmpv4_finalize(struct net_pkt *pkt) icmp_hdr->chksum = 0U; if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) { icmp_hdr->chksum = net_calc_chksum_icmpv4(pkt); + net_pkt_set_chksum_done(pkt, true); } return net_pkt_set_data(pkt, &icmpv4_access); diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index ccd4c7f99cede0d..6b436139d1ac634 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -71,6 +71,7 @@ int net_icmpv6_finalize(struct net_pkt *pkt) icmp_hdr->chksum = 0U; if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) { icmp_hdr->chksum = net_calc_chksum_icmpv6(pkt); + net_pkt_set_chksum_done(pkt, true); } return net_pkt_set_data(pkt, &icmp_access); diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 4965c34061a52fe..253004c4e1f758b 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -3597,6 +3597,7 @@ int net_tcp_finalize(struct net_pkt *pkt) if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) { tcp_hdr->chksum = net_calc_chksum_tcp(pkt); + net_pkt_set_chksum_done(pkt, true); } return net_pkt_set_data(pkt, &tcp_access); diff --git a/subsys/net/ip/udp.c b/subsys/net/ip/udp.c index 972eadb5a0279be..858c046b9079ac1 100644 --- a/subsys/net/ip/udp.c +++ b/subsys/net/ip/udp.c @@ -53,6 +53,7 @@ int net_udp_finalize(struct net_pkt *pkt) if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) { udp_hdr->chksum = net_calc_chksum_udp(pkt); + net_pkt_set_chksum_done(pkt, true); } return net_pkt_set_data(pkt, &udp_access); From 08879ea7fbb9d17ec3d057d6fd3e0a6950edd0cf Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 12 Oct 2023 15:49:00 +0200 Subject: [PATCH 0046/1049] net: ip: Add option to force checksum calculation Modify internal L4 protocols APIs, to allow to enforce checksum calculation, regardless of the checksum HW offloading capability. Signed-off-by: Robert Lubos --- subsys/net/ip/icmpv4.c | 4 ++-- subsys/net/ip/icmpv4.h | 2 +- subsys/net/ip/icmpv6.c | 4 ++-- subsys/net/ip/icmpv6.h | 2 +- subsys/net/ip/ipv4.c | 6 +++--- subsys/net/ip/ipv6.c | 6 +++--- subsys/net/ip/tcp.c | 4 ++-- subsys/net/ip/tcp.h | 2 +- subsys/net/ip/tcp_internal.h | 5 +++-- subsys/net/ip/udp.c | 4 ++-- subsys/net/ip/udp_internal.h | 5 +++-- tests/net/ipv4_fragment/src/main.c | 6 +++--- tests/net/ipv6_fragment/src/main.c | 4 ++-- 13 files changed, 28 insertions(+), 26 deletions(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 205ca5627544946..8bab97d9cfc55d3 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -47,7 +47,7 @@ int net_icmpv4_create(struct net_pkt *pkt, uint8_t icmp_type, uint8_t icmp_code) return net_pkt_set_data(pkt, &icmpv4_access); } -int net_icmpv4_finalize(struct net_pkt *pkt) +int net_icmpv4_finalize(struct net_pkt *pkt, bool force_chksum) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access, struct net_icmp_hdr); @@ -65,7 +65,7 @@ int net_icmpv4_finalize(struct net_pkt *pkt) } icmp_hdr->chksum = 0U; - if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) { + if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt)) || force_chksum) { icmp_hdr->chksum = net_calc_chksum_icmpv4(pkt); net_pkt_set_chksum_done(pkt, true); } diff --git a/subsys/net/ip/icmpv4.h b/subsys/net/ip/icmpv4.h index b9680c44b345b35..ae848c9d9641548 100644 --- a/subsys/net/ip/icmpv4.h +++ b/subsys/net/ip/icmpv4.h @@ -48,7 +48,7 @@ enum net_verdict net_icmpv4_input(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr); int net_icmpv4_create(struct net_pkt *pkt, uint8_t icmp_type, uint8_t icmp_code); -int net_icmpv4_finalize(struct net_pkt *pkt); +int net_icmpv4_finalize(struct net_pkt *pkt, bool force_chksum); void net_icmpv4_init(void); #else diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index 6b436139d1ac634..c04e3dddf72e80e 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -57,7 +57,7 @@ const char *net_icmpv6_type2str(int icmpv6_type) return "?"; } -int net_icmpv6_finalize(struct net_pkt *pkt) +int net_icmpv6_finalize(struct net_pkt *pkt, bool force_chksum) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, struct net_icmp_hdr); @@ -69,7 +69,7 @@ int net_icmpv6_finalize(struct net_pkt *pkt) } icmp_hdr->chksum = 0U; - if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) { + if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt)) || force_chksum) { icmp_hdr->chksum = net_calc_chksum_icmpv6(pkt); net_pkt_set_chksum_done(pkt, true); } diff --git a/subsys/net/ip/icmpv6.h b/subsys/net/ip/icmpv6.h index 967111955f36fc7..64ee1dfaa7bcb6b 100644 --- a/subsys/net/ip/icmpv6.h +++ b/subsys/net/ip/icmpv6.h @@ -188,7 +188,7 @@ enum net_verdict net_icmpv6_input(struct net_pkt *pkt, struct net_ipv6_hdr *ip_hdr); int net_icmpv6_create(struct net_pkt *pkt, uint8_t icmp_type, uint8_t icmp_code); -int net_icmpv6_finalize(struct net_pkt *pkt); +int net_icmpv6_finalize(struct net_pkt *pkt, bool force_chksum); void net_icmpv6_init(void); #else diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index 922068274f721e3..ce5c1e9986c5c19 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -118,12 +118,12 @@ int net_ipv4_finalize(struct net_pkt *pkt, uint8_t next_header_proto) if (IS_ENABLED(CONFIG_NET_UDP) && next_header_proto == IPPROTO_UDP) { - return net_udp_finalize(pkt); + return net_udp_finalize(pkt, false); } else if (IS_ENABLED(CONFIG_NET_TCP) && next_header_proto == IPPROTO_TCP) { - return net_tcp_finalize(pkt); + return net_tcp_finalize(pkt, false); } else if (next_header_proto == IPPROTO_ICMP) { - return net_icmpv4_finalize(pkt); + return net_icmpv4_finalize(pkt, false); } return 0; diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 7ef758314060c5a..4957f1cb5579ab5 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -120,12 +120,12 @@ int net_ipv6_finalize(struct net_pkt *pkt, uint8_t next_header_proto) if (IS_ENABLED(CONFIG_NET_UDP) && next_header_proto == IPPROTO_UDP) { - return net_udp_finalize(pkt); + return net_udp_finalize(pkt, false); } else if (IS_ENABLED(CONFIG_NET_TCP) && next_header_proto == IPPROTO_TCP) { - return net_tcp_finalize(pkt); + return net_tcp_finalize(pkt, false); } else if (next_header_proto == IPPROTO_ICMPV6) { - return net_icmpv6_finalize(pkt); + return net_icmpv6_finalize(pkt, false); } return 0; diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 253004c4e1f758b..6ec7745c9523067 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -3583,7 +3583,7 @@ int net_tcp_recv(struct net_context *context, net_context_recv_cb_t cb, return 0; } -int net_tcp_finalize(struct net_pkt *pkt) +int net_tcp_finalize(struct net_pkt *pkt, bool force_chksum) { NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr); struct net_tcp_hdr *tcp_hdr; @@ -3595,7 +3595,7 @@ int net_tcp_finalize(struct net_pkt *pkt) tcp_hdr->chksum = 0U; - if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) { + if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt)) || force_chksum) { tcp_hdr->chksum = net_calc_chksum_tcp(pkt); net_pkt_set_chksum_done(pkt, true); } diff --git a/subsys/net/ip/tcp.h b/subsys/net/ip/tcp.h index f6f481d54432d68..77d5c5634a6ccc8 100644 --- a/subsys/net/ip/tcp.h +++ b/subsys/net/ip/tcp.h @@ -113,7 +113,7 @@ void net_tcp_init(void); #endif int net_tcp_update_recv_wnd(struct net_context *context, int32_t delta); int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt); -int net_tcp_finalize(struct net_pkt *pkt); +int net_tcp_finalize(struct net_pkt *pkt, bool force_chksum); #if defined(CONFIG_NET_TEST_PROTOCOL) /** diff --git a/subsys/net/ip/tcp_internal.h b/subsys/net/ip/tcp_internal.h index 4275206009206c5..49edae13f687da3 100644 --- a/subsys/net/ip/tcp_internal.h +++ b/subsys/net/ip/tcp_internal.h @@ -249,11 +249,12 @@ static inline int net_tcp_recv(struct net_context *context, * @return 0 on success, negative errno otherwise. */ #if defined(CONFIG_NET_NATIVE_TCP) -int net_tcp_finalize(struct net_pkt *pkt); +int net_tcp_finalize(struct net_pkt *pkt, bool force_chksum); #else -static inline int net_tcp_finalize(struct net_pkt *pkt) +static inline int net_tcp_finalize(struct net_pkt *pkt, bool force_chksum) { ARG_UNUSED(pkt); + ARG_UNUSED(force_chksum); return 0; } #endif diff --git a/subsys/net/ip/udp.c b/subsys/net/ip/udp.c index 858c046b9079ac1..5ecc595053b391c 100644 --- a/subsys/net/ip/udp.c +++ b/subsys/net/ip/udp.c @@ -35,7 +35,7 @@ int net_udp_create(struct net_pkt *pkt, uint16_t src_port, uint16_t dst_port) return net_pkt_set_data(pkt, &udp_access); } -int net_udp_finalize(struct net_pkt *pkt) +int net_udp_finalize(struct net_pkt *pkt, bool force_chksum) { NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); struct net_udp_hdr *udp_hdr; @@ -51,7 +51,7 @@ int net_udp_finalize(struct net_pkt *pkt) udp_hdr->len = htons(length); - if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt))) { + if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt)) || force_chksum) { udp_hdr->chksum = net_calc_chksum_udp(pkt); net_pkt_set_chksum_done(pkt, true); } diff --git a/subsys/net/ip/udp_internal.h b/subsys/net/ip/udp_internal.h index 94106d600102ee4..00009177d0b5561 100644 --- a/subsys/net/ip/udp_internal.h +++ b/subsys/net/ip/udp_internal.h @@ -63,11 +63,12 @@ static inline int net_udp_create(struct net_pkt *pkt, * @return 0 on success, negative errno otherwise. */ #if defined(CONFIG_NET_NATIVE_UDP) -int net_udp_finalize(struct net_pkt *pkt); +int net_udp_finalize(struct net_pkt *pkt, bool force_chksum); #else -static inline int net_udp_finalize(struct net_pkt *pkt) +static inline int net_udp_finalize(struct net_pkt *pkt, bool force_chksum) { ARG_UNUSED(pkt); + ARG_UNUSED(force_chksum); return 0; } diff --git a/tests/net/ipv4_fragment/src/main.c b/tests/net/ipv4_fragment/src/main.c index 4db5b877d4f0483..7375aab17aa6ec0 100644 --- a/tests/net/ipv4_fragment/src/main.c +++ b/tests/net/ipv4_fragment/src/main.c @@ -636,7 +636,7 @@ ZTEST(net_ipv4_fragment, test_udp) net_pkt_cursor_init(pkt); net_pkt_set_overwrite(pkt, true); net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt)); - net_udp_finalize(pkt); + net_udp_finalize(pkt, false); pkt_recv_expected_size = net_pkt_get_len(pkt); @@ -706,7 +706,7 @@ ZTEST(net_ipv4_fragment, test_tcp) net_pkt_set_overwrite(pkt, true); net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt)); - net_tcp_finalize(pkt); + net_tcp_finalize(pkt, false); pkt_recv_expected_size = net_pkt_get_len(pkt); @@ -849,7 +849,7 @@ ZTEST(net_ipv4_fragment, test_do_not_fragment) net_pkt_cursor_init(pkt); net_pkt_set_overwrite(pkt, true); net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt)); - net_udp_finalize(pkt); + net_udp_finalize(pkt, false); pkt_recv_expected_size = net_pkt_get_len(pkt); diff --git a/tests/net/ipv6_fragment/src/main.c b/tests/net/ipv6_fragment/src/main.c index 890ddc32b577f67..adb8652bdc1f6e2 100644 --- a/tests/net/ipv6_fragment/src/main.c +++ b/tests/net/ipv6_fragment/src/main.c @@ -2015,7 +2015,7 @@ ZTEST(net_ipv6_fragment, test_send_ipv6_fragment) net_pkt_set_overwrite(pkt, true); net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt)); - net_udp_finalize(pkt); + net_udp_finalize(pkt, false); test_failed = false; test_complete = false; @@ -2175,7 +2175,7 @@ ZTEST(net_ipv6_fragment, test_send_ipv6_fragment_udp_loopback) net_pkt_set_overwrite(pkt, true); net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt)); - net_udp_finalize(pkt); + net_udp_finalize(pkt, false); test_failed = false; test_complete = false; From 887a3a321d812249b200dd99f26d0845ae67e899 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 12 Oct 2023 18:18:11 +0200 Subject: [PATCH 0047/1049] net: ipv4: Calculate checksum before fragmentation In case the stack has to fragment the IPv4 packet, calculate the checksum before fragmentation (if haven't done so). Signed-off-by: Robert Lubos --- subsys/net/ip/ipv4_fragment.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/subsys/net/ip/ipv4_fragment.c b/subsys/net/ip/ipv4_fragment.c index d61dd246075b154..53cd72a87489f3e 100644 --- a/subsys/net/ip/ipv4_fragment.c +++ b/subsys/net/ip/ipv4_fragment.c @@ -480,9 +480,9 @@ static int send_ipv4_fragment(struct net_pkt *pkt, uint16_t rand_id, uint16_t fi ipv4_hdr->len = htons((fit_len + net_pkt_ip_hdr_len(pkt))); ipv4_hdr->chksum = 0; - if (net_if_need_calc_tx_checksum(net_pkt_iface(frag_pkt))) { - ipv4_hdr->chksum = net_calc_chksum_ipv4(frag_pkt); - } + ipv4_hdr->chksum = net_calc_chksum_ipv4(frag_pkt); + + net_pkt_set_chksum_done(frag_pkt, true); net_pkt_set_data(frag_pkt, &ipv4_access); @@ -554,6 +554,35 @@ int net_ipv4_send_fragmented_pkt(struct net_if *iface, struct net_pkt *pkt, pkt_len -= net_pkt_ip_hdr_len(pkt); + /* Calculate the L4 checksum (if not done already) before the fragmentation. */ + if (!net_pkt_is_chksum_done(pkt)) { + struct net_pkt_cursor backup; + + net_pkt_cursor_backup(pkt, &backup); + net_pkt_acknowledge_data(pkt, &frag_access); + + switch (frag_hdr->proto) { + case IPPROTO_ICMP: + ret = net_icmpv4_finalize(pkt, true); + break; + case IPPROTO_TCP: + ret = net_tcp_finalize(pkt, true); + break; + case IPPROTO_UDP: + ret = net_udp_finalize(pkt, true); + break; + default: + ret = 0; + break; + } + + if (ret < 0) { + return ret; + } + + net_pkt_cursor_restore(pkt, &backup); + } + while (frag_offset < pkt_len) { bool final = false; From 13a22e68142a3da882df4d6d3332e129bd444a30 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 20 Oct 2023 11:52:00 +0200 Subject: [PATCH 0048/1049] net: ipv6: Calculate checksum before fragmentation In case the stack has to fragment the IPv6 packet, calculate the checksum before fragmentation (if haven't done so). Signed-off-by: Robert Lubos --- subsys/net/ip/ipv6_fragment.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/subsys/net/ip/ipv6_fragment.c b/subsys/net/ip/ipv6_fragment.c index 3aa2a49fb654f29..5ff789aaac9db17 100644 --- a/subsys/net/ip/ipv6_fragment.c +++ b/subsys/net/ip/ipv6_fragment.c @@ -635,6 +635,8 @@ static int send_ipv6_fragment(struct net_pkt *pkt, frag_hdr->id = net_pkt_ipv6_fragment_id(pkt); frag_hdr->offset = htons(((frag_offset / 8U) << 3) | !final); + net_pkt_set_chksum_done(frag_pkt, true); + if (net_pkt_set_data(frag_pkt, &frag_access)) { goto fail; } @@ -720,6 +722,31 @@ int net_ipv6_send_fragmented_pkt(struct net_if *iface, struct net_pkt *pkt, frag_offset = 0U; + /* Calculate the L4 checksum (if not done already) before the fragmentation. */ + if (!net_pkt_is_chksum_done(pkt)) { + net_pkt_cursor_init(pkt); + net_pkt_skip(pkt, last_hdr_off); + + switch (next_hdr) { + case IPPROTO_ICMPV6: + ret = net_icmpv6_finalize(pkt, true); + break; + case IPPROTO_TCP: + ret = net_tcp_finalize(pkt, true); + break; + case IPPROTO_UDP: + ret = net_udp_finalize(pkt, true); + break; + default: + ret = 0; + break; + } + + if (ret < 0) { + return ret; + } + } + length = net_pkt_get_len(pkt) - (net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt)); while (length) { From 0c1c939d9e322057203b8a4910d3cf5258cdbb4f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 20 Oct 2023 16:43:35 +0200 Subject: [PATCH 0049/1049] net: ipv6: Remove invalid/unneeded code from fragmentation logic Skipping both next_hdr_off and last_hdr_off and filling last_hdr variable doesn't make much sense, as this effectively moves the packet cursor inside/behind the last (L4) header with no particular meaning. Plus the last_hdr variable isn't really used anywhere, which kind of proves the point. Therefore, remove the unused variable and needless net_pkt operations. Signed-off-by: Robert Lubos --- subsys/net/ip/ipv6_fragment.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/subsys/net/ip/ipv6_fragment.c b/subsys/net/ip/ipv6_fragment.c index 5ff789aaac9db17..e10af12dad9d10f 100644 --- a/subsys/net/ip/ipv6_fragment.c +++ b/subsys/net/ip/ipv6_fragment.c @@ -687,7 +687,6 @@ int net_ipv6_send_fragmented_pkt(struct net_if *iface, struct net_pkt *pkt, uint16_t frag_offset; size_t length; uint8_t next_hdr; - uint8_t last_hdr; int fit_len; int ret; @@ -701,9 +700,7 @@ int net_ipv6_send_fragmented_pkt(struct net_if *iface, struct net_pkt *pkt, net_pkt_cursor_init(pkt); if (net_pkt_skip(pkt, next_hdr_off) || - net_pkt_read_u8(pkt, &next_hdr) || - net_pkt_skip(pkt, last_hdr_off) || - net_pkt_read_u8(pkt, &last_hdr)) { + net_pkt_read_u8(pkt, &next_hdr)) { return -ENOBUFS; } From 64e615263afa0845d762fd8ebf04a28df8868d95 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Sun, 29 Oct 2023 16:07:16 +0100 Subject: [PATCH 0050/1049] net: ipv6: Set IP header length on the fragmented packet IPv6 fragmentation code did not set the IP header field on the fragment net_pkt. Signed-off-by: Robert Lubos --- subsys/net/ip/ipv6_fragment.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/net/ip/ipv6_fragment.c b/subsys/net/ip/ipv6_fragment.c index e10af12dad9d10f..7ea9765be4c8506 100644 --- a/subsys/net/ip/ipv6_fragment.c +++ b/subsys/net/ip/ipv6_fragment.c @@ -641,6 +641,7 @@ static int send_ipv6_fragment(struct net_pkt *pkt, goto fail; } + net_pkt_set_ip_hdr_len(frag_pkt, net_pkt_ip_hdr_len(pkt)); net_pkt_set_ipv6_ext_len(frag_pkt, net_pkt_ipv6_ext_len(pkt) + sizeof(struct net_ipv6_frag_hdr)); From 2836d0701d647d380d1f798bf58483cae894d5b1 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 20 Oct 2023 14:43:20 +0200 Subject: [PATCH 0051/1049] net: ip: Set net_context on the final fragment IPv4/6 fragmentation did not set the net_context pointer on the fragment packet and in result the send callback registered on net_context was not called. Therefore, copy the net_context pointer from the original packet to the final fragment to ensure that the registered callback is called. Signed-off-by: Robert Lubos --- subsys/net/ip/ipv4_fragment.c | 4 ++++ subsys/net/ip/ipv6_fragment.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/subsys/net/ip/ipv4_fragment.c b/subsys/net/ip/ipv4_fragment.c index 53cd72a87489f3e..5bcf4e0026c5cd6 100644 --- a/subsys/net/ip/ipv4_fragment.c +++ b/subsys/net/ip/ipv4_fragment.c @@ -489,6 +489,10 @@ static int send_ipv4_fragment(struct net_pkt *pkt, uint16_t rand_id, uint16_t fi net_pkt_set_overwrite(frag_pkt, false); net_pkt_cursor_restore(frag_pkt, &cur); + if (final) { + net_pkt_set_context(frag_pkt, net_pkt_context(pkt)); + } + /* If everything has been ok so far, we can send the packet. */ ret = net_send_data(frag_pkt); if (ret < 0) { diff --git a/subsys/net/ip/ipv6_fragment.c b/subsys/net/ip/ipv6_fragment.c index 7ea9765be4c8506..6d391b3b823e4cf 100644 --- a/subsys/net/ip/ipv6_fragment.c +++ b/subsys/net/ip/ipv6_fragment.c @@ -660,6 +660,10 @@ static int send_ipv6_fragment(struct net_pkt *pkt, goto fail; } + if (final) { + net_pkt_set_context(frag_pkt, net_pkt_context(pkt)); + } + /* If everything has been ok so far, we can send the packet. */ ret = net_send_data(frag_pkt); if (ret < 0) { From 76a256ea576a41544c9b64665ad2a5a80ddbf2db Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 30 Oct 2023 13:17:51 +0100 Subject: [PATCH 0052/1049] net: pkt: Add function to check if packet was reassembled at IP level Move the existing code verifying that the net_pkt was reassembled at IP level to a helper function, as it will be needed in other places as well. Additionally, add packet family check before accessing union fields. Signed-off-by: Robert Lubos --- include/zephyr/net/net_pkt.h | 14 ++++++++++++++ subsys/net/ip/net_core.c | 3 +-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index 98646b25b2651b8..591002a9d6683fc 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -836,6 +836,20 @@ static inline void net_pkt_set_ipv6_fragment_id(struct net_pkt *pkt, } #endif /* CONFIG_NET_IPV6_FRAGMENT */ +static inline bool net_pkt_is_ip_reassembled(struct net_pkt *pkt) +{ + if ((IS_ENABLED(CONFIG_NET_IPV4_FRAGMENT) && + net_pkt_family(pkt) == AF_INET && + net_pkt_ipv4_fragment_more(pkt)) || + (IS_ENABLED(CONFIG_NET_IPV6_FRAGMENT) && + net_pkt_family(pkt) == AF_INET6 && + net_pkt_ipv6_fragment_start(pkt))) { + return true; + } + + return false; +} + static inline uint8_t net_pkt_priority(struct net_pkt *pkt) { return pkt->priority; diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 3d37743a39d43ab..baa8cd695c50de8 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -76,8 +76,7 @@ static inline enum net_verdict process_data(struct net_pkt *pkt, /* If the packet is routed back to us when we have reassembled an IPv4 or IPv6 packet, * then do not pass it to L2 as the packet does not have link layer headers in it. */ - if ((IS_ENABLED(CONFIG_NET_IPV4_FRAGMENT) && net_pkt_ipv4_fragment_more(pkt)) || - (IS_ENABLED(CONFIG_NET_IPV6_FRAGMENT) && net_pkt_ipv6_fragment_start(pkt))) { + if (net_pkt_is_ip_reassembled(pkt)) { locally_routed = true; } From 24abc4307bafc43edd3f7c7cdf80a934eaa06c5e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 30 Oct 2023 13:23:02 +0100 Subject: [PATCH 0053/1049] net: Verify L4 checksum unconditionally for reassembled packets In case of reassembled IP packets, we cannot rely on checksum offloading as the drivers/HW has no means to verify L4 checksum before the fragment is reassembled. Therefore, for such packets, verify L4 checksum in the software unconditionally. Signed-off-by: Robert Lubos --- subsys/net/ip/icmpv4.c | 3 ++- subsys/net/ip/icmpv6.c | 3 ++- subsys/net/ip/tcp.c | 3 ++- subsys/net/ip/udp.c | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index 8bab97d9cfc55d3..0ea8d40ba46df17 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -610,7 +610,8 @@ enum net_verdict net_icmpv4_input(struct net_pkt *pkt, return NET_DROP; } - if (net_if_need_calc_rx_checksum(net_pkt_iface(pkt))) { + if (net_if_need_calc_rx_checksum(net_pkt_iface(pkt)) || + net_pkt_is_ip_reassembled(pkt)) { if (net_calc_chksum_icmpv4(pkt) != 0U) { NET_DBG("DROP: Invalid checksum"); goto drop; diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index c04e3dddf72e80e..65c01a510c7e709 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -342,7 +342,8 @@ enum net_verdict net_icmpv6_input(struct net_pkt *pkt, } - if (net_if_need_calc_rx_checksum(net_pkt_iface(pkt))) { + if (net_if_need_calc_rx_checksum(net_pkt_iface(pkt)) || + net_pkt_is_ip_reassembled(pkt)) { if (net_calc_chksum_icmpv6(pkt) != 0U) { NET_DBG("DROP: invalid checksum"); goto drop; diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 6ec7745c9523067..82faa777694781a 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -3609,7 +3609,8 @@ struct net_tcp_hdr *net_tcp_input(struct net_pkt *pkt, struct net_tcp_hdr *tcp_hdr; if (IS_ENABLED(CONFIG_NET_TCP_CHECKSUM) && - net_if_need_calc_rx_checksum(net_pkt_iface(pkt)) && + (net_if_need_calc_rx_checksum(net_pkt_iface(pkt)) || + net_pkt_is_ip_reassembled(pkt)) && net_calc_chksum_tcp(pkt) != 0U) { NET_DBG("DROP: checksum mismatch"); goto drop; diff --git a/subsys/net/ip/udp.c b/subsys/net/ip/udp.c index 5ecc595053b391c..e3f45b3db38a928 100644 --- a/subsys/net/ip/udp.c +++ b/subsys/net/ip/udp.c @@ -164,7 +164,8 @@ struct net_udp_hdr *net_udp_input(struct net_pkt *pkt, } if (IS_ENABLED(CONFIG_NET_UDP_CHECKSUM) && - net_if_need_calc_rx_checksum(net_pkt_iface(pkt))) { + (net_if_need_calc_rx_checksum(net_pkt_iface(pkt)) || + net_pkt_is_ip_reassembled(pkt))) { if (!udp_hdr->chksum) { if (IS_ENABLED(CONFIG_NET_UDP_MISSING_CHECKSUM) && net_pkt_family(pkt) == AF_INET) { From 736888be0c02a2c5ea74b12becc693598236c897 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 27 Oct 2023 14:11:20 +0200 Subject: [PATCH 0054/1049] tests: net: checksum_offload: Move net context init to helper function Move code responsible for net context initialization, repeated over multiple test cases, to a helper function to reduce code duplication. Signed-off-by: Robert Lubos --- tests/net/checksum_offload/src/main.c | 343 +++++++++----------------- 1 file changed, 122 insertions(+), 221 deletions(-) diff --git a/tests/net/checksum_offload/src/main.c b/tests/net/checksum_offload/src/main.c index 52b8add0fb002ff..4fc133442110616 100644 --- a/tests/net/checksum_offload/src/main.c +++ b/tests/net/checksum_offload/src/main.c @@ -490,42 +490,103 @@ static void add_neighbor(struct net_if *iface, struct in6_addr *addr) } } -ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6) +static struct net_context *test_udp_context_prepare(sa_family_t family, + bool offloaded, + struct sockaddr *dst_addr) { struct net_context *net_ctx; struct eth_context *ctx; /* This is interface context */ + struct sockaddr src_addr; + socklen_t addrlen; struct net_if *iface; - int ret, len; - struct sockaddr_in6 dst_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = htons(TEST_PORT), - }; - struct sockaddr_in6 src_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = 0, - }; - - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &net_ctx); - zassert_equal(ret, 0, "Create IPv6 UDP context failed"); - - memcpy(&src_addr6.sin6_addr, &my_addr1, sizeof(struct in6_addr)); - memcpy(&dst_addr6.sin6_addr, &dst_addr1, sizeof(struct in6_addr)); - - ret = net_context_bind(net_ctx, (struct sockaddr *)&src_addr6, - sizeof(struct sockaddr_in6)); + int ret; + + if (family == AF_INET6) { + struct sockaddr_in6 *dst_addr6 = + (struct sockaddr_in6 *)dst_addr; + struct sockaddr_in6 *src_addr6 = + (struct sockaddr_in6 *)&src_addr; + + dst_addr6->sin6_family = AF_INET6; + dst_addr6->sin6_port = htons(TEST_PORT); + src_addr6->sin6_family = AF_INET6; + src_addr6->sin6_port = 0; + + if (offloaded) { + memcpy(&src_addr6->sin6_addr, &my_addr2, + sizeof(struct in6_addr)); + memcpy(&dst_addr6->sin6_addr, &dst_addr2, + sizeof(struct in6_addr)); + } else { + memcpy(&src_addr6->sin6_addr, &my_addr1, + sizeof(struct in6_addr)); + memcpy(&dst_addr6->sin6_addr, &dst_addr1, + sizeof(struct in6_addr)); + } + + addrlen = sizeof(struct sockaddr_in6); + } else { + struct sockaddr_in *dst_addr4 = + (struct sockaddr_in *)dst_addr; + struct sockaddr_in *src_addr4 = + (struct sockaddr_in *)&src_addr; + + dst_addr4->sin_family = AF_INET; + dst_addr4->sin_port = htons(TEST_PORT); + src_addr4->sin_family = AF_INET; + src_addr4->sin_port = 0; + + if (offloaded) { + memcpy(&src_addr4->sin_addr, &in4addr_my2, + sizeof(struct in_addr)); + memcpy(&dst_addr4->sin_addr, &in4addr_dst2, + sizeof(struct in_addr)); + } else { + memcpy(&src_addr4->sin_addr, &in4addr_my, + sizeof(struct in_addr)); + memcpy(&dst_addr4->sin_addr, &in4addr_dst, + sizeof(struct in_addr)); + } + + addrlen = sizeof(struct sockaddr_in6); + } + + ret = net_context_get(family, SOCK_DGRAM, IPPROTO_UDP, &net_ctx); + zassert_equal(ret, 0, "Create %s UDP context failed", + family == AF_INET6 ? "IPv6" : "IPv4"); + + ret = net_context_bind(net_ctx, &src_addr, addrlen); zassert_equal(ret, 0, "Context bind failure test failed"); - iface = eth_interfaces[0]; - ctx = net_if_get_device(iface)->data; - zassert_equal_ptr(ð_context_offloading_disabled, ctx, - "eth context mismatch"); + /* Verify iface data */ + if (offloaded) { + iface = eth_interfaces[1]; + ctx = net_if_get_device(iface)->data; + zassert_equal_ptr(ð_context_offloading_enabled, ctx, + "eth context mismatch"); + } else { + iface = eth_interfaces[0]; + ctx = net_if_get_device(iface)->data; + zassert_equal_ptr(ð_context_offloading_disabled, ctx, + "eth context mismatch"); + } + + return net_ctx; +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6) +{ + struct net_context *net_ctx; + struct sockaddr dst_addr; + int ret, len; + + net_ctx = test_udp_context_prepare(AF_INET6, false, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; len = strlen(test_data); - - ret = net_context_sendto(net_ctx, test_data, len, - (struct sockaddr *)&dst_addr6, + ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, sizeof(struct sockaddr_in6), NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); @@ -541,39 +602,16 @@ ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6) ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4) { struct net_context *net_ctx; - struct eth_context *ctx; /* This is interface context */ - struct net_if *iface; + struct sockaddr dst_addr; int ret, len; - struct sockaddr_in dst_addr4 = { - .sin_family = AF_INET, - .sin_port = htons(TEST_PORT), - }; - struct sockaddr_in src_addr4 = { - .sin_family = AF_INET, - .sin_port = 0, - }; - - ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &net_ctx); - zassert_equal(ret, 0, "Create IPv4 UDP context failed"); - - memcpy(&src_addr4.sin_addr, &in4addr_my, sizeof(struct in_addr)); - memcpy(&dst_addr4.sin_addr, &in4addr_dst, sizeof(struct in_addr)); - - ret = net_context_bind(net_ctx, (struct sockaddr *)&src_addr4, - sizeof(struct sockaddr_in)); - zassert_equal(ret, 0, "Context bind failure test failed"); - iface = eth_interfaces[0]; - ctx = net_if_get_device(iface)->data; - zassert_equal_ptr(ð_context_offloading_disabled, ctx, - "eth context mismatch"); - - len = strlen(test_data); + net_ctx = test_udp_context_prepare(AF_INET, false, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; - ret = net_context_sendto(net_ctx, test_data, len, - (struct sockaddr *)&dst_addr4, + len = strlen(test_data); + ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, sizeof(struct sockaddr_in), NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); @@ -589,39 +627,16 @@ ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4) ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6) { struct net_context *net_ctx; - struct eth_context *ctx; /* This is interface context */ - struct net_if *iface; + struct sockaddr dst_addr; int ret, len; - struct sockaddr_in6 dst_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = htons(TEST_PORT), - }; - struct sockaddr_in6 src_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = 0, - }; - - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &net_ctx); - zassert_equal(ret, 0, "Create IPv6 UDP context failed"); - - memcpy(&src_addr6.sin6_addr, &my_addr2, sizeof(struct in6_addr)); - memcpy(&dst_addr6.sin6_addr, &dst_addr2, sizeof(struct in6_addr)); - - ret = net_context_bind(net_ctx, (struct sockaddr *)&src_addr6, - sizeof(struct sockaddr_in6)); - zassert_equal(ret, 0, "Context bind failure test failed"); - - iface = eth_interfaces[1]; - ctx = net_if_get_device(iface)->data; - zassert_equal_ptr(ð_context_offloading_enabled, ctx, - "eth context mismatch"); - len = strlen(test_data); + net_ctx = test_udp_context_prepare(AF_INET6, true, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; - ret = net_context_sendto(net_ctx, test_data, len, - (struct sockaddr *)&dst_addr6, + len = strlen(test_data); + ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, sizeof(struct sockaddr_in6), NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); @@ -637,39 +652,16 @@ ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6) ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4) { struct net_context *net_ctx; - struct eth_context *ctx; /* This is interface context */ - struct net_if *iface; + struct sockaddr dst_addr; int ret, len; - struct sockaddr_in dst_addr4 = { - .sin_family = AF_INET, - .sin_port = htons(TEST_PORT), - }; - struct sockaddr_in src_addr4 = { - .sin_family = AF_INET, - .sin_port = 0, - }; - - ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &net_ctx); - zassert_equal(ret, 0, "Create IPv4 UDP context failed"); - - memcpy(&src_addr4.sin_addr, &in4addr_my2, sizeof(struct in_addr)); - memcpy(&dst_addr4.sin_addr, &in4addr_dst2, sizeof(struct in_addr)); - - ret = net_context_bind(net_ctx, (struct sockaddr *)&src_addr4, - sizeof(struct sockaddr_in)); - zassert_equal(ret, 0, "Context bind failure test failed"); - iface = eth_interfaces[1]; - ctx = net_if_get_device(iface)->data; - zassert_equal_ptr(ð_context_offloading_enabled, ctx, - "eth context mismatch"); - - len = strlen(test_data); + net_ctx = test_udp_context_prepare(AF_INET, true, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; - ret = net_context_sendto(net_ctx, test_data, len, - (struct sockaddr *)&dst_addr4, + len = strlen(test_data); + ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, sizeof(struct sockaddr_in), NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); @@ -728,34 +720,11 @@ static void recv_cb_offload_enabled(struct net_context *context, ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6) { struct net_context *net_ctx; - struct eth_context *ctx; /* This is interface context */ - struct net_if *iface; + struct sockaddr dst_addr; int ret, len; - struct sockaddr_in6 dst_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = htons(TEST_PORT), - }; - struct sockaddr_in6 src_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = 0, - }; - - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &net_ctx); - zassert_equal(ret, 0, "Create IPv6 UDP context failed"); - - memcpy(&src_addr6.sin6_addr, &my_addr1, sizeof(struct in6_addr)); - memcpy(&dst_addr6.sin6_addr, &dst_addr1, sizeof(struct in6_addr)); - - ret = net_context_bind(net_ctx, (struct sockaddr *)&src_addr6, - sizeof(struct sockaddr_in6)); - zassert_equal(ret, 0, "Context bind failure test failed"); - iface = eth_interfaces[0]; - ctx = net_if_get_device(iface)->data; - zassert_equal_ptr(ð_context_offloading_disabled, ctx, - "eth context mismatch"); - - len = strlen(test_data); + net_ctx = test_udp_context_prepare(AF_INET6, false, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; start_receiving = true; @@ -764,8 +733,8 @@ ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6) K_NO_WAIT, NULL); zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); - ret = net_context_sendto(net_ctx, test_data, len, - (struct sockaddr *)&dst_addr6, + len = strlen(test_data); + ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, sizeof(struct sockaddr_in6), NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); @@ -784,34 +753,11 @@ ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6) ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4) { struct net_context *net_ctx; - struct eth_context *ctx; /* This is interface context */ - struct net_if *iface; + struct sockaddr dst_addr; int ret, len; - struct sockaddr_in dst_addr4 = { - .sin_family = AF_INET, - .sin_port = htons(TEST_PORT), - }; - struct sockaddr_in src_addr4 = { - .sin_family = AF_INET, - .sin_port = 0, - }; - - ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &net_ctx); - zassert_equal(ret, 0, "Create IPv4 UDP context failed"); - - memcpy(&src_addr4.sin_addr, &in4addr_my, sizeof(struct in_addr)); - memcpy(&dst_addr4.sin_addr, &in4addr_dst, sizeof(struct in_addr)); - - ret = net_context_bind(net_ctx, (struct sockaddr *)&src_addr4, - sizeof(struct sockaddr_in)); - zassert_equal(ret, 0, "Context bind failure test failed"); - iface = eth_interfaces[0]; - ctx = net_if_get_device(iface)->data; - zassert_equal_ptr(ð_context_offloading_disabled, ctx, - "eth context mismatch"); - - len = strlen(test_data); + net_ctx = test_udp_context_prepare(AF_INET, false, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; start_receiving = true; @@ -820,8 +766,9 @@ ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4) K_NO_WAIT, NULL); zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); + len = strlen(test_data); ret = net_context_sendto(net_ctx, test_data, len, - (struct sockaddr *)&dst_addr4, + (struct sockaddr *)&dst_addr, sizeof(struct sockaddr_in), NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); @@ -840,34 +787,11 @@ ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4) ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6) { struct net_context *net_ctx; - struct eth_context *ctx; /* This is interface context */ - struct net_if *iface; + struct sockaddr dst_addr; int ret, len; - struct sockaddr_in6 dst_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = htons(TEST_PORT), - }; - struct sockaddr_in6 src_addr6 = { - .sin6_family = AF_INET6, - .sin6_port = 0, - }; - - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &net_ctx); - zassert_equal(ret, 0, "Create IPv6 UDP context failed"); - - memcpy(&src_addr6.sin6_addr, &my_addr2, sizeof(struct in6_addr)); - memcpy(&dst_addr6.sin6_addr, &dst_addr2, sizeof(struct in6_addr)); - - ret = net_context_bind(net_ctx, (struct sockaddr *)&src_addr6, - sizeof(struct sockaddr_in6)); - zassert_equal(ret, 0, "Context bind failure test failed"); - - iface = net_if_ipv6_select_src_iface(&dst_addr6.sin6_addr); - ctx = net_if_get_device(iface)->data; - zassert_equal_ptr(ð_context_offloading_enabled, ctx, - "eth context mismatch"); - len = strlen(test_data); + net_ctx = test_udp_context_prepare(AF_INET6, true, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; start_receiving = true; @@ -876,8 +800,8 @@ ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6) K_NO_WAIT, NULL); zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); - ret = net_context_sendto(net_ctx, test_data, len, - (struct sockaddr *)&dst_addr6, + len = strlen(test_data); + ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, sizeof(struct sockaddr_in6), NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); @@ -896,34 +820,11 @@ ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6) ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4) { struct net_context *net_ctx; - struct eth_context *ctx; /* This is interface context */ - struct net_if *iface; + struct sockaddr dst_addr; int ret, len; - struct sockaddr_in dst_addr4 = { - .sin_family = AF_INET, - .sin_port = htons(TEST_PORT), - }; - struct sockaddr_in src_addr4 = { - .sin_family = AF_INET, - .sin_port = 0, - }; - - ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &net_ctx); - zassert_equal(ret, 0, "Create IPv4 UDP context failed"); - - memcpy(&src_addr4.sin_addr, &in4addr_my2, sizeof(struct in_addr)); - memcpy(&dst_addr4.sin_addr, &in4addr_dst2, sizeof(struct in_addr)); - - ret = net_context_bind(net_ctx, (struct sockaddr *)&src_addr4, - sizeof(struct sockaddr_in)); - zassert_equal(ret, 0, "Context bind failure test failed"); - iface = eth_interfaces[1]; - ctx = net_if_get_device(iface)->data; - zassert_equal_ptr(ð_context_offloading_enabled, ctx, - "eth context mismatch"); - - len = strlen(test_data); + net_ctx = test_udp_context_prepare(AF_INET, true, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; start_receiving = true; @@ -932,8 +833,8 @@ ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4) K_NO_WAIT, NULL); zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); - ret = net_context_sendto(net_ctx, test_data, len, - (struct sockaddr *)&dst_addr4, + len = strlen(test_data); + ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, sizeof(struct sockaddr_in), NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); From 5f8a73f6cbc56fb454f5ab2508bd2636449ea0f7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Sun, 29 Oct 2023 14:24:32 +0100 Subject: [PATCH 0055/1049] tests: net: checksum_offload: Move test code into helper function Further reduce code duplication by moving test code for similar test cases into a helper function, parametrized based on the test case. Signed-off-by: Robert Lubos --- tests/net/checksum_offload/src/main.c | 196 +++++--------------------- 1 file changed, 33 insertions(+), 163 deletions(-) diff --git a/tests/net/checksum_offload/src/main.c b/tests/net/checksum_offload/src/main.c index 4fc133442110616..99d3057a1c5b571 100644 --- a/tests/net/checksum_offload/src/main.c +++ b/tests/net/checksum_offload/src/main.c @@ -574,24 +574,26 @@ static struct net_context *test_udp_context_prepare(sa_family_t family, return net_ctx; } -ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6) +static void test_tx_chksum(sa_family_t family, bool offloaded) { + struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff; + socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in); struct net_context *net_ctx; struct sockaddr dst_addr; int ret, len; - net_ctx = test_udp_context_prepare(AF_INET6, false, &dst_addr); + net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr); zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; len = strlen(test_data); ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, - sizeof(struct sockaddr_in6), - NULL, K_FOREVER, NULL); + addrlen, NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); - if (k_sem_take(&wait_data_nonoff, WAIT_TIME)) { + if (k_sem_take(wait_data, WAIT_TIME)) { DBG("Timeout while waiting interface data\n"); zassert_false(true, "Timeout"); } @@ -599,79 +601,24 @@ ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6) net_context_unref(net_ctx); } -ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4) +ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6) { - struct net_context *net_ctx; - struct sockaddr dst_addr; - int ret, len; - - net_ctx = test_udp_context_prepare(AF_INET, false, &dst_addr); - zassert_not_null(net_ctx, "Failed to obtain net_ctx"); - - test_started = true; - - len = strlen(test_data); - ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, - sizeof(struct sockaddr_in), - NULL, K_FOREVER, NULL); - zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); - - if (k_sem_take(&wait_data_nonoff, WAIT_TIME)) { - DBG("Timeout while waiting interface data\n"); - zassert_false(true, "Timeout"); - } + test_tx_chksum(AF_INET6, false); +} - net_context_unref(net_ctx); +ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4) +{ + test_tx_chksum(AF_INET, false); } ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6) { - struct net_context *net_ctx; - struct sockaddr dst_addr; - int ret, len; - - net_ctx = test_udp_context_prepare(AF_INET6, true, &dst_addr); - zassert_not_null(net_ctx, "Failed to obtain net_ctx"); - - test_started = true; - - len = strlen(test_data); - ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, - sizeof(struct sockaddr_in6), - NULL, K_FOREVER, NULL); - zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); - - if (k_sem_take(&wait_data_off, WAIT_TIME)) { - DBG("Timeout while waiting interface data\n"); - zassert_false(true, "Timeout"); - } - - net_context_unref(net_ctx); + test_tx_chksum(AF_INET6, true); } ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4) { - struct net_context *net_ctx; - struct sockaddr dst_addr; - int ret, len; - - net_ctx = test_udp_context_prepare(AF_INET, true, &dst_addr); - zassert_not_null(net_ctx, "Failed to obtain net_ctx"); - - test_started = true; - - len = strlen(test_data); - ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, - sizeof(struct sockaddr_in), - NULL, K_FOREVER, NULL); - zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); - - if (k_sem_take(&wait_data_off, WAIT_TIME)) { - DBG("Timeout while waiting interface data\n"); - zassert_false(true, "Timeout"); - } - - net_context_unref(net_ctx); + test_tx_chksum(AF_INET, true); } static void recv_cb_offload_disabled(struct net_context *context, @@ -717,29 +664,32 @@ static void recv_cb_offload_enabled(struct net_context *context, net_pkt_unref(pkt); } -ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6) +static void test_rx_chksum(sa_family_t family, bool offloaded) { + struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff; + net_context_recv_cb_t cb = offloaded ? recv_cb_offload_enabled : + recv_cb_offload_disabled; + socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in); struct net_context *net_ctx; struct sockaddr dst_addr; int ret, len; - net_ctx = test_udp_context_prepare(AF_INET6, false, &dst_addr); + net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr); zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; start_receiving = true; - ret = net_context_recv(net_ctx, recv_cb_offload_disabled, - K_NO_WAIT, NULL); + ret = net_context_recv(net_ctx, cb, K_NO_WAIT, NULL); zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); len = strlen(test_data); ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, - sizeof(struct sockaddr_in6), - NULL, K_FOREVER, NULL); + addrlen, NULL, K_FOREVER, NULL); zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); - if (k_sem_take(&wait_data_nonoff, WAIT_TIME)) { + if (k_sem_take(wait_data, WAIT_TIME)) { DBG("Timeout while waiting interface data\n"); zassert_false(true, "Timeout"); } @@ -750,104 +700,24 @@ ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6) net_context_unref(net_ctx); } -ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4) +ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6) { - struct net_context *net_ctx; - struct sockaddr dst_addr; - int ret, len; - - net_ctx = test_udp_context_prepare(AF_INET, false, &dst_addr); - zassert_not_null(net_ctx, "Failed to obtain net_ctx"); - - test_started = true; - start_receiving = true; - - ret = net_context_recv(net_ctx, recv_cb_offload_disabled, - K_NO_WAIT, NULL); - zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); - - len = strlen(test_data); - ret = net_context_sendto(net_ctx, test_data, len, - (struct sockaddr *)&dst_addr, - sizeof(struct sockaddr_in), - NULL, K_FOREVER, NULL); - zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); - - if (k_sem_take(&wait_data_nonoff, WAIT_TIME)) { - DBG("Timeout while waiting interface data\n"); - zassert_false(true, "Timeout"); - } - - /* Let the receiver to receive the packets */ - k_sleep(K_MSEC(10)); + test_rx_chksum(AF_INET6, false); +} - net_context_unref(net_ctx); +ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4) +{ + test_rx_chksum(AF_INET, false); } ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6) { - struct net_context *net_ctx; - struct sockaddr dst_addr; - int ret, len; - - net_ctx = test_udp_context_prepare(AF_INET6, true, &dst_addr); - zassert_not_null(net_ctx, "Failed to obtain net_ctx"); - - test_started = true; - start_receiving = true; - - ret = net_context_recv(net_ctx, recv_cb_offload_enabled, - K_NO_WAIT, NULL); - zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); - - len = strlen(test_data); - ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, - sizeof(struct sockaddr_in6), - NULL, K_FOREVER, NULL); - zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); - - if (k_sem_take(&wait_data_off, WAIT_TIME)) { - DBG("Timeout while waiting interface data\n"); - zassert_false(true, "Timeout"); - } - - /* Let the receiver to receive the packets */ - k_sleep(K_MSEC(10)); - - net_context_unref(net_ctx); + test_rx_chksum(AF_INET6, true); } ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4) { - struct net_context *net_ctx; - struct sockaddr dst_addr; - int ret, len; - - net_ctx = test_udp_context_prepare(AF_INET, true, &dst_addr); - zassert_not_null(net_ctx, "Failed to obtain net_ctx"); - - test_started = true; - start_receiving = true; - - ret = net_context_recv(net_ctx, recv_cb_offload_enabled, - K_NO_WAIT, NULL); - zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); - - len = strlen(test_data); - ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, - sizeof(struct sockaddr_in), - NULL, K_FOREVER, NULL); - zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); - - if (k_sem_take(&wait_data_off, WAIT_TIME)) { - DBG("Timeout while waiting interface data\n"); - zassert_false(true, "Timeout"); - } - - /* Let the receiver to receive the packets */ - k_sleep(K_MSEC(10)); - - net_context_unref(net_ctx); + test_rx_chksum(AF_INET, true); } static void *net_chksum_offload_tests_setup(void) From f505dc528e0aa565ba24f6eaf0ff01a8f64fa860 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 26 Oct 2023 14:59:22 +0200 Subject: [PATCH 0056/1049] tests: net: checksum_offload: Add tests involving IP fragmentation Add test cases verifying proper checksum calculation involving IPv4/IPv6 fragmentation. Signed-off-by: Robert Lubos --- tests/net/checksum_offload/prj.conf | 6 +- tests/net/checksum_offload/src/main.c | 647 +++++++++++++++++++++++++- 2 files changed, 631 insertions(+), 22 deletions(-) diff --git a/tests/net/checksum_offload/prj.conf b/tests/net/checksum_offload/prj.conf index ac345eaa1d7f6e5..fb86bf9dfac067a 100644 --- a/tests/net/checksum_offload/prj.conf +++ b/tests/net/checksum_offload/prj.conf @@ -1,9 +1,11 @@ CONFIG_NETWORKING=y CONFIG_NET_TEST=y CONFIG_NET_IPV6=y +CONFIG_NET_IPV6_FRAGMENT=y CONFIG_NET_UDP=y CONFIG_NET_TCP=y CONFIG_NET_IPV4=y +CONFIG_NET_IPV4_FRAGMENT=y CONFIG_NET_ARP=n CONFIG_NET_MAX_CONTEXTS=4 CONFIG_NET_L2_ETHERNET=y @@ -14,8 +16,8 @@ CONFIG_NET_IPV6_DAD=n CONFIG_NET_IPV6_MLD=n CONFIG_NET_PKT_TX_COUNT=15 CONFIG_NET_PKT_RX_COUNT=15 -CONFIG_NET_BUF_RX_COUNT=15 -CONFIG_NET_BUF_TX_COUNT=15 +CONFIG_NET_BUF_RX_COUNT=40 +CONFIG_NET_BUF_TX_COUNT=40 CONFIG_NET_IF_MAX_IPV6_COUNT=2 CONFIG_NET_IF_MAX_IPV4_COUNT=2 CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=6 diff --git a/tests/net/checksum_offload/src/main.c b/tests/net/checksum_offload/src/main.c index 99d3057a1c5b571..e9c59695602d648 100644 --- a/tests/net/checksum_offload/src/main.c +++ b/tests/net/checksum_offload/src/main.c @@ -43,6 +43,8 @@ LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL); #define TEST_PORT 9999 static char *test_data = "Test data to be sent"; +static uint8_t test_data_large[2000]; +static uint8_t verify_buf[2000]; /* Interface 1 addresses */ static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0, @@ -78,7 +80,12 @@ static struct net_if *eth_interfaces[2 + IS_ENABLED(CONFIG_ETH_NATIVE_POSIX)]; static bool test_failed; static bool test_started; +static int test_proto; +static bool verify_fragment; static bool start_receiving; +static bool change_chksum; +static int fragment_count; +static int fragment_offset; static K_SEM_DEFINE(wait_data_off, 0, UINT_MAX); static K_SEM_DEFINE(wait_data_nonoff, 0, UINT_MAX); @@ -95,6 +102,15 @@ struct eth_context { static struct eth_context eth_context_offloading_disabled; static struct eth_context eth_context_offloading_enabled; +static void verify_test_data_large(uint8_t *buf, size_t offset, size_t len) +{ + zassert(offset + len <= sizeof(test_data_large), "Out of bound data"); + + for (size_t i = 0; i < len; i++) { + zassert_equal(buf[i], test_data_large[offset + i], "Invalid data"); + } +} + static void eth_iface_init(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); @@ -137,10 +153,35 @@ static uint16_t get_udp_chksum(struct net_pkt *pkt) return udp_hdr->chksum; } +static uint16_t get_icmp_chksum(struct net_pkt *pkt) +{ + NET_PKT_DATA_ACCESS_DEFINE(icmp_access, struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; + struct net_pkt_cursor backup; + + net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_backup(pkt, &backup); + net_pkt_cursor_init(pkt); + + /* Move the cursor to the ICMP header */ + if (net_pkt_skip(pkt, sizeof(struct net_eth_hdr) + + net_pkt_ip_hdr_len(pkt) + + net_pkt_ipv6_ext_len(pkt))) { + return 0; + } + + icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data(pkt, &icmp_access); + if (!icmp_hdr) { + return 0; + } + + net_pkt_cursor_restore(pkt, &backup); + + return icmp_hdr->chksum; +} + static void test_receiving(struct net_pkt *pkt) { - NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(udp_access, struct net_udp_hdr); - struct net_udp_hdr *udp_hdr; uint16_t port; uint8_t lladdr[6]; @@ -187,13 +228,39 @@ static void test_receiving(struct net_pkt *pkt) net_ipv4_addr_copy_raw(ipv4_hdr->dst, (uint8_t *)&addr); } - net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ip_opts_len(pkt)); - udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access); - zassert_not_null(udp_hdr, "Can't access UDP header"); - - port = udp_hdr->src_port; - udp_hdr->src_port = udp_hdr->dst_port; - udp_hdr->dst_port = port; + if (!verify_fragment || fragment_count == 1) { + net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ip_opts_len(pkt)); + if (test_proto == IPPROTO_UDP) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE( + udp_access, struct net_udp_hdr); + struct net_udp_hdr *udp_hdr; + + udp_hdr = (struct net_udp_hdr *) + net_pkt_get_data(pkt, &udp_access); + zassert_not_null(udp_hdr, "Can't access UDP header"); + + port = udp_hdr->src_port; + udp_hdr->src_port = udp_hdr->dst_port; + udp_hdr->dst_port = port; + + if (change_chksum) { + udp_hdr->chksum++; + } + } else if (test_proto == IPPROTO_ICMP || + test_proto == IPPROTO_ICMPV6) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE( + icmp_access, struct net_icmp_hdr); + struct net_icmp_hdr *icmp_hdr; + + icmp_hdr = (struct net_icmp_hdr *) + net_pkt_get_data(pkt, &icmp_access); + zassert_not_null(icmp_hdr, "Can't access ICMP header"); + + if (change_chksum) { + icmp_hdr->chksum++; + } + } + } net_pkt_cursor_init(pkt); @@ -204,6 +271,61 @@ static void test_receiving(struct net_pkt *pkt) } } +static void test_fragment(struct net_pkt *pkt, bool offloaded) +{ + uint16_t chksum = 0; + size_t data_len; + size_t hdr_offset = sizeof(struct net_eth_hdr) + + net_pkt_ip_hdr_len(pkt) + + net_pkt_ip_opts_len(pkt); + + fragment_count++; + + net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_init(pkt); + + if (start_receiving) { + test_receiving(pkt); + return; + } + + if (fragment_count == 1) { + if (test_proto == IPPROTO_UDP) { + chksum = get_udp_chksum(pkt); + hdr_offset += sizeof(struct net_udp_hdr); + } else if (test_proto == IPPROTO_ICMP || + test_proto == IPPROTO_ICMPV6) { + chksum = get_icmp_chksum(pkt); + hdr_offset += sizeof(struct net_icmp_hdr) + + sizeof(struct net_icmpv6_echo_req); + } + + /* Fragmented packet should have checksum set regardless of + * checksum offloading + */ + zassert_not_equal(chksum, 0, "Checksum missing"); + } + + zassert_true(net_pkt_is_chksum_done(pkt), + "Checksum should me marked as ready on net_pkt"); + + /* Verify that payload has not been altered. */ + data_len = net_pkt_get_len(pkt) - hdr_offset; + net_pkt_skip(pkt, hdr_offset); + net_pkt_read(pkt, verify_buf, data_len); + + verify_test_data_large(verify_buf, fragment_offset, data_len); + fragment_offset += data_len; + + if (fragment_count > 1) { + if (offloaded) { + k_sem_give(&wait_data_off); + } else { + k_sem_give(&wait_data_nonoff); + } + } +} + static int eth_tx_offloading_disabled(const struct device *dev, struct net_pkt *pkt) { @@ -218,19 +340,29 @@ static int eth_tx_offloading_disabled(const struct device *dev, return -ENODATA; } + if (verify_fragment) { + test_fragment(pkt, false); + return 0; + } + if (start_receiving) { test_receiving(pkt); return 0; } if (test_started) { - uint16_t chksum; + uint16_t chksum = 0; - chksum = get_udp_chksum(pkt); + if (test_proto == IPPROTO_UDP) { + chksum = get_udp_chksum(pkt); + } else if (test_proto == IPPROTO_ICMP || + test_proto == IPPROTO_ICMPV6) { + chksum = get_icmp_chksum(pkt); + } DBG("Chksum 0x%x offloading disabled\n", chksum); - zassert_not_equal(chksum, 0, "Checksum calculated"); + zassert_not_equal(chksum, 0, "Checksum not calculated"); k_sem_give(&wait_data_nonoff); } @@ -252,15 +384,24 @@ static int eth_tx_offloading_enabled(const struct device *dev, return -ENODATA; } + if (verify_fragment) { + test_fragment(pkt, true); + return 0; + } + if (start_receiving) { test_receiving(pkt); - return 0; } if (test_started) { - uint16_t chksum; + uint16_t chksum = 0; - chksum = get_udp_chksum(pkt); + if (test_proto == IPPROTO_UDP) { + chksum = get_udp_chksum(pkt); + } else if (test_proto == IPPROTO_ICMP || + test_proto == IPPROTO_ICMPV6) { + chksum = get_icmp_chksum(pkt); + } DBG("Chksum 0x%x offloading enabled\n", chksum); @@ -587,6 +728,7 @@ static void test_tx_chksum(sa_family_t family, bool offloaded) zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; + test_proto = IPPROTO_UDP; len = strlen(test_data); ret = net_context_sendto(net_ctx, test_data, len, &dst_addr, @@ -621,6 +763,179 @@ ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4) test_tx_chksum(AF_INET, true); } +static void test_tx_chksum_udp_frag(sa_family_t family, bool offloaded) +{ + struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff; + socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in); + struct net_context *net_ctx; + struct sockaddr dst_addr; + int ret, len; + + net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); + + test_started = true; + test_proto = IPPROTO_UDP; + verify_fragment = true; + + len = sizeof(test_data_large); + ret = net_context_sendto(net_ctx, test_data_large, len, &dst_addr, + addrlen, NULL, K_FOREVER, NULL); + zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); + + if (k_sem_take(wait_data, WAIT_TIME)) { + DBG("Timeout while waiting interface data\n"); + zassert_false(true, "Timeout"); + } + + net_context_unref(net_ctx); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6_udp_frag) +{ + test_tx_chksum_udp_frag(AF_INET6, false); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4_udp_frag) +{ + test_tx_chksum_udp_frag(AF_INET, false); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6_udp_frag) +{ + test_tx_chksum_udp_frag(AF_INET6, true); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4_udp_frag) +{ + test_tx_chksum_udp_frag(AF_INET, true); +} + +static int dummy_icmp_handler(struct net_icmp_ctx *ctx, + struct net_pkt *pkt, + struct net_icmp_ip_hdr *hdr, + struct net_icmp_hdr *icmp_hdr, + void *user_data) +{ + ARG_UNUSED(ctx); + ARG_UNUSED(pkt); + ARG_UNUSED(hdr); + ARG_UNUSED(icmp_hdr); + ARG_UNUSED(user_data); + + return 0; +} + +static void test_icmp_init(sa_family_t family, bool offloaded, + struct sockaddr *dst_addr, struct net_if **iface) +{ + if (family == AF_INET6) { + struct sockaddr_in6 *dst_addr6 = + (struct sockaddr_in6 *)dst_addr; + + dst_addr6->sin6_family = AF_INET6; + + if (offloaded) { + memcpy(&dst_addr6->sin6_addr, &dst_addr2, + sizeof(struct in6_addr)); + } else { + memcpy(&dst_addr6->sin6_addr, &dst_addr1, + sizeof(struct in6_addr)); + } + } else { + struct sockaddr_in *dst_addr4 = + (struct sockaddr_in *)dst_addr; + + dst_addr4->sin_family = AF_INET; + + if (offloaded) { + memcpy(&dst_addr4->sin_addr, &in4addr_dst2, + sizeof(struct in_addr)); + } else { + memcpy(&dst_addr4->sin_addr, &in4addr_dst, + sizeof(struct in_addr)); + } + } + + if (offloaded) { + *iface = eth_interfaces[1]; + } else { + *iface = eth_interfaces[0]; + } +} + +static void test_tx_chksum_icmp_frag(sa_family_t family, bool offloaded) +{ + struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff; + struct net_icmp_ping_params params = { 0 }; + struct net_icmp_ctx ctx; + struct sockaddr dst_addr; + struct net_if *iface; + int ret; + + test_icmp_init(family, offloaded, &dst_addr, &iface); + + ret = net_icmp_init_ctx(&ctx, 0, 0, dummy_icmp_handler); + zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret); + + test_started = true; + test_proto = (family == AF_INET6) ? IPPROTO_ICMPV6 : IPPROTO_ICMP; + verify_fragment = true; + + params.data = test_data_large; + params.data_size = sizeof(test_data_large); + ret = net_icmp_send_echo_request(&ctx, iface, &dst_addr, ¶ms, NULL); + zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret); + + if (k_sem_take(wait_data, WAIT_TIME)) { + DBG("Timeout while waiting interface data\n"); + zassert_false(true, "Timeout"); + } + + ret = net_icmp_cleanup_ctx(&ctx); + zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6_icmp_frag) +{ + test_tx_chksum_icmp_frag(AF_INET6, false); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4_icmp_frag) +{ + test_tx_chksum_icmp_frag(AF_INET, false); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6_icmp_frag) +{ + test_tx_chksum_icmp_frag(AF_INET6, true); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4_icmp_frag) +{ + test_tx_chksum_icmp_frag(AF_INET, true); +} + +static void test_fragment_rx_udp(struct net_pkt *pkt, + union net_proto_header *proto_hdr) +{ + size_t hdr_offset = net_pkt_ip_hdr_len(pkt) + + net_pkt_ip_opts_len(pkt) + + sizeof(struct net_udp_hdr); + size_t data_len = net_pkt_get_len(pkt) - hdr_offset; + + /* In case of fragmented packets, checksum shall be present/verified + * regardless. + */ + zassert_not_equal(proto_hdr->udp->chksum, 0, "Checksum is not set"); + zassert_equal(net_calc_verify_chksum_udp(pkt), 0, "Incorrect checksum"); + + /* Verify that packet content has not been altered */ + net_pkt_read(pkt, verify_buf, data_len); + verify_test_data_large(verify_buf, 0, data_len); +} + static void recv_cb_offload_disabled(struct net_context *context, struct net_pkt *pkt, union net_ip_header *ip_hdr, @@ -629,7 +944,13 @@ static void recv_cb_offload_disabled(struct net_context *context, void *user_data) { zassert_not_null(proto_hdr->udp, "UDP header missing"); - zassert_not_equal(proto_hdr->udp->chksum, 0, "Checksum is not set"); + + if (verify_fragment) { + test_fragment_rx_udp(pkt, proto_hdr); + } else { + zassert_not_equal(proto_hdr->udp->chksum, 0, "Checksum is not set"); + zassert_equal(net_calc_verify_chksum_udp(pkt), 0, "Incorrect checksum"); + } if (net_pkt_family(pkt) == AF_INET) { struct net_ipv4_hdr *ipv4 = NET_IPV4_HDR(pkt); @@ -651,12 +972,17 @@ static void recv_cb_offload_enabled(struct net_context *context, void *user_data) { zassert_not_null(proto_hdr->udp, "UDP header missing"); - zassert_equal(proto_hdr->udp->chksum, 0, "Checksum is set"); - if (net_pkt_family(pkt) == AF_INET) { - struct net_ipv4_hdr *ipv4 = NET_IPV4_HDR(pkt); + if (verify_fragment) { + test_fragment_rx_udp(pkt, proto_hdr); + } else { + zassert_equal(proto_hdr->udp->chksum, 0, "Checksum is set"); + + if (net_pkt_family(pkt) == AF_INET) { + struct net_ipv4_hdr *ipv4 = NET_IPV4_HDR(pkt); - zassert_equal(ipv4->chksum, 0, "IPv4 checksum is set"); + zassert_equal(ipv4->chksum, 0, "IPv4 checksum is set"); + } } k_sem_give(&wait_data_off); @@ -679,6 +1005,7 @@ static void test_rx_chksum(sa_family_t family, bool offloaded) zassert_not_null(net_ctx, "Failed to obtain net_ctx"); test_started = true; + test_proto = IPPROTO_UDP; start_receiving = true; ret = net_context_recv(net_ctx, cb, K_NO_WAIT, NULL); @@ -720,6 +1047,275 @@ ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4) test_rx_chksum(AF_INET, true); } +static void test_rx_chksum_udp_frag(sa_family_t family, bool offloaded) +{ + struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff; + net_context_recv_cb_t cb = offloaded ? recv_cb_offload_enabled : + recv_cb_offload_disabled; + socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in); + struct net_context *net_ctx; + struct sockaddr dst_addr; + int ret, len; + + net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); + + test_started = true; + test_proto = IPPROTO_UDP; + start_receiving = true; + verify_fragment = true; + + ret = net_context_recv(net_ctx, cb, K_NO_WAIT, NULL); + zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); + + len = sizeof(test_data_large); + ret = net_context_sendto(net_ctx, test_data_large, len, &dst_addr, + addrlen, NULL, K_FOREVER, NULL); + zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); + + if (k_sem_take(wait_data, WAIT_TIME)) { + DBG("Timeout while waiting interface data\n"); + zassert_false(true, "Timeout"); + } + + /* Let the receiver to receive the packets */ + k_sleep(K_MSEC(10)); + + net_context_unref(net_ctx); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6_udp_frag) +{ + test_rx_chksum_udp_frag(AF_INET6, false); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4_udp_frag) +{ + test_rx_chksum_udp_frag(AF_INET, false); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6_udp_frag) +{ + test_rx_chksum_udp_frag(AF_INET6, true); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4_udp_frag) +{ + test_rx_chksum_udp_frag(AF_INET, true); +} + +static void test_rx_chksum_udp_frag_bad(sa_family_t family, bool offloaded) +{ + struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff; + net_context_recv_cb_t cb = offloaded ? recv_cb_offload_enabled : + recv_cb_offload_disabled; + socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in); + struct net_context *net_ctx; + struct sockaddr dst_addr; + int ret, len; + + net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr); + zassert_not_null(net_ctx, "Failed to obtain net_ctx"); + + test_started = true; + test_proto = IPPROTO_UDP; + start_receiving = true; + verify_fragment = true; + change_chksum = true; + + ret = net_context_recv(net_ctx, cb, K_NO_WAIT, NULL); + zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret); + + len = sizeof(test_data_large); + ret = net_context_sendto(net_ctx, test_data_large, len, &dst_addr, + addrlen, NULL, K_FOREVER, NULL); + zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret); + + if (k_sem_take(wait_data, WAIT_TIME) == 0) { + DBG("Packet with bad chksum should be dropped\n"); + zassert_false(true, "Packet received"); + } + + /* Let the receiver to receive the packets */ + k_sleep(K_MSEC(10)); + + net_context_unref(net_ctx); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6_udp_frag_bad) +{ + test_rx_chksum_udp_frag_bad(AF_INET6, false); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4_udp_frag_bad) +{ + test_rx_chksum_udp_frag_bad(AF_INET, false); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6_udp_frag_bad) +{ + test_rx_chksum_udp_frag_bad(AF_INET6, true); +} + +ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4_udp_frag_bad) +{ + test_rx_chksum_udp_frag_bad(AF_INET, true); +} + +static int icmp_handler(struct net_icmp_ctx *ctx, + struct net_pkt *pkt, + struct net_icmp_ip_hdr *hdr, + struct net_icmp_hdr *icmp_hdr, + void *user_data) +{ + struct k_sem *wait_data = user_data; + + size_t hdr_offset = net_pkt_ip_hdr_len(pkt) + + net_pkt_ip_opts_len(pkt) + + sizeof(struct net_icmp_hdr) + + sizeof(struct net_icmpv6_echo_req); + size_t data_len = net_pkt_get_len(pkt) - hdr_offset; + + /* In case of fragmented packets, checksum shall be present/verified + * regardless. + */ + zassert_not_equal(icmp_hdr->chksum, 0, "Checksum is not set"); + + if (test_proto == IPPROTO_ICMPV6) { + zassert_equal(net_calc_chksum_icmpv6(pkt), 0, "Incorrect checksum"); + } else { + zassert_equal(net_calc_chksum_icmpv4(pkt), 0, "Incorrect checksum"); + } + + /* Verify that packet content has not been altered */ + net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_init(pkt); + net_pkt_skip(pkt, hdr_offset); + net_pkt_read(pkt, verify_buf, data_len); + verify_test_data_large(verify_buf, 0, data_len); + + k_sem_give(wait_data); + + return 0; +} + +static void test_rx_chksum_icmp_frag(sa_family_t family, bool offloaded) +{ + struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff; + struct net_icmp_ping_params params = { 0 }; + struct net_icmp_ctx ctx; + struct sockaddr dst_addr; + struct net_if *iface; + int ret; + + test_icmp_init(family, offloaded, &dst_addr, &iface); + + ret = net_icmp_init_ctx(&ctx, + family == AF_INET6 ? NET_ICMPV6_ECHO_REPLY : + NET_ICMPV4_ECHO_REPLY, + 0, icmp_handler); + zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret); + + test_started = true; + test_proto = (family == AF_INET6) ? IPPROTO_ICMPV6 : IPPROTO_ICMP; + start_receiving = true; + verify_fragment = true; + + params.data = test_data_large; + params.data_size = sizeof(test_data_large); + ret = net_icmp_send_echo_request(&ctx, iface, &dst_addr, ¶ms, + wait_data); + zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret); + + if (k_sem_take(wait_data, WAIT_TIME)) { + DBG("Timeout while waiting interface data\n"); + zassert_false(true, "Timeout"); + } + + ret = net_icmp_cleanup_ctx(&ctx); + zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6_icmp_frag) +{ + test_rx_chksum_icmp_frag(AF_INET6, false); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4_icmp_frag) +{ + test_rx_chksum_icmp_frag(AF_INET, false); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6_icmp_frag) +{ + test_rx_chksum_icmp_frag(AF_INET6, true); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4_icmp_frag) +{ + test_rx_chksum_icmp_frag(AF_INET, true); +} + +static void test_rx_chksum_icmp_frag_bad(sa_family_t family, bool offloaded) +{ + struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff; + struct net_icmp_ping_params params = { 0 }; + struct net_icmp_ctx ctx; + struct sockaddr dst_addr; + struct net_if *iface; + int ret; + + test_icmp_init(family, offloaded, &dst_addr, &iface); + + ret = net_icmp_init_ctx(&ctx, + family == AF_INET6 ? NET_ICMPV6_ECHO_REPLY : + NET_ICMPV4_ECHO_REPLY, + 0, icmp_handler); + zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret); + + test_started = true; + test_proto = (family == AF_INET6) ? IPPROTO_ICMPV6 : IPPROTO_ICMP; + start_receiving = true; + verify_fragment = true; + change_chksum = true; + + params.data = test_data_large; + params.data_size = sizeof(test_data_large); + ret = net_icmp_send_echo_request(&ctx, iface, &dst_addr, ¶ms, + wait_data); + zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret); + + if (k_sem_take(wait_data, WAIT_TIME) == 0) { + DBG("Packet with bad chksum should be dropped\n"); + zassert_false(true, "Packet received"); + } + + ret = net_icmp_cleanup_ctx(&ctx); + zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6_icmp_frag_bad) +{ + test_rx_chksum_icmp_frag_bad(AF_INET6, false); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4_icmp_frag_bad) +{ + test_rx_chksum_icmp_frag_bad(AF_INET, false); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6_icmp_frag_bad) +{ + test_rx_chksum_icmp_frag_bad(AF_INET6, true); +} + +ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4_icmp_frag_bad) +{ + test_rx_chksum_icmp_frag_bad(AF_INET, true); +} + static void *net_chksum_offload_tests_setup(void) { test_eth_setup(); @@ -728,6 +1324,10 @@ static void *net_chksum_offload_tests_setup(void) add_neighbor(eth_interfaces[0], &dst_addr1); add_neighbor(eth_interfaces[1], &dst_addr2); + for (size_t i = 0; i < sizeof(test_data_large); i++) { + test_data_large[i] = (uint8_t)i; + } + return NULL; } @@ -741,6 +1341,13 @@ static void net_chksum_offload_tests_before(void *fixture) test_failed = false; test_started = false; start_receiving = false; + verify_fragment = false; + change_chksum = false; + fragment_count = 0; + fragment_offset = 0; + test_proto = 0; + + memset(verify_buf, 0, sizeof(verify_buf)); } ZTEST_SUITE(net_chksum_offload, NULL, net_chksum_offload_tests_setup, From c724cf99f4d40a056dc1aaef594c55754b43e99a Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 8 Nov 2023 10:18:01 +0100 Subject: [PATCH 0057/1049] net: pkt: Add explicit flag to indicate packet is IP reassembled The current logic to determine whether a packet is IP reassembled is flawed, as it only worked in certain conditions (which was ok, as the conditions were satisfied for the current use case, but now it's a public function). Therefore, add an explicit flag that indicates whether a packet is IP reassembled or not. Signed-off-by: Robert Lubos --- include/zephyr/net/net_pkt.h | 33 ++++++++++++++++++++++++--------- subsys/net/ip/ipv4_fragment.c | 1 + subsys/net/ip/ipv6_fragment.c | 1 + subsys/net/ip/net_pkt.c | 1 + 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index 591002a9d6683fc..fb00d7b980c1601 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -197,7 +197,9 @@ struct net_pkt { uint8_t chksum_done : 1; /* Checksum has already been computed for * the packet. */ - +#if defined(CONFIG_NET_IPV4_FRAGMENT) || defined(CONFIG_NET_IPV6_FRAGMENT) + uint8_t ip_reassembled : 1; /* Packet is a reassembled IP packet. */ +#endif /* bitfield byte alignment boundary */ #if defined(CONFIG_NET_IP) @@ -836,20 +838,33 @@ static inline void net_pkt_set_ipv6_fragment_id(struct net_pkt *pkt, } #endif /* CONFIG_NET_IPV6_FRAGMENT */ +#if defined(CONFIG_NET_IPV4_FRAGMENT) || defined(CONFIG_NET_IPV6_FRAGMENT) static inline bool net_pkt_is_ip_reassembled(struct net_pkt *pkt) { - if ((IS_ENABLED(CONFIG_NET_IPV4_FRAGMENT) && - net_pkt_family(pkt) == AF_INET && - net_pkt_ipv4_fragment_more(pkt)) || - (IS_ENABLED(CONFIG_NET_IPV6_FRAGMENT) && - net_pkt_family(pkt) == AF_INET6 && - net_pkt_ipv6_fragment_start(pkt))) { - return true; - } + return !!(pkt->ip_reassembled); +} + +static inline void net_pkt_set_ip_reassembled(struct net_pkt *pkt, + bool reassembled) +{ + pkt->ip_reassembled = reassembled; +} +#else /* CONFIG_NET_IPV4_FRAGMENT || CONFIG_NET_IPV6_FRAGMENT */ +static inline bool net_pkt_is_ip_reassembled(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); return false; } +static inline void net_pkt_set_ip_reassembled(struct net_pkt *pkt, + bool reassembled) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(reassembled); +} +#endif /* CONFIG_NET_IPV4_FRAGMENT || CONFIG_NET_IPV6_FRAGMENT */ + static inline uint8_t net_pkt_priority(struct net_pkt *pkt) { return pkt->priority; diff --git a/subsys/net/ip/ipv4_fragment.c b/subsys/net/ip/ipv4_fragment.c index 5bcf4e0026c5cd6..ee6e43c83d3dfbc 100644 --- a/subsys/net/ip/ipv4_fragment.c +++ b/subsys/net/ip/ipv4_fragment.c @@ -203,6 +203,7 @@ static void reassemble_packet(struct net_ipv4_reassembly *reass) ipv4_hdr->chksum = net_calc_chksum_ipv4(pkt); net_pkt_set_data(pkt, &ipv4_access); + net_pkt_set_ip_reassembled(pkt, true); LOG_DBG("New pkt %p IPv4 len is %d bytes", pkt, net_pkt_get_len(pkt)); diff --git a/subsys/net/ip/ipv6_fragment.c b/subsys/net/ip/ipv6_fragment.c index 6d391b3b823e4cf..fda00c59f039022 100644 --- a/subsys/net/ip/ipv6_fragment.c +++ b/subsys/net/ip/ipv6_fragment.c @@ -338,6 +338,7 @@ static void reassemble_packet(struct net_ipv6_reassembly *reass) ipv6.hdr->len = htons(len); net_pkt_set_data(pkt, &ipv6_access); + net_pkt_set_ip_reassembled(pkt, true); NET_DBG("New pkt %p IPv6 len is %d bytes", pkt, len + NET_IPV6H_LEN); diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index cef7cbcd1076d69..ea60060abe578a5 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -1813,6 +1813,7 @@ static void clone_pkt_attributes(struct net_pkt *pkt, struct net_pkt *clone_pkt) net_pkt_set_ptp(clone_pkt, net_pkt_is_ptp(pkt)); net_pkt_set_forwarding(clone_pkt, net_pkt_forwarding(pkt)); net_pkt_set_chksum_done(clone_pkt, net_pkt_is_chksum_done(pkt)); + net_pkt_set_ip_reassembled(pkt, net_pkt_is_ip_reassembled(pkt)); net_pkt_set_l2_bridged(clone_pkt, net_pkt_is_l2_bridged(pkt)); net_pkt_set_l2_processed(clone_pkt, net_pkt_is_l2_processed(pkt)); From 83f9fc4ce2537d9cb9ba820ec2b705a09926c68e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 8 Nov 2023 10:53:04 +0100 Subject: [PATCH 0058/1049] net: ip: Add hidden Kconfig symbol for IP fragmentation Instead of consistently checking for both, IPv4 and IPv6 fragmentation in several places, add a hidden Kconfig symbol which indicates that some IP fragmentation has been enabled (either IPv4 or IPv6 or both). Signed-off-by: Robert Lubos --- include/zephyr/net/net_pkt.h | 12 ++++++------ subsys/net/ip/Kconfig | 5 +++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index fb00d7b980c1601..4f67249f15ba512 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -197,7 +197,7 @@ struct net_pkt { uint8_t chksum_done : 1; /* Checksum has already been computed for * the packet. */ -#if defined(CONFIG_NET_IPV4_FRAGMENT) || defined(CONFIG_NET_IPV6_FRAGMENT) +#if defined(CONFIG_NET_IP_FRAGMENT) uint8_t ip_reassembled : 1; /* Packet is a reassembled IP packet. */ #endif /* bitfield byte alignment boundary */ @@ -224,7 +224,7 @@ struct net_pkt { #endif }; -#if defined(CONFIG_NET_IPV4_FRAGMENT) || defined(CONFIG_NET_IPV6_FRAGMENT) +#if defined(CONFIG_NET_IP_FRAGMENT) union { #if defined(CONFIG_NET_IPV4_FRAGMENT) struct { @@ -240,7 +240,7 @@ struct net_pkt { } ipv6_fragment; #endif /* CONFIG_NET_IPV6_FRAGMENT */ }; -#endif /* CONFIG_NET_IPV4_FRAGMENT || CONFIG_NET_IPV6_FRAGMENT */ +#endif /* CONFIG_NET_IP_FRAGMENT */ #if defined(CONFIG_NET_IPV6) /* Where is the start of the last header before payload data @@ -838,7 +838,7 @@ static inline void net_pkt_set_ipv6_fragment_id(struct net_pkt *pkt, } #endif /* CONFIG_NET_IPV6_FRAGMENT */ -#if defined(CONFIG_NET_IPV4_FRAGMENT) || defined(CONFIG_NET_IPV6_FRAGMENT) +#if defined(CONFIG_NET_IP_FRAGMENT) static inline bool net_pkt_is_ip_reassembled(struct net_pkt *pkt) { return !!(pkt->ip_reassembled); @@ -849,7 +849,7 @@ static inline void net_pkt_set_ip_reassembled(struct net_pkt *pkt, { pkt->ip_reassembled = reassembled; } -#else /* CONFIG_NET_IPV4_FRAGMENT || CONFIG_NET_IPV6_FRAGMENT */ +#else /* CONFIG_NET_IP_FRAGMENT */ static inline bool net_pkt_is_ip_reassembled(struct net_pkt *pkt) { ARG_UNUSED(pkt); @@ -863,7 +863,7 @@ static inline void net_pkt_set_ip_reassembled(struct net_pkt *pkt, ARG_UNUSED(pkt); ARG_UNUSED(reassembled); } -#endif /* CONFIG_NET_IPV4_FRAGMENT || CONFIG_NET_IPV6_FRAGMENT */ +#endif /* CONFIG_NET_IP_FRAGMENT */ static inline uint8_t net_pkt_priority(struct net_pkt *pkt) { diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index b8e51e09f641b62..fffa028b628faba 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -12,6 +12,11 @@ config NET_IP bool default y if NET_IPV6 || NET_IPV4 +# Hidden option enabled whenever an IP fragmentation is enabled. +config NET_IP_FRAGMENT + bool + default y if NET_IPV6_FRAGMENT || NET_IPV4_FRAGMENT + # Hidden option selected by net connection based socket implementations # to draw in all code required for connection infrastructure. config NET_CONNECTION_SOCKETS From c5ee143d773e713901896319a4d116082ca0771d Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Wed, 1 Nov 2023 15:44:23 +0100 Subject: [PATCH 0059/1049] Bluetooth: Mesh: no more tinycrypt in ble mesh tfm image PR allows to get rid of tinycrypt objects from the final binary of the ble mesh apps based on PSA TFM crypto. Signed-off-by: Aleksandr Khromykh --- .../boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 5 +++ .../boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 5 +++ .../boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 3 ++ subsys/bluetooth/host/Kconfig | 7 ++-- subsys/bluetooth/mesh/crypto_psa.c | 10 ++++++ tests/bsim/bluetooth/mesh/overlay_psa.conf | 5 +++ tests/bsim/bluetooth/mesh/src/test_dfu.c | 35 ++++++++++--------- .../bluetooth/mesh/src/test_persistence.c | 2 +- .../bluetooth/mesh/src/test_replay_cache.c | 8 +++++ 9 files changed, 59 insertions(+), 21 deletions(-) diff --git a/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index c638a292c910dc8..4693e4d1f78d83a 100644 --- a/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -1,3 +1,8 @@ +# The option adds TinyCrypt based bt_rand. +CONFIG_BT_HOST_CRYPTO=n +# The option adds GATT caching feature that is based on TinyCrypt. +CONFIG_BT_GATT_CACHING=n + # Known issue: non secure platforms do not work with settings subsystem. CONFIG_SETTINGS=n CONFIG_BT_SETTINGS=n diff --git a/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index c638a292c910dc8..4693e4d1f78d83a 100644 --- a/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -1,3 +1,8 @@ +# The option adds TinyCrypt based bt_rand. +CONFIG_BT_HOST_CRYPTO=n +# The option adds GATT caching feature that is based on TinyCrypt. +CONFIG_BT_GATT_CACHING=n + # Known issue: non secure platforms do not work with settings subsystem. CONFIG_SETTINGS=n CONFIG_BT_SETTINGS=n diff --git a/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index c638a292c910dc8..c3d134592fc52c3 100644 --- a/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -1,3 +1,6 @@ +# The option adds TinyCrypt based bt_rand. +CONFIG_BT_HOST_CRYPTO=n + # Known issue: non secure platforms do not work with settings subsystem. CONFIG_SETTINGS=n CONFIG_BT_SETTINGS=n diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 59cf196c363491c..f09d8a14d724b09 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -163,12 +163,13 @@ rsource "../mesh/Kconfig" rsource "../audio/Kconfig" config BT_HOST_CRYPTO - # Hidden option that compiles in AES encryption support using TinyCrypt - # library if this is not provided by the controller implementation. - bool + bool "Use crypto functionality implemented in the Bluetooth host" default y if !BT_CTLR_CRYPTO select TINYCRYPT select TINYCRYPT_AES + help + The option adds the AES encryption support using TinyCrypt + library if this is not provided by the controller implementation. config BT_HOST_CRYPTO_PRNG bool "Use Tinycrypt library for random number generation" diff --git a/subsys/bluetooth/mesh/crypto_psa.c b/subsys/bluetooth/mesh/crypto_psa.c index 450cde679a85830..587c367a6bdf3b9 100644 --- a/subsys/bluetooth/mesh/crypto_psa.c +++ b/subsys/bluetooth/mesh/crypto_psa.c @@ -7,6 +7,7 @@ #include #include +#include #define LOG_LEVEL CONFIG_BT_MESH_CRYPTO_LOG_LEVEL #include @@ -510,3 +511,12 @@ int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key return memcmp(out, raw_key, 16); } + +__weak int bt_rand(void *buf, size_t len) +{ + CHECKIF(buf == NULL || len == 0) { + return -EINVAL; + } + + return psa_generate_random(buf, len) == PSA_SUCCESS ? 0 : -EIO; +} diff --git a/tests/bsim/bluetooth/mesh/overlay_psa.conf b/tests/bsim/bluetooth/mesh/overlay_psa.conf index ba81c1e0213d52d..1957085b7e4cd80 100644 --- a/tests/bsim/bluetooth/mesh/overlay_psa.conf +++ b/tests/bsim/bluetooth/mesh/overlay_psa.conf @@ -1,2 +1,7 @@ +# The option adds TinyCrypt based bt_rand. +CONFIG_BT_HOST_CRYPTO=n +# The option adds GATT caching feature that is based on TinyCrypt. +CONFIG_BT_GATT_CACHING=n + # Enable mbedTLS PSA as a crypto backend CONFIG_BT_MESH_USES_MBEDTLS_PSA=y diff --git a/tests/bsim/bluetooth/mesh/src/test_dfu.c b/tests/bsim/bluetooth/mesh/src/test_dfu.c index 08631cba6b69fa2..0eed5d1478d2529 100644 --- a/tests/bsim/bluetooth/mesh/src/test_dfu.c +++ b/tests/bsim/bluetooth/mesh/src/test_dfu.c @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); #define TARGET_ADDR 0x0100 #define IMPOSTER_MODEL_ID 0xe000 #define TEST_BLOB_ID 0xaabbccdd +#define SEMAPHORE_TIMEOUT 250 /* seconds */ struct bind_params { uint16_t model_id; @@ -1016,7 +1017,7 @@ static void test_cli_fail_on_persistency(void) FAIL("DFU Client send failed (err: %d)", err); } - if (k_sem_take(&dfu_ended, K_SECONDS(200))) { + if (k_sem_take(&dfu_ended, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Firmware transfer failed"); } @@ -1050,7 +1051,7 @@ static void test_cli_fail_on_persistency(void) FAIL("DFU Client apply failed (err: %d)", err); } - if (k_sem_take(&dfu_cli_applied_sem, K_SECONDS(200))) { + if (k_sem_take(&dfu_cli_applied_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Failed to apply firmware"); } @@ -1063,7 +1064,7 @@ static void test_cli_fail_on_persistency(void) FAIL("DFU Client confirm failed (err: %d)", err); } - if (k_sem_take(&dfu_cli_confirmed_sem, K_SECONDS(200))) { + if (k_sem_take(&dfu_cli_confirmed_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Failed to confirm firmware"); } @@ -1096,7 +1097,7 @@ static void test_cli_all_targets_lost_common(void) FAIL("DFU Client send failed (err: %d)", err); } - if (k_sem_take(&dfu_ended, K_SECONDS(200))) { + if (k_sem_take(&dfu_ended, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Firmware transfer failed"); } } @@ -1187,7 +1188,7 @@ static void test_cli_all_targets_lost_on_apply(void) FAIL("DFU Client apply failed (err: %d)", err); } - if (!k_sem_take(&dfu_cli_applied_sem, K_SECONDS(200))) { + if (!k_sem_take(&dfu_cli_applied_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Apply should not be successful on any target"); } @@ -1218,7 +1219,7 @@ static void test_cli_stop(void) FAIL("DFU Client send failed (err: %d)", err); } - if (k_sem_take(&dfu_started, K_SECONDS(200))) { + if (k_sem_take(&dfu_started, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Firmware transfer failed"); } @@ -1234,7 +1235,7 @@ static void test_cli_stop(void) FAIL("DFU Client resume failed (err: %d)", err); } - if (k_sem_take(&dfu_verifying, K_SECONDS(200))) { + if (k_sem_take(&dfu_verifying, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Firmware transfer failed"); } ASSERT_EQUAL(BT_MESH_DFU_ERR_INTERNAL, dfu_cli_xfer.targets[0].status); @@ -1253,7 +1254,7 @@ static void test_cli_stop(void) FAIL("DFU Client send failed (err: %d)", err); } - if (k_sem_take(&dfu_verify_failed, K_SECONDS(200))) { + if (k_sem_take(&dfu_verify_failed, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Firmware transfer failed"); } @@ -1269,12 +1270,12 @@ static void test_cli_stop(void) if (err) { FAIL("DFU Client send failed (err: %d)", err); } - if (k_sem_take(&dfu_ended, K_SECONDS(200))) { + if (k_sem_take(&dfu_ended, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Firmware transfer failed"); } bt_mesh_dfu_cli_apply(&dfu_cli); - if (k_sem_take(&dfu_cli_applied_sem, K_SECONDS(200))) { + if (k_sem_take(&dfu_cli_applied_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { /* This will time out as target will reboot before applying */ } ASSERT_EQUAL(BT_MESH_DFU_ERR_INTERNAL, dfu_cli_xfer.targets[0].status); @@ -1464,7 +1465,7 @@ static void test_target_fail_on_metadata(void) common_fail_on_target_init(&target_comp); target_prov_and_conf_default(); - if (k_sem_take(&dfu_metadata_check_sem, K_SECONDS(200))) { + if (k_sem_take(&dfu_metadata_check_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Metadata check CB wasn't called"); } @@ -1478,7 +1479,7 @@ static void test_target_fail_on_caps_get(void) common_fail_on_target_init(&srv_caps_broken_comp); target_prov_and_conf_with_imposer(); - if (k_sem_take(&caps_get_sem, K_SECONDS(200))) { + if (k_sem_take(&caps_get_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("BLOB Info Get msg handler wasn't called"); } @@ -1492,11 +1493,11 @@ static void test_target_fail_on_update_get(void) common_fail_on_target_init(&srv_update_get_broken_comp); target_prov_and_conf_with_imposer(); - if (k_sem_take(&dfu_verify_sem, K_SECONDS(200))) { + if (k_sem_take(&dfu_verify_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Transfer end CB wasn't triggered"); } - if (k_sem_take(&update_get_sem, K_SECONDS(200))) { + if (k_sem_take(&update_get_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Firmware Update Get msg handler wasn't called"); } @@ -1511,7 +1512,7 @@ static void test_target_fail_on_verify(void) common_fail_on_target_init(&target_comp); target_prov_and_conf_default(); - if (k_sem_take(&dfu_verify_sem, K_SECONDS(200))) { + if (k_sem_take(&dfu_verify_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Transfer end CB wasn't triggered"); } @@ -1525,7 +1526,7 @@ static void test_target_fail_on_apply(void) common_fail_on_target_init(&srv_update_apply_broken_comp); target_prov_and_conf_with_imposer(); - if (k_sem_take(&update_apply_sem, K_SECONDS(200))) { + if (k_sem_take(&update_apply_sem, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("Firmware Update Apply msg handler wasn't called"); } @@ -1537,7 +1538,7 @@ static void test_target_fail_on_nothing(void) common_fail_on_target_init(&target_comp); target_prov_and_conf_default(); - if (k_sem_take(&dfu_ended, K_SECONDS(200))) { + if (k_sem_take(&dfu_ended, K_SECONDS(SEMAPHORE_TIMEOUT))) { FAIL("DFU failed"); } diff --git a/tests/bsim/bluetooth/mesh/src/test_persistence.c b/tests/bsim/bluetooth/mesh/src/test_persistence.c index 2f8d523bede3171..17244be15fede60 100644 --- a/tests/bsim/bluetooth/mesh/src/test_persistence.c +++ b/tests/bsim/bluetooth/mesh/src/test_persistence.c @@ -549,7 +549,7 @@ static void node_configure(void) */ uint8_t net_transmit; - net_transmit = BT_MESH_TRANSMIT(3, 20); + net_transmit = BT_MESH_TRANSMIT(3, 50); err = bt_mesh_cfg_cli_net_transmit_set(test_netkey_idx, TEST_ADDR, net_transmit, &status); if (err || status != net_transmit) { FAIL("Net transmit set failed (err %d, transmit %x)", err, status); diff --git a/tests/bsim/bluetooth/mesh/src/test_replay_cache.c b/tests/bsim/bluetooth/mesh/src/test_replay_cache.c index 5479387a4f43e66..68dc52a7b5dc636 100644 --- a/tests/bsim/bluetooth/mesh/src/test_replay_cache.c +++ b/tests/bsim/bluetooth/mesh/src/test_replay_cache.c @@ -149,6 +149,8 @@ static void test_tx_immediate_replay_attack(void) } ASSERT_TRUE(is_tx_succeeded); + /* Let complete advertising of the previous transaction to prevent collisions. */ + k_sleep(K_SECONDS(1)); } bt_mesh.seq = seq; @@ -165,6 +167,8 @@ static void test_tx_immediate_replay_attack(void) } ASSERT_TRUE(!is_tx_succeeded); + /* Let complete advertising of the previous transaction to prevent collisions. */ + k_sleep(K_SECONDS(1)); } PASS(); @@ -208,6 +212,8 @@ static void test_tx_power_replay_attack(void) } ASSERT_TRUE(!is_tx_succeeded); + /* Let complete advertising of the previous transaction to prevent collisions. */ + k_sleep(K_SECONDS(1)); } for (int i = 0; i < 3; i++) { @@ -222,6 +228,8 @@ static void test_tx_power_replay_attack(void) } ASSERT_TRUE(is_tx_succeeded); + /* Let complete advertising of the previous transaction to prevent collisions. */ + k_sleep(K_SECONDS(1)); } PASS(); From 7a32e1d84b596ecb77173b5651dd053021e5e1c5 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Thu, 2 Nov 2023 10:50:15 +0100 Subject: [PATCH 0060/1049] samples: Bluetooth: Mesh: add main stack for mesh provisioner The current main stack size is not enough for any platform. This commit stack size was checked for nrf52840 and nrf5340. Everything works. Signed-off-by: Aleksandr Khromykh --- samples/bluetooth/mesh_provisioner/prj.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bluetooth/mesh_provisioner/prj.conf b/samples/bluetooth/mesh_provisioner/prj.conf index 3b40d2c2c7b9a10..bfc6d5a12417cfd 100644 --- a/samples/bluetooth/mesh_provisioner/prj.conf +++ b/samples/bluetooth/mesh_provisioner/prj.conf @@ -1,5 +1,5 @@ #CONFIG_INIT_STACKS=y -CONFIG_MAIN_STACK_SIZE=1408 +CONFIG_MAIN_STACK_SIZE=2048 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 # The Bluetooth API should not be used from a preemptive thread: CONFIG_MAIN_THREAD_PRIORITY=-2 From a0db07888f3509e98b3b0cf10d020b3be558c19a Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Fri, 27 Oct 2023 17:01:58 +0200 Subject: [PATCH 0061/1049] drivers: flash: stm32 ospi driver active wait during init Wait with k_busy_wait instead of k_sleep during the peripheral init. Signed-off-by: Francois Ramu --- drivers/flash/flash_stm32_ospi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index 7e06f8ee2bede1a..eb84564ddea12cb 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -827,7 +827,7 @@ static int stm32_ospi_config_mem(const struct device *dev) } /* Wait that the configuration is effective and check that memory is ready */ - k_msleep(STM32_OSPI_WRITE_REG_MAX_TIME); + k_busy_wait(STM32_OSPI_WRITE_REG_MAX_TIME * USEC_PER_MSEC); /* Reconfigure the memory type of the peripheral */ dev_data->hospi.Init.MemoryType = HAL_OSPI_MEMTYPE_MACRONIX; @@ -949,8 +949,8 @@ static int stm32_ospi_mem_reset(const struct device *dev) } #endif - /* After SWreset CMD, wait in case SWReset occurred during erase operation */ - k_msleep(STM32_OSPI_RESET_MAX_TIME); + /* Wait after SWreset CMD, in case SWReset occurred during erase operation */ + k_busy_wait(STM32_OSPI_RESET_MAX_TIME * USEC_PER_MSEC); return 0; } From a2210bde638641666d8d9a9e56ba9f5add0223b8 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 7 Nov 2023 13:32:18 +0100 Subject: [PATCH 0062/1049] bluetooth: audio: delegator: Use BT_ATT_ERR_WRITE_REQ_REJECTED If the total length of the opcode and parameter values of Broadcast Receive State characteristic operation is incorrect, the server shall respond with an ATT Error Response and the Error Code set to Write Request Rejected (0xfc), instead of 0x0d (BT_ATT_ERR_INVALID_ATTRIBUTE_LEN). Signed-off-by: Magdalena Kasenberg --- subsys/bluetooth/audio/bap_scan_delegator.c | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index d0de2a4fb271525..79865fc382a3624 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -459,7 +459,7 @@ static int scan_delegator_add_source(struct bt_conn *conn, /* subtract 1 as the opcode has already been pulled */ if (buf->len < sizeof(struct bt_bap_bass_cp_add_src) - 1) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } internal_state = get_free_recv_state(); @@ -510,7 +510,7 @@ static int scan_delegator_add_source(struct bt_conn *conn, if (buf->len < (sizeof(subgroup->bis_sync) + sizeof(subgroup->metadata_len))) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } internal_state->requested_bis_sync[i] = net_buf_simple_pull_le32(buf); @@ -545,7 +545,7 @@ static int scan_delegator_add_source(struct bt_conn *conn, if (buf->len < subgroup->metadata_len) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } @@ -563,7 +563,7 @@ static int scan_delegator_add_source(struct bt_conn *conn, if (buf->len != 0) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } if (pa_sync != BT_BAP_BASS_PA_REQ_NO_SYNC) { @@ -625,7 +625,7 @@ static int scan_delegator_mod_src(struct bt_conn *conn, if (buf->len < sizeof(struct bt_bap_bass_cp_mod_src) - 1) { LOG_DBG("Invalid length %u", buf->len); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } src_id = net_buf_simple_pull_u8(buf); @@ -664,7 +664,7 @@ static int scan_delegator_mod_src(struct bt_conn *conn, if (buf->len < (sizeof(subgroup->bis_sync) + sizeof(subgroup->metadata_len))) { LOG_DBG("Invalid length %u", buf->len); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } old_bis_sync_req = internal_state->requested_bis_sync[i]; @@ -699,7 +699,7 @@ static int scan_delegator_mod_src(struct bt_conn *conn, if (buf->len < subgroup->metadata_len) { LOG_DBG("Invalid length %u", buf->len); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } if (subgroup->metadata_len > CONFIG_BT_BAP_SCAN_DELEGATOR_MAX_METADATA_LEN) { @@ -717,7 +717,7 @@ static int scan_delegator_mod_src(struct bt_conn *conn, if (buf->len != 0) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } /* All input has been validated; update receive state and check for changes */ @@ -797,7 +797,7 @@ static int scan_delegator_broadcast_code(struct bt_conn *conn, /* subtract 1 as the opcode has already been pulled */ if (buf->len != sizeof(struct bt_bap_bass_cp_broadcase_code) - 1) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } src_id = net_buf_simple_pull_u8(buf); @@ -836,7 +836,7 @@ static int scan_delegator_rem_src(struct bt_conn *conn, /* subtract 1 as the opcode has already been pulled */ if (buf->len != sizeof(struct bt_bap_bass_cp_rem_src) - 1) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } src_id = net_buf_simple_pull_u8(buf); @@ -903,7 +903,7 @@ static ssize_t write_control_point(struct bt_conn *conn, if (offset != 0) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); } else if (len == 0) { - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } net_buf_simple_init_with_data(&buf, (void *)data, len); @@ -928,7 +928,7 @@ static ssize_t write_control_point(struct bt_conn *conn, if (buf.len != 0) { LOG_DBG("Invalid length %u", buf.size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } bap_broadcast_assistant->scanning = false; @@ -938,7 +938,7 @@ static ssize_t write_control_point(struct bt_conn *conn, if (buf.len != 0) { LOG_DBG("Invalid length %u", buf.size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } bap_broadcast_assistant->scanning = true; break; From bf8a055b4ba12e248e4d17c90428b552ea1217c8 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 7 Nov 2023 14:28:07 +0100 Subject: [PATCH 0063/1049] include: dt-bindings: stm32wba_clocks.h: Add RTC_SEL macro Add a dt macro to allow configuring RTC domain clock. Signed-off-by: Erwan Gouriou --- include/zephyr/dt-bindings/clock/stm32wba_clock.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/zephyr/dt-bindings/clock/stm32wba_clock.h b/include/zephyr/dt-bindings/clock/stm32wba_clock.h index 757cb8a05524075..50ec4703e3f0a6d 100644 --- a/include/zephyr/dt-bindings/clock/stm32wba_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wba_clock.h @@ -72,6 +72,8 @@ #define CCIPR1_REG 0xE0 #define CCIPR2_REG 0xE4 #define CCIPR3_REG 0xE8 +/** @brief RCC_BCDR1 register offset (RM0493.pdf) */ +#define BCDR1_REG 0xF0 /** @brief Device clk sources selection helpers */ /** CCIPR1 devices */ @@ -90,5 +92,7 @@ #define I2C3_SEL(val) STM32_CLOCK(val, 3, 6, CCIPR3_REG) #define LPTIM1_SEL(val) STM32_CLOCK(val, 3, 10, CCIPR3_REG) #define ADC_SEL(val) STM32_CLOCK(val, 7, 12, CCIPR3_REG) +/** BCDR1 devices */ +#define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BCDR1_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_H_ */ From 645de482f0d3bfba3a3af4e3ea50cb8e9f45a155 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 7 Nov 2023 14:55:40 +0100 Subject: [PATCH 0064/1049] drivers: counter: Add support for stm32wba devices Implement RTC support in counter driver for STM32WBA devices. Changes are made according to the following specificities: - Similarly to STM32U5, it is not connected to EXTI. - On this series, there is no bit in BCDR register to enable RTC. Enabling RTC is done directly via the RCC APB register bit Signed-off-by: Erwan Gouriou --- drivers/counter/counter_ll_stm32_rtc.c | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/counter/counter_ll_stm32_rtc.c b/drivers/counter/counter_ll_stm32_rtc.c index bb8a119409b682e..76114cab386e089 100644 --- a/drivers/counter/counter_ll_stm32_rtc.c +++ b/drivers/counter/counter_ll_stm32_rtc.c @@ -184,11 +184,22 @@ static void rtc_stm32_irq_config(const struct device *dev); static int rtc_stm32_start(const struct device *dev) { +#if defined(CONFIG_SOC_SERIES_STM32WBAX) + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + const struct rtc_stm32_config *cfg = dev->config; + + /* Enable RTC bus clock */ + if (clock_control_on(clk, (clock_control_subsys_t) &cfg->pclken[0]) != 0) { + LOG_ERR("clock op failed\n"); + return -EIO; + } +#else ARG_UNUSED(dev); z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); LL_RCC_EnableRTC(); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); +#endif return 0; } @@ -196,11 +207,22 @@ static int rtc_stm32_start(const struct device *dev) static int rtc_stm32_stop(const struct device *dev) { +#if defined(CONFIG_SOC_SERIES_STM32WBAX) + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + const struct rtc_stm32_config *cfg = dev->config; + + /* Enable RTC bus clock */ + if (clock_control_on(clk, (clock_control_subsys_t) &cfg->pclken[0]) != 0) { + LOG_ERR("clock op failed\n"); + return -EIO; + } +#else ARG_UNUSED(dev); z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); LL_RCC_DisableRTC(); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); +#endif return 0; } @@ -504,7 +526,7 @@ void rtc_stm32_isr(const struct device *dev) || defined(CONFIG_SOC_SERIES_STM32L5X) \ || defined(CONFIG_SOC_SERIES_STM32H5X) LL_EXTI_ClearRisingFlag_0_31(RTC_EXTI_LINE); -#elif defined(CONFIG_SOC_SERIES_STM32U5X) +#elif defined(CONFIG_SOC_SERIES_STM32U5X) || defined(CONFIG_SOC_SERIES_STM32WBAX) /* in STM32U5 family RTC is not connected to EXTI */ #else LL_EXTI_ClearFlag_0_31(RTC_EXTI_LINE); @@ -546,7 +568,9 @@ static int rtc_stm32_init(const struct device *dev) return -EIO; } +#if !defined(CONFIG_SOC_SERIES_STM32WBAX) LL_RCC_EnableRTC(); +#endif z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); @@ -570,7 +594,7 @@ static int rtc_stm32_init(const struct device *dev) #if defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4) LL_C2_EXTI_EnableIT_0_31(RTC_EXTI_LINE); LL_EXTI_EnableRisingTrig_0_31(RTC_EXTI_LINE); -#elif defined(CONFIG_SOC_SERIES_STM32U5X) +#elif defined(CONFIG_SOC_SERIES_STM32U5X) || defined(CONFIG_SOC_SERIES_STM32WBAX) /* in STM32U5 family RTC is not connected to EXTI */ #else LL_EXTI_EnableIT_0_31(RTC_EXTI_LINE); From 9e74efd159fbf7e5f664b2764ad7f8c81f5a765b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 7 Nov 2023 14:56:23 +0100 Subject: [PATCH 0065/1049] dts: stm32wba: Add rtc node Add RTC node for stm32wba series. Signed-off-by: Erwan Gouriou --- dts/arm/st/wba/stm32wba.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index de7ec91d347af8b..6c5cc8f869a2bb8 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -189,6 +189,14 @@ }; }; + rtc: rtc@46007800 { + compatible = "st,stm32-rtc"; + reg = <0x46007800 0x400>; + interrupts = <2 0>; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00200000>; + status = "disabled"; + }; + iwdg: watchdog@40003000 { compatible = "st,stm32-watchdog"; reg = <0x40003000 0x400>; From ee75020c0a12f4dd94b5dea54fab8601b5637ed5 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 7 Nov 2023 14:58:23 +0100 Subject: [PATCH 0066/1049] boards: nucleo_wba52cg: Enable RTC node Set LSE as domain clock. Configure rtc prescaler accordingly. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts | 7 +++++++ boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml | 1 + 2 files changed, 8 insertions(+) diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts index 23b8f85e8cdc8d5..df2707f4eebd97c 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts @@ -82,6 +82,13 @@ status = "okay"; }; +&rtc { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00200000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + prescaler = <32768>; +}; + &usart1 { pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; pinctrl-names = "default"; diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml index a5eb79afc423fbc..8e075b44ae12dcb 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml @@ -15,6 +15,7 @@ supported: - arduino_gpio - arduino_i2c - arduino_spi + - counter ram: 128 flash: 1024 vendor: st From 614df97a4979d89311061d0e9912513bf28f9c20 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 7 Nov 2023 15:07:39 +0100 Subject: [PATCH 0067/1049] tests: counter_basic_api: Test subseconds on nucleo_wba52cg Enable STM32 RTC subsecond test on nucleo_wba52cg. Signed-off-by: Erwan Gouriou --- tests/drivers/counter/counter_basic_api/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drivers/counter/counter_basic_api/testcase.yaml b/tests/drivers/counter/counter_basic_api/testcase.yaml index 6e68f4480f4cf9f..2173d417c06ef41 100644 --- a/tests/drivers/counter/counter_basic_api/testcase.yaml +++ b/tests/drivers/counter/counter_basic_api/testcase.yaml @@ -23,7 +23,7 @@ tests: - drivers - counter depends_on: counter - platform_allow: nucleo_f429zi + platform_allow: nucleo_f429zi nucleo_wba52cg timeout: 600 extra_configs: - CONFIG_COUNTER_RTC_STM32_SUBSECONDS=y From d69d4013d3c39b2b1c14522863364cfe3eb73b6c Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Tue, 7 Nov 2023 16:23:34 +0200 Subject: [PATCH 0068/1049] net: lwm2m: Fix blockwise response code In CoAP blockwise the client is supposed to respond with 2.31 Continue code on Ack. This was recently broken when Block1 parsing was moved after the initialization of reponse packet. We need separate CoAP API to modify the code of existing CoAP packet. Also Ack packet should contain the Block1 options, even the last one. Signed-off-by: Seppo Takalo --- include/zephyr/net/coap.h | 9 ++++++ subsys/net/lib/coap/coap.c | 10 +++++++ subsys/net/lib/lwm2m/lwm2m_message_handling.c | 30 +++++++++++++------ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index 325ced2ebbc40c9..ebc72709751b48e 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -373,6 +373,15 @@ uint8_t coap_header_get_token(const struct coap_packet *cpkt, uint8_t *token); */ uint8_t coap_header_get_code(const struct coap_packet *cpkt); +/** + * @brief Modifies the code of the CoAP packet. + * + * @param cpkt CoAP packet representation + * @param code CoAP code + * @return 0 on success, -EINVAL on failure + */ +int coap_header_set_code(const struct coap_packet *cpkt, uint8_t code); + /** * @brief Returns the message id associated with the CoAP packet. * diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 429d3fd3d4ae660..8ac8d73e78d5693 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -950,6 +950,16 @@ static uint8_t __coap_header_get_code(const struct coap_packet *cpkt) return cpkt->data[1]; } +int coap_header_set_code(const struct coap_packet *cpkt, uint8_t code) +{ + if (!cpkt || !cpkt->data) { + return -EINVAL; + } + + cpkt->data[1] = code; + return 0; +} + uint8_t coap_header_get_token(const struct coap_packet *cpkt, uint8_t *token) { uint8_t tkl; diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index ed5f28aabdb33aa..6d006b4603e6121 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -2065,6 +2065,13 @@ static int parse_write_op(struct lwm2m_message *msg, uint16_t format) if (block_num < block_ctx->expected) { LOG_WRN("Block already handled %d, expected %d", block_num, block_ctx->expected); + (void)coap_header_set_code(msg->out.out_cpkt, COAP_RESPONSE_CODE_CONTINUE); + /* Respond with the original Block1 header, original Ack migh have been + * lost, and this is a retry. We don't know the original response, but + * since it is handled, just assume we can continue. + */ + (void)coap_append_option_int(msg->out.out_cpkt, COAP_OPTION_BLOCK1, + block_opt); return 0; } if (block_num > block_ctx->expected) { @@ -2087,30 +2094,35 @@ static int parse_write_op(struct lwm2m_message *msg, uint16_t format) * number. */ block_ctx->expected += GET_BLOCK_SIZE(block_opt) - block_ctx->ctx.block_size + 1; - - /* Handle blockwise 1 (Part 1): Set response code */ - if (!last_block) { - msg->code = COAP_RESPONSE_CODE_CONTINUE; - } } r = do_write_op(msg, format); /* Handle blockwise 1 (Part 2): Append BLOCK1 option / free context */ if (block_ctx) { - if (r >= 0 && !last_block) { - /* More to come, ack with correspond block # */ + if (r >= 0) { + /* Add block1 option to response. + * As RFC7959 Section-2.3, More flag is off, because we have already + * written the data. + */ r = coap_append_block1_option(msg->out.out_cpkt, &block_ctx->ctx); if (r < 0) { /* report as internal server error */ - LOG_ERR("Fail adding block1 option: %d", r); + LOG_DBG("Fail adding block1 option: %d", r); r = -EINVAL; } + if (!last_block) { + r = coap_header_set_code(msg->out.out_cpkt, + COAP_RESPONSE_CODE_CONTINUE); + if (r < 0) { + LOG_DBG("Failed to modify response code"); + r = -EINVAL; + } + } } if (r < 0 || last_block) { /* Free context when finished or when there is error */ free_block_ctx(block_ctx); - } } From 58ba0e1e2683582d8f6b299c7a8729a437361f51 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 8 Nov 2023 09:44:46 +0200 Subject: [PATCH 0069/1049] modules: acpica: Fix CMakeLists.txt style Fix indentation to use spaces (instead of tabs) and remove the unnecessary repetition of the condition inside endif(). Signed-off-by: Johan Hedberg --- modules/acpica/CMakeLists.txt | 342 +++++++++++++++++----------------- 1 file changed, 171 insertions(+), 171 deletions(-) diff --git a/modules/acpica/CMakeLists.txt b/modules/acpica/CMakeLists.txt index 2c77a6c16330c9a..ad8a75b0230e727 100644 --- a/modules/acpica/CMakeLists.txt +++ b/modules/acpica/CMakeLists.txt @@ -1,179 +1,179 @@ # Copyright (c) 2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -if (CONFIG_ACPI) - set(ACPI_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/) - set(INC_DIR ${ACPI_DIR}/source/include/) - set(SRC_DIR ${ACPI_DIR}/source) - set(COMP_DIR ${ACPI_DIR}/source/components) - set(PARENT_SRC_DIR ${ACPI_DIR}../../zephyr) - set(ACPI_PARENT_DIR ${ACPI_DIR}/../) +if(CONFIG_ACPI) + set(ACPI_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/) + set(INC_DIR ${ACPI_DIR}/source/include/) + set(SRC_DIR ${ACPI_DIR}/source) + set(COMP_DIR ${ACPI_DIR}/source/components) + set(PARENT_SRC_DIR ${ACPI_DIR}../../zephyr) + set(ACPI_PARENT_DIR ${ACPI_DIR}/../) - zephyr_include_directories( - ${PARENT_SRC_DIR}/include/ - ${ACPI_PARENT_DIR}/ - ${INC_DIR}/ - ${INC_DIR}/platform/ - ${SRC_DIR}/compiler/ - ${ZEPHYR_CURRENT_MODULE_DIR}/generate/zephyr/ - ${SRC_DIR}/tools/acpiexec/ - ${SRC_DIR}/tools/acpidump/ - ) + zephyr_include_directories( + ${PARENT_SRC_DIR}/include/ + ${ACPI_PARENT_DIR}/ + ${INC_DIR}/ + ${INC_DIR}/platform/ + ${SRC_DIR}/compiler/ + ${ZEPHYR_CURRENT_MODULE_DIR}/generate/zephyr/ + ${SRC_DIR}/tools/acpiexec/ + ${SRC_DIR}/tools/acpidump/ + ) - zephyr_library() + zephyr_library() - add_compile_definitions(__ZEPHYR__) - add_compile_definitions(ACPI_DEBUG_OUTPUT) - add_compile_definitions(ACPI_EXAMPLE_APP) - add_compile_definitions(CONFIG_EXTERNAL_LIBC) + add_compile_definitions(__ZEPHYR__) + add_compile_definitions(ACPI_DEBUG_OUTPUT) + add_compile_definitions(ACPI_EXAMPLE_APP) + add_compile_definitions(CONFIG_EXTERNAL_LIBC) - get_filename_component(libname "${SRC_DIR}/common/" NAME) + get_filename_component(libname "${SRC_DIR}/common/" NAME) -if (CONFIG_ACPI_DSDT_SUPPORT) - zephyr_library_sources( - ${COMP_DIR}/dispatcher/dsargs.c - ${COMP_DIR}/dispatcher/dscontrol.c - ${COMP_DIR}/dispatcher/dsdebug.c - ${COMP_DIR}/dispatcher/dsfield.c - ${COMP_DIR}/dispatcher/dsinit.c - ${COMP_DIR}/dispatcher/dsmethod.c - ${COMP_DIR}/dispatcher/dsmthdat.c - ${COMP_DIR}/dispatcher/dsobject.c - ${COMP_DIR}/dispatcher/dsopcode.c - ${COMP_DIR}/dispatcher/dspkginit.c - ${COMP_DIR}/dispatcher/dsutils.c - ${COMP_DIR}/dispatcher/dswexec.c - ${COMP_DIR}/dispatcher/dswload.c - ${COMP_DIR}/dispatcher/dswload2.c - ${COMP_DIR}/dispatcher/dswscope.c - ${COMP_DIR}/dispatcher/dswstate.c - ${COMP_DIR}/events/evhandler.c - ${COMP_DIR}/events/evmisc.c - ${COMP_DIR}/events/evregion.c - ${COMP_DIR}/events/evrgnini.c - ${COMP_DIR}/events/evxface.c - ${COMP_DIR}/events/evxfregn.c - ${COMP_DIR}/executer/exconcat.c - ${COMP_DIR}/executer/exconfig.c - ${COMP_DIR}/executer/exconvrt.c - ${COMP_DIR}/executer/excreate.c - ${COMP_DIR}/executer/exdebug.c - ${COMP_DIR}/executer/exdump.c - ${COMP_DIR}/executer/exfield.c - ${COMP_DIR}/executer/exfldio.c - ${COMP_DIR}/executer/exmisc.c - ${COMP_DIR}/executer/exmutex.c - ${COMP_DIR}/executer/exnames.c - ${COMP_DIR}/executer/exoparg1.c - ${COMP_DIR}/executer/exoparg2.c - ${COMP_DIR}/executer/exoparg3.c - ${COMP_DIR}/executer/exoparg6.c - ${COMP_DIR}/executer/exprep.c - ${COMP_DIR}/executer/exregion.c - ${COMP_DIR}/executer/exresnte.c - ${COMP_DIR}/executer/exresolv.c - ${COMP_DIR}/executer/exresop.c - ${COMP_DIR}/executer/exserial.c - ${COMP_DIR}/executer/exstore.c - ${COMP_DIR}/executer/exstoren.c - ${COMP_DIR}/executer/exstorob.c - ${COMP_DIR}/executer/exsystem.c - ${COMP_DIR}/executer/extrace.c - ${COMP_DIR}/executer/exutils.c - ${COMP_DIR}/hardware/hwpci.c - ${COMP_DIR}/namespace/nsaccess.c - ${COMP_DIR}/namespace/nsalloc.c - ${COMP_DIR}/namespace/nsarguments.c - ${COMP_DIR}/namespace/nsconvert.c - ${COMP_DIR}/namespace/nsdump.c - ${COMP_DIR}/namespace/nseval.c - ${COMP_DIR}/namespace/nsinit.c - ${COMP_DIR}/namespace/nsload.c - ${COMP_DIR}/namespace/nsnames.c - ${COMP_DIR}/namespace/nsobject.c - ${COMP_DIR}/namespace/nsparse.c - ${COMP_DIR}/namespace/nspredef.c - ${COMP_DIR}/namespace/nsprepkg.c - ${COMP_DIR}/namespace/nsrepair.c - ${COMP_DIR}/namespace/nsrepair2.c - ${COMP_DIR}/namespace/nssearch.c - ${COMP_DIR}/namespace/nsutils.c - ${COMP_DIR}/namespace/nswalk.c - ${COMP_DIR}/namespace/nsxfeval.c - ${COMP_DIR}/namespace/nsxfname.c - ${COMP_DIR}/namespace/nsxfobj.c - ${COMP_DIR}/parser/psargs.c - ${COMP_DIR}/parser/psloop.c - ${COMP_DIR}/parser/psobject.c - ${COMP_DIR}/parser/psopcode.c - ${COMP_DIR}/parser/psopinfo.c - ${COMP_DIR}/parser/psparse.c - ${COMP_DIR}/parser/psscope.c - ${COMP_DIR}/parser/pstree.c - ${COMP_DIR}/parser/psutils.c - ${COMP_DIR}/parser/pswalk.c - ${COMP_DIR}/parser/psxface.c - ${COMP_DIR}/resources/rsxface.c - ${COMP_DIR}/resources/rsutils.c - ${COMP_DIR}/resources/rsaddr.c - ${COMP_DIR}/resources/rscalc.c - ${COMP_DIR}/resources/rscreate.c - ${COMP_DIR}/resources/rsdumpinfo.c - ${COMP_DIR}/resources/rsinfo.c - ${COMP_DIR}/resources/rsio.c - ${COMP_DIR}/resources/rsirq.c - ${COMP_DIR}/resources/rslist.c - ${COMP_DIR}/resources/rsmemory.c - ${COMP_DIR}/resources/rsmisc.c - ${COMP_DIR}/resources/rsserial.c - ) -endif (CONFIG_ACPI_DSDT_SUPPORT) - zephyr_library_sources( - ${COMP_DIR}/tables/tbdata.c - ${COMP_DIR}/tables/tbfadt.c - ${COMP_DIR}/tables/tbfind.c - ${COMP_DIR}/tables/tbinstal.c - ${COMP_DIR}/tables/tbprint.c - ${COMP_DIR}/tables/tbutils.c - ${COMP_DIR}/tables/tbxface.c - ${COMP_DIR}/tables/tbxfload.c - ${COMP_DIR}/tables/tbxfroot.c - ${COMP_DIR}/utilities/utaddress.c - ${COMP_DIR}/utilities/utalloc.c - ${COMP_DIR}/utilities/utascii.c - ${COMP_DIR}/utilities/utbuffer.c - ${COMP_DIR}/utilities/utcache.c - ${COMP_DIR}/utilities/utcksum.c - ${COMP_DIR}/utilities/utcopy.c - ${COMP_DIR}/utilities/utdebug.c - ${COMP_DIR}/utilities/utdecode.c - ${COMP_DIR}/utilities/utdelete.c - ${COMP_DIR}/utilities/uterror.c - ${COMP_DIR}/utilities/uteval.c - ${COMP_DIR}/utilities/utexcep.c - ${COMP_DIR}/utilities/utglobal.c - ${COMP_DIR}/utilities/uthex.c - ${COMP_DIR}/utilities/utids.c - ${COMP_DIR}/utilities/utinit.c - ${COMP_DIR}/utilities/utlock.c - ${COMP_DIR}/utilities/utmath.c - ${COMP_DIR}/utilities/utmisc.c - ${COMP_DIR}/utilities/utmutex.c - ${COMP_DIR}/utilities/utobject.c - ${COMP_DIR}/utilities/utosi.c - ${COMP_DIR}/utilities/utownerid.c - ${COMP_DIR}/utilities/utnonansi.c - ${COMP_DIR}/utilities/utpredef.c - ${COMP_DIR}/utilities/utresrc.c - ${COMP_DIR}/utilities/utstate.c - ${COMP_DIR}/utilities/utstring.c - ${COMP_DIR}/utilities/utstrsuppt.c - ${COMP_DIR}/utilities/utstrtoul64.c - ${COMP_DIR}/utilities/utxface.c - ${COMP_DIR}/utilities/utxferror.c - ${COMP_DIR}/utilities/utxfinit.c - ${COMP_DIR}/utilities/utresdecode.c - ${COMP_DIR}/hardware/hwvalid.c - ${SRC_DIR}/os_specific/service_layers/oszephyr.c - ) -endif (CONFIG_ACPI) + if(CONFIG_ACPI_DSDT_SUPPORT) + zephyr_library_sources( + ${COMP_DIR}/dispatcher/dsargs.c + ${COMP_DIR}/dispatcher/dscontrol.c + ${COMP_DIR}/dispatcher/dsdebug.c + ${COMP_DIR}/dispatcher/dsfield.c + ${COMP_DIR}/dispatcher/dsinit.c + ${COMP_DIR}/dispatcher/dsmethod.c + ${COMP_DIR}/dispatcher/dsmthdat.c + ${COMP_DIR}/dispatcher/dsobject.c + ${COMP_DIR}/dispatcher/dsopcode.c + ${COMP_DIR}/dispatcher/dspkginit.c + ${COMP_DIR}/dispatcher/dsutils.c + ${COMP_DIR}/dispatcher/dswexec.c + ${COMP_DIR}/dispatcher/dswload.c + ${COMP_DIR}/dispatcher/dswload2.c + ${COMP_DIR}/dispatcher/dswscope.c + ${COMP_DIR}/dispatcher/dswstate.c + ${COMP_DIR}/events/evhandler.c + ${COMP_DIR}/events/evmisc.c + ${COMP_DIR}/events/evregion.c + ${COMP_DIR}/events/evrgnini.c + ${COMP_DIR}/events/evxface.c + ${COMP_DIR}/events/evxfregn.c + ${COMP_DIR}/executer/exconcat.c + ${COMP_DIR}/executer/exconfig.c + ${COMP_DIR}/executer/exconvrt.c + ${COMP_DIR}/executer/excreate.c + ${COMP_DIR}/executer/exdebug.c + ${COMP_DIR}/executer/exdump.c + ${COMP_DIR}/executer/exfield.c + ${COMP_DIR}/executer/exfldio.c + ${COMP_DIR}/executer/exmisc.c + ${COMP_DIR}/executer/exmutex.c + ${COMP_DIR}/executer/exnames.c + ${COMP_DIR}/executer/exoparg1.c + ${COMP_DIR}/executer/exoparg2.c + ${COMP_DIR}/executer/exoparg3.c + ${COMP_DIR}/executer/exoparg6.c + ${COMP_DIR}/executer/exprep.c + ${COMP_DIR}/executer/exregion.c + ${COMP_DIR}/executer/exresnte.c + ${COMP_DIR}/executer/exresolv.c + ${COMP_DIR}/executer/exresop.c + ${COMP_DIR}/executer/exserial.c + ${COMP_DIR}/executer/exstore.c + ${COMP_DIR}/executer/exstoren.c + ${COMP_DIR}/executer/exstorob.c + ${COMP_DIR}/executer/exsystem.c + ${COMP_DIR}/executer/extrace.c + ${COMP_DIR}/executer/exutils.c + ${COMP_DIR}/hardware/hwpci.c + ${COMP_DIR}/namespace/nsaccess.c + ${COMP_DIR}/namespace/nsalloc.c + ${COMP_DIR}/namespace/nsarguments.c + ${COMP_DIR}/namespace/nsconvert.c + ${COMP_DIR}/namespace/nsdump.c + ${COMP_DIR}/namespace/nseval.c + ${COMP_DIR}/namespace/nsinit.c + ${COMP_DIR}/namespace/nsload.c + ${COMP_DIR}/namespace/nsnames.c + ${COMP_DIR}/namespace/nsobject.c + ${COMP_DIR}/namespace/nsparse.c + ${COMP_DIR}/namespace/nspredef.c + ${COMP_DIR}/namespace/nsprepkg.c + ${COMP_DIR}/namespace/nsrepair.c + ${COMP_DIR}/namespace/nsrepair2.c + ${COMP_DIR}/namespace/nssearch.c + ${COMP_DIR}/namespace/nsutils.c + ${COMP_DIR}/namespace/nswalk.c + ${COMP_DIR}/namespace/nsxfeval.c + ${COMP_DIR}/namespace/nsxfname.c + ${COMP_DIR}/namespace/nsxfobj.c + ${COMP_DIR}/parser/psargs.c + ${COMP_DIR}/parser/psloop.c + ${COMP_DIR}/parser/psobject.c + ${COMP_DIR}/parser/psopcode.c + ${COMP_DIR}/parser/psopinfo.c + ${COMP_DIR}/parser/psparse.c + ${COMP_DIR}/parser/psscope.c + ${COMP_DIR}/parser/pstree.c + ${COMP_DIR}/parser/psutils.c + ${COMP_DIR}/parser/pswalk.c + ${COMP_DIR}/parser/psxface.c + ${COMP_DIR}/resources/rsxface.c + ${COMP_DIR}/resources/rsutils.c + ${COMP_DIR}/resources/rsaddr.c + ${COMP_DIR}/resources/rscalc.c + ${COMP_DIR}/resources/rscreate.c + ${COMP_DIR}/resources/rsdumpinfo.c + ${COMP_DIR}/resources/rsinfo.c + ${COMP_DIR}/resources/rsio.c + ${COMP_DIR}/resources/rsirq.c + ${COMP_DIR}/resources/rslist.c + ${COMP_DIR}/resources/rsmemory.c + ${COMP_DIR}/resources/rsmisc.c + ${COMP_DIR}/resources/rsserial.c + ) + endif() + zephyr_library_sources( + ${COMP_DIR}/tables/tbdata.c + ${COMP_DIR}/tables/tbfadt.c + ${COMP_DIR}/tables/tbfind.c + ${COMP_DIR}/tables/tbinstal.c + ${COMP_DIR}/tables/tbprint.c + ${COMP_DIR}/tables/tbutils.c + ${COMP_DIR}/tables/tbxface.c + ${COMP_DIR}/tables/tbxfload.c + ${COMP_DIR}/tables/tbxfroot.c + ${COMP_DIR}/utilities/utaddress.c + ${COMP_DIR}/utilities/utalloc.c + ${COMP_DIR}/utilities/utascii.c + ${COMP_DIR}/utilities/utbuffer.c + ${COMP_DIR}/utilities/utcache.c + ${COMP_DIR}/utilities/utcksum.c + ${COMP_DIR}/utilities/utcopy.c + ${COMP_DIR}/utilities/utdebug.c + ${COMP_DIR}/utilities/utdecode.c + ${COMP_DIR}/utilities/utdelete.c + ${COMP_DIR}/utilities/uterror.c + ${COMP_DIR}/utilities/uteval.c + ${COMP_DIR}/utilities/utexcep.c + ${COMP_DIR}/utilities/utglobal.c + ${COMP_DIR}/utilities/uthex.c + ${COMP_DIR}/utilities/utids.c + ${COMP_DIR}/utilities/utinit.c + ${COMP_DIR}/utilities/utlock.c + ${COMP_DIR}/utilities/utmath.c + ${COMP_DIR}/utilities/utmisc.c + ${COMP_DIR}/utilities/utmutex.c + ${COMP_DIR}/utilities/utobject.c + ${COMP_DIR}/utilities/utosi.c + ${COMP_DIR}/utilities/utownerid.c + ${COMP_DIR}/utilities/utnonansi.c + ${COMP_DIR}/utilities/utpredef.c + ${COMP_DIR}/utilities/utresrc.c + ${COMP_DIR}/utilities/utstate.c + ${COMP_DIR}/utilities/utstring.c + ${COMP_DIR}/utilities/utstrsuppt.c + ${COMP_DIR}/utilities/utstrtoul64.c + ${COMP_DIR}/utilities/utxface.c + ${COMP_DIR}/utilities/utxferror.c + ${COMP_DIR}/utilities/utxfinit.c + ${COMP_DIR}/utilities/utresdecode.c + ${COMP_DIR}/hardware/hwvalid.c + ${SRC_DIR}/os_specific/service_layers/oszephyr.c + ) +endif() From d06c93f24c3a96d2b582013b4cbde8f4b7230e12 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 25 Jul 2023 15:33:12 +0200 Subject: [PATCH 0070/1049] drivers: clock_control: stm32wba: Apply VOS range 2 when sysclock = 16MHz When sysclock is 16MHz, we're allowed to used VOS range 2. Signed-off-by: Erwan Gouriou --- drivers/clock_control/clock_stm32_ll_wba.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_stm32_ll_wba.c b/drivers/clock_control/clock_stm32_ll_wba.c index 46b834c52e9f4d8..8b9da70017a4dc8 100644 --- a/drivers/clock_control/clock_stm32_ll_wba.c +++ b/drivers/clock_control/clock_stm32_ll_wba.c @@ -287,7 +287,7 @@ static int get_vco_input_range(uint32_t m_div, uint32_t *range) static void set_regu_voltage(uint32_t hclk_freq) { - if (hclk_freq < MHZ(16)) { + if (hclk_freq <= MHZ(16)) { LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); } else { LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); From 26002b0607081182cd6183b690dc0f24f1ef7b29 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 8 Nov 2023 14:05:19 +0100 Subject: [PATCH 0071/1049] Bluetooth: fix doxygen warnings Fix doxygen warnings ("warning: found tag without matching ") from building the Bluetooth API documention. Signed-off-by: Henrik Brix Andersen --- .../zephyr/bluetooth/audio/bap_lc3_preset.h | 128 +++++++++--------- include/zephyr/bluetooth/audio/lc3.h | 48 +++---- include/zephyr/bluetooth/gatt.h | 34 ++--- 3 files changed, 105 insertions(+), 105 deletions(-) diff --git a/include/zephyr/bluetooth/audio/bap_lc3_preset.h b/include/zephyr/bluetooth/audio/bap_lc3_preset.h index c8b82054e01bcbe..952451d4b162266 100644 --- a/include/zephyr/bluetooth/audio/bap_lc3_preset.h +++ b/include/zephyr/bluetooth/audio/bap_lc3_preset.h @@ -31,7 +31,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_8_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ @@ -41,7 +41,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_8_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ @@ -51,7 +51,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 16_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_16_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ @@ -63,7 +63,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as both unicast client and server * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_16_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ @@ -73,7 +73,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 24_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_24_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ @@ -85,7 +85,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as unicast server * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_24_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ @@ -95,7 +95,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 32_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_32_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -105,7 +105,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 32_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_32_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -115,7 +115,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 441_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_441_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ @@ -126,7 +126,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 441_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_441_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ @@ -137,7 +137,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -147,7 +147,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -157,7 +157,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_3_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_3_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -167,7 +167,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_4_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_4_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ @@ -177,7 +177,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_5_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_5_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ @@ -187,7 +187,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_6_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_6_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ @@ -197,7 +197,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ /* Following presets are for unicast high reliability audio data */ #define BT_BAP_LC3_UNICAST_PRESET_8_1_2(_loc, _stream_context) \ @@ -208,7 +208,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_8_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ @@ -218,7 +218,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 16_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_16_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ @@ -228,7 +228,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 16_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_16_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ @@ -238,7 +238,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 24_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_24_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ @@ -248,7 +248,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 24_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_24_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ @@ -258,7 +258,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 32_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_32_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -268,7 +268,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 32_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_32_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -278,7 +278,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 441_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_441_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ @@ -289,7 +289,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 441_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_441_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ @@ -300,7 +300,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -310,7 +310,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -320,7 +320,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_3_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_3_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -330,7 +330,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_4_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_4_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ @@ -340,7 +340,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_5_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_5_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ @@ -350,7 +350,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_6_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_6_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ @@ -360,7 +360,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 8_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ /* LC3 Broadcast presets defined by table 6.4 in the BAP v1.0 specification */ #define BT_BAP_LC3_BROADCAST_PRESET_8_1_1(_loc, _stream_context) \ @@ -371,7 +371,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 8_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_8_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ @@ -381,7 +381,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 16_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ @@ -393,7 +393,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as both broadcast source and sink * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ @@ -403,7 +403,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 24_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ @@ -415,7 +415,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as broadcast sink * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ @@ -425,7 +425,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 32_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -435,7 +435,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 32_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -445,7 +445,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 441_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ @@ -456,7 +456,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 441_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ @@ -467,7 +467,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -477,7 +477,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -487,7 +487,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_3_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_3_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -497,7 +497,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_4_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_4_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ @@ -507,7 +507,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_5_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_5_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ @@ -517,7 +517,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_6_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_6_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ @@ -527,7 +527,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 8_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ /* Following presets are for broadcast high reliability audio data */ #define BT_BAP_LC3_BROADCAST_PRESET_8_1_2(_loc, _stream_context) \ @@ -538,7 +538,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 8_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_8_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ @@ -548,7 +548,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 16_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ @@ -560,7 +560,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as both broadcast source and sink * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ @@ -570,7 +570,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 24_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ @@ -582,7 +582,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as broadcast sink * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ @@ -592,7 +592,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 32_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -602,7 +602,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 32_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -612,7 +612,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 441_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ @@ -623,7 +623,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 441_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ @@ -634,7 +634,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -644,7 +644,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -654,7 +654,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_3_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_3_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -664,7 +664,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_4_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_4_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ @@ -674,7 +674,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_5_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_5_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ @@ -684,7 +684,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_6_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_6_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ diff --git a/include/zephyr/bluetooth/audio/lc3.h b/include/zephyr/bluetooth/audio/lc3.h index 5ca0f2768496203..80fec536f89e6b9 100644 --- a/include/zephyr/bluetooth/audio/lc3.h +++ b/include/zephyr/bluetooth/audio/lc3.h @@ -257,7 +257,7 @@ enum bt_audio_codec_config_frame_dur { /** * @brief Helper to declare LC3 codec capability * - * _max_frames_per_sdu value is optional and will be included only if != 1 + * ``_max_frames_per_sdu`` value is optional and will be included only if != 1 */ /* COND_CODE_1 is used to omit an LTV entry in case the _frames_per_sdu is 1. * COND_CODE_1 will evaluate to second argument if the flag parameter(first argument) is 1 @@ -292,8 +292,8 @@ enum bt_audio_codec_config_frame_dur { /** * @brief Helper to declare LC3 codec * - * @param _freq Supported Sampling Frequencies bitfield (see BT_AUDIO_CODEC_LC3_FREQ_*) - * @param _duration Supported Frame Durations bitfield (see BT_AUDIO_CODEC_LC3_DURATION_*) + * @param _freq Supported Sampling Frequencies bitfield (see ``BT_AUDIO_CODEC_LC3_FREQ_*``) + * @param _duration Supported Frame Durations bitfield (see ``BT_AUDIO_CODEC_LC3_DURATION_*``) * @param _chan_count Supported channels (see @ref BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT) * @param _len_min Minimum number of octets supported per codec frame * @param _len_max Maximum number of octets supported per codec frame @@ -311,8 +311,8 @@ enum bt_audio_codec_config_frame_dur { /** * @brief Helper to declare LC3 codec data configuration * - * @param _freq Sampling frequency (BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*) - * @param _duration Frame duration (BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*) + * @param _freq Sampling frequency (``BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*``) + * @param _duration Frame duration (``BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*``) * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _len Octets per frame (16-bit integer) * @param _frames_per_sdu Frames per SDU (8-bit integer). This value is optional and will be @@ -343,12 +343,12 @@ enum bt_audio_codec_config_frame_dur { /** * @brief Helper to declare LC3 codec configuration. * - * @param _freq Sampling frequency (BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*) - * @param _duration Frame duration (BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*) + * @param _freq Sampling frequency (``BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*``) + * @param _duration Frame duration (``BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*``) * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _len Octets per frame (16-bit integer) * @param _frames_per_sdu Frames per SDU (8-bit integer) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG(_freq, _duration, _loc, _len, _frames_per_sdu, _stream_context) \ BT_AUDIO_CODEC_CFG( \ @@ -360,7 +360,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 8.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_8_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ, \ @@ -370,7 +370,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 8.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ, \ @@ -380,7 +380,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 16.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ, \ @@ -390,7 +390,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 16.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ, \ @@ -401,7 +401,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 24.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ, \ @@ -411,7 +411,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 24.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ, \ @@ -421,7 +421,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 32.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ, \ @@ -431,7 +431,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 32.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ, \ @@ -441,7 +441,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 441.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ, \ @@ -451,7 +451,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 441.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ, \ @@ -461,7 +461,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 48.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -471,7 +471,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 48.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -481,7 +481,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 48.3 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -491,7 +491,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 48.4 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -501,7 +501,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 48.5 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -511,7 +511,7 @@ enum bt_audio_codec_config_frame_dur { * @brief Helper to declare LC3 48.6 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 6b31e5dc92baced..c50bfb25c3d4ea9 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -72,7 +72,7 @@ enum bt_gatt_perm { /** @brief Attribute prepare write permission. * - * If set, allows prepare writes with use of BT_GATT_WRITE_FLAG_PREPARE + * If set, allows prepare writes with use of ``BT_GATT_WRITE_FLAG_PREPARE`` * passed to write callback. */ BT_GATT_PERM_PREPARE_WRITE = BIT(6), @@ -140,7 +140,7 @@ struct bt_gatt_attr; * @param offset Offset to start reading from * * @return Number of bytes read, or in case of an error - * BT_GATT_ERR() with a specific BT_ATT_ERR_* error code. + * ``BT_GATT_ERR()`` with a specific ``BT_ATT_ERR_*`` error code. */ typedef ssize_t (*bt_gatt_attr_read_func_t)(struct bt_conn *conn, const struct bt_gatt_attr *attr, @@ -155,10 +155,10 @@ typedef ssize_t (*bt_gatt_attr_read_func_t)(struct bt_conn *conn, * @param buf Buffer with the data to write * @param len Number of bytes in the buffer * @param offset Offset to start writing from - * @param flags Flags (BT_GATT_WRITE_FLAG_*) + * @param flags Flags (``BT_GATT_WRITE_FLAG_*``) * * @return Number of bytes written, or in case of an error - * BT_GATT_ERR() with a specific BT_ATT_ERR_* error code. + * ``BT_GATT_ERR()`` with a specific ``BT_ATT_ERR_*`` error code. */ typedef ssize_t (*bt_gatt_attr_write_func_t)(struct bt_conn *conn, const struct bt_gatt_attr *attr, @@ -178,7 +178,7 @@ struct bt_gatt_attr { uint16_t handle; /** @brief Attribute permissions. * - * Will be 0 if returned from bt_gatt_discover(). + * Will be 0 if returned from ``bt_gatt_discover()``. */ uint16_t perm; }; @@ -379,8 +379,8 @@ void bt_gatt_cb_register(struct bt_gatt_cb *cb); /** @brief Register GATT service. * * Register GATT service. Applications can make use of - * macros such as BT_GATT_PRIMARY_SERVICE, BT_GATT_CHARACTERISTIC, - * BT_GATT_DESCRIPTOR, etc. + * macros such as ``BT_GATT_PRIMARY_SERVICE``, ``BT_GATT_CHARACTERISTIC``, + * ``BT_GATT_DESCRIPTOR``, etc. * * When using @kconfig{CONFIG_BT_SETTINGS} then all services that should have * bond configuration loaded, i.e. CCC values, must be registered before @@ -400,7 +400,7 @@ void bt_gatt_cb_register(struct bt_gatt_cb *cb); * @param svc Service containing the available attributes * * @return 0 in case of success or negative value in case of error. - * @return -EAGAIN if `bt_init()` has been called but `settings_load()` hasn't yet. + * @return -EAGAIN if ``bt_init()`` has been called but ``settings_load()`` hasn't yet. */ int bt_gatt_service_register(struct bt_gatt_service *svc); @@ -432,8 +432,8 @@ enum { * @param handle Attribute handle found. * @param user_data Data given. * - * @return BT_GATT_ITER_CONTINUE if should continue to the next attribute. - * @return BT_GATT_ITER_STOP to stop. + * @return ``BT_GATT_ITER_CONTINUE`` if should continue to the next attribute. + * @return ``BT_GATT_ITER_STOP`` to stop. */ typedef uint8_t (*bt_gatt_attr_func_t)(const struct bt_gatt_attr *attr, uint16_t handle, @@ -488,7 +488,7 @@ struct bt_gatt_attr *bt_gatt_attr_next(const struct bt_gatt_attr *attr); * * Find the attribute with the matching UUID. * To limit the search to a service set the attr to the service attributes and - * the attr_count to the service attribute count . + * the ``attr_count`` to the service attribute count . * * @param attr Pointer to an attribute that serves as the starting point * for the search of a match for the UUID. @@ -515,7 +515,7 @@ uint16_t bt_gatt_attr_get_handle(const struct bt_gatt_attr *attr); * * @param attr A Characteristic Attribute. * - * @note The user_data of the attribute must of type @ref bt_gatt_chrc. + * @note The ``user_data`` of the attribute must of type @ref bt_gatt_chrc. * * @return the handle of the corresponding Characteristic Value. The value will * be zero (the invalid handle) if @p attr was not a characteristic @@ -546,7 +546,7 @@ ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, * * Read service attribute value from local database storing the result into * buffer after encoding it. - * @note Only use this with attributes which user_data is a bt_uuid. + * @note Only use this with attributes which ``user_data`` is a ``bt_uuid``. * * @param conn Connection object. * @param attr Attribute to read. @@ -583,7 +583,7 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, * * Helper macro to statically define service structure array. Each element * of the array is linked to the service attribute array which is also - * defined in this scope using _attrs_def macro. + * defined in this scope using ``_attrs_def`` macro. * * @param _name Name of service structure array. * @param _instances Array of instances to pass as user context to the @@ -645,7 +645,7 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, * * Read include service attribute value from local database storing the result * into buffer after encoding it. - * @note Only use this with attributes which user_data is a bt_gatt_include. + * @note Only use this with attributes which user_data is a ``bt_gatt_include``. * * @param conn Connection object. * @param attr Attribute to read. @@ -675,7 +675,7 @@ ssize_t bt_gatt_attr_read_included(struct bt_conn *conn, * * Read characteristic attribute value from local database storing the result * into buffer after encoding it. - * @note Only use this with attributes which user_data is a bt_gatt_chrc. + * @note Only use this with attributes which ``user_data`` is a ``bt_gatt_chrc``. * * @param conn Connection object. * @param attr Attribute to read. @@ -705,7 +705,7 @@ ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn, * * @param _uuid Characteristic attribute uuid. * @param _props Characteristic attribute properties, - * a bitmap of BT_GATT_CHRC_* macros. + * a bitmap of ``BT_GATT_CHRC_*`` macros. * @param _perm Characteristic Attribute access permissions, * a bitmap of @ref bt_gatt_perm values. * @param _read Characteristic Attribute read callback From ec202d852f8dffb3787349088c93266505d83f8b Mon Sep 17 00:00:00 2001 From: Tobias Pisani Date: Fri, 27 Oct 2023 11:09:39 +0200 Subject: [PATCH 0072/1049] drivers: sensor: bq274xx: Configure or confirm chemistry profile Both the BQ27421 and BQ27427 have a few preset Chemistry profiles. For the BQ27421 there exists three variants of the IC, and for the BQ27427, it can be configured. The chemistry profile among other things includes the taper voltage, which is used to detect charge termination. This adds an optional `chemistry-id` config option to the driver. On the BQ27421, it will confirm that the correct variant of the IC is mounted, and on the BQ27427, it will configure it with the correct value. Side note: The reference manual for the BQ27427 (https://www.ti.com/lit/ug/sluucd5/sluucd5.pdf) currently contains some errors and inconsistencies regarding these registers. The table on page 7 appears to be correct. Signed-off-by: Tobias Pisani --- drivers/sensor/bq274xx/bq274xx.c | 69 +++++++++++++++++++++ drivers/sensor/bq274xx/bq274xx.h | 7 +++ dts/bindings/sensor/ti,bq274xx.yaml | 6 ++ include/zephyr/dt-bindings/sensor/bq274xx.h | 27 ++++++++ 4 files changed, 109 insertions(+) create mode 100644 include/zephyr/dt-bindings/sensor/bq274xx.h diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 0cf52c79f17819d..27810204798292f 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -321,6 +321,69 @@ static int bq27427_ccgain_quirk(const struct device *dev) return 0; } +static int bq274xx_ensure_chemistry(const struct device *dev) +{ + struct bq274xx_data *data = dev->data; + const struct bq274xx_config *const config = dev->config; + uint16_t chem_id = config->chemistry_id; + + if (chem_id == 0) { + /* No chemistry ID set, rely on the default of the device.*/ + return 0; + } + int ret; + uint16_t val; + + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_CHEM_ID); + if (ret < 0) { + LOG_ERR("Unable to write control register"); + return -EIO; + } + + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_CONTROL, &val); + if (ret < 0) { + LOG_ERR("Unable to read register"); + return -EIO; + } + + LOG_DBG("Chem ID: %04x", val); + + if (val != chem_id) { + /* Only the bq27427 has a configurable Chemistry ID. On bq27421, it depends on the + * variant of the chip, so just error out if the chemistry ID is wrong. + */ + if (data->regs != &bq27427_regs) { + LOG_ERR("Unable to confirm chemistry ID 0x%04x. Device reported 0x%04x", + chem_id, val); + return -EIO; + } + + uint16_t cmd; + + switch (val) { + case BQ27427_CHEM_ID_A: + cmd = BQ27427_CTRL_CHEM_A; + break; + case BQ27427_CHEM_ID_B: + cmd = BQ27427_CTRL_CHEM_B; + break; + case BQ27427_CHEM_ID_C: + cmd = BQ27427_CTRL_CHEM_C; + break; + default: + LOG_ERR("Unsupported chemistry ID 0x%04x", val); + return -EINVAL; + } + + ret = bq274xx_ctrl_reg_write(dev, cmd); + if (ret < 0) { + LOG_ERR("Unable to configure chemistry"); + return -EIO; + } + } + return 0; +} + static int bq274xx_gauge_configure(const struct device *dev) { const struct bq274xx_config *const config = dev->config; @@ -390,6 +453,11 @@ static int bq274xx_gauge_configure(const struct device *dev) } } + ret = bq274xx_ensure_chemistry(dev); + if (ret < 0) { + return ret; + } + ret = bq274xx_mode_cfgupdate(dev, false); if (ret < 0) { return ret; @@ -798,6 +866,7 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { .design_capacity = DT_INST_PROP(index, design_capacity), \ .taper_current = DT_INST_PROP(index, taper_current), \ .terminate_voltage = DT_INST_PROP(index, terminate_voltage), \ + .chemistry_id = DT_INST_PROP_OR(index, chemistry_id, 0), \ .lazy_loading = DT_INST_PROP(index, zephyr_lazy_load), \ }; \ \ diff --git a/drivers/sensor/bq274xx/bq274xx.h b/drivers/sensor/bq274xx/bq274xx.h index ead248a47380494..3fbf4f52f089130 100644 --- a/drivers/sensor/bq274xx/bq274xx.h +++ b/drivers/sensor/bq274xx/bq274xx.h @@ -9,6 +9,7 @@ #include #include +#include /*** General Constant ***/ #define BQ274XX_UNSEAL_KEY_A 0x8000 /* Unseal code one on BQ27441-G1A and similar */ @@ -59,6 +60,11 @@ #define BQ274XX_CTRL_EXIT_CFGUPDATE 0x0043 #define BQ274XX_CTRL_EXIT_RESIM 0x0044 +/* BQ27427 */ +#define BQ27427_CTRL_CHEM_A 0x0030 +#define BQ27427_CTRL_CHEM_B 0x0031 +#define BQ27427_CTRL_CHEM_C 0x0032 + /*** Extended Data Commands ***/ #define BQ274XX_EXT_OPCONFIG 0x3A /* OpConfig() */ #define BQ274XX_EXT_CAPACITY 0x3C /* DesignCapacity() */ @@ -119,6 +125,7 @@ struct bq274xx_config { #if defined(CONFIG_BQ274XX_PM) || defined(CONFIG_BQ274XX_TRIGGER) struct gpio_dt_spec int_gpios; #endif + uint16_t chemistry_id; bool lazy_loading; }; diff --git a/dts/bindings/sensor/ti,bq274xx.yaml b/dts/bindings/sensor/ti,bq274xx.yaml index 16032b625cf3593..f50aba228c1d034 100644 --- a/dts/bindings/sensor/ti,bq274xx.yaml +++ b/dts/bindings/sensor/ti,bq274xx.yaml @@ -31,6 +31,12 @@ properties: required: true description: Battery Terminate Voltage in mV + chemistry-id: + type: int + description: | + The value of the Chem ID register. When zero, the driver will not check the register. + See the reference manual for the specific BQ274xx variant for values. + int-gpios: type: phandle-array description: | diff --git a/include/zephyr/dt-bindings/sensor/bq274xx.h b/include/zephyr/dt-bindings/sensor/bq274xx.h new file mode 100644 index 000000000000000..9e8c259068ec86b --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/bq274xx.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 The Zephyr Contributors. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Relevant documents: + * - BQ27421 + * Datasheet: https://www.ti.com/lit/gpn/bq27421-g1 + * Technical reference manual: https://www.ti.com/lit/pdf/sluuac5 + * - BQ27427 + * Datasheet: https://www.ti.com/lit/gpn/bq27427 + * Technical reference manual: https://www.ti.com/lit/pdf/sluucd5 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_BQ274XX_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_BQ274XX_H_ + +/* Chemistry IDs for BQ27427 */ +#define BQ27427_CHEM_ID_A 0x3230 +#define BQ27427_CHEM_ID_B 0x1202 +#define BQ27427_CHEM_ID_C 0x3142 + +/* Chemistry IDs for BQ27421 variants */ +#define BQ27421_G1A_CHEM_ID 0x0128 +#define BQ27421_G1B_CHEM_ID 0x0312 +#define BQ27421_G1D_CHEM_ID 0x3142 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_BQ274XX_H_ */ From 73a106ccb404fa7236a457b64f4440ead510de06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 8 Nov 2023 14:32:57 +0100 Subject: [PATCH 0073/1049] charger: doc: Fix doxygen docstrings in charger header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed a couple of improperly formatted Javadoc docstrings. Added @file tag. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/charger.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/zephyr/drivers/charger.h b/include/zephyr/drivers/charger.h index 25802e6b76aa1cc..6159f41dcc00e0f 100644 --- a/include/zephyr/drivers/charger.h +++ b/include/zephyr/drivers/charger.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Charger APIs + */ + #ifndef ZEPHYR_INCLUDE_DRIVERS_CHARGER_H_ #define ZEPHYR_INCLUDE_DRIVERS_CHARGER_H_ @@ -106,7 +111,7 @@ enum charger_charge_type { CHARGER_CHARGE_TYPE_UNKNOWN = 0, /** Charging is not occurring */ CHARGER_CHARGE_TYPE_NONE, - /* + /** * Charging is occurring at the slowest desired charge rate, * typically for battery detection or preconditioning */ @@ -145,7 +150,7 @@ enum charger_health { CHARGER_HEALTH_OVERHEAT, /** The battery voltage has exceeded its overvoltage threshold */ CHARGER_HEALTH_OVERVOLTAGE, - /* + /** * The battery or charger device is experiencing an unspecified * failure. */ From 559424285f635e7bb1c6878d8475907942723249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 6 Nov 2023 14:59:58 +0100 Subject: [PATCH 0074/1049] doc: develop: update ram and rom report sample and reduce width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the sample outputs for ram and rom report commands to reflect current look&feel, and reduce the width of the output to better fit on narrow screens & PDF output. Signed-off-by: Benjamin Cabé --- doc/develop/optimizations/tools.rst | 148 ++++++++++++++-------------- 1 file changed, 76 insertions(+), 72 deletions(-) diff --git a/doc/develop/optimizations/tools.rst b/doc/develop/optimizations/tools.rst index 762891cf8d80c83..c253d47092ee587 100644 --- a/doc/develop/optimizations/tools.rst +++ b/doc/develop/optimizations/tools.rst @@ -33,37 +33,48 @@ Use the ``ram_report`` target with your board: which will generate something similar to the output below:: - Path Size % - ============================================================================================================== - ... - ... - SystemCoreClock 4 0.08% - _kernel 48 0.99% - _sw_isr_table 384 7.94% - cli.10544 16 0.33% - gpio_initialized.9765 1 0.02% - on.10543 4 0.08% - poll_out_lock.9764 4 0.08% - z_idle_threads 128 2.65% - z_interrupt_stacks 2048 42.36% - z_main_thread 128 2.65% - arch 1 0.02% - arm 1 0.02% - core 1 0.02% - aarch32 1 0.02% - cortex_m 1 0.02% - mpu 1 0.02% - arm_mpu.c 1 0.02% - static_regions_num 1 0.02% - drivers 536 11.09% - clock_control 100 2.07% - nrf_power_clock.c 100 2.07% - __device_clock_nrf 16 0.33% - data 80 1.65% - hfclk_users 4 0.08% - ... - ... - + Path Size % + ======================================================================================== + Root 4637 100.00% + ├── (hidden) 4 0.09% + ├── (no paths) 2748 59.26% + │ ├── _cpus_active 4 0.09% + │ ├── _kernel 32 0.69% + │ ├── _sw_isr_table 384 8.28% + │ ├── cli.1 16 0.35% + │ ├── on.2 4 0.09% + │ ├── poll_out_lock.0 4 0.09% + │ ├── z_idle_threads 128 2.76% + │ ├── z_interrupt_stacks 2048 44.17% + │ └── z_main_thread 128 2.76% + ├── WORKSPACE 184 3.97% + │ └── modules 184 3.97% + │ └── hal 184 3.97% + │ └── nordic 184 3.97% + │ └── nrfx 184 3.97% + │ └── drivers 184 3.97% + │ └── src 184 3.97% + │ ├── nrfx_clock.c 8 0.17% + │ │ └── m_clock_cb 8 0.17% + │ ├── nrfx_gpiote.c 132 2.85% + │ │ └── m_cb 132 2.85% + │ ├── nrfx_ppi.c 4 0.09% + │ │ └── m_channels_allocated 4 0.09% + │ └── nrfx_twim.c 40 0.86% + │ └── m_cb 40 0.86% + └── ZEPHYR_BASE 1701 36.68% + ├── arch 5 0.11% + │ └── arm 5 0.11% + │ └── core 5 0.11% + │ ├── mpu 1 0.02% + │ │ └── arm_mpu.c 1 0.02% + │ │ └── static_regions_num 1 0.02% + │ └── tls.c 4 0.09% + │ └── z_arm_tls_ptr 4 0.09% + ├── drivers 258 5.56% + │ ├── ... ... ...% + ======================================================================================== + 4637 Build Target: rom_report ======================== @@ -82,47 +93,40 @@ Use the ``rom_report`` to get the ROM report: which will generate something similar to the output below:: - Path Size % - ============================================================================================================== - ... - ... - CSWTCH.5 4 0.02% - SystemCoreClock 4 0.02% - __aeabi_idiv0 2 0.01% - __udivmoddi4 702 3.37% - _sw_isr_table 384 1.85% - delay_machine_code.9114 6 0.03% - levels.8826 20 0.10% - mpu_config 8 0.04% - transitions.10558 12 0.06% - arch 1194 5.74% - arm 1194 5.74% - core 1194 5.74% - aarch32 1194 5.74% - cortex_m 852 4.09% - fault.c 400 1.92% - bus_fault.isra.0 60 0.29% - mem_manage_fault.isra.0 56 0.27% - usage_fault.isra.0 36 0.17% - z_arm_fault 232 1.11% - z_arm_fault_init 16 0.08% - irq_init.c 24 0.12% - z_arm_interrupt_init 24 0.12% - mpu 352 1.69% - arm_core_mpu.c 56 0.27% - z_arm_configure_static_mpu_regions 56 0.27% - arm_mpu.c 296 1.42% - __init_sys_init_arm_mpu_init0 8 0.04% - arm_core_mpu_configure_static_mpu_regions 20 0.10% - arm_core_mpu_disable 16 0.08% - arm_core_mpu_enable 20 0.10% - arm_mpu_init 92 0.44% - mpu_configure_regions 140 0.67% - thread_abort.c 76 0.37% - z_impl_k_thread_abort - 76 0.37% - ... - ... + Path Size % + ======================================================================================== + Root 21652 100.00% + ├── ... ... ...% + └── ZEPHYR_BASE 13378 61.79% + ├── arch 1718 7.93% + │ └── arm 1718 7.93% + │ └── core 1718 7.93% + │ ├── cortex_m 1020 4.71% + │ │ ├── fault.c 620 2.86% + │ │ │ ├── bus_fault.constprop.0 108 0.50% + │ │ │ ├── mem_manage_fault.constprop.0 120 0.55% + │ │ │ ├── usage_fault.constprop.0 84 0.39% + │ │ │ ├── z_arm_fault 292 1.35% + │ │ │ └── z_arm_fault_init 16 0.07% + │ │ ├── ... ... ...% + ├── boards 32 0.15% + │ └── arm 32 0.15% + │ └── reel_board 32 0.15% + │ └── board.c 32 0.15% + │ ├── __init_board_reel_board_init 8 0.04% + │ └── board_reel_board_init 24 0.11% + ├── build 194 0.90% + │ └── zephyr 194 0.90% + │ ├── isr_tables.c 192 0.89% + │ │ └── _irq_vector_table 192 0.89% + │ └── misc 2 0.01% + │ └── generated 2 0.01% + │ └── configs.c 2 0.01% + │ └── _ConfigAbsSyms 2 0.01% + ├── drivers 6162 28.46% + │ ├── ... ... ...% + ======================================================================================== + 21652 Build Target: puncover ====================== From 3769938e785b09cff9ebb604a371100d1bfcf257 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Mon, 6 Nov 2023 16:53:17 -0600 Subject: [PATCH 0075/1049] boards: arm: Fix sensor shell sample for beagleconnect_freedom board Commit 944ced68f5e558c9cf5e30b69b3ab8a6d7e6f15e enabled CONFIG_UART_CONSOLE=y for the beagleconnect_freedom board, which had the side effect of satisfying a required dependency for the sensor shell sample application and causing new build errors in the weekly full twister run. Fix the build errors by moving the board's light and humidity sensor nodes to be children of the I2C controller node. Signed-off-by: Maureen Helm --- .../arm/beagle_bcf/beagleconnect_freedom.dts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/boards/arm/beagle_bcf/beagleconnect_freedom.dts b/boards/arm/beagle_bcf/beagleconnect_freedom.dts index 3f6fcafaa218718..7300e9de5db864d 100644 --- a/boards/arm/beagle_bcf/beagleconnect_freedom.dts +++ b/boards/arm/beagle_bcf/beagleconnect_freedom.dts @@ -64,18 +64,6 @@ #size-cells = <0>; controller = <&i2c0>; gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; - - light: opt3001-light@44 { - status = "okay"; - compatible = "ti,opt3001"; - reg = <0x44>; - }; - - humidity: hdc2010-humidity@41 { - status = "okay"; - compatible = "ti,hdc2010"; - reg = <0x41>; - }; }; }; @@ -138,6 +126,18 @@ compatible = "beagle,usbbridge"; reg = <0x4>; }; + + light: opt3001-light@44 { + status = "okay"; + compatible = "ti,opt3001"; + reg = <0x44>; + }; + + humidity: hdc2010-humidity@41 { + status = "okay"; + compatible = "ti,hdc2010"; + reg = <0x41>; + }; }; &spi0 { From 9bb44b8e5fc42d6d638660ef9d42edd11aa63623 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 8 Nov 2023 21:11:44 +0000 Subject: [PATCH 0076/1049] dts: arm: st: set flash size for stm32l011X4 This device lost the reg property since 88c9d1fbaf, causing the nucleo_l011k4 board to not build anymore. Add it back, 512 bytes should be the right number for this chip. Signed-off-by: Fabio Baltieri --- dts/arm/st/l0/stm32l011X4.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dts/arm/st/l0/stm32l011X4.dtsi b/dts/arm/st/l0/stm32l011X4.dtsi index e42fa1af64cf851..e2d7b5eafd3c526 100644 --- a/dts/arm/st/l0/stm32l011X4.dtsi +++ b/dts/arm/st/l0/stm32l011X4.dtsi @@ -18,5 +18,9 @@ reg = <0x08000000 DT_SIZE_K(16)>; }; }; + + eeprom: eeprom@8080000{ + reg = <0x08080000 512>; + }; }; }; From b4625d6f137905846af62bb44d0adc437c17da7c Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Wed, 4 Oct 2023 13:57:24 -0300 Subject: [PATCH 0077/1049] drivers: sensor: add tsl2561 basic support Add basic support for ams TSL2561 light sensor. Triggers, attributes and manual integration time are currently not supported. Signed-off-by: Gustavo Silva --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/tsl2561/CMakeLists.txt | 5 + drivers/sensor/tsl2561/Kconfig | 10 + drivers/sensor/tsl2561/tsl2561.c | 346 ++++++++++++++++++++++++ dts/bindings/sensor/ams,tsl2561.yaml | 28 ++ tests/drivers/build_all/sensor/i2c.dtsi | 5 + 7 files changed, 396 insertions(+) create mode 100644 drivers/sensor/tsl2561/CMakeLists.txt create mode 100644 drivers/sensor/tsl2561/Kconfig create mode 100644 drivers/sensor/tsl2561/tsl2561.c create mode 100644 dts/bindings/sensor/ams,tsl2561.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index a50b1c55657ef60..b0359f0254b9cc9 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -146,6 +146,7 @@ add_subdirectory_ifdef(CONFIG_TMP108 tmp108) add_subdirectory_ifdef(CONFIG_TMP112 tmp112) add_subdirectory_ifdef(CONFIG_TMP116 tmp116) add_subdirectory_ifdef(CONFIG_TSL2540 tsl2540) +add_subdirectory_ifdef(CONFIG_TSL2561 tsl2561) add_subdirectory_ifdef(CONFIG_VCMP_IT8XXX2 ite_vcmp_it8xxx2) add_subdirectory_ifdef(CONFIG_VCNL4040 vcnl4040) add_subdirectory_ifdef(CONFIG_VEML7700 veml7700) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 585bc7dc2db4fa9..31809dd07910f19 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -202,6 +202,7 @@ source "drivers/sensor/tmp108/Kconfig" source "drivers/sensor/tmp112/Kconfig" source "drivers/sensor/tmp116/Kconfig" source "drivers/sensor/tsl2540/Kconfig" +source "drivers/sensor/tsl2561/Kconfig" source "drivers/sensor/vcnl4040/Kconfig" source "drivers/sensor/veml7700/Kconfig" source "drivers/sensor/vl53l0x/Kconfig" diff --git a/drivers/sensor/tsl2561/CMakeLists.txt b/drivers/sensor/tsl2561/CMakeLists.txt new file mode 100644 index 000000000000000..7c2d251b1507dec --- /dev/null +++ b/drivers/sensor/tsl2561/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(tsl2561.c) diff --git a/drivers/sensor/tsl2561/Kconfig b/drivers/sensor/tsl2561/Kconfig new file mode 100644 index 000000000000000..e5b975bad3477d0 --- /dev/null +++ b/drivers/sensor/tsl2561/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Gustavo Silva +# SPDX-License-Identifier: Apache-2.0 + +config TSL2561 + bool "OSRAM-AMS TSL2561 light sensor" + default y + depends on DT_HAS_AMS_TSL2561_ENABLED + select I2C + help + Enable driver for TSL2561 sensor. diff --git a/drivers/sensor/tsl2561/tsl2561.c b/drivers/sensor/tsl2561/tsl2561.c new file mode 100644 index 000000000000000..42efffb224243b0 --- /dev/null +++ b/drivers/sensor/tsl2561/tsl2561.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2023, Gustavo Silva + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ams_tsl2561 + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(TSL2561, CONFIG_SENSOR_LOG_LEVEL); + +#define TSL2561_CHIP_ID 0x05 + +#define TSL2561_GAIN_1X 0x00 +#define TSL2561_GAIN_16X 0x01 + +#define TSL2561_INTEGRATION_13MS 0x00 +#define TSL2561_INTEGRATION_101MS 0x01 +#define TSL2561_INTEGRATION_402MS 0x02 + +/* Register set */ +#define TSL2561_REG_CONTROL 0x00 +#define TSL2561_REG_TIMING 0x01 +#define TSL2561_REG_THRESHLOWLOW 0x02 +#define TSL2561_REG_THRESHLOWHIGH 0x03 +#define TSL2561_REG_THRESHHIGHLOW 0x04 +#define TSL2561_REG_THRESHHIGHHIGH 0x05 +#define TSL2561_REG_INTERRUPT 0x06 +#define TSL2561_REG_ID 0x0A +#define TSL2561_REG_DATA0LOW 0x0C +#define TSL2561_REG_DATA0HIGH 0x0D +#define TSL2561_REG_DATA1LOW 0x0E +#define TSL2561_REG_DATA1HIGH 0x0F + +/* Command register fields */ +#define TSL2561_COMMAND_CMD BIT(7) +#define TSL2561_COMMAND_WORD BIT(5) + +/* Control register fields */ +#define TSL2561_CONTROL_POWER_UP 0x03 +#define TSL2561_CONTROL_POWER_DOWN 0x00 + +/* Timing register fields */ +#define TSL2561_TIMING_GAIN BIT(4) +#define TSL2561_TIMING_INTEG GENMASK(1, 0) + +/* ID register part number mask */ +#define TSL2561_ID_PARTNO GENMASK(7, 4) + +/* Lux calculation constants */ +#define TSL2561_LUX_SCALE 14U +#define TSL2561_RATIO_SCALE 9U +#define TSL2561_CH_SCALE 10U +#define TSL2561_CHSCALE_TINT0 0x7517 +#define TSL2561_CHSCALE_TINT1 0x0FE7 + +#define TSL2561_LUX_K1T 0X0040 /* 0.125 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B1T 0X01F2 /* 0.0304 * 2^LUX_SCALE */ +#define TSL2561_LUX_M1T 0X01BE /* 0.0272 * 2^LUX_SCALE */ +#define TSL2561_LUX_K2T 0X0080 /* 0.250 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B2T 0X0214 /* 0.0325 * 2^LUX_SCALE */ +#define TSL2561_LUX_M2T 0X02D1 /* 0.0440 * 2^LUX_SCALE */ +#define TSL2561_LUX_K3T 0X00C0 /* 0.375 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B3T 0X023F /* 0.0351 * 2^LUX_SCALE */ +#define TSL2561_LUX_M3T 0X037B /* 0.0544 * 2^LUX_SCALE */ +#define TSL2561_LUX_K4T 0X0100 /* 0.50 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B4T 0X0270 /* 0.0381 * 2^LUX_SCALE */ +#define TSL2561_LUX_M4T 0X03FE /* 0.0624 * 2^LUX_SCALE */ +#define TSL2561_LUX_K5T 0X0138 /* 0.61 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B5T 0X016F /* 0.0224 * 2^LUX_SCALE */ +#define TSL2561_LUX_M5T 0X01FC /* 0.0310 * 2^LUX_SCALE */ +#define TSL2561_LUX_K6T 0X019A /* 0.80 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B6T 0X00D2 /* 0.0128 * 2^LUX_SCALE */ +#define TSL2561_LUX_M6T 0X00FB /* 0.0153 * 2^LUX_SCALE */ +#define TSL2561_LUX_K7T 0X029A /* 1.3 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B7T 0X0018 /* 0.00146 * 2^LUX_SCALE */ +#define TSL2561_LUX_M7T 0X0012 /* 0.00112 * 2^LUX_SCALE */ +#define TSL2561_LUX_K8T 0X029A /* 1.3 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B8T 0X0000 /* 0.000 * 2^LUX_SCALE */ +#define TSL2561_LUX_M8T 0X0000 /* 0.000 * 2^LUX_SCALE */ + +struct tsl2561_config { + struct i2c_dt_spec i2c; + uint16_t integration_time; + uint8_t gain; +}; + +struct tsl2561_data { + uint16_t ch0; + uint16_t ch1; + uint32_t ch_scale; +}; + +static int tsl2561_reg_read(const struct device *dev, uint8_t reg, uint8_t *buf, uint8_t size) +{ + int ret; + const struct tsl2561_config *config = dev->config; + uint8_t cmd = (TSL2561_COMMAND_CMD | TSL2561_COMMAND_WORD | reg); + + ret = i2c_write_read_dt(&config->i2c, &cmd, 1U, buf, size); + if (ret < 0) { + LOG_ERR("Failed reading register 0x%02x", reg); + return ret; + } + + return 0; +} + +static int tsl2561_reg_write(const struct device *dev, uint8_t reg, uint8_t val) +{ + int ret; + const struct tsl2561_config *config = dev->config; + uint8_t buf[2]; + + buf[0] = (TSL2561_COMMAND_CMD | TSL2561_COMMAND_WORD | reg); + buf[1] = val; + + ret = i2c_write_dt(&config->i2c, buf, 2U); + if (ret < 0) { + LOG_ERR("Failed writing register 0x%02x", reg); + return ret; + } + + return 0; +} + +static int tsl2561_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct tsl2561_config *config = dev->config; + struct tsl2561_data *data = dev->data; + uint8_t bytes[2]; + uint8_t ret; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_LIGHT) { + LOG_ERR("Unsupported sensor channel"); + return -ENOTSUP; + } + + ret = tsl2561_reg_write(dev, TSL2561_REG_CONTROL, TSL2561_CONTROL_POWER_UP); + if (ret < 0) { + LOG_ERR("Failed to power up device"); + return ret; + } + + /* Short sleep after power up. Not in the datasheet, but found by trial and error */ + k_msleep(5); + + k_msleep(config->integration_time); + + /* Read data register's lower and upper bytes consecutively */ + ret = tsl2561_reg_read(dev, TSL2561_REG_DATA0LOW, bytes, 2U); + if (ret < 0) { + LOG_ERR("Failed reading channel0 data"); + return ret; + } + data->ch0 = bytes[1] << 8 | bytes[0]; + + ret = tsl2561_reg_read(dev, TSL2561_REG_DATA1LOW, bytes, 2U); + if (ret < 0) { + LOG_ERR("Failed reading channel1 data"); + return ret; + } + data->ch1 = bytes[1] << 8 | bytes[0]; + + ret = tsl2561_reg_write(dev, TSL2561_REG_CONTROL, TSL2561_CONTROL_POWER_DOWN); + if (ret < 0) { + LOG_ERR("Failed to power down device"); + return ret; + } + + LOG_DBG("channel0: 0x%x; channel1: 0x%x", data->ch0, data->ch1); + + return 0; +} + +static int tsl2561_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct tsl2561_data *data = dev->data; + uint32_t channel0; + uint32_t channel1; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_LIGHT) { + return -ENOTSUP; + } + + channel0 = (data->ch0 * data->ch_scale) >> TSL2561_CH_SCALE; + channel1 = (data->ch1 * data->ch_scale) >> TSL2561_CH_SCALE; + + uint32_t ratio1 = 0; + + if (channel0 != 0) { + ratio1 = (channel1 << (TSL2561_RATIO_SCALE + 1)) / channel0; + } + + /* Round the ratio value */ + uint32_t ratio = (ratio1 + 1) >> 1; + + uint32_t b = 0; + uint32_t m = 0; + + if (ratio <= TSL2561_LUX_K1T) { + b = TSL2561_LUX_B1T; + m = TSL2561_LUX_M1T; + } else if (ratio <= TSL2561_LUX_K2T) { + b = TSL2561_LUX_B2T; + m = TSL2561_LUX_M2T; + } else if (ratio <= TSL2561_LUX_K3T) { + b = TSL2561_LUX_B3T; + m = TSL2561_LUX_M3T; + } else if (ratio <= TSL2561_LUX_K4T) { + b = TSL2561_LUX_B4T; + m = TSL2561_LUX_M4T; + } else if (ratio <= TSL2561_LUX_K5T) { + b = TSL2561_LUX_B5T; + m = TSL2561_LUX_M5T; + } else if (ratio <= TSL2561_LUX_K6T) { + b = TSL2561_LUX_B6T; + m = TSL2561_LUX_M6T; + } else if (ratio <= TSL2561_LUX_K7T) { + b = TSL2561_LUX_B7T; + m = TSL2561_LUX_M7T; + } else if (ratio > TSL2561_LUX_K8T) { + b = TSL2561_LUX_B8T; + m = TSL2561_LUX_M8T; + } + + int32_t tmp = ((channel0 * b) - (channel1 * m)); + + /* Round LSB (2^(LUX_SCALE−1)) */ + tmp += (1 << (TSL2561_LUX_SCALE - 1)); + + /* Strip off fractional portion */ + val->val1 = tmp >> TSL2561_LUX_SCALE; + + val->val2 = 0; + + return 0; +} + +static const struct sensor_driver_api tsl2561_driver_api = { + .sample_fetch = tsl2561_sample_fetch, + .channel_get = tsl2561_channel_get +}; + +static int tsl2561_sensor_setup(const struct device *dev) +{ + const struct tsl2561_config *config = dev->config; + struct tsl2561_data *data = dev->data; + uint8_t timing_reg; + uint8_t chip_id; + uint8_t tmp; + int ret; + + ret = tsl2561_reg_read(dev, TSL2561_REG_ID, &chip_id, 1U); + if (ret < 0) { + LOG_ERR("Failed reading chip ID"); + return ret; + } + + if (FIELD_GET(TSL2561_ID_PARTNO, chip_id) != TSL2561_CHIP_ID) { + LOG_ERR("Chip ID is invalid! Device @%02x is not TSL2561!", config->i2c.addr); + return -EIO; + } + + switch (config->integration_time) { + case 13: + tmp = TSL2561_INTEGRATION_13MS; + data->ch_scale = TSL2561_CHSCALE_TINT0; + break; + case 101: + tmp = TSL2561_INTEGRATION_101MS; + data->ch_scale = TSL2561_CHSCALE_TINT1; + break; + case 402: + tmp = TSL2561_INTEGRATION_402MS; + data->ch_scale = (1 << TSL2561_CH_SCALE); + break; + default: + LOG_ERR("Invalid integration time"); + return -EINVAL; + } + + timing_reg = TSL2561_TIMING_INTEG & tmp; + + switch (config->gain) { + case 1: + tmp = TSL2561_GAIN_1X; + data->ch_scale = data->ch_scale << 4; + break; + case 16: + tmp = TSL2561_GAIN_16X; + break; + default: + LOG_ERR("Invalid ADC gain"); + return -EINVAL; + } + + timing_reg |= FIELD_PREP(TSL2561_TIMING_GAIN, tmp); + + ret = tsl2561_reg_write(dev, TSL2561_REG_TIMING, timing_reg); + if (ret < 0) { + LOG_ERR("Failed setting timing register"); + return ret; + } + + return 0; +} + +static int tsl2561_init(const struct device *dev) +{ + const struct tsl2561_config *config = dev->config; + int ret; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C dev %s not ready", config->i2c.bus->name); + return -ENODEV; + } + + ret = tsl2561_sensor_setup(dev); + if (ret < 0) { + LOG_ERR("Failed to configure device"); + return ret; + } + + return 0; +} + +#define TSL2561_INIT_INST(n) \ + static struct tsl2561_data tsl2561_data_##n; \ + static const struct tsl2561_config tsl2561_config_##n = { \ + .i2c = I2C_DT_SPEC_INST_GET(n), \ + .integration_time = DT_INST_PROP(n, integration_time), \ + .gain = DT_INST_PROP(n, gain)}; \ + SENSOR_DEVICE_DT_INST_DEFINE(n, tsl2561_init, NULL, &tsl2561_data_##n, \ + &tsl2561_config_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &tsl2561_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(TSL2561_INIT_INST) diff --git a/dts/bindings/sensor/ams,tsl2561.yaml b/dts/bindings/sensor/ams,tsl2561.yaml new file mode 100644 index 000000000000000..fbc97a673e8d049 --- /dev/null +++ b/dts/bindings/sensor/ams,tsl2561.yaml @@ -0,0 +1,28 @@ +# Copyright (c) 2023, Gustavo Silva +# SPDX-License-Identifier: Apache-2.0 + +description: | + OSRAM ams TSL2561 light sensor. + +compatible: "ams,tsl2561" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + integration-time: + type: int + default: 402 + description: | + ADC integration time in ms. The default value matches Timing Register's value at power on. + enum: + - 13 + - 101 + - 402 + gain: + type: int + default: 16 + description: | + ADC gain factor. The default value matches Timing Register's value at power on. + enum: + - 1 + - 16 diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index c7c167aca14ebab..4e54911f969a0c1 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -794,3 +794,8 @@ test_i2c_adxl367: adxl367@77 { reg = <0x77>; odr = <4>; }; + +test_i2c_tsl2561: tsl2561@78 { + compatible = "ams,tsl2561"; + reg = <0x78>; +}; From 546a64065773841af565771fe968f5c72ab3a2f3 Mon Sep 17 00:00:00 2001 From: Ioannis Karachalios Date: Mon, 9 Oct 2023 10:58:56 +0300 Subject: [PATCH 0078/1049] drivers: dma: smartbond: Support DMA accelerator. Add support for the DMA engine. Signed-off-by: Ioannis Karachalios --- drivers/dma/CMakeLists.txt | 1 + drivers/dma/Kconfig | 1 + drivers/dma/Kconfig.smartbond | 11 + drivers/dma/dma_smartbond.c | 969 ++++++++++++++++++++ dts/bindings/dma/renesas,smartbond-dma.yaml | 21 + include/zephyr/drivers/dma/dma_smartbond.h | 33 + 6 files changed, 1036 insertions(+) create mode 100644 drivers/dma/Kconfig.smartbond create mode 100644 drivers/dma/dma_smartbond.c create mode 100644 dts/bindings/dma/renesas,smartbond-dma.yaml create mode 100644 include/zephyr/drivers/dma/dma_smartbond.h diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index da2d43fc2c02838..271ddf19ff08962 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -36,3 +36,4 @@ zephyr_library_sources_ifdef(CONFIG_MCUX_PXP dma_mcux_pxp.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_SMARTDMA dma_mcux_smartdma.c) zephyr_library_sources_ifdef(CONFIG_DMA_ANDES_ATCDMAC300 dma_andes_atcdmac300.c) zephyr_library_sources_ifdef(CONFIG_DMA_SEDI dma_sedi.c) +zephyr_library_sources_ifdef(CONFIG_DMA_SMARTBOND dma_smartbond.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 0136eaa92a21560..5a2ce5bdceda1a7 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -68,4 +68,5 @@ source "drivers/dma/Kconfig.andes_atcdmac300" source "drivers/dma/Kconfig.sedi" +source "drivers/dma/Kconfig.smartbond" endif # DMA diff --git a/drivers/dma/Kconfig.smartbond b/drivers/dma/Kconfig.smartbond new file mode 100644 index 000000000000000..3234e13020feccb --- /dev/null +++ b/drivers/dma/Kconfig.smartbond @@ -0,0 +1,11 @@ +# Smartbond DMA Accelerator Configuration Options + +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config DMA_SMARTBOND + bool "Smartbond DMA Accelerator Driver" + depends on DT_HAS_RENESAS_SMARTBOND_DMA_ENABLED + default y + help + Enable Smartbond DMA Accelerator Driver diff --git a/drivers/dma/dma_smartbond.c b/drivers/dma/dma_smartbond.c new file mode 100644 index 000000000000000..79305c77d6a0674 --- /dev/null +++ b/drivers/dma/dma_smartbond.c @@ -0,0 +1,969 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(dma_smartbond, CONFIG_DMA_LOG_LEVEL); + +#define DT_DRV_COMPAT renesas_smartbond_dma + +#define SMARTBOND_IRQN DT_INST_IRQN(0) +#define SMARTBOND_IRQ_PRIO DT_INST_IRQ(0, priority) + +#define DMA_CHANNELS_COUNT DT_PROP(DT_NODELABEL(dma), dma_channels) +#define DMA_BLOCK_COUNT DT_PROP(DT_NODELABEL(dma), block_count) +#define DMA_SECURE_CHANNEL 7 + +#define DMA_CTRL_REG_SET_FIELD(_field, _var, _val) \ + (_var) = \ + (((_var) & ~DMA_DMA0_CTRL_REG_ ## _field ## _Msk) | \ + (((_val) << DMA_DMA0_CTRL_REG_ ## _field ## _Pos) & DMA_DMA0_CTRL_REG_ ## _field ## _Msk)) + +#define DMA_CTRL_REG_GET_FIELD(_field, _var) \ + (((_var) & DMA_DMA0_CTRL_REG_ ## _field ## _Msk) >> DMA_DMA0_CTRL_REG_ ## _field ## _Pos) + +#define DMA_CHN2REG(_idx) (&((struct channel_regs *)DMA)[(_idx)]) + +#define DMA_MUX_SHIFT(_idx) (((_idx) >> 1) * 4) + +#define DMA_REQ_MUX_REG_SET(_idx, _val) \ + DMA->DMA_REQ_MUX_REG = \ + (DMA->DMA_REQ_MUX_REG & ~(0xf << DMA_MUX_SHIFT((_idx)))) | \ + (((_val) & 0xf) << DMA_MUX_SHIFT((_idx))) + +#define DMA_REQ_MUX_REG_GET(_idx) \ + ((DMA->DMA_REQ_MUX_REG >> DMA_MUX_SHIFT((_idx))) & 0xf) + +#define CRYPTO_KEYS_BUF_ADDR 0x30040100 +#define CRYPTO_KEYS_BUF_SIZE 0x100 +#define IS_AES_KEYS_BUF_RANGE(_a) ((uint32_t)(_a) >= (uint32_t)(CRYPTO_KEYS_BUF_ADDR)) && \ + ((uint32_t)(_a) < (uint32_t)(CRYPTO_KEYS_BUF_ADDR + CRYPTO_KEYS_BUF_SIZE)) + +/* + * DMA channel priority level. The smaller the value the lower the priority granted to a channel + * when two or more channels request the bus at the same time. For channels of same priority an + * inherent mechanism is applied in which the lower the channel number the higher the priority. + */ +enum dma_smartbond_channel_prio { + DMA_SMARTBOND_CHANNEL_PRIO_0 = 0x0, /* Lowest channel priority */ + DMA_SMARTBOND_CHANNEL_PRIO_1, + DMA_SMARTBOND_CHANNEL_PRIO_2, + DMA_SMARTBOND_CHANNEL_PRIO_3, + DMA_SMARTBOND_CHANNEL_PRIO_4, + DMA_SMARTBOND_CHANNEL_PRIO_5, + DMA_SMARTBOND_CHANNEL_PRIO_6, + DMA_SMARTBOND_CHANNEL_PRIO_7, /* Highest channel priority */ + DMA_SMARTBOND_CHANNEL_PRIO_MAX +}; + +enum dma_smartbond_channel { + DMA_SMARTBOND_CHANNEL_0 = 0x0, + DMA_SMARTBOND_CHANNEL_1, + DMA_SMARTBOND_CHANNEL_2, + DMA_SMARTBOND_CHANNEL_3, + DMA_SMARTBOND_CHANNEL_4, + DMA_SMARTBOND_CHANNEL_5, + DMA_SMARTBOND_CHANNEL_6, + DMA_SMARTBOND_CHANNEL_7, + DMA_SMARTBOND_CHANNEL_MAX +}; + +enum dma_smartbond_burst_len { + DMA_SMARTBOND_BURST_LEN_1B = 0x1, /* Burst mode is disabled */ + DMA_SMARTBOND_BURST_LEN_4B = 0x4, /* Perform bursts of 4 beats (INCR4) */ + DMA_SMARTBOND_BURST_LEN_8B = 0x8 /* Perform bursts of 8 beats (INCR8) */ +}; + +/* + * DMA bus width indicating how many bytes are retrived/written per transfer. + * Note that the bus width is the same for the source and destination. + */ +enum dma_smartbond_bus_width { + DMA_SMARTBOND_BUS_WIDTH_1B = 0x1, + DMA_SMARTBOND_BUS_WIDTH_2B = 0x2, + DMA_SMARTBOND_BUS_WIDTH_4B = 0x4 +}; + +enum dreq_mode { + DREQ_MODE_SW = 0x0, + DREQ_MODE_HW +}; + +enum burst_mode { + BURST_MODE_0B = 0x0, + BURST_MODE_4B = 0x1, + BURST_MODE_8B = 0x2 +}; + +enum bus_width { + BUS_WIDTH_1B = 0x0, + BUS_WIDTH_2B = 0x1, + BUS_WIDTH_4B = 0x2 +}; + +enum addr_adj { + ADDR_ADJ_NO_CHANGE = 0x0, + ADDR_ADJ_INCR +}; + +enum copy_mode { + COPY_MODE_BLOCK = 0x0, + COPY_MODE_INIT +}; + +enum req_sense { + REQ_SENSE_LEVEL = 0x0, + REQ_SENSE_EDGE +}; + +struct channel_regs { + __IO uint32_t DMA_A_START; + __IO uint32_t DMA_B_START; + __IO uint32_t DMA_INT_REG; + __IO uint32_t DMA_LEN_REG; + __IO uint32_t DMA_CTRL_REG; + + __I uint32_t DMA_IDX_REG; + __I uint32_t RESERVED[2]; +}; + +struct dma_channel_data { + dma_callback_t cb; + void *user_data; + enum dma_smartbond_bus_width bus_width; + enum dma_smartbond_burst_len burst_len; + enum dma_channel_direction dir; + bool is_dma_configured; +}; + +struct dma_smartbond_data { + /* Should be the first member of the driver data */ + struct dma_context dma_ctx; + + ATOMIC_DEFINE(channels_atomic, DMA_CHANNELS_COUNT); + + /* User callbacks and data to be stored per channel */ + struct dma_channel_data channel_data[DMA_CHANNELS_COUNT]; +}; + +/* True if there is any DMA activity on any channel, false otheriwise. */ +static bool dma_smartbond_is_dma_active(void) +{ + int idx; + struct channel_regs *regs; + + for (idx = 0; idx < DMA_CHANNELS_COUNT; idx++) { + regs = DMA_CHN2REG(idx); + + if (DMA_CTRL_REG_GET_FIELD(DMA_ON, regs->DMA_CTRL_REG)) { + return true; + } + } + + return false; +} + +static void dma_smartbond_set_channel_status(uint32_t channel, bool status) +{ + unsigned int key; + struct channel_regs *regs = DMA_CHN2REG(channel); + + key = irq_lock(); + + if (status) { + /* Make sure the status register for the requested channel is cleared. */ + DMA->DMA_CLEAR_INT_REG |= BIT(channel); + /* Enable interrupts for the requested channel. */ + DMA->DMA_INT_MASK_REG |= BIT(channel); + + /* Check if this is the first attempt to enable DMA interrupts. */ + if (!irq_is_enabled(SMARTBOND_IRQN)) { + irq_enable(SMARTBOND_IRQN); + } + + DMA_CTRL_REG_SET_FIELD(DMA_ON, regs->DMA_CTRL_REG, 0x1); + } else { + DMA_CTRL_REG_SET_FIELD(DMA_ON, regs->DMA_CTRL_REG, 0x0); + + /* + * It might happen that DMA is already in progress. Make sure the current + * on-going transfer is complete (cannot be interrupted). + */ + while (DMA_CTRL_REG_GET_FIELD(DMA_ON, regs->DMA_CTRL_REG)) { + } + + /* Disable interrupts for the requested channel */ + DMA->DMA_INT_MASK_REG &= ~(BIT(channel)); + /* Clear the status register; the requested channel should be considered obsolete */ + DMA->DMA_CLEAR_INT_REG |= BIT(channel); + + /* DMA interrupts should be disabled only if all channels are disabled. */ + if (!dma_smartbond_is_dma_active()) { + irq_disable(SMARTBOND_IRQN); + } + } + + irq_unlock(key); +} + +static bool dma_channel_dst_addr_check_and_adjust(uint32_t channel, uint32_t *dst) +{ + uint32_t phy_address; + uint32_t secure_boot_reg; + bool is_aes_keys_protected, is_qspic_keys_protected; + + phy_address = black_orca_phy_addr(*dst); + + secure_boot_reg = CRG_TOP->SECURE_BOOT_REG; + is_aes_keys_protected = + (secure_boot_reg & CRG_TOP_SECURE_BOOT_REG_PROT_AES_KEY_READ_Msk); + is_qspic_keys_protected = + (secure_boot_reg & CRG_TOP_SECURE_BOOT_REG_PROT_QSPI_KEY_READ_Msk); + + /* + * If the destination address reflects the AES key buffer area and secure keys are protected + * then only the secure channel #7 can be used to transfer data to AES key buffer. + */ + if ((IS_AES_KEYS_BUF_RANGE(phy_address) && + (is_aes_keys_protected || is_qspic_keys_protected) && + (channel != DMA_SECURE_CHANNEL))) { + LOG_ERR("Keys are protected. Only secure channel #7 can be employed."); + return false; + } + + if (IS_QSPIF_ADDRESS(phy_address) || IS_QSPIF_CACHED_ADDRESS(phy_address) || + IS_OTP_ADDRESS(phy_address) || IS_OTP_P_ADDRESS(phy_address)) { + LOG_ERR("Invalid destination location."); + return false; + } + + *dst = phy_address; + + return true; +} + +static bool dma_channel_src_addr_check_and_adjust(uint32_t channel, uint32_t *src) +{ + uint32_t phy_address; + uint32_t secure_boot_reg; + bool is_aes_keys_protected, is_qspic_keys_protected; + + /* DMA can only access physical addresses, not remapped. */ + phy_address = black_orca_phy_addr(*src); + + if (IS_QSPIF_CACHED_ADDRESS(phy_address)) { + /* + * To achiebe max. perfomance, peripherals should not access the Flash memory + * through the instruction cache controller (avoid cache misses). + */ + phy_address += (MCU_QSPIF_M_BASE - MCU_QSPIF_M_CACHED_BASE); + } else if (IS_OTP_ADDRESS(phy_address)) { + /* Peripherals should access OTP through its peripheral address space. */ + phy_address += (MCU_OTP_M_P_BASE - MCU_OTP_M_BASE); + } + + secure_boot_reg = CRG_TOP->SECURE_BOOT_REG; + is_aes_keys_protected = + (secure_boot_reg & CRG_TOP_SECURE_BOOT_REG_PROT_AES_KEY_READ_Msk); + is_qspic_keys_protected = + (secure_boot_reg & CRG_TOP_SECURE_BOOT_REG_PROT_QSPI_KEY_READ_Msk); + + /* + * If the source address reflects protected area in OTP then only the + * secure channel #7 can be used to fetch secure keys data. + */ + if (((IS_ADDRESS_USER_DATA_KEYS_SEGMENT(phy_address) && is_aes_keys_protected) || + (IS_ADDRESS_QSPI_FW_KEYS_SEGMENT(phy_address) && is_qspic_keys_protected)) && + (channel != DMA_SECURE_CHANNEL)) { + LOG_ERR("Keys are protected. Only secure channel #7 can be employed."); + return false; + } + + *src = phy_address; + + return true; +} + +static bool dma_channel_update_dreq_mode(enum dma_channel_direction direction, + uint32_t *dma_ctrl_reg) +{ + switch (direction) { + case MEMORY_TO_HOST: + case HOST_TO_MEMORY: + case MEMORY_TO_MEMORY: + /* DMA channel starts immediately */ + DMA_CTRL_REG_SET_FIELD(DREQ_MODE, *dma_ctrl_reg, DREQ_MODE_SW); + break; + case PERIPHERAL_TO_MEMORY: + case PERIPHERAL_TO_PERIPHERAL: + /* DMA channels starts by peripheral DMA req */ + DMA_CTRL_REG_SET_FIELD(DREQ_MODE, *dma_ctrl_reg, DREQ_MODE_HW); + break; + default: + return false; + }; + + return true; +} + +static bool dma_channel_update_src_addr_adj(enum dma_addr_adj addr_adj, uint32_t *dma_ctrl_reg) +{ + switch (addr_adj) { + case DMA_ADDR_ADJ_NO_CHANGE: + DMA_CTRL_REG_SET_FIELD(AINC, *dma_ctrl_reg, ADDR_ADJ_NO_CHANGE); + break; + case DMA_ADDR_ADJ_INCREMENT: + DMA_CTRL_REG_SET_FIELD(AINC, *dma_ctrl_reg, ADDR_ADJ_INCR); + break; + default: + return false; + } + + return true; +} + +static bool dma_channel_update_dst_addr_adj(enum dma_addr_adj addr_adj, uint32_t *dma_ctrl_reg) +{ + switch (addr_adj) { + case DMA_ADDR_ADJ_NO_CHANGE: + DMA_CTRL_REG_SET_FIELD(BINC, *dma_ctrl_reg, ADDR_ADJ_NO_CHANGE); + break; + case DMA_ADDR_ADJ_INCREMENT: + DMA_CTRL_REG_SET_FIELD(BINC, *dma_ctrl_reg, ADDR_ADJ_INCR); + break; + default: + return false; + } + + return true; +} + +static bool dma_channel_update_bus_width(uint16_t bw, uint32_t *dma_ctrl_reg) +{ + switch (bw) { + case DMA_SMARTBOND_BUS_WIDTH_1B: + DMA_CTRL_REG_SET_FIELD(BW, *dma_ctrl_reg, BUS_WIDTH_1B); + break; + case DMA_SMARTBOND_BUS_WIDTH_2B: + DMA_CTRL_REG_SET_FIELD(BW, *dma_ctrl_reg, BUS_WIDTH_2B); + break; + case DMA_SMARTBOND_BUS_WIDTH_4B: + DMA_CTRL_REG_SET_FIELD(BW, *dma_ctrl_reg, BUS_WIDTH_4B); + break; + default: + return false; + } + + return true; +} + +static bool dma_channel_update_burst_mode(uint16_t burst, uint32_t *dma_ctrl_reg) +{ + switch (burst) { + case DMA_SMARTBOND_BURST_LEN_1B: + DMA_CTRL_REG_SET_FIELD(BURST_MODE, *dma_ctrl_reg, BURST_MODE_0B); + break; + case DMA_SMARTBOND_BURST_LEN_4B: + DMA_CTRL_REG_SET_FIELD(BURST_MODE, *dma_ctrl_reg, BURST_MODE_4B); + break; + case DMA_SMARTBOND_BURST_LEN_8B: + DMA_CTRL_REG_SET_FIELD(BURST_MODE, *dma_ctrl_reg, BURST_MODE_8B); + break; + default: + return false; + } + + return true; +} + +static void dma_channel_update_req_sense(enum dma_smartbond_trig_mux trig_mux, + uint32_t channel, uint32_t *dma_ctrl_reg) +{ + switch (trig_mux) { + case DMA_SMARTBOND_TRIG_MUX_UART: + case DMA_SMARTBOND_TRIG_MUX_UART2: + case DMA_SMARTBOND_TRIG_MUX_UART3: + case DMA_SMARTBOND_TRIG_MUX_I2C: + case DMA_SMARTBOND_TRIG_MUX_I2C2: + case DMA_SMARTBOND_TRIG_MUX_USB: + /* Odd channel numbers should reflect TX path */ + if (channel & BIT(0)) { + DMA_CTRL_REG_SET_FIELD(REQ_SENSE, *dma_ctrl_reg, REQ_SENSE_EDGE); + break; + } + default: + DMA_CTRL_REG_SET_FIELD(REQ_SENSE, *dma_ctrl_reg, REQ_SENSE_LEVEL); + } +} + +static void dma_set_mux_request(enum dma_smartbond_trig_mux trig_mux, uint32_t channel) +{ + unsigned int key; + + key = irq_lock(); + DMA_REQ_MUX_REG_SET(channel, trig_mux); + + /* + * Having same trigger for different channels can cause unpredictable results. + * The audio triggers (src and pcm) are an exception, as they use 2 pairs each + * for DMA access. + * The lesser significant selector has higher priority and will control + * the DMA acknowledge signal driven to the selected peripheral. Make sure + * the current selector does not match with selectors of + * higher priorities (dma channels of lower indexing). It's OK if a + * channel of higher indexing defines the same peripheral request source + * (should be ignored as it has lower priority). + */ + if (trig_mux != DMA_SMARTBOND_TRIG_MUX_NONE) { + switch (channel) { + case DMA_SMARTBOND_CHANNEL_7: + case DMA_SMARTBOND_CHANNEL_6: + if (DMA_REQ_MUX_REG_GET(DMA_SMARTBOND_CHANNEL_5) == trig_mux) { + DMA_REQ_MUX_REG_SET(DMA_SMARTBOND_CHANNEL_5, + DMA_SMARTBOND_TRIG_MUX_NONE); + } + /* fall-through */ + case DMA_SMARTBOND_CHANNEL_5: + case DMA_SMARTBOND_CHANNEL_4: + if (DMA_REQ_MUX_REG_GET(DMA_SMARTBOND_CHANNEL_3) == trig_mux) { + DMA_REQ_MUX_REG_SET(DMA_SMARTBOND_CHANNEL_3, + DMA_SMARTBOND_TRIG_MUX_NONE); + } + /* fall-through */ + case DMA_SMARTBOND_CHANNEL_3: + case DMA_SMARTBOND_CHANNEL_2: + if (DMA_REQ_MUX_REG_GET(DMA_SMARTBOND_CHANNEL_1) == trig_mux) { + DMA_REQ_MUX_REG_SET(DMA_SMARTBOND_CHANNEL_1, + DMA_SMARTBOND_TRIG_MUX_NONE); + } + case DMA_SMARTBOND_CHANNEL_1: + case DMA_SMARTBOND_CHANNEL_0: + break; + } + } + + irq_unlock(key); +} + +static int dma_smartbond_config(const struct device *dev, uint32_t channel, struct dma_config *cfg) +{ + struct dma_smartbond_data *data = dev->data; + struct channel_regs *regs; + uint32_t dma_ctrl_reg; + uint32_t src_dst_address; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + regs = DMA_CHN2REG(channel); + + dma_ctrl_reg = regs->DMA_CTRL_REG; + + if (DMA_CTRL_REG_GET_FIELD(DMA_ON, dma_ctrl_reg)) { + LOG_ERR("Requested channel is enabled. It should first be disabled"); + return -EIO; + } + + if (cfg == NULL || cfg->head_block == NULL) { + LOG_ERR("Missing configuration structure"); + return -EINVAL; + } + + /* Error handling is not supported; just warn user. */ + if (cfg->error_callback_en) { + LOG_WRN("Error handling is not supported"); + } + + if (!cfg->complete_callback_en) { + data->channel_data[channel].cb = cfg->dma_callback; + data->channel_data[channel].user_data = cfg->user_data; + } else { + LOG_WRN("User callback can only be called at completion only and not per block."); + + /* Nulify pointers to indicate notifications are disabled. */ + data->channel_data[channel].cb = NULL; + data->channel_data[channel].user_data = NULL; + } + + data->channel_data[channel].dir = cfg->channel_direction; + + if (cfg->block_count > DMA_BLOCK_COUNT) { + LOG_WRN("A single block is supported. The rest blocks will be discarded"); + } + + if (cfg->channel_priority >= DMA_SMARTBOND_CHANNEL_PRIO_MAX) { + cfg->channel_priority = DMA_SMARTBOND_CHANNEL_PRIO_7; + LOG_WRN("Channel priority exceeded max. Setting to highest valid level"); + } + + DMA_CTRL_REG_SET_FIELD(DMA_PRIO, dma_ctrl_reg, cfg->channel_priority); + + if (((cfg->source_burst_length != cfg->dest_burst_length) || + !dma_channel_update_burst_mode(cfg->source_burst_length, &dma_ctrl_reg))) { + LOG_ERR("Invalid burst mode or source and destination mode mismatch"); + return -EINVAL; + } + + data->channel_data[channel].burst_len = cfg->source_burst_length; + + if (cfg->source_data_size != cfg->dest_data_size || + !dma_channel_update_bus_width(cfg->source_data_size, &dma_ctrl_reg)) { + LOG_ERR("Invalid bus width or source and destination bus width mismatch"); + return -EINVAL; + } + + data->channel_data[channel].bus_width = cfg->source_data_size; + + if (cfg->source_chaining_en || cfg->dest_chaining_en || + cfg->head_block->source_gather_en || cfg->head_block->dest_scatter_en || + cfg->head_block->source_reload_en || cfg->head_block->dest_reload_en) { + LOG_WRN("Chainning, scattering, gathering or reloading is not supported"); + } + + if (!dma_channel_update_src_addr_adj(cfg->head_block->source_addr_adj, + &dma_ctrl_reg)) { + LOG_ERR("Invalid source address adjustment"); + return -EINVAL; + } + + if (!dma_channel_update_dst_addr_adj(cfg->head_block->dest_addr_adj, &dma_ctrl_reg)) { + LOG_ERR("Invalid destination address adjustment"); + return -EINVAL; + } + + if (!dma_channel_update_dreq_mode(cfg->channel_direction, &dma_ctrl_reg)) { + LOG_ERR("Inavlid channel direction"); + return -EINVAL; + } + + /* Cyclic is valid only when DREQ_MODE is set */ + if (cfg->cyclic && DMA_CTRL_REG_GET_FIELD(DREQ_MODE, dma_ctrl_reg) != DREQ_MODE_HW) { + LOG_ERR("Circular mode is only supported for non memory-memory transfers"); + return -EINVAL; + } + + DMA_CTRL_REG_SET_FIELD(CIRCULAR, dma_ctrl_reg, cfg->cyclic); + + if (DMA_CTRL_REG_GET_FIELD(DREQ_MODE, dma_ctrl_reg) == DREQ_MODE_SW && + DMA_CTRL_REG_GET_FIELD(AINC, dma_ctrl_reg) == ADDR_ADJ_NO_CHANGE && + DMA_CTRL_REG_GET_FIELD(BINC, dma_ctrl_reg) == ADDR_ADJ_INCR) { + /* + * Valid for memory initialization to a specific value. This process + * cannot be interrupted by other DMA channels. + */ + DMA_CTRL_REG_SET_FIELD(DMA_INIT, dma_ctrl_reg, COPY_MODE_INIT); + } else { + DMA_CTRL_REG_SET_FIELD(DMA_INIT, dma_ctrl_reg, COPY_MODE_BLOCK); + } + + dma_channel_update_req_sense(cfg->dma_slot, channel, &dma_ctrl_reg); + + regs->DMA_CTRL_REG = dma_ctrl_reg; + + /* Requested address might be changed */ + src_dst_address = cfg->head_block->source_address; + if (!dma_channel_src_addr_check_and_adjust(channel, &src_dst_address)) { + return -EINVAL; + } + + if (src_dst_address % cfg->source_data_size) { + LOG_ERR("Source address is not bus width aligned"); + return -EINVAL; + } + + regs->DMA_A_START = src_dst_address; + + src_dst_address = cfg->head_block->dest_address; + if (!dma_channel_dst_addr_check_and_adjust(channel, &src_dst_address)) { + return -EINVAL; + } + + if (src_dst_address % cfg->dest_data_size) { + LOG_ERR("Destination address is not bus width aligned"); + return -EINVAL; + } + + regs->DMA_B_START = src_dst_address; + + if (cfg->head_block->block_size % (cfg->source_data_size * cfg->source_burst_length)) { + LOG_ERR("Requested data size is not multiple of bus width"); + return -EINVAL; + } + + regs->DMA_LEN_REG = (cfg->head_block->block_size / cfg->source_data_size) - 1; + + /* Interrupt will be raised once all transfers are complete. */ + regs->DMA_INT_REG = (cfg->head_block->block_size / cfg->source_data_size) - 1; + + if ((cfg->source_handshake != cfg->dest_handshake) || + (cfg->source_handshake != 0)/*HW*/) { + LOG_ERR("Source/destination handshakes mismatch or invalid"); + return -EINVAL; + } + + dma_set_mux_request(cfg->dma_slot, channel); + + /* Designate that channel has been configured */ + data->channel_data[channel].is_dma_configured = true; + + return 0; +} + + +static int dma_smartbond_reload(const struct device *dev, uint32_t channel, uint32_t src, + uint32_t dst, size_t size) +{ + struct dma_smartbond_data *data = dev->data; + struct channel_regs *regs; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + regs = DMA_CHN2REG(channel); + + if (!data->channel_data[channel].is_dma_configured) { + LOG_ERR("Requested DMA channel should first be configured"); + return -EINVAL; + } + + if (size == 0) { + LOG_ERR("Min. transfer size is one"); + return -EINVAL; + } + + if (DMA_CTRL_REG_GET_FIELD(DMA_ON, regs->DMA_CTRL_REG)) { + LOG_ERR("Channel is busy, settings cannot be changed mid-transfer"); + return -EBUSY; + } + + if (src % data->channel_data[channel].bus_width) { + LOG_ERR("Source address is not bus width aligned"); + return -EINVAL; + } + + if (!dma_channel_src_addr_check_and_adjust(channel, &src)) { + return -EINVAL; + } + + regs->DMA_A_START = src; + + if (dst % data->channel_data[channel].bus_width) { + LOG_ERR("Destination address is not bus width aligned"); + return -EINVAL; + } + + if (!dma_channel_dst_addr_check_and_adjust(channel, &dst)) { + return -EINVAL; + } + + regs->DMA_B_START = dst; + + if (size % (data->channel_data[channel].burst_len * + data->channel_data[channel].bus_width)) { + LOG_ERR("Requested data size is not multiple of bus width"); + return -EINVAL; + } + + regs->DMA_LEN_REG = (size / data->channel_data[channel].bus_width) - 1; + + /* Interrupt will be raised once all transfers are complete. */ + regs->DMA_INT_REG = (size / data->channel_data[channel].bus_width) - 1; + + return 0; +} + +static int dma_smartbond_start(const struct device *dev, uint32_t channel) +{ + struct channel_regs *regs; + struct dma_smartbond_data *data = dev->data; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + regs = DMA_CHN2REG(channel); + + if (!data->channel_data[channel].is_dma_configured) { + LOG_ERR("Requested DMA channel should first be configured"); + return -EINVAL; + } + + /* Should return succss if the requested channel is already started. */ + if (DMA_CTRL_REG_GET_FIELD(DMA_ON, regs->DMA_CTRL_REG)) { + return 0; + } + + dma_smartbond_set_channel_status(channel, true); + + return 0; +} + +static int dma_smartbond_stop(const struct device *dev, uint32_t channel) +{ + struct channel_regs *regs; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + regs = DMA_CHN2REG(channel); + + /* + * In normal mode DMA_ON is cleared automatically. However we need to clear + * the corresponding register mask and disable NVIC if there is no other + * channel in use. + */ + dma_smartbond_set_channel_status(channel, false); + + return 0; +} + +static int dma_smartbond_suspend(const struct device *dev, uint32_t channel) +{ + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + + /* + * Freezing the DMA engine is valid for memory-to-memory operations. + * Valid memory locations are SYSRAM and/or PSRAM. + */ + LOG_WRN("DMA is freezed globally"); + + /* + * Freezing the DMA engine can be done universally and not per channel!. + * An attempt to disable the channel would result in resetting the IDX + * register next time the channel was re-enabled. + */ + GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_DMA_Msk; + + return 0; +} + +static int dma_smartbond_resume(const struct device *dev, uint32_t channel) +{ + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + + LOG_WRN("DMA is unfreezed globally"); + + /* Unfreezing the DMA engine can be done unviversally and not per channel! */ + GPREG->RESET_FREEZE_REG = GPREG_RESET_FREEZE_REG_FRZ_DMA_Msk; + + return 0; +} + +static int dma_smartbond_get_status(const struct device *dev, uint32_t channel, + struct dma_status *stat) +{ + struct channel_regs *regs; + int key; + struct dma_smartbond_data *data = dev->data; + uint8_t bus_width; + uint32_t dma_ctrl_reg, dma_idx_reg, dma_len_reg; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + + if (stat == NULL) { + LOG_ERR("User should provide a valid pointer to store the status info requested"); + } + + if (!data->channel_data[channel].is_dma_configured) { + LOG_ERR("Requested DMA channel should first be configured"); + return -EINVAL; + } + + regs = DMA_CHN2REG(channel); + + /* + * The DMA is running in parallel with CPU and so it might happen that an on-going transfer + * might be completed the moment user parses the status results. Disable interrupts globally + * so there is no chance for a new transfer to be initiated from within ISR and so changing + * the channel registers values. + */ + key = irq_lock(); + + dma_ctrl_reg = regs->DMA_CTRL_REG; + dma_idx_reg = regs->DMA_IDX_REG; + dma_len_reg = regs->DMA_LEN_REG; + + /* Calculate how many byes each transfer consists of. */ + bus_width = DMA_CTRL_REG_GET_FIELD(BW, dma_ctrl_reg); + if (bus_width == BUS_WIDTH_1B) { + bus_width = 1; + } else { + bus_width <<= 1; + } + + /* Convert transfers to bytes. */ + stat->total_copied = dma_idx_reg * bus_width; + stat->pending_length = ((dma_len_reg + 1) - dma_idx_reg) * bus_width; + stat->busy = DMA_CTRL_REG_GET_FIELD(DMA_ON, dma_ctrl_reg); + stat->dir = data->channel_data[channel].dir; + + /* DMA does not support circular buffer functionality */ + stat->free = 0; + stat->read_position = 0; + stat->write_position = 0; + + irq_unlock(key); + + return 0; +} + +static int dma_smartbond_get_attribute(const struct device *dev, uint32_t type, uint32_t *value) +{ + if (value == NULL) { + LOG_ERR("User should provide a valid pointer to attribute value"); + return -EINVAL; + } + + switch (type) { + /* + * Source and destination addresses should be multiple of a channel's bus width. + * This info could be provided at runtime given that attributes of a specific + * channel could be requested. + */ + case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: + case DMA_ATTR_COPY_ALIGNMENT: + /* + * Buffer size should be multiple of a channel's bus width multiplied by burst length. + * This info could be provided at runtime given that attributes of a specific channel + * could be requested. + */ + case DMA_ATTR_BUFFER_SIZE_ALIGNMENT: + return -ENOSYS; + case DMA_ATTR_MAX_BLOCK_COUNT: + *value = DMA_BLOCK_COUNT; + return 0; + default: + return -EINVAL; + } +} + +static bool dma_smartbond_chan_filter(const struct device *dev, int channel, void *filter_param) +{ + uint32_t requested_channel; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + + /* If user does not provide any channel request explicitly, return true. */ + if (filter_param == NULL) { + return true; + } + + requested_channel = *(uint32_t *)filter_param; + + if (channel == requested_channel) { + return true; + } + + return false; +} + +static struct dma_driver_api dma_smartbond_driver_api = { + .config = dma_smartbond_config, + .reload = dma_smartbond_reload, + .start = dma_smartbond_start, + .stop = dma_smartbond_stop, + .suspend = dma_smartbond_suspend, + .resume = dma_smartbond_resume, + .get_status = dma_smartbond_get_status, + .get_attribute = dma_smartbond_get_attribute, + .chan_filter = dma_smartbond_chan_filter +}; + +static void smartbond_dma_isr(const void *arg) +{ + uint16_t dma_int_status_reg; + int i; + struct channel_regs *regs; + struct dma_smartbond_data *data = ((const struct device *)arg)->data; + + /* + * A single interrupt line is generated for all channels and so each channel + * should be parsed separately. + */ + for (i = 0, dma_int_status_reg = DMA->DMA_INT_STATUS_REG; + i < DMA_CHANNELS_COUNT && dma_int_status_reg != 0; ++i, dma_int_status_reg >>= 1) { + /* Check if the selected channel has raised the interrupt line */ + if (dma_int_status_reg & BIT(0)) { + + regs = DMA_CHN2REG(i); + /* + * Should be valid if callbacks are explicitly enabled by users. + * Interrupt should be triggered only when the total size of + * bytes has been transferred. Bus errors cannot raise interrupts. + */ + if (data->channel_data[i].cb) { + data->channel_data[i].cb((const struct device *)arg, + data->channel_data[i].user_data, i, DMA_STATUS_COMPLETE); + } + /* Channel line should be cleared otherwise ISR will keep firing! */ + DMA->DMA_CLEAR_INT_REG = BIT(i); + } + } +} + +static int dma_smartbond_init(const struct device *dev) +{ +#ifdef CONFIG_DMA_64BIT + LOG_ERR("64-bit addressing mode is not supported\n"); + return -ENOSYS; +#endif + + int idx; + struct dma_smartbond_data *data; + + data = dev->data; + data->dma_ctx.magic = DMA_MAGIC; + data->dma_ctx.dma_channels = DMA_CHANNELS_COUNT; + data->dma_ctx.atomic = data->channels_atomic; + + /* Make sure that all channels are disabled. */ + for (idx = 0; idx < DMA_CHANNELS_COUNT; idx++) { + dma_smartbond_set_channel_status(idx, false); + data->channel_data[idx].is_dma_configured = false; + } + + IRQ_CONNECT(SMARTBOND_IRQN, SMARTBOND_IRQ_PRIO, smartbond_dma_isr, + DEVICE_DT_INST_GET(0), 0); + + return 0; +} + +#define SMARTBOND_DMA_INIT(inst) \ + BUILD_ASSERT((inst) == 0, "multiple instances are not supported"); \ + \ + static struct dma_smartbond_data dma_smartbond_data_ ## inst; \ + \ + DEVICE_DT_INST_DEFINE(0, dma_smartbond_init, NULL, \ + &dma_smartbond_data_ ## inst, NULL, \ + POST_KERNEL, \ + CONFIG_DMA_INIT_PRIORITY, \ + &dma_smartbond_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SMARTBOND_DMA_INIT) diff --git a/dts/bindings/dma/renesas,smartbond-dma.yaml b/dts/bindings/dma/renesas,smartbond-dma.yaml new file mode 100644 index 000000000000000..0845df77463249e --- /dev/null +++ b/dts/bindings/dma/renesas,smartbond-dma.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +include: dma-controller.yaml + +description: Renesas Smartbond(tm) DMA + +compatible: "renesas,smartbond-dma" + +properties: + reg: + required: true + + interrupts: + required: true + + block-count: + required: true + type: int + const: 1 + description: Number of block counts supported diff --git a/include/zephyr/drivers/dma/dma_smartbond.h b/include/zephyr/drivers/dma/dma_smartbond.h new file mode 100644 index 000000000000000..c154488039d87f9 --- /dev/null +++ b/include/zephyr/drivers/dma/dma_smartbond.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef DMA_SMARTBOND_H_ +#define DMA_SMARTBOND_H_ + +/** + * @brief Vendror-specific DMA peripheral triggering sources. + * + * A valid triggering source should be provided when DMA + * is configured for peripheral to peripheral or memory to peripheral + * transactions. + */ +enum dma_smartbond_trig_mux { + DMA_SMARTBOND_TRIG_MUX_SPI = 0x0, + DMA_SMARTBOND_TRIG_MUX_SPI2 = 0x1, + DMA_SMARTBOND_TRIG_MUX_UART = 0x2, + DMA_SMARTBOND_TRIG_MUX_UART2 = 0x3, + DMA_SMARTBOND_TRIG_MUX_I2C = 0x4, + DMA_SMARTBOND_TRIG_MUX_I2C2 = 0x5, + DMA_SMARTBOND_TRIG_MUX_USB = 0x6, + DMA_SMARTBOND_TRIG_MUX_UART3 = 0x7, + DMA_SMARTBOND_TRIG_MUX_PCM = 0x8, + DMA_SMARTBOND_TRIG_MUX_SRC = 0x9, + DMA_SMARTBOND_TRIG_MUX_GPADC = 0xC, + DMA_SMARTBOND_TRIG_MUX_SDADC = 0xD, + DMA_SMARTBOND_TRIG_MUX_NONE = 0xF +}; + +#endif /* DMA_SMARTBOND_H_ */ From dd1371da8b64ed79036e7bdec4c4d78190ba4f7d Mon Sep 17 00:00:00 2001 From: Ioannis Karachalios Date: Mon, 9 Oct 2023 10:39:24 +0300 Subject: [PATCH 0079/1049] dts: renesas: smartbond: Support the DMA engine. Update DTS and board configurations to support the DMA accelerator. Signed-off-by: Ioannis Karachalios --- boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml | 1 + dts/arm/renesas/smartbond/da1469x.dtsi | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml index edfaff84876d4a5..e31a27490023ce1 100644 --- a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml +++ b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml @@ -17,4 +17,5 @@ supported: - usb_device - rtc - crypto + - dma vendor: renesas diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index ecf2f4df63a7b66..6916b2b804cd58a 100644 --- a/dts/arm/renesas/smartbond/da1469x.dtsi +++ b/dts/arm/renesas/smartbond/da1469x.dtsi @@ -303,6 +303,16 @@ interrupts = <15 0>, <21 0>; status = "disabled"; }; + + dma: dma@50040800 { + compatible = "renesas,smartbond-dma"; + reg = <0x50040800 0x110>; + interrupts = <1 0>; + status = "disabled"; + dma-channels = <8>; + block-count = <1>; + #dma-cells = <0>; + }; }; }; From 96a4300c6f7bb99b4734ad060ae69ab950019c1c Mon Sep 17 00:00:00 2001 From: Ioannis Karachalios Date: Tue, 24 Oct 2023 20:26:47 +0300 Subject: [PATCH 0080/1049] tests: drivers: dma: Control testcases via Kconfig Added Kconfig to control BURST16 and board config for da1469x_dk_pro. Signed-off-by: Ioannis Karachalios --- tests/drivers/dma/chan_blen_transfer/Kconfig | 4 ++++ .../chan_blen_transfer/boards/da1469x_dk_pro.conf | 1 + .../boards/da1469x_dk_pro.overlay | 9 +++++++++ .../drivers/dma/chan_blen_transfer/src/test_dma.c | 15 +++++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.conf create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/Kconfig b/tests/drivers/dma/chan_blen_transfer/Kconfig index 7867be5a629f356..748f380b71eac23 100644 --- a/tests/drivers/dma/chan_blen_transfer/Kconfig +++ b/tests/drivers/dma/chan_blen_transfer/Kconfig @@ -21,3 +21,7 @@ config DMA_LOOP_TRANSFER_SRAM_SECTION config DMA_LOOP_TRANSFER_NUMBER_OF_DMAS int "Number of DMAs to test" default 1 + +config DMA_TRANSFER_BURST16 + bool "Enable loop transfers of 16-beat bursts" + default y diff --git a/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.conf b/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.conf new file mode 100644 index 000000000000000..9664ee7c6219304 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.conf @@ -0,0 +1 @@ +CONFIG_DMA_TRANSFER_BURST16=n diff --git a/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.overlay b/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.overlay new file mode 100644 index 000000000000000..eca3c9dc752449b --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/da1469x_dk_pro.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + + test_dma0: &dma { + status = "okay"; +}; diff --git a/tests/drivers/dma/chan_blen_transfer/src/test_dma.c b/tests/drivers/dma/chan_blen_transfer/src/test_dma.c index d0fa561f37ba542..312e7666aec28fb 100644 --- a/tests/drivers/dma/chan_blen_transfer/src/test_dma.c +++ b/tests/drivers/dma/chan_blen_transfer/src/test_dma.c @@ -106,6 +106,7 @@ static int test_task(const struct device *dma, uint32_t chan_id, uint32_t blen) #define DMA_NAME(i, _) test_dma##i #define DMA_LIST LISTIFY(CONFIG_DMA_LOOP_TRANSFER_NUMBER_OF_DMAS, DMA_NAME, (,)) +#if CONFIG_DMA_TRANSFER_BURST16 #define TEST_TASK(dma_name) \ ZTEST(dma_m2m, test_##dma_name##_m2m_chan0_burst8) \ { \ @@ -130,5 +131,19 @@ static int test_task(const struct device *dma, uint32_t chan_id, uint32_t blen) const struct device *dma = DEVICE_DT_GET(DT_NODELABEL(dma_name)); \ zassert_true((test_task(dma, CONFIG_DMA_TRANSFER_CHANNEL_NR_1, 16) == TC_PASS)); \ } +#else +#define TEST_TASK(dma_name) \ + ZTEST(dma_m2m, test_##dma_name##_m2m_chan0_burst8) \ + { \ + const struct device *dma = DEVICE_DT_GET(DT_NODELABEL(dma_name)); \ + zassert_true((test_task(dma, CONFIG_DMA_TRANSFER_CHANNEL_NR_0, 8) == TC_PASS)); \ + } \ + \ + ZTEST(dma_m2m, test_##dma_name##_m2m_chan1_burst8) \ + { \ + const struct device *dma = DEVICE_DT_GET(DT_NODELABEL(dma_name)); \ + zassert_true((test_task(dma, CONFIG_DMA_TRANSFER_CHANNEL_NR_1, 8) == TC_PASS)); \ + } +#endif FOR_EACH(TEST_TASK, (), DMA_LIST); From fbee62d9e32a6caae99949cd4b32af9133a9008a Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Fri, 27 Oct 2023 11:39:34 +0300 Subject: [PATCH 0081/1049] dts: bindings: adxl372: move int1-gpios to common The `int1-gpios` property is common for both spi and i2c implementations of adxl372. Therefore move it to `adi,adxl372-common.yaml` Signed-off-by: Antoniu Miclaus --- dts/bindings/sensor/adi,adxl372-common.yaml | 7 +++++++ dts/bindings/sensor/adi,adxl372-i2c.yaml | 8 -------- dts/bindings/sensor/adi,adxl372-spi.yaml | 8 -------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/dts/bindings/sensor/adi,adxl372-common.yaml b/dts/bindings/sensor/adi,adxl372-common.yaml index 6c666dce8a9355a..547337fc70a0f92 100644 --- a/dts/bindings/sensor/adi,adxl372-common.yaml +++ b/dts/bindings/sensor/adi,adxl372-common.yaml @@ -56,3 +56,10 @@ properties: - 2 - 3 - 4 + + int1-gpios: + type: phandle-array + description: | + The INT1 signal defaults to active high as produced by the + sensor. The property value should ensure the flags properly + describe the signal that is presented to the driver. diff --git a/dts/bindings/sensor/adi,adxl372-i2c.yaml b/dts/bindings/sensor/adi,adxl372-i2c.yaml index f6f0ac197eddcf6..1e732b1f9d48988 100644 --- a/dts/bindings/sensor/adi,adxl372-i2c.yaml +++ b/dts/bindings/sensor/adi,adxl372-i2c.yaml @@ -6,11 +6,3 @@ description: ADXL372 3-axis high-g accelerometer, accessed through I2C bus compatible: "adi,adxl372" include: ["i2c-device.yaml", "adi,adxl372-common.yaml"] - -properties: - int1-gpios: - type: phandle-array - description: | - The INT1 signal defaults to active high as produced by the - sensor. The property value should ensure the flags properly - describe the signal that is presented to the driver. diff --git a/dts/bindings/sensor/adi,adxl372-spi.yaml b/dts/bindings/sensor/adi,adxl372-spi.yaml index 7d6863c3118117f..2cb4e6745223466 100644 --- a/dts/bindings/sensor/adi,adxl372-spi.yaml +++ b/dts/bindings/sensor/adi,adxl372-spi.yaml @@ -7,11 +7,3 @@ description: ADXL372 3-axis high-g accelerometer, accessed through SPI bus compatible: "adi,adxl372" include: ["spi-device.yaml", "adi,adxl372-common.yaml"] - -properties: - int1-gpios: - type: phandle-array - description: | - The INT1 signal defaults to active high as produced by the - sensor. The property value should ensure the flags properly - describe the signal that is presented to the driver. From f93243b68feb253e7b0f3cd9c0da344e72d63e35 Mon Sep 17 00:00:00 2001 From: Emil Obalski Date: Tue, 24 Oct 2023 16:59:10 +0200 Subject: [PATCH 0082/1049] ipc: Remove nocopy feature from icmsg_me backend Remove nocopy feature from icmsg_me backend. The backend is not meant to be used to send big data chunks thus no-copy feature is removed. If one wants to use no-copy it is recommended to use icmsg_me only for control messages while allocator will shall be written seperately. Signed-off-by: Emil Obalski --- include/zephyr/ipc/icmsg.h | 145 ------------------ include/zephyr/ipc/icmsg_me.h | 112 -------------- .../subsys/ipc/ipc_service/icmsg_me/prj.conf | 1 - .../ipc/ipc_service/icmsg_me/remote/prj.conf | 1 - .../ipc_service/icmsg_me/remote/src/main.c | 39 +---- .../ipc/ipc_service/icmsg_me/src/main.c | 40 +---- .../ipc/ipc_service/backends/Kconfig.icmsg_me | 10 -- .../backends/ipc_icmsg_me_follower.c | 61 -------- .../backends/ipc_icmsg_me_initiator.c | 57 ------- subsys/ipc/ipc_service/lib/Kconfig | 9 -- subsys/ipc/ipc_service/lib/Kconfig.icmsg | 7 - subsys/ipc/ipc_service/lib/icmsg_me.c | 118 -------------- 12 files changed, 14 insertions(+), 586 deletions(-) diff --git a/include/zephyr/ipc/icmsg.h b/include/zephyr/ipc/icmsg.h index cdd1cb064d1e83f..099c6265acd5272 100644 --- a/include/zephyr/ipc/icmsg.h +++ b/include/zephyr/ipc/icmsg.h @@ -134,151 +134,6 @@ int icmsg_send(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const void *msg, size_t len); -/** @brief Get an empty TX buffer to be sent using @ref icmsg_send_nocopy - * - * This function can be called to get an empty TX buffer so that the - * application can directly put its data into the sending buffer avoiding copy - * performed by the icmsg library. - * - * It is the application responsibility to correctly fill the allocated TX - * buffer with data and passing correct parameters to @ref - * icmsg_send_nocopy function to perform data no-copy-send mechanism. - * - * The size parameter can be used to request a buffer with a certain size: - * - if the size can be accommodated the function returns no errors and the - * buffer is allocated - * - if the requested size is too big, the function returns -ENOMEM and the - * the buffer is not allocated. - * - if the requested size is '0' the buffer is allocated with the maximum - * allowed size. - * - * In all the cases on return the size parameter contains the maximum size for - * the returned buffer. - * - * When the function returns no errors, the buffer is intended as allocated - * and it is released under one of two conditions: (1) when sending the buffer - * using @ref icmsg_send_nocopy (and in this case the buffer is automatically - * released by the backend), (2) when using @ref icmsg_drop_tx_buffer on a - * buffer not sent. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[out] data Pointer to the empty TX buffer. - * @param[inout] size Pointer to store the requested TX buffer size. If the - * function returns -ENOMEM, this parameter returns the - * maximum allowed size. - * - * @retval -ENOBUFS when there are no TX buffers available. - * @retval -EALREADY when a buffer was already claimed and not yet released. - * @retval -ENOMEM when the requested size is too big (and the size parameter - * contains the maximum allowed size). - * - * @retval 0 on success. - */ -int icmsg_get_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - void **data, size_t *size); - -/** @brief Drop and release a TX buffer - * - * Drop and release a TX buffer. It is possible to drop only TX buffers - * obtained by using @ref icmsg_get_tx_buffer. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[in] data Pointer to the TX buffer. - * - * @retval -EALREADY when the buffer was already dropped. - * @retval -ENXIO when the buffer was not obtained using @ref - * ipc_service_get_tx_buffer - * - * @retval 0 on success. - */ -int icmsg_drop_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *data); - -/** @brief Send a message from a buffer obtained by @ref icmsg_get_tx_buffer - * to the remote icmsg instance. - * - * This is equivalent to @ref icmsg_send but in this case the TX buffer must - * have been obtained by using @ref icmsg_get_tx_buffer. - * - * The API user has to take the responsibility for getting the TX buffer using - * @ref icmsg_get_tx_buffer and filling the TX buffer with the data. - * - * After the @ref icmsg_send_nocopy function is issued the TX buffer is no - * more owned by the sending task and must not be touched anymore unless the - * function fails and returns an error. - * - * If this function returns an error, @ref icmsg_drop_tx_buffer can be used - * to drop the TX buffer. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[in] msg Pointer to a buffer containing data to send. - * @param[in] len Size of data in the @p msg buffer. - * - * - * @return Size of sent data on success. - * @retval -EBUSY when the instance has not finished handshake with the remote - * instance. - * @retval -ENODATA when the requested data to send is empty. - * @retval -EBADMSG when the requested data to send is too big. - * @retval -ENXIO when the buffer was not obtained using @ref - * ipc_service_get_tx_buffer - * @retval other errno codes from dependent modules. - */ -int icmsg_send_nocopy(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *msg, size_t len); - -#ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX -/** @brief Hold RX buffer to be used outside of the received callback. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[in] data Pointer to the buffer to be held. - * - * @retval 0 on success. - * @retval -EBUSY when the instance has not finished handshake with the remote - * instance. - * @retval -EINVAL when the @p data argument does not point to a valid RX - * buffer. - * @retval -EALREADY when the buffer is already held. - */ -int icmsg_hold_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *data); - -/** @brief Release RX buffer for future use. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[in] data Pointer to the buffer to be released. - * - * @retval 0 on success. - * @retval -EBUSY when the instance has not finished handshake with the remote - * instance. - * @retval -EINVAL when the @p data argument does not point to a valid RX - * buffer. - * @retval -EALREADY when the buffer is not held. - */ -int icmsg_release_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *data); -#endif - /** * @} */ diff --git a/include/zephyr/ipc/icmsg_me.h b/include/zephyr/ipc/icmsg_me.h index 554f5785ba837d4..9736b0148c6cd0c 100644 --- a/include/zephyr/ipc/icmsg_me.h +++ b/include/zephyr/ipc/icmsg_me.h @@ -247,118 +247,6 @@ int icmsg_me_send(const struct icmsg_config_t *conf, struct icmsg_me_data_t *data, icmsg_me_ept_id_t id, const void *msg, size_t len); -/** @brief Get an empty TX buffer to be sent using @ref icmsg_me_send_nocopy - * - * This function is a wrapper around @ref icmsg_get_tx_buffer aligning buffer - * size and pointers to fit header required by the multi-endpoint feature. - * It shares all properites and usage scenarios with @ref icmsg_get_tx_buffer. - * - * @param[in] conf Structure containing configuration parameters for the - & underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[out] buffer Pointer to the empty TX buffer. - * @param[inout] size Pointer to store the requested TX buffer size. If the - * function returns -ENOMEM, this parameter returns the - * maximum allowed size. - * @param[in] wait Timeout value to wait for a free buffer acceptable by - * the function caller. Only K_NO_WAIT is supported by icmsg. - * - * @retval 0 on success. - * @retval -ENOTSUP when requested unsupported @p wait timeout. - * @retval -ENOBUFS when there are no TX buffers available. - * @retval -ENOMEM when the requested size is too big (and the size parameter - * contains the maximum allowed size). - * @retval other errno codes from dependent modules. - */ -int icmsg_me_get_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, - void **buffer, uint32_t *size, k_timeout_t wait); - -/** @brief Drop and release a TX buffer - * - * This function is a wrapper around @ref icmsg_drop_tx_buffer aligning buffer - * pointer to fit header required by the multi-endpoint feature. This function - * shares all properties and usage scenarios with @ref icmsg_drop_tx_buffer. - * - * @param[in] conf Structure containing configuration parameters for the - * underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[in] buffer Pointer to the TX buffer obtained with - * @ref icmsg_me_get_tx_buffer. - * - * @retval 0 on success. - * @retval other errno codes from dependent modules. - */ -int icmsg_me_drop_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, - const void *buffer); - -/** @brief Send a message from a buffer obtained by @ref icmsg_me_get_tx_buffer - * to the remote icmsg_me instance. - * - * This function is a wrapper around @ref icmsg_send_nocopy aligning buffer - * size and pointer to fit header required by the multi-endpoint feature. This - * function shares all properties and usage scenarios with - * @ref icmsg_send_nocopy. - * - * @param[in] conf Structure containing configuration parameters for the - * underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[in] id Id of the endpoint to use. - * @param[in] msg Pointer to a buffer containing data to send. - * @param[in] len Size of data in the @p msg buffer. - * - * - * @return Size of sent data on success. - * @retval other errno codes from dependent modules. - */ -int icmsg_me_send_nocopy(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, icmsg_me_ept_id_t id, - const void *msg, size_t len); - -#ifdef CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX -/** @brief Hold RX buffer to be used outside of the received callback. - * - * @param[in] conf Structure containing configuration parameters for the - * underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[in] buffer Pointer to the buffer to be held. - * - * @retval 0 on success. - * @retval other errno codes from dependent modules. - */ -int icmsg_me_hold_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, void *buffer); - -/** @brief Release RX buffer for future use. - * - * @param[in] conf Structure containing configuration parameters for the - * underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[in] buffer Pointer to the buffer to be released. - * - * @retval 0 on success. - * @retval other errno codes from dependent modules. - */ -int icmsg_me_release_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, void *buffer); -#endif /* CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX */ - /** * @} */ diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/prj.conf b/samples/subsys/ipc/ipc_service/icmsg_me/prj.conf index 5feb10b31200f50..4c5326d139769e2 100644 --- a/samples/subsys/ipc/ipc_service/icmsg_me/prj.conf +++ b/samples/subsys/ipc/ipc_service/icmsg_me/prj.conf @@ -1,7 +1,6 @@ CONFIG_PRINTK=y CONFIG_IPC_SERVICE=y -CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX=y CONFIG_MBOX=y CONFIG_LOG=y diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf b/samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf index 5feb10b31200f50..4c5326d139769e2 100644 --- a/samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf +++ b/samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf @@ -1,7 +1,6 @@ CONFIG_PRINTK=y CONFIG_IPC_SERVICE=y -CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX=y CONFIG_MBOX=y CONFIG_LOG=y diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/src/main.c b/samples/subsys/ipc/ipc_service/icmsg_me/remote/src/main.c index 387f962af95379f..9b288f8a6a1801f 100644 --- a/samples/subsys/ipc/ipc_service/icmsg_me/remote/src/main.c +++ b/samples/subsys/ipc/ipc_service/icmsg_me/remote/src/main.c @@ -18,7 +18,7 @@ K_THREAD_STACK_DEFINE(ipc1_stack, STACKSIZE); static volatile uint8_t ipc0A_received_data; static volatile uint8_t ipc0B_received_data; -static const void *ipc1_received_data; +static volatile uint8_t ipc1_received_data; static K_SEM_DEFINE(ipc0A_bound_sem, 0, 1); static K_SEM_DEFINE(ipc0B_bound_sem, 0, 1); @@ -182,11 +182,8 @@ K_THREAD_DEFINE(ipc0B_thread_id, STACKSIZE, ipc0B_entry, NULL, NULL, NULL, PRIOR /* * ==> THREAD 1 (IPC instance 1) <== * - * NOTE: This instance is using the NOCOPY copability of the backend. */ -static struct ipc_ept ipc1_ept; - static void ipc1_ept_bound(void *priv) { k_sem_give(&ipc1_bound_sem); @@ -194,10 +191,9 @@ static void ipc1_ept_bound(void *priv) static void ipc1_ept_recv(const void *data, size_t len, void *priv) { - ipc_service_hold_rx_buffer(&ipc1_ept, (void *)data); - ipc1_received_data = data; + ipc1_received_data = *((uint8_t *) data); - k_sem_give(&ipc1_data_sem); + k_sem_give(&ipc0B_data_sem); } static struct ipc_ept_cfg ipc1_ept_cfg = { @@ -216,6 +212,7 @@ static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2) const struct device *ipc1_instance; unsigned char message = 0; + struct ipc_ept ipc1_ept; int ret; printk("IPC-service REMOTE [INST 1] demo started\n"); @@ -237,38 +234,16 @@ static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2) k_sem_take(&ipc1_bound_sem, K_FOREVER); while (message < 99) { - void *tx_buffer; - uint32_t tx_buffer_size = sizeof(message); - k_sem_take(&ipc1_data_sem, K_FOREVER); - message = *((uint8_t *) ipc1_received_data); - - ret = ipc_service_release_rx_buffer(&ipc1_ept, (void *) ipc1_received_data); - if (ret < 0) { - printk("release_rx_buffer() failed with ret %d\n", ret); - break; - } + message = ipc1_received_data; printk("REMOTE [1]: %d\n", message); message++; - ret = ipc_service_get_tx_buffer(&ipc1_ept, &tx_buffer, &tx_buffer_size, K_NO_WAIT); + ret = ipc_service_send(&ipc1_ept, &message, sizeof(message)); if (ret < 0) { - printk("get_tx_buffer(%u) failed with ret %d\n", sizeof(message), ret); - break; - } - if (tx_buffer_size != sizeof(message)) { - printk("get_tx_buffer modified buffer size to unexpected value %u\n", - tx_buffer_size); - break; - } - - *((uint8_t *) tx_buffer) = message; - - ret = ipc_service_send_nocopy(&ipc1_ept, tx_buffer, tx_buffer_size); - if (ret < 0) { - printk("send_message_nocopy(%u) failed with ret %d\n", message, ret); + printk("send_message(%d) failed with ret %d\n", message, ret); break; } } diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/src/main.c b/samples/subsys/ipc/ipc_service/icmsg_me/src/main.c index 92b3a5569ef109a..78d7af05288208a 100644 --- a/samples/subsys/ipc/ipc_service/icmsg_me/src/main.c +++ b/samples/subsys/ipc/ipc_service/icmsg_me/src/main.c @@ -18,7 +18,7 @@ K_THREAD_STACK_DEFINE(ipc1_stack, STACKSIZE); static volatile uint8_t ipc0A_received_data; static volatile uint8_t ipc0B_received_data; -static const void *ipc1_received_data; +static volatile uint8_t ipc1_received_data; static K_SEM_DEFINE(ipc0A_bound_sem, 0, 1); static K_SEM_DEFINE(ipc0B_bound_sem, 0, 1); @@ -179,12 +179,8 @@ K_THREAD_DEFINE(ipc0B_thread_id, STACKSIZE, ipc0B_entry, NULL, NULL, NULL, PRIOR /* * ==> THREAD 1 (IPC instance 1) <== - * - * NOTE: This instance is using the NOCOPY copability of the backend. */ -static struct ipc_ept ipc1_ept; - static void ipc1_ept_bound(void *priv) { k_sem_give(&ipc1_bound_sem); @@ -192,10 +188,9 @@ static void ipc1_ept_bound(void *priv) static void ipc1_ept_recv(const void *data, size_t len, void *priv) { - ipc_service_hold_rx_buffer(&ipc1_ept, (void *)data); - ipc1_received_data = data; + ipc1_received_data = *((uint8_t *) data); - k_sem_give(&ipc1_data_sem); + k_sem_give(&ipc0B_data_sem); } static struct ipc_ept_cfg ipc1_ept_cfg = { @@ -214,6 +209,7 @@ static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2) const struct device *ipc1_instance; unsigned char message = 0; + struct ipc_ept ipc1_ept; int ret; printk("IPC-service HOST [INST 1] demo started\n"); @@ -242,36 +238,14 @@ static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2) k_sleep(K_MSEC(1000)); while (message < 100) { - void *tx_buffer; - uint32_t tx_buffer_size = sizeof(message); - - ret = ipc_service_get_tx_buffer(&ipc1_ept, &tx_buffer, &tx_buffer_size, K_NO_WAIT); - if (ret < 0) { - printk("get_tx_buffer(%u) failed with ret %d\n", sizeof(message), ret); - break; - } - if (tx_buffer_size != sizeof(message)) { - printk("get_tx_buffer modified buffer size to unexpected value %u\n", - tx_buffer_size); - break; - } - - *((uint8_t *) tx_buffer) = message; - - ret = ipc_service_send_nocopy(&ipc1_ept, tx_buffer, tx_buffer_size); + ret = ipc_service_send(&ipc1_ept, &message, sizeof(message)); if (ret < 0) { - printk("send_message_nocopy(%u) failed with ret %d\n", message, ret); + printk("send_message(%d) failed with ret %d\n", message, ret); break; } k_sem_take(&ipc1_data_sem, K_FOREVER); - message = *((uint8_t *) ipc1_received_data); - - ret = ipc_service_release_rx_buffer(&ipc1_ept, (void *) ipc1_received_data); - if (ret < 0) { - printk("release_rx_buffer() failed with ret %d\n", ret); - break; - } + message = ipc1_received_data; printk("HOST [1]: %d\n", message); message++; diff --git a/subsys/ipc/ipc_service/backends/Kconfig.icmsg_me b/subsys/ipc/ipc_service/backends/Kconfig.icmsg_me index 0513719cc982acd..e348984fb621e0b 100644 --- a/subsys/ipc/ipc_service/backends/Kconfig.icmsg_me +++ b/subsys/ipc/ipc_service/backends/Kconfig.icmsg_me @@ -28,14 +28,4 @@ config IPC_SERVICE_BACKEND_ICMSG_ME_EP_NAME_LEN Maximal length of a string used to discover endpoints between the initiator and the follower. -config IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX - bool "Nocopy feature for receive path" - select IPC_SERVICE_ICMSG_ME_NOCOPY_RX - help - Enable nocopy feature for receive path of multiendpoint icmsg - ipc_service backend. This features enables functions to hold and - release rx buffer by the ipc_service API user. It also creates - performance and memory overhead so it is recommended to disable - this feature if unused by the API user. - endif # IPC_SERVICE_BACKEND_ICMSG_ME_INITIATOR || IPC_SERVICE_BACKEND_ICMSG_ME_FOLLOWER 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 df27aaedcbb0f36..8b0944c840f9b8c 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c @@ -260,71 +260,10 @@ static int send(const struct device *instance, void *token, user_len); } -static int get_tx_buffer(const struct device *instance, void *token, - void **data, uint32_t *user_len, k_timeout_t wait) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - - return icmsg_me_get_tx_buffer(conf, &dev_data->icmsg_me_data, data, - user_len, wait); -} - -static int drop_tx_buffer(const struct device *instance, void *token, - const void *data) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - - return icmsg_me_drop_tx_buffer(conf, &dev_data->icmsg_me_data, data); -} - -static int send_nocopy(const struct device *instance, void *token, - const void *data, size_t len) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - icmsg_me_ept_id_t *id = token; - - if (*id == INVALID_EPT_ID) { - return -ENOTCONN; - } - - return icmsg_me_send_nocopy(conf, &dev_data->icmsg_me_data, *id, - data, len); -} - -#ifdef CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX -int hold_rx_buffer(const struct device *instance, void *token, void *data) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - - return icmsg_me_hold_rx_buffer(conf, &dev_data->icmsg_me_data, data); -} - -int release_rx_buffer(const struct device *instance, void *token, void *data) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - - return icmsg_me_release_rx_buffer(conf, &dev_data->icmsg_me_data, data); -} -#endif /* CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX */ - const static struct ipc_service_backend backend_ops = { .open_instance = open, .register_endpoint = register_ept, .send = send, - - .get_tx_buffer = get_tx_buffer, - .drop_tx_buffer = drop_tx_buffer, - .send_nocopy = send_nocopy, - -#ifdef CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX - .hold_rx_buffer = hold_rx_buffer, - .release_rx_buffer = release_rx_buffer, -#endif }; static int backend_init(const struct device *instance) 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 da6912c83880863..2699d3b6db66feb 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c @@ -166,67 +166,10 @@ static int send(const struct device *instance, void *token, return icmsg_me_send(conf, &dev_data->icmsg_me_data, *id, msg, len); } -static int get_tx_buffer(const struct device *instance, void *token, - void **data, uint32_t *user_len, k_timeout_t wait) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - - return icmsg_me_get_tx_buffer(conf, &dev_data->icmsg_me_data, data, - user_len, wait); -} - -static int drop_tx_buffer(const struct device *instance, void *token, - const void *data) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - - return icmsg_me_drop_tx_buffer(conf, &dev_data->icmsg_me_data, data); -} - -static int send_nocopy(const struct device *instance, void *token, - const void *data, size_t len) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - icmsg_me_ept_id_t *id = token; - - return icmsg_me_send_nocopy(conf, &dev_data->icmsg_me_data, *id, - data, len); -} - -#ifdef CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX -int hold_rx_buffer(const struct device *instance, void *token, void *data) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - - return icmsg_me_hold_rx_buffer(conf, &dev_data->icmsg_me_data, data); -} - -int release_rx_buffer(const struct device *instance, void *token, void *data) -{ - const struct icmsg_config_t *conf = instance->config; - struct backend_data_t *dev_data = instance->data; - - return icmsg_me_release_rx_buffer(conf, &dev_data->icmsg_me_data, data); -} -#endif /* CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX */ - const static struct ipc_service_backend backend_ops = { .open_instance = open, .register_endpoint = register_ept, .send = send, - - .get_tx_buffer = get_tx_buffer, - .drop_tx_buffer = drop_tx_buffer, - .send_nocopy = send_nocopy, - -#ifdef CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX - .hold_rx_buffer = hold_rx_buffer, - .release_rx_buffer = release_rx_buffer, -#endif }; static int backend_init(const struct device *instance) diff --git a/subsys/ipc/ipc_service/lib/Kconfig b/subsys/ipc/ipc_service/lib/Kconfig index f2b4d8ae210a1a4..6bd57ab15aa67a3 100644 --- a/subsys/ipc/ipc_service/lib/Kconfig +++ b/subsys/ipc/ipc_service/lib/Kconfig @@ -36,12 +36,3 @@ config IPC_SERVICE_ICMSG_ME select EVENTS help Multi-endpoint functionality for the icmsg library - -config IPC_SERVICE_ICMSG_ME_NOCOPY_RX - bool - depends on IPC_SERVICE_ICMSG_ME - select IPC_SERVICE_ICMSG_NOCOPY_RX - help - Enable nocopy feature for receiving path of the multi-endpoint - feature of the icmsg library. This features might be used by backends - based on multi-endpoint icmsg. diff --git a/subsys/ipc/ipc_service/lib/Kconfig.icmsg b/subsys/ipc/ipc_service/lib/Kconfig.icmsg index e8f92a945a3c2e0..8f1a380a18f3692 100644 --- a/subsys/ipc/ipc_service/lib/Kconfig.icmsg +++ b/subsys/ipc/ipc_service/lib/Kconfig.icmsg @@ -1,13 +1,6 @@ # Copyright (c) 2022 Nordic Semiconductor (ASA) # SPDX-License-Identifier: Apache-2.0 -config IPC_SERVICE_ICMSG_NOCOPY_RX - bool - depends on IPC_SERVICE_ICMSG - help - Enable nocopy feature for receiving path of the icmsg library that - might be used by backends based on icmsg. - config IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC bool "Synchronize access to shared memory" default y diff --git a/subsys/ipc/ipc_service/lib/icmsg_me.c b/subsys/ipc/ipc_service/lib/icmsg_me.c index 870dca0d483c681..24e3ba6514e9c1b 100644 --- a/subsys/ipc/ipc_service/lib/icmsg_me.c +++ b/subsys/ipc/ipc_service/lib/icmsg_me.c @@ -20,11 +20,6 @@ static void *icmsg_buffer_to_user_buffer(const void *icmsg_buffer) return (void *)(((char *)icmsg_buffer) + HEADER_SIZE); } -static void *user_buffer_to_icmsg_buffer(const void *user_buffer) -{ - return (void *)(((char *)user_buffer) - HEADER_SIZE); -} - static size_t icmsg_buffer_len_to_user_buffer_len(size_t icmsg_buffer_len) { return icmsg_buffer_len - HEADER_SIZE; @@ -202,116 +197,3 @@ int icmsg_me_send(const struct icmsg_config_t *conf, return sent_bytes; } - -static size_t get_buffer_length_to_pass(size_t icmsg_buffer_len) -{ - if (icmsg_buffer_len >= HEADER_SIZE) { - return icmsg_buffer_len_to_user_buffer_len(icmsg_buffer_len); - } else { - return 0; - } -} - -int icmsg_me_get_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, - void **buffer, uint32_t *user_len, k_timeout_t wait) -{ - void *icmsg_buffer; - int r; - size_t icmsg_len; - - if (!K_TIMEOUT_EQ(wait, K_NO_WAIT)) { - return -ENOTSUP; - } - - if (*user_len) { - icmsg_len = user_buffer_len_to_icmsg_buffer_len(*user_len); - } else { - icmsg_len = 0; - } - - r = icmsg_get_tx_buffer(conf, &data->icmsg_data, - &icmsg_buffer, &icmsg_len); - if (r == -ENOMEM) { - *user_len = get_buffer_length_to_pass(icmsg_len); - return -ENOMEM; - } - - if (r < 0) { - return r; - } - - /* If requested max buffer length (*len == 0) allocated buffer might be - * shorter than HEADER_SIZE. In such circumstances drop the buffer - * and return error. - */ - *user_len = get_buffer_length_to_pass(icmsg_len); - - if (!(*user_len)) { - r = icmsg_drop_tx_buffer(conf, &data->icmsg_data, icmsg_buffer); - __ASSERT_NO_MSG(!r); - return -ENOBUFS; - } - - *buffer = icmsg_buffer_to_user_buffer(icmsg_buffer); - return 0; - -} - -int icmsg_me_drop_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, - const void *buffer) -{ - const void *buffer_to_drop = user_buffer_to_icmsg_buffer(buffer); - - return icmsg_drop_tx_buffer(conf, &data->icmsg_data, buffer_to_drop); -} - -int icmsg_me_send_nocopy(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, icmsg_me_ept_id_t id, - const void *msg, size_t len) -{ - void *buffer_to_send; - size_t len_to_send; - int r; - int sent_bytes; - - buffer_to_send = user_buffer_to_icmsg_buffer(msg); - len_to_send = user_buffer_len_to_icmsg_buffer_len(len); - - set_ept_id_in_send_buffer(buffer_to_send, id); - - r = icmsg_send_nocopy(conf, &data->icmsg_data, - buffer_to_send, len_to_send); - - if (r < 0) { - return r; - } - - __ASSERT_NO_MSG(r >= HEADER_SIZE); - if (r < HEADER_SIZE) { - return 0; - } - - sent_bytes = icmsg_buffer_len_to_user_buffer_len(r); - - return sent_bytes; -} - -#ifdef CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX -int icmsg_me_hold_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, void *buffer) -{ - void *icmsg_buffer = user_buffer_to_icmsg_buffer(buffer); - - return icmsg_hold_rx_buffer(conf, &data->icmsg_data, icmsg_buffer); -} - -int icmsg_me_release_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, void *buffer) -{ - void *icmsg_buffer = user_buffer_to_icmsg_buffer(buffer); - - return icmsg_release_rx_buffer(conf, &data->icmsg_data, icmsg_buffer); -} -#endif /* CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX */ From 380f83bab1efb4480dfebdbefb1ed22fbae317e8 Mon Sep 17 00:00:00 2001 From: Emil Obalski Date: Fri, 11 Aug 2023 14:29:29 +0200 Subject: [PATCH 0083/1049] ipc: Add pbuf implementation This adds implementation of secure packed buffer. Secure packed buffer is added with intention to be used in icmsg backed backends. Signed-off-by: Emil Obalski --- include/zephyr/ipc/pbuf.h | 201 +++++++++++++++++++ subsys/ipc/ipc_service/lib/CMakeLists.txt | 1 + subsys/ipc/ipc_service/lib/Kconfig.icmsg | 8 + subsys/ipc/ipc_service/lib/pbuf.c | 223 ++++++++++++++++++++++ 4 files changed, 433 insertions(+) create mode 100644 include/zephyr/ipc/pbuf.h create mode 100644 subsys/ipc/ipc_service/lib/pbuf.c diff --git a/include/zephyr/ipc/pbuf.h b/include/zephyr/ipc/pbuf.h new file mode 100644 index 000000000000000..f8eff0b1ad1753e --- /dev/null +++ b/include/zephyr/ipc/pbuf.h @@ -0,0 +1,201 @@ +/* + * 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 + * @ingroup kernel_apis + * @{ + */ + +/** @brief Size of packet length field. */ +#define PBUF_PACKET_LEN_SZ sizeof(uint32_t) + +/* Amount of data that is left unused to distinguish between empty and full. */ +#define _PBUF_IDX_SIZE sizeof(uint32_t) + +/* Minimal length of the data field in the buffer to store the smalest packet + * possible. + * (+1) for at least one byte of data. + * (+_PBUF_IDX_SIZE) to distinguish buffer full and buffer empty. + * Rounded up to keep wr/rd indexes pointing to aligned address. + */ +#define _PBUF_MIN_DATA_LEN ROUND_UP(PBUF_PACKET_LEN_SZ + 1 + _PBUF_IDX_SIZE, _PBUF_IDX_SIZE) + +/** @brief Control block of packet buffer. + * + * The structure contains configuration data. + */ +struct pbuf_cfg { + volatile uint32_t *rd_idx_loc; /* Address of the variable holding + * index value of the first valid byte + * in data[]. + */ + volatile uint32_t *wr_idx_loc; /* Address of the variable holding + * index value of the first free byte + * in data[]. + */ + uint32_t dcache_alignment; /* CPU data cache line size in bytes. + * Used for validation - TODO: To be + * replaced by flags. + */ + uint32_t len; /* Length of data[] in bytes. */ + uint8_t *data_loc; /* Location of the data[]. */ +}; + +/** + * @brief Data block of the packed buffer. + * + * The structure contains local copies of wr and rd indexes used by writer and + * reader respecitvely. + */ +struct pbuf_data { + volatile uint32_t wr_idx; /* Index of the first holding first + * free byte in data[]. Used for + * writing. + */ + volatile uint32_t rd_idx; /* Index of the first holding first + * valid byte in data[]. Used for + * reading. + */ +}; + + +/** + * @brief Scure packed buffer. + * + * The packet buffer implements lightweight unidirectional packet + * buffer with read/write semantics on top of a memory region shared + * by the reader and writer. It embeds cache and memory barrier management to + * ensure correct data access. + * + * This structure supports single writer and reader. Data stored in the buffer + * is encapsulated to a message (with length header). The read/write API is + * written in a way to protect the data from being corrupted. + */ +struct pbuf { + const struct pbuf_cfg *const cfg; /* Configuration of the + * buffer. + */ + struct pbuf_data data; /* Data used to read and write + * to the buffer + */ +}; + +/** + * @brief Macro for configuration initialization. + * + * It is recommended to use this macro to initialize packed buffer + * configuration. + * + * @param mem_addr Memory address for pbuf. + * @param size Size of the memory. + * @param dcache_align Data cache alignment. + */ +#define PBUF_CFG_INIT(mem_addr, size, dcache_align) \ +{ \ + .rd_idx_loc = (uint32_t *)(mem_addr), \ + .wr_idx_loc = (uint32_t *)((uint8_t *)(mem_addr) + \ + MAX(dcache_align, _PBUF_IDX_SIZE)), \ + .data_loc = (uint8_t *)((uint8_t *)(mem_addr) + \ + MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE), \ + .len = (uint32_t)((uint32_t)(size) - MAX(dcache_align, _PBUF_IDX_SIZE) - \ + _PBUF_IDX_SIZE), \ + .dcache_alignment = (dcache_align), \ +} + +/** + * @brief Statically define and initialize pbuf. + * + * @param name Name of the pbuf. + * @param mem_addr Memory address for pbuf. + * @param size Size of the memory. + * @param dcache_align Data cache line size. + */ +#define PBUF_DEFINE(name, mem_addr, size, dcache_align) \ + BUILD_ASSERT(dcache_align >= 0, \ + "Cache line size must be non negative."); \ + BUILD_ASSERT((size) > 0 && IS_PTR_ALIGNED_BYTES(size, _PBUF_IDX_SIZE), \ + "Incorrect size."); \ + BUILD_ASSERT(IS_PTR_ALIGNED_BYTES(mem_addr, MAX(dcache_align, _PBUF_IDX_SIZE)), \ + "Misaligned memory."); \ + BUILD_ASSERT(size >= (MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE + \ + _PBUF_MIN_DATA_LEN), "Insufficient size."); \ + \ + static const struct pbuf_cfg cfg_##name = \ + PBUF_CFG_INIT(mem_addr, size, dcache_align); \ + static struct pbuf name = { \ + .cfg = &cfg_##name, \ + } + +/** + * @brief Initialize the packet buffer. + * + * This function initializes the packet buffer based on provided configuration. + * If the configuration is incorrect, the function will return error. + * + * It is recommended to use PBUF_DEFINE macro for build time initialization. + * + * @param pb Pointer to the packed buffer containing + * configuration and data. Configuration has to be + * fixed before the initialization. + * @retval 0 on success. + * @retval -EINVAL when the input parameter is incorrect. + */ +int pbuf_init(struct pbuf *pb); + +/** + * @brief Write specified amount of data to the packet buffer. + * + * This function call writes specified amount of data to the packet buffer if + * the buffer will fit the data. + * + * @param pb A buffer to which to write. + * @param buf Pointer to the data to be written to the buffer. + * @param len Number of bytes to be written to the buffer. Must be positive. + * @retval int Number of bytes written, negative error code on fail. + * -EINVAL, if any of input parameter is incorrect. + * -ENOMEM, if len is bigger than the buffer can fit. + */ + +int pbuf_write(struct pbuf *pb, const char *buf, uint16_t len); + +/** + * @brief Read specified amount of data from the packet buffer. + * + * Single read allows to read the message send by the single write. + * The provided %p buf must be big enough to store the whole message. + * + * @param pb A buffer from which data will be read. + * @param buf Data pointer to which read data will be written. + * If NULL, len of stored message is returned. + * @param len Number of bytes to be read from the buffer. + * @retval int Bytes read, negative error code on fail. + * Bytes to be read, if buf == NULL. + * -EINVAL, if any of input parameter is incorrect. + * -ENOMEM, if message can not fit in provided buf. + * -EAGAIN, if not whole message is ready yet. + */ +int pbuf_read(struct pbuf *pb, char *buf, uint16_t len); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_IPC_PBUF_H_ */ diff --git a/subsys/ipc/ipc_service/lib/CMakeLists.txt b/subsys/ipc/ipc_service/lib/CMakeLists.txt index 97148185954a421..a560489be7261d7 100644 --- a/subsys/ipc/ipc_service/lib/CMakeLists.txt +++ b/subsys/ipc/ipc_service/lib/CMakeLists.txt @@ -4,3 +4,4 @@ zephyr_sources_ifdef(CONFIG_IPC_SERVICE_ICMSG icmsg.c) zephyr_sources_ifdef(CONFIG_IPC_SERVICE_ICMSG_ME icmsg_me.c) zephyr_sources_ifdef(CONFIG_IPC_SERVICE_RPMSG ipc_rpmsg.c) zephyr_sources_ifdef(CONFIG_IPC_SERVICE_STATIC_VRINGS ipc_static_vrings.c) +zephyr_sources_ifdef(CONFIG_PBUF pbuf.c) diff --git a/subsys/ipc/ipc_service/lib/Kconfig.icmsg b/subsys/ipc/ipc_service/lib/Kconfig.icmsg index 8f1a380a18f3692..39b8c8d0c75b838 100644 --- a/subsys/ipc/ipc_service/lib/Kconfig.icmsg +++ b/subsys/ipc/ipc_service/lib/Kconfig.icmsg @@ -70,3 +70,11 @@ endif # at a cooperative priority. config SYSTEM_WORKQUEUE_PRIORITY range -256 -1 if !IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE + +config PBUF + bool "Packed buffer support library" + 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. diff --git a/subsys/ipc/ipc_service/lib/pbuf.c b/subsys/ipc/ipc_service/lib/pbuf.c new file mode 100644 index 000000000000000..1164f814ca0820c --- /dev/null +++ b/subsys/ipc/ipc_service/lib/pbuf.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +/* Helper funciton for getting numer of bytes being written to the bufer. */ +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; +} + +int pbuf_init(struct pbuf *pb) +{ + if (validate_cfg(pb->cfg) != 0) { + return -EINVAL; + } + + /* 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_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; +} From 25a0489d62bfe16975ffff7d31adf31ac3a85a06 Mon Sep 17 00:00:00 2001 From: Emil Obalski Date: Wed, 9 Aug 2023 16:58:33 +0200 Subject: [PATCH 0084/1049] tests: ipc: Add pbuf unit tests Add unit tests for packed buffer. Signed-off-by: Emil Obalski --- tests/subsys/ipc/pbuf/CMakeLists.txt | 8 + tests/subsys/ipc/pbuf/prj.conf | 7 + tests/subsys/ipc/pbuf/src/main.c | 294 +++++++++++++++++++++++++++ tests/subsys/ipc/pbuf/testcase.yaml | 5 + 4 files changed, 314 insertions(+) create mode 100644 tests/subsys/ipc/pbuf/CMakeLists.txt create mode 100644 tests/subsys/ipc/pbuf/prj.conf create mode 100644 tests/subsys/ipc/pbuf/src/main.c create mode 100644 tests/subsys/ipc/pbuf/testcase.yaml diff --git a/tests/subsys/ipc/pbuf/CMakeLists.txt b/tests/subsys/ipc/pbuf/CMakeLists.txt new file mode 100644 index 000000000000000..9d12b21862b1b05 --- /dev/null +++ b/tests/subsys/ipc/pbuf/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ipc_pbuf) + +FILE(GLOB app_sources src/main.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/ipc/pbuf/prj.conf b/tests/subsys/ipc/pbuf/prj.conf new file mode 100644 index 000000000000000..8580c4f26a5254f --- /dev/null +++ b/tests/subsys/ipc/pbuf/prj.conf @@ -0,0 +1,7 @@ +CONFIG_ZTEST=y +CONFIG_ZTRESS=y +CONFIG_ZTEST_SHUFFLE=y + +CONFIG_IPC_SERVICE=y +CONFIG_IPC_SERVICE_ICMSG=y +CONFIG_PBUF=y diff --git a/tests/subsys/ipc/pbuf/src/main.c b/tests/subsys/ipc/pbuf/src/main.c new file mode 100644 index 000000000000000..7a20fc9bdd6c9ab --- /dev/null +++ b/tests/subsys/ipc/pbuf/src/main.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + + +#define MEM_AREA_SZ 256 +#define MPS 240 +#define MSGA_SZ 11 +#define MSGB_SZ 25 + +static char memory_area[MEM_AREA_SZ] __aligned(32); + +static void print_pbuf_info(struct pbuf *pb) +{ + printk("----------stats start-----------\n"); + printk("cfg->rd_idx_loc: %p, val: %u\n", pb->cfg->rd_idx_loc, *(pb->cfg->rd_idx_loc)); + printk("cfg->wr_idx_loc: %p, val: %u\n", pb->cfg->wr_idx_loc, *(pb->cfg->wr_idx_loc)); + printk("cfg->data_loc: %p\n", pb->cfg->data_loc); + printk("cfg->len: %u\n", pb->cfg->len); + printk("cfg->dcache_alignment: %u\n", pb->cfg->dcache_alignment); + + printk("data.rd_idx: %u\n", pb->data.rd_idx); + printk("data.wr_idx: %u\n", pb->data.wr_idx); + printk("-----------stats end------------\n"); +} + +/* Read/write tests. */ +ZTEST(test_pbuf, test_rw) +{ + uint8_t read_buf[MEM_AREA_SZ] = {0}; + uint8_t write_buf[MEM_AREA_SZ]; + int ret; + + BUILD_ASSERT(MSGA_SZ < MEM_AREA_SZ); + BUILD_ASSERT(MSGB_SZ < MEM_AREA_SZ); + BUILD_ASSERT(MPS < MEM_AREA_SZ); + + /* TODO: Use PBUF_DEFINE(). + * The user should use PBUF_DEFINE() macro to define the buffer, + * however for the purpose of this test PBUF_CFG_INIT() is used in + * order to avoid clang complains about memory_area not being constant + * expression. + */ + static const struct pbuf_cfg cfg = PBUF_CFG_INIT(memory_area, MEM_AREA_SZ, 0); + + static struct pbuf pb = { + .cfg = &cfg, + }; + + for (size_t i = 0; i < MEM_AREA_SZ; i++) { + write_buf[i] = i+1; + } + + zassert_equal(pbuf_init(&pb), 0); + + /* Write MSGA_SZ bytes packet. */ + ret = pbuf_write(&pb, write_buf, MSGA_SZ); + zassert_equal(ret, MSGA_SZ); + + /* Write MSGB_SZ bytes packet. */ + ret = pbuf_write(&pb, write_buf+MSGA_SZ, MSGB_SZ); + zassert_equal(ret, MSGB_SZ); + + /* Get the number of bytes stored. */ + ret = pbuf_read(&pb, NULL, 0); + zassert_equal(ret, MSGA_SZ); + /* Attempt to read with too small read buffer. */ + ret = pbuf_read(&pb, read_buf, ret-1); + zassert_equal(ret, -ENOMEM); + /* Read the packet. */ + ret = pbuf_read(&pb, read_buf, ret); + zassert_equal(ret, MSGA_SZ); + /* Check data corectness. */ + zassert_mem_equal(read_buf, write_buf, ret); + + /* Get the number of bytes stored. */ + ret = pbuf_read(&pb, NULL, 0); + zassert_equal(ret, MSGB_SZ); + /* Read the packet. */ + ret = pbuf_read(&pb, read_buf, ret); + zassert_equal(ret, MSGB_SZ); + /* Check data corectness. */ + zassert_mem_equal(read_buf, write_buf+MSGA_SZ, ret); + + /* Get the number of bytes stored. */ + ret = pbuf_read(&pb, NULL, 0); + zassert_equal(ret, 0); + + /* Write max packet size with wrapping around. */ + ret = pbuf_write(&pb, write_buf, MPS); + zassert_equal(ret, MPS); + /* Get the number of bytes stored. */ + ret = pbuf_read(&pb, NULL, 0); + zassert_equal(ret, MPS); + /* Read max packet size with wrapp around. */ + ret = pbuf_read(&pb, read_buf, ret); + zassert_equal(ret, MPS); + /* Check data corectness. */ + zassert_mem_equal(write_buf, read_buf, MPS); +} + +/* API ret codes tests. */ +ZTEST(test_pbuf, test_retcodes) +{ + /* TODO: Use PBUF_DEFINE(). + * The user should use PBUF_DEFINE() macro to define the buffer, + * however for the purpose of this test PBUF_CFG_INIT() is used in + * order to avoid clang complains about memory_area not being constant + * expression. + */ + static const struct pbuf_cfg cfg0 = PBUF_CFG_INIT(memory_area, MEM_AREA_SZ, 32); + static const struct pbuf_cfg cfg1 = PBUF_CFG_INIT(memory_area, MEM_AREA_SZ, 0); + static const struct pbuf_cfg cfg2 = PBUF_CFG_INIT(memory_area, 20, 4); + + static struct pbuf pb0 = { + .cfg = &cfg0, + }; + + static struct pbuf pb1 = { + .cfg = &cfg1, + }; + + static struct pbuf pb2 = { + .cfg = &cfg2, + }; + + /* Initialize buffers. */ + zassert_equal(pbuf_init(&pb0), 0); + zassert_equal(pbuf_init(&pb1), 0); + zassert_equal(pbuf_init(&pb2), 0); + + print_pbuf_info(&pb0); + print_pbuf_info(&pb1); + print_pbuf_info(&pb2); + + uint8_t read_buf[MEM_AREA_SZ]; + uint8_t write_buf[MEM_AREA_SZ]; + + for (size_t i = 0; i < MEM_AREA_SZ; i++) { + write_buf[i] = i+1; + } + + /* pbuf_write incorrect params tests. */ + zassert_equal(pbuf_write(NULL, write_buf, 10), -EINVAL); + zassert_equal(pbuf_write(&pb2, NULL, 10), -EINVAL); + zassert_equal(pbuf_write(&pb2, write_buf, 0), -EINVAL); + zassert_equal(pbuf_read(NULL, read_buf, 10), -EINVAL); + + /* Attempt to write more than the buffer can fit. */ + zassert_equal(pbuf_write(&pb2, write_buf, 5), -ENOMEM); + + /* Write maximal amount, the buffer fit. */ + zassert_equal(pbuf_write(&pb2, write_buf, 4), 4); + + /* Attempt to write to full buffer. */ + zassert_equal(pbuf_write(&pb2, write_buf, 1), -ENOMEM); + + /* Get the bytes stored. */ + zassert_equal(pbuf_read(&pb2, NULL, 1), 4); + + /* Attempt to read with too small read buffer. */ + zassert_equal(pbuf_read(&pb2, read_buf, 1), -ENOMEM); + + /* Get the bytes stored. */ + zassert_equal(pbuf_read(&pb2, NULL, 0), 4); + + /* Read the data with correct buffer size. */ + zassert_equal(pbuf_read(&pb2, read_buf, 4), 4); + + /* Check data correctness. */ + zassert_mem_equal(read_buf, write_buf, 4); + + /* Read from empty buffer. */ + zassert_equal(pbuf_read(&pb2, read_buf, 10), 0); + zassert_equal(pbuf_read(&pb2, read_buf, 10), 0); + zassert_equal(pbuf_read(&pb2, read_buf, 10), 0); +} + +#define STRESS_LEN_MOD (44) +#define STRESS_LEN_MIN (20) +#define STRESS_LEN_MAX (STRESS_LEN_MIN + STRESS_LEN_MOD) + +struct stress_data { + struct pbuf *pbuf; + uint32_t wr_cnt; + uint32_t rd_cnt; + uint32_t wr_err; +}; + +/* Check if buffer of len contains exp values. */ +static int check_buffer(char *buf, uint16_t len, char exp) +{ + for (uint16_t i = 0; i < len; i++) { + if (buf[i] != exp) { + return -EINVAL; + } + } + + return 0; +} + +bool stress_read(void *user_data, uint32_t cnt, bool last, int prio) +{ + struct stress_data *ctx = (struct stress_data *)user_data; + char buf[STRESS_LEN_MAX]; + int len; + int rpt = (sys_rand32_get() & 3) + 1; + + for (int i = 0; i < rpt; i++) { + len = pbuf_read(ctx->pbuf, buf, (uint16_t)sizeof(buf)); + if (len == 0) { + return true; + } + + if (len < 0) { + zassert_true(false, "Unexpected error: %d, cnt:%d", len, ctx->rd_cnt); + } + + zassert_ok(check_buffer(buf, len, ctx->rd_cnt)); + ctx->rd_cnt++; + } + + return true; +} + +bool stress_write(void *user_data, uint32_t cnt, bool last, int prio) +{ + struct stress_data *ctx = (struct stress_data *)user_data; + char buf[STRESS_LEN_MAX]; + + uint16_t len = STRESS_LEN_MIN + (sys_rand32_get() % STRESS_LEN_MOD); + int rpt = (sys_rand32_get() & 1) + 1; + + zassert_true(len < sizeof(buf)); + + for (int i = 0; i < rpt; i++) { + memset(buf, (uint8_t)ctx->wr_cnt, len); + int ret = pbuf_write(ctx->pbuf, buf, len); + + if (ret == len) { + ctx->wr_cnt++; + } else if (ret == -ENOMEM) { + ctx->wr_err++; + } else { + zassert_unreachable(); + } + } + + return true; +} + +ZTEST(test_pbuf, test_stress) +{ + static uint8_t buffer[MEM_AREA_SZ] __aligned(32); + static struct stress_data ctx = {}; + uint32_t repeat = 0; + + /* TODO: Use PBUF_DEFINE(). + * The user should use PBUF_DEFINE() macro to define the buffer, + * however for the purpose of this test PBUF_CFG_INIT() is used in + * order to avoid clang complains about buffer not being constant + * expression. + */ + static const struct pbuf_cfg cfg = PBUF_CFG_INIT(buffer, MEM_AREA_SZ, 4); + + static struct pbuf pb = { + .cfg = &cfg, + }; + + zassert_equal(pbuf_init(&pb), 0); + ctx.pbuf = &pb; + ctx.wr_cnt = 0; + ctx.rd_cnt = 0; + + ztress_set_timeout(K_MSEC(1500)); + TC_PRINT("Reading from an interrupt, writing from a thread\n"); + ZTRESS_EXECUTE(ZTRESS_TIMER(stress_read, &ctx, repeat, Z_TIMEOUT_TICKS(4)), + ZTRESS_THREAD(stress_write, &ctx, repeat, 2000, Z_TIMEOUT_TICKS(4))); + TC_PRINT("Writes:%d unsuccessful: %d\n", ctx.wr_cnt, ctx.wr_err); + + TC_PRINT("Writing from an interrupt, reading from a thread\n"); + ZTRESS_EXECUTE(ZTRESS_TIMER(stress_write, &ctx, repeat, Z_TIMEOUT_TICKS(4)), + ZTRESS_THREAD(stress_read, &ctx, repeat, 1000, Z_TIMEOUT_TICKS(4))); + TC_PRINT("Writes:%d unsuccessful: %d\n", ctx.wr_cnt, ctx.wr_err); +} + +ZTEST_SUITE(test_pbuf, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/ipc/pbuf/testcase.yaml b/tests/subsys/ipc/pbuf/testcase.yaml new file mode 100644 index 000000000000000..4113335403ae4d1 --- /dev/null +++ b/tests/subsys/ipc/pbuf/testcase.yaml @@ -0,0 +1,5 @@ +tests: + ipc.icmsg_pbuf: + integration_platforms: + - native_posix + timeout: 120 From eb4fc3f0838541512f84febceeab8712f5f7fbc2 Mon Sep 17 00:00:00 2001 From: Emil Obalski Date: Tue, 24 Oct 2023 12:24:49 +0200 Subject: [PATCH 0085/1049] ipc: backends: Port IcMsg based backends to use pbuf Replace spsc_pbuf with pbuf implementation dedicated to be used by IcMsg based backends. The pbuf is written on top of simple read/write semantics with minimal footprint and code complexity Signed-off-by: Emil Obalski --- dts/bindings/ipc/zephyr,ipc-icmsg.yaml | 13 + include/zephyr/ipc/icmsg.h | 17 +- subsys/ipc/ipc_service/backends/ipc_icmsg.c | 48 +-- .../backends/ipc_icmsg_me_follower.c | 26 +- .../backends/ipc_icmsg_me_initiator.c | 26 +- subsys/ipc/ipc_service/lib/Kconfig | 3 +- subsys/ipc/ipc_service/lib/icmsg.c | 276 ++---------------- 7 files changed, 105 insertions(+), 304 deletions(-) diff --git a/dts/bindings/ipc/zephyr,ipc-icmsg.yaml b/dts/bindings/ipc/zephyr,ipc-icmsg.yaml index b67c9072980fc0e..417930053734df7 100644 --- a/dts/bindings/ipc/zephyr,ipc-icmsg.yaml +++ b/dts/bindings/ipc/zephyr,ipc-icmsg.yaml @@ -21,6 +21,19 @@ properties: required: true type: phandle + dcache-alignment: + type: int + description: | + Data cache alignment. If any side of the communication uses cache on + rx-region/tx-region this property must be the biggest value of the + invalidation or the write-back size for both sides of the communication. + If no side of the communication uses data cache this property could be + safely omitted. + For example: + Side A: no data cache + Side B: 32 Bytes write-back size, 16 Bytes invalidation size + dcache-alignment = 32; for both + mboxes: description: phandle to the MBOX controller (TX and RX are required) required: true diff --git a/include/zephyr/ipc/icmsg.h b/include/zephyr/ipc/icmsg.h index 099c6265acd5272..a3b43690cc4be5a 100644 --- a/include/zephyr/ipc/icmsg.h +++ b/include/zephyr/ipc/icmsg.h @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #ifdef __cplusplus extern "C" { @@ -33,19 +33,14 @@ enum icmsg_state { }; struct icmsg_config_t { - uintptr_t tx_shm_addr; - uintptr_t rx_shm_addr; - size_t tx_shm_size; - size_t rx_shm_size; struct mbox_channel mbox_tx; struct mbox_channel mbox_rx; }; struct icmsg_data_t { /* Tx/Rx buffers. */ - struct spsc_pbuf *tx_ib; - struct spsc_pbuf *rx_ib; - atomic_t tx_buffer_state; + struct pbuf *tx_pb; + struct pbuf *rx_pb; #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC struct k_mutex tx_lock; #endif @@ -59,12 +54,6 @@ struct icmsg_data_t { struct k_work_delayable notify_work; struct k_work mbox_work; atomic_t state; - /* No-copy */ -#ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX - atomic_t rx_buffer_state; - const void *rx_buffer; - uint16_t rx_len; -#endif }; /** @brief Open an icmsg instance diff --git a/subsys/ipc/ipc_service/backends/ipc_icmsg.c b/subsys/ipc/ipc_service/backends/ipc_icmsg.c index eca84f3275c34da..28b94b861e34f08 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg.c @@ -54,27 +54,33 @@ static int backend_init(const struct device *instance) return 0; } -#define DEFINE_BACKEND_DEVICE(i) \ - static const struct icmsg_config_t backend_config_##i = { \ - .tx_shm_size = DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)), \ - .tx_shm_addr = DT_REG_ADDR(DT_INST_PHANDLE(i, tx_region)), \ - .rx_shm_size = DT_REG_SIZE(DT_INST_PHANDLE(i, rx_region)), \ - .rx_shm_addr = DT_REG_ADDR(DT_INST_PHANDLE(i, rx_region)), \ - .mbox_tx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(i), tx), \ - .mbox_rx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(i), rx), \ - }; \ - \ - BUILD_ASSERT(DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)) > \ - sizeof(struct spsc_pbuf)); \ - static struct icmsg_data_t backend_data_##i; \ - \ - DEVICE_DT_INST_DEFINE(i, \ - &backend_init, \ - NULL, \ - &backend_data_##i, \ - &backend_config_##i, \ - POST_KERNEL, \ - CONFIG_IPC_SERVICE_REG_BACKEND_PRIORITY, \ +#define DEFINE_BACKEND_DEVICE(i) \ + static const struct icmsg_config_t backend_config_##i = { \ + .mbox_tx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(i), tx), \ + .mbox_rx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(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/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c index 8b0944c840f9b8c..5492da0a3026af1 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c @@ -277,16 +277,28 @@ static int backend_init(const struct device *instance) } #define DEFINE_BACKEND_DEVICE(i) \ - static const struct icmsg_config_t backend_config_##i = \ - { \ - .tx_shm_size = DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)), \ - .tx_shm_addr = DT_REG_ADDR(DT_INST_PHANDLE(i, tx_region)), \ - .rx_shm_size = DT_REG_SIZE(DT_INST_PHANDLE(i, rx_region)), \ - .rx_shm_addr = DT_REG_ADDR(DT_INST_PHANDLE(i, rx_region)), \ + static const struct icmsg_config_t backend_config_##i = { \ .mbox_tx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(i), tx), \ .mbox_rx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(i), rx), \ }; \ - static struct backend_data_t backend_data_##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)); \ + 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 backend_data_t backend_data_##i = { \ + .icmsg_me_data = { \ + .icmsg_data = { \ + .tx_pb = &tx_pb_##i, \ + .rx_pb = &rx_pb_##i, \ + } \ + } \ + }; \ \ DEVICE_DT_INST_DEFINE(i, \ &backend_init, \ 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 2699d3b6db66feb..2d537dc84a25a67 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c @@ -183,16 +183,28 @@ static int backend_init(const struct device *instance) } #define DEFINE_BACKEND_DEVICE(i) \ - static const struct icmsg_config_t backend_config_##i = \ - { \ - .tx_shm_size = DT_REG_SIZE(DT_INST_PHANDLE(i, tx_region)), \ - .tx_shm_addr = DT_REG_ADDR(DT_INST_PHANDLE(i, tx_region)), \ - .rx_shm_size = DT_REG_SIZE(DT_INST_PHANDLE(i, rx_region)), \ - .rx_shm_addr = DT_REG_ADDR(DT_INST_PHANDLE(i, rx_region)), \ + static const struct icmsg_config_t backend_config_##i = { \ .mbox_tx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(i), tx), \ .mbox_rx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(i), rx), \ }; \ - static struct backend_data_t backend_data_##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)); \ + 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 backend_data_t backend_data_##i = { \ + .icmsg_me_data = { \ + .icmsg_data = { \ + .tx_pb = &tx_pb_##i, \ + .rx_pb = &rx_pb_##i, \ + } \ + } \ + }; \ \ DEVICE_DT_INST_DEFINE(i, \ &backend_init, \ diff --git a/subsys/ipc/ipc_service/lib/Kconfig b/subsys/ipc/ipc_service/lib/Kconfig index 6bd57ab15aa67a3..0fbc82ddc13f14e 100644 --- a/subsys/ipc/ipc_service/lib/Kconfig +++ b/subsys/ipc/ipc_service/lib/Kconfig @@ -21,8 +21,7 @@ config IPC_SERVICE_STATIC_VRINGS_MEM_ALIGNMENT menuconfig IPC_SERVICE_ICMSG bool "icmsg IPC library" - select SPSC_PBUF - select SPSC_PBUF_USE_CACHE + select PBUF help Icmsg library diff --git a/subsys/ipc/ipc_service/lib/icmsg.c b/subsys/ipc/ipc_service/lib/icmsg.c index 9d238f193514e74..5d93686eed94b78 100644 --- a/subsys/ipc/ipc_service/lib/icmsg.c +++ b/subsys/ipc/ipc_service/lib/icmsg.c @@ -9,22 +9,12 @@ #include #include #include -#include +#include #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) -enum rx_buffer_state { - RX_BUFFER_STATE_RELEASED, - RX_BUFFER_STATE_RELEASING, - RX_BUFFER_STATE_HELD -}; - -enum tx_buffer_state { - TX_BUFFER_STATE_UNUSED, - TX_BUFFER_STATE_RESERVED -}; static const uint8_t magic[] = {0x45, 0x6d, 0x31, 0x6c, 0x31, 0x4b, 0x30, 0x72, 0x6e, 0x33, 0x6c, 0x69, 0x34}; @@ -82,12 +72,6 @@ static bool is_endpoint_ready(struct icmsg_data_t *dev_data) return atomic_get(&dev_data->state) == ICMSG_STATE_READY; } -static bool is_tx_buffer_reserved(struct icmsg_data_t *dev_data) -{ - return atomic_get(&dev_data->tx_buffer_state) == - TX_BUFFER_STATE_RESERVED; -} - static int reserve_tx_buffer_if_unused(struct icmsg_data_t *dev_data) { #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC @@ -97,52 +81,20 @@ static int reserve_tx_buffer_if_unused(struct icmsg_data_t *dev_data) return ret; } #endif - - bool was_unused = atomic_cas(&dev_data->tx_buffer_state, - TX_BUFFER_STATE_UNUSED, TX_BUFFER_STATE_RESERVED); - - return was_unused ? 0 : -EALREADY; + return 0; } static int release_tx_buffer(struct icmsg_data_t *dev_data) { - bool was_reserved = atomic_cas(&dev_data->tx_buffer_state, - TX_BUFFER_STATE_RESERVED, TX_BUFFER_STATE_UNUSED); - - if (!was_reserved) { - return -EALREADY; - } - #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC return k_mutex_unlock(&dev_data->tx_lock); -#else - return 0; -#endif -} - -static bool is_rx_buffer_free(struct icmsg_data_t *dev_data) -{ -#ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX - return atomic_get(&dev_data->rx_buffer_state) == RX_BUFFER_STATE_RELEASED; -#else - return true; -#endif -} - -static bool is_rx_buffer_held(struct icmsg_data_t *dev_data) -{ -#ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX - return atomic_get(&dev_data->rx_buffer_state) == RX_BUFFER_STATE_HELD; -#else - return false; #endif + return 0; } -static bool is_rx_data_available(struct icmsg_data_t *dev_data) +static uint32_t data_available(struct icmsg_data_t *dev_data) { - int len = spsc_pbuf_read(dev_data->rx_ib, NULL, 0); - - return len > 0; + return pbuf_read(dev_data->rx_pb, NULL, 0); } static void submit_mbox_work(struct icmsg_data_t *dev_data) @@ -157,20 +109,13 @@ static void submit_mbox_work(struct icmsg_data_t *dev_data) static void submit_work_if_buffer_free(struct icmsg_data_t *dev_data) { - if (!is_rx_buffer_free(dev_data)) { - return; - } - submit_mbox_work(dev_data); } static void submit_work_if_buffer_free_and_data_available( struct icmsg_data_t *dev_data) { - if (!is_rx_buffer_free(dev_data)) { - return; - } - if (!is_rx_data_available(dev_data)) { + if (!data_available(dev_data)) { return; } @@ -179,47 +124,31 @@ static void submit_work_if_buffer_free_and_data_available( static void mbox_callback_process(struct k_work *item) { - char *rx_buffer; struct icmsg_data_t *dev_data = CONTAINER_OF(item, struct icmsg_data_t, mbox_work); atomic_t state = atomic_get(&dev_data->state); - uint16_t len = spsc_pbuf_claim(dev_data->rx_ib, &rx_buffer); + uint32_t len = data_available(dev_data); if (len == 0) { /* Unlikely, no data in buffer. */ return; } + uint8_t rx_buffer[len]; + + len = pbuf_read(dev_data->rx_pb, rx_buffer, len); + if (state == ICMSG_STATE_READY) { if (dev_data->cb->received) { -#if CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX - dev_data->rx_buffer = rx_buffer; - dev_data->rx_len = len; -#endif - dev_data->cb->received(rx_buffer, len, dev_data->ctx); - - /* Release Rx buffer here only in case when user did not request - * to hold it. - */ - if (!is_rx_buffer_held(dev_data)) { - spsc_pbuf_free(dev_data->rx_ib, len); - -#if CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX - dev_data->rx_buffer = NULL; - dev_data->rx_len = 0; -#endif - } } } else { __ASSERT_NO_MSG(state == ICMSG_STATE_BUSY); bool endpoint_invalid = (len != sizeof(magic) || memcmp(magic, rx_buffer, len)); - spsc_pbuf_free(dev_data->rx_ib, len); - if (endpoint_invalid) { __ASSERT_NO_MSG(false); return; @@ -262,8 +191,6 @@ int icmsg_open(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const struct ipc_service_cb *cb, void *ctx) { - __ASSERT_NO_MSG(conf->tx_shm_size > sizeof(struct spsc_pbuf)); - if (!atomic_cas(&dev_data->state, ICMSG_STATE_OFF, ICMSG_STATE_BUSY)) { /* Already opened. */ return -EALREADY; @@ -277,12 +204,18 @@ int icmsg_open(const struct icmsg_config_t *conf, k_mutex_init(&dev_data->tx_lock); #endif - dev_data->tx_ib = spsc_pbuf_init((void *)conf->tx_shm_addr, - conf->tx_shm_size, - SPSC_PBUF_CACHE); - dev_data->rx_ib = (void *)conf->rx_shm_addr; + int ret = pbuf_init(dev_data->tx_pb); - int ret = spsc_pbuf_write(dev_data->tx_ib, magic, sizeof(magic)); + if (ret < 0) { + __ASSERT(false, "Incorrect configuration"); + return ret; + } + + /* Initialize local copies of rx_pb. */ + dev_data->rx_pb->data.wr_idx = 0; + dev_data->rx_pb->data.rd_idx = 0; + + ret = pbuf_write(dev_data->tx_pb, magic, sizeof(magic)); if (ret < 0) { __ASSERT_NO_MSG(false); @@ -345,7 +278,7 @@ int icmsg_send(const struct icmsg_config_t *conf, return -ENOBUFS; } - write_ret = spsc_pbuf_write(dev_data->tx_ib, msg, len); + write_ret = pbuf_write(dev_data->tx_pb, msg, len); release_ret = release_tx_buffer(dev_data); __ASSERT_NO_MSG(!release_ret); @@ -366,169 +299,6 @@ int icmsg_send(const struct icmsg_config_t *conf, return sent_bytes; } -int icmsg_get_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - void **data, size_t *size) -{ - int ret; - int release_ret; - uint16_t requested_size; - int allocated_len; - char *allocated_buf; - - if (*size == 0) { - /* Requested allocation of maximal size. - * Try to allocate maximal buffer size from spsc, - * potentially after wrapping marker. - */ - requested_size = SPSC_PBUF_MAX_LEN - 1; - } else { - requested_size = *size; - } - - ret = reserve_tx_buffer_if_unused(dev_data); - if (ret < 0) { - return -ENOBUFS; - } - - ret = spsc_pbuf_alloc(dev_data->tx_ib, requested_size, &allocated_buf); - if (ret < 0) { - release_ret = release_tx_buffer(dev_data); - __ASSERT_NO_MSG(!release_ret); - return ret; - } - allocated_len = ret; - - if (*size == 0) { - /* Requested allocation of maximal size. - * Pass the buffer that was allocated. - */ - *size = allocated_len; - *data = allocated_buf; - return 0; - } - - if (*size == allocated_len) { - /* Allocated buffer is of requested size. */ - *data = allocated_buf; - return 0; - } - - /* Allocated smaller buffer than requested. - * Silently stop using the allocated buffer what is allowed by SPSC API - */ - release_tx_buffer(dev_data); - *size = allocated_len; - return -ENOMEM; -} - -int icmsg_drop_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *data) -{ - /* Silently stop using the allocated buffer what is allowed by SPSC API - */ - return release_tx_buffer(dev_data); -} - -int icmsg_send_nocopy(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *msg, size_t len) -{ - int ret; - int sent_bytes; - - if (!is_endpoint_ready(dev_data)) { - return -EBUSY; - } - - /* Empty message is not allowed */ - if (len == 0) { - return -ENODATA; - } - - if (!is_tx_buffer_reserved(dev_data)) { - return -ENXIO; - } - - spsc_pbuf_commit(dev_data->tx_ib, len); - sent_bytes = len; - - ret = release_tx_buffer(dev_data); - __ASSERT_NO_MSG(!ret); - - __ASSERT_NO_MSG(conf->mbox_tx.dev != NULL); - - ret = mbox_send(&conf->mbox_tx, NULL); - if (ret) { - return ret; - } - - return sent_bytes; -} - -#ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX -int icmsg_hold_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *data) -{ - bool was_released; - - if (!is_endpoint_ready(dev_data)) { - return -EBUSY; - } - - if (data != dev_data->rx_buffer) { - return -EINVAL; - } - - was_released = atomic_cas(&dev_data->rx_buffer_state, - RX_BUFFER_STATE_RELEASED, RX_BUFFER_STATE_HELD); - if (!was_released) { - return -EALREADY; - } - - return 0; -} - -int icmsg_release_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *data) -{ - bool was_held; - - if (!is_endpoint_ready(dev_data)) { - return -EBUSY; - } - - if (data != dev_data->rx_buffer) { - return -EINVAL; - } - - /* Do not schedule new packet processing until buffer will be released. - * Protect buffer against being freed multiple times. - */ - was_held = atomic_cas(&dev_data->rx_buffer_state, - RX_BUFFER_STATE_HELD, RX_BUFFER_STATE_RELEASING); - if (!was_held) { - return -EALREADY; - } - - spsc_pbuf_free(dev_data->rx_ib, dev_data->rx_len); - -#if CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX - dev_data->rx_buffer = NULL; - dev_data->rx_len = 0; -#endif - - atomic_set(&dev_data->rx_buffer_state, RX_BUFFER_STATE_RELEASED); - - submit_work_if_buffer_free_and_data_available(dev_data); - - return 0; -} -#endif /* CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX */ - #if IS_ENABLED(CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE) static int work_q_init(void) From d769a925201f58e13763ccbf400670190cbfee85 Mon Sep 17 00:00:00 2001 From: Emil Obalski Date: Thu, 2 Nov 2023 15:24:14 +0100 Subject: [PATCH 0086/1049] ipc: icmsg: Allow to support future versions Allow magic number to be longer than the sizeof(magic). This will allow to support future versions of the icmsg with backwards compatibility. Signed-off-by: Emil Obalski --- subsys/ipc/ipc_service/lib/icmsg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/ipc/ipc_service/lib/icmsg.c b/subsys/ipc/ipc_service/lib/icmsg.c index 5d93686eed94b78..52e2dd10f1b801d 100644 --- a/subsys/ipc/ipc_service/lib/icmsg.c +++ b/subsys/ipc/ipc_service/lib/icmsg.c @@ -147,7 +147,9 @@ static void mbox_callback_process(struct k_work *item) } else { __ASSERT_NO_MSG(state == ICMSG_STATE_BUSY); - bool endpoint_invalid = (len != sizeof(magic) || memcmp(magic, rx_buffer, len)); + /* 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); From c4ffadb0b61fb4c7e5d0cdb517bbd21ca6791484 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Fri, 3 Nov 2023 15:54:46 +0200 Subject: [PATCH 0087/1049] arch: arm64: avoid invalidating of RO mem after mem map The Cortex ARM documentation states that the DC IVAC instruction requires write access permission to the virtual address (VA); otherwise, it may generate a permission fault. Therefore, it is needed to avoid invalidating read-only memory after the memory map operation. This issue has been produced by commit c9b534c. This commit resolves the issue #64758. Signed-off-by: Mykola Kvach --- arch/arm64/core/mmu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/core/mmu.c b/arch/arm64/core/mmu.c index 7d5670da0f238fe..2260d22c101f73d 100644 --- a/arch/arm64/core/mmu.c +++ b/arch/arm64/core/mmu.c @@ -731,6 +731,14 @@ static inline void add_arm_mmu_region(struct arm_mmu_ptables *ptables, static inline void inv_dcache_after_map_helper(void *virt, size_t size, uint32_t attrs) { + /* + * DC IVAC instruction requires write access permission to the VA, + * otherwise it can generate a permission fault + */ + if ((attrs & MT_RW) != MT_RW) { + return; + } + if (MT_TYPE(attrs) == MT_NORMAL || MT_TYPE(attrs) == MT_NORMAL_WT) { sys_cache_data_invd_range(virt, size); } @@ -987,6 +995,7 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) case K_MEM_CACHE_WB: case K_MEM_CACHE_WT: mem_flags = (mem_flags == K_MEM_CACHE_WB) ? MT_NORMAL : MT_NORMAL_WT; + mem_flags |= (flags & K_MEM_PERM_RW) ? MT_RW : 0; inv_dcache_after_map_helper(virt, size, mem_flags); default: break; From 4e5868faaf9d5cbe1796e06b915f417a8b3aab0f Mon Sep 17 00:00:00 2001 From: Corey Wharton Date: Wed, 20 Sep 2023 15:19:29 -0700 Subject: [PATCH 0088/1049] arch: arm: cortex-m: support custom interrupt controllers This change adds support for the CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER option on Cortex-M platforms. While all Cortex-M platforms have a NVIC controller some custom SoCs may have additional IRQ controllers or custom handling. This change allows those SoCs to modify this bahaviour without having to place platform specific logic inside applications or drivers. Signed-off-by: Corey Wharton --- arch/arm/Kconfig | 12 ++++++------ arch/arm/core/cortex_m/CMakeLists.txt | 2 +- arch/arm/core/cortex_m/irq_manage.c | 4 ++++ arch/arm/core/cortex_m/isr_wrapper.S | 16 ++++++++++++++++ arch/arm/core/cortex_m/prep_c.c | 5 +++++ 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3f775e4d6389095..8b0d53ec3cf2031 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -16,23 +16,23 @@ config CPU_CORTEX config ARM_CUSTOM_INTERRUPT_CONTROLLER bool - depends on !CPU_CORTEX_M help This option indicates that the ARM CPU is connected to a custom (i.e. - non-GIC) interrupt controller. + non-GIC or NVIC) interrupt controller. A number of Cortex-A and Cortex-R cores (Cortex-A5, Cortex-R4/5, ...) allow interfacing to a custom external interrupt controller and this option must be selected when such cores are connected to an interrupt - controller that is not the ARM Generic Interrupt Controller (GIC). + controller that is not the ARM Generic Interrupt Controller (GIC) or + the Cortex-M ARM Nested Vectored Interrupt Controller (NVIC). When this option is selected, the architecture interrupt control functions are mapped to the SoC interrupt control interface, which is implemented at the SoC level. - N.B. This option is only applicable to the Cortex-A and Cortex-R - family cores. The Cortex-M family cores are always equipped with - the ARM Nested Vectored Interrupt Controller (NVIC). + N.B. Since all Cortex-M cores have a NVIC, if this option is selected it + is assumed that the custom interrupt control interface implementation + assumes responsibility for handling the NVIC. config CODE_DATA_RELOCATION_SRAM bool "Relocate code/data sections to SRAM" diff --git a/arch/arm/core/cortex_m/CMakeLists.txt b/arch/arm/core/cortex_m/CMakeLists.txt index 7ec2441f12f010e..225d7111bdc9ff4 100644 --- a/arch/arm/core/cortex_m/CMakeLists.txt +++ b/arch/arm/core/cortex_m/CMakeLists.txt @@ -7,7 +7,6 @@ zephyr_library_sources( fault.c fault_s.S fpu.c - irq_init.c reset.S scb.c thread_abort.c @@ -20,6 +19,7 @@ zephyr_library_sources( cpu_idle.S ) +zephyr_library_sources_ifndef(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER irq_init.c) zephyr_library_sources_ifdef(CONFIG_GEN_SW_ISR_TABLE isr_wrapper.S) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S) diff --git a/arch/arm/core/cortex_m/irq_manage.c b/arch/arm/core/cortex_m/irq_manage.c index cd0c6f6e5bfb28b..3940d5246d4b5d2 100644 --- a/arch/arm/core/cortex_m/irq_manage.c +++ b/arch/arm/core/cortex_m/irq_manage.c @@ -32,6 +32,8 @@ extern void z_arm_reserved(void); #define REG_FROM_IRQ(irq) (irq / NUM_IRQS_PER_REG) #define BIT_FROM_IRQ(irq) (irq % NUM_IRQS_PER_REG) +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + void arch_irq_enable(unsigned int irq) { NVIC_EnableIRQ((IRQn_Type)irq); @@ -90,6 +92,8 @@ void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) NVIC_SetPriority((IRQn_Type)irq, prio); } +#endif /* !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) */ + void z_arm_fatal_error(unsigned int reason, const z_arch_esf_t *esf); /** diff --git a/arch/arm/core/cortex_m/isr_wrapper.S b/arch/arm/core/cortex_m/isr_wrapper.S index 78ad6cd1e83a778..f81b577804f53ba 100644 --- a/arch/arm/core/cortex_m/isr_wrapper.S +++ b/arch/arm/core/cortex_m/isr_wrapper.S @@ -97,13 +97,24 @@ _idle_state_cleared: #endif /* CONFIG_PM */ +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + bl z_soc_irq_get_active +#else mrs r0, IPSR /* get exception number */ +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) ldr r1, =16 subs r0, r1 /* get IRQ number */ +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + push {r0} +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ lsls r0, #3 /* table is 8-byte wide */ #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) sub r0, r0, #16 /* get IRQ number */ +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + push {r0} +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ lsl r0, r0, #3 /* table is 8-byte wide */ #else #error Unknown ARM architecture @@ -116,6 +127,11 @@ _idle_state_cleared: ldm r1!,{r0,r3} /* arg in r0, ISR in r3 */ blx r3 /* call ISR */ +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + pop {r0} + bl z_soc_irq_eoi +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + #ifdef CONFIG_TRACING_ISR bl sys_trace_isr_exit #endif diff --git a/arch/arm/core/cortex_m/prep_c.c b/arch/arm/core/cortex_m/prep_c.c index ad166775ca478d3..329f7f8987ddbf9 100644 --- a/arch/arm/core/cortex_m/prep_c.c +++ b/arch/arm/core/cortex_m/prep_c.c @@ -187,7 +187,12 @@ void z_arm_prep_c(void) #endif z_bss_zero(); z_data_copy(); +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + /* Invoke SoC-specific interrupt controller initialization */ + z_soc_irq_init(); +#else z_arm_interrupt_init(); +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ z_cstart(); CODE_UNREACHABLE; } From 0fdb50b8694f9ceac1af234a4c6e3ce2c2e723ec Mon Sep 17 00:00:00 2001 From: Corey Wharton Date: Wed, 20 Sep 2023 15:42:01 -0700 Subject: [PATCH 0089/1049] tests: arch: arm: add new test for custom interrupt control on Cortex-M Adds a new test for ARM Cortex-M architectures with the CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER option enabled. Signed-off-by: Corey Wharton --- .../arm/arm_custom_interrupt/CMakeLists.txt | 9 + tests/arch/arm/arm_custom_interrupt/Kconfig | 13 ++ .../arch/arm/arm_custom_interrupt/README.txt | 35 +++ tests/arch/arm/arm_custom_interrupt/prj.conf | 4 + .../src/arm_custom_interrupt.c | 209 ++++++++++++++++++ .../arch/arm/arm_custom_interrupt/src/main.c | 9 + .../arm/arm_custom_interrupt/testcase.yaml | 10 + 7 files changed, 289 insertions(+) create mode 100644 tests/arch/arm/arm_custom_interrupt/CMakeLists.txt create mode 100644 tests/arch/arm/arm_custom_interrupt/Kconfig create mode 100644 tests/arch/arm/arm_custom_interrupt/README.txt create mode 100644 tests/arch/arm/arm_custom_interrupt/prj.conf create mode 100644 tests/arch/arm/arm_custom_interrupt/src/arm_custom_interrupt.c create mode 100644 tests/arch/arm/arm_custom_interrupt/src/main.c create mode 100644 tests/arch/arm/arm_custom_interrupt/testcase.yaml diff --git a/tests/arch/arm/arm_custom_interrupt/CMakeLists.txt b/tests/arch/arm/arm_custom_interrupt/CMakeLists.txt new file mode 100644 index 000000000000000..04c0945156453eb --- /dev/null +++ b/tests/arch/arm/arm_custom_interrupt/CMakeLists.txt @@ -0,0 +1,9 @@ +#SPDX - License - Identifier : Apache - 2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(arm_interrupt) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/arch/arm/arm_custom_interrupt/Kconfig b/tests/arch/arm/arm_custom_interrupt/Kconfig new file mode 100644 index 000000000000000..73a87ef561bab00 --- /dev/null +++ b/tests/arch/arm/arm_custom_interrupt/Kconfig @@ -0,0 +1,13 @@ +# Private config options for test + +# Copyright Meta Platforms, Inc. and its affiliates. +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Custom interrupt test" + +source "Kconfig.zephyr" + +config ENABLE_CUSTOM_INTERRUPTS + bool + default y + select ARM_CUSTOM_INTERRUPT_CONTROLLER diff --git a/tests/arch/arm/arm_custom_interrupt/README.txt b/tests/arch/arm/arm_custom_interrupt/README.txt new file mode 100644 index 000000000000000..d5adfc01241f946 --- /dev/null +++ b/tests/arch/arm/arm_custom_interrupt/README.txt @@ -0,0 +1,35 @@ +Title: Test to verify custom interrupt controller handling with on + the Cortex-M architectures. + +Description: + +This test verifies customer interrupt controller handling on +Cortex-M architectures using the CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER +option. It will locate a unused interrupt to trigger via software and test +all methods that are part of the SoC interrupt control interface. + +--------------------------------------------------------------------------- + +Sample Output +*** Booting Zephyr OS build zephyr-v3.4.0-4023-g7fca0aa8a693 *** +Running TESTSUITE arm_custom_interrupt +=================================================================== +START - test_arm_interrupt +Available IRQ line: 42 +Got IRQ: 42 +Got IRQ: 42 +Got IRQ: 42 + PASS - test_arm_interrupt in 0.001 seconds +=================================================================== +TESTSUITE arm_custom_interrupt succeeded + +------ TESTSUITE SUMMARY START ------ + +SUITE PASS - 100.00% [arm_custom_interrupt]: pass = 1, fail = 0, skip = 0, total = 1 duration = 0.001 seconds + - PASS - [arm_custom_interrupt.test_arm_interrupt] duration = 0.001 seconds + +------ TESTSUITE SUMMARY END ------ + +=================================================================== +RunID: b979ee8bbf5ad07d1754866129997539 +PROJECT EXECUTION SUCCESSFUL diff --git a/tests/arch/arm/arm_custom_interrupt/prj.conf b/tests/arch/arm/arm_custom_interrupt/prj.conf new file mode 100644 index 000000000000000..ab8b7519f5540aa --- /dev/null +++ b/tests/arch/arm/arm_custom_interrupt/prj.conf @@ -0,0 +1,4 @@ +CONFIG_ZTEST=y +CONFIG_DYNAMIC_INTERRUPTS=y +CONFIG_IDLE_STACK_SIZE=512 +CONFIG_ASSERT_TEST=y diff --git a/tests/arch/arm/arm_custom_interrupt/src/arm_custom_interrupt.c b/tests/arch/arm/arm_custom_interrupt/src/arm_custom_interrupt.c new file mode 100644 index 000000000000000..97d3c55365d59c1 --- /dev/null +++ b/tests/arch/arm/arm_custom_interrupt/src/arm_custom_interrupt.c @@ -0,0 +1,209 @@ +/* + * Copyright Meta Platforms, Inc. and its affiliates. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +unsigned int sw_irq_number = (unsigned int)(-1); +static volatile bool custom_init_called; +static volatile bool custom_enable_called; +static volatile bool custom_disable_called; +static volatile bool custom_set_priority_called; +static volatile bool custom_eoi_called; +static volatile bool irq_handler_called; + +/* Define out custom SoC interrupt controller interface methods. + * These closely match the normal Cortex-M implementations. + */ + +#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) + +void z_soc_irq_init(void) +{ + int irq = 0; + + for (; irq < CONFIG_NUM_IRQS; irq++) { + NVIC_SetPriority((IRQn_Type)irq, _IRQ_PRIO_OFFSET); + } + + custom_init_called = true; +} + +void z_soc_irq_enable(unsigned int irq) +{ + if (irq == sw_irq_number) { + custom_enable_called = true; + } + NVIC_EnableIRQ((IRQn_Type)irq); +} + +void z_soc_irq_disable(unsigned int irq) +{ + if (irq == sw_irq_number) { + custom_disable_called = true; + } + NVIC_DisableIRQ((IRQn_Type)irq); +} + +int z_soc_irq_is_enabled(unsigned int irq) +{ + return NVIC->ISER[REG_FROM_IRQ(irq)] & BIT(BIT_FROM_IRQ(irq)); +} + +void z_soc_irq_eoi(unsigned int irq) +{ + if (irq == sw_irq_number) { + custom_eoi_called = true; + } +} + +inline __attribute__((always_inline)) unsigned int z_soc_irq_get_active(void) +{ + return __get_IPSR(); +} + +void z_soc_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) +{ + if (irq == sw_irq_number) { + custom_set_priority_called = true; + } + + if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) && (flags & IRQ_ZERO_LATENCY)) { + prio = _EXC_ZERO_LATENCY_IRQS_PRIO; + } else { + prio += _IRQ_PRIO_OFFSET; + } + + NVIC_SetPriority((IRQn_Type)irq, prio); +} + +void arm_isr_handler(const void *args) +{ + ARG_UNUSED(args); + +#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" + */ +#if defined(CONFIG_ARMV8_1_M_MAINLINE) + /* + * For ARMv8.1-M with FPU, the FPSCR[18:16] LTPSIZE field must be set + * to 0b100 for "Tail predication not applied" as it's reset value + */ + __set_FPSCR(4 << FPU_FPDSCR_LTPSIZE_Pos); +#else + __set_FPSCR(0); +#endif +#endif + + /* IRQ numbers are offset by 16 on Cortex-M. */ + unsigned int this_irq = z_soc_irq_get_active() - 16; + + TC_PRINT("Got IRQ: %u\n", this_irq); + + zassert_equal(this_irq, sw_irq_number, "Unexpected active IRQ\n"); + irq_handler_called = true; +} + +/** + * @brief Test custom interrupt controller handling with CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER. + * @addtogroup kernel_interrupt_tests + * @ingroup all_tests + * @{ + */ + +ZTEST(arm_custom_interrupt, test_arm_interrupt) +{ + zassert_true(custom_init_called, "Custom IRQ init not called\n"); + + /* Determine an NVIC IRQ line that is not currently in use. */ + int i; + + for (i = CONFIG_NUM_IRQS - 1; i >= 0; i--) { + if (NVIC_GetEnableIRQ(i) == 0) { + /* + * Interrupts configured statically with IRQ_CONNECT(.) + * are automatically enabled. NVIC_GetEnableIRQ() + * returning false, here, implies that the IRQ line is + * either not implemented or it is not enabled, thus, + * currently not in use by Zephyr. + */ + + /* Set the NVIC line to pending. */ + NVIC_SetPendingIRQ(i); + + if (NVIC_GetPendingIRQ(i)) { + /* If the NVIC line is pending, it is + * guaranteed that it is implemented; clear the + * line. + */ + NVIC_ClearPendingIRQ(i); + + if (!NVIC_GetPendingIRQ(i)) { + /* + * If the NVIC line can be successfully + * un-pended, it is guaranteed that it + * can be used for software interrupt + * triggering. + */ + break; + } + } + } + } + + zassert_true(i >= 0, "No available IRQ line to use in the test\n"); + + TC_PRINT("Available IRQ line: %u\n", i); + sw_irq_number = i; + + zassert_false(custom_set_priority_called, "Custom set priority flag set\n"); + arch_irq_connect_dynamic(sw_irq_number, 0 /* highest priority */, arm_isr_handler, NULL, 0); + zassert_true(custom_set_priority_called, "Custom set priority not called\n"); + + NVIC_ClearPendingIRQ(i); + + zassert_false(arch_irq_is_enabled(sw_irq_number), "SW IRQ already enabled\n"); + zassert_false(custom_enable_called, "Custom IRQ enable flag is set\n"); + irq_enable(sw_irq_number); + zassert_true(custom_enable_called, "Custom IRQ enable not called\n"); + zassert_true(arch_irq_is_enabled(sw_irq_number), "SW IRQ is not enabled\n"); + + for (int j = 1; j <= 3; j++) { + custom_eoi_called = false; + irq_handler_called = false; + custom_set_priority_called = false; + + /* Set the dynamic IRQ to pending state. */ + NVIC_SetPendingIRQ(i); + + /* + * Instruction barriers to make sure the NVIC IRQ is + * set to pending state before 'test_flag' is checked. + */ + barrier_dsync_fence_full(); + barrier_isync_fence_full(); + + /* Returning here implies the thread was not aborted. */ + + /* Confirm test flag is set by the ISR handler. */ + zassert_true(custom_eoi_called, "Custom EOI handler not called\n"); + zassert_true(irq_handler_called, "ISR handler not called\n"); + } + + zassert_false(custom_disable_called, "Custom IRQ disable flag is set\n"); + irq_disable(sw_irq_number); + zassert_true(custom_disable_called, "Custom IRQ disable not called\n"); +} + +/** + * @} + */ diff --git a/tests/arch/arm/arm_custom_interrupt/src/main.c b/tests/arch/arm/arm_custom_interrupt/src/main.c new file mode 100644 index 000000000000000..e1f3c2679658db1 --- /dev/null +++ b/tests/arch/arm/arm_custom_interrupt/src/main.c @@ -0,0 +1,9 @@ +/* + * Copyright Meta Platforms, Inc. and its affiliates. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +ZTEST_SUITE(arm_custom_interrupt, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/arch/arm/arm_custom_interrupt/testcase.yaml b/tests/arch/arm/arm_custom_interrupt/testcase.yaml new file mode 100644 index 000000000000000..d20f87e17ae112c --- /dev/null +++ b/tests/arch/arm/arm_custom_interrupt/testcase.yaml @@ -0,0 +1,10 @@ +common: + filter: CONFIG_ARMV6_M_ARMV8_M_BASELINE or CONFIG_ARMV7_M_ARMV8_M_MAINLINE + tags: + - arm + - interrupt + ignore_faults: true + arch_allow: arm +tests: + arch.arm.custom_interrupt: + filter: not CONFIG_TRUSTED_EXECUTION_NONSECURE From 6744d6084dd3ef0e1ab683551dd5301885f43dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 7 Nov 2023 08:53:36 +0700 Subject: [PATCH 0090/1049] watchdog: nxp_s32: use instance-based DT macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At present, many of the NXP S32 shim drivers do not make use of devicetree instance-based macros because the NXP S32 HAL relies on an index-based approach, requiring knowledge of the peripheral instance index during both compilation and runtime, and this index might not align with the devicetree instance index. The proposed solution in this patch eliminates this limitation by determining the peripheral instance index during compilation through macrobatics and defining the driver's ISR within the shim driver itself. Note that for some peripheral instances is needed to redefine the HAL macros of the peripheral base address, since the naming is not uniform for all instances. Signed-off-by: Manuel Argüelles --- drivers/watchdog/wdt_nxp_s32.c | 63 ++++++++++++++-------------------- soc/arm/nxp_s32/s32ze/soc.h | 15 ++++++++ 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/drivers/watchdog/wdt_nxp_s32.c b/drivers/watchdog/wdt_nxp_s32.c index 2d380264b941387..709cf9aaffbdf2b 100644 --- a/drivers/watchdog/wdt_nxp_s32.c +++ b/drivers/watchdog/wdt_nxp_s32.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_swt + #include #include #include @@ -129,6 +131,13 @@ static int swt_nxp_s32_feed(const struct device *dev, int channel_id) return 0; } +void swt_nxp_s32_isr(const struct device *dev) +{ + const struct swt_nxp_s32_config *config = dev->config; + + Swt_Ip_IrqHandler(config->instance); +} + static const struct wdt_driver_api swt_nxp_s32_driver_api = { .setup = swt_nxp_s32_setup, .disable = swt_nxp_s32_disable, @@ -136,17 +145,10 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { .feed = swt_nxp_s32_feed, }; -#define SWT_NODE(n) DT_NODELABEL(swt##n) -#define RTU0_SWT_OFFSET_IDX 2 -#define RTU1_SWT_OFFSET_IDX 7 -#define RTU_SWT(n) \ - COND_CODE_1(CONFIG_NXP_S32_RTU_INDEX, (RTU1_SWT_OFFSET_IDX + n), \ - (RTU0_SWT_OFFSET_IDX + n)) - #define SWT_NXP_S32_CALLBACK(n) \ void swt_nxp_s32_##n##_callback(void) \ { \ - const struct device *dev = DEVICE_DT_GET(SWT_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ struct swt_nxp_s32_data *data = dev->data; \ \ if (data->callback) { \ @@ -154,6 +156,12 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { } \ } +#define SWT_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_SWT_##i##_BASE) ? i : 0) + +#define SWT_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET SWT_INSTANCE_COUNT, SWT_NXP_S32_HW_INSTANCE_CHECK, (|), n) + #define SWT_NXP_S32_DEVICE_INIT(n) \ SWT_NXP_S32_CALLBACK(n) \ static struct swt_nxp_s32_data swt_nxp_s32_data_##n = { \ @@ -171,10 +179,10 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { }, \ }; \ static const struct swt_nxp_s32_config swt_nxp_s32_config_##n = { \ - .instance = (uint8_t)(RTU_SWT(n)), \ - .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(SWT_NODE(n))), \ + .instance = SWT_NXP_S32_HW_INSTANCE(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = (clock_control_subsys_t) \ - DT_CLOCKS_CELL(SWT_NODE(n), name), \ + DT_INST_CLOCKS_CELL(n, name), \ }; \ \ static int swt_nxp_s32_##n##_init(const struct device *dev) \ @@ -191,17 +199,15 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { return err; \ } \ \ - IRQ_CONNECT(DT_IRQN(SWT_NODE(n)), \ - DT_IRQ(SWT_NODE(n), priority), \ - Swt_Ip_IrqHandler, \ - (uint8_t)(RTU_SWT(n)), \ - DT_IRQ(SWT_NODE(n), flags)); \ - irq_enable(DT_IRQN(SWT_NODE(n))); \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + swt_nxp_s32_isr, DEVICE_DT_INST_GET(n), \ + DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ \ return 0; \ } \ \ - DEVICE_DT_DEFINE(SWT_NODE(n), \ + DEVICE_DT_INST_DEFINE(n, \ swt_nxp_s32_##n##_init, \ NULL, \ &swt_nxp_s32_data_##n, \ @@ -210,23 +216,4 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ &swt_nxp_s32_driver_api); - -#if DT_NODE_HAS_STATUS(SWT_NODE(0), okay) -SWT_NXP_S32_DEVICE_INIT(0) -#endif - -#if DT_NODE_HAS_STATUS(SWT_NODE(1), okay) -SWT_NXP_S32_DEVICE_INIT(1) -#endif - -#if DT_NODE_HAS_STATUS(SWT_NODE(2), okay) -SWT_NXP_S32_DEVICE_INIT(2) -#endif - -#if DT_NODE_HAS_STATUS(SWT_NODE(3), okay) -SWT_NXP_S32_DEVICE_INIT(3) -#endif - -#if DT_NODE_HAS_STATUS(SWT_NODE(4), okay) -SWT_NXP_S32_DEVICE_INIT(4) -#endif +DT_INST_FOREACH_STATUS_OKAY(SWT_NXP_S32_DEVICE_INIT) diff --git a/soc/arm/nxp_s32/s32ze/soc.h b/soc/arm/nxp_s32/s32ze/soc.h index cdee74ad54c4fe9..756774d7202f04e 100644 --- a/soc/arm/nxp_s32/s32ze/soc.h +++ b/soc/arm/nxp_s32/s32ze/soc.h @@ -18,4 +18,19 @@ /* LINFlexD*/ #define IP_LINFLEX_12_BASE IP_MSC_0_LIN_BASE +/* SWT */ +#define IP_SWT_0_BASE IP_CE_SWT_0_BASE +#define IP_SWT_1_BASE IP_CE_SWT_1_BASE +#define IP_SWT_2_BASE IP_RTU0__SWT_0_BASE +#define IP_SWT_3_BASE IP_RTU0__SWT_1_BASE +#define IP_SWT_4_BASE IP_RTU0__SWT_2_BASE +#define IP_SWT_5_BASE IP_RTU0__SWT_3_BASE +#define IP_SWT_6_BASE IP_RTU0__SWT_4_BASE +#define IP_SWT_7_BASE IP_RTU1__SWT_0_BASE +#define IP_SWT_8_BASE IP_RTU1__SWT_1_BASE +#define IP_SWT_9_BASE IP_RTU1__SWT_2_BASE +#define IP_SWT_10_BASE IP_RTU1__SWT_3_BASE +#define IP_SWT_11_BASE IP_RTU1__SWT_4_BASE +#define IP_SWT_12_BASE IP_SMU__SWT_BASE + #endif /* _NXP_S32_S32ZE_SOC_H_ */ From db0ec23ba4cf839ec5115b3cec7cea9275deadf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 7 Nov 2023 09:07:08 +0700 Subject: [PATCH 0091/1049] tests: samples: watchdog: add s32z270dc2_r52 rev.D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Twister treats board revisions as separate boards, so s32z270dc2_r52 revision D must be added to the filters. Signed-off-by: Manuel Argüelles --- samples/drivers/watchdog/sample.yaml | 4 ++++ tests/drivers/watchdog/wdt_basic_api/testcase.yaml | 4 ++++ tests/drivers/watchdog/wdt_basic_reset_none/testcase.yaml | 2 ++ 3 files changed, 10 insertions(+) diff --git a/samples/drivers/watchdog/sample.yaml b/samples/drivers/watchdog/sample.yaml index d9c908d536d41b9..f3e11dda9b5c347 100644 --- a/samples/drivers/watchdog/sample.yaml +++ b/samples/drivers/watchdog/sample.yaml @@ -20,6 +20,8 @@ tests: platform_exclude: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 + - s32z270dc2_rtu0_r52@D + - s32z270dc2_rtu1_r52@D sample.drivers.watchdog.stm32_wwdg: extra_args: DTC_OVERLAY_FILE=boards/stm32_wwdg.overlay filter: dt_compat_enabled("st,stm32-window-watchdog") @@ -106,3 +108,5 @@ tests: platform_allow: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 + - s32z270dc2_rtu0_r52@D + - s32z270dc2_rtu1_r52@D diff --git a/tests/drivers/watchdog/wdt_basic_api/testcase.yaml b/tests/drivers/watchdog/wdt_basic_api/testcase.yaml index f42734011c8588b..a2f8ea97f1f13e5 100644 --- a/tests/drivers/watchdog/wdt_basic_api/testcase.yaml +++ b/tests/drivers/watchdog/wdt_basic_api/testcase.yaml @@ -14,6 +14,8 @@ tests: - mec15xxevb_assy6853 - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 + - s32z270dc2_rtu0_r52@D + - s32z270dc2_rtu1_r52@D 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" @@ -117,6 +119,8 @@ tests: platform_allow: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 + - s32z270dc2_rtu0_r52@D + - s32z270dc2_rtu1_r52@D - mr_canhubk3 drivers.watchdog.mimxrt1050_evk_ti_tps382x: filter: dt_compat_enabled("ti,tps382x") diff --git a/tests/drivers/watchdog/wdt_basic_reset_none/testcase.yaml b/tests/drivers/watchdog/wdt_basic_reset_none/testcase.yaml index 0096842c2ec00d8..0290edbafc19f81 100644 --- a/tests/drivers/watchdog/wdt_basic_reset_none/testcase.yaml +++ b/tests/drivers/watchdog/wdt_basic_reset_none/testcase.yaml @@ -6,6 +6,8 @@ tests: platform_allow: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 + - s32z270dc2_rtu0_r52@D + - s32z270dc2_rtu1_r52@D tags: - drivers - watchdog From f9a4a3597bb56fa99aac69f699e213c51ca354d2 Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Fri, 22 Sep 2023 01:46:28 -0700 Subject: [PATCH 0092/1049] soc: arm: npcx: move soc-specific register definitions to soc.h This CL is to minimize `CONFIG_SOC_SERIES_XXXX` definitions when we introduce a new chip series. Most of them are relevant to register layouts in different npcx soc series. It moves soc-specific register definitions from `reg_def.h` to its own soc.h file. Signed-off-by: Mulin Chao --- drivers/flash/flash_npcx_fiu_qspi.c | 9 +- drivers/pinctrl/pinctrl_npcx.c | 11 +- soc/arm/nuvoton_npcx/common/reg/reg_def.h | 184 +++------------------- soc/arm/nuvoton_npcx/common/soc_clock.h | 22 --- soc/arm/nuvoton_npcx/npcx4/soc.h | 51 ++++++ soc/arm/nuvoton_npcx/npcx7/soc.h | 32 ++++ soc/arm/nuvoton_npcx/npcx9/soc.h | 43 +++++ 7 files changed, 153 insertions(+), 199 deletions(-) diff --git a/drivers/flash/flash_npcx_fiu_qspi.c b/drivers/flash/flash_npcx_fiu_qspi.c index 37afe6cfa4226ff..39e699bbef9d3a6 100644 --- a/drivers/flash/flash_npcx_fiu_qspi.c +++ b/drivers/flash/flash_npcx_fiu_qspi.c @@ -247,7 +247,6 @@ void qspi_npcx_fiu_mutex_unlock(const struct device *dev) static int qspi_npcx_fiu_init(const struct device *dev) { const struct npcx_qspi_fiu_config *const config = dev->config; - struct fiu_reg *const inst = HAL_INSTANCE(dev); struct npcx_qspi_fiu_data *const data = dev->data; const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); int ret; @@ -270,9 +269,11 @@ static int qspi_npcx_fiu_init(const struct device *dev) /* Enable direct access for 2 external SPI devices */ if (config->en_direct_access_2dev) { - if (IS_ENABLED(CONFIG_FLASH_NPCX_FIU_SUPP_DRA_2_DEV)) { - inst->FIU_EXT_CFG |= BIT(NPCX_FIU_EXT_CFG_SPI1_2DEV); - } +#if defined(CONFIG_FLASH_NPCX_FIU_SUPP_DRA_2_DEV) + struct fiu_reg *const inst = HAL_INSTANCE(dev); + + inst->FIU_EXT_CFG |= BIT(NPCX_FIU_EXT_CFG_SPI1_2DEV); +#endif } return 0; diff --git a/drivers/pinctrl/pinctrl_npcx.c b/drivers/pinctrl/pinctrl_npcx.c index 5759122018f4405..373a7158cfc8a6f 100644 --- a/drivers/pinctrl/pinctrl_npcx.c +++ b/drivers/pinctrl/pinctrl_npcx.c @@ -38,17 +38,10 @@ static const struct npcx_pwm_pinctrl_config pwm_pinctrl_cfg[] = { /* Pin-control local functions for peripheral devices */ static bool npcx_periph_pinmux_has_lock(int group) { -#if defined(CONFIG_SOC_SERIES_NPCX7) - if (group == 0x00 || (group >= 0x02 && group <= 0x04) || group == 0x06 || - group == 0x0b || group == 0x0f) { + if ((BIT(group) & NPCX_DEVALT_LK_GROUP_MASK) != 0) { return true; } -#elif defined(CONFIG_SOC_SERIES_NPCX9) - if (group == 0x00 || (group >= 0x02 && group <= 0x06) || group == 0x0b || - group == 0x0d || (group >= 0x0f && group <= 0x12)) { - return true; - } -#endif + return false; } diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index 794bb5545bb514f..e9ef3460e63cce2 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -228,49 +228,17 @@ struct scfg_reg { volatile uint8_t LV_GPIO_CTL0[5]; }; -/* SCFG internal inline functions for multi-registers */ -static inline uint32_t npcx_devalt_offset(uint32_t alt_no) -{ - return 0x010 + alt_no; -} - -static inline uint32_t npcx_devalt_lk_offset(uint32_t alt_lk_no) -{ - return 0x210 + alt_lk_no; -} - -static inline uint32_t npcx_pupd_en_offset(uint32_t pupd_en_no) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7) || IS_ENABLED(CONFIG_SOC_SERIES_NPCX9)) { - return 0x28 + pupd_en_no; - } else { /* NPCX4 and later series */ - return 0x2b + pupd_en_no; - } -} - -static inline uint32_t npcx_lv_gpio_ctl_offset(uint32_t ctl_no) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7) || IS_ENABLED(CONFIG_SOC_SERIES_NPCX9)) { - if (ctl_no < 5) { - return 0x02a + ctl_no; - } else { - return 0x026 + ctl_no - 5; - } - } else { /* NPCX4 and later series */ - return 0x150 + ctl_no; - } -} - /* Macro functions for SCFG multi-registers */ -#define NPCX_DEV_CTL(base, n) (*(volatile uint8_t *)(base + n)) -#define NPCX_DEVALT(base, n) (*(volatile uint8_t *)(base + \ - npcx_devalt_offset(n))) -#define NPCX_DEVALT_LK(base, n) (*(volatile uint8_t *)(base + \ - npcx_devalt_lk_offset(n))) -#define NPCX_PUPD_EN(base, n) (*(volatile uint8_t *)(base + \ - npcx_pupd_en_offset(n))) -#define NPCX_LV_GPIO_CTL(base, n) (*(volatile uint8_t *)(base + \ - npcx_lv_gpio_ctl_offset(n))) +#define NPCX_DEV_CTL(base, n) \ + (*(volatile uint8_t *)(base + n)) +#define NPCX_DEVALT(base, n) \ + (*(volatile uint8_t *)(base + NPCX_DEVALT_OFFSET(n))) +#define NPCX_DEVALT_LK(base, n) \ + (*(volatile uint8_t *)(base + NPCX_DEVALT_LK_OFFSET(n))) +#define NPCX_PUPD_EN(base, n) \ + (*(volatile uint8_t *)(base + NPCX_PUPD_EN_OFFSET(n))) +#define NPCX_LV_GPIO_CTL(base, n) \ + (*(volatile uint8_t *)(base + NPCX_LV_GPIO_CTL_OFFSET(n))) /* SCFG register fields */ #define NPCX_DEVCNT_F_SPI_TRIS 6 @@ -413,95 +381,21 @@ struct uart_reg { #define NPCX_UFRCTL_RNEMPTY_EN 6 #define NPCX_UFRCTL_ERR_EN 7 -/* - * Multi-Input Wake-Up Unit (MIWU) device registers - */ - -/* MIWU internal inline functions for multi-registers */ -static inline uint32_t npcx_wkedg_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x000 + (group * 2ul) + (group < 5 ? 0 : 0x1e); - } else { /* NPCX9 and later series */ - return 0x000 + group * 0x10UL; - } -} - -static inline uint32_t npcx_wkaedg_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x001 + (group * 2ul) + (group < 5 ? 0 : 0x1e); - } else { /* NPCX9 and later series */ - return 0x001 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wkmod_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x070 + group; - } else { /* NPCX9 and later series */ - return 0x002 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wkpnd_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x00a + (group * 4ul) + (group < 5 ? 0 : 0x10); - } else { /* NPCX9 and later series */ - return 0x003 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wkpcl_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x00c + (group * 4ul) + (group < 5 ? 0 : 0x10); - } else { /* NPCX9 and later series */ - return 0x004 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wken_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x01e + (group * 2ul) + (group < 5 ? 0 : 0x12); - } else { /* NPCX9 and later series */ - return 0x005 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wkst_offset(uint32_t group) -{ - /* NPCX9 and later series only */ - return 0x006 + group * 0x10ul; -} - -static inline uint32_t npcx_wkinen_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x01f + (group * 2ul) + (group < 5 ? 0 : 0x12); - } else { /* NPCX9 and later series */ - return 0x007 + group * 0x10ul; - } -} - /* Macro functions for MIWU multi-registers */ #define NPCX_WKEDG(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkedg_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKEDG_OFFSET(group))) #define NPCX_WKAEDG(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkaedg_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKAEDG_OFFSET(group))) #define NPCX_WKPND(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkpnd_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKPND_OFFSET(group))) #define NPCX_WKPCL(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkpcl_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKPCL_OFFSET(group))) #define NPCX_WKEN(base, group) \ - (*(volatile uint8_t *)(base + npcx_wken_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKEN_OFFSET(group))) #define NPCX_WKINEN(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkinen_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKINEN_OFFSET(group))) #define NPCX_WKMOD(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkmod_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKMOD_OFFSET(group))) /* * General-Purpose I/O (GPIO) device registers @@ -582,33 +476,10 @@ struct adc_reg { }; /* ADC internal inline functions for multi-registers */ -static inline uint32_t npcx_chndat_offset(uint32_t ch) -{ - return 0x40 + ch * 2; -} - -static inline uint32_t npcx_thr_base(void) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x014; - } else if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX9)) { - return 0x060; - } else { /* NPCX4 and later series */ - return 0x080; - } -} - -static inline uint32_t npcx_thrctl_offset(uint32_t ctrl) -{ - return npcx_thr_base() + ctrl * 2; -} - -#define CHNDAT(base, ch) (*(volatile uint16_t *)((base) + npcx_chndat_offset(ch))) +#define CHNDAT(base, ch) \ + (*(volatile uint16_t *)((base) + NPCX_CHNDAT_OFFSET(ch))) #define THRCTL(base, ctrl) \ - (*(volatile uint16_t *)(base + npcx_thrctl_offset(ctrl))) -#ifdef CONFIG_SOC_SERIES_NPCX4 -#define THEN(base) (*(volatile uint16_t *)(base + 0x90)) -#endif + (*(volatile uint16_t *)(base + NPCX_THRCTL_OFFSET(ctrl))) /* ADC register fields */ #define NPCX_ATCTL_SCLKDIV_FIELD FIELD(0, 6) @@ -628,16 +499,6 @@ static inline uint32_t npcx_thrctl_offset(uint32_t ctrl) #define NPCX_ADCCNF_STOP 11 #define NPCX_CHNDAT_CHDAT_FIELD FIELD(0, 10) #define NPCX_CHNDAT_NEW 15 -#ifdef CONFIG_SOC_SERIES_NPCX4 -#define NPCX_THRCTL_L_H 15 -#define NPCX_THRCTL_CHNSEL FIELD(10, 5) -#define NPCX_THRCTL_THRVAL FIELD(0, 10) -#else -#define NPCX_THRCTL_THEN 15 -#define NPCX_THRCTL_L_H 14 -#define NPCX_THRCTL_CHNSEL FIELD(10, 4) -#define NPCX_THRCTL_THRVAL FIELD(0, 10) -#endif #define NPCX_THRCTS_ADC_WKEN 15 #define NPCX_THRCTS_THR3_IEN 10 #define NPCX_THRCTS_THR2_IEN 9 @@ -1598,11 +1459,6 @@ struct fiu_reg { #define NPCX_SPI1_DEV_FOUR_BADDR_CS10 6 #define NPCX_SPI1_DEV_FOUR_BADDR_CS11 7 #define NPCX_SPI1_DEV_SPI1_LO_DEV_SIZE FIELD(0, 4) -#if defined(CONFIG_SOC_SERIES_NPCX9) -#define NPCX_FIU_EXT_CFG_SPI1_2DEV 7 -#else -#define NPCX_FIU_EXT_CFG_SPI1_2DEV 6 -#endif #define NPCX_FIU_EXT_CFG_SET_DMM_EN 2 #define NPCX_FIU_EXT_CFG_SET_CMD_EN 1 #define NPCX_SPI_DEV_NADDRB FIELD(5, 3) diff --git a/soc/arm/nuvoton_npcx/common/soc_clock.h b/soc/arm/nuvoton_npcx/common/soc_clock.h index cda024dc0dfdc0a..6b302f2e885d74a 100644 --- a/soc/arm/nuvoton_npcx/common/soc_clock.h +++ b/soc/arm/nuvoton_npcx/common/soc_clock.h @@ -42,14 +42,6 @@ struct npcx_clk_cfg { #define APB2DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb2_prescaler) - 1) /* APB3 clock divider */ #define APB3DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb3_prescaler) - 1) -/* APB4 clock divider if supported */ -#if DT_NODE_HAS_PROP(DT_NODELABEL(pcc), apb4_prescaler) -#if !defined(CONFIG_SOC_SERIES_NPCX7) /* Supported in NPCX9 and later series */ -#define APB4DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb4_prescaler) - 1) -#else -#error "APB4 clock divider is not supported but defined in pcc node!" -#endif /* !CONFIG_SOC_SERIES_NPCX7 */ -#endif /* Construct a uint8_t array from 'pwdwn-ctl-val' prop for PWDWN_CTL initialization. */ #define NPCX_PWDWN_CTL_ITEMS_INIT(node, prop, idx) DT_PROP_BY_IDX(node, prop, idx), @@ -68,12 +60,6 @@ struct npcx_clk_cfg { * - CORE_CLK > MAX_OFMCLK/2, AHB6DIV should be 1, else 0. * - CORE_CLK > MAX_OFMCLK/2, FIUDIV should be 1, else 0. */ -#if defined(CONFIG_SOC_SERIES_NPCX4) -#define MAX_OFMCLK 120000000 -#else -#define MAX_OFMCLK 100000000 -#endif /* CONFIG_SOC_SERIES_NPCX4 */ - /* Core domain clock */ #define CORE_CLK (OFMCLK / DT_PROP(DT_NODELABEL(pcc), core_prescaler)) /* Low Frequency clock */ @@ -103,14 +89,6 @@ struct npcx_clk_cfg { #define FIUDIV_VAL 0 /* FIU_CLK = CORE_CLK */ #endif -#if defined(CONFIG_SOC_SERIES_NPCX4) -#if (CORE_CLK > (MAX_OFMCLK / 2)) -#define FIU1DIV_VAL 1 /* FIU1_CLK = CORE_CLK/2 */ -#else -#define FIU1DIV_VAL 0 /* FIU1_CLK = CORE_CLK */ -#endif -#endif /* CONFIG_SOC_SERIES_NPCX4 */ - /* Get APB clock freq */ #define NPCX_APB_CLOCK(no) (APBSRC_CLK / (APB##no##DIV_VAL + 1)) diff --git a/soc/arm/nuvoton_npcx/npcx4/soc.h b/soc/arm/nuvoton_npcx/npcx4/soc.h index e61c1e108f020f8..5c3f7cf59272529 100644 --- a/soc/arm/nuvoton_npcx/npcx4/soc.h +++ b/soc/arm/nuvoton_npcx/npcx4/soc.h @@ -11,6 +11,45 @@ #define __FPU_PRESENT CONFIG_CPU_HAS_FPU #define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +/* NPCX4 SCFG multi-registers */ +#define NPCX_DEVALT_OFFSET(n) (0x010 + n) +#define NPCX_PUPD_EN_OFFSET(n) (0x02b + n) +#define NPCX_LV_GPIO_CTL_OFFSET(n) (0x150 + n) +#define NPCX_DEVALT_LK_OFFSET(n) (0x210 + n) + +/* NPCX4 MIWU multi-registers */ +#define NPCX_WKEDG_OFFSET(n) (0x000 + (n * 0x010)) +#define NPCX_WKAEDG_OFFSET(n) (0x001 + (n * 0x010)) +#define NPCX_WKMOD_OFFSET(n) (0x002 + (n * 0x010)) +#define NPCX_WKPND_OFFSET(n) (0x003 + (n * 0x010)) +#define NPCX_WKPCL_OFFSET(n) (0x004 + (n * 0x010)) +#define NPCX_WKEN_OFFSET(n) (0x005 + (n * 0x010)) +#define NPCX_WKST_OFFSET(n) (0x006 + (n * 0x010)) +#define NPCX_WKINEN_OFFSET(n) (0x007 + (n * 0x010)) + +/* NPCX4 ADC multi-registers */ +#define NPCX_CHNDAT_OFFSET(n) (0x040 + n * 2) +#define NPCX_THRCTL_OFFSET(n) (0x080 + n * 2) +#define NPCX_THEN_OFFSET 0x090 +#define THEN(base) (*(volatile uint16_t *)(base + NPCX_THEN_OFFSET)) + +/* NPCX4 ADC register fields */ +#define NPCX_THRCTL_L_H 15 +#define NPCX_THRCTL_CHNSEL FIELD(10, 5) +#define NPCX_THRCTL_THRVAL FIELD(0, 10) + +/* NPCX4 FIU register fields */ +#define NPCX_FIU_EXT_CFG_SPI1_2DEV 6 + +/* NPCX4 supported group mask of DEVALT_LK */ +#define NPCX_DEVALT_LK_GROUP_MASK \ + (BIT(0) | BIT(2) | BIT(3) | BIT(4) | \ + BIT(5) | BIT(6) | BIT(11) | BIT(13) | \ + BIT(15) | BIT(16) | BIT(17) | BIT(18) | \ + BIT(19) | BIT(21)) /* DEVALT0_LK - DEVALTN_LK */ + +/* NPCX4 Clock Configuration */ +#define MAX_OFMCLK 120000000 #include #include @@ -19,4 +58,16 @@ #include #include +/* NPCX4 Clock definitions */ +#if DT_NODE_HAS_PROP(DT_NODELABEL(pcc), apb4_prescaler) +/* APB4 clock divider if supported */ +#define APB4DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb4_prescaler) - 1) +#endif + +#if (CORE_CLK > (MAX_OFMCLK / 2)) +#define FIU1DIV_VAL 1 /* If CORE_CLK > MAX_OFMCLK / 2, FIU1_CLK = CORE_CLK/2 */ +#else +#define FIU1DIV_VAL 0 /* Else, FIU1_CLK = CORE_CLK */ +#endif + #endif /* _NUVOTON_NPCX_SOC_H_ */ diff --git a/soc/arm/nuvoton_npcx/npcx7/soc.h b/soc/arm/nuvoton_npcx/npcx7/soc.h index 9c293e05753c5cc..7099552cec38b86 100644 --- a/soc/arm/nuvoton_npcx/npcx7/soc.h +++ b/soc/arm/nuvoton_npcx/npcx7/soc.h @@ -11,6 +11,38 @@ #define __FPU_PRESENT CONFIG_CPU_HAS_FPU #define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +/* NPCX7 SCFG multi-registers offset */ +#define NPCX_DEVALT_OFFSET(n) (0x010 + n) +#define NPCX_PUPD_EN_OFFSET(n) (0x028 + n) +#define NPCX_LV_GPIO_CTL_OFFSET(n) ((n < 5) ? (0x02a + n) : (0x021 + n)) +#define NPCX_DEVALT_LK_OFFSET(n) (0x210 + n) + +/* NPCX7 MIWU multi-registers offset */ +#define NPCX_WKEDG_OFFSET(n) (0x000 + (n * 2) + ((n < 5) ? 0 : 0x01e)) +#define NPCX_WKAEDG_OFFSET(n) (0x001 + (n * 2) + ((n < 5) ? 0 : 0x01e)) +#define NPCX_WKMOD_OFFSET(n) (0x070 + n) +#define NPCX_WKPND_OFFSET(n) (0x00a + (n * 4) + ((n < 5) ? 0 : 0x010)) +#define NPCX_WKPCL_OFFSET(n) (0x00c + (n * 4) + ((n < 5) ? 0 : 0x010)) +#define NPCX_WKEN_OFFSET(n) (0x01e + (n * 2) + ((n < 5) ? 0 : 0x012)) +#define NPCX_WKINEN_OFFSET(n) (0x01f + (n * 2) + ((n < 5) ? 0 : 0x012)) + +/* NPCX7 ADC multi-registers offset */ +#define NPCX_CHNDAT_OFFSET(n) (0x040 + (n * 2)) +#define NPCX_THRCTL_OFFSET(n) (0x014 + (n * 2)) + +/* NPCX7 ADC register fields */ +#define NPCX_THRCTL_THEN 15 +#define NPCX_THRCTL_L_H 14 +#define NPCX_THRCTL_CHNSEL FIELD(10, 4) +#define NPCX_THRCTL_THRVAL FIELD(0, 10) + +/* NPCX7 supported group mask of DEVALT_LK */ +#define NPCX_DEVALT_LK_GROUP_MASK \ + (BIT(0) | BIT(2) | BIT(3) | BIT(4) | \ + BIT(6) | BIT(11) | BIT(15)) /* DEVALT0_LK - DEVALTF_LK */ + +/* NPCX7 Clock configuration */ +#define MAX_OFMCLK 100000000 #include #include diff --git a/soc/arm/nuvoton_npcx/npcx9/soc.h b/soc/arm/nuvoton_npcx/npcx9/soc.h index a1769e11a00659d..0e9e23cda36ee6a 100644 --- a/soc/arm/nuvoton_npcx/npcx9/soc.h +++ b/soc/arm/nuvoton_npcx/npcx9/soc.h @@ -11,6 +11,43 @@ #define __FPU_PRESENT CONFIG_CPU_HAS_FPU #define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +/* NPCX9 SCFG multi-registers */ +#define NPCX_DEVALT_OFFSET(n) (0x010 + n) +#define NPCX_PUPD_EN_OFFSET(n) (0x028 + n) +#define NPCX_LV_GPIO_CTL_OFFSET(n) ((n < 5) ? (0x02a + n) : (0x021 + n)) +#define NPCX_DEVALT_LK_OFFSET(n) (0x210 + n) + +/* NPCX9 MIWU multi-registers */ +#define NPCX_WKEDG_OFFSET(n) (0x000 + (n * 0x010)) +#define NPCX_WKAEDG_OFFSET(n) (0x001 + (n * 0x010)) +#define NPCX_WKMOD_OFFSET(n) (0x002 + (n * 0x010)) +#define NPCX_WKPND_OFFSET(n) (0x003 + (n * 0x010)) +#define NPCX_WKPCL_OFFSET(n) (0x004 + (n * 0x010)) +#define NPCX_WKEN_OFFSET(n) (0x005 + (n * 0x010)) +#define NPCX_WKST_OFFSET(n) (0x006 + (n * 0x010)) +#define NPCX_WKINEN_OFFSET(n) (0x007 + (n * 0x010)) + +/* NPCX9 ADC multi-registers */ +#define NPCX_CHNDAT_OFFSET(n) (0x040 + (n * 2)) +#define NPCX_THRCTL_OFFSET(n) (0x060 + (n * 2)) + +/* NPCX9 ADC register fields */ +#define NPCX_THRCTL_THEN 15 +#define NPCX_THRCTL_L_H 14 +#define NPCX_THRCTL_CHNSEL FIELD(10, 4) +#define NPCX_THRCTL_THRVAL FIELD(0, 10) + +/* NPCX9 FIU register fields */ +#define NPCX_FIU_EXT_CFG_SPI1_2DEV 7 + +/* NPCX9 supported group mask of DEVALT_LK */ +#define NPCX_DEVALT_LK_GROUP_MASK \ + (BIT(0) | BIT(2) | BIT(3) | BIT(4) | \ + BIT(5) | BIT(6) | BIT(11) | BIT(13) | \ + BIT(15) | BIT(16) | BIT(17) | BIT(18)) /* DEVALT0_LK - DEVALTJ_LK */ + +/* NPCX9 Clock configuration and limitation */ +#define MAX_OFMCLK 100000000 #include #include @@ -19,4 +56,10 @@ #include #include +/* NPCX9 Clock definitions */ +#if DT_NODE_HAS_PROP(DT_NODELABEL(pcc), apb4_prescaler) +/* APB4 clock divider if supported */ +#define APB4DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb4_prescaler) - 1) +#endif + #endif /* _NUVOTON_NPCX_SOC_H_ */ From d24545072c0b5dd2bdcf0169a014ca4ec66d1386 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 20 Sep 2023 16:08:36 +0800 Subject: [PATCH 0093/1049] arch: sw_isr: store device info in the table and add funtions to access Change the internal function to `get_parent_entry`, which returns the entire entry of table. Store the parent interrupt controller device in the `irq_parent_offset` table, and added 2 helper functions to: 1. determine the parent interrupt controller based on the IRQ 2. determine the IRQ of the parent interrupt controller Declare the `struct _irq_parent_entry` in the header and added `-` suffix to the struct so that it can be used to test the functions in testsuites. Signed-off-by: Yong Cong Sin --- arch/common/sw_isr_common.c | 129 ++++++++++++++++++++++++++++------ include/zephyr/sw_isr_table.h | 26 +++++++ 2 files changed, 132 insertions(+), 23 deletions(-) diff --git a/arch/common/sw_isr_common.c b/arch/common/sw_isr_common.c index a9c0a6df3d24dea..907fbfdfa169ad1 100644 --- a/arch/common/sw_isr_common.c +++ b/arch/common/sw_isr_common.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -17,12 +18,38 @@ #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS -struct irq_parent_offset { - unsigned int irq; - unsigned int offset; -}; +/* + * Insert code if the node_id is an interrupt controller + */ +#define Z_IF_DT_IS_INTC(node_id, code) \ + IF_ENABLED(DT_NODE_HAS_PROP(node_id, interrupt_controller), (code)) + +/* + * Expands to node_id if its IRQN is equal to `irq`, nothing otherwise + * This only works for `irq` between 0 & 4095, see `IS_EQ` + */ +#define Z_IF_DT_INTC_IRQN_EQ(node_id, irq) IF_ENABLED(IS_EQ(DT_IRQ(node_id, irq), irq), (node_id)) -#define INIT_IRQ_PARENT_OFFSET(i, o) { \ +/* + * Expands to node_id if it's an interrupt controller & its IRQN is `irq`, or nothing otherwise + */ +#define Z_DT_INTC_GET_IRQN(node_id, irq) \ + Z_IF_DT_IS_INTC(node_id, Z_IF_DT_INTC_IRQN_EQ(node_id, irq)) + +/** + * Loop through child of "/soc" and get root interrupt controllers with `irq` as IRQN, + * this assumes only one device has the IRQN + * @param irq irq number + * @return node_id(s) that has the `irq` number, or empty if none of them has the `irq` + */ +#define INTC_DT_IRQN_GET(irq) \ + DT_FOREACH_CHILD_STATUS_OKAY_VARGS(DT_PATH(soc), Z_DT_INTC_GET_IRQN, irq) + +/* If can't find any matching interrupt controller, fills with `NULL` */ +#define INTC_DEVICE_INIT(node_id) .dev = DEVICE_DT_GET_OR_NULL(node_id), + +#define INIT_IRQ_PARENT_OFFSET(d, i, o) { \ + INTC_DEVICE_INIT(d) \ .irq = i, \ .offset = o, \ } @@ -32,9 +59,9 @@ struct irq_parent_offset { #ifdef CONFIG_2ND_LEVEL_INTERRUPTS #define CAT_2ND_LVL_LIST(i, base) \ - INIT_IRQ_PARENT_OFFSET(CONFIG_2ND_LVL_INTR_0##i##_OFFSET, \ - IRQ_INDEX_TO_OFFSET(i, base)) -static struct irq_parent_offset lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] + INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_2ND_LVL_INTR_0##i##_OFFSET), \ + CONFIG_2ND_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) +const struct _irq_parent_entry _lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] = { LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, CAT_2ND_LVL_LIST, (,), CONFIG_2ND_LVL_ISR_TBL_OFFSET) }; @@ -43,57 +70,113 @@ static struct irq_parent_offset lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] #ifdef CONFIG_3RD_LEVEL_INTERRUPTS #define CAT_3RD_LVL_LIST(i, base) \ - INIT_IRQ_PARENT_OFFSET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET, \ - IRQ_INDEX_TO_OFFSET(i, base)) -static struct irq_parent_offset lvl3_irq_list[CONFIG_NUM_3RD_LEVEL_AGGREGATORS] + INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET), \ + CONFIG_3RD_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) +const struct _irq_parent_entry _lvl3_irq_list[CONFIG_NUM_3RD_LEVEL_AGGREGATORS] = { LISTIFY(CONFIG_NUM_3RD_LEVEL_AGGREGATORS, CAT_3RD_LVL_LIST, (,), CONFIG_3RD_LVL_ISR_TBL_OFFSET) }; #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ -unsigned int get_parent_offset(unsigned int parent_irq, - struct irq_parent_offset list[], - unsigned int length) +static const struct _irq_parent_entry *get_parent_entry(unsigned int parent_irq, + const struct _irq_parent_entry list[], + unsigned int length) { unsigned int i; - unsigned int offset = 0U; + const struct _irq_parent_entry *entry = NULL; for (i = 0U; i < length; ++i) { if (list[i].irq == parent_irq) { - offset = list[i].offset; + entry = &list[i]; break; } } __ASSERT(i != length, "Invalid argument: %i", parent_irq); - return offset; + return entry; } #endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ +const struct device *z_get_sw_isr_device_from_irq(unsigned int irq) +{ + const struct device *dev = NULL; + +#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS + unsigned int level, parent_irq; + const struct _irq_parent_entry *entry = NULL; + + level = irq_get_level(irq); + + if (level == 2U) { + parent_irq = irq_parent_level_2(irq); + entry = get_parent_entry(parent_irq, + _lvl2_irq_list, + CONFIG_NUM_2ND_LEVEL_AGGREGATORS); + } +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + else if (level == 3U) { + parent_irq = irq_parent_level_3(irq); + entry = get_parent_entry(parent_irq, + _lvl3_irq_list, + CONFIG_NUM_3RD_LEVEL_AGGREGATORS); + } +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ + dev = entry != NULL ? entry->dev : NULL; +#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ + + return dev; +} + +unsigned int z_get_sw_isr_irq_from_device(const struct device *dev) +{ +#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS + for (size_t i = 0U; i < CONFIG_NUM_2ND_LEVEL_AGGREGATORS; ++i) { + if (_lvl2_irq_list[i].dev == dev) { + return _lvl2_irq_list[i].irq; + } + } + +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + for (size_t i = 0U; i < CONFIG_NUM_3RD_LEVEL_AGGREGATORS; ++i) { + if (_lvl3_irq_list[i].dev == dev) { + return _lvl3_irq_list[i].irq; + } + } +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ +#else + ARG_UNUSED(dev); +#endif + + return 0; +} + unsigned int z_get_sw_isr_table_idx(unsigned int irq) { unsigned int table_idx; #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS unsigned int level, parent_irq, parent_offset; + const struct _irq_parent_entry *entry = NULL; level = irq_get_level(irq); if (level == 2U) { parent_irq = irq_parent_level_2(irq); - parent_offset = get_parent_offset(parent_irq, - lvl2_irq_list, - CONFIG_NUM_2ND_LEVEL_AGGREGATORS); + entry = get_parent_entry(parent_irq, + _lvl2_irq_list, + CONFIG_NUM_2ND_LEVEL_AGGREGATORS); + parent_offset = entry != NULL ? entry->offset : 0U; table_idx = parent_offset + irq_from_level_2(irq); } #ifdef CONFIG_3RD_LEVEL_INTERRUPTS else if (level == 3U) { parent_irq = irq_parent_level_3(irq); - parent_offset = get_parent_offset(parent_irq, - lvl3_irq_list, - CONFIG_NUM_3RD_LEVEL_AGGREGATORS); + entry = get_parent_entry(parent_irq, + _lvl3_irq_list, + CONFIG_NUM_3RD_LEVEL_AGGREGATORS); + parent_offset = entry != NULL ? entry->offset : 0U; table_idx = parent_offset + irq_from_level_3(irq); } #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ diff --git a/include/zephyr/sw_isr_table.h b/include/zephyr/sw_isr_table.h index 7db7381422b4f98..fb68272c34c6b3a 100644 --- a/include/zephyr/sw_isr_table.h +++ b/include/zephyr/sw_isr_table.h @@ -15,6 +15,7 @@ #define ZEPHYR_INCLUDE_SW_ISR_TABLE_H_ #if !defined(_ASMLANGUAGE) +#include #include #include @@ -43,6 +44,12 @@ struct _isr_table_entry { */ extern struct _isr_table_entry _sw_isr_table[]; +struct _irq_parent_entry { + const struct device *dev; + unsigned int irq; + unsigned int offset; +}; + /* * Data structure created in a special binary .intlist section for each * configured interrupt. gen_irq_tables.py pulls this out of the binary and @@ -87,6 +94,25 @@ extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; */ unsigned int z_get_sw_isr_table_idx(unsigned int irq); +/** + * @brief Helper function used to get the parent interrupt controller device based on passed IRQ. + * + * @param irq IRQ number in its zephyr format + * + * @return corresponding interrupt controller device in _sw_isr_table + */ +const struct device *z_get_sw_isr_device_from_irq(unsigned int irq); + +/** + * @brief Helper function used to get the IRQN of the passed in parent interrupt + * controller device. + * + * @param dev parent interrupt controller device + * + * @return IRQN of the interrupt controller + */ +unsigned int z_get_sw_isr_irq_from_device(const struct device *dev); + /** This interrupt gets put directly in the vector table */ #define ISR_FLAG_DIRECT BIT(0) From ad788a335f87d41b5ac49afa0e64b6a1a0bda3ea Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 22 Sep 2023 12:43:54 +0800 Subject: [PATCH 0094/1049] tests: interrupt: add testcase for functions in the sw_isr_table Validate the following functions in the sw_isr_table: - z_get_sw_isr_table_idx - z_get_sw_isr_device_from_irq - z_get_sw_isr_irq_from_device Signed-off-by: Yong Cong Sin --- tests/kernel/interrupt/CMakeLists.txt | 4 ++ tests/kernel/interrupt/src/sw_isr_table.c | 54 +++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/kernel/interrupt/src/sw_isr_table.c diff --git a/tests/kernel/interrupt/CMakeLists.txt b/tests/kernel/interrupt/CMakeLists.txt index 80f3fbca6653a75..645f1f7965b676d 100644 --- a/tests/kernel/interrupt/CMakeLists.txt +++ b/tests/kernel/interrupt/CMakeLists.txt @@ -22,3 +22,7 @@ target_sources_ifdef(CONFIG_SHARED_INTERRUPTS app PRIVATE src/static_shared_irq. if (CONFIG_SHARED_INTERRUPTS) target_sources_ifdef(CONFIG_DYNAMIC_INTERRUPTS app PRIVATE src/dynamic_shared_irq.c) endif() + +if(CONFIG_MULTI_LEVEL_INTERRUPTS) + target_sources_ifdef(CONFIG_DYNAMIC_INTERRUPTS app PRIVATE src/sw_isr_table.c) +endif() diff --git a/tests/kernel/interrupt/src/sw_isr_table.c b/tests/kernel/interrupt/src/sw_isr_table.c new file mode 100644 index 000000000000000..621480905a71e2c --- /dev/null +++ b/tests/kernel/interrupt/src/sw_isr_table.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +extern const struct _irq_parent_entry _lvl2_irq_list[]; + +/** + * @brief Test sw_isr_table function + * + * @details Validates that: + * - z_get_sw_isr_device_from_irq() returns the parent interrupt controller for an IRQN + * - z_get_sw_isr_irq_from_device() returns the IRQN of a parent interrupt controller + * - z_get_sw_isr_table_idx() returns the corresponding SW ISR table index for an IRQN + */ +ZTEST(interrupt_feature, test_sw_isr_irq_parent_table) +{ + const struct device *parent_dev; + unsigned int parent_irq; + unsigned int parent_isr_offset; + const struct device *test_dev; + unsigned int test_irq; + unsigned int test_isr_offset; + + for (size_t i = 0; i < CONFIG_NUM_2ND_LEVEL_AGGREGATORS; i++) { + parent_dev = _lvl2_irq_list[i].dev; + parent_irq = _lvl2_irq_list[i].irq; + parent_isr_offset = _lvl2_irq_list[i].offset; + + for (unsigned int local_irq = 0; + local_irq < BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); local_irq++) { + test_irq = irq_to_level_2(local_irq) | parent_irq; + test_dev = z_get_sw_isr_device_from_irq(test_irq); + zassert_equal_ptr(parent_dev, test_dev, "expected dev: %p, got: %p", + parent_dev, test_dev); + } + + test_irq = z_get_sw_isr_irq_from_device(parent_dev); + zassert_equal(parent_irq, test_irq, "expected offset: %d, got: %d", parent_irq, + test_irq); + + for (unsigned int local_irq = 0; + local_irq < BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); local_irq++) { + test_irq = irq_to_level_2(local_irq) | parent_irq; + test_isr_offset = z_get_sw_isr_table_idx(test_irq); + zassert_equal(parent_isr_offset + local_irq, test_isr_offset, + "expected offset: %d, got: %d", parent_isr_offset + local_irq, + test_isr_offset); + } + } +} From ec93404a2682ca72ec0313c5008b92bf45a69f36 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 16 Oct 2023 15:39:48 +0800 Subject: [PATCH 0095/1049] arch: common: irq: relocate internal functions into a private header Relocate new and existing internal software-managed table access functions from the public `sw_isr_table.h` into a private header that should only be accessed internally. Signed-off-by: Yong Cong Sin --- arch/common/CMakeLists.txt | 2 + arch/common/include/sw_isr_common.h | 57 +++++++++++++++++++++++ arch/common/shared_irq.c | 2 + include/zephyr/sw_isr_table.h | 29 ------------ tests/kernel/interrupt/CMakeLists.txt | 1 + tests/kernel/interrupt/src/sw_isr_table.c | 2 + 6 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 arch/common/include/sw_isr_common.h diff --git a/arch/common/CMakeLists.txt b/arch/common/CMakeLists.txt index 8056ad5d95d80ea..7421e44631add95 100644 --- a/arch/common/CMakeLists.txt +++ b/arch/common/CMakeLists.txt @@ -2,6 +2,8 @@ zephyr_library() +zephyr_library_include_directories(include) + # Library may be empty due to kconfigs zephyr_library_property(ALLOW_EMPTY TRUE) diff --git a/arch/common/include/sw_isr_common.h b/arch/common/include/sw_isr_common.h new file mode 100644 index 000000000000000..223c9ba2442a2f3 --- /dev/null +++ b/arch/common/include/sw_isr_common.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Private header for the software-managed ISR table's functions + */ + +#ifndef ZEPHYR_ARCH_COMMON_INCLUDE_SW_ISR_COMMON_H_ +#define ZEPHYR_ARCH_COMMON_INCLUDE_SW_ISR_COMMON_H_ + +#if !defined(_ASMLANGUAGE) +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Helper function used to compute the index in _sw_isr_table + * based on passed IRQ. + * + * @param irq IRQ number in its zephyr format + * + * @return corresponding index in _sw_isr_table + */ +unsigned int z_get_sw_isr_table_idx(unsigned int irq); + +/** + * @brief Helper function used to get the parent interrupt controller device based on passed IRQ. + * + * @param irq IRQ number in its zephyr format + * + * @return corresponding interrupt controller device in _sw_isr_table + */ +const struct device *z_get_sw_isr_device_from_irq(unsigned int irq); + +/** + * @brief Helper function used to get the IRQN of the passed in parent interrupt + * controller device. + * + * @param dev parent interrupt controller device + * + * @return IRQN of the interrupt controller + */ +unsigned int z_get_sw_isr_irq_from_device(const struct device *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_ARCH_COMMON_INCLUDE_SW_ISR_COMMON_H_ */ diff --git a/arch/common/shared_irq.c b/arch/common/shared_irq.c index 744aece2fd7ca65..68641cb2bb0d1ae 100644 --- a/arch/common/shared_irq.c +++ b/arch/common/shared_irq.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "sw_isr_common.h" + #include #include diff --git a/include/zephyr/sw_isr_table.h b/include/zephyr/sw_isr_table.h index fb68272c34c6b3a..f43efafad492be5 100644 --- a/include/zephyr/sw_isr_table.h +++ b/include/zephyr/sw_isr_table.h @@ -84,35 +84,6 @@ void z_shared_isr(const void *data); extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; #endif /* CONFIG_SHARED_INTERRUPTS */ -/** - * @brief Helper function used to compute the index in _sw_isr_table - * based on passed IRQ. - * - * @param irq IRQ number in its zephyr format - * - * @return corresponding index in _sw_isr_table - */ -unsigned int z_get_sw_isr_table_idx(unsigned int irq); - -/** - * @brief Helper function used to get the parent interrupt controller device based on passed IRQ. - * - * @param irq IRQ number in its zephyr format - * - * @return corresponding interrupt controller device in _sw_isr_table - */ -const struct device *z_get_sw_isr_device_from_irq(unsigned int irq); - -/** - * @brief Helper function used to get the IRQN of the passed in parent interrupt - * controller device. - * - * @param dev parent interrupt controller device - * - * @return IRQN of the interrupt controller - */ -unsigned int z_get_sw_isr_irq_from_device(const struct device *dev); - /** This interrupt gets put directly in the vector table */ #define ISR_FLAG_DIRECT BIT(0) diff --git a/tests/kernel/interrupt/CMakeLists.txt b/tests/kernel/interrupt/CMakeLists.txt index 645f1f7965b676d..b464719f89a65bd 100644 --- a/tests/kernel/interrupt/CMakeLists.txt +++ b/tests/kernel/interrupt/CMakeLists.txt @@ -7,6 +7,7 @@ project(interrupt) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/kernel/include ${ZEPHYR_BASE}/arch/${ARCH}/include + ${ZEPHYR_BASE}/arch/common/include ) target_sources(app PRIVATE diff --git a/tests/kernel/interrupt/src/sw_isr_table.c b/tests/kernel/interrupt/src/sw_isr_table.c index 621480905a71e2c..385f2c244b5d261 100644 --- a/tests/kernel/interrupt/src/sw_isr_table.c +++ b/tests/kernel/interrupt/src/sw_isr_table.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "sw_isr_common.h" + #include extern const struct _irq_parent_entry _lvl2_irq_list[]; From cdb606aa033053a449e470921c086921fc6548fa Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 6 Nov 2023 15:27:30 +0800 Subject: [PATCH 0096/1049] arch: common: refactor multi-level IRQ code Refactor multi-level IRQ related code from `sw_isr_common.c` to `multilevel_irq.c` to simplify `sw_isr_common` & macrologies. Signed-off-by: Yong Cong Sin --- arch/common/CMakeLists.txt | 5 + arch/common/multilevel_irq.c | 167 ++++++++++++++++++++++++++++++++ arch/common/sw_isr_common.c | 182 +---------------------------------- 3 files changed, 177 insertions(+), 177 deletions(-) create mode 100644 arch/common/multilevel_irq.c diff --git a/arch/common/CMakeLists.txt b/arch/common/CMakeLists.txt index 7421e44631add95..e1353c1eaabb04b 100644 --- a/arch/common/CMakeLists.txt +++ b/arch/common/CMakeLists.txt @@ -12,6 +12,11 @@ zephyr_library_sources_ifdef( sw_isr_common.c ) +zephyr_library_sources_ifdef( + CONFIG_MULTI_LEVEL_INTERRUPTS + multilevel_irq.c + ) + zephyr_library_sources_ifdef(CONFIG_SHARED_INTERRUPTS shared_irq.c) if(NOT CONFIG_ARCH_HAS_TIMING_FUNCTIONS AND diff --git a/arch/common/multilevel_irq.c b/arch/common/multilevel_irq.c new file mode 100644 index 000000000000000..96f3ab0801f28d5 --- /dev/null +++ b/arch/common/multilevel_irq.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * Copyright (c) 2023 Meta. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* + * Insert code if the node_id is an interrupt controller + */ +#define Z_IF_DT_IS_INTC(node_id, code) \ + IF_ENABLED(DT_NODE_HAS_PROP(node_id, interrupt_controller), (code)) + +/* + * Expands to node_id if its IRQN is equal to `irq`, nothing otherwise + * This only works for `irq` between 0 & 4095, see `IS_EQ` + */ +#define Z_IF_DT_INTC_IRQN_EQ(node_id, irq) IF_ENABLED(IS_EQ(DT_IRQ(node_id, irq), irq), (node_id)) + +/* + * Expands to node_id if it's an interrupt controller & its IRQN is `irq`, or nothing otherwise + */ +#define Z_DT_INTC_GET_IRQN(node_id, irq) \ + Z_IF_DT_IS_INTC(node_id, Z_IF_DT_INTC_IRQN_EQ(node_id, irq)) + +/** + * Loop through child of "/soc" and get root interrupt controllers with `irq` as IRQN, + * this assumes only one device has the IRQN + * @param irq irq number + * @return node_id(s) that has the `irq` number, or empty if none of them has the `irq` + */ +#define INTC_DT_IRQN_GET(irq) \ + DT_FOREACH_CHILD_STATUS_OKAY_VARGS(DT_PATH(soc), Z_DT_INTC_GET_IRQN, irq) + +/* If can't find any matching interrupt controller, fills with `NULL` */ +#define INTC_DEVICE_INIT(node_id) .dev = DEVICE_DT_GET_OR_NULL(node_id), + +#define INIT_IRQ_PARENT_OFFSET(d, i, o) { \ + INTC_DEVICE_INIT(d) \ + .irq = i, \ + .offset = o, \ +} + +#define IRQ_INDEX_TO_OFFSET(i, base) (base + i * CONFIG_MAX_IRQ_PER_AGGREGATOR) + +#define CAT_2ND_LVL_LIST(i, base) \ + INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_2ND_LVL_INTR_0##i##_OFFSET), \ + CONFIG_2ND_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) +const struct _irq_parent_entry _lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] + = { LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, CAT_2ND_LVL_LIST, (,), + CONFIG_2ND_LVL_ISR_TBL_OFFSET) }; + +#define CAT_3RD_LVL_LIST(i, base) \ + INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET), \ + CONFIG_3RD_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) + +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + +const struct _irq_parent_entry _lvl3_irq_list[CONFIG_NUM_3RD_LEVEL_AGGREGATORS] + = { LISTIFY(CONFIG_NUM_3RD_LEVEL_AGGREGATORS, CAT_3RD_LVL_LIST, (,), + CONFIG_3RD_LVL_ISR_TBL_OFFSET) }; + +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ + +static const struct _irq_parent_entry *get_parent_entry(unsigned int parent_irq, + const struct _irq_parent_entry list[], + unsigned int length) +{ + unsigned int i; + const struct _irq_parent_entry *entry = NULL; + + for (i = 0U; i < length; ++i) { + if (list[i].irq == parent_irq) { + entry = &list[i]; + break; + } + } + + __ASSERT(i != length, "Invalid argument: %i", parent_irq); + + return entry; +} + +const struct device *z_get_sw_isr_device_from_irq(unsigned int irq) +{ + const struct device *dev = NULL; + unsigned int level, parent_irq; + const struct _irq_parent_entry *entry = NULL; + + level = irq_get_level(irq); + + if (level == 2U) { + parent_irq = irq_parent_level_2(irq); + entry = get_parent_entry(parent_irq, + _lvl2_irq_list, + CONFIG_NUM_2ND_LEVEL_AGGREGATORS); + } +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + else if (level == 3U) { + parent_irq = irq_parent_level_3(irq); + entry = get_parent_entry(parent_irq, + _lvl3_irq_list, + CONFIG_NUM_3RD_LEVEL_AGGREGATORS); + } +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ + dev = entry != NULL ? entry->dev : NULL; + + return dev; +} + +unsigned int z_get_sw_isr_irq_from_device(const struct device *dev) +{ + for (size_t i = 0U; i < CONFIG_NUM_2ND_LEVEL_AGGREGATORS; ++i) { + if (_lvl2_irq_list[i].dev == dev) { + return _lvl2_irq_list[i].irq; + } + } + +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + for (size_t i = 0U; i < CONFIG_NUM_3RD_LEVEL_AGGREGATORS; ++i) { + if (_lvl3_irq_list[i].dev == dev) { + return _lvl3_irq_list[i].irq; + } + } +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ + + return 0; +} + +unsigned int z_get_sw_isr_table_idx(unsigned int irq) +{ + unsigned int table_idx; + unsigned int level, parent_irq, parent_offset; + const struct _irq_parent_entry *entry = NULL; + + level = irq_get_level(irq); + + if (level == 2U) { + parent_irq = irq_parent_level_2(irq); + entry = get_parent_entry(parent_irq, + _lvl2_irq_list, + CONFIG_NUM_2ND_LEVEL_AGGREGATORS); + parent_offset = entry != NULL ? entry->offset : 0U; + table_idx = parent_offset + irq_from_level_2(irq); + } +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + else if (level == 3U) { + parent_irq = irq_parent_level_3(irq); + entry = get_parent_entry(parent_irq, + _lvl3_irq_list, + CONFIG_NUM_3RD_LEVEL_AGGREGATORS); + parent_offset = entry != NULL ? entry->offset : 0U; + table_idx = parent_offset + irq_from_level_3(irq); + } +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ + else { + table_idx = irq; + } + + table_idx -= CONFIG_GEN_IRQ_START_VECTOR; + + return table_idx; +} diff --git a/arch/common/sw_isr_common.c b/arch/common/sw_isr_common.c index 907fbfdfa169ad1..9ed50e1084fa34a 100644 --- a/arch/common/sw_isr_common.c +++ b/arch/common/sw_isr_common.c @@ -4,193 +4,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include "sw_isr_common.h" #include -#include #include -#include #include -/* - * Common code for arches that use software ISR tables (CONFIG_GEN_ISR_TABLES) - */ - -#ifdef CONFIG_DYNAMIC_INTERRUPTS - -#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS /* - * Insert code if the node_id is an interrupt controller - */ -#define Z_IF_DT_IS_INTC(node_id, code) \ - IF_ENABLED(DT_NODE_HAS_PROP(node_id, interrupt_controller), (code)) - -/* - * Expands to node_id if its IRQN is equal to `irq`, nothing otherwise - * This only works for `irq` between 0 & 4095, see `IS_EQ` - */ -#define Z_IF_DT_INTC_IRQN_EQ(node_id, irq) IF_ENABLED(IS_EQ(DT_IRQ(node_id, irq), irq), (node_id)) - -/* - * Expands to node_id if it's an interrupt controller & its IRQN is `irq`, or nothing otherwise - */ -#define Z_DT_INTC_GET_IRQN(node_id, irq) \ - Z_IF_DT_IS_INTC(node_id, Z_IF_DT_INTC_IRQN_EQ(node_id, irq)) - -/** - * Loop through child of "/soc" and get root interrupt controllers with `irq` as IRQN, - * this assumes only one device has the IRQN - * @param irq irq number - * @return node_id(s) that has the `irq` number, or empty if none of them has the `irq` + * Common code for arches that use software ISR tables (CONFIG_GEN_ISR_TABLES) */ -#define INTC_DT_IRQN_GET(irq) \ - DT_FOREACH_CHILD_STATUS_OKAY_VARGS(DT_PATH(soc), Z_DT_INTC_GET_IRQN, irq) - -/* If can't find any matching interrupt controller, fills with `NULL` */ -#define INTC_DEVICE_INIT(node_id) .dev = DEVICE_DT_GET_OR_NULL(node_id), - -#define INIT_IRQ_PARENT_OFFSET(d, i, o) { \ - INTC_DEVICE_INIT(d) \ - .irq = i, \ - .offset = o, \ -} - -#define IRQ_INDEX_TO_OFFSET(i, base) (base + i * CONFIG_MAX_IRQ_PER_AGGREGATOR) - -#ifdef CONFIG_2ND_LEVEL_INTERRUPTS - -#define CAT_2ND_LVL_LIST(i, base) \ - INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_2ND_LVL_INTR_0##i##_OFFSET), \ - CONFIG_2ND_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) -const struct _irq_parent_entry _lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] - = { LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, CAT_2ND_LVL_LIST, (,), - CONFIG_2ND_LVL_ISR_TBL_OFFSET) }; - -#endif/* CONFIG_2ND_LEVEL_INTERRUPTS */ - -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS - -#define CAT_3RD_LVL_LIST(i, base) \ - INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET), \ - CONFIG_3RD_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) -const struct _irq_parent_entry _lvl3_irq_list[CONFIG_NUM_3RD_LEVEL_AGGREGATORS] - = { LISTIFY(CONFIG_NUM_3RD_LEVEL_AGGREGATORS, CAT_3RD_LVL_LIST, (,), - CONFIG_3RD_LVL_ISR_TBL_OFFSET) }; - -#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ -static const struct _irq_parent_entry *get_parent_entry(unsigned int parent_irq, - const struct _irq_parent_entry list[], - unsigned int length) +unsigned int __weak z_get_sw_isr_table_idx(unsigned int irq) { - unsigned int i; - const struct _irq_parent_entry *entry = NULL; - - for (i = 0U; i < length; ++i) { - if (list[i].irq == parent_irq) { - entry = &list[i]; - break; - } - } - - __ASSERT(i != length, "Invalid argument: %i", parent_irq); - - return entry; + return irq - CONFIG_GEN_IRQ_START_VECTOR; } -#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ - -const struct device *z_get_sw_isr_device_from_irq(unsigned int irq) -{ - const struct device *dev = NULL; - -#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS - unsigned int level, parent_irq; - const struct _irq_parent_entry *entry = NULL; - - level = irq_get_level(irq); - - if (level == 2U) { - parent_irq = irq_parent_level_2(irq); - entry = get_parent_entry(parent_irq, - _lvl2_irq_list, - CONFIG_NUM_2ND_LEVEL_AGGREGATORS); - } -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS - else if (level == 3U) { - parent_irq = irq_parent_level_3(irq); - entry = get_parent_entry(parent_irq, - _lvl3_irq_list, - CONFIG_NUM_3RD_LEVEL_AGGREGATORS); - } -#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ - dev = entry != NULL ? entry->dev : NULL; -#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ - - return dev; -} - -unsigned int z_get_sw_isr_irq_from_device(const struct device *dev) -{ -#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS - for (size_t i = 0U; i < CONFIG_NUM_2ND_LEVEL_AGGREGATORS; ++i) { - if (_lvl2_irq_list[i].dev == dev) { - return _lvl2_irq_list[i].irq; - } - } - -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS - for (size_t i = 0U; i < CONFIG_NUM_3RD_LEVEL_AGGREGATORS; ++i) { - if (_lvl3_irq_list[i].dev == dev) { - return _lvl3_irq_list[i].irq; - } - } -#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ -#else - ARG_UNUSED(dev); -#endif - - return 0; -} - -unsigned int z_get_sw_isr_table_idx(unsigned int irq) -{ - unsigned int table_idx; - -#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS - unsigned int level, parent_irq, parent_offset; - const struct _irq_parent_entry *entry = NULL; - - level = irq_get_level(irq); - - if (level == 2U) { - parent_irq = irq_parent_level_2(irq); - entry = get_parent_entry(parent_irq, - _lvl2_irq_list, - CONFIG_NUM_2ND_LEVEL_AGGREGATORS); - parent_offset = entry != NULL ? entry->offset : 0U; - table_idx = parent_offset + irq_from_level_2(irq); - } -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS - else if (level == 3U) { - parent_irq = irq_parent_level_3(irq); - entry = get_parent_entry(parent_irq, - _lvl3_irq_list, - CONFIG_NUM_3RD_LEVEL_AGGREGATORS); - parent_offset = entry != NULL ? entry->offset : 0U; - table_idx = parent_offset + irq_from_level_3(irq); - } -#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ - else { - table_idx = irq; - } - - table_idx -= CONFIG_GEN_IRQ_START_VECTOR; -#else - table_idx = irq - CONFIG_GEN_IRQ_START_VECTOR; -#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ - - return table_idx; -} +#ifdef CONFIG_DYNAMIC_INTERRUPTS void __weak z_isr_install(unsigned int irq, void (*routine)(const void *), const void *param) From 63bd547e9f084013a25f8ce61da6f05b4c663b59 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 6 Nov 2023 15:37:52 +0800 Subject: [PATCH 0097/1049] arch: common: guard the compilation of sw_isr_common with CMakeLists.txt Instead of using a macro guard to prevent functions in `sw_isr_common.c` from getting compiled when `CONFIG_DYNAMIC_INTERRUPTS` isn't enabled, do that in `CMakeLists.txt` instead. Signed-off-by: Yong Cong Sin --- arch/common/CMakeLists.txt | 11 ++++++--- arch/common/dynamic_isr.c | 49 +++++++++++++++++++++++++++++++++++++ arch/common/sw_isr_common.c | 43 -------------------------------- 3 files changed, 57 insertions(+), 46 deletions(-) create mode 100644 arch/common/dynamic_isr.c diff --git a/arch/common/CMakeLists.txt b/arch/common/CMakeLists.txt index e1353c1eaabb04b..1a89ba9c13aa86c 100644 --- a/arch/common/CMakeLists.txt +++ b/arch/common/CMakeLists.txt @@ -7,10 +7,15 @@ zephyr_library_include_directories(include) # Library may be empty due to kconfigs zephyr_library_property(ALLOW_EMPTY TRUE) -zephyr_library_sources_ifdef( - CONFIG_GEN_ISR_TABLES - sw_isr_common.c +if(CONFIG_GEN_ISR_TABLES) + zephyr_library_sources( + sw_isr_common.c ) + zephyr_library_sources_ifdef( + CONFIG_DYNAMIC_INTERRUPTS + dynamic_isr.c + ) +endif() zephyr_library_sources_ifdef( CONFIG_MULTI_LEVEL_INTERRUPTS diff --git a/arch/common/dynamic_isr.c b/arch/common/dynamic_isr.c new file mode 100644 index 000000000000000..9f56977f2599847 --- /dev/null +++ b/arch/common/dynamic_isr.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sw_isr_common.h" +#include +#include +#include + +void __weak z_isr_install(unsigned int irq, void (*routine)(const void *), + const void *param) +{ + unsigned int table_idx; + + /* + * Do not assert on the IRQ enable status for ARM GIC since the SGI + * type interrupts are always enabled and attempting to install an ISR + * for them will cause the assertion to fail. + */ +#ifndef CONFIG_GIC + __ASSERT(!irq_is_enabled(irq), "IRQ %d is enabled", irq); +#endif /* !CONFIG_GIC */ + + table_idx = z_get_sw_isr_table_idx(irq); + + /* If dynamic IRQs are enabled, then the _sw_isr_table is in RAM and + * can be modified + */ + _sw_isr_table[table_idx].arg = param; + _sw_isr_table[table_idx].isr = routine; +} + +/* Some architectures don't/can't interpret flags or priority and have + * no more processing to do than this. Provide a generic fallback. + */ +int __weak arch_irq_connect_dynamic(unsigned int irq, + unsigned int priority, + void (*routine)(const void *), + const void *parameter, + uint32_t flags) +{ + ARG_UNUSED(flags); + ARG_UNUSED(priority); + + z_isr_install(irq, routine, parameter); + return irq; +} diff --git a/arch/common/sw_isr_common.c b/arch/common/sw_isr_common.c index 9ed50e1084fa34a..5efdeb89a670c05 100644 --- a/arch/common/sw_isr_common.c +++ b/arch/common/sw_isr_common.c @@ -17,46 +17,3 @@ unsigned int __weak z_get_sw_isr_table_idx(unsigned int irq) { return irq - CONFIG_GEN_IRQ_START_VECTOR; } - -#ifdef CONFIG_DYNAMIC_INTERRUPTS - -void __weak z_isr_install(unsigned int irq, void (*routine)(const void *), - const void *param) -{ - unsigned int table_idx; - - /* - * Do not assert on the IRQ enable status for ARM GIC since the SGI - * type interrupts are always enabled and attempting to install an ISR - * for them will cause the assertion to fail. - */ -#ifndef CONFIG_GIC - __ASSERT(!irq_is_enabled(irq), "IRQ %d is enabled", irq); -#endif /* !CONFIG_GIC */ - - table_idx = z_get_sw_isr_table_idx(irq); - - /* If dynamic IRQs are enabled, then the _sw_isr_table is in RAM and - * can be modified - */ - _sw_isr_table[table_idx].arg = param; - _sw_isr_table[table_idx].isr = routine; -} - -/* Some architectures don't/can't interpret flags or priority and have - * no more processing to do than this. Provide a generic fallback. - */ -int __weak arch_irq_connect_dynamic(unsigned int irq, - unsigned int priority, - void (*routine)(const void *), - const void *parameter, - uint32_t flags) -{ - ARG_UNUSED(flags); - ARG_UNUSED(priority); - - z_isr_install(irq, routine, parameter); - return irq; -} - -#endif /* CONFIG_DYNAMIC_INTERRUPTS */ From 7485ef91f54a682c8061a38e7da523ee483f5ed4 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 6 Nov 2023 15:53:50 +0800 Subject: [PATCH 0098/1049] irq: multilevel: reduce the use of macros Convert `#if defined CONFIG_*` to use `if (IS_ENABLED(CONFIG_*))` and removed some macro guards since they are safe to be compile. Signed-off-by: Yong Cong Sin --- include/zephyr/irq_multilevel.h | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/include/zephyr/irq_multilevel.h b/include/zephyr/irq_multilevel.h index 7d320ca1419797f..3a2b5116602b5ca 100644 --- a/include/zephyr/irq_multilevel.h +++ b/include/zephyr/irq_multilevel.h @@ -45,7 +45,6 @@ static inline unsigned int irq_get_level(unsigned int irq) return 1; } -#if defined(CONFIG_2ND_LEVEL_INTERRUPTS) /** * @brief Return the 2nd level interrupt number * @@ -58,12 +57,12 @@ static inline unsigned int irq_get_level(unsigned int irq) */ static inline unsigned int irq_from_level_2(unsigned int irq) { -#if defined(CONFIG_3RD_LEVEL_INTERRUPTS) - return ((irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) & - BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1; -#else - return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) - 1; -#endif + if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS)) { + return ((irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) & + BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1; + } else { + return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) - 1; + } } /** @@ -106,9 +105,7 @@ static inline unsigned int irq_parent_level_2(unsigned int irq) { return irq & BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS); } -#endif -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS /** * @brief Return the 3rd level interrupt number * @@ -167,7 +164,6 @@ static inline unsigned int irq_parent_level_3(unsigned int irq) return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) & BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); } -#endif #ifdef __cplusplus } From 7f7b097499e4ca212ccd554b52e94367d722cfa3 Mon Sep 17 00:00:00 2001 From: Piotr Narajowski Date: Thu, 28 Sep 2023 13:25:34 +0200 Subject: [PATCH 0099/1049] bluetooth: tester: MCP Client tests Add support for Media Control Client tests Signed-off-by: Piotr Narajowski --- tests/bluetooth/tester/CMakeLists.txt | 4 + tests/bluetooth/tester/overlay-le-audio.conf | 5 + tests/bluetooth/tester/src/btp/btp.h | 4 +- tests/bluetooth/tester/src/btp/btp_mcp.h | 291 ++++ tests/bluetooth/tester/src/btp/bttester.h | 3 + tests/bluetooth/tester/src/btp_core.c | 13 + tests/bluetooth/tester/src/btp_mcp.c | 1319 ++++++++++++++++++ 7 files changed, 1638 insertions(+), 1 deletion(-) create mode 100644 tests/bluetooth/tester/src/btp/btp_mcp.h create mode 100644 tests/bluetooth/tester/src/btp_mcp.c diff --git a/tests/bluetooth/tester/CMakeLists.txt b/tests/bluetooth/tester/CMakeLists.txt index d76de937f5d7924..842b6ebe5d8f2bd 100644 --- a/tests/bluetooth/tester/CMakeLists.txt +++ b/tests/bluetooth/tester/CMakeLists.txt @@ -59,3 +59,7 @@ endif() if (CONFIG_BT_CAP_ACCEPTOR) target_sources(app PRIVATE src/btp_cas.c) endif() + +if(CONFIG_BT_MCC) + target_sources(app PRIVATE src/btp_mcp.c) +endif() diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index 1db37efb5a3d816..530558c1308c09c 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -92,3 +92,8 @@ CONFIG_BT_TBS_CLIENT_TBS=n # CAS CONFIG_BT_CAP_ACCEPTOR=y CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER=y + +# MCP +CONFIG_BT_MCC=y +CONFIG_BT_OTS_CLIENT=y +CONFIG_BT_MCC_OTS=y diff --git a/tests/bluetooth/tester/src/btp/btp.h b/tests/bluetooth/tester/src/btp/btp.h index b1092dc6d5dabf8..c77819328017de9 100644 --- a/tests/bluetooth/tester/src/btp/btp.h +++ b/tests/bluetooth/tester/src/btp/btp.h @@ -30,6 +30,7 @@ #include "btp_ccp.h" #include "btp_vcp.h" #include "btp_cas.h" +#include "btp_mcp.h" #define BTP_MTU 1024 #define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) @@ -59,8 +60,9 @@ #define BTP_SERVICE_ID_CCP 19 #define BTP_SERVICE_ID_VCP 20 #define BTP_SERVICE_ID_CAS 21 +#define BTP_SERVICE_ID_MCP 22 -#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_CAS +#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_MCP #define BTP_STATUS_SUCCESS 0x00 #define BTP_STATUS_FAILED 0x01 diff --git a/tests/bluetooth/tester/src/btp/btp_mcp.h b/tests/bluetooth/tester/src/btp/btp_mcp.h new file mode 100644 index 000000000000000..d9b7f84e4101d48 --- /dev/null +++ b/tests/bluetooth/tester/src/btp/btp_mcp.h @@ -0,0 +1,291 @@ +/* btp_mcp.h - Bluetooth tester headers */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/* MCP commands */ +#define BTP_MCP_READ_SUPPORTED_COMMANDS 0x01 +struct btp_mcp_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_MCP_DISCOVER 0x02 +struct btp_mcp_discover_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_TRACK_DURATION_READ 0x03 +struct btp_mcp_track_duration_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_TRACK_POSITION_READ 0x04 +struct btp_mcp_track_position_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_TRACK_POSITION_SET 0x05 +struct btp_mcp_track_position_set_cmd { + bt_addr_le_t address; + int32_t pos; +} __packed; + +#define BTP_MCP_PLAYBACK_SPEED_READ 0x06 +struct btp_mcp_playback_speed_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_PLAYBACK_SPEED_SET 0x07 +struct btp_mcp_playback_speed_set { + bt_addr_le_t address; + int8_t speed; +} __packed; + +#define BTP_MCP_SEEKING_SPEED_READ 0x08 +struct btp_mcp_seeking_speed_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_ICON_OBJ_ID_READ 0x09 +struct btp_mcp_icon_obj_id_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_NEXT_TRACK_OBJ_ID_READ 0x0a +struct btp_mcp_next_track_obj_id_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_NEXT_TRACK_OBJ_ID_SET 0x0b +struct btp_mcp_set_next_track_obj_id_cmd { + bt_addr_le_t address; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCP_PARENT_GROUP_OBJ_ID_READ 0x0c +struct btp_mcp_parent_group_obj_id_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_CURRENT_GROUP_OBJ_ID_READ 0x0d +struct btp_mcp_current_group_obj_id_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_CURRENT_GROUP_OBJ_ID_SET 0x0e +struct btp_mcp_current_group_obj_id_set_cmd { + bt_addr_le_t address; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCP_PLAYING_ORDER_READ 0x0f +struct btp_mcp_playing_order_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_PLAYING_ORDER_SET 0x10 +struct btp_mcp_playing_order_set_cmd { + bt_addr_le_t address; + uint8_t order; +} __packed; + +#define BTP_MCP_PLAYING_ORDERS_SUPPORTED_READ 0x11 +struct btp_mcp_playing_orders_supported_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_MEDIA_STATE_READ 0x12 +struct btp_mcp_media_state_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_OPCODES_SUPPORTED_READ 0x13 +struct btp_mcp_opcodes_supported_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_CONTENT_CONTROL_ID_READ 0x14 +struct btp_mcp_content_control_id_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_SEGMENTS_OBJ_ID_READ 0x15 +struct btp_mcp_segments_obj_id_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_CURRENT_TRACK_OBJ_ID_READ 0x16 +struct btp_mcp_current_track_obj_id_read_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_MCP_CURRENT_TRACK_OBJ_ID_SET 0x17 +struct btp_mcp_current_track_obj_id_set_cmd { + bt_addr_le_t address; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCP_CMD_SEND 0x18 +struct btp_mcp_send_cmd { + bt_addr_le_t address; + uint8_t opcode; + uint8_t use_param; + int32_t param; +} __packed; + +#define BTP_MCP_CMD_SEARCH 0x19 +struct btp_mcp_search_cmd { + bt_addr_le_t address; + uint8_t type; + uint8_t param_len; + uint8_t param[]; +} __packed; + +/* MCP events */ +#define BTP_MCP_DISCOVERED_EV 0x80 +struct btp_mcp_discovered_ev { + bt_addr_le_t address; + uint8_t status; +} __packed; + +#define BTP_MCP_TRACK_DURATION_EV 0x81 +struct btp_mcp_track_duration_ev { + bt_addr_le_t address; + uint8_t status; + int32_t dur; +} __packed; + +#define BTP_MCP_TRACK_POSITION_EV 0x82 +struct btp_mcp_track_position_ev { + bt_addr_le_t address; + uint8_t status; + int32_t pos; +} __packed; + +#define BTP_MCP_PLAYBACK_SPEED_EV 0x83 +struct btp_mcp_playback_speed_ev { + bt_addr_le_t address; + uint8_t status; + int8_t speed; +} __packed; + +#define BTP_MCP_SEEKING_SPEED_EV 0x84 +struct btp_mcp_seeking_speed_ev { + bt_addr_le_t address; + uint8_t status; + int8_t speed; +} __packed; + +#define BTP_MCP_ICON_OBJ_ID_EV 0x85 +struct btp_mcp_icon_obj_id_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCP_NEXT_TRACK_OBJ_ID_EV 0x86 +struct btp_mcp_next_track_obj_id_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCP_PARENT_GROUP_OBJ_ID_EV 0x87 +struct btp_mcp_parent_group_obj_id_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCP_CURRENT_GROUP_OBJ_ID_EV 0x88 +struct btp_mcp_current_group_obj_id_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCP_PLAYING_ORDER_EV 0x89 +struct btp_mcp_playing_order_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t order; +} __packed; + +#define BTP_MCP_PLAYING_ORDERS_SUPPORTED_EV 0x8a +struct btp_mcp_playing_orders_supported_ev { + bt_addr_le_t address; + uint8_t status; + uint16_t orders; +} __packed; + +#define BTP_MCP_MEDIA_STATE_EV 0x8b +struct btp_mcp_media_state_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t state; +} __packed; + +#define BTP_MCP_OPCODES_SUPPORTED_EV 0x8c +struct btp_mcp_opcodes_supported_ev { + bt_addr_le_t address; + uint8_t status; + uint32_t opcodes; +} __packed; + +#define BTP_MCP_CONTENT_CONTROL_ID_EV 0x8d +struct btp_mcp_content_control_id_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t ccid; +} __packed; + +#define BTP_MCP_SEGMENTS_OBJ_ID_EV 0x8e +struct btp_mcp_segments_obj_id_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCP_CURRENT_TRACK_OBJ_ID_EV 0x8f +struct btp_mcp_current_track_obj_id_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t id[BT_OTS_OBJ_ID_SIZE]; +} __packed; + +#define BTP_MCP_MEDIA_CP_EV 0x90 +struct btp_mcp_media_cp_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t opcode; + bool use_param; + int32_t param; +} __packed; + +#define BTP_MCP_SEARCH_CP_EV 0x91 +struct btp_mcp_search_cp_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t param_len; + uint8_t search_type; + uint8_t param[]; +} __packed; + +#define BTP_MCP_NTF_EV 0x92 +struct btp_mcp_cmd_ntf_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t requested_opcode; + uint8_t result_code; +} __packed; + +#define BTP_SCP_NTF_EV 0x93 +struct btp_scp_cmd_ntf_ev { + bt_addr_le_t address; + uint8_t status; + uint8_t result_code; +} __packed; diff --git a/tests/bluetooth/tester/src/btp/bttester.h b/tests/bluetooth/tester/src/btp/bttester.h index b6ddc561cf42cb5..ce8b1259a42de4b 100644 --- a/tests/bluetooth/tester/src/btp/bttester.h +++ b/tests/bluetooth/tester/src/btp/bttester.h @@ -114,3 +114,6 @@ uint8_t tester_unregister_vcp(void); uint8_t tester_init_cas(void); uint8_t tester_unregister_cas(void); + +uint8_t tester_init_mcp(void); +uint8_t tester_unregister_mcp(void); diff --git a/tests/bluetooth/tester/src/btp_core.c b/tests/bluetooth/tester/src/btp_core.c index b91aa5be1e160e3..1840d2d5d0b80f2 100644 --- a/tests/bluetooth/tester/src/btp_core.c +++ b/tests/bluetooth/tester/src/btp_core.c @@ -92,6 +92,9 @@ static uint8_t supported_services(const void *cmd, uint16_t cmd_len, #if defined(CONFIG_BT_CAP_ACCEPTOR) tester_set_bit(rp->data, BTP_SERVICE_ID_CAS); #endif /* CONFIG_BT_CAP_ACCEPTOR */ +#if defined(CONFIG_BT_MCC) + tester_set_bit(rp->data, BTP_SERVICE_ID_MCP); +#endif /* CONFIG_BT_MCC */ *rsp_len = sizeof(*rp) + 2; @@ -192,6 +195,11 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len, status = tester_init_cas(); break; #endif /* CONFIG_BT_CAP_ACCEPTOR */ +#if defined(CONFIG_BT_MCC) + case BTP_SERVICE_ID_MCP: + status = tester_init_mcp(); + break; +#endif /* CONFIG_BT_MCC */ default: LOG_WRN("unknown id: 0x%02x", cp->id); status = BTP_STATUS_FAILED; @@ -291,6 +299,11 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len, status = tester_unregister_cas(); break; #endif /* CONFIG_BT_CAP_ACCEPTOR */ +#if defined(CONFIG_BT_MCC) + case BTP_SERVICE_ID_MCP: + status = tester_unregister_mcp(); + break; +#endif /* CONFIG_BT_MCC */ default: LOG_WRN("unknown id: 0x%x", cp->id); status = BTP_STATUS_FAILED; diff --git a/tests/bluetooth/tester/src/btp_mcp.c b/tests/bluetooth/tester/src/btp_mcp.c new file mode 100644 index 000000000000000..d04dca35dc08803 --- /dev/null +++ b/tests/bluetooth/tester/src/btp_mcp.c @@ -0,0 +1,1319 @@ +/* btp_mcp.c - Bluetooth MCP Tester */ + +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "bap_endpoint.h" +#include "btp/btp.h" +#include "../../../../include/zephyr/bluetooth/audio/media_proxy.h" + +#define LOG_MODULE_NAME bttester_mcp +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); + +#define SEARCH_LEN_MAX 64 + +static struct net_buf_simple *rx_ev_buf = NET_BUF_SIMPLE(SEARCH_LEN_MAX + + sizeof(struct btp_mcp_search_cp_ev)); + +/* Media Control Profile */ +static void btp_send_mcp_found_ev(struct bt_conn *conn, uint8_t status) +{ + struct btp_mcp_discovered_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_DISCOVERED_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_track_duration_ev(struct bt_conn *conn, uint8_t status, int32_t dur) +{ + struct btp_mcp_track_duration_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.dur = sys_cpu_to_le32(dur); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_TRACK_DURATION_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_track_position_ev(struct bt_conn *conn, uint8_t status, int32_t pos) +{ + struct btp_mcp_track_position_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.pos = sys_cpu_to_le32(pos); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_TRACK_POSITION_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_playback_speed_ev(struct bt_conn *conn, uint8_t status, int8_t speed) +{ + struct btp_mcp_playback_speed_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.speed = speed; + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_PLAYBACK_SPEED_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_seeking_speed_ev(struct bt_conn *conn, uint8_t status, int8_t speed) +{ + struct btp_mcp_seeking_speed_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.speed = speed; + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_SEEKING_SPEED_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_icon_obj_id_ev(struct bt_conn *conn, uint8_t status, uint64_t id) +{ + struct btp_mcp_icon_obj_id_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + sys_put_le48(id, ev.id); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_ICON_OBJ_ID_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_next_track_obj_id_ev(struct bt_conn *conn, uint8_t status, + uint64_t id) +{ + struct btp_mcp_next_track_obj_id_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + sys_put_le48(id, ev.id); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_NEXT_TRACK_OBJ_ID_EV, &ev, sizeof(ev)); +} + +static void btp_send_parent_group_obj_id_ev(struct bt_conn *conn, uint8_t status, uint64_t id) +{ + struct btp_mcp_parent_group_obj_id_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + sys_put_le48(id, ev.id); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_PARENT_GROUP_OBJ_ID_EV, &ev, sizeof(ev)); +} + +static void btp_send_current_group_obj_id_ev(struct bt_conn *conn, uint8_t status, uint64_t id) +{ + struct btp_mcp_current_group_obj_id_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + sys_put_le48(id, ev.id); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_CURRENT_GROUP_OBJ_ID_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_playing_order_ev(struct bt_conn *conn, uint8_t status, uint8_t order) +{ + struct btp_mcp_playing_order_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.order = order; + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_PLAYING_ORDER_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_playing_orders_supported_ev(struct bt_conn *conn, uint8_t status, + uint16_t orders) +{ + struct btp_mcp_playing_orders_supported_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.orders = sys_cpu_to_le16(orders); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_PLAYING_ORDERS_SUPPORTED_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_media_state_ev(struct bt_conn *conn, uint8_t status, uint8_t state) +{ + struct btp_mcp_media_state_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.state = state; + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_MEDIA_STATE_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_opcodes_supported_ev(struct bt_conn *conn, uint8_t status, + uint32_t opcodes) +{ + struct btp_mcp_opcodes_supported_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.opcodes = sys_cpu_to_le32(opcodes); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_OPCODES_SUPPORTED_EV, &ev, sizeof(ev)); +} + +static void btp_send_mcp_content_control_id_ev(struct bt_conn *conn, uint8_t status, + uint8_t ccid) +{ + struct btp_mcp_content_control_id_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.ccid = ccid; + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_CONTENT_CONTROL_ID_EV, &ev, sizeof(ev)); +} + +static void btp_send_segments_obj_id_ev(struct bt_conn *conn, uint8_t status, uint64_t id) +{ + struct btp_mcp_segments_obj_id_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + sys_put_le48(id, ev.id); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_SEGMENTS_OBJ_ID_EV, &ev, sizeof(ev)); +} + +static void btp_send_current_track_obj_id_ev(struct bt_conn *conn, uint8_t status, uint64_t id) +{ + struct btp_mcp_current_track_obj_id_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + sys_put_le48(id, ev.id); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_CURRENT_TRACK_OBJ_ID_EV, &ev, sizeof(ev)); +} + +static void btp_send_media_cp_ev(struct bt_conn *conn, uint8_t status, + const struct mpl_cmd *cmd) +{ + struct btp_mcp_media_cp_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.opcode = cmd->opcode; + ev.use_param = cmd->use_param; + ev.param = sys_cpu_to_le32(cmd->param); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_MEDIA_CP_EV, &ev, sizeof(ev)); +} + +static void btp_send_search_cp_ev(struct bt_conn *conn, uint8_t status, + const struct mpl_search *search) +{ + struct btp_mcp_search_cp_ev *ev; + uint8_t param[SEARCH_LEN_MAX]; + + net_buf_simple_init(rx_ev_buf, 0); + + ev = net_buf_simple_add(rx_ev_buf, sizeof(*ev)); + + bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn)); + + ev->status = status; + ev->param_len = (uint8_t)search->search[0]; + + if (ev->param_len > (SEARCH_LEN_MAX - sizeof(ev->param_len))) { + return; + } + + ev->search_type = search->search[1]; + strcpy(param, &search->search[2]); + net_buf_simple_add_mem(rx_ev_buf, param, ev->param_len); + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_SEARCH_CP_EV, ev, sizeof(*ev) + ev->param_len); +} + +static void btp_send_command_notifications_ev(struct bt_conn *conn, uint8_t status, + const struct mpl_cmd_ntf *ntf) +{ + struct btp_mcp_cmd_ntf_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.requested_opcode = ntf->requested_opcode; + ev.result_code = ntf->result_code; + + tester_event(BTP_SERVICE_ID_MCP, BTP_MCP_NTF_EV, &ev, sizeof(ev)); +} + +static void btp_send_search_notifications_ev(struct bt_conn *conn, uint8_t status, + uint8_t result_code) +{ + struct btp_scp_cmd_ntf_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + ev.status = status; + ev.result_code = result_code; + + tester_event(BTP_SERVICE_ID_MCP, BTP_SCP_NTF_EV, &ev, sizeof(ev)); +} + +static void mcc_discover_cb(struct bt_conn *conn, int err) +{ + if (err) { + LOG_DBG("Discovery failed (%d)", err); + return; + } + + btp_send_mcp_found_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); +} + +static void mcc_read_track_duration_cb(struct bt_conn *conn, int err, int32_t dur) +{ + LOG_DBG("MCC Read track duration cb (%d)", err); + + btp_send_mcp_track_duration_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, dur); +} + +static void mcc_read_track_position_cb(struct bt_conn *conn, int err, int32_t pos) +{ + LOG_DBG("MCC Read track position cb (%d)", err); + + btp_send_mcp_track_position_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, pos); +} + +static void mcc_set_track_position_cb(struct bt_conn *conn, int err, int32_t pos) +{ + LOG_DBG("MCC Set track position cb (%d)", err); + + btp_send_mcp_track_position_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, pos); +} + +static void mcc_read_playback_speed_cb(struct bt_conn *conn, int err, int8_t speed) +{ + LOG_DBG("MCC read playback speed cb (%d)", err); + + btp_send_mcp_playback_speed_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, speed); +} + +static void mcc_set_playback_speed_cb(struct bt_conn *conn, int err, int8_t speed) +{ + LOG_DBG("MCC set playback speed cb (%d)", err); + + btp_send_mcp_playback_speed_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, speed); +} + +static void mcc_read_seeking_speed_cb(struct bt_conn *conn, int err, int8_t speed) +{ + LOG_DBG("MCC read seeking speed cb (%d)", err); + + btp_send_mcp_seeking_speed_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, speed); +} + +static void mcc_read_icon_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) +{ + LOG_DBG("MCC read Icon Object ID cb (%d)", err); + + btp_send_mcp_icon_obj_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, id); +} + +static void mcc_read_next_track_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) +{ + LOG_DBG("MCC read next track obj ID cb (%d)", err); + + btp_send_mcp_next_track_obj_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, id); +} + +static void mcc_set_next_track_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) +{ + LOG_DBG("MCC set next track obj ID cb (%d)", err); + + btp_send_mcp_next_track_obj_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, id); +} + +static void mcc_read_parent_group_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) +{ + LOG_DBG("MCC read parent group obj ID cb (%d)", err); + + btp_send_parent_group_obj_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, id); +} + +static void mcc_read_current_group_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) +{ + LOG_DBG("MCC read current group obj ID cb (%d)", err); + + btp_send_current_group_obj_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, id); +} + +static void mcc_set_current_group_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) +{ + LOG_DBG("MCC read current group obj ID cb (%d)", err); + + btp_send_current_group_obj_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, id); +} + +static void mcc_read_playing_order_cb(struct bt_conn *conn, int err, uint8_t order) +{ + LOG_DBG("MCC read playing order cb (%d)", err); + + btp_send_mcp_playing_order_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, order); +} + +static void mcc_set_playing_order_cb(struct bt_conn *conn, int err, uint8_t order) +{ + LOG_DBG("MCC set playing order cb (%d)", err); + + btp_send_mcp_playing_order_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, order); +} + +static void mcc_read_playing_orders_supported_cb(struct bt_conn *conn, int err, uint16_t orders) +{ + LOG_DBG("MCC set playing order cb (%d)", err); + + btp_send_mcp_playing_orders_supported_ev(conn, + err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, + orders); +} + +static void mcc_media_state_read_cb(struct bt_conn *conn, int err, uint8_t state) +{ + LOG_DBG("MCC media state read cb (%d)", err); + + btp_send_mcp_media_state_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, state); +} + +static void mcc_opcodes_supported_cb(struct bt_conn *conn, int err, uint32_t opcodes) +{ + LOG_DBG("MCC opcodes supported cb (%d)", err); + + btp_send_mcp_opcodes_supported_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, + opcodes); +} + +static void mcc_content_control_id_cb(struct bt_conn *conn, int err, uint8_t ccid) +{ + LOG_DBG("MCC Content control ID cb (%d)", err); + + btp_send_mcp_content_control_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, + ccid); +} + +static void mcc_segments_object_id_cb(struct bt_conn *conn, int err, uint64_t id) +{ + LOG_DBG("MCC Segments Object ID cb (%d)", err); + + btp_send_segments_obj_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, id); +} + +static void mcc_current_track_obj_id_read_cb(struct bt_conn *conn, int err, uint64_t id) +{ + LOG_DBG("MCC Segments Object ID read cb (%d)", err); + + btp_send_current_track_obj_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, id); +} + +static void mcc_current_track_obj_id_set_cb(struct bt_conn *conn, int err, uint64_t id) +{ + LOG_DBG("MCC Segments Object ID set cb (%d)", err); + + btp_send_current_track_obj_id_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, id); +} + +static void mcc_send_cmd_cb(struct bt_conn *conn, int err, const struct mpl_cmd *cmd) +{ + LOG_DBG("MCC Send Command cb (%d)", err); + + btp_send_media_cp_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, cmd); +} + +static void mcc_send_search_cb(struct bt_conn *conn, int err, const struct mpl_search *search) +{ + LOG_DBG("MCC Send Search cb (%d)", err); + + btp_send_search_cp_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, search); +} + +static void mcc_cmd_ntf_cb(struct bt_conn *conn, int err, const struct mpl_cmd_ntf *ntf) +{ + LOG_DBG("MCC Media Control Point Command Notify cb (%d)", err); + + btp_send_command_notifications_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, ntf); +} + +static void mcc_search_ntf_cb(struct bt_conn *conn, int err, uint8_t result_code) +{ + LOG_DBG("MCC Search Control Point Notify cb (%d)", err); + + btp_send_search_notifications_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, + result_code); +} + +static struct bt_mcc_cb mcp_cb = { + .discover_mcs = mcc_discover_cb, + .read_track_duration = mcc_read_track_duration_cb, + .read_track_position = mcc_read_track_position_cb, + .set_track_position = mcc_set_track_position_cb, + .read_playback_speed = mcc_read_playback_speed_cb, + .set_playback_speed = mcc_set_playback_speed_cb, + .read_seeking_speed = mcc_read_seeking_speed_cb, + .read_playing_order = mcc_read_playing_order_cb, + .set_playing_order = mcc_set_playing_order_cb, + .read_playing_orders_supported = mcc_read_playing_orders_supported_cb, + .read_media_state = mcc_media_state_read_cb, + .read_opcodes_supported = mcc_opcodes_supported_cb, + .read_content_control_id = mcc_content_control_id_cb, + .send_cmd = mcc_send_cmd_cb, + .cmd_ntf = mcc_cmd_ntf_cb, +#ifdef CONFIG_BT_OTS_CLIENT + .read_icon_obj_id = mcc_read_icon_obj_id_cb, + .read_next_track_obj_id = mcc_read_next_track_obj_id_cb, + .set_next_track_obj_id = mcc_set_next_track_obj_id_cb, + .read_parent_group_obj_id = mcc_read_parent_group_obj_id_cb, + .read_current_group_obj_id = mcc_read_current_group_obj_id_cb, + .set_current_group_obj_id = mcc_set_current_group_obj_id_cb, + .read_segments_obj_id = mcc_segments_object_id_cb, + .read_current_track_obj_id = mcc_current_track_obj_id_read_cb, + .set_current_track_obj_id = mcc_current_track_obj_id_set_cb, + .send_search = mcc_send_search_cb, + .search_ntf = mcc_search_ntf_cb, +#endif /* CONFIG_BT_OTS_CLIENT */ +}; + +static uint8_t mcp_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + struct btp_mcp_read_supported_commands_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_MCP_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_MCP_DISCOVER); + tester_set_bit(rp->data, BTP_MCP_TRACK_DURATION_READ); + tester_set_bit(rp->data, BTP_MCP_TRACK_POSITION_READ); + tester_set_bit(rp->data, BTP_MCP_TRACK_POSITION_SET); + tester_set_bit(rp->data, BTP_MCP_PLAYBACK_SPEED_READ); + tester_set_bit(rp->data, BTP_MCP_PLAYBACK_SPEED_SET); + + /* octet 1 */ + tester_set_bit(rp->data, BTP_MCP_SEEKING_SPEED_READ); + tester_set_bit(rp->data, BTP_MCP_ICON_OBJ_ID_READ); + tester_set_bit(rp->data, BTP_MCP_NEXT_TRACK_OBJ_ID_READ); + tester_set_bit(rp->data, BTP_MCP_NEXT_TRACK_OBJ_ID_SET); + tester_set_bit(rp->data, BTP_MCP_PARENT_GROUP_OBJ_ID_READ); + tester_set_bit(rp->data, BTP_MCP_CURRENT_GROUP_OBJ_ID_READ); + tester_set_bit(rp->data, BTP_MCP_CURRENT_GROUP_OBJ_ID_SET); + + /* octet 2 */ + tester_set_bit(rp->data, BTP_MCP_PLAYING_ORDER_READ); + tester_set_bit(rp->data, BTP_MCP_PLAYING_ORDER_SET); + tester_set_bit(rp->data, BTP_MCP_PLAYING_ORDERS_SUPPORTED_READ); + tester_set_bit(rp->data, BTP_MCP_MEDIA_STATE_READ); + tester_set_bit(rp->data, BTP_MCP_OPCODES_SUPPORTED_READ); + tester_set_bit(rp->data, BTP_MCP_CONTENT_CONTROL_ID_READ); + tester_set_bit(rp->data, BTP_MCP_SEGMENTS_OBJ_ID_READ); + + /* octet 3 */ + tester_set_bit(rp->data, BTP_MCP_CURRENT_TRACK_OBJ_ID_READ); + tester_set_bit(rp->data, BTP_MCP_CURRENT_TRACK_OBJ_ID_SET); + tester_set_bit(rp->data, BTP_MCP_CMD_SEND); + tester_set_bit(rp->data, BTP_MCP_CMD_SEARCH); + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_discover(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_mcp_discover_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_discover_mcs(conn, true); + if (err) { + LOG_DBG("Discovery failed: %d", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_track_duration_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_track_duration_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Read track duration"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_track_duration(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_track_position_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_track_position_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Read track position"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_track_position(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_track_position_set(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_track_position_set_cmd *cp = cmd; + uint32_t pos = sys_le32_to_cpu(cp->pos); + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Set track position"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_set_track_position(conn, pos); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_playback_speed_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_playback_speed_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Read playback speed"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_playback_speed(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_playback_speed_set(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_playback_speed_set *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Set playback speed"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_set_playback_speed(conn, cp->speed); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_seeking_speed_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_seeking_speed_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Read seeking speed"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_seeking_speed(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_read_icon_obj_id(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_icon_obj_id_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Read Icon Object ID"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_icon_obj_id(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_read_next_track_obj_id(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_next_track_obj_id_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Read Next Track Object ID"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_next_track_obj_id(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_set_next_track_obj_id(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_set_next_track_obj_id_cmd *cp = cmd; + uint64_t id = sys_get_le48(cp->id); + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Set Next Track Object ID"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_set_next_track_obj_id(conn, id); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_parent_group_obj_id_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_parent_group_obj_id_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Read Parent Group Object ID"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_parent_group_obj_id(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_current_group_obj_id_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_current_group_obj_id_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Read Current Group Object ID"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_current_group_obj_id(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_set_current_group_obj_id(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_current_group_obj_id_set_cmd *cp = cmd; + uint64_t id = sys_get_le48(cp->id); + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Set Next Track Object ID"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_set_current_group_obj_id(conn, id); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_playing_order_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_playing_order_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Read Playing Order"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_playing_order(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_playing_order_set(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_playing_order_set_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Set Playing Order"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_set_playing_order(conn, cp->order); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_playing_orders_supported_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_playing_orders_supported_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Playing orders supported read"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_playing_orders_supported(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_media_state_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_media_state_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Media State read"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_media_state(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_opcodes_supported_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_opcodes_supported_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Supported opcodes read"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_opcodes_supported(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_content_control_id_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_content_control_id_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Content Control ID read"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_content_control_id(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_segments_obj_id_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_segments_obj_id_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Track Segments Object ID read"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_segments_obj_id(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_current_track_obj_id_read(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_current_track_obj_id_read_cmd *cp = cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Current Track Object ID read"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_read_current_track_obj_id(conn); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_current_track_obj_id_set(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_mcp_current_track_obj_id_set_cmd *cp = cmd; + uint64_t id = sys_get_le48(cp->id); + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Set Current Track Object ID"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + err = bt_mcc_set_current_track_obj_id(conn, id); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_cmd_send(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_mcp_send_cmd *cp = cmd; + struct mpl_cmd mcp_cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Send Command"); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + mcp_cmd.opcode = cp->opcode; + mcp_cmd.use_param = cp->use_param; + mcp_cmd.param = sys_le32_to_cpu(cp->param); + + err = bt_mcc_send_cmd(conn, &mcp_cmd); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t mcp_cmd_search(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct btp_mcp_search_cmd *cp = cmd; + struct mpl_search search_items; + struct mpl_sci scp_cmd; + struct bt_conn *conn; + int err; + + LOG_DBG("MCC Send Search Control Point Command"); + + if (cmd_len < sizeof(*cp) || cmd_len != sizeof(*cp) + cp->param_len) { + return BTP_STATUS_FAILED; + } + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + LOG_ERR("Unknown connection"); + return BTP_STATUS_FAILED; + } + + search_items.len = 0; + scp_cmd.type = cp->type; + + if (scp_cmd.type == BT_MCS_SEARCH_TYPE_ONLY_TRACKS || + scp_cmd.type == BT_MCS_SEARCH_TYPE_ONLY_GROUPS) { + scp_cmd.len = sizeof(scp_cmd.type); + + if (ARRAY_SIZE(search_items.search) < (sizeof(scp_cmd.len) + + sizeof(scp_cmd.type))) { + return BTP_STATUS_FAILED; + } + + memcpy(&search_items.search[search_items.len], &scp_cmd.len, sizeof(scp_cmd.len)); + search_items.len += sizeof(scp_cmd.len); + + memcpy(&search_items.search[search_items.len], &scp_cmd.type, + sizeof(scp_cmd.type)); + search_items.len += sizeof(scp_cmd.type); + } else { + if (cp->param_len >= (SEARCH_LEN_MAX - 1)) { + return BTP_STATUS_FAILED; + } + + strcpy(scp_cmd.param, cp->param); + scp_cmd.len = sizeof(scp_cmd.type) + strlen(scp_cmd.param); + + if (ARRAY_SIZE(search_items.search) < (sizeof(scp_cmd.len) + sizeof(scp_cmd.len) + + strlen(scp_cmd.param))) { + return BTP_STATUS_FAILED; + } + + memcpy(&search_items.search[search_items.len], &scp_cmd.len, sizeof(scp_cmd.len)); + search_items.len += sizeof(scp_cmd.len); + + memcpy(&search_items.search[search_items.len], &scp_cmd.type, + sizeof(scp_cmd.type)); + search_items.len += sizeof(scp_cmd.type); + + strcpy(&search_items.search[search_items.len], scp_cmd.param); + search_items.len += strlen(scp_cmd.param); + search_items.search[search_items.len] = '\0'; + } + + err = bt_mcc_send_search(conn, &search_items); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler mcp_handlers[] = { + { + .opcode = BTP_MCP_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = mcp_supported_commands, + }, + { + .opcode = BTP_MCP_DISCOVER, + .expect_len = sizeof(struct btp_mcp_discover_cmd), + .func = mcp_discover, + }, + { + .opcode = BTP_MCP_TRACK_DURATION_READ, + .expect_len = sizeof(struct btp_mcp_track_duration_cmd), + .func = mcp_track_duration_read, + }, + { + .opcode = BTP_MCP_TRACK_POSITION_READ, + .expect_len = sizeof(struct btp_mcp_track_position_read_cmd), + .func = mcp_track_position_read, + }, + { + .opcode = BTP_MCP_TRACK_POSITION_SET, + .expect_len = sizeof(struct btp_mcp_track_position_set_cmd), + .func = mcp_track_position_set, + }, + { + .opcode = BTP_MCP_PLAYBACK_SPEED_READ, + .expect_len = sizeof(struct btp_mcp_playback_speed_read_cmd), + .func = mcp_playback_speed_read, + }, + { + .opcode = BTP_MCP_PLAYBACK_SPEED_SET, + .expect_len = sizeof(struct btp_mcp_playback_speed_set), + .func = mcp_playback_speed_set, + }, + { + .opcode = BTP_MCP_SEEKING_SPEED_READ, + .expect_len = sizeof(struct btp_mcp_seeking_speed_read_cmd), + .func = mcp_seeking_speed_read, + }, + { + .opcode = BTP_MCP_ICON_OBJ_ID_READ, + .expect_len = sizeof(struct btp_mcp_icon_obj_id_read_cmd), + .func = mcp_read_icon_obj_id, + }, + { + .opcode = BTP_MCP_NEXT_TRACK_OBJ_ID_READ, + .expect_len = sizeof(struct btp_mcp_next_track_obj_id_cmd), + .func = mcp_read_next_track_obj_id, + }, + { + .opcode = BTP_MCP_NEXT_TRACK_OBJ_ID_SET, + .expect_len = sizeof(struct btp_mcp_set_next_track_obj_id_cmd), + .func = mcp_set_next_track_obj_id, + }, + { + .opcode = BTP_MCP_PARENT_GROUP_OBJ_ID_READ, + .expect_len = sizeof(struct btp_mcp_parent_group_obj_id_read_cmd), + .func = mcp_parent_group_obj_id_read, + }, + { + .opcode = BTP_MCP_CURRENT_GROUP_OBJ_ID_READ, + .expect_len = sizeof(struct btp_mcp_current_group_obj_id_read_cmd), + .func = mcp_current_group_obj_id_read, + }, + { + .opcode = BTP_MCP_CURRENT_GROUP_OBJ_ID_SET, + .expect_len = sizeof(struct btp_mcp_current_group_obj_id_set_cmd), + .func = mcp_set_current_group_obj_id, + }, + { + .opcode = BTP_MCP_PLAYING_ORDER_READ, + .expect_len = sizeof(struct btp_mcp_playing_order_read_cmd), + .func = mcp_playing_order_read, + }, + { + .opcode = BTP_MCP_PLAYING_ORDER_SET, + .expect_len = sizeof(struct btp_mcp_playing_order_set_cmd), + .func = mcp_playing_order_set, + }, + { + .opcode = BTP_MCP_PLAYING_ORDERS_SUPPORTED_READ, + .expect_len = sizeof(struct btp_mcp_playing_orders_supported_read_cmd), + .func = mcp_playing_orders_supported_read, + }, + { + .opcode = BTP_MCP_MEDIA_STATE_READ, + .expect_len = sizeof(struct btp_mcp_media_state_read_cmd), + .func = mcp_media_state_read, + }, + { + .opcode = BTP_MCP_OPCODES_SUPPORTED_READ, + .expect_len = sizeof(struct btp_mcp_opcodes_supported_read_cmd), + .func = mcp_opcodes_supported_read, + }, + { + .opcode = BTP_MCP_CONTENT_CONTROL_ID_READ, + .expect_len = sizeof(struct btp_mcp_content_control_id_read_cmd), + .func = mcp_content_control_id_read, + }, + { + .opcode = BTP_MCP_SEGMENTS_OBJ_ID_READ, + .expect_len = sizeof(struct btp_mcp_segments_obj_id_read_cmd), + .func = mcp_segments_obj_id_read, + }, + { + .opcode = BTP_MCP_CURRENT_TRACK_OBJ_ID_READ, + .expect_len = sizeof(struct btp_mcp_current_track_obj_id_read_cmd), + .func = mcp_current_track_obj_id_read, + }, + { + .opcode = BTP_MCP_CURRENT_TRACK_OBJ_ID_SET, + .expect_len = sizeof(struct btp_mcp_current_track_obj_id_set_cmd), + .func = mcp_current_track_obj_id_set, + }, + { + .opcode = BTP_MCP_CMD_SEND, + .expect_len = sizeof(struct btp_mcp_send_cmd), + .func = mcp_cmd_send, + }, + { + .opcode = BTP_MCP_CMD_SEARCH, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = mcp_cmd_search, + }, +}; + +uint8_t tester_init_mcp(void) +{ + int err; + + err = bt_mcc_init(&mcp_cb); + if (err) { + LOG_DBG("Failed to initialize Media Control Client: %d", err); + return BTP_STATUS_FAILED; + } + + tester_register_command_handlers(BTP_SERVICE_ID_MCP, mcp_handlers, + ARRAY_SIZE(mcp_handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t tester_unregister_mcp(void) +{ + return BTP_STATUS_SUCCESS; +} From ed17320c3d2e43c76b09dc359d3b371e9d23732d Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 8 Nov 2023 20:23:37 +0530 Subject: [PATCH 0100/1049] net: Remove unnecessary lock The main action in this function it queueing the packet for transmission which doesn't need a lock and interface flags use atomic operations. So, remove the unnecessary lock. Signed-off-by: Chaitanya Tata --- subsys/net/ip/net_if.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 9f5a3306f941547..099618b84761443 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -437,8 +437,6 @@ enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt) enum net_verdict verdict = NET_OK; int status = -EIO; - net_if_lock(iface); - if (!net_if_flag_is_set(iface, NET_IF_LOWER_UP) || net_if_flag_is_set(iface, NET_IF_SUSPENDED)) { /* Drop packet if interface is not up */ @@ -521,8 +519,6 @@ enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt) net_if_queue_tx(iface, pkt); } - net_if_unlock(iface); - return verdict; } From c33ed20eb87c39b9f415f0ca1b33abf6b500124b Mon Sep 17 00:00:00 2001 From: Ning Yang Date: Wed, 8 Nov 2023 10:24:36 +0800 Subject: [PATCH 0101/1049] drivers: dma: copy whole user dma config to fix dma case failure user dma config is not fully saved in dma_sedi_chan_config function. When dma_sedi_start function it will check local context, it will cause failure here. Signed-off-by: Ning Yang --- drivers/dma/dma_sedi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma/dma_sedi.c b/drivers/dma/dma_sedi.c index 629ca8f0e201c59..96ae8bbf8fb2a4a 100644 --- a/drivers/dma/dma_sedi.c +++ b/drivers/dma/dma_sedi.c @@ -254,9 +254,8 @@ static int dma_sedi_chan_config(const struct device *dev, uint32_t channel, const struct dma_sedi_config_info *const info = DEV_CFG(dev); struct dma_sedi_driver_data *const data = DEV_DATA(dev); - struct dma_config *local_config = &(data->dma_configs[channel]); - local_config->head_block = config->head_block; + memcpy(&(data->dma_configs[channel]), config, sizeof(struct dma_config)); /* initialize the dma controller, following the sedi api*/ sedi_dma_event_cb_t cb = dma_handler; From 1158c5dc01ca0033ea489e549f8d1c8596c0ecbd Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 23 Oct 2023 15:35:51 +0200 Subject: [PATCH 0102/1049] include: coap: Fix typo Fixed a typo to include DOXYGEN generated documentation. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index ebc72709751b48e..b80e93df32ac186 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -274,7 +274,7 @@ struct coap_packet { uint8_t hdr_len; /**< CoAP header length */ uint16_t opt_len; /**< Total options length (delta + len + value) */ uint16_t delta; /**< Used for delta calculation in CoAP packet */ -#if defined(CONFIG_COAP_KEEP_USER_DATA) || defined(DOXGEN) +#if defined(CONFIG_COAP_KEEP_USER_DATA) || defined(DOXYGEN) /** * Application specific user data. * Only available when @kconfig{CONFIG_COAP_KEEP_USER_DATA} is enabled. From bea29cf631e581e05456b0ae76651d15814ab853 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 25 Sep 2023 22:05:54 +0200 Subject: [PATCH 0103/1049] net: lib: coap: Add resources length based variants Add length variant for the well known core resource and parsing. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap.h | 26 +++++++- include/zephyr/net/coap_link_format.h | 36 ++++++++++- subsys/net/lib/coap/coap.c | 39 ++++++++---- subsys/net/lib/coap/coap_link_format.c | 85 +++++++++++++++++--------- 4 files changed, 141 insertions(+), 45 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index b80e93df32ac186..efe2d010d0b4a8e 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -583,12 +583,36 @@ int coap_packet_append_payload(struct coap_packet *cpkt, const uint8_t *payload, * * @param cpkt Packet received * @param resources Array of known resources + * @param resources_len Number of resources in the array * @param options Parsed options from coap_packet_parse() * @param opt_num Number of options * @param addr Peer address * @param addr_len Peer address length * - * @retval 0 in case of success. + * @retval >= 0 in case of success. + * @retval -ENOTSUP in case of invalid request code. + * @retval -EPERM in case resource handler is not implemented. + * @retval -ENOENT in case the resource is not found. + */ +int coap_handle_request_len(struct coap_packet *cpkt, + struct coap_resource *resources, + size_t resources_len, + struct coap_option *options, + uint8_t opt_num, + struct sockaddr *addr, socklen_t addr_len); + +/** + * @brief When a request is received, call the appropriate methods of + * the matching resources. + * + * @param cpkt Packet received + * @param resources Array of known resources (terminated with empty resource) + * @param options Parsed options from coap_packet_parse() + * @param opt_num Number of options + * @param addr Peer address + * @param addr_len Peer address length + * + * @retval >= 0 in case of success. * @retval -ENOTSUP in case of invalid request code. * @retval -EPERM in case resource handler is not implemented. * @retval -ENOENT in case the resource is not found. diff --git a/include/zephyr/net/coap_link_format.h b/include/zephyr/net/coap_link_format.h index 17374202b6d0079..cabfb9ff859d928 100644 --- a/include/zephyr/net/coap_link_format.h +++ b/include/zephyr/net/coap_link_format.h @@ -24,15 +24,45 @@ extern "C" { /** * This resource should be added before all other resources that should be - * included in the responses of the .well-known/core resource. + * included in the responses of the .well-known/core resource if is to be used with + * coap_well_known_core_get. */ #define COAP_WELL_KNOWN_CORE_PATH \ ((const char * const[]) { ".well-known", "core", NULL }) +/** + * @brief Build a CoAP response for a .well-known/core CoAP request. + * + * @param resource Array of known resources, terminated with an empty resource + * @param request A pointer to the .well-known/core CoAP request + * @param response A pointer to a CoAP response, will be initialized + * @param data A data pointer to be used to build the CoAP response + * @param data_len The maximum length of the data buffer + * + * @return 0 in case of success or negative in case of error. + */ int coap_well_known_core_get(struct coap_resource *resource, - struct coap_packet *request, + const struct coap_packet *request, struct coap_packet *response, - uint8_t *data, uint16_t len); + uint8_t *data, uint16_t data_len); + +/** + * @brief Build a CoAP response for a .well-known/core CoAP request. + * + * @param resources Array of known resources + * @param resources_len Number of resources in the array + * @param request A pointer to the .well-known/core CoAP request + * @param response A pointer to a CoAP response, will be initialized + * @param data A data pointer to be used to build the CoAP response + * @param data_len The maximum length of the data buffer + * + * @return 0 in case of success or negative in case of error. + */ +int coap_well_known_core_get_len(struct coap_resource *resources, + size_t resources_len, + const struct coap_packet *request, + struct coap_packet *response, + uint8_t *data, uint16_t data_len); /** * In case you want to add attributes to the resources included in the diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 8ac8d73e78d5693..45974210367c1db 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1147,29 +1147,28 @@ static bool is_request(const struct coap_packet *cpkt) return !(code & ~COAP_REQUEST_MASK); } -int coap_handle_request(struct coap_packet *cpkt, - struct coap_resource *resources, - struct coap_option *options, - uint8_t opt_num, - struct sockaddr *addr, socklen_t addr_len) +int coap_handle_request_len(struct coap_packet *cpkt, + struct coap_resource *resources, + size_t resources_len, + struct coap_option *options, + uint8_t opt_num, + struct sockaddr *addr, socklen_t addr_len) { - struct coap_resource *resource; - if (!is_request(cpkt)) { return 0; } /* FIXME: deal with hierarchical resources */ - for (resource = resources; resource && resource->path; resource++) { + for (size_t i = 0; i < resources_len; i++) { coap_method_t method; uint8_t code; - if (!uri_path_eq(cpkt, resource->path, options, opt_num)) { + if (!uri_path_eq(cpkt, resources[i].path, options, opt_num)) { continue; } code = coap_header_get_code(cpkt); - if (method_from_code(resource, code, &method) < 0) { + if (method_from_code(&resources[i], code, &method) < 0) { return -ENOTSUP; } @@ -1177,13 +1176,29 @@ int coap_handle_request(struct coap_packet *cpkt, return -EPERM; } - return method(resource, cpkt, addr, addr_len); + return method(&resources[i], cpkt, addr, addr_len); } - NET_DBG("%d", __LINE__); return -ENOENT; } +int coap_handle_request(struct coap_packet *cpkt, + struct coap_resource *resources, + struct coap_option *options, + uint8_t opt_num, + struct sockaddr *addr, socklen_t addr_len) +{ + size_t resources_len = 0; + struct coap_resource *resource; + + for (resource = resources; resource && resource->path; resource++) { + resources_len++; + } + + return coap_handle_request_len(cpkt, resources, resources_len, options, opt_num, addr, + addr_len); +} + int coap_block_transfer_init(struct coap_block_context *ctx, enum coap_block_size block_size, size_t total_size) diff --git a/subsys/net/lib/coap/coap_link_format.c b/subsys/net/lib/coap/coap_link_format.c index 10c72d62c9ec1cf..a3ea175b2df0a60 100644 --- a/subsys/net/lib/coap/coap_link_format.c +++ b/subsys/net/lib/coap/coap_link_format.c @@ -432,10 +432,11 @@ int clear_more_flag(struct coap_packet *cpkt) return 0; } -int coap_well_known_core_get(struct coap_resource *resource, - struct coap_packet *request, - struct coap_packet *response, - uint8_t *data, uint16_t len) +int coap_well_known_core_get_len(struct coap_resource *resources, + size_t resources_len, + struct coap_packet *request, + struct coap_packet *response, + uint8_t *data, uint16_t len) { static struct coap_block_context ctx; struct coap_option query; @@ -446,9 +447,9 @@ int coap_well_known_core_get(struct coap_resource *resource, uint16_t id; uint8_t tkl; int r; - bool more = false; + bool more = false, first = true; - if (!resource || !request || !response || !data || !len) { + if (!resources || !request || !response || !data || !len) { return -EINVAL; } @@ -505,29 +506,31 @@ int coap_well_known_core_get(struct coap_resource *resource, offset = 0; remaining = coap_block_size_to_bytes(ctx.block_size); - while (resource++ && resource->path) { + for (size_t i = 0; i < resources_len; ++i) { if (!remaining) { more = true; break; } - if (!match_queries_resource(resource, &query, num_queries)) { + if (!match_queries_resource(&resources[i], &query, num_queries)) { continue; } - r = format_resource(resource, response, &remaining, &offset, - ctx.current, &more); - if (r < 0) { - goto end; - } - - if ((resource + 1) && (resource + 1)->path) { + if (first) { + first = false; + } else { r = append_to_coap_pkt(response, ",", 1, &remaining, &offset, ctx.current); if (!r) { goto end; } } + + r = format_resource(&resources[i], response, &remaining, &offset, + ctx.current, &more); + if (r < 0) { + goto end; + } } /* Offset is the total size now, but block2 option is already @@ -631,10 +634,11 @@ static int format_resource(const struct coap_resource *resource, return format_attributes(attributes, response); } -int coap_well_known_core_get(struct coap_resource *resource, - struct coap_packet *request, - struct coap_packet *response, - uint8_t *data, uint16_t len) +int coap_well_known_core_get_len(struct coap_resource *resources, + size_t resources_len, + const struct coap_packet *request, + struct coap_packet *response, + uint8_t *data, uint16_t data_len) { struct coap_option query; uint8_t token[COAP_TOKEN_MAX_LEN]; @@ -642,8 +646,9 @@ int coap_well_known_core_get(struct coap_resource *resource, uint8_t tkl; uint8_t num_queries; int r; + bool first = true; - if (!resource || !request || !response || !data || !len) { + if (!resources || !request || !response || !data || !data_len) { return -EINVAL; } @@ -660,7 +665,7 @@ int coap_well_known_core_get(struct coap_resource *resource, num_queries = r; - r = coap_packet_init(response, data, len, COAP_VERSION_1, COAP_TYPE_ACK, + r = coap_packet_init(response, data, data_len, COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, COAP_RESPONSE_CODE_CONTENT, id); if (r < 0) { return r; @@ -677,28 +682,50 @@ int coap_well_known_core_get(struct coap_resource *resource, return -EINVAL; } - while (resource++ && resource->path) { - if (!match_queries_resource(resource, &query, num_queries)) { + for (size_t i = 0; i < resources_len; ++i) { + if (!match_queries_resource(&resources[i], &query, num_queries)) { continue; } - r = format_resource(resource, response); - if (r < 0) { - return r; - } - - if ((resource + 1)->path) { + if (first) { + first = false; + } else { r = append_u8(response, (uint8_t) ','); if (!r) { return -ENOMEM; } } + + r = format_resource(&resources[i], response); + if (r < 0) { + return r; + } } return 0; } #endif +int coap_well_known_core_get(struct coap_resource *resource, + const struct coap_packet *request, + struct coap_packet *response, + uint8_t *data, uint16_t data_len) +{ + struct coap_resource *resources = resource + 1; + size_t resources_len = 0; + + if (resource == NULL) { + return -EINVAL; + } + + while (resources[resources_len].path) { + resources_len++; + } + + return coap_well_known_core_get_len(resources, resources_len, request, response, data, + data_len); +} + /* Exposing some of the APIs to CoAP unit tests in tests/net/lib/coap */ #if defined(CONFIG_COAP_TEST_API_ENABLE) bool _coap_match_path_uri(const char * const *path, From 0a4668a2f73bc17eaa11396fe7813a56bb220583 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 27 Sep 2023 14:47:42 +0200 Subject: [PATCH 0104/1049] net: lib: coap: Add coap_uri_path_match Add URI path matching function to public CoAP API. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap.h | 14 ++++++++++++++ subsys/net/lib/coap/coap.c | 9 ++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index efe2d010d0b4a8e..ee511b71a484375 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -403,6 +403,20 @@ uint16_t coap_header_get_id(const struct coap_packet *cpkt); const uint8_t *coap_packet_get_payload(const struct coap_packet *cpkt, uint16_t *len); +/** + * @brief Verify if CoAP URI path matches with provided options. + * + * @param path Null-terminated array of strings. + * @param options Parsed options from coap_packet_parse() + * @param opt_num Number of options + * + * @return true if the CoAP URI path matches, + * false otherwise. + */ +bool coap_uri_path_match(const char * const *path, + struct coap_option *options, + uint8_t opt_num); + /** * @brief Parses the CoAP packet in data, validating it and * initializing @a cpkt. @a data must remain valid while @a cpkt is used. diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 45974210367c1db..c8f12b71e1340fe 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1056,10 +1056,9 @@ const uint8_t *coap_packet_get_payload(const struct coap_packet *cpkt, uint16_t cpkt->data + cpkt->hdr_len + cpkt->opt_len + 1; } -static bool uri_path_eq(const struct coap_packet *cpkt, - const char * const *path, - struct coap_option *options, - uint8_t opt_num) +bool coap_uri_path_match(const char * const *path, + struct coap_option *options, + uint8_t opt_num) { uint8_t i; uint8_t j = 0U; @@ -1163,7 +1162,7 @@ int coap_handle_request_len(struct coap_packet *cpkt, coap_method_t method; uint8_t code; - if (!uri_path_eq(cpkt, resources[i].path, options, opt_num)) { + if (!coap_uri_path_match(resources[i].path, options, opt_num)) { continue; } From cc893388887a4c0d2d7723619b3cb71bc13f3d6b Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 27 Sep 2023 15:05:12 +0200 Subject: [PATCH 0105/1049] net: lib: coap: Add coap_packet_is_request Add function to check if CoAP packet is a request to the public API. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap.h | 10 ++++++++++ subsys/net/lib/coap/coap.c | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index ee511b71a484375..67a70cbc43a81de 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -591,6 +591,16 @@ int coap_packet_append_payload_marker(struct coap_packet *cpkt); int coap_packet_append_payload(struct coap_packet *cpkt, const uint8_t *payload, uint16_t payload_len); +/** + * @brief Check if a CoAP packet is a CoAP request. + * + * @param cpkt Packet to be checked. + * + * @return true if the packet is a request, + * false otherwise. + */ +bool coap_packet_is_request(const struct coap_packet *cpkt); + /** * @brief When a request is received, call the appropriate methods of * the matching resources. diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index c8f12b71e1340fe..bd266360f98813b 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1139,7 +1139,7 @@ static inline bool is_empty_message(const struct coap_packet *cpkt) return __coap_header_get_code(cpkt) == COAP_CODE_EMPTY; } -static bool is_request(const struct coap_packet *cpkt) +bool coap_packet_is_request(const struct coap_packet *cpkt) { uint8_t code = coap_header_get_code(cpkt); @@ -1153,7 +1153,7 @@ int coap_handle_request_len(struct coap_packet *cpkt, uint8_t opt_num, struct sockaddr *addr, socklen_t addr_len) { - if (!is_request(cpkt)) { + if (!coap_packet_is_request(cpkt)) { return 0; } @@ -1219,7 +1219,7 @@ int coap_block_transfer_init(struct coap_block_context *ctx, int coap_append_descriptive_block_option(struct coap_packet *cpkt, struct coap_block_context *ctx) { - if (is_request(cpkt)) { + if (coap_packet_is_request(cpkt)) { return coap_append_block1_option(cpkt, ctx); } else { return coap_append_block2_option(cpkt, ctx); @@ -1228,7 +1228,7 @@ int coap_append_descriptive_block_option(struct coap_packet *cpkt, struct coap_b bool coap_has_descriptive_block_option(struct coap_packet *cpkt) { - if (is_request(cpkt)) { + if (coap_packet_is_request(cpkt)) { return coap_get_option_int(cpkt, COAP_OPTION_BLOCK1) >= 0; } else { return coap_get_option_int(cpkt, COAP_OPTION_BLOCK2) >= 0; @@ -1237,7 +1237,7 @@ bool coap_has_descriptive_block_option(struct coap_packet *cpkt) int coap_remove_descriptive_block_option(struct coap_packet *cpkt) { - if (is_request(cpkt)) { + if (coap_packet_is_request(cpkt)) { return coap_packet_remove_option(cpkt, COAP_OPTION_BLOCK1); } else { return coap_packet_remove_option(cpkt, COAP_OPTION_BLOCK2); @@ -1251,7 +1251,7 @@ int coap_append_block1_option(struct coap_packet *cpkt, unsigned int val = 0U; int r; - if (is_request(cpkt)) { + if (coap_packet_is_request(cpkt)) { SET_BLOCK_SIZE(val, ctx->block_size); SET_MORE(val, ctx->current + bytes < ctx->total_size); SET_NUM(val, ctx->current / bytes); @@ -1271,7 +1271,7 @@ int coap_append_block2_option(struct coap_packet *cpkt, int r, val = 0; uint16_t bytes = coap_block_size_to_bytes(ctx->block_size); - if (is_request(cpkt)) { + if (coap_packet_is_request(cpkt)) { SET_BLOCK_SIZE(val, ctx->block_size); SET_NUM(val, ctx->current / bytes); } else { @@ -1479,7 +1479,7 @@ int coap_update_from_block(const struct coap_packet *cpkt, size1 = coap_get_option_int(cpkt, COAP_OPTION_SIZE1); size2 = coap_get_option_int(cpkt, COAP_OPTION_SIZE2); - if (is_request(cpkt)) { + if (coap_packet_is_request(cpkt)) { r = update_control_block2(ctx, block2, size2); if (r) { return r; @@ -1534,7 +1534,7 @@ size_t coap_next_block(const struct coap_packet *cpkt, enum coap_option_num option; int ret; - option = is_request(cpkt) ? COAP_OPTION_BLOCK1 : COAP_OPTION_BLOCK2; + option = coap_packet_is_request(cpkt) ? COAP_OPTION_BLOCK1 : COAP_OPTION_BLOCK2; ret = coap_next_block_for_option(cpkt, ctx, option); return MAX(ret, 0); @@ -1737,7 +1737,7 @@ struct coap_reply *coap_response_received( uint8_t tkl; size_t i; - if (!is_empty_message(response) && is_request(response)) { + if (!is_empty_message(response) && coap_packet_is_request(response)) { /* Request can't be response */ return NULL; } From fac670e1e26c8d3487f84fbb2e158aaef1c7c51b Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 9 Oct 2023 09:57:46 +0200 Subject: [PATCH 0106/1049] net: lib: coap: Add coap_find_observer_by_token Add a CoAP helper function to find a matching observer by token. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap.h | 15 +++++++++++++++ subsys/net/lib/coap/coap.c | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index 67a70cbc43a81de..42eee01cfc1c97a 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -916,6 +916,21 @@ struct coap_observer *coap_find_observer_by_addr( struct coap_observer *observers, size_t len, const struct sockaddr *addr); +/** + * @brief Returns the observer that has token @a token. + * + * @param observers Pointer to the array of observers + * @param len Size of the array of observers + * @param token Pointer to the token + * @param token_len Length of valid bytes in the token + * + * @return A pointer to a observer if a match is found, NULL + * otherwise. + */ +struct coap_observer *coap_find_observer_by_token( + struct coap_observer *observers, size_t len, + const uint8_t *token, uint8_t token_len); + /** * @brief Returns the next available observer representation. * diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index bd266360f98813b..a7dd9302ba295c7 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1915,6 +1915,25 @@ struct coap_observer *coap_find_observer_by_addr( return NULL; } +struct coap_observer *coap_find_observer_by_token( + struct coap_observer *observers, size_t len, + const uint8_t *token, uint8_t token_len) +{ + if (token_len == 0U || token_len > COAP_TOKEN_MAX_LEN) { + return NULL; + } + + for (size_t i = 0; i < len; i++) { + struct coap_observer *o = &observers[i]; + + if (o->tkl == token_len && memcmp(o->token, token, token_len) == 0) { + return o; + } + } + + return NULL; +} + /** * @brief Internal initialization function for CoAP library. * From 291743b686499ec13b909c318c74ab720da667ed Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 9 Oct 2023 10:08:33 +0200 Subject: [PATCH 0107/1049] net: lib: coap: coap_remove_observer result type Change coap_remove_observer to return the result of removing the observer if found. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap.h | 4 +++- subsys/net/lib/coap/coap.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index 42eee01cfc1c97a..ddc6b080df5d889 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -898,8 +898,10 @@ bool coap_register_observer(struct coap_resource *resource, * * @param resource Resource in which to remove the observer * @param observer Observer to be removed + * + * @return true if the observer was found and removed. */ -void coap_remove_observer(struct coap_resource *resource, +bool coap_remove_observer(struct coap_resource *resource, struct coap_observer *observer); /** diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index a7dd9302ba295c7..97226fc9c544939 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1856,10 +1856,10 @@ bool coap_register_observer(struct coap_resource *resource, return first; } -void coap_remove_observer(struct coap_resource *resource, +bool coap_remove_observer(struct coap_resource *resource, struct coap_observer *observer) { - sys_slist_find_and_remove(&resource->observers, &observer->list); + return sys_slist_find_and_remove(&resource->observers, &observer->list); } static bool sockaddr_equal(const struct sockaddr *a, From 5227f248153f67e05b0ede9f859deb6f63ed4456 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 23 Oct 2023 14:55:45 +0200 Subject: [PATCH 0108/1049] net: lib: coap: Add support for observer event callbacks This commit adds the option to register an event handler to CoAP resources when observers are added/removed. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap.h | 30 ++++++++++++++++++++++++++++++ subsys/net/lib/coap/Kconfig | 6 ++++++ subsys/net/lib/coap/coap.c | 17 ++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index ddc6b080df5d889..ef9eb660ff496f9 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -238,6 +238,29 @@ typedef int (*coap_method_t)(struct coap_resource *resource, typedef void (*coap_notify_t)(struct coap_resource *resource, struct coap_observer *observer); +/** + * @brief Event types for observer event callbacks. + */ +enum coap_observer_event { + /** An observer was added. */ + COAP_OBSERVER_ADDED = 0, + /** An observer was removed. */ + COAP_OBSERVER_REMOVED, +}; + +/** + * @typedef coap_observer_event_handler_t + * @brief Type of the handler being called when a resource's observers has been modified. + * Either an observer was added or removed. + * + * @param resource A pointer to a CoAP resource for which the event occurred + * @param observer The observer being added/removed + * @param event The event type + */ +typedef void (*coap_observer_event_handler_t)(struct coap_resource *resource, + struct coap_observer *observer, + enum coap_observer_event event); + /** * @brief Description of CoAP resource. * @@ -252,6 +275,13 @@ struct coap_resource { void *user_data; sys_slist_t observers; int age; +#if defined(CONFIG_COAP_OBSERVER_EVENTS) || defined(DOXYGEN) + /** + * Optional observer event callback function + * Only available when @kconfig{CONFIG_COAP_OBSERVER_EVENTS} is enabled. + */ + coap_observer_event_handler_t observer_event_handler; +#endif }; /** diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index e7587ab21acb193..00ee157a11674a6 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -89,6 +89,12 @@ config COAP_URI_WILDCARD This option enables MQTT-style wildcards in path. Disable it if resource path may contain plus or hash symbol. +config COAP_OBSERVER_EVENTS + bool "CoAP resource observer events" + help + This option enables to register a callback function to CoAP resources + that will be called when adding/removing observers. + config COAP_KEEP_USER_DATA bool "Keeping user data in the CoAP packet" help diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 97226fc9c544939..9747e33fc56b4bc 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1853,13 +1853,28 @@ bool coap_register_observer(struct coap_resource *resource, resource->age = 2; } +#ifdef CONFIG_COAP_OBSERVER_EVENTS + if (resource->observer_event_handler) { + resource->observer_event_handler(resource, observer, COAP_OBSERVER_ADDED); + } +#endif + return first; } bool coap_remove_observer(struct coap_resource *resource, struct coap_observer *observer) { - return sys_slist_find_and_remove(&resource->observers, &observer->list); + if (!sys_slist_find_and_remove(&resource->observers, &observer->list)) { + return false; + } + +#ifdef CONFIG_COAP_OBSERVER_EVENTS + if (resource->observer_event_handler) { + resource->observer_event_handler(resource, observer, COAP_OBSERVER_REMOVED); + } +#endif + return true; } static bool sockaddr_equal(const struct sockaddr *a, From ae6e0106e7a0309d55b343760dabbdd915a42eae Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 21 Sep 2023 17:25:22 +0200 Subject: [PATCH 0109/1049] net: lib: coap: Add service support Add CoAP services and server as a subsystem implementation. Signed-off-by: Pieter De Gendt --- .../linker/common-rom/common-rom-net.ld | 4 + include/zephyr/net/coap_service.h | 292 +++++++ subsys/net/lib/coap/CMakeLists.txt | 4 + subsys/net/lib/coap/Kconfig | 93 +++ subsys/net/lib/coap/coap_server.c | 762 ++++++++++++++++++ 5 files changed, 1155 insertions(+) create mode 100644 include/zephyr/net/coap_service.h create mode 100644 subsys/net/lib/coap/coap_server.c diff --git a/include/zephyr/linker/common-rom/common-rom-net.ld b/include/zephyr/linker/common-rom/common-rom-net.ld index e535f5f1fd01880..71c1c1e089f51cd 100644 --- a/include/zephyr/linker/common-rom/common-rom-net.ld +++ b/include/zephyr/linker/common-rom/common-rom-net.ld @@ -17,3 +17,7 @@ #if defined(CONFIG_HTTP_SERVER) ITERABLE_SECTION_ROM(http_service_desc, 4) #endif + +#if defined(CONFIG_COAP_SERVER) + ITERABLE_SECTION_ROM(coap_service, 4) +#endif diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h new file mode 100644 index 000000000000000..3e3201308b946f3 --- /dev/null +++ b/include/zephyr/net/coap_service.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief CoAP Service API + * + * An API for applications to respond to CoAP requests + */ + +#ifndef ZEPHYR_INCLUDE_NET_COAP_SERVICE_H_ +#define ZEPHYR_INCLUDE_NET_COAP_SERVICE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief CoAP Service API + * @defgroup coap_service CoAP service API + * @ingroup networking + * @{ + */ + +/** + * @name CoAP Service configuration flags + * @anchor COAP_SERVICE_FLAGS + * @{ + */ + +/** Start the service on boot. */ +#define COAP_SERVICE_AUTOSTART BIT(0) + +/** @} */ + +/** @cond INTERNAL_HIDDEN */ + +struct coap_service_data { + int sock_fd; + struct coap_observer observers[CONFIG_COAP_SERVICE_OBSERVERS]; + struct coap_pending pending[CONFIG_COAP_SERVICE_PENDING_MESSAGES]; +}; + +struct coap_service { + const char *name; + const char *host; + uint16_t *port; + uint8_t flags; + struct coap_resource *res_begin; + struct coap_resource *res_end; + struct coap_service_data *data; +}; + +#define __z_coap_service_define(_name, _host, _port, _flags, _res_begin, _res_end) \ + static struct coap_service_data coap_service_data_##_name; \ + const STRUCT_SECTION_ITERABLE(coap_service, _name) = { \ + .name = STRINGIFY(_name), \ + .host = _host, \ + .port = (uint16_t *)(_port), \ + .flags = _flags, \ + .res_begin = (_res_begin), \ + .res_end = (_res_end), \ + .data = &coap_service_data_##_name, \ + } + +/** @endcond */ + +/** + * @brief Define a static CoAP resource owned by the service named @p _service . + * + * @note The handlers registered with the resource can return a CoAP response code to reply with + * an acknowledge without any payload, nothing is sent if the return value is 0 or negative. + * As seen in the example. + * + * @code{.c} + * static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); + * + * static int led_put(struct coap_resource *resource, struct coap_packet *request, + * struct sockaddr *addr, socklen_t addr_len) + * { + * const uint8_t *payload; + * uint16_t payload_len; + * + * payload = coap_packet_get_payload(request, &payload_len); + * if (payload_len != 1) { + * return COAP_RESPONSE_CODE_BAD_REQUEST; + * } + * + * if (gpio_pin_set_dt(&led, payload[0]) < 0) { + * return COAP_RESPONSE_CODE_INTERNAL_ERROR; + * } + * + * return COAP_RESPONSE_CODE_CHANGED; + * } + * + * COAP_RESOURCE_DEFINE(my_resource, my_service, { + * .put = led_put, + * }); + * @endcode + * + * @param _name Name of the resource. + * @param _service Name of the associated service. + */ +#define COAP_RESOURCE_DEFINE(_name, _service, ...) \ + STRUCT_SECTION_ITERABLE_ALTERNATE(coap_resource_##_service, coap_resource, _name) \ + = __VA_ARGS__ + +/** + * @brief Define a CoAP service with static resources. + * + * @note The @p _host parameter can be `NULL`. If not, it is used to specify an IP address either in + * IPv4 or IPv6 format a fully-qualified hostname or a virtual host, otherwise the any address is + * used. + * + * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port + * number to use for the service. If the specified port number is zero, then an ephemeral port + * number will be used and the actual port number assigned will be written back to memory. For + * ephemeral port numbers, the memory pointed to by @p _port must be writeable. + * + * @param _name Name of the service. + * @param _host IP address or hostname associated with the service. + * @param[inout] _port Pointer to port associated with the service. + * @param _flags Configuration flags @see @ref COAP_SERVICE_FLAGS. + */ +#define COAP_SERVICE_DEFINE(_name, _host, _port, _flags) \ + extern struct coap_resource _CONCAT(_coap_resource_##_name, _list_start)[]; \ + extern struct coap_resource _CONCAT(_coap_resource_##_name, _list_end)[]; \ + __z_coap_service_define(_name, _host, _port, _flags, \ + &_CONCAT(_coap_resource_##_name, _list_start)[0], \ + &_CONCAT(_coap_resource_##_name, _list_end)[0]) + +/** + * @brief Count the number of CoAP services. + * + * @param[out] _dst Pointer to location where result is written. + */ +#define COAP_SERVICE_COUNT(_dst) STRUCT_SECTION_COUNT(coap_service, _dst) + +/** + * @brief Count CoAP service static resources. + * + * @param _service Pointer to a service. + */ +#define COAP_SERVICE_RESOURCE_COUNT(_service) ((_service)->res_end - (_service)->res_begin) + +/** + * @brief Check if service has the specified resource. + * + * @param _service Pointer to a service. + * @param _resource Pointer to a resource. + */ +#define COAP_SERVICE_HAS_RESOURCE(_service, _resource) \ + ((_service)->res_begin <= _resource && _resource < (_service)->res_end) + +/** + * @brief Iterate over all CoAP services. + * + * @param _it Name of iterator (of type @ref coap_service) + */ +#define COAP_SERVICE_FOREACH(_it) STRUCT_SECTION_FOREACH(coap_service, _it) + +/** + * @brief Iterate over static CoAP resources associated with a given @p _service. + * + * @note This macro requires that @p _service is defined with @ref COAP_SERVICE_DEFINE. + * + * @param _service Name of CoAP service + * @param _it Name of iterator (of type @ref coap_resource) + */ +#define COAP_RESOURCE_FOREACH(_service, _it) \ + STRUCT_SECTION_FOREACH_ALTERNATE(coap_resource_##_service, coap_resource, _it) + +/** + * @brief Iterate over all static resources associated with @p _service . + * + * @note This macro is suitable for a @p _service defined with @ref COAP_SERVICE_DEFINE. + * + * @param _service Pointer to COAP service + * @param _it Name of iterator (of type @ref coap_resource) + */ +#define COAP_SERVICE_FOREACH_RESOURCE(_service, _it) \ + for (struct coap_resource *_it = (_service)->res_begin; ({ \ + __ASSERT(_it <= (_service)->res_end, "unexpected list end location"); \ + _it < (_service)->res_end; \ + }); _it++) + +/** + * @brief Start the provided @p service . + * + * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE. + * + * @param service Pointer to CoAP service + * @retval 0 in case of success. + * @retval -EALREADY in case of an already running service. + * @retval -ENOMEM in case the server has no available context. + */ +int coap_service_start(const struct coap_service *service); + +/** + * @brief Stop the provided @p service . + * + * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE. + * + * @param service Pointer to CoAP service + * @retval 0 in case of success. + * @retval -EALREADY in case the service isn't running. + */ +int coap_service_stop(const struct coap_service *service); + +/** + * @brief Send a CoAP message from the provided @p service . + * + * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE. + * + * @param service Pointer to CoAP service + * @param cpkt CoAP Packet to send + * @param addr Peer address + * @param addr_len Peer address length + * @return 0 in case of success or negative in case of error. + */ +int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt, + const struct sockaddr *addr, socklen_t addr_len); + +/** + * @brief Send a CoAP message from the provided @p resource . + * + * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE. + * + * @param resource Pointer to CoAP resource + * @param cpkt CoAP Packet to send + * @param addr Peer address + * @param addr_len Peer address length + * @return 0 in case of success or negative in case of error. + */ +int coap_resource_send(const struct coap_resource *resource, const struct coap_packet *cpkt, + const struct sockaddr *addr, socklen_t addr_len); + +/** + * @brief Parse a CoAP observe request for the provided @p resource . + * + * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE. + * + * If the observe option value is equal to 0, an observer will be added, if the value is equal + * to 1, an existing observer will be removed. + * + * @param resource Pointer to CoAP resource + * @param request CoAP request to parse + * @param addr Peer address + * @return the observe option value in case of success or negative in case of error. + */ +int coap_resource_parse_observe(struct coap_resource *resource, const struct coap_packet *request, + const struct sockaddr *addr); + +/** + * @brief Lookup an observer by address and remove it from the @p resource . + * + * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE. + * + * @param resource Pointer to CoAP resource + * @param addr Peer address + * @return 0 in case of success or negative in case of error. + */ +int coap_resource_remove_observer_by_addr(struct coap_resource *resource, + const struct sockaddr *addr); + +/** + * @brief Lookup an observer by token and remove it from the @p resource . + * + * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE. + * + * @param resource Pointer to CoAP resource + * @param token Pointer to the token + * @param token_len Length of valid bytes in the token + * @return 0 in case of success or negative in case of error. + */ +int coap_resource_remove_observer_by_token(struct coap_resource *resource, + const uint8_t *token, uint8_t token_len); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_NET_COAP_SERVICE_H_ */ diff --git a/subsys/net/lib/coap/CMakeLists.txt b/subsys/net/lib/coap/CMakeLists.txt index 39ef8196fbba4b8..b2e40f9bcfb8037 100644 --- a/subsys/net/lib/coap/CMakeLists.txt +++ b/subsys/net/lib/coap/CMakeLists.txt @@ -10,3 +10,7 @@ zephyr_sources_ifdef(CONFIG_COAP zephyr_sources_ifdef(CONFIG_COAP_CLIENT coap_client.c ) + +zephyr_sources_ifdef(CONFIG_COAP_SERVER + coap_server.c +) diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index 00ee157a11674a6..3125c4ce612ace1 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -153,6 +153,99 @@ config COAP_CLIENT_MAX_REQUESTS endif # COAP_CLIENT +config COAP_SERVER + bool "CoAP server support [EXPERIMENTAL]" + select EXPERIMENTAL + select NET_SOCKETS + select NET_SOCKETPAIR + help + This option enables the API for CoAP-services to register resources. + +if COAP_SERVER + +config COAP_SERVER_STACK_SIZE + int "CoAP server thread stack size" + default 4096 + help + CoAP server thread stack size for processing RX/TX events. + +config COAP_SERVER_BLOCK_SIZE + int "CoAP server block-wise transfer size" + default 256 + range 64 1024 + help + CoAP block size used by CoAP server resources when performing block-wise + transfers. Possible values: 64, 128, 256, 512 and 1024. + +config COAP_SERVER_MESSAGE_SIZE + int "CoAP server message payload size" + default COAP_SERVER_BLOCK_SIZE + help + CoAP server message payload size. Can't be smaller than COAP_SERVER_BLOCK_SIZE. + +config COAP_SERVER_MESSAGE_OPTIONS + int "CoAP server message options" + default 16 + help + CoAP server message maximum number of options to parse. + +config COAP_SERVER_WELL_KNOWN_CORE + bool "CoAP server support ./well-known/core service" + default y + help + Enable responding to the ./well-known/core service resource. + +config COAP_SERVICE_PENDING_MESSAGES + int "CoAP service pending messages" + default 10 + help + Maximum number of pending CoAP messages to retransmit per active service. + +config COAP_SERVICE_PENDING_RETRANSMITS + int "CoAP retransmit count" + default 2 + help + Maximum number of retries to send a pending message. + +config COAP_SERVICE_OBSERVERS + int "CoAP service observers" + default 3 + help + Maximum number of CoAP observers per active service. + +choice COAP_SERVER_PENDING_ALLOCATOR + prompt "Pending data allocator" + default COAP_SERVER_PENDING_ALLOCATOR_STATIC + +config COAP_SERVER_PENDING_ALLOCATOR_NONE + bool "No pending packets" + help + Never allocate data for pending requests, this disables retransmits for confirmable + packets. + +config COAP_SERVER_PENDING_ALLOCATOR_STATIC + bool "Static reserved memory" + help + Static memory will be reserved for pending messages. The total size is equal to + COAP_SERVER_PENDING_ALLOCATOR_STATIC_BLOCKS * COAP_SERVER_MESSAGE_SIZE. + +config COAP_SERVER_PENDING_ALLOCATOR_SYSTEM_HEAP + bool "System heap allocator" + depends on HEAP_MEM_POOL_SIZE > 0 + help + Use k_malloc/k_free for pending data. + +endchoice + +config COAP_SERVER_PENDING_ALLOCATOR_STATIC_BLOCKS + int "Number of pending data blocks" + default COAP_SERVICE_PENDING_MESSAGES + depends on COAP_SERVER_PENDING_ALLOCATOR_STATIC + help + The number of data blocks to reserve for pending messages to retransmit. + +endif + module = COAP module-dep = NET_LOG module-str = Log level for CoAP diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c new file mode 100644 index 000000000000000..fbcbe1721b2b421 --- /dev/null +++ b/subsys/net/lib/coap/coap_server.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +LOG_MODULE_DECLARE(net_coap, CONFIG_COAP_LOG_LEVEL); + +#include + +#include +#include +#include +#include +#include +#ifdef CONFIG_ARCH_POSIX +#include +#else +#include +#endif + +#if defined(CONFIG_NET_TC_THREAD_COOPERATIVE) +/* Lowest priority cooperative thread */ +#define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1) +#else +#define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1) +#endif + +#define ADDRLEN(sock) \ + (((struct sockaddr *)sock)->sa_family == AF_INET ? \ + sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) + +/* Shortened defines */ +#define MAX_OPTIONS CONFIG_COAP_SERVER_MESSAGE_OPTIONS +#define MAX_PENDINGS CONFIG_COAP_SERVICE_PENDING_MESSAGES +#define MAX_OBSERVERS CONFIG_COAP_SERVICE_OBSERVERS +#define MAX_POLL_FD CONFIG_NET_SOCKETS_POLL_MAX + +BUILD_ASSERT(CONFIG_NET_SOCKETS_POLL_MAX > 0, "CONFIG_NET_SOCKETS_POLL_MAX can't be 0"); + +static K_MUTEX_DEFINE(lock); +static int control_socks[2]; + +#if defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC) +K_MEM_SLAB_DEFINE_STATIC(pending_data, CONFIG_COAP_SERVER_MESSAGE_SIZE, + CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC_BLOCKS, 4); +#endif + +static inline void *coap_server_alloc(size_t len) +{ +#if defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC) + void *ptr; + int ret; + + if (len > CONFIG_COAP_SERVER_MESSAGE_SIZE) { + return NULL; + } + + ret = k_mem_slab_alloc(&pending_data, &ptr, K_NO_WAIT); + if (ret < 0) { + return NULL; + } + + return ptr; +#elif defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_SYSTEM_HEAP) + return k_malloc(len); +#else + ARG_UNUSED(len); + + return NULL; +#endif +} + +static inline void coap_server_free(void *ptr) +{ +#if defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC) + k_mem_slab_free(&pending_data, ptr); +#elif defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_SYSTEM_HEAP) + k_free(ptr); +#else + ARG_UNUSED(ptr); +#endif +} + +static int coap_service_remove_observer(const struct coap_service *service, + struct coap_resource *resource, + const struct sockaddr *addr, + const uint8_t *token, uint8_t tkl) +{ + struct coap_observer *obs; + + /* Prefer token to find the observer */ + if (tkl > 0 && token != NULL) { + obs = coap_find_observer_by_token(service->data->observers, MAX_OBSERVERS, token, + tkl); + } else if (addr != NULL) { + obs = coap_find_observer_by_addr(service->data->observers, MAX_OBSERVERS, addr); + } else { + /* Either a token or an address is required */ + return -EINVAL; + } + + if (obs == NULL) { + return 0; + } + + if (resource == NULL) { + COAP_SERVICE_FOREACH_RESOURCE(service, it) { + if (coap_remove_observer(it, obs)) { + memset(obs, 0, sizeof(*obs)); + return 1; + } + } + } else if (coap_remove_observer(resource, obs)) { + memset(obs, 0, sizeof(*obs)); + return 1; + } + + return 0; +} + +static int coap_server_process(int sock_fd) +{ + uint8_t buf[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct sockaddr client_addr; + socklen_t client_addr_len = sizeof(client_addr); + struct coap_service *service = NULL; + struct coap_packet request; + struct coap_pending *pending; + struct coap_option options[MAX_OPTIONS] = { 0 }; + uint8_t opt_num = MAX_OPTIONS; + uint8_t type; + ssize_t received; + int ret; + + received = zsock_recvfrom(sock_fd, buf, sizeof(buf), ZSOCK_MSG_DONTWAIT, &client_addr, + &client_addr_len); + __ASSERT_NO_MSG(received <= sizeof(buf)); + + if (received < 0) { + if (errno == EWOULDBLOCK) { + return 0; + } + + LOG_ERR("Failed to process client request (%d)", -errno); + return -errno; + } + + ret = coap_packet_parse(&request, buf, received, options, opt_num); + if (ret < 0) { + LOG_ERR("Failed To parse coap message (%d)", ret); + return ret; + } + + (void)k_mutex_lock(&lock, K_FOREVER); + /* Find the active service */ + COAP_SERVICE_FOREACH(svc) { + if (svc->data->sock_fd == sock_fd) { + service = svc; + break; + } + } + if (service == NULL) { + ret = -ENOENT; + goto unlock; + } + + type = coap_header_get_type(&request); + + pending = coap_pending_received(&request, service->data->pending, MAX_PENDINGS); + if (pending) { + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint8_t tkl; + + switch (type) { + case COAP_TYPE_RESET: + tkl = coap_header_get_token(&request, token); + coap_service_remove_observer(service, NULL, &client_addr, token, tkl); + __fallthrough; + case COAP_TYPE_ACK: + coap_server_free(pending->data); + coap_pending_clear(pending); + break; + default: + LOG_WRN("Unexpected pending type %d", type); + ret = -EINVAL; + goto unlock; + } + + goto unlock; + } else if (type == COAP_TYPE_ACK || type == COAP_TYPE_RESET) { + LOG_WRN("Unexpected type %d without pending packet", type); + ret = -EINVAL; + goto unlock; + } + + if (IS_ENABLED(CONFIG_COAP_SERVER_WELL_KNOWN_CORE) && + coap_header_get_code(&request) == COAP_METHOD_GET && + coap_uri_path_match(COAP_WELL_KNOWN_CORE_PATH, options, opt_num)) { + uint8_t well_known_buf[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + + ret = coap_well_known_core_get_len(service->res_begin, + COAP_SERVICE_RESOURCE_COUNT(service), + &request, &response, + well_known_buf, sizeof(well_known_buf)); + if (ret < 0) { + LOG_ERR("Failed to build well known core for %s (%d)", service->name, ret); + goto unlock; + } + + ret = coap_service_send(service, &response, &client_addr, client_addr_len); + } else { + ret = coap_handle_request_len(&request, service->res_begin, + COAP_SERVICE_RESOURCE_COUNT(service), + options, opt_num, &client_addr, client_addr_len); + + /* Shortcut for replying a code without a body */ + if (ret > 0 && type == COAP_TYPE_CON) { + /* Minimal sized ack buffer */ + uint8_t ack_buf[COAP_TOKEN_MAX_LEN + 4U]; + struct coap_packet ack; + + ret = coap_ack_init(&ack, &request, ack_buf, sizeof(ack_buf), (uint8_t)ret); + if (ret < 0) { + LOG_ERR("Failed to init ACK (%d)", ret); + goto unlock; + } + + ret = coap_service_send(service, &ack, &client_addr, client_addr_len); + } + } + +unlock: + (void)k_mutex_unlock(&lock); + + return ret; +} + +static void coap_server_retransmit(void) +{ + struct coap_pending *pending; + int64_t remaining; + int64_t now = k_uptime_get(); + int ret; + + (void)k_mutex_lock(&lock, K_FOREVER); + + COAP_SERVICE_FOREACH(service) { + if (service->data->sock_fd < 0) { + continue; + } + + pending = coap_pending_next_to_expire(service->data->pending, MAX_PENDINGS); + if (pending == NULL) { + /* No work to be done */ + continue; + } + + /* Check if the pending request has expired */ + remaining = pending->t0 + pending->timeout - now; + if (remaining > 0) { + continue; + } + + if (coap_pending_cycle(pending)) { + ret = zsock_sendto(service->data->sock_fd, pending->data, pending->len, 0, + &pending->addr, ADDRLEN(&pending->addr)); + if (ret < 0) { + LOG_ERR("Failed to send pending retransmission for %s (%d)", + service->name, ret); + } + __ASSERT_NO_MSG(ret == pending->len); + } else { + LOG_WRN("Packet retransmission failed for %s", service->name); + + coap_service_remove_observer(service, NULL, &pending->addr, NULL, 0U); + coap_server_free(pending->data); + coap_pending_clear(pending); + } + } + + (void)k_mutex_unlock(&lock); +} + +static int coap_server_poll_timeout(void) +{ + struct coap_pending *pending; + int64_t result = INT64_MAX; + int64_t remaining; + int64_t now = k_uptime_get(); + + COAP_SERVICE_FOREACH(svc) { + if (svc->data->sock_fd < -1) { + continue; + } + + pending = coap_pending_next_to_expire(svc->data->pending, MAX_PENDINGS); + if (pending == NULL) { + continue; + } + + remaining = pending->t0 + pending->timeout - now; + if (result > remaining) { + result = remaining; + } + } + + if (result == INT64_MAX) { + return -1; + } + + return MAX(result, 0); +} + +static void coap_server_update_services(void) +{ + zsock_send(control_socks[1], &(char){0}, 1, 0); +} + +static inline bool coap_service_in_section(const struct coap_service *service) +{ + STRUCT_SECTION_START_EXTERN(coap_service); + STRUCT_SECTION_END_EXTERN(coap_service); + + return STRUCT_SECTION_START(coap_service) <= service && + STRUCT_SECTION_END(coap_service) > service; +} + +int coap_service_start(const struct coap_service *service) +{ + int ret; + + uint8_t af; + socklen_t len; + struct sockaddr_storage addr_storage; + union { + struct sockaddr *addr; + struct sockaddr_in *addr4; + struct sockaddr_in6 *addr6; + } addr_ptrs = { + .addr = (struct sockaddr *)&addr_storage, + }; + + if (!coap_service_in_section(service)) { + __ASSERT_NO_MSG(false); + return -EINVAL; + } + + k_mutex_lock(&lock, K_FOREVER); + + if (service->data->sock_fd >= 0) { + ret = -EALREADY; + goto end; + } + + /* set the default address (in6addr_any / INADDR_ANY are all 0) */ + addr_storage = (struct sockaddr_storage){0}; + if (IS_ENABLED(CONFIG_NET_IPV6) && service->host != NULL && + zsock_inet_pton(AF_INET6, service->host, &addr_ptrs.addr6->sin6_addr) == 1) { + /* if a literal IPv6 address is provided as the host, use IPv6 */ + af = AF_INET6; + len = sizeof(struct sockaddr_in6); + + addr_ptrs.addr6->sin6_family = AF_INET6; + addr_ptrs.addr6->sin6_port = htons(*service->port); + } else if (IS_ENABLED(CONFIG_NET_IPV4) && service->host != NULL && + zsock_inet_pton(AF_INET, service->host, &addr_ptrs.addr4->sin_addr) == 1) { + /* if a literal IPv4 address is provided as the host, use IPv4 */ + af = AF_INET; + len = sizeof(struct sockaddr_in); + + addr_ptrs.addr4->sin_family = AF_INET; + addr_ptrs.addr4->sin_port = htons(*service->port); + } else if (IS_ENABLED(CONFIG_NET_IPV6)) { + /* prefer IPv6 if both IPv6 and IPv4 are supported */ + af = AF_INET6; + len = sizeof(struct sockaddr_in6); + + addr_ptrs.addr6->sin6_family = AF_INET6; + addr_ptrs.addr6->sin6_port = htons(*service->port); + } else if (IS_ENABLED(CONFIG_NET_IPV4)) { + af = AF_INET; + len = sizeof(struct sockaddr_in); + + addr_ptrs.addr4->sin_family = AF_INET; + addr_ptrs.addr4->sin_port = htons(*service->port); + } else { + ret = -ENOTSUP; + goto end; + } + + service->data->sock_fd = zsock_socket(af, SOCK_DGRAM, IPPROTO_UDP); + if (service->data->sock_fd < 0) { + ret = -errno; + goto end; + } + + ret = zsock_fcntl(service->data->sock_fd, F_SETFL, O_NONBLOCK); + if (ret < 0) { + ret = -errno; + goto close; + } + + ret = zsock_bind(service->data->sock_fd, addr_ptrs.addr, len); + if (ret < 0) { + ret = -errno; + goto close; + } + + if (*service->port == 0) { + /* ephemeral port - read back the port number */ + len = sizeof(addr_storage); + ret = zsock_getsockname(service->data->sock_fd, addr_ptrs.addr, &len); + if (ret < 0) { + goto close; + } + + if (af == AF_INET6) { + *service->port = addr_ptrs.addr6->sin6_port; + } else { + *service->port = addr_ptrs.addr4->sin_port; + } + } + +end: + k_mutex_unlock(&lock); + + coap_server_update_services(); + + return ret; + +close: + (void)zsock_close(service->data->sock_fd); + service->data->sock_fd = -1; + + k_mutex_unlock(&lock); + + return ret; +} + +int coap_service_stop(const struct coap_service *service) +{ + int ret; + + if (!coap_service_in_section(service)) { + __ASSERT_NO_MSG(false); + return -EINVAL; + } + + k_mutex_lock(&lock, K_FOREVER); + + if (service->data->sock_fd < 0) { + ret = -EALREADY; + goto end; + } + + /* Closing a socket will trigger a poll event */ + ret = zsock_close(service->data->sock_fd); + service->data->sock_fd = -1; + +end: + k_mutex_unlock(&lock); + + return ret; +} + +int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt, + const struct sockaddr *addr, socklen_t addr_len) +{ + int ret; + + if (!coap_service_in_section(service)) { + __ASSERT_NO_MSG(false); + return -EINVAL; + } + + (void)k_mutex_lock(&lock, K_FOREVER); + + if (service->data->sock_fd < 0) { + (void)k_mutex_unlock(&lock); + return -EBADF; + } + + /* + * Check if we should start with retransmits, if creating a pending message fails we still + * try to send. + */ + if (coap_header_get_type(cpkt) == COAP_TYPE_CON) { + struct coap_pending *pending = coap_pending_next_unused(service->data->pending, + MAX_PENDINGS); + + if (pending == NULL) { + LOG_WRN("No pending message available for %s", service->name); + goto send; + } + + ret = coap_pending_init(pending, cpkt, addr, + CONFIG_COAP_SERVICE_PENDING_RETRANSMITS); + if (ret < 0) { + LOG_WRN("Failed to init pending message for %s (%d)", service->name, ret); + goto send; + } + + /* Replace tracked data with our allocated copy */ + pending->data = coap_server_alloc(pending->len); + if (pending->data == NULL) { + LOG_WRN("Failed to allocate pending message data for %s", service->name); + coap_pending_clear(pending); + goto send; + } + memcpy(pending->data, cpkt->data, pending->len); + + coap_pending_cycle(pending); + + /* Trigger event in receive loop to schedule retransmit */ + coap_server_update_services(); + } + +send: + (void)k_mutex_unlock(&lock); + + ret = zsock_sendto(service->data->sock_fd, cpkt->data, cpkt->offset, 0, addr, addr_len); + if (ret < 0) { + LOG_ERR("Failed to send CoAP message (%d)", ret); + return ret; + } + __ASSERT_NO_MSG(ret == cpkt->offset); + + return 0; +} + +int coap_resource_send(const struct coap_resource *resource, const struct coap_packet *cpkt, + const struct sockaddr *addr, socklen_t addr_len) +{ + /* Find owning service */ + COAP_SERVICE_FOREACH(svc) { + if (COAP_SERVICE_HAS_RESOURCE(svc, resource)) { + return coap_service_send(svc, cpkt, addr, addr_len); + } + } + + return -ENOENT; +} + +int coap_resource_parse_observe(struct coap_resource *resource, const struct coap_packet *request, + const struct sockaddr *addr) +{ + const struct coap_service *service = NULL; + int ret; + + if (!coap_packet_is_request(request)) { + return -EINVAL; + } + + ret = coap_get_option_int(request, COAP_OPTION_OBSERVE); + if (ret < 0) { + return ret; + } + + /* Find owning service */ + COAP_SERVICE_FOREACH(svc) { + if (COAP_SERVICE_HAS_RESOURCE(svc, resource)) { + service = svc; + break; + } + } + + if (service == NULL) { + return -ENOENT; + } + + (void)k_mutex_lock(&lock, K_FOREVER); + + if (ret == 0) { + struct coap_observer *observer; + + observer = coap_observer_next_unused(service->data->observers, MAX_OBSERVERS); + if (observer == NULL) { + ret = -ENOMEM; + goto unlock; + } + + coap_observer_init(observer, request, addr); + coap_register_observer(resource, observer); + } else if (ret == 1) { + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint8_t tkl; + + tkl = coap_header_get_token(request, token); + ret = coap_service_remove_observer(service, resource, addr, token, tkl); + if (ret < 0) { + LOG_WRN("Failed to remove observer (%d)", ret); + } + } + +unlock: + (void)k_mutex_unlock(&lock); + + return ret; +} + +static int coap_resource_remove_observer(struct coap_resource *resource, + const struct sockaddr *addr, + const uint8_t *token, uint8_t token_len) +{ + const struct coap_service *service = NULL; + int ret; + + /* Find owning service */ + COAP_SERVICE_FOREACH(svc) { + if (COAP_SERVICE_HAS_RESOURCE(svc, resource)) { + service = svc; + break; + } + } + + if (service == NULL) { + return -ENOENT; + } + + (void)k_mutex_lock(&lock, K_FOREVER); + ret = coap_service_remove_observer(service, resource, addr, token, token_len); + (void)k_mutex_unlock(&lock); + + if (ret == 1) { + /* An observer was found and removed */ + return 0; + } else if (ret == 0) { + /* No matching observer found */ + return -ENOENT; + } + + /* An error occurred */ + return ret; +} + +int coap_resource_remove_observer_by_addr(struct coap_resource *resource, + const struct sockaddr *addr) +{ + return coap_resource_remove_observer(resource, addr, NULL, 0); +} + +int coap_resource_remove_observer_by_token(struct coap_resource *resource, + const uint8_t *token, uint8_t token_len) +{ + return coap_resource_remove_observer(resource, NULL, token, token_len); +} + +static void coap_server_thread(void *p1, void *p2, void *p3) +{ + struct zsock_pollfd sock_fds[MAX_POLL_FD]; + int sock_nfds; + int ret; + + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + /* Create a socket pair to wake zsock_poll */ + ret = zsock_socketpair(AF_UNIX, SOCK_STREAM, 0, control_socks); + if (ret < 0) { + LOG_ERR("Failed to create socket pair (%d)", ret); + return; + } + + for (int i = 0; i < 2; ++i) { + ret = zsock_fcntl(control_socks[i], F_SETFL, O_NONBLOCK); + + if (ret < 0) { + zsock_close(control_socks[0]); + zsock_close(control_socks[1]); + + LOG_ERR("Failed to set socket pair [%d] non-blocking (%d)", i, ret); + return; + } + } + + COAP_SERVICE_FOREACH(svc) { + /* Init all file descriptors to -1 */ + svc->data->sock_fd = -1; + + if (svc->flags & COAP_SERVICE_AUTOSTART) { + ret = coap_service_start(svc); + if (ret < 0) { + LOG_ERR("Failed to autostart service %s (%d)", svc->name, ret); + } + } + } + + while (true) { + sock_nfds = 0; + COAP_SERVICE_FOREACH(svc) { + if (svc->data->sock_fd < 0) { + continue; + } + if (sock_nfds >= MAX_POLL_FD) { + LOG_ERR("Maximum active CoAP services reached (%d), " + "increase CONFIG_NET_SOCKETS_POLL_MAX to support more.", + MAX_POLL_FD); + break; + } + + sock_fds[sock_nfds].fd = svc->data->sock_fd; + sock_fds[sock_nfds].events = ZSOCK_POLLIN; + sock_fds[sock_nfds].revents = 0; + sock_nfds++; + } + + /* Add socket pair FD to allow wake up */ + if (sock_nfds < MAX_POLL_FD) { + sock_fds[sock_nfds].fd = control_socks[0]; + sock_fds[sock_nfds].events = ZSOCK_POLLIN; + sock_fds[sock_nfds].revents = 0; + sock_nfds++; + } + + __ASSERT_NO_MSG(sock_nfds > 0); + + ret = zsock_poll(sock_fds, sock_nfds, coap_server_poll_timeout()); + if (ret < 0) { + LOG_ERR("Poll error (%d)", -errno); + k_msleep(10); + } + + for (int i = 0; i < sock_nfds; ++i) { + /* Check the wake up event */ + if (sock_fds[i].fd == control_socks[0] && + sock_fds[i].revents & ZSOCK_POLLIN) { + char tmp; + + zsock_recv(sock_fds[i].fd, &tmp, 1, 0); + continue; + } + + /* Check if socket can receive/was closed first */ + if (sock_fds[i].revents & ZSOCK_POLLIN) { + coap_server_process(sock_fds[i].fd); + continue; + } + + if (sock_fds[i].revents & ZSOCK_POLLERR) { + LOG_ERR("Poll error on %d", sock_fds[i].fd); + } + if (sock_fds[i].revents & ZSOCK_POLLHUP) { + LOG_ERR("Poll hup on %d", sock_fds[i].fd); + } + if (sock_fds[i].revents & ZSOCK_POLLNVAL) { + LOG_ERR("Poll invalid on %d", sock_fds[i].fd); + } + } + + /* Process retransmits */ + coap_server_retransmit(); + } +} + +K_THREAD_DEFINE(coap_server_id, CONFIG_COAP_SERVER_STACK_SIZE, + coap_server_thread, NULL, NULL, NULL, + THREAD_PRIORITY, 0, 0); From e8e6d23270e734c06225aef31af2ebad909557d5 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 4 Oct 2023 10:09:43 +0200 Subject: [PATCH 0110/1049] net: lib: coap: Add CoAP server shell Add shell commands that allow to start/stop CoAP services. Signed-off-by: Pieter De Gendt --- subsys/net/lib/coap/CMakeLists.txt | 4 + subsys/net/lib/coap/Kconfig | 6 ++ subsys/net/lib/coap/coap_server_shell.c | 98 +++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 subsys/net/lib/coap/coap_server_shell.c diff --git a/subsys/net/lib/coap/CMakeLists.txt b/subsys/net/lib/coap/CMakeLists.txt index b2e40f9bcfb8037..c0a555082b29794 100644 --- a/subsys/net/lib/coap/CMakeLists.txt +++ b/subsys/net/lib/coap/CMakeLists.txt @@ -14,3 +14,7 @@ zephyr_sources_ifdef(CONFIG_COAP_CLIENT zephyr_sources_ifdef(CONFIG_COAP_SERVER coap_server.c ) + +zephyr_sources_ifdef(CONFIG_COAP_SERVER_SHELL + coap_server_shell.c +) diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index 3125c4ce612ace1..8e62983ea729fdf 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -244,6 +244,12 @@ config COAP_SERVER_PENDING_ALLOCATOR_STATIC_BLOCKS help The number of data blocks to reserve for pending messages to retransmit. +config COAP_SERVER_SHELL + bool "CoAP service shell commands" + depends on SHELL + help + Enable CoAP service shell commands. + endif module = COAP diff --git a/subsys/net/lib/coap/coap_server_shell.c b/subsys/net/lib/coap/coap_server_shell.c new file mode 100644 index 000000000000000..bf0a52553da97a2 --- /dev/null +++ b/subsys/net/lib/coap/coap_server_shell.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + + +static int cmd_list(const struct shell *sh, size_t argc, char **argv) +{ + int count = 0; + + ARG_UNUSED(argv); + + if (argc > 1) { + return -EINVAL; + } + + shell_print(sh, " Name State Endpoint"); + COAP_SERVICE_FOREACH(service) { + shell_print(sh, + "[%2d] %-16s %-16s %s:%d", + ++count, + service->name, + service->data->sock_fd < 0 ? "INACTIVE" : "ACTIVE", + service->host != NULL ? service->host : "", + *service->port); + } + + if (count == 0) { + shell_print(sh, "No services available"); + return -ENOENT; + } + + return 0; +} + +static int cmd_start(const struct shell *sh, size_t argc, char **argv) +{ + int ret = -ENOENT; + + if (argc != 2) { + shell_error(sh, "Usage: start "); + return -EINVAL; + } + + COAP_SERVICE_FOREACH(service) { + if (strcmp(argv[1], service->name) == 0) { + ret = coap_service_start(service); + break; + } + } + + if (ret < 0) { + shell_error(sh, "Failed to start service (%d)", ret); + } + + return ret; +} + +static int cmd_stop(const struct shell *sh, size_t argc, char **argv) +{ + int ret = -ENOENT; + + if (argc != 2) { + shell_error(sh, "Usage: stop "); + return -EINVAL; + } + + COAP_SERVICE_FOREACH(service) { + if (strcmp(argv[1], service->name) == 0) { + ret = coap_service_stop(service); + break; + } + } + + if (ret < 0) { + shell_error(sh, "Failed to stop service (%d)", ret); + } + + return ret; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_coap_service, + SHELL_CMD(start, NULL, + "Start a CoAP Service\n" + "Usage: start ", + cmd_start), + SHELL_CMD(stop, NULL, + "Stop a CoAP Service\n" + "Usage: stop ", + cmd_stop), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); +SHELL_CMD_REGISTER(coap_service, &sub_coap_service, "CoAP Service commands", cmd_list); From 74db06694176e7807c8934e12c8f21750e96d025 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 21 Sep 2023 17:25:58 +0200 Subject: [PATCH 0111/1049] tests: net: lib: Add CoAP service tests Add a test for CoAP macro usage. Signed-off-by: Pieter De Gendt --- .../net/lib/coap_server/common/CMakeLists.txt | 10 + tests/net/lib/coap_server/common/prj.conf | 9 + .../lib/coap_server/common/sections-ram.ld | 7 + tests/net/lib/coap_server/common/src/main.c | 321 ++++++++++++++++++ .../net/lib/coap_server/common/testcase.yaml | 11 + 5 files changed, 358 insertions(+) create mode 100644 tests/net/lib/coap_server/common/CMakeLists.txt create mode 100644 tests/net/lib/coap_server/common/prj.conf create mode 100644 tests/net/lib/coap_server/common/sections-ram.ld create mode 100644 tests/net/lib/coap_server/common/src/main.c create mode 100644 tests/net/lib/coap_server/common/testcase.yaml diff --git a/tests/net/lib/coap_server/common/CMakeLists.txt b/tests/net/lib/coap_server/common/CMakeLists.txt new file mode 100644 index 000000000000000..6607ada694854ec --- /dev/null +++ b/tests/net/lib/coap_server/common/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(coap_service_defines) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +zephyr_linker_sources(DATA_SECTIONS sections-ram.ld) diff --git a/tests/net/lib/coap_server/common/prj.conf b/tests/net/lib/coap_server/common/prj.conf new file mode 100644 index 000000000000000..07cf69355fc080f --- /dev/null +++ b/tests/net/lib/coap_server/common/prj.conf @@ -0,0 +1,9 @@ +CONFIG_ZTEST=y + +CONFIG_NETWORKING=y +CONFIG_NET_TEST=y +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y + +CONFIG_COAP=y +CONFIG_COAP_SERVER=y diff --git a/tests/net/lib/coap_server/common/sections-ram.ld b/tests/net/lib/coap_server/common/sections-ram.ld new file mode 100644 index 000000000000000..d435ffbddd4fdb2 --- /dev/null +++ b/tests/net/lib/coap_server/common/sections-ram.ld @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include + +ITERABLE_SECTION_RAM(coap_resource_service_A, 4) +ITERABLE_SECTION_RAM(coap_resource_service_B, 4) +ITERABLE_SECTION_RAM(coap_resource_service_C, 4) diff --git a/tests/net/lib/coap_server/common/src/main.c b/tests/net/lib/coap_server/common/src/main.c new file mode 100644 index 000000000000000..7af940c5360963a --- /dev/null +++ b/tests/net/lib/coap_server/common/src/main.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +static int coap_method1(struct coap_resource *resource, struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + ARG_UNUSED(resource); + ARG_UNUSED(request); + ARG_UNUSED(addr); + ARG_UNUSED(addr_len); + + return -ENOSYS; +} + +static int coap_method2(struct coap_resource *resource, struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + ARG_UNUSED(resource); + ARG_UNUSED(request); + ARG_UNUSED(addr); + ARG_UNUSED(addr_len); + + return -ENOSYS; +} + +static const uint16_t service_A_port = 4242; +COAP_SERVICE_DEFINE(service_A, "a.service.com", &service_A_port, COAP_SERVICE_AUTOSTART); + +static const char * const resource_0_path[] = { "res0", NULL }; +COAP_RESOURCE_DEFINE(resource_0, service_A, { + .path = resource_0_path, + .get = coap_method1, + .put = coap_method2, +}); + +static const char * const resource_1_path[] = { "res1", NULL }; +COAP_RESOURCE_DEFINE(resource_1, service_A, { + .path = resource_1_path, + .post = coap_method1, +}); + +static uint16_t service_B_port; +COAP_SERVICE_DEFINE(service_B, "b.service.com", &service_B_port, COAP_SERVICE_AUTOSTART); + +static const char * const resource_2_path[] = { "res2", "sub", NULL }; +COAP_RESOURCE_DEFINE(resource_2, service_B, { + .path = resource_2_path, + .get = coap_method2, + .put = coap_method1, +}); + +static const char * const resource_3_path[] = { "res3", "+", NULL }; +COAP_RESOURCE_DEFINE(resource_3, service_B, { + .path = resource_3_path, + .post = coap_method2, +}); + +static const uint16_t service_C_port = 5959; +COAP_SERVICE_DEFINE(service_C, "192.168.1.1", &service_C_port, 0); + +static const char * const resource_4_path[] = { "res4", "*", NULL }; +COAP_RESOURCE_DEFINE(resource_4, service_C, { + .path = resource_4_path, + .get = coap_method1, +}); + +ZTEST(coap_service, test_COAP_SERVICE_DEFINE) +{ + zassert_ok(strcmp(service_A.host, "a.service.com")); + zassert_equal(service_A.port, &service_A_port); + zassert_equal(*service_A.port, 4242); + + zassert_ok(strcmp(service_B.host, "b.service.com")); + zassert_equal(service_B.port, &service_B_port); + zassert_equal(*service_B.port, 0); + + zassert_ok(strcmp(service_C.host, "192.168.1.1")); + zassert_equal(service_C.port, &service_C_port); + zassert_equal(*service_C.port, 5959); +} + +ZTEST(coap_service, test_COAP_SERVICE_COUNT) +{ + size_t n_svc; + + n_svc = 4273; + COAP_SERVICE_COUNT(&n_svc); + zassert_equal(n_svc, 3); +} + +ZTEST(coap_service, test_COAP_SERVICE_RESOURCE_COUNT) +{ + zassert_equal(COAP_SERVICE_RESOURCE_COUNT(&service_A), 2); + zassert_equal(COAP_SERVICE_RESOURCE_COUNT(&service_B), 2); + zassert_equal(COAP_SERVICE_RESOURCE_COUNT(&service_C), 1); +} + +ZTEST(coap_service, test_COAP_SERVICE_HAS_RESOURCE) +{ + zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_A, &resource_0)); + zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_A, &resource_1)); + zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_A, &resource_2)); + zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_A, &resource_3)); + + zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_B, &resource_0)); + zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_B, &resource_1)); + zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_B, &resource_2)); + zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_B, &resource_3)); + + zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_C, &resource_0)); + zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_C, &resource_4)); +} + +ZTEST(coap_service, test_COAP_SERVICE_FOREACH) +{ + size_t n_svc = 0; + size_t have_service_A = 0; + size_t have_service_B = 0; + size_t have_service_C = 0; + + COAP_SERVICE_FOREACH(svc) { + if (svc == &service_A) { + have_service_A = 1; + zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, COAP_SERVICE_AUTOSTART); + } else if (svc == &service_B) { + have_service_B = 1; + zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, COAP_SERVICE_AUTOSTART); + } else if (svc == &service_C) { + have_service_C = 1; + zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, 0); + } else { + zassert_unreachable("svc (%p) not equal to &service_A (%p), &service_B " + "(%p), or &service_C (%p)", + svc, &service_A, &service_B, &service_C); + } + + n_svc++; + } + + zassert_equal(n_svc, 3); + zassert_equal(have_service_A + have_service_B + have_service_C, n_svc); +} + +ZTEST(coap_service, test_COAP_RESOURCE_FOREACH) +{ + size_t first_res, second_res, n_res; + + n_res = 0; + first_res = 0; + second_res = 0; + COAP_RESOURCE_FOREACH(service_A, res) { + if (res == &resource_0) { + first_res = 1; + } else if (res == &resource_1) { + second_res = 1; + } else { + zassert_unreachable( + "res (%p) not equal to &resource_0 (%p) or &resource_1 (%p)", res, + &resource_0, &resource_1); + } + + n_res++; + } + + zassert_equal(n_res, 2); + zassert_equal(first_res + second_res, n_res); + + n_res = 0; + first_res = 0; + second_res = 0; + COAP_RESOURCE_FOREACH(service_B, res) { + if (res == &resource_2) { + first_res = 1; + } else if (res == &resource_3) { + second_res = 1; + } else { + zassert_unreachable( + "res (%p) not equal to &resource_2 (%p) or &resource_3 (%p)", res, + &resource_2, &resource_3); + } + + n_res++; + } + + zassert_equal(n_res, 2); + zassert_equal(first_res + second_res, n_res); + + n_res = 0; + first_res = 0; + second_res = 0; + COAP_RESOURCE_FOREACH(service_C, res) { + if (res == &resource_4) { + first_res = 1; + } else { + zassert_unreachable( + "res (%p) not equal to &resource_4 (%p)", res, &resource_4); + } + n_res++; + } + + zassert_equal(n_res, 1); + zassert_equal(first_res + second_res, n_res); +} + +ZTEST(coap_service, test_COAP_SERVICE_FOREACH_RESOURCE) +{ + size_t first_res, second_res, n_res; + + n_res = 0; + first_res = 0; + second_res = 0; + COAP_SERVICE_FOREACH_RESOURCE(&service_A, res) { + if (res == &resource_0) { + first_res = 1; + } else if (res == &resource_1) { + second_res = 1; + } else { + zassert_unreachable( + "res (%p) not equal to &resource_0 (%p) or &resource_1 (%p)", res, + &resource_0, &resource_1); + } + + n_res++; + } + + zassert_equal(n_res, 2); + zassert_equal(first_res + second_res, n_res); + + n_res = 0; + first_res = 0; + second_res = 0; + COAP_SERVICE_FOREACH_RESOURCE(&service_B, res) { + if (res == &resource_2) { + first_res = 1; + } else if (res == &resource_3) { + second_res = 1; + } else { + zassert_unreachable( + "res (%p) not equal to &resource_2 (%p) or &resource_3 (%p)", res, + &resource_2, &resource_3); + } + + n_res++; + } + + zassert_equal(n_res, 2); + zassert_equal(first_res + second_res, n_res); + + n_res = 0; + first_res = 0; + second_res = 0; + COAP_SERVICE_FOREACH_RESOURCE(&service_C, res) { + if (res == &resource_4) { + first_res = 1; + } else { + zassert_unreachable( + "res (%p) not equal to &resource_4 (%p)", res, &resource_4); + } + n_res++; + } + + zassert_equal(n_res, 1); + zassert_equal(first_res + second_res, n_res); +} + +ZTEST(coap_service, test_COAP_RESOURCE_DEFINE) +{ + COAP_SERVICE_FOREACH_RESOURCE(&service_A, res) { + if (res == &resource_0) { + zassert_ok(strcmp(res->path[0], "res0")); + zassert_equal(res->get, coap_method1); + zassert_equal(res->put, coap_method2); + } else if (res == &resource_1) { + zassert_ok(strcmp(res->path[0], "res1")); + zassert_equal(res->post, coap_method1); + } else { + zassert_unreachable( + "res (%p) not equal to &resource_0 (%p) or &resource_1 (%p)", res, + &resource_0, &resource_1); + } + } + + COAP_SERVICE_FOREACH_RESOURCE(&service_B, res) { + if (res == &resource_2) { + zassert_ok(strcmp(res->path[0], "res2")); + zassert_ok(strcmp(res->path[1], "sub")); + zassert_equal(res->get, coap_method2); + zassert_equal(res->put, coap_method1); + } else if (res == &resource_3) { + zassert_ok(strcmp(res->path[0], "res3")); + zassert_ok(strcmp(res->path[1], "+")); + zassert_equal(res->post, coap_method2); + } else { + zassert_unreachable( + "res (%p) not equal to &resource_2 (%p) or &resource_3 (%p)", res, + &resource_2, &resource_3); + } + } + + COAP_SERVICE_FOREACH_RESOURCE(&service_C, res) { + if (res == &resource_4) { + zassert_ok(strcmp(res->path[0], "res4")); + zassert_ok(strcmp(res->path[1], "*")); + zassert_equal(res->get, coap_method1); + zassert_equal(res->put, NULL); + } else { + zassert_unreachable( + "res (%p) not equal to &resource_4 (%p)", res, &resource_4); + } + } +} + +ZTEST_SUITE(coap_service, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/net/lib/coap_server/common/testcase.yaml b/tests/net/lib/coap_server/common/testcase.yaml new file mode 100644 index 000000000000000..c36e9646270542a --- /dev/null +++ b/tests/net/lib/coap_server/common/testcase.yaml @@ -0,0 +1,11 @@ +common: + min_ram: 16 + tags: + - net + - coap + - server + integration_platforms: + - native_posix + +tests: + net.coap.server.common: {} From 1f63c32c03041ca032eafed4f911a7f2149d056b Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 4 Oct 2023 12:29:04 +0200 Subject: [PATCH 0112/1049] samples: net: sockets: Add CoAP service example Replaced the CoAP server example with CoAP services. Signed-off-by: Pieter De Gendt --- .../net/sockets/coap_server/CMakeLists.txt | 2 + samples/net/sockets/coap_server/README.rst | 13 +- .../coap_server/boards/native_posix.conf | 3 + .../coap_server/boards/native_posix_64.conf | 3 + .../coap_server/boards/qemu_cortex_m3.conf | 4 + samples/net/sockets/coap_server/prj.conf | 7 +- samples/net/sockets/coap_server/sample.yaml | 8 +- .../net/sockets/coap_server/sections-ram.ld | 5 + .../net/sockets/coap_server/src/coap-server.c | 1466 ----------------- samples/net/sockets/coap_server/src/core.c | 81 + samples/net/sockets/coap_server/src/large.c | 266 +++ .../sockets/coap_server/src/location_query.c | 72 + samples/net/sockets/coap_server/src/main.c | 85 + .../net/sockets/coap_server/src/observer.c | 153 ++ samples/net/sockets/coap_server/src/query.c | 102 ++ .../net/sockets/coap_server/src/separate.c | 99 ++ samples/net/sockets/coap_server/src/test.c | 262 +++ 17 files changed, 1155 insertions(+), 1476 deletions(-) create mode 100644 samples/net/sockets/coap_server/boards/native_posix.conf create mode 100644 samples/net/sockets/coap_server/boards/native_posix_64.conf create mode 100644 samples/net/sockets/coap_server/boards/qemu_cortex_m3.conf create mode 100644 samples/net/sockets/coap_server/sections-ram.ld delete mode 100644 samples/net/sockets/coap_server/src/coap-server.c create mode 100644 samples/net/sockets/coap_server/src/core.c create mode 100644 samples/net/sockets/coap_server/src/large.c create mode 100644 samples/net/sockets/coap_server/src/location_query.c create mode 100644 samples/net/sockets/coap_server/src/main.c create mode 100644 samples/net/sockets/coap_server/src/observer.c create mode 100644 samples/net/sockets/coap_server/src/query.c create mode 100644 samples/net/sockets/coap_server/src/separate.c create mode 100644 samples/net/sockets/coap_server/src/test.c diff --git a/samples/net/sockets/coap_server/CMakeLists.txt b/samples/net/sockets/coap_server/CMakeLists.txt index 97f67d0a3587501..17d207098254be6 100644 --- a/samples/net/sockets/coap_server/CMakeLists.txt +++ b/samples/net/sockets/coap_server/CMakeLists.txt @@ -7,3 +7,5 @@ project(coap_server) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip) + +zephyr_linker_sources(DATA_SECTIONS sections-ram.ld) diff --git a/samples/net/sockets/coap_server/README.rst b/samples/net/sockets/coap_server/README.rst index 57e4a81880909da..89490ad399b736a 100644 --- a/samples/net/sockets/coap_server/README.rst +++ b/samples/net/sockets/coap_server/README.rst @@ -1,13 +1,18 @@ .. zephyr:code-sample:: coap-server - :name: CoAP server - :relevant-api: coap udp + :name: CoAP service + :relevant-api: coap coap_service udp - Use the CoAP library to implement a server that exposes CoAP resources. + Use the CoAP server subsystem to register CoAP resources. Overview ******** -This sample is a simple CoAP server showing how to expose a simple resource. +This sample shows how to register CoAP resources to a main CoAP service. +The CoAP server implementation expects all services and resources to be +available at compile time, as they are put into dedicated sections. + +The resource is placed into the correct linker section based on the owning +service's name. A linker file is required, see ``sections-ram.ld`` for an example. This demo assumes that the platform of choice has networking support, some adjustments to the configuration may be needed. diff --git a/samples/net/sockets/coap_server/boards/native_posix.conf b/samples/net/sockets/coap_server/boards/native_posix.conf new file mode 100644 index 000000000000000..b8f2d57be74311f --- /dev/null +++ b/samples/net/sockets/coap_server/boards/native_posix.conf @@ -0,0 +1,3 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y +CONFIG_NATIVE_UART_0_ON_STDINOUT=y diff --git a/samples/net/sockets/coap_server/boards/native_posix_64.conf b/samples/net/sockets/coap_server/boards/native_posix_64.conf new file mode 100644 index 000000000000000..b8f2d57be74311f --- /dev/null +++ b/samples/net/sockets/coap_server/boards/native_posix_64.conf @@ -0,0 +1,3 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y +CONFIG_NATIVE_UART_0_ON_STDINOUT=y diff --git a/samples/net/sockets/coap_server/boards/qemu_cortex_m3.conf b/samples/net/sockets/coap_server/boards/qemu_cortex_m3.conf new file mode 100644 index 000000000000000..dc256b47832a2f9 --- /dev/null +++ b/samples/net/sockets/coap_server/boards/qemu_cortex_m3.conf @@ -0,0 +1,4 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_ETH_DRIVER=y +CONFIG_ETH_STELLARIS=y +CONFIG_NET_QEMU_ETHERNET=y diff --git a/samples/net/sockets/coap_server/prj.conf b/samples/net/sockets/coap_server/prj.conf index 6a8b972b06923ca..1a26e61478623a4 100644 --- a/samples/net/sockets/coap_server/prj.conf +++ b/samples/net/sockets/coap_server/prj.conf @@ -10,7 +10,10 @@ CONFIG_NET_SOCKETS_POLL_MAX=4 # CoAP CONFIG_COAP=y +CONFIG_COAP_SERVER=y +CONFIG_COAP_SERVER_WELL_KNOWN_CORE=y CONFIG_COAP_WELL_KNOWN_BLOCK_WISE=n +CONFIG_COAP_OBSERVER_EVENTS=y # Kernel options CONFIG_ENTROPY_GENERATOR=y @@ -22,9 +25,7 @@ CONFIG_NET_LOG=y # Network Shell CONFIG_NET_SHELL=y - -CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_COAP_SERVER_SHELL=y # Configuration CONFIG_NET_CONFIG_SETTINGS=y diff --git a/samples/net/sockets/coap_server/sample.yaml b/samples/net/sockets/coap_server/sample.yaml index 8b6ab35ab6a93de..3c0cfe475db8139 100644 --- a/samples/net/sockets/coap_server/sample.yaml +++ b/samples/net/sockets/coap_server/sample.yaml @@ -1,12 +1,14 @@ common: filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample: - description: TBD - name: TBD + description: BSD Sockets API CoAP server example + name: socket_coap_server tests: sample.net.sockets.coap_server: harness: net tags: - net - socket - platform_allow: qemu_x86 + platform_allow: + - native_posix + - qemu_x86 diff --git a/samples/net/sockets/coap_server/sections-ram.ld b/samples/net/sockets/coap_server/sections-ram.ld new file mode 100644 index 000000000000000..04534264195305d --- /dev/null +++ b/samples/net/sockets/coap_server/sections-ram.ld @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include + +ITERABLE_SECTION_RAM(coap_resource_coap_server, 4) diff --git a/samples/net/sockets/coap_server/src/coap-server.c b/samples/net/sockets/coap_server/src/coap-server.c deleted file mode 100644 index ce47e31a2455e8b..000000000000000 --- a/samples/net/sockets/coap_server/src/coap-server.c +++ /dev/null @@ -1,1466 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(net_coap_server_sample, LOG_LEVEL_DBG); - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "net_private.h" -#if defined(CONFIG_NET_IPV6) -#include "ipv6.h" -#endif - -#define MAX_RETRANSMIT_COUNT 2 - -#define MAX_COAP_MSG_LEN 256 - -#define MY_COAP_PORT 5683 - -#define BLOCK_WISE_TRANSFER_SIZE_GET 2048 - -#if defined(CONFIG_NET_IPV6) -#define ALL_NODES_LOCAL_COAP_MCAST \ - { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } } - -#define MY_IP6ADDR \ - { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } } -#endif - -#define ADDRLEN(sock) \ - (((struct sockaddr *)sock)->sa_family == AF_INET ? \ - sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) - -#define NUM_OBSERVERS 3 - -#define NUM_PENDINGS 10 - -/* CoAP socket fd */ -static int sock; - -static struct coap_observer observers[NUM_OBSERVERS]; - -static struct coap_pending pendings[NUM_PENDINGS]; - -static struct k_work_delayable observer_work; - -static int obs_counter; - -static struct coap_resource *resource_to_notify; - -static struct k_work_delayable retransmit_work; - -#if defined(CONFIG_NET_IPV6) -static bool join_coap_multicast_group(void) -{ - static struct in6_addr my_addr = MY_IP6ADDR; - static struct sockaddr_in6 mcast_addr = { - .sin6_family = AF_INET6, - .sin6_addr = ALL_NODES_LOCAL_COAP_MCAST, - .sin6_port = htons(MY_COAP_PORT) }; - struct net_if_addr *ifaddr; - struct net_if *iface; - int ret; - - iface = net_if_get_default(); - if (!iface) { - LOG_ERR("Could not get te default interface\n"); - return false; - } - -#if defined(CONFIG_NET_CONFIG_SETTINGS) - if (net_addr_pton(AF_INET6, - CONFIG_NET_CONFIG_MY_IPV6_ADDR, - &my_addr) < 0) { - LOG_ERR("Invalid IPv6 address %s", - CONFIG_NET_CONFIG_MY_IPV6_ADDR); - } -#endif - - ifaddr = net_if_ipv6_addr_add(iface, &my_addr, NET_ADDR_MANUAL, 0); - if (!ifaddr) { - LOG_ERR("Could not add unicast address to interface"); - return false; - } - - ifaddr->addr_state = NET_ADDR_PREFERRED; - - ret = net_ipv6_mld_join(iface, &mcast_addr.sin6_addr); - if (ret < 0) { - LOG_ERR("Cannot join %s IPv6 multicast group (%d)", - net_sprint_ipv6_addr(&mcast_addr.sin6_addr), ret); - return false; - } - - return true; -} -#endif - -#if defined(CONFIG_NET_IPV6) -static int start_coap_server(void) -{ - struct sockaddr_in6 addr6; - int r; - - memset(&addr6, 0, sizeof(addr6)); - addr6.sin6_family = AF_INET6; - addr6.sin6_port = htons(MY_COAP_PORT); - - sock = socket(addr6.sin6_family, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) { - LOG_ERR("Failed to create UDP socket %d", errno); - return -errno; - } - - r = bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)); - if (r < 0) { - LOG_ERR("Failed to bind UDP socket %d", errno); - return -errno; - } - - return 0; -} -#endif - -#if defined(CONFIG_NET_IPV4) -static int start_coap_server(void) -{ - struct sockaddr_in addr; - int r; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(MY_COAP_PORT); - - sock = socket(addr.sin_family, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) { - LOG_ERR("Failed to create UDP socket %d", errno); - return -errno; - } - - r = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); - if (r < 0) { - LOG_ERR("Failed to bind UDP socket %d", errno); - return -errno; - } - - return 0; -} -#endif - -static int send_coap_reply(struct coap_packet *cpkt, - const struct sockaddr *addr, - socklen_t addr_len) -{ - int r; - - net_hexdump("Response", cpkt->data, cpkt->offset); - - r = sendto(sock, cpkt->data, cpkt->offset, 0, addr, addr_len); - if (r < 0) { - LOG_ERR("Failed to send %d", errno); - r = -errno; - } - - return r; -} - -static int well_known_core_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t *data; - int r; - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_well_known_core_get(resource, request, &response, - data, MAX_COAP_MSG_LEN); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int piggyback_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t payload[40]; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - goto end; - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, sizeof(payload), - "Type: %u\nCode: %u\nMID: %u\n", type, code, id); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)payload, - strlen(payload)); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int test_del(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint8_t tkl; - uint8_t code; - uint8_t type; - uint16_t id; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_DELETED, id); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int test_put(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t token[COAP_TOKEN_MAX_LEN]; - const uint8_t *payload; - uint8_t *data; - uint16_t payload_len; - uint8_t code; - uint8_t type; - uint8_t tkl; - uint16_t id; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - payload = coap_packet_get_payload(request, &payload_len); - if (payload) { - net_hexdump("PUT Payload", payload, payload_len); - } - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CHANGED, id); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int test_post(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static const char * const location_path[] = { "location1", - "location2", - "location3", - NULL }; - const char * const *p; - struct coap_packet response; - uint8_t token[COAP_TOKEN_MAX_LEN]; - const uint8_t *payload; - uint8_t *data; - uint16_t payload_len; - uint8_t code; - uint8_t type; - uint8_t tkl; - uint16_t id; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - payload = coap_packet_get_payload(request, &payload_len); - if (payload) { - net_hexdump("POST Payload", payload, payload_len); - } - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CREATED, id); - if (r < 0) { - goto end; - } - - for (p = location_path; *p; p++) { - r = coap_packet_append_option(&response, - COAP_OPTION_LOCATION_PATH, - *p, strlen(*p)); - if (r < 0) { - goto end; - } - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int query_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_option options[4]; - struct coap_packet response; - uint8_t payload[40]; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int i, r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - r = coap_find_options(request, COAP_OPTION_URI_QUERY, options, 4); - if (r < 0) { - return -EINVAL; - } - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("num queries: %d", r); - - for (i = 0; i < r; i++) { - char str[16]; - - if (options[i].len + 1 > sizeof(str)) { - LOG_INF("Unexpected length of query: " - "%d (expected %zu)", - options[i].len, sizeof(str)); - break; - } - - memcpy(str, options[i].value, options[i].len); - str[options[i].len] = '\0'; - - LOG_INF("query[%d]: %s", i + 1, str); - } - - LOG_INF("*******"); - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - goto end; - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, sizeof(payload), - "Type: %u\nCode: %u\nMID: %u\n", type, code, id); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)payload, - strlen(payload)); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int location_query_post(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static const char *const location_query[] = { "first=1", - "second=2", - NULL }; - const char * const *p; - struct coap_packet response; - uint8_t *data; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CREATED, id); - if (r < 0) { - goto end; - } - - for (p = location_query; *p; p++) { - r = coap_packet_append_option(&response, - COAP_OPTION_LOCATION_QUERY, - *p, strlen(*p)); - if (r < 0) { - goto end; - } - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int separate_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t payload[40]; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (type == COAP_TYPE_ACK) { - return 0; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, 0, id); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - if (r < 0) { - goto end; - } - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_CON; - } else { - type = COAP_TYPE_NON_CON; - } - - /* Do not free and allocate "data" again, re-use the buffer */ - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - goto end; - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, sizeof(payload), - "Type: %u\nCode: %u\nMID: %u\n", type, code, id); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)payload, - strlen(payload)); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int large_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) - -{ - static struct coap_block_context ctx; - struct coap_packet response; - uint8_t payload[64]; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t size; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - - if (ctx.total_size == 0) { - coap_block_transfer_init(&ctx, COAP_BLOCK_64, - BLOCK_WISE_TRANSFER_SIZE_GET); - } - - r = coap_update_from_block(request, &ctx); - if (r < 0) { - return -EINVAL; - } - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - return -EINVAL; - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_append_block2_option(&response, &ctx); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - size = MIN(coap_block_size_to_bytes(ctx.block_size), - ctx.total_size - ctx.current); - - memset(payload, 'A', MIN(size, sizeof(payload))); - - r = coap_packet_append_payload(&response, (uint8_t *)payload, size); - if (r < 0) { - goto end; - } - - r = coap_next_block(&response, &ctx); - if (!r) { - /* Will return 0 when it's the last block. */ - memset(&ctx, 0, sizeof(ctx)); - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int large_update_put(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static struct coap_block_context ctx; - struct coap_packet response; - const uint8_t *payload; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint16_t len; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - bool last_block; - - r = coap_get_option_int(request, COAP_OPTION_BLOCK1); - if (r < 0) { - return -EINVAL; - } - - last_block = !GET_MORE(r); - - /* initialize block context upon the arrival of first block */ - if (!GET_BLOCK_NUM(r)) { - coap_block_transfer_init(&ctx, COAP_BLOCK_64, 0); - } - - r = coap_update_from_block(request, &ctx); - if (r < 0) { - LOG_ERR("Invalid block size option from request"); - return -EINVAL; - } - - payload = coap_packet_get_payload(request, &len); - if (!last_block && payload == NULL) { - LOG_ERR("Packet without payload"); - return -EINVAL; - } - - LOG_INF("**************"); - LOG_INF("[ctx] current %zu block_size %u total_size %zu", - ctx.current, coap_block_size_to_bytes(ctx.block_size), - ctx.total_size); - LOG_INF("**************"); - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - /* Do something with the payload */ - - if (!last_block) { - code = COAP_RESPONSE_CODE_CONTINUE; - } else { - code = COAP_RESPONSE_CODE_CHANGED; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - code, id); - if (r < 0) { - goto end; - } - - r = coap_append_block1_option(&response, &ctx); - if (r < 0) { - LOG_ERR("Could not add Block1 option to response"); - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int large_create_post(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static struct coap_block_context ctx; - struct coap_packet response; - const uint8_t *payload; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t len; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - bool last_block; - - r = coap_get_option_int(request, COAP_OPTION_BLOCK1); - if (r < 0) { - return -EINVAL; - } - - last_block = !GET_MORE(r); - - /* initialize block context upon the arrival of first block */ - if (!GET_BLOCK_NUM(r)) { - coap_block_transfer_init(&ctx, COAP_BLOCK_32, 0); - } - - r = coap_update_from_block(request, &ctx); - if (r < 0) { - LOG_ERR("Invalid block size option from request"); - return -EINVAL; - } - - payload = coap_packet_get_payload(request, &len); - if (!last_block && payload) { - LOG_ERR("Packet without payload"); - return -EINVAL; - } - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (!last_block) { - code = COAP_RESPONSE_CODE_CONTINUE; - } else { - code = COAP_RESPONSE_CODE_CREATED; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - code, id); - if (r < 0) { - goto end; - } - - r = coap_append_block1_option(&response, &ctx); - if (r < 0) { - LOG_ERR("Could not add Block1 option to response"); - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static void schedule_next_retransmission(void) -{ - struct coap_pending *pending; - int64_t remaining; - int64_t now = k_uptime_get(); - - /* Get the first pending retransmission to expire after cycling. */ - pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); - if (!pending) { - return; - } - - remaining = pending->t0 + pending->timeout - now; - if (remaining < 0) { - remaining = 0; - } - - k_work_reschedule(&retransmit_work, K_MSEC(remaining)); -} - -static void remove_observer(struct sockaddr *addr); - -static void retransmit_request(struct k_work *work) -{ - struct coap_pending *pending; - int r; - - pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); - if (!pending) { - return; - } - - if (!coap_pending_cycle(pending)) { - remove_observer(&pending->addr); - k_free(pending->data); - coap_pending_clear(pending); - } else { - net_hexdump("Retransmit", pending->data, pending->len); - - r = sendto(sock, pending->data, pending->len, 0, - &pending->addr, ADDRLEN(&pending->addr)); - if (r < 0) { - LOG_ERR("Failed to send %d", errno); - } - } - - schedule_next_retransmission(); -} - -static void update_counter(struct k_work *work) -{ - obs_counter++; - - if (resource_to_notify) { - coap_resource_notify(resource_to_notify); - } - - k_work_reschedule(&observer_work, K_SECONDS(5)); -} - -static int create_pending_request(struct coap_packet *response, - const struct sockaddr *addr) -{ - struct coap_pending *pending; - int r; - - pending = coap_pending_next_unused(pendings, NUM_PENDINGS); - if (!pending) { - return -ENOMEM; - } - - r = coap_pending_init(pending, response, addr, MAX_RETRANSMIT_COUNT); - if (r < 0) { - return -EINVAL; - } - - coap_pending_cycle(pending); - - schedule_next_retransmission(); - - return 0; -} - -static int send_notification_packet(const struct sockaddr *addr, - socklen_t addr_len, - uint16_t age, uint16_t id, - const uint8_t *token, uint8_t tkl, - bool is_response) -{ - struct coap_packet response; - char payload[14]; - uint8_t *data; - uint8_t type; - int r; - - if (is_response) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_CON; - } - - if (!is_response) { - id = coap_next_id(); - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - goto end; - } - - if (age >= 2U) { - r = coap_append_option_int(&response, COAP_OPTION_OBSERVE, age); - if (r < 0) { - goto end; - } - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, sizeof(payload), - "Counter: %d\n", obs_counter); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)payload, - strlen(payload)); - if (r < 0) { - goto end; - } - - if (type == COAP_TYPE_CON) { - r = create_pending_request(&response, addr); - if (r < 0) { - goto end; - } - } - - k_work_reschedule(&observer_work, K_SECONDS(5)); - - r = send_coap_reply(&response, addr, addr_len); - - /* On successful creation of pending request, do not free memory */ - if (type == COAP_TYPE_CON) { - return r; - } - -end: - k_free(data); - - return r; -} - -static int obs_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_observer *observer; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - bool observe = true; - - if (!coap_request_is_observe(request)) { - if (coap_get_option_int(request, COAP_OPTION_OBSERVE) == 1) { - remove_observer(addr); - } - observe = false; - goto done; - } - - observer = coap_observer_next_unused(observers, NUM_OBSERVERS); - if (!observer) { - LOG_ERR("Not enough observer slots."); - return -ENOMEM; - } - - coap_observer_init(observer, request, addr); - - coap_register_observer(resource, observer); - - resource_to_notify = resource; - -done: - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - return send_notification_packet(addr, addr_len, - observe ? resource->age : 0, - id, token, tkl, true); -} - -static void obs_notify(struct coap_resource *resource, - struct coap_observer *observer) -{ - send_notification_packet(&observer->addr, - sizeof(observer->addr), - resource->age, 0, - observer->token, observer->tkl, false); -} - -static int core_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static const char dummy_str[] = "Just a test\n"; - struct coap_packet response; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint8_t tkl; - int r; - - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - r = -EINVAL; - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - r = -EINVAL; - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)dummy_str, - sizeof(dummy_str)); - if (r < 0) { - r = -EINVAL; - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static const char * const test_path[] = { "test", NULL }; - -static const char * const segments_path[] = { "seg1", "seg2", "seg3", NULL }; - -#if defined(CONFIG_COAP_URI_WILDCARD) -static const char * const wildcard1_path[] = { "wild1", "+", "wild3", NULL }; - -static const char * const wildcard2_path[] = { "wild2", "#", NULL }; -#endif /* CONFIG_COAP_URI_WILDCARD */ - -static const char * const query_path[] = { "query", NULL }; - -static const char * const separate_path[] = { "separate", NULL }; - -static const char * const location_query_path[] = { "location-query", NULL }; - -static const char * const large_path[] = { "large", NULL }; - -static const char * const large_update_path[] = { "large-update", NULL }; - -static const char * const large_create_path[] = { "large-create", NULL }; - -static const char * const obs_path[] = { "obs", NULL }; - -static const char * const core_1_path[] = { "core1", NULL }; -static const char * const core_1_attributes[] = { - "title=\"Core 1\"", - "rt=core1", - NULL }; - -static const char * const core_2_path[] = { "core2", NULL }; -static const char * const core_2_attributes[] = { - "title=\"Core 1\"", - "rt=core1", - NULL }; - -static struct coap_resource coap_resources[] = { - { .get = well_known_core_get, - .path = COAP_WELL_KNOWN_CORE_PATH, - }, - { .get = piggyback_get, - .post = test_post, - .del = test_del, - .put = test_put, - .path = test_path - }, - { .get = piggyback_get, - .path = segments_path, - }, -#if defined(CONFIG_COAP_URI_WILDCARD) - { .get = piggyback_get, - .path = wildcard1_path, - }, - { .get = piggyback_get, - .path = wildcard2_path, - }, -#endif /* CONFIG_COAP_URI_WILDCARD */ - { .get = query_get, - .path = query_path, - }, - { .get = separate_get, - .path = separate_path, - }, - { .path = location_query_path, - .post = location_query_post, - }, - { .path = large_path, - .get = large_get, - }, - { .path = large_update_path, - .put = large_update_put, - }, - { .path = large_create_path, - .post = large_create_post, - }, - { .path = obs_path, - .get = obs_get, - .notify = obs_notify, - }, - { .get = core_get, - .path = core_1_path, - .user_data = &((struct coap_core_metadata) { - .attributes = core_1_attributes, - }), - }, - { .get = core_get, - .path = core_2_path, - .user_data = &((struct coap_core_metadata) { - .attributes = core_2_attributes, - }), - }, - { }, -}; - -static struct coap_resource *find_resource_by_observer( - struct coap_resource *resources, struct coap_observer *o) -{ - struct coap_resource *r; - - for (r = resources; r && r->path; r++) { - sys_snode_t *node; - - SYS_SLIST_FOR_EACH_NODE(&r->observers, node) { - if (&o->list == node) { - return r; - } - } - } - - return NULL; -} - -static void remove_observer(struct sockaddr *addr) -{ - struct coap_resource *r; - struct coap_observer *o; - - o = coap_find_observer_by_addr(observers, NUM_OBSERVERS, addr); - if (!o) { - return; - } - - r = find_resource_by_observer(coap_resources, o); - if (!r) { - LOG_ERR("Observer found but Resource not found\n"); - return; - } - - LOG_INF("Removing observer %p", o); - - coap_remove_observer(r, o); - memset(o, 0, sizeof(struct coap_observer)); -} - -static void process_coap_request(uint8_t *data, uint16_t data_len, - struct sockaddr *client_addr, - socklen_t client_addr_len) -{ - struct coap_packet request; - struct coap_pending *pending; - struct coap_option options[16] = { 0 }; - uint8_t opt_num = 16U; - uint8_t type; - int r; - - r = coap_packet_parse(&request, data, data_len, options, opt_num); - if (r < 0) { - LOG_ERR("Invalid data received (%d)\n", r); - return; - } - - type = coap_header_get_type(&request); - - pending = coap_pending_received(&request, pendings, NUM_PENDINGS); - if (!pending) { - goto not_found; - } - - /* Clear CoAP pending request */ - if (type == COAP_TYPE_ACK || type == COAP_TYPE_RESET) { - k_free(pending->data); - coap_pending_clear(pending); - - if (type == COAP_TYPE_RESET) { - remove_observer(client_addr); - } - } - - return; - -not_found: - r = coap_handle_request(&request, coap_resources, options, opt_num, - client_addr, client_addr_len); - if (r < 0) { - LOG_WRN("No handler for such request (%d)\n", r); - } -} - -static int process_client_request(void) -{ - int received; - struct sockaddr client_addr; - socklen_t client_addr_len; - uint8_t request[MAX_COAP_MSG_LEN]; - - do { - client_addr_len = sizeof(client_addr); - received = recvfrom(sock, request, sizeof(request), 0, - &client_addr, &client_addr_len); - if (received < 0) { - LOG_ERR("Connection error %d", errno); - return -errno; - } - - process_coap_request(request, received, &client_addr, - client_addr_len); - } while (true); - - return 0; -} - -int main(void) -{ - int r; - - LOG_DBG("Start CoAP-server sample"); - -#if defined(CONFIG_NET_IPV6) - bool res; - - res = join_coap_multicast_group(); - if (!res) { - goto quit; - } -#endif - - r = start_coap_server(); - if (r < 0) { - goto quit; - } - - k_work_init_delayable(&retransmit_work, retransmit_request); - k_work_init_delayable(&observer_work, update_counter); - - while (1) { - r = process_client_request(); - if (r < 0) { - goto quit; - } - } - - LOG_DBG("Done"); - return 0; - -quit: - LOG_ERR("Quit"); - return 0; -} diff --git a/samples/net/sockets/coap_server/src/core.c b/samples/net/sockets/coap_server/src/core.c new file mode 100644 index 000000000000000..276ab0d5de1895f --- /dev/null +++ b/samples/net/sockets/coap_server/src/core.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include +#include + +static int core_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + static const char dummy_str[] = "Just a test\n"; + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t tkl; + int r; + + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)dummy_str, + sizeof(dummy_str)); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static const char * const core_1_path[] = { "core1", NULL }; +static const char * const core_1_attributes[] = { + "title=\"Core 1\"", + "rt=core1", + NULL, +}; +COAP_RESOURCE_DEFINE(core_1, coap_server, +{ + .get = core_get, + .path = core_1_path, + .user_data = &((struct coap_core_metadata) { + .attributes = core_1_attributes, + }), +}); + +static const char * const core_2_path[] = { "core2", NULL }; +static const char * const core_2_attributes[] = { + "title=\"Core 2\"", + "rt=core2", + NULL, +}; +COAP_RESOURCE_DEFINE(core_2, coap_server, +{ + .get = core_get, + .path = core_2_path, + .user_data = &((struct coap_core_metadata) { + .attributes = core_2_attributes, + }), +}); diff --git a/samples/net/sockets/coap_server/src/large.c b/samples/net/sockets/coap_server/src/large.c new file mode 100644 index 000000000000000..28a3eebe099facf --- /dev/null +++ b/samples/net/sockets/coap_server/src/large.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +#define BLOCK_WISE_TRANSFER_SIZE_GET 2048 + +static int large_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) + +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + static struct coap_block_context ctx; + struct coap_packet response; + uint8_t payload[64]; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t size; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + if (ctx.total_size == 0) { + coap_block_transfer_init(&ctx, COAP_BLOCK_64, BLOCK_WISE_TRANSFER_SIZE_GET); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + return -EINVAL; + } + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return -EINVAL; + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_append_block2_option(&response, &ctx); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + size = MIN(coap_block_size_to_bytes(ctx.block_size), + ctx.total_size - ctx.current); + + memset(payload, 'A', MIN(size, sizeof(payload))); + + r = coap_packet_append_payload(&response, (uint8_t *)payload, size); + if (r < 0) { + return r; + } + + r = coap_next_block(&response, &ctx); + if (!r) { + /* Will return 0 when it's the last block. */ + memset(&ctx, 0, sizeof(ctx)); + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static int large_update_put(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + static struct coap_block_context ctx; + struct coap_packet response; + const uint8_t *payload; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint16_t len; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + bool last_block; + + r = coap_get_option_int(request, COAP_OPTION_BLOCK1); + if (r < 0) { + return -EINVAL; + } + + last_block = !GET_MORE(r); + + /* initialize block context upon the arrival of first block */ + if (!GET_BLOCK_NUM(r)) { + coap_block_transfer_init(&ctx, COAP_BLOCK_64, 0); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + LOG_ERR("Invalid block size option from request"); + return -EINVAL; + } + + payload = coap_packet_get_payload(request, &len); + if (!last_block && payload == NULL) { + LOG_ERR("Packet without payload"); + return -EINVAL; + } + + LOG_INF("**************"); + LOG_INF("[ctx] current %zu block_size %u total_size %zu", + ctx.current, coap_block_size_to_bytes(ctx.block_size), + ctx.total_size); + LOG_INF("**************"); + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + /* Do something with the payload */ + + if (!last_block) { + code = COAP_RESPONSE_CODE_CONTINUE; + } else { + code = COAP_RESPONSE_CODE_CHANGED; + } + + r = coap_ack_init(&response, request, data, sizeof(data), code); + if (r < 0) { + return r; + } + + r = coap_append_block1_option(&response, &ctx); + if (r < 0) { + LOG_ERR("Could not add Block1 option to response"); + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static int large_create_post(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + static struct coap_block_context ctx; + struct coap_packet response; + const uint8_t *payload; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t len; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + bool last_block; + + r = coap_get_option_int(request, COAP_OPTION_BLOCK1); + if (r < 0) { + return -EINVAL; + } + + last_block = !GET_MORE(r); + + /* initialize block context upon the arrival of first block */ + if (!GET_BLOCK_NUM(r)) { + coap_block_transfer_init(&ctx, COAP_BLOCK_32, 0); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + LOG_ERR("Invalid block size option from request"); + return -EINVAL; + } + + payload = coap_packet_get_payload(request, &len); + if (!last_block && payload) { + LOG_ERR("Packet without payload"); + return -EINVAL; + } + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (!last_block) { + code = COAP_RESPONSE_CODE_CONTINUE; + } else { + code = COAP_RESPONSE_CODE_CREATED; + } + + r = coap_ack_init(&response, request, data, sizeof(data), code); + if (r < 0) { + return r; + } + + r = coap_append_block1_option(&response, &ctx); + if (r < 0) { + LOG_ERR("Could not add Block1 option to response"); + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static const char * const large_path[] = { "large", NULL }; +COAP_RESOURCE_DEFINE(large, coap_server, +{ + .get = large_get, + .path = large_path, +}); + +static const char * const large_update_path[] = { "large-update", NULL }; +COAP_RESOURCE_DEFINE(large_update, coap_server, +{ + .put = large_update_put, + .path = large_update_path, +}); + +static const char * const large_create_path[] = { "large-create", NULL }; +COAP_RESOURCE_DEFINE(large_create, coap_server, +{ + .post = large_create_post, + .path = large_create_path, +}); diff --git a/samples/net/sockets/coap_server/src/location_query.c b/samples/net/sockets/coap_server/src/location_query.c new file mode 100644 index 000000000000000..b13079bc4567afb --- /dev/null +++ b/samples/net/sockets/coap_server/src/location_query.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +static int location_query_post(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + static const char *const location_query[] = { "first=1", + "second=2", + NULL }; + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + const char * const *p; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CREATED, id); + if (r < 0) { + return r; + } + + for (p = location_query; *p; p++) { + r = coap_packet_append_option(&response, + COAP_OPTION_LOCATION_QUERY, + *p, strlen(*p)); + if (r < 0) { + return r; + } + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static const char * const location_query_path[] = { "location-query", NULL }; +COAP_RESOURCE_DEFINE(location_query, coap_server, +{ + .post = location_query_post, + .path = location_query_path, +}); diff --git a/samples/net/sockets/coap_server/src/main.c b/samples/net/sockets/coap_server/src/main.c new file mode 100644 index 000000000000000..4f476511b2cfc38 --- /dev/null +++ b/samples/net/sockets/coap_server/src/main.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(net_coap_service_sample, LOG_LEVEL_DBG); + +#include + +#ifdef CONFIG_NET_IPV6 +#include "net_private.h" +#include "ipv6.h" +#endif + +static const uint16_t coap_port = 5683; + +#ifdef CONFIG_NET_IPV6 + +#define ALL_NODES_LOCAL_COAP_MCAST \ + { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } } + +#define MY_IP6ADDR \ + { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } } + +static int join_coap_multicast_group(void) +{ + static struct in6_addr my_addr = MY_IP6ADDR; + static struct sockaddr_in6 mcast_addr = { + .sin6_family = AF_INET6, + .sin6_addr = ALL_NODES_LOCAL_COAP_MCAST, + .sin6_port = htons(coap_port) }; + struct net_if_addr *ifaddr; + struct net_if *iface; + int ret; + + iface = net_if_get_default(); + if (!iface) { + LOG_ERR("Could not get the default interface"); + return -ENOENT; + } + +#if defined(CONFIG_NET_CONFIG_SETTINGS) + if (net_addr_pton(AF_INET6, + CONFIG_NET_CONFIG_MY_IPV6_ADDR, + &my_addr) < 0) { + LOG_ERR("Invalid IPv6 address %s", + CONFIG_NET_CONFIG_MY_IPV6_ADDR); + } +#endif + + ifaddr = net_if_ipv6_addr_add(iface, &my_addr, NET_ADDR_MANUAL, 0); + if (!ifaddr) { + LOG_ERR("Could not add unicast address to interface"); + return -EINVAL; + } + + ifaddr->addr_state = NET_ADDR_PREFERRED; + + ret = net_ipv6_mld_join(iface, &mcast_addr.sin6_addr); + if (ret < 0) { + LOG_ERR("Cannot join %s IPv6 multicast group (%d)", + net_sprint_ipv6_addr(&mcast_addr.sin6_addr), ret); + return ret; + } + + return 0; +} + +int main(void) +{ + return join_coap_multicast_group(); +} + +#else /* CONFIG_NET_IPV6 */ + +int main(void) +{ + return 0; +} + +#endif /* CONFIG_NET_IPV6 */ + +COAP_SERVICE_DEFINE(coap_server, NULL, &coap_port, COAP_SERVICE_AUTOSTART); diff --git a/samples/net/sockets/coap_server/src/observer.c b/samples/net/sockets/coap_server/src/observer.c new file mode 100644 index 000000000000000..29b7b4ed47274a5 --- /dev/null +++ b/samples/net/sockets/coap_server/src/observer.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include +#include + +static int obs_counter; + +static void update_counter(struct k_work *work); +K_WORK_DELAYABLE_DEFINE(obs_work, update_counter); + +#ifdef CONFIG_COAP_OBSERVER_EVENTS + +static void observer_event(struct coap_resource *resource, struct coap_observer *observer, + enum coap_observer_event event) +{ + LOG_INF("Observer %s", event == COAP_OBSERVER_ADDED ? "added" : "removed"); +} + +#endif + +static int send_notification_packet(struct coap_resource *resource, + const struct sockaddr *addr, + socklen_t addr_len, + uint16_t age, uint16_t id, + const uint8_t *token, uint8_t tkl, + bool is_response) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + char payload[14]; + uint8_t type; + int r; + + if (is_response) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_CON; + } + + if (!is_response) { + id = coap_next_id(); + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + if (age >= 2U) { + r = coap_append_option_int(&response, COAP_OPTION_OBSERVE, age); + if (r < 0) { + return r; + } + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Counter: %d\n", obs_counter); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)payload, + strlen(payload)); + if (r < 0) { + return r; + } + + k_work_reschedule(&obs_work, K_SECONDS(5)); + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static int obs_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + r = coap_resource_parse_observe(resource, request, addr); + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + return send_notification_packet(resource, addr, addr_len, + r == 0 ? resource->age : 0, + id, token, tkl, true); +} + +static void obs_notify(struct coap_resource *resource, + struct coap_observer *observer) +{ + send_notification_packet(resource, + &observer->addr, + sizeof(observer->addr), + resource->age, 0, + observer->token, observer->tkl, false); +} + +static const char * const obs_path[] = { "obs", NULL }; +COAP_RESOURCE_DEFINE(obs, coap_server, +{ + .get = obs_get, + .path = obs_path, + .notify = obs_notify, +#ifdef CONFIG_COAP_OBSERVER_EVENTS + .observer_event_handler = observer_event, +#endif +}); + +static void update_counter(struct k_work *work) +{ + obs_counter++; + + coap_resource_notify(&obs); + + k_work_reschedule(&obs_work, K_SECONDS(5)); +} diff --git a/samples/net/sockets/coap_server/src/query.c b/samples/net/sockets/coap_server/src/query.c new file mode 100644 index 000000000000000..10479b1e6f19437 --- /dev/null +++ b/samples/net/sockets/coap_server/src/query.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +static int query_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_option options[4]; + struct coap_packet response; + uint8_t payload[40]; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int i, r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + r = coap_find_options(request, COAP_OPTION_URI_QUERY, options, 4); + if (r < 0) { + return -EINVAL; + } + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("num queries: %d", r); + + for (i = 0; i < r; i++) { + char str[16]; + + if (options[i].len + 1 > sizeof(str)) { + LOG_INF("Unexpected length of query: " + "%d (expected %zu)", + options[i].len, sizeof(str)); + break; + } + + memcpy(str, options[i].value, options[i].len); + str[options[i].len] = '\0'; + + LOG_INF("query[%d]: %s", i + 1, str); + } + + LOG_INF("*******"); + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)payload, + strlen(payload)); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static const char * const query_path[] = { "query", NULL }; +COAP_RESOURCE_DEFINE(query, coap_server, +{ + .get = query_get, + .path = query_path, +}); diff --git a/samples/net/sockets/coap_server/src/separate.c b/samples/net/sockets/coap_server/src/separate.c new file mode 100644 index 000000000000000..c3f6f6c256ee9f4 --- /dev/null +++ b/samples/net/sockets/coap_server/src/separate.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +static int separate_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t payload[40]; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (type == COAP_TYPE_ACK) { + return 0; + } + + r = coap_ack_init(&response, request, data, sizeof(data), 0); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len); + if (r < 0) { + return r; + } + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_CON; + } else { + type = COAP_TYPE_NON_CON; + } + + /* Re-use the buffer */ + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)payload, + strlen(payload)); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static const char * const separate_path[] = { "separate", NULL }; +COAP_RESOURCE_DEFINE(separate, coap_server, +{ + .get = separate_get, + .path = separate_path, +}); diff --git a/samples/net/sockets/coap_server/src/test.c b/samples/net/sockets/coap_server/src/test.c new file mode 100644 index 000000000000000..aa496a125b10080 --- /dev/null +++ b/samples/net/sockets/coap_server/src/test.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +#include "net_private.h" + +static int piggyback_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t payload[40]; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)payload, + strlen(payload)); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static int test_del(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint8_t tkl; + uint8_t code; + uint8_t type; + uint16_t id; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_DELETED, id); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static int test_put(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + const uint8_t *payload; + uint16_t payload_len; + uint8_t code; + uint8_t type; + uint8_t tkl; + uint16_t id; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + payload = coap_packet_get_payload(request, &payload_len); + if (payload) { + net_hexdump("PUT Payload", payload, payload_len); + } + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CHANGED, id); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static int test_post(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + static const char * const location_path[] = { "location1", + "location2", + "location3", + NULL }; + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + const char * const *p; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + const uint8_t *payload; + uint16_t payload_len; + uint8_t code; + uint8_t type; + uint8_t tkl; + uint16_t id; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + payload = coap_packet_get_payload(request, &payload_len); + if (payload) { + net_hexdump("POST Payload", payload, payload_len); + } + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CREATED, id); + if (r < 0) { + return r; + } + + for (p = location_path; *p; p++) { + r = coap_packet_append_option(&response, + COAP_OPTION_LOCATION_PATH, + *p, strlen(*p)); + if (r < 0) { + return r; + } + } + + r = coap_resource_send(resource, &response, addr, addr_len); + + return r; +} + +static const char * const test_path[] = { "test", NULL }; +COAP_RESOURCE_DEFINE(test, coap_server, +{ + .get = piggyback_get, + .post = test_post, + .del = test_del, + .put = test_put, + .path = test_path, +}); + +static const char * const segments_path[] = { "seg1", "seg2", "seg3", NULL }; +COAP_RESOURCE_DEFINE(segments, coap_server, +{ + .get = piggyback_get, + .path = segments_path, +}); + +#if defined(CONFIG_COAP_URI_WILDCARD) + +static const char * const wildcard1_path[] = { "wild1", "+", "wild3", NULL }; +COAP_RESOURCE_DEFINE(wildcard1, coap_server, +{ + .get = piggyback_get, + .path = wildcard1_path, +}); + +static const char * const wildcard2_path[] = { "wild2", "#", NULL }; +COAP_RESOURCE_DEFINE(wildcard2, coap_server, +{ + .get = piggyback_get, + .path = wildcard2_path, +}); + +#endif From 230c989590328eebe272b452ef310ee2c4be07b1 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Tue, 7 Nov 2023 14:22:38 +0100 Subject: [PATCH 0113/1049] doc: connectivity: networking: api: Add CoAP server documentation Created a dedicated page for CoAP service and resource examples. Signed-off-by: Pieter De Gendt --- .../networking/api/coap_server.rst | 247 ++++++++++++++++++ doc/connectivity/networking/api/protocols.rst | 1 + 2 files changed, 248 insertions(+) create mode 100644 doc/connectivity/networking/api/coap_server.rst diff --git a/doc/connectivity/networking/api/coap_server.rst b/doc/connectivity/networking/api/coap_server.rst new file mode 100644 index 000000000000000..9a91081f4498103 --- /dev/null +++ b/doc/connectivity/networking/api/coap_server.rst @@ -0,0 +1,247 @@ +.. _coap_server_interface: + +CoAP server +########### + +.. contents:: + :local: + :depth: 2 + +Overview +******** + +Zephyr comes with a batteries-included CoAP server, which uses services to listen for CoAP +requests. The CoAP services handle communication over sockets and pass requests to registered +CoAP resources. + +Setup +***** + +Some configuration is required to make sure services can be started using the CoAP server. The +:kconfig:option:`CONFIG_COAP_SERVER` option should be enabled in your project: + +.. code-block:: cfg + :caption: ``prj.conf`` + + CONFIG_COAP_SERVER=y + +All services are added to a predefined linker section and all resources for each service also get +their respective linker sections. If you would have a service ``my_service`` it has to be +prefixed wth ``coap_resource_`` and added to a linker file: + +.. code-block:: c + :caption: ``sections-ram.ld`` + + #include + + ITERABLE_SECTION_RAM(coap_resource_my_service, 4) + +Add this linker file to your application using CMake: + +.. code-block:: cmake + :caption: ``CMakeLists.txt`` + + zephyr_linker_sources(DATA_SECTIONS sections-ram.ld) + +You can now define your service as part of the application: + +.. code-block:: c + + #include + + static const uint16_t my_service_port = 5683; + + COAP_SERVICE_DEFINE(my_service, "0.0.0.0", &my_service_port, COAP_SERVICE_AUTOSTART); + +.. note:: + + Services defined with the ``COAP_SERVICE_AUTOSTART`` flag will be started together with the CoAP + server thread. Services can be manually started and stopped with ``coap_service_start`` and + ``coap_service_stop`` respectively. + +Sample Usage +************ + +The following is an example of a CoAP resource registered with our service: + +.. code-block:: c + + #include + + static int my_get(struct coap_resource *resource, struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) + { + static const char *msg = "Hello, world!"; + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint16_t id; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint8_t tkl, type; + + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + /* Determine response type */ + type = (type == COAP_TYPE_CON) ? COAP_TYPE_ACK : COAP_TYPE_NON_CON; + + coap_packet_init(&response, data, sizeof(data), COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + + /* Set content format */ + coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + + /* Append payload */ + coap_packet_append_payload_marker(&response); + coap_packet_append_payload(&response, (uint8_t *)msg, sizeof(msg)); + + /* Send to response back to the client */ + return coap_resource_send(resource, &response, addr, addr_len); + } + + static int my_put(struct coap_resource *resource, struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) + { + /* ... Handle the incoming request ... */ + + /* Return a CoAP response code as a shortcut for an empty ACK message */ + return COAP_RESPONSE_CODE_CHANGED; + } + + static const char * const my_resource_path[] = { "test", NULL }; + COAP_RESOURCE_DEFINE(my_resource, my_service, { + .path = my_resource_path, + .get = my_get, + .put = my_put, + }); + +.. note:: + + As demonstrated in the example above, a CoAP resource handler can return response codes to let + the server respond with an empty ACK response. + +Observable resources +******************** + +The CoAP server provides logic for parsing observe requests and stores these using the runtime data +of CoAP services. Together with observer events, enabled with +:kconfig:option:`CONFIG_COAP_OBSERVER_EVENTS`, the application can easily keep track of clients +and send state updates. An example using a temperature sensor can look like: + +.. code-block:: c + + #include + #include + #include + + static void notify_observers(struct k_work *work); + K_WORK_DELAYABLE_DEFINE(temp_work, notify_observers); + + static void temp_observer_event(struct coap_resource *resource, struct coap_observer *observer, + enum coap_observer_event event) + { + /* Only track the sensor temperature if an observer is active */ + if (event == COAP_OBSERVER_ADDED) { + k_work_schedule(&temp_work, K_SECONDS(1)); + } + } + + static int send_temperature(struct coap_resource *resource, + const struct sockaddr *addr, socklen_t addr_len, + uint16_t age, uint16_t id, const uint8_t *token, uint8_t tkl, + bool is_response) + { + const struct device *dev = DEVICE_DT_GET(DT_ALIAS(ambient_temp0)); + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + char payload[14]; + struct sensor_value value; + double temp; + uint8_t type; + + /* Determine response type */ + type = is_response ? COAP_TYPE_ACK : COAP_TYPE_CON; + + if (!is_response) { + id = coap_next_id(); + } + + coap_packet_init(&response, data, sizeof(data), COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + + if (age >= 2U) { + coap_append_option_int(&response, COAP_OPTION_OBSERVE, age); + } + + /* Set content format */ + coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + + /* Get the sensor date */ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP); + sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &value); + temp = sensor_value_to_double(&value); + + snprintk(payload, sizeof(payload), "%0.2f°C", temp); + + /* Append payload */ + coap_packet_append_payload_marker(&response); + coap_packet_append_payload(&response, (uint8_t *)payload, strlen(payload)); + + return coap_resource_send(resource, &response, addr, addr_len); + } + + static int temp_get(struct coap_resource *resource, struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) + { + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t tkl; + int r; + + /* Let the CoAP server parse the request and add/remove observers if needed */ + r = coap_resource_parse_observe(resource, request, addr); + + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + return send_temperature(resource, addr, addr_len, r == 0 ? resource->age : 0, + id, token, tkl, true); + } + + static void temp_notify(struct coap_resource *resource, struct coap_observer *observer) + { + send_temperature(resource, &observer->addr, sizeof(observer->addr), resource->age, 0, + observer->token, observer->tkl, false); + } + + static const char * const temp_resource_path[] = { "sensors", "temp1", NULL }; + COAP_RESOURCE_DEFINE(temp_resource, my_service, { + .path = temp_resource_path, + .get = temp_get, + .notify = temp_notify, + .observer_event_handler = temp_observer_event, + }); + + static void notify_observers(struct k_work *work) + { + if (sys_slist_is_empty(&temp_resource.observers)) { + return; + } + + coap_resource_notify(&temp_resource); + k_work_reschedule(&temp_work, K_SECONDS(1)); + } + +CoRE Link Format +**************** + +The :kconfig:option:`CONFIG_COAP_SERVER_WELL_KNOWN_CORE` option enables handling the +``.well-known/core`` GET requests by the server. This allows clients to get a list of hypermedia +links to other resources hosted in that server. + +API Reference +************* + +.. doxygengroup:: coap_service diff --git a/doc/connectivity/networking/api/protocols.rst b/doc/connectivity/networking/api/protocols.rst index 8f2bc2af3d5a58c..aea485b74aa6d03 100644 --- a/doc/connectivity/networking/api/protocols.rst +++ b/doc/connectivity/networking/api/protocols.rst @@ -9,6 +9,7 @@ Protocols coap coap_client + coap_server http lwm2m mqtt From b81ce1f95747f6ad6239735a03da4d52a93fc507 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 8 Nov 2023 11:08:42 +0100 Subject: [PATCH 0114/1049] doc: connectivity: networking: api: Add subsystem link notes to CoAP The CoAP documentation has server/clients sample usages, added a note about the available subsystems that can be used instead. Signed-off-by: Pieter De Gendt --- doc/connectivity/networking/api/coap.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/connectivity/networking/api/coap.rst b/doc/connectivity/networking/api/coap.rst index 4f0654a57d4c8ea..ffb794a0c8a37e1 100644 --- a/doc/connectivity/networking/api/coap.rst +++ b/doc/connectivity/networking/api/coap.rst @@ -28,8 +28,6 @@ See :ref:`lwm2m_interface` for more information. Supported RFCs: -Supported RFCs: - - `RFC7252: The Constrained Application Protocol (CoAP) `_ - `RFC6690: Constrained RESTful Environments (CoRE) Link Format `_ - `RFC7959: Block-Wise Transfers in the Constrained Application Protocol (CoAP) `_ @@ -43,6 +41,11 @@ Sample Usage CoAP Server =========== +.. note:: + + A :ref:`coap_server_interface` subsystem is available, the following is for creating a custom + server implementation. + To create a CoAP server, resources for the server need to be defined. The ``.well-known/core`` resource should be added before all other resources that should be included in the responses of the ``.well-known/core`` @@ -97,6 +100,11 @@ with resource path like '/some_resource/+/#'. CoAP Client =========== +.. note:: + + A :ref:`coap_client_interface` subsystem is available, the following is for creating a custom + client implementation. + If the CoAP client knows about resources in the CoAP server, the client can start prepare CoAP requests and wait for responses. If the client doesn't know about resources in the CoAP server, it can request resources through From 98052aabb7bb3594ec0e48bfb3d424010810a448 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 8 Nov 2023 11:11:26 +0100 Subject: [PATCH 0115/1049] doc: releases: migration: Add CoAP API changes Add a note to the 3.6 migration guide about the CoAP API changes introduced with the CoAP server subsystem. Signed-off-by: Pieter De Gendt --- doc/releases/migration-guide-3.6.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index ca73ed0ae82091e..42a485d633e4a72 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -76,6 +76,11 @@ Bluetooth Networking ========== +* The CoAP public API has some minor changes to take into account. The + :c:func:`coap_remove_observer` now returns a result if the observer was removed. This + change is used by the newly introduced :ref:`coap_server_interface` subsystem. Also, the + ``request`` argument for :c:func:`coap_well_known_core_get` is made ``const``. + Other Subsystems ================ From be0cb45e1abdcb02a6b83079696dff868c2f313b Mon Sep 17 00:00:00 2001 From: Ning Yang Date: Wed, 8 Nov 2023 13:54:28 +0800 Subject: [PATCH 0116/1049] drivers: dma: fix build warning issue for dma sedi driver Remove unused functions to avoid build warning check. Signed-off-by: Ning Yang --- drivers/dma/dma_sedi.c | 52 ------------------------------------------ 1 file changed, 52 deletions(-) diff --git a/drivers/dma/dma_sedi.c b/drivers/dma/dma_sedi.c index 96ae8bbf8fb2a4a..7c4ffa72e57755d 100644 --- a/drivers/dma/dma_sedi.c +++ b/drivers/dma/dma_sedi.c @@ -366,58 +366,6 @@ static int dma_sedi_init(const struct device *dev) return 0; } -#ifdef CONFIG_PM_DEVICE - -static bool is_dma_busy(sedi_dma_t dev) -{ - sedi_dma_status_t chn_status; - - for (int chn = 0; chn < DMA_CHANNEL_NUM; chn++) { - sedi_dma_get_status(dev, chn, &chn_status); - if (chn_status.busy == 1) { - return true; - } - } - return false; -} - -static int dma_change_device_power(const struct device *dev, - enum pm_device_action action) -{ - struct dma_sedi_driver_data *const data = DEV_DATA(dev); - const struct dma_sedi_config_info *const info = DEV_CFG(dev); - sedi_dma_t dma_dev = info->peripheral_id; - int ret; - - sedi_power_state_t state; - - switch (action) { - case PM_DEVICE_ACTION_RESUME: - state = SEDI_POWER_FULL; - break; - case PM_DEVICE_ACTION_SUSPEND: - if (is_dma_busy(dma_dev)) { - return -EBUSY; - } - state = SEDI_POWER_SUSPEND; - break; - - default: - return -ENOTSUP; - } - - for (uint8_t chn = 0; chn < DMA_CHANNEL_NUM; chn++) { - ret = sedi_dma_set_power(dma_dev, chn, state); - if (ret != SEDI_DRIVER_OK) { - return -EIO; - } - } - - return 0; -} - -#endif - #define DMA_DEVICE_INIT_SEDI(inst) \ static void dma_sedi_##inst##_irq_config(void); \ \ From 1f0b4c62a26983815442fb5bb5b952e6d08e8661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B8e?= Date: Tue, 7 Nov 2023 16:19:15 +0100 Subject: [PATCH 0117/1049] drivers: entropy: psa: Don't have PSA_CRYPTO_RNG depend on TF-M MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the depenency on TF-M so that this driver can be used when PSA is provided by something else than TF-M. Signed-off-by: Sebastian Bøe --- drivers/entropy/Kconfig.psa_crypto | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/entropy/Kconfig.psa_crypto b/drivers/entropy/Kconfig.psa_crypto index 50f31509004072b..d06001225b05491 100644 --- a/drivers/entropy/Kconfig.psa_crypto +++ b/drivers/entropy/Kconfig.psa_crypto @@ -5,7 +5,6 @@ config ENTROPY_PSA_CRYPTO_RNG bool "PSA Crypto Random source Entropy driver" - depends on BUILD_WITH_TFM depends on DT_HAS_ZEPHYR_PSA_CRYPTO_RNG_ENABLED select ENTROPY_HAS_DRIVER default y From 702399080e94131c124d8c5428e6508e8c8d0bb1 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 8 Nov 2023 10:05:50 +0000 Subject: [PATCH 0118/1049] Kconfig: drop COMPAT_INCLUDES Last reference of this was dropped in 01b7800bc8, almost 2y ago. Signed-off-by: Fabio Baltieri --- Kconfig.zephyr | 11 ----------- doc/releases/release-notes-3.6.rst | 2 ++ 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index b532dbc44359424..c484898206b713b 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -921,14 +921,3 @@ config BOOTLOADER_BOSSA_ADAFRUIT_UF2 endchoice endmenu - -menu "Compatibility" - -config COMPAT_INCLUDES - bool "Suppress warnings when using header shims" - default y - help - Suppress any warnings from the pre-processor when including - deprecated header files. - -endmenu diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index ea62b9cc977a977..3c1248222ee5d88 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -110,6 +110,8 @@ Boards & SoC Support Build system and infrastructure ******************************* +- Dropped the ``COMPAT_INCLUDES`` option, it was unused since 3.0. + Drivers and Sensors ******************* From 56395ec42f59aa43667006b400903ee04c30f43c Mon Sep 17 00:00:00 2001 From: William MARTIN Date: Wed, 8 Nov 2023 14:19:08 +0100 Subject: [PATCH 0119/1049] dts: arm: st: Update stm32l496.dtsi Add missing master-can-reg into stm32l496.dtsi Signed-off-by: William MARTIN --- dts/arm/st/l4/stm32l496.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/arm/st/l4/stm32l496.dtsi b/dts/arm/st/l4/stm32l496.dtsi index 12d74f6859bef60..c11eba47796d26e 100644 --- a/dts/arm/st/l4/stm32l496.dtsi +++ b/dts/arm/st/l4/stm32l496.dtsi @@ -54,6 +54,7 @@ interrupts = <86 0>, <87 0>, <88 0>, <89 0>; interrupt-names = "TX", "RX0", "RX1", "SCE"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x04000000>; //RCC_APB1ENR1_CAN2EN + master-can-reg = <0x40006400>; status = "disabled"; sample-point = <875>; }; From 6af171d44b275b6c3df7b2d2daa6e6d7fc9242ea Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 8 Nov 2023 09:12:47 -0600 Subject: [PATCH 0120/1049] include: net_if: Fix IPV6 prefix struct doc desc IPv6 Prefix struct doc description is a copy paste error, fix Signed-off-by: Declan Snyder --- include/zephyr/net/net_if.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 82a1447b4f93a61..79fc2c79b317a85 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -106,7 +106,7 @@ struct net_if_mcast_addr { /** * @brief Network Interface IPv6 prefixes * - * Stores the multicast IP addresses assigned to this network interface. + * Stores the IPV6 prefixes assigned to this network interface. */ struct net_if_ipv6_prefix { /** Prefix lifetime */ From f409f67db4530e36b176d914e8d4ac7367118045 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 8 Nov 2023 16:15:09 +0100 Subject: [PATCH 0121/1049] tests: drivers: adc: move ad5592-adc node into native_posix.overlay Remove the `app.overlay` file which has been wrongly added in ad3c5a2 commit. Instead of that add the ad5592-adc node into `native_posix.overlay` file. Signed-off-by: Bartosz Bilas --- tests/drivers/build_all/adc/app.overlay | 50 ------------------- .../build_all/adc/boards/native_posix.overlay | 14 ++++++ 2 files changed, 14 insertions(+), 50 deletions(-) delete mode 100644 tests/drivers/build_all/adc/app.overlay diff --git a/tests/drivers/build_all/adc/app.overlay b/tests/drivers/build_all/adc/app.overlay deleted file mode 100644 index 82634f87df474bf..000000000000000 --- a/tests/drivers/build_all/adc/app.overlay +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023 Grinn - * - * SPDX-License-Identifier: Apache-2.0 - * - * Application overlay for testing driver builds - * - * Names in this file should be chosen in a way that won't conflict - * with real-world devicetree nodes, to allow these tests to run on - * (and be extended to test) real hardware. - */ - -/ { - test { - #address-cells = <1>; - #size-cells = <1>; - - test_gpio: gpio@deadbeef { - compatible = "vnd,gpio"; - gpio-controller; - reg = <0xdeadbeef 0x1000>; - #gpio-cells = <0x2>; - status = "okay"; - }; - - test_spi: spi@33334444 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "vnd,spi"; - reg = <0x33334444 0x1000>; - status = "okay"; - clock-frequency = <2000000>; - - cs-gpios = <&test_gpio 0 0>; - - test_spi_ad5592: ad5592@0 { - compatible = "adi,ad5592"; - status = "okay"; - reg = <0x0>; - spi-max-frequency = <0>; - reset-gpios = <&test_gpio 0 0>; - - ad5592_adc: adc-controller { - compatible = "adi,ad5592-adc"; - #io-channel-cells = <1>; - }; - }; - }; - }; -}; diff --git a/tests/drivers/build_all/adc/boards/native_posix.overlay b/tests/drivers/build_all/adc/boards/native_posix.overlay index 7f6f64243c8c04e..5e787d8932f5285 100644 --- a/tests/drivers/build_all/adc/boards/native_posix.overlay +++ b/tests/drivers/build_all/adc/boards/native_posix.overlay @@ -118,6 +118,7 @@ <&test_gpio 0 0>, <&test_gpio 0 0>, <&test_gpio 0 0>, + <&test_gpio 0 0>, <&test_gpio 0 0>; test_spi_mcp3204: mcp3204@0 { @@ -305,6 +306,19 @@ spi-max-frequency = <0>; #io-channel-cells = <1>; }; + + test_spi_ad5592: ad5592@13 { + compatible = "adi,ad5592"; + status = "okay"; + reg = <0x13>; + spi-max-frequency = <0>; + reset-gpios = <&test_gpio 0 0>; + + ad5592_adc: adc-controller { + compatible = "adi,ad5592-adc"; + #io-channel-cells = <1>; + }; + }; }; }; }; From 00758b3e9a5f6c20d779ae82d47604cb005f5919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 8 Nov 2023 17:57:49 +0100 Subject: [PATCH 0122/1049] doc: gsg: macOS: Use menuselection role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Small tweak to use Sphinx `menuselection` role and make the menu output more readable. Signed-off-by: Benjamin Cabé --- doc/develop/getting_started/installation_mac.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/develop/getting_started/installation_mac.rst b/doc/develop/getting_started/installation_mac.rst index de7b3f861b3e50b..a6043d37b4f592f 100644 --- a/doc/develop/getting_started/installation_mac.rst +++ b/doc/develop/getting_started/installation_mac.rst @@ -19,9 +19,9 @@ get around this issue you can take two different approaches: ``path/to/folder`` is the path to the enclosing folder where the executables you want to run are located. -* Open "System Preferences" -> "Security and Privacy" -> "Privacy" and then - scroll down to "Developer Tools". Then unlock the lock to be able to make - changes and check the checkbox corresponding to your terminal emulator of +* Open :menuselection:`System Preferences --> Security and Privacy --> Privacy` + and then scroll down to "Developer Tools". Then unlock the lock to be able to + make changes and check the checkbox corresponding to your terminal emulator of choice. This will apply to any executable being launched from such terminal program. From df6a9f2d309e1b0196cb782bcc0c17a903cbb488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 8 Nov 2023 19:34:33 +0100 Subject: [PATCH 0123/1049] doc: css: fix dark theme for gui roles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix dark theme issues with guilabel and menuselection roles. Signed-off-by: Benjamin Cabé --- doc/_static/css/custom.css | 8 ++++++++ doc/_static/css/dark.css | 3 +++ doc/_static/css/light.css | 3 +++ 3 files changed, 14 insertions(+) diff --git a/doc/_static/css/custom.css b/doc/_static/css/custom.css index edd7f24629b5f71..72756780b8eab2d 100644 --- a/doc/_static/css/custom.css +++ b/doc/_static/css/custom.css @@ -582,6 +582,14 @@ kbd, .kbd, vertical-align: middle; } +/* guilabel and menuselection tweaks */ +.rst-content .guilabel, +.rst-content .menuselection { + color: var(--body-color); + background-color: var(--guiitems-background-color); + border-color: var(--guiitems-border-color); +} + /* Buttons */ .btn-neutral { diff --git a/doc/_static/css/dark.css b/doc/_static/css/dark.css index a577bd69d358e96..47d555242f6a87a 100644 --- a/doc/_static/css/dark.css +++ b/doc/_static/css/dark.css @@ -87,6 +87,9 @@ --kbd-shadow-color: #1e2023; --kbd-text-color: #e2f2ff; + --guiitems-background-color: #303d4f; + --guiitems-border-color: #7fbbe3; + --btn-neutral-background-color: #404040; --btn-neutral-hover-background-color: #505050; --footer-color: #aaa; diff --git a/doc/_static/css/light.css b/doc/_static/css/light.css index 625516dce31bb80..0389650278c7cdd 100644 --- a/doc/_static/css/light.css +++ b/doc/_static/css/light.css @@ -85,6 +85,9 @@ --kbd-shadow-color: #b0b7bf; --kbd-text-color: #444d56; + --guiitems-background-color: #e7f2fa; + --guiitems-border-color: #7fbbe3; + --btn-neutral-background-color: #f3f6f6; --btn-neutral-hover-background-color: #e5ebeb; --footer-color: #808080; From a39d2dc9d574299824c5be0359d74c678405923b Mon Sep 17 00:00:00 2001 From: Dat Nguyen Duy Date: Thu, 9 Nov 2023 01:50:14 +0700 Subject: [PATCH 0124/1049] drivers: nxp_s32: add missing soc.h inclusion Some NXP S32 shim drivers are using macros defined in soc/arm/nxp_s32/*/soc.h but not including soc.h. Those still can be built because the header file is included indirectly by some other header files. This is very fragile, it should be included directly Signed-off-by: Dat Nguyen Duy --- drivers/interrupt_controller/intc_eirq_nxp_s32.c | 1 + drivers/serial/uart_nxp_s32_linflexd.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/interrupt_controller/intc_eirq_nxp_s32.c b/drivers/interrupt_controller/intc_eirq_nxp_s32.c index 2dae70824cec850..2526aecad4ddd2f 100644 --- a/drivers/interrupt_controller/intc_eirq_nxp_s32.c +++ b/drivers/interrupt_controller/intc_eirq_nxp_s32.c @@ -6,6 +6,7 @@ #define DT_DRV_COMPAT nxp_s32_siul2_eirq +#include #include #include #include diff --git a/drivers/serial/uart_nxp_s32_linflexd.c b/drivers/serial/uart_nxp_s32_linflexd.c index aeb8925da9f5d44..9a8d8fe3790c310 100644 --- a/drivers/serial/uart_nxp_s32_linflexd.c +++ b/drivers/serial/uart_nxp_s32_linflexd.c @@ -6,6 +6,7 @@ #define DT_DRV_COMPAT nxp_s32_linflexd +#include #include #include #include From 0f07889bcd1409cd9a1b3a4faae075faf841b060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 3 Nov 2023 15:44:39 +0100 Subject: [PATCH 0125/1049] doc: gh_utils: add docstring for get_page_prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add documentation to the get_page_prefix method. Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/gh_utils.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index 4d2127756b46064..313260a2968548b 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -51,6 +51,20 @@ def get_page_prefix(app: Sphinx, pagename: str) -> str: + """Return the prefix that needs to be added to the page path to get its location in the + repository. + + If pagename refers to a page that is automatically generated by Sphinx or if it matches one of + the patterns in ``gh_link_exclude`` configuration option, return None. + + Args: + app: Sphinx instance. + pagename: Page name (path). + + Returns: + Prefix if applicable, None otherwise. + """ + if not os.path.isfile(app.env.project.doc2path(pagename)): return None From cf52afb3fb9afe3a7dd125dbbeb61628cbf19f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 3 Nov 2023 15:43:54 +0100 Subject: [PATCH 0126/1049] doc: gh_utils: Remove unnecessary ZEPHYR_BASE config option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compute ZEPHYR_BASE like other extensions do rather than artificially pretend it's a config option. Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/gh_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index 313260a2968548b..0efc524e579d3f4 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -40,12 +40,13 @@ from datetime import datetime from pathlib import Path from textwrap import dedent -from typing import Optional, Tuple +from typing import Final, Optional, Tuple from urllib.parse import quote from sphinx.application import Sphinx from sphinx.util.i18n import format_date +ZEPHYR_BASE : Final[str] = Path(__file__).parents[3] __version__ = "0.1.0" @@ -162,7 +163,7 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: return None orig_path = os.path.join( - app.config.ZEPHYR_BASE, + ZEPHYR_BASE, page_prefix, app.env.project.doc2path(pagename, basedir=False), ) @@ -214,7 +215,6 @@ def add_jinja_filter(app: Sphinx): def setup(app: Sphinx): - app.add_config_value("ZEPHYR_BASE", Path(__file__).resolve().parents[3], "html") app.add_config_value("gh_link_version", "", "") app.add_config_value("gh_link_base_url", "", "") app.add_config_value("gh_link_prefixes", {}, "") From 61dd68a5ee3a5fa09c4ddd73ad41e56999bf0b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 3 Nov 2023 11:33:36 +0100 Subject: [PATCH 0127/1049] doc: gh_utils: use doc2path method from BuildEnvironment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use BuildEnvironment to get the path of a document. Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/gh_utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index 0efc524e579d3f4..b79697e924120c6 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -66,7 +66,7 @@ def get_page_prefix(app: Sphinx, pagename: str) -> str: Prefix if applicable, None otherwise. """ - if not os.path.isfile(app.env.project.doc2path(pagename)): + if not os.path.isfile(app.env.doc2path(pagename)): return None for exclude in app.config.gh_link_exclude: @@ -104,7 +104,7 @@ def gh_link_get_url(app: Sphinx, pagename: str, mode: str = "blob") -> Optional[ mode, app.config.gh_link_version, page_prefix, - app.env.project.doc2path(pagename, basedir=False), + app.env.doc2path(pagename, False), ] ) @@ -121,7 +121,7 @@ def gh_link_get_open_issue_url(app: Sphinx, pagename: str, sha1: str) -> Optiona URL to open a new issue if applicable, None otherwise. """ - if not os.path.isfile(app.env.project.doc2path(pagename)): + if not os.path.isfile(app.env.doc2path(pagename)): return None title = quote(f"[doc] Documentation issue in '{pagename}'") @@ -165,7 +165,7 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: orig_path = os.path.join( ZEPHYR_BASE, page_prefix, - app.env.project.doc2path(pagename, basedir=False), + app.env.doc2path(pagename, False), ) try: From f6400f17cbfe5dfb12462ba400f4a3dd50e6b247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 3 Nov 2023 12:06:45 +0100 Subject: [PATCH 0128/1049] doc: gh_utils: Fix incorrect condition for empty string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Page prefix can be an empty string. Fixed the condition so that it only evaluates to try when prefix is truly None. Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/gh_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index b79697e924120c6..ff5e0fa5b6d5454 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -95,7 +95,7 @@ def gh_link_get_url(app: Sphinx, pagename: str, mode: str = "blob") -> Optional[ """ page_prefix = get_page_prefix(app, pagename) - if not page_prefix: + if page_prefix is None: return None return "/".join( @@ -159,7 +159,7 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: """ page_prefix = get_page_prefix(app, pagename) - if not page_prefix: + if page_prefix is None: return None orig_path = os.path.join( From a3ed8f827f33fd6487f60291e7c2a592d989d647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 3 Nov 2023 15:25:40 +0100 Subject: [PATCH 0129/1049] doc: gh_utils: Use "doc:" prefix in opened issue title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not sure why I used square brackets for "[doc]" prefix of the default Github issue title. Change it to "doc:". Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/gh_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index ff5e0fa5b6d5454..019a37a7dfb8e93 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -124,7 +124,7 @@ def gh_link_get_open_issue_url(app: Sphinx, pagename: str, sha1: str) -> Optiona if not os.path.isfile(app.env.doc2path(pagename)): return None - title = quote(f"[doc] Documentation issue in '{pagename}'") + title = quote(f"doc: Documentation issue in '{pagename}'") labels = quote("area: Documentation") body = quote( dedent( From 6cf694a2adcfaf26011a1edc45faab1daaed8533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 3 Nov 2023 16:21:58 +0100 Subject: [PATCH 0130/1049] doc: gh_utils: Use MAINTAINERS file to add labels to opened issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use get_maintainer.py to add more meaningful labels to issues creates from a documentation page. Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/gh_utils.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index 019a37a7dfb8e93..6ba75ce5ab7c12e 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -37,6 +37,7 @@ import os import re import subprocess +import sys from datetime import datetime from pathlib import Path from textwrap import dedent @@ -47,6 +48,13 @@ from sphinx.util.i18n import format_date ZEPHYR_BASE : Final[str] = Path(__file__).parents[3] +SCRIPTS : Final[str] = ZEPHYR_BASE / "scripts" +sys.path.insert(0, str(SCRIPTS)) + +from get_maintainer import Maintainers + +MAINTAINERS : Final[Maintainers] = Maintainers() + __version__ = "0.1.0" @@ -121,11 +129,21 @@ def gh_link_get_open_issue_url(app: Sphinx, pagename: str, sha1: str) -> Optiona URL to open a new issue if applicable, None otherwise. """ - if not os.path.isfile(app.env.doc2path(pagename)): + page_prefix = get_page_prefix(app, pagename) + if page_prefix is None: return None + rel_path = os.path.join( + os.path.relpath(ZEPHYR_BASE), + page_prefix, + app.env.doc2path(pagename, False), + ) + title = quote(f"doc: Documentation issue in '{pagename}'") labels = quote("area: Documentation") + areas = MAINTAINERS.path2areas(rel_path) + if areas: + labels += "," + ",".join([label for area in areas for label in area.labels]) body = quote( dedent( f"""\ From 7d3381f9c8850dbd309c3ac0b3bf2327233cd07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 3 Nov 2023 16:34:41 +0100 Subject: [PATCH 0131/1049] doc: Rename "report an issue" label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify the "Report an issue" label in HTML documentation. Signed-off-by: Benjamin Cabé --- doc/_templates/breadcrumbs.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_templates/breadcrumbs.html b/doc/_templates/breadcrumbs.html index 4f974503da48f23..d1855e491fd392c 100644 --- a/doc/_templates/breadcrumbs.html +++ b/doc/_templates/breadcrumbs.html @@ -26,7 +26,7 @@ {%- set git_last_updated, sha1 = pagename | git_info | default((None, None), true) %} {%- if sha1 %} - {{ _('Report an issue')}} + {{ _('Report an issue with this page')}} {% endif %} {% endif %} From 4b0fa40c71e03c42569e0fe55ada13dc973b16c9 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 9 Nov 2023 16:30:26 +0800 Subject: [PATCH 0132/1049] doc: kconfig: remove duplicated devicetree function These devicetree function entries already existed in the doc since #21133. Signed-off-by: Yong Cong Sin --- doc/build/kconfig/preprocessor-functions.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/build/kconfig/preprocessor-functions.rst b/doc/build/kconfig/preprocessor-functions.rst index cb66658d2e4a5e3..2c94188c01c0597 100644 --- a/doc/build/kconfig/preprocessor-functions.rst +++ b/doc/build/kconfig/preprocessor-functions.rst @@ -29,10 +29,8 @@ while the ``*_hex`` version returns a hexadecimal value starting with ``0x``. .. code-block:: none $(dt_has_compat,) - $(dt_compat_enabled,) $(dt_compat_on_bus,,) $(dt_chosen_label,) - $(dt_chosen_enabled,) $(dt_chosen_path,) $(dt_chosen_has_compat,) $(dt_path_enabled,) From 30940418b3fbcf860c287c02a2b85c50227020af Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 9 Nov 2023 16:32:21 +0800 Subject: [PATCH 0133/1049] doc: kconfig: sort devicetree functions alphabetically Sort these entries alphabetically to make it easier to read. Signed-off-by: Yong Cong Sin --- doc/build/kconfig/preprocessor-functions.rst | 52 ++++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/doc/build/kconfig/preprocessor-functions.rst b/doc/build/kconfig/preprocessor-functions.rst index 2c94188c01c0597..ae3777444d84509 100644 --- a/doc/build/kconfig/preprocessor-functions.rst +++ b/doc/build/kconfig/preprocessor-functions.rst @@ -28,43 +28,43 @@ while the ``*_hex`` version returns a hexadecimal value starting with ``0x``. .. code-block:: none - $(dt_has_compat,) - $(dt_compat_on_bus,,) + $(dt_alias_enabled,) + $(dt_chosen_bool_prop, , ) + $(dt_chosen_enabled,) + $(dt_chosen_has_compat,) $(dt_chosen_label,) $(dt_chosen_path,) - $(dt_chosen_has_compat,) - $(dt_path_enabled,) - $(dt_alias_enabled,) - $(dt_nodelabel_enabled,) - $(dt_nodelabel_enabled_with_compat,,) - $(dt_chosen_reg_addr_int,[,,]) $(dt_chosen_reg_addr_hex,[,,]) - $(dt_chosen_reg_size_int,[,,]) + $(dt_chosen_reg_addr_int,[,,]) $(dt_chosen_reg_size_hex,[,,]) - $(dt_node_reg_addr_int,[,,]) - $(dt_node_reg_addr_hex,[,,]) - $(dt_node_reg_size_int,[,,]) - $(dt_node_reg_size_hex,[,,]) - $(dt_nodelabel_reg_addr_int,[,,]) - $(dt_nodelabel_reg_addr_hex,[,,]) - $(dt_nodelabel_reg_size_int,[,,]) - $(dt_nodelabel_reg_size_hex,[,,]) + $(dt_chosen_reg_size_int,[,,]) $(dt_compat_enabled,) - $(dt_chosen_enabled,) + $(dt_compat_on_bus,,) + $(dt_gpio_hogs_enabled) + $(dt_has_compat,) $(dt_node_bool_prop,,) - $(dt_nodelabel_bool_prop,,) - $(dt_chosen_bool_prop, , ) + $(dt_node_has_compat,,) $(dt_node_has_prop,,) - $(dt_nodelabel_has_prop,,) - $(dt_node_int_prop_int,,[,]) $(dt_node_int_prop_hex,,[,]) + $(dt_node_int_prop_int,,[,]) + $(dt_node_parent,) + $(dt_node_reg_addr_hex,[,,]) + $(dt_node_reg_addr_int,[,,]) + $(dt_node_reg_size_hex,[,,]) + $(dt_node_reg_size_int,[,,]) $(dt_node_str_prop_equals,,,) + $(dt_nodelabel_array_prop_has_val, , , ) + $(dt_nodelabel_bool_prop,,) + $(dt_nodelabel_enabled,) + $(dt_nodelabel_enabled_with_compat,,) $(dt_nodelabel_has_compat,,) - $(dt_node_has_compat,,) + $(dt_nodelabel_has_prop,,) $(dt_nodelabel_path,) - $(dt_node_parent,) - $(dt_nodelabel_array_prop_has_val, , , ) - $(dt_gpio_hogs_enabled) + $(dt_nodelabel_reg_addr_hex,[,,]) + $(dt_nodelabel_reg_addr_int,[,,]) + $(dt_nodelabel_reg_size_hex,[,,]) + $(dt_nodelabel_reg_size_int,[,,]) + $(dt_path_enabled,) $(shields_list_contains,) From 47ce94527aed5d0c16a887cd3ac01a286eb45e1e Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 8 Nov 2023 14:19:54 -0600 Subject: [PATCH 0134/1049] doc: services: pm: fix function prototype for PM device support Function prototype in PM device implementation documentation had the incorrect prototype for device power management. Fix this to align with the correct prototype. Signed-off-by: Daniel DeGrasse --- doc/services/pm/device.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/pm/device.rst b/doc/services/pm/device.rst index 490102e78a4cf43..3eb936942ea8e9d 100644 --- a/doc/services/pm/device.rst +++ b/doc/services/pm/device.rst @@ -146,7 +146,7 @@ support in a device driver. #define DT_DRV_COMPAT dummy_device static int dummy_driver_pm_action(const struct device *dev, - enum pm_device_action *action) + enum pm_device_action action) { switch (action) { case PM_DEVICE_ACTION_SUSPEND: From 45f664abf5421546ab0aa9119ba3e0d1637458e2 Mon Sep 17 00:00:00 2001 From: Mariano Goluboff Date: Wed, 8 Nov 2023 06:45:07 -0500 Subject: [PATCH 0135/1049] drivers: console: fix dropped characters when using debug hooks When using console debug server hooks, not all characters are processed if the server hook returns non-zero for one character while there are other characters in the buffer. This is seen when using a fast console (like USB) where multiple characters come in before the ISR is called. Fix it by continuing to process characters instead of returning from the ISR with characters still in the buffer. Fixes: #64661 Signed-off-by: Mariano Goluboff --- drivers/console/uart_console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/console/uart_console.c b/drivers/console/uart_console.c index 378bbe91ff3897e..21df7fd34554497 100644 --- a/drivers/console/uart_console.c +++ b/drivers/console/uart_console.c @@ -474,7 +474,7 @@ static void uart_console_isr(const struct device *unused, void *user_data) * The input hook indicates that no further processing * should be done by this handler. */ - return; + continue; } #endif From 488f56c0333f33942cd2b918eec8b6eafde9dc0a Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Mon, 6 Nov 2023 14:36:50 +0000 Subject: [PATCH 0136/1049] drivers: regulator: npm1300: soft start configuration Added configuration of soft start functionality Signed-off-by: Andy Sinclair --- drivers/regulator/regulator_npm1300.c | 33 +++++++++++++++++++ .../regulator/nordic,npm1300-regulator.yaml | 10 ++++++ 2 files changed, 43 insertions(+) diff --git a/drivers/regulator/regulator_npm1300.c b/drivers/regulator/regulator_npm1300.c index b3a9d1aced9afb4..fb193f1d39e85ad 100644 --- a/drivers/regulator/regulator_npm1300.c +++ b/drivers/regulator/regulator_npm1300.c @@ -68,6 +68,11 @@ enum npm1300_gpio_type { #define LDSW1_ON_MASK 0x03U #define LDSW2_ON_MASK 0x0CU +#define LDSW1_SOFTSTART_MASK 0x0CU +#define LDSW1_SOFTSTART_SHIFT 2U +#define LDSW2_SOFTSTART_MASK 0x30U +#define LDSW2_SOFTSTART_SHIFT 4U + struct regulator_npm1300_pconfig { const struct device *mfd; struct gpio_dt_spec dvs_state_pins[5]; @@ -81,6 +86,7 @@ struct regulator_npm1300_config { struct gpio_dt_spec enable_gpios; struct gpio_dt_spec retention_gpios; struct gpio_dt_spec pwm_gpios; + uint8_t soft_start; }; struct regulator_npm1300_data { @@ -554,6 +560,24 @@ static int get_enabled(const struct device *dev, bool *enabled) } } +static int soft_start_set(const struct device *dev, uint8_t soft_start) +{ + const struct regulator_npm1300_config *config = dev->config; + + switch (config->source) { + case NPM1300_SOURCE_LDO1: + return mfd_npm1300_reg_update(config->mfd, LDSW_BASE, LDSW_OFFSET_CONFIG, + soft_start << LDSW1_SOFTSTART_SHIFT, + LDSW1_SOFTSTART_MASK); + case NPM1300_SOURCE_LDO2: + return mfd_npm1300_reg_update(config->mfd, LDSW_BASE, LDSW_OFFSET_CONFIG, + soft_start << LDSW2_SOFTSTART_SHIFT, + LDSW2_SOFTSTART_MASK); + default: + return -ENOTSUP; + } +} + int regulator_npm1300_init(const struct device *dev) { const struct regulator_npm1300_config *config = dev->config; @@ -582,6 +606,14 @@ int regulator_npm1300_init(const struct device *dev) } } + /* Configure soft start */ + if (config->soft_start != UINT8_MAX) { + ret = soft_start_set(dev, config->soft_start); + if (ret != 0) { + return ret; + } + } + /* Configure GPIO pin control */ ret = regulator_npm1300_set_pin_ctrl(dev, &config->enable_gpios, NPM1300_GPIO_TYPE_ENABLE); if (ret != 0) { @@ -618,6 +650,7 @@ static const struct regulator_driver_api api = {.enable = regulator_npm1300_enab .mfd = DEVICE_DT_GET(DT_GPARENT(node_id)), \ .source = _source, \ .retention_uv = DT_PROP_OR(node_id, retention_microvolt, 0), \ + .soft_start = DT_ENUM_IDX_OR(node_id, soft_start_microamp, UINT8_MAX), \ .enable_gpios = GPIO_DT_SPEC_GET_OR(node_id, enable_gpios, {0}), \ .retention_gpios = GPIO_DT_SPEC_GET_OR(node_id, retention_gpios, {0}), \ .pwm_gpios = GPIO_DT_SPEC_GET_OR(node_id, pwm_gpios, {0})}; \ diff --git a/dts/bindings/regulator/nordic,npm1300-regulator.yaml b/dts/bindings/regulator/nordic,npm1300-regulator.yaml index 987a3b522e1228c..cbd62671f15b918 100644 --- a/dts/bindings/regulator/nordic,npm1300-regulator.yaml +++ b/dts/bindings/regulator/nordic,npm1300-regulator.yaml @@ -83,3 +83,13 @@ child-binding: type: phandle-array description: | Retention mode controlled by specified regulator GPIO pin. + + soft-start-microamp: + type: int + enum: + - 10000 + - 20000 + - 35000 + - 50000 + description: | + Soft start current limit in microamps. From 0cbe0298cbfa4cc5f2db64a86b3d4830f3a4752e Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 8 Nov 2023 11:00:08 +0000 Subject: [PATCH 0137/1049] drivers: regulator: npm1300: Fixed LDSW GPIO control The load switch / LDO pin configuration function now correctly configures the associated GPIO pin. Signed-off-by: Andy Sinclair --- drivers/regulator/regulator_npm1300.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/regulator_npm1300.c b/drivers/regulator/regulator_npm1300.c index fb193f1d39e85ad..8adb2d3cb817aba 100644 --- a/drivers/regulator/regulator_npm1300.c +++ b/drivers/regulator/regulator_npm1300.c @@ -439,7 +439,7 @@ static int regulator_npm1300_set_ldsw_pin_ctrl(const struct device *dev, uint8_t ctrl = (pin + 1U) | (inv << 3U); - return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_GPISEL + chan, type); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_GPISEL + chan, ctrl); } int regulator_npm1300_set_pin_ctrl(const struct device *dev, const struct gpio_dt_spec *spec, From 35f326b82120708ae44a7360c9e95fa5e73022ad Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Wed, 8 Nov 2023 10:25:14 +0100 Subject: [PATCH 0138/1049] bluetooth: leaudio: Termination of PA at Modify Source From BASS spec: If the PA_Sync parameter value written by the client is set to a value of 0x00 (Do not synchronize to PA) and the server is synchronized to the PA, the server shall stop synchronization with the PA and shall write a value of 0x00 (Not synchronized to PA) to the PA_Sync_State field of the Broadcast Receive State characteristic . Fixes BASS/SR/CP/BV-12-C test case. Signed-off-by: Magdalena Kasenberg --- subsys/bluetooth/audio/bap_scan_delegator.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index 79865fc382a3624..3cef96bd1b80a15 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -770,6 +770,20 @@ static int scan_delegator_mod_src(struct bt_conn *conn, return err; } + } else if (pa_sync == BT_BAP_BASS_PA_REQ_NO_SYNC && + (state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ || + state->pa_sync_state == BT_BAP_PA_STATE_SYNCED)) { + /* Terminate PA sync */ + const int err = pa_sync_term_request(conn, &internal_state->state); + + if (err != 0) { + LOG_DBG("PA sync term from %p was reject with reason %d", + conn, err); + + return err; + } + + state_changed = true; } /* Notify if changed */ From 2938856cac67b574f556ddb966ec060ac825befb Mon Sep 17 00:00:00 2001 From: Dong Wang Date: Mon, 6 Nov 2023 20:47:01 +0800 Subject: [PATCH 0139/1049] west.yml: update hal_intel to latest It contains changes from ISH code base: - Switch IPC/SPI SEDI drivers to use OSXML header files. - Enhance SEDI debug functions. - I2C and SPI drivers' bug fix and enhancements. Signed-off-by: Dong Wang --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 6b4391cb3806cb0..17fe8066384de72 100644 --- a/west.yml +++ b/west.yml @@ -173,7 +173,7 @@ manifest: groups: - hal - name: hal_intel - revision: 11feb65898253ac6f715bf12bd04b869e4c1d577 + revision: 7b4c25669f1513b0d6d6ee78ee42340d91958884 path: modules/hal/intel groups: - hal From abc334016f2f236560a6b83ba3e1846870a8f66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 6 Nov 2023 12:39:57 +0100 Subject: [PATCH 0140/1049] doc: pdf: Use single column for the index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The index at the end of the PDF document can contain pretty long strings that don't fit in the default 2-column layout. This commit makes the index use a single-column. Note: this relies on LaTeX package idxlayout which should already be included in the packages recommended for installation in our instructions. Signed-off-by: Benjamin Cabé --- doc/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/conf.py b/doc/conf.py index 0f20f424f809cb8..85488318a0a9cc5 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -184,6 +184,7 @@ "papersize": "a4paper", "maketitle": open(ZEPHYR_BASE / "doc" / "_static" / "latex" / "title.tex").read(), "preamble": open(ZEPHYR_BASE / "doc" / "_static" / "latex" / "preamble.tex").read(), + "makeindex": r"\usepackage[columns=1]{idxlayout}\makeindex", "fontpkg": textwrap.dedent(r""" \usepackage{noto} \usepackage{inconsolata-nerd-font} From 2b98b6710959de1bf20dc8d2a1fa4b4557ba3283 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 26 Oct 2023 13:47:02 +0530 Subject: [PATCH 0141/1049] dt-bindings: i2c: Add gpio-i2c-switch Generic GPIO enabled analog switch to isolate devices from an I2C bus Signed-off-by: Vaishnav Achath Signed-off-by: Ayush Singh --- dts/bindings/i2c/gpio-i2c-switch.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 dts/bindings/i2c/gpio-i2c-switch.yaml diff --git a/dts/bindings/i2c/gpio-i2c-switch.yaml b/dts/bindings/i2c/gpio-i2c-switch.yaml new file mode 100644 index 000000000000000..ebd932afc710f2a --- /dev/null +++ b/dts/bindings/i2c/gpio-i2c-switch.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2023, Ayush Singh +# Copyright (c) 2021, Jason Kridner, BeagleBoard.org Foundation +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO enabled analog switch to isolate devices from an I2C bus + +compatible: "gpio-i2c-switch" + +include: i2c-controller.yaml + +properties: + "#address-cells": + required: true + const: 1 + "#size-cells": + required: true + const: 0 + controller: + type: phandle + required: true + gpios: + type: phandle-array + required: true From dfe1c3a32bdd0e6d01259501d83a4eb91eedcc3e Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 1 Nov 2023 18:32:05 +0530 Subject: [PATCH 0142/1049] drivers: i2c: add gpio_i2c_switch Add drivers for gpio_i2c_switch which is present in beagleconnect freedom Signed-off-by: Vaishnav Achath Signed-off-by: Ayush Singh --- .../arm/beagle_bcf/beagleconnect_freedom.dts | 2 +- drivers/i2c/CMakeLists.txt | 1 + drivers/i2c/Kconfig | 7 ++ drivers/i2c/gpio_i2c_switch.c | 95 +++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 drivers/i2c/gpio_i2c_switch.c diff --git a/boards/arm/beagle_bcf/beagleconnect_freedom.dts b/boards/arm/beagle_bcf/beagleconnect_freedom.dts index 7300e9de5db864d..7fd8341e89b6962 100644 --- a/boards/arm/beagle_bcf/beagleconnect_freedom.dts +++ b/boards/arm/beagle_bcf/beagleconnect_freedom.dts @@ -59,7 +59,7 @@ sens_i2c: sensor-switch { status = "okay"; - compatible = "ti,ts5a2066"; + compatible = "gpio-i2c-switch"; #address-cells = <1>; #size-cells = <0>; controller = <&i2c0>; diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 20ea5c0cb1e3891..f7f363ed8d4169f 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -54,6 +54,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_XILINX_AXI i2c_xilinx_axi.c) zephyr_library_sources_ifdef(CONFIG_I2C_MCHP_MSS i2c_mchp_mss.c) zephyr_library_sources_ifdef(CONFIG_I2C_SEDI i2c_sedi.c) zephyr_library_sources_ifdef(CONFIG_I2C_AMBIQ i2c_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_I2C_SWITCH gpio_i2c_switch.c) zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1 i2c_ll_stm32_v1.c diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 5f62fbb4eb1e9eb..2523877c8513da1 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -195,4 +195,11 @@ config I2C_RV32M1_LPI2C help Enable the RV32M1 LPI2C driver. +config GPIO_I2C_SWITCH + bool "GPIO controlled I2C bus switch" + default y + depends on DT_HAS_GPIO_I2C_SWITCH_ENABLED + help + Enable GPIO controlled I2C bus switch driver. + endif # I2C diff --git a/drivers/i2c/gpio_i2c_switch.c b/drivers/i2c/gpio_i2c_switch.c new file mode 100644 index 000000000000000..938ed11d769dce0 --- /dev/null +++ b/drivers/i2c/gpio_i2c_switch.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023 Ayush Singh + * Copyright (c) 2021 Jason Kridner, BeagleBoard.org Foundation + * Copyright (c) 2020 Innoseis BV + * + * Based on i2c_tca9656a.c + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gpio_i2c_switch + +#define GPIO_I2C_TOGGLE_DELAY_US 1 +#define GPIO_I2C_LOCK_TIMEOUT_US (GPIO_I2C_TOGGLE_DELAY_US * 2 + 100) + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(gpio_i2c_switch, CONFIG_I2C_LOG_LEVEL); + +struct gpio_i2c_switch_config { + const struct device *bus; + const struct gpio_dt_spec gpio; +}; + +struct gpio_i2c_switch_data { + struct k_mutex lock; +}; + +static int gpio_i2c_switch_configure(const struct device *dev, uint32_t dev_config) +{ + const struct gpio_i2c_switch_config *config = dev->config; + + return i2c_configure(config->bus, dev_config); +} + +static int gpio_i2c_switch_transfer(const struct device *dev, struct i2c_msg *msgs, + uint8_t num_msgs, uint16_t addr) +{ + int res; + struct gpio_i2c_switch_data *data = dev->data; + const struct gpio_i2c_switch_config *config = dev->config; + + res = k_mutex_lock(&data->lock, K_USEC(GPIO_I2C_LOCK_TIMEOUT_US)); + if (res != 0) { + return res; + } + + /* enable switch */ + gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT_HIGH); + k_busy_wait(GPIO_I2C_TOGGLE_DELAY_US); + + res = i2c_transfer(config->bus, msgs, num_msgs, addr); + + /* disable switch */ + gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT_LOW); + k_busy_wait(GPIO_I2C_TOGGLE_DELAY_US); + k_mutex_unlock(&data->lock); + + return res; +} + +const struct i2c_driver_api gpio_i2c_switch_api_funcs = { + .configure = gpio_i2c_switch_configure, + .transfer = gpio_i2c_switch_transfer, +}; + +static int gpio_i2c_switch_init(const struct device *dev) +{ + const struct gpio_i2c_switch_config *config = dev->config; + struct gpio_i2c_switch_data *data = dev->data; + + k_mutex_init(&data->lock); + + return gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT_LOW); +} + +#define DEFINE_GPIO_I2C_SWITCH(inst) \ + \ + static struct gpio_i2c_switch_data gpio_i2c_switch_dev_data_##inst; \ + \ + static const struct gpio_i2c_switch_config gpio_i2c_switch_dev_cfg_##inst = { \ + .bus = DEVICE_DT_GET(DT_PHANDLE(DT_DRV_INST(inst), controller)), \ + .gpio = GPIO_DT_SPEC_GET(DT_DRV_INST(inst), gpios), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, gpio_i2c_switch_init, device_pm_control_nop, \ + &gpio_i2c_switch_dev_data_##inst, &gpio_i2c_switch_dev_cfg_##inst, \ + POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, &gpio_i2c_switch_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_GPIO_I2C_SWITCH) From c5d3fc10c1917624b589cee33d52f5f4ee2f46ce Mon Sep 17 00:00:00 2001 From: Ting Shen Date: Fri, 27 Oct 2023 15:08:24 +0800 Subject: [PATCH 0143/1049] drivers: usb_dc_it82xx2: fix uninitialized variable warning ep_ctrl and ep_trans_type is not used inside it82xx2_usb_dc_isr, this triggers a compile warning. Move these variables to a smaller scope. Signed-off-by: Ting Shen --- drivers/usb/device/usb_dc_it82xx2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index f67db012e1d70c1..b5307252325376c 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -719,7 +719,7 @@ static void it82xx2_ep_in_out_config(uint8_t idx) } } -static void it82xx2_usb_dc_trans_done(uint8_t ep_ctrl, uint8_t ep_trans_type) +static void it82xx2_usb_dc_trans_done(void) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); @@ -730,12 +730,12 @@ static void it82xx2_usb_dc_trans_done(uint8_t ep_ctrl, uint8_t ep_trans_type) int ret; for (uint8_t idx = 0 ; idx < EP4 ; idx++) { - ep_ctrl = ep_regs[idx].ep_ctrl; + uint8_t ep_ctrl = ep_regs[idx].ep_ctrl; /* check ready bit ,will be 0 when trans done */ if ((ep_ctrl & ENDPOINT_EN) && !(ep_ctrl & ENDPOINT_RDY)) { if (idx == EP0) { - ep_trans_type = ep_regs[idx].ep_transtype_sts & + uint8_t ep_trans_type = ep_regs[idx].ep_transtype_sts & DC_ALL_TRANS; /* set up*/ @@ -785,7 +785,6 @@ static void it82xx2_usb_dc_isr(void) uint8_t status = usb_regs->dc_interrupt_status & usb_regs->dc_interrupt_mask; /* mask non enable int */ - uint8_t ep_ctrl, ep_trans_type; /* reset */ if (status & DC_RESET_EVENT) { @@ -813,7 +812,7 @@ static void it82xx2_usb_dc_isr(void) if (status & DC_TRANS_DONE) { /* clear interrupt before new transaction */ usb_regs->dc_interrupt_status = DC_TRANS_DONE; - it82xx2_usb_dc_trans_done(ep_ctrl, ep_trans_type); + it82xx2_usb_dc_trans_done(); return; } From 345f079e49598d2dcab17215aaef965073cc613f Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 16 Oct 2023 16:55:09 -0500 Subject: [PATCH 0144/1049] dts: bindings: Fix NXP USB bindings NXP USB bindings were combined into one binding and using a property corresponding to HAL enums which is improper use of devicetree. Signed-off-by: Declan Snyder --- drivers/usb/device/Kconfig | 2 +- drivers/usb/device/usb_dc_mcux.c | 36 ++++++++++++++++++++++--- dts/arm/nxp/nxp_lpc55S1x_common.dtsi | 3 +-- dts/arm/nxp/nxp_lpc55S2x_common.dtsi | 3 +-- dts/arm/nxp/nxp_lpc55S3x_common.dtsi | 3 +-- dts/arm/nxp/nxp_lpc55S6x_common.dtsi | 6 ++--- dts/arm/nxp/nxp_rt1010.dtsi | 3 +-- dts/arm/nxp/nxp_rt10xx.dtsi | 6 ++--- dts/arm/nxp/nxp_rt11xx.dtsi | 6 ++--- dts/arm/nxp/nxp_rt5xx_common.dtsi | 3 +-- dts/arm/nxp/nxp_rt6xx_common.dtsi | 3 +-- dts/bindings/usb/nxp,ehci.yaml | 8 ++++++ dts/bindings/usb/nxp,lpcip3511.yaml | 8 ++++++ dts/bindings/usb/nxp,mcux-usbd.yaml | 23 ---------------- modules/hal_nxp/usb/usb_device_config.h | 10 ++++++- soc/arm/nxp_lpc/lpc55xxx/soc.c | 4 +-- 16 files changed, 73 insertions(+), 54 deletions(-) create mode 100644 dts/bindings/usb/nxp,ehci.yaml create mode 100644 dts/bindings/usb/nxp,lpcip3511.yaml diff --git a/drivers/usb/device/Kconfig b/drivers/usb/device/Kconfig index 41d3d446f8db81f..91db896eede5e63 100644 --- a/drivers/usb/device/Kconfig +++ b/drivers/usb/device/Kconfig @@ -147,7 +147,7 @@ config USB_KINETIS config USB_MCUX bool "NXP MCUX USB Device Controller Driver" default y - depends on DT_HAS_NXP_MCUX_USBD_ENABLED + depends on DT_HAS_NXP_EHCI_ENABLED || DT_HAS_NXP_LPCIP3511_ENABLED help NXP MCUX USB Device Controller Driver for MXRT and LPC SoC's. diff --git a/drivers/usb/device/usb_dc_mcux.c b/drivers/usb/device/usb_dc_mcux.c index 7278d25d728bdd9..0667486b62806aa 100644 --- a/drivers/usb/device/usb_dc_mcux.c +++ b/drivers/usb/device/usb_dc_mcux.c @@ -5,8 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT nxp_mcux_usbd - #include #include #include @@ -21,15 +19,20 @@ #include "usb_device_dci.h" #ifdef CONFIG_USB_DC_NXP_EHCI +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_ehci #include "usb_device_ehci.h" #endif #ifdef CONFIG_USB_DC_NXP_LPCIP3511 +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_lpcip3511 #include "usb_device_lpcip3511.h" #endif #ifdef CONFIG_HAS_MCUX_CACHE #include #endif + #define LOG_LEVEL CONFIG_USB_DRIVER_LOG_LEVEL #include #include @@ -68,7 +71,34 @@ static void usb_isr_handler(void); #define EP_ABS_IDX(ep) (USB_EP_GET_IDX(ep) * 2 + \ (USB_EP_GET_DIR(ep) >> 7)) #define NUM_OF_EP_MAX (DT_INST_PROP(0, num_bidir_endpoints) * 2) -#define CONTROLLER_ID (DT_INST_ENUM_IDX(0, usb_controller_index)) + +#define NUM_INSTS DT_NUM_INST_STATUS_OKAY(nxp_ehci) + DT_NUM_INST_STATUS_OKAY(nxp_lpcip3511) +BUILD_ASSERT(NUM_INSTS <= 1, "Only one USB device supported"); + +/* Controller ID is for HAL usage */ +#if defined(CONFIG_SOC_SERIES_IMX_RT5XX) || \ + defined(CONFIG_SOC_SERIES_IMX_RT6XX) || \ + defined(CONFIG_SOC_LPC55S28) || \ + defined(CONFIG_SOC_LPC55S16) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Hs0 +#elif defined(CONFIG_SOC_LPC55S36) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Fs0 +#elif defined(CONFIG_SOC_LPC55S69_CPU0) || defined(CONFIG_SOC_LPC55S69_CPU1) +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usbhs), okay) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Hs0 +#elif DT_NODE_HAS_STATUS(DT_NODELABEL(usbfs), okay) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Fs0 +#endif /* LPC55s69 */ +#elif defined(CONFIG_SOC_SERIES_IMX_RT) +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) +#define CONTROLLER_ID kUSB_ControllerEhci0 +#elif DT_NODE_HAS_STATUS(DT_NODELABEL(usb2), okay) +#define CONTROLLER_ID kUSB_ControllerEhci1 +#endif /* IMX RT */ +#else +/* If SOC has EHCI or LPCIP3511 then probably just need to add controller ID to this code */ +#error "USB driver does not yet support this SOC" +#endif /* CONTROLLER ID */ /* We do not need a buffer for the write side on platforms that have USB RAM. * The SDK driver will copy the data buffer to be sent to USB RAM. diff --git a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi index 9e4ee4841dbd0c6..76d551555ef2920 100644 --- a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi @@ -240,11 +240,10 @@ }; usbhs: usbhs@144000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x94000 0x1000>; interrupts = <47 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi index c429a4bd4ef8382..16d9c1312c306c9 100644 --- a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi @@ -284,11 +284,10 @@ }; usbhs: usbhs@144000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x94000 0x1000>; interrupts = <47 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi index 381a0b073913aa9..dd011ece96d0f02 100644 --- a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi @@ -443,12 +443,11 @@ }; usbfs: usbfs@84000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x84000 0x1000>; interrupts = <28 0>; num-bidir-endpoints = <5>; maximum-speed = "full-speed"; - usb-controller-index = "LpcIp3511Fs0"; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index c7c7d238dc7862f..411f8ac8f5fc56e 100644 --- a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi @@ -325,21 +325,19 @@ }; usbfs: usbfs@84000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x84000 0x1000>; interrupts = <28 1>; num-bidir-endpoints = <5>; maximum-speed = "full-speed"; - usb-controller-index = "LpcIp3511Fs0"; status = "disabled"; }; usbhs: usbhs@94000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x94000 0x1000>; interrupts = <47 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_rt1010.dtsi b/dts/arm/nxp/nxp_rt1010.dtsi index cdd132b59df2b90..1afed91a45ca775 100644 --- a/dts/arm/nxp/nxp_rt1010.dtsi +++ b/dts/arm/nxp/nxp_rt1010.dtsi @@ -234,13 +234,12 @@ /* Fixup USB it has different base addr and interrupt numbers on RT1010 */ /delete-node/ usbd@402e0000; usb1: usbd@400e4000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x400e4000 0x200>; interrupts = <25 1>; interrupt-names = "usb_otg"; clocks = <&usbclk>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci0"; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index d6c247ba651a6ec..23bd7255301bb45 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -790,24 +790,22 @@ }; usb1: usbd@402e0000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x402E0000 0x200>; interrupts = <113 1>; interrupt-names = "usb_otg"; clocks = <&usbclk>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci0"; status = "disabled"; }; usb2: usbd@402e0200 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x402E0200 0x200>; interrupts = <112 1>; interrupt-names = "usb_otg"; clocks = <&usbclk>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci1"; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index faf4b9cae7b5dd0..eb14d37f8349c3d 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -749,24 +749,22 @@ }; usb1: usbd@40430000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x40430000 0x200>; interrupts = <136 1>; interrupt-names = "usb_otg"; clocks = <&xtal>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci0"; status = "disabled"; }; usb2: usbd@4042c000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x4042c000 0x200>; interrupts = <135 1>; interrupt-names = "usb_otg"; clocks = <&xtal>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci1"; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 9165b26441e1afe..3f5319a7401d5f6 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -338,11 +338,10 @@ }; usbhs: usbhs@144000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x144000 0x1000>; interrupts = <50 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 843c1739cd29efd..e4acafbafa5f1da 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -259,11 +259,10 @@ }; usbhs: usbhs@144000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x144000 0x1000>; interrupts = <50 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; diff --git a/dts/bindings/usb/nxp,ehci.yaml b/dts/bindings/usb/nxp,ehci.yaml new file mode 100644 index 000000000000000..cf72a69545c9f27 --- /dev/null +++ b/dts/bindings/usb/nxp,ehci.yaml @@ -0,0 +1,8 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP EHCI USB device mode + +compatible: nxp,ehci + +include: "nxp,mcux-usbd.yaml" diff --git a/dts/bindings/usb/nxp,lpcip3511.yaml b/dts/bindings/usb/nxp,lpcip3511.yaml new file mode 100644 index 000000000000000..70ea11888372239 --- /dev/null +++ b/dts/bindings/usb/nxp,lpcip3511.yaml @@ -0,0 +1,8 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP LPCIP3511 USB device mode + +compatible: nxp,lpcip3511 + +include: "nxp,mcux-usbd.yaml" diff --git a/dts/bindings/usb/nxp,mcux-usbd.yaml b/dts/bindings/usb/nxp,mcux-usbd.yaml index 389f43e1da0e1a9..af0dd7621371c92 100644 --- a/dts/bindings/usb/nxp,mcux-usbd.yaml +++ b/dts/bindings/usb/nxp,mcux-usbd.yaml @@ -4,8 +4,6 @@ description: | NPX MXRT and LPC USBOTG Controller in device mode -compatible: "nxp,mcux-usbd" - include: [usb-ep.yaml, pinctrl-device.yaml] properties: @@ -14,24 +12,3 @@ properties: interrupts: required: true - - usb-controller-index: - required: true - type: string - description: | - This is taken from the usb_controller_index_t enum that is included inside the NXP SDK - enum: - - "Khci0" - - "Khci1" - - "Ehci0" - - "Ehci1" - - "LpcIp3511Fs0" - - "LpcIp3511Fs1" - - "LpcIp3511Hs0" - - "LpcIp3511Hs1" - - "Ohci0" - - "Ohci1" - - "Ip3516Hs0" - - "Ip3516Hs1" - - "Dwc30" - - "Dwc31" diff --git a/modules/hal_nxp/usb/usb_device_config.h b/modules/hal_nxp/usb/usb_device_config.h index ca2bc5d9373b646..31a62ffbfebc522 100644 --- a/modules/hal_nxp/usb/usb_device_config.h +++ b/modules/hal_nxp/usb/usb_device_config.h @@ -39,7 +39,15 @@ /* Whether device is self power. 1U supported, 0U not supported */ #define USB_DEVICE_CONFIG_SELF_POWER (1U) -#define DT_DRV_COMPAT nxp_mcux_usbd +#define NUM_INSTS DT_NUM_INST_STATUS_OKAY(nxp_ehci) + DT_NUM_INST_STATUS_OKAY(nxp_lpcip3511) +BUILD_ASSERT(NUM_INSTS <= 1, "Only one USB device supported"); +#if DT_HAS_COMPAT_STATUS_OKAY(nxp_lpcip3511) +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_lpcip3511 +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_ehci) +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_ehci +#endif /* Number of endpoints supported */ #define USB_DEVICE_CONFIG_ENDPOINTS (DT_INST_PROP(0, num_bidir_endpoints)) diff --git a/soc/arm/nxp_lpc/lpc55xxx/soc.c b/soc/arm/nxp_lpc/lpc55xxx/soc.c index 8084be533841e51..e3620782acb29c9 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc55xxx/soc.c @@ -217,7 +217,7 @@ static ALWAYS_INLINE void clock_init(void) #if CONFIG_USB_DC_NXP_LPCIP3511 -#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbfs), nxp_mcux_usbd, okay) +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbfs), nxp_lpcip3511, okay) /*< Turn on USB Phy */ #if defined(CONFIG_SOC_LPC55S36) POWER_DisablePD(kPDRUNCFG_PD_USBFSPHY); @@ -248,7 +248,7 @@ static ALWAYS_INLINE void clock_init(void) #endif /* USB_DEVICE_TYPE_FS */ -#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbhs), nxp_mcux_usbd, okay) +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbhs), nxp_lpcip3511, okay) /* enable usb1 host clock */ CLOCK_EnableClock(kCLOCK_Usbh1); /* Put PHY powerdown under software control */ From 1cef7f3250efef663b0f0ce33b7b4768ee97c1b9 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 8 Aug 2023 13:00:30 +0200 Subject: [PATCH 0145/1049] driver: eth: Implementation of Open Alliance's TC6 T1S communication Those files provide generic functions to handle transmission between chip conforming OA TC6 standard and Zephyr's network stack represented by struct net_pkt. The communication is performed via SPI and is focused on reduced memory footprint (works with SOC equipped with 32 KiB of RAM) and robustness of operation. Signed-off-by: Lukasz Majewski --- CODEOWNERS | 1 + drivers/ethernet/oa_tc6.c | 393 ++++++++++++++++++++++++++++++++++++++ drivers/ethernet/oa_tc6.h | 233 ++++++++++++++++++++++ 3 files changed, 627 insertions(+) create mode 100644 drivers/ethernet/oa_tc6.c create mode 100644 drivers/ethernet/oa_tc6.h diff --git a/CODEOWNERS b/CODEOWNERS index f339c8958fee913..f3d2bb732c90bf4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -305,6 +305,7 @@ /drivers/ethernet/*xlnx_gem* @ibirnbaum /drivers/ethernet/*smsc91x* @sgrrzhf /drivers/ethernet/*adin2111* @GeorgeCGV +/drivers/ethernet/*oa_tc6* @lmajewski /drivers/ethernet/phy/ @rlubos @tbursztyka @arvinf @jukkar /drivers/ethernet/phy/*adin2111* @GeorgeCGV /drivers/mdio/ @rlubos @tbursztyka @arvinf diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c new file mode 100644 index 000000000000000..0fa1f105581d344 --- /dev/null +++ b/drivers/ethernet/oa_tc6.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2023 DENX Software Engineering GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "oa_tc6.h" + +#include +LOG_MODULE_REGISTER(oa_tc6, CONFIG_ETHERNET_LOG_LEVEL); + +int oa_tc6_reg_read(struct oa_tc6 *tc6, const uint32_t reg, uint32_t *val) +{ + uint8_t buf[OA_TC6_HDR_SIZE + 12] = { 0 }; + struct spi_buf tx_buf = { .buf = buf, .len = sizeof(buf) }; + const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 }; + struct spi_buf rx_buf = { .buf = buf, .len = sizeof(buf) }; + const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 }; + uint32_t rv, rvn, hdr_bkp, *hdr = (uint32_t *) &buf[0]; + int ret = 0; + + /* + * Buffers are allocated for protected (larger) case (by 4 bytes). + * When non-protected case - we need to decrase them + */ + if (!tc6->protected) { + tx_buf.len -= sizeof(rvn); + rx_buf.len -= sizeof(rvn); + } + + *hdr = FIELD_PREP(OA_CTRL_HDR_DNC, 0) | + FIELD_PREP(OA_CTRL_HDR_WNR, 0) | + FIELD_PREP(OA_CTRL_HDR_AID, 0) | + FIELD_PREP(OA_CTRL_HDR_MMS, reg >> 16) | + FIELD_PREP(OA_CTRL_HDR_ADDR, reg) | + FIELD_PREP(OA_CTRL_HDR_LEN, 0); /* To read single register len = 0 */ + *hdr |= FIELD_PREP(OA_CTRL_HDR_P, oa_tc6_get_parity(*hdr)); + hdr_bkp = *hdr; + *hdr = sys_cpu_to_be32(*hdr); + + ret = spi_transceive_dt(tc6->spi, &tx, &rx); + if (ret < 0) { + return ret; + } + + /* Check if echoed control command header is correct */ + rv = sys_be32_to_cpu(*(uint32_t *)&buf[4]); + if (hdr_bkp != rv) { + LOG_ERR("Header transmission error!"); + return -1; + } + + rv = sys_be32_to_cpu(*(uint32_t *)&buf[8]); + + /* In protected mode read data is followed by its compliment value */ + if (tc6->protected) { + rvn = sys_be32_to_cpu(*(uint32_t *)&buf[12]); + if (rv != ~rvn) { + LOG_ERR("Protected mode transmission error!"); + return -1; + } + } + + *val = rv; + + return ret; +} + +int oa_tc6_reg_write(struct oa_tc6 *tc6, const uint32_t reg, uint32_t val) +{ + uint8_t buf_tx[OA_TC6_HDR_SIZE + 12] = { 0 }; + uint8_t buf_rx[OA_TC6_HDR_SIZE + 12] = { 0 }; + struct spi_buf tx_buf = { .buf = buf_tx, .len = sizeof(buf_tx) }; + const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 }; + struct spi_buf rx_buf = { .buf = buf_rx, .len = sizeof(buf_rx) }; + const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 }; + uint32_t rv, rvn, hdr_bkp, *hdr = (uint32_t *) &buf_tx[0]; + int ret; + + /* + * Buffers are allocated for protected (larger) case (by 4 bytes). + * When non-protected case - we need to decrase them + */ + if (!tc6->protected) { + tx_buf.len -= sizeof(rvn); + rx_buf.len -= sizeof(rvn); + } + + *hdr = FIELD_PREP(OA_CTRL_HDR_DNC, 0) | + FIELD_PREP(OA_CTRL_HDR_WNR, 1) | + FIELD_PREP(OA_CTRL_HDR_AID, 0) | + FIELD_PREP(OA_CTRL_HDR_MMS, reg >> 16) | + FIELD_PREP(OA_CTRL_HDR_ADDR, reg) | + FIELD_PREP(OA_CTRL_HDR_LEN, 0); /* To read single register len = 0 */ + *hdr |= FIELD_PREP(OA_CTRL_HDR_P, oa_tc6_get_parity(*hdr)); + hdr_bkp = *hdr; + *hdr = sys_cpu_to_be32(*hdr); + + *(uint32_t *)&buf_tx[4] = sys_cpu_to_be32(val); + if (tc6->protected) { + *(uint32_t *)&buf_tx[8] = sys_be32_to_cpu(~val); + } + + ret = spi_transceive_dt(tc6->spi, &tx, &rx); + if (ret < 0) { + return ret; + } + + /* Check if echoed control command header is correct */ + rv = sys_be32_to_cpu(*(uint32_t *)&buf_rx[4]); + if (hdr_bkp != rv) { + LOG_ERR("Header transmission error!"); + return -1; + } + + /* Check if echoed value is correct */ + rv = sys_be32_to_cpu(*(uint32_t *)&buf_rx[8]); + if (val != rv) { + LOG_ERR("Header transmission error!"); + return -1; + } + + /* + * In protected mode check if read value is followed by its + * compliment value + */ + if (tc6->protected) { + rvn = sys_be32_to_cpu(*(uint32_t *)&buf_rx[12]); + if (val != ~rvn) { + LOG_ERR("Protected mode transmission error!"); + return -1; + } + } + + return ret; +} + +int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote) +{ + uint32_t val; + int ret; + + ret = oa_tc6_reg_read(tc6, OA_CONFIG0, &val); + if (ret < 0) { + return ret; + } + + if (prote) { + val |= OA_CONFIG0_PROTE; + } else { + val &= ~OA_CONFIG0_PROTE; + } + + ret = oa_tc6_reg_write(tc6, OA_CONFIG0, val); + if (ret < 0) { + return ret; + } + + tc6->protected = prote; + return 0; +} + +int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) +{ + uint16_t len = net_pkt_get_len(pkt); + uint8_t oa_tx[tc6->cps]; + uint32_t hdr, ftr; + uint8_t chunks, i; + int ret; + + chunks = (len / tc6->cps) + 1; + + /* Check if LAN865x has any free internal buffer space */ + if (chunks > tc6->txc) { + return -EIO; + } + + /* Transform struct net_pkt content into chunks */ + for (i = 1; i <= chunks; i++) { + hdr = FIELD_PREP(OA_DATA_HDR_DNC, 1) | + FIELD_PREP(OA_DATA_HDR_DV, 1) | + FIELD_PREP(OA_DATA_HDR_NORX, 1) | + FIELD_PREP(OA_DATA_HDR_SWO, 0); + + if (i == 1) { + hdr |= FIELD_PREP(OA_DATA_HDR_SV, 1); + } + + if (i == chunks) { + hdr |= FIELD_PREP(OA_DATA_HDR_EBO, len - 1) | + FIELD_PREP(OA_DATA_HDR_EV, 1); + } + + hdr |= FIELD_PREP(OA_DATA_HDR_P, oa_tc6_get_parity(hdr)); + + ret = net_pkt_read(pkt, oa_tx, len > tc6->cps ? tc6->cps : len); + if (ret < 0) { + return ret; + } + + ret = oa_tc6_chunk_spi_transfer(tc6, NULL, oa_tx, hdr, &ftr); + if (ret < 0) { + return ret; + } + + len -= tc6->cps; + } + + return 0; +} + +static void oa_tc6_update_status(struct oa_tc6 *tc6, uint32_t ftr) +{ + tc6->exst = FIELD_GET(OA_DATA_FTR_EXST, ftr); + tc6->sync = FIELD_GET(OA_DATA_FTR_SYNC, ftr); + tc6->rca = FIELD_GET(OA_DATA_FTR_RCA, ftr); + tc6->txc = FIELD_GET(OA_DATA_FTR_TXC, ftr); +} + +int oa_tc6_update_buf_info(struct oa_tc6 *tc6) +{ + uint32_t val; + int ret; + + ret = oa_tc6_reg_read(tc6, OA_BUFSTS, &val); + if (ret < 0) { + return ret; + } + + tc6->rca = FIELD_GET(OA_BUFSTS_RCA, val); + tc6->txc = FIELD_GET(OA_BUFSTS_TXC, val); + + return 0; +} + +int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_tx, + uint32_t hdr, uint32_t *ftr) +{ + struct spi_buf tx_buf[2]; + struct spi_buf rx_buf[2]; + struct spi_buf_set tx; + struct spi_buf_set rx; + int ret; + + hdr = sys_cpu_to_be32(hdr); + tx_buf[0].buf = &hdr; + tx_buf[0].len = sizeof(hdr); + + tx_buf[1].buf = buf_tx; + tx_buf[1].len = tc6->cps; + + tx.buffers = tx_buf; + tx.count = ARRAY_SIZE(tx_buf); + + rx_buf[0].buf = buf_rx; + rx_buf[0].len = tc6->cps; + + rx_buf[1].buf = ftr; + rx_buf[1].len = sizeof(*ftr); + + rx.buffers = rx_buf; + rx.count = ARRAY_SIZE(rx_buf); + + ret = spi_transceive_dt(tc6->spi, &tx, &rx); + if (ret < 0) { + return ret; + } + *ftr = sys_be32_to_cpu(*ftr); + oa_tc6_update_status(tc6, *ftr); + + return 0; +} + +int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr) +{ + uint32_t hdr; + + hdr = FIELD_PREP(OA_DATA_HDR_DNC, 1) | + FIELD_PREP(OA_DATA_HDR_DV, 0) | + FIELD_PREP(OA_DATA_HDR_NORX, 1); + hdr |= FIELD_PREP(OA_DATA_HDR_P, oa_tc6_get_parity(hdr)); + + return oa_tc6_chunk_spi_transfer(tc6, NULL, NULL, hdr, ftr); +} + +int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) +{ + struct net_buf *buf_rx = NULL; + uint8_t chunks, sbo, ebo; + uint32_t hdr, ftr; + int ret; + + /* + * Special case - append already received data (extracted from previous + * chunk) to new packet. + */ + if (tc6->concat_buf) { + net_pkt_append_buffer(pkt, tc6->concat_buf); + tc6->concat_buf = NULL; + } + + for (chunks = tc6->rca; chunks; chunks--) { + buf_rx = net_pkt_get_frag(pkt, tc6->cps, OA_TC6_BUF_ALLOC_TIMEOUT); + if (!buf_rx) { + LOG_ERR("OA RX: Can't allocate RX buffer fordata!"); + return -ENOMEM; + } + + hdr = FIELD_PREP(OA_DATA_HDR_DNC, 1); + hdr |= FIELD_PREP(OA_DATA_HDR_P, oa_tc6_get_parity(hdr)); + + ret = oa_tc6_chunk_spi_transfer(tc6, buf_rx->data, NULL, hdr, &ftr); + if (ret < 0) { + LOG_ERR("OA RX: transmission error: %d!", ret); + goto unref_buf; + } + + ret = -EIO; + if (oa_tc6_get_parity(ftr)) { + LOG_ERR("OA RX: Footer parity error!"); + goto unref_buf; + } + + if (!FIELD_GET(OA_DATA_FTR_SYNC, ftr)) { + LOG_ERR("OA RX: Configuration not SYNC'ed!"); + goto unref_buf; + } + + if (!FIELD_GET(OA_DATA_FTR_DV, ftr)) { + LOG_ERR("OA RX: Data chunk not valid, skip!"); + goto unref_buf; + } + + sbo = FIELD_GET(OA_DATA_FTR_SWO, ftr) * sizeof(uint32_t); + ebo = FIELD_GET(OA_DATA_FTR_EBO, ftr) + 1; + + if (FIELD_GET(OA_DATA_FTR_SV, ftr)) { + /* + * Adjust beginning of the buffer with SWO only when + * we DO NOT have two frames concatenated together + * in one chunk. + */ + if (!(FIELD_GET(OA_DATA_FTR_EV, ftr) && (ebo <= sbo))) { + if (sbo) { + net_buf_pull(buf_rx, sbo); + } + } + } + + net_pkt_append_buffer(pkt, buf_rx); + buf_rx->len = tc6->cps; + + if (FIELD_GET(OA_DATA_FTR_EV, ftr)) { + /* + * Check if received frame shall be dropped - i.e. MAC has + * detected error condition, which shall result in frame drop + * by the SPI host. + */ + if (FIELD_GET(OA_DATA_FTR_FD, ftr)) { + ret = -EIO; + goto unref_buf; + } + + /* + * Concatenation of frames in a single chunk - one frame ends + * and second one starts just afterwards (ebo == sbo). + */ + if (FIELD_GET(OA_DATA_FTR_SV, ftr) && (ebo <= sbo)) { + tc6->concat_buf = net_buf_clone(buf_rx, OA_TC6_BUF_ALLOC_TIMEOUT); + if (!tc6->concat_buf) { + LOG_ERR("OA RX: Can't allocate RX buffer for data!"); + ret = -ENOMEM; + goto unref_buf; + } + net_buf_pull(tc6->concat_buf, sbo); + } + + /* Set final size of the buffer */ + buf_rx->len = ebo; + /* + * Exit when complete packet is read and added to + * struct net_pkt + */ + break; + } + } + + return 0; + + unref_buf: + net_buf_unref(buf_rx); + return ret; +} diff --git a/drivers/ethernet/oa_tc6.h b/drivers/ethernet/oa_tc6.h new file mode 100644 index 000000000000000..7a9337e7c5d0ac7 --- /dev/null +++ b/drivers/ethernet/oa_tc6.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2023 DENX Software Engineering GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef OA_TC6_CFG_H__ +#define OA_TC6_CFG_H__ + +#include +#include +#include +#include +#include +#include + +#define MMS_REG(m, r) ((((m) & GENMASK(3, 0)) << 16) | ((r) & GENMASK(15, 0))) +/* Memory Map Sector (MMS) 0 */ +#define OA_ID MMS_REG(0x0, 0x000) /* expect 0x11 */ +#define OA_PHYID MMS_REG(0x0, 0x001) +#define OA_RESET MMS_REG(0x0, 0x003) +#define OA_RESET_SWRESET BIT(0) +#define OA_CONFIG0 MMS_REG(0x0, 0x004) +#define OA_CONFIG0_SYNC BIT(15) +#define OA_CONFIG0_PROTE BIT(5) +#define OA_STATUS0 MMS_REG(0x0, 0x008) +#define OA_STATUS0_RESETC BIT(6) +#define OA_STATUS1 MMS_REG(0x0, 0x009) +#define OA_BUFSTS MMS_REG(0x0, 0x00B) +#define OA_BUFSTS_TXC GENMASK(15, 8) +#define OA_BUFSTS_RCA GENMASK(7, 0) +#define OA_IMASK0 MMS_REG(0x0, 0x00C) +#define OA_IMASK0_TXPEM BIT(0) +#define OA_IMASK0_TXBOEM BIT(1) +#define OA_IMASK0_TXBUEM BIT(2) +#define OA_IMASK0_RXBOEM BIT(3) +#define OA_IMASK0_LOFEM BIT(4) +#define OA_IMASK0_HDREM BIT(5) +#define OA_IMASK1 MMS_REG(0x0, 0x00D) +#define OA_IMASK0_UV18M BIT(19) + +/* OA Control header */ +#define OA_CTRL_HDR_DNC BIT(31) +#define OA_CTRL_HDR_HDRB BIT(30) +#define OA_CTRL_HDR_WNR BIT(29) +#define OA_CTRL_HDR_AID BIT(28) +#define OA_CTRL_HDR_MMS GENMASK(27, 24) +#define OA_CTRL_HDR_ADDR GENMASK(23, 8) +#define OA_CTRL_HDR_LEN GENMASK(7, 1) +#define OA_CTRL_HDR_P BIT(0) + +/* OA Data header */ +#define OA_DATA_HDR_DNC BIT(31) +#define OA_DATA_HDR_SEQ BIT(30) +#define OA_DATA_HDR_NORX BIT(29) +#define OA_DATA_HDR_DV BIT(21) +#define OA_DATA_HDR_SV BIT(20) +#define OA_DATA_HDR_SWO GENMASK(19, 16) +#define OA_DATA_HDR_EV BIT(14) +#define OA_DATA_HDR_EBO GENMASK(13, 8) +#define OA_DATA_HDR_P BIT(0) + +/* OA Data footer */ +#define OA_DATA_FTR_EXST BIT(31) +#define OA_DATA_FTR_HDRB BIT(30) +#define OA_DATA_FTR_SYNC BIT(29) +#define OA_DATA_FTR_RCA GENMASK(28, 24) +#define OA_DATA_FTR_DV BIT(21) +#define OA_DATA_FTR_SV BIT(20) +#define OA_DATA_FTR_SWO GENMASK(19, 16) +#define OA_DATA_FTR_FD BIT(15) +#define OA_DATA_FTR_EV BIT(14) +#define OA_DATA_FTR_EBO GENMASK(13, 8) +#define OA_DATA_FTR_TXC GENMASK(5, 1) +#define OA_DATA_FTR_P BIT(0) + +#define OA_TC6_HDR_SIZE 4 +#define OA_TC6_FTR_SIZE 4 +#define OA_TC6_BUF_ALLOC_TIMEOUT K_MSEC(10) + +/** + * @brief OA TC6 data. + */ +struct oa_tc6 { + /** Pointer to SPI device */ + const struct spi_dt_spec *spi; + + /** OA data payload (chunk) size */ + uint8_t cps; + + /** + * Number of available chunks buffers in OA TC6 device to store + * data for transmission + */ + uint8_t txc; + + /** Number of available chunks to read from OA TC6 device */ + uint8_t rca; + + /** Indication of pending interrupt in OA TC6 device */ + bool exst; + + /** Indication of OA TC6 device being ready for transmission */ + bool sync; + + /** Indication of protected control transmission mode */ + bool protected; + + /** Pointer to network buffer concatenated from received chunk */ + struct net_buf *concat_buf; +}; + +typedef struct { + uint32_t address; + uint32_t value; +} oa_mem_map_t; + +/** + * @brief Calculate parity bit from data + * + * @param x data to calculate parity + * + * @return 0 if number of ones is odd, 1 otherwise. + */ +static inline bool oa_tc6_get_parity(const uint32_t x) +{ + uint32_t y; + + y = x ^ (x >> 1); + y = y ^ (y >> 2); + y = y ^ (y >> 4); + y = y ^ (y >> 8); + y = y ^ (y >> 16); + + return !(y & 1); +} + +/** + * @brief Read OA TC6 compliant device single register + * + * @param tc6 OA TC6 specific data + * + * @param reg register to read + + * @param val pointer to variable to store read value + * + * @return 0 if read was successful, <0 otherwise. + */ +int oa_tc6_reg_read(struct oa_tc6 *tc6, const uint32_t reg, uint32_t *val); + +/** + * @brief Write to OA TC6 compliant device a single register + * + * @param tc6 OA TC6 specific data + * + * @param reg register to read + + * @param val data to send to device + * + * @return 0 if write was successful, <0 otherwise. + */ +int oa_tc6_reg_write(struct oa_tc6 *tc6, const uint32_t reg, uint32_t val); + +/** + * @brief Enable or disable the protected mode for control transactions + * + * @param tc6 OA TC6 specific data + * + * @param prote enable or disable protected control transactions + * + * @return 0 if operation was successful, <0 otherwise. + */ +int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote); + +/** + * @brief Send OA TC6 data chunks to the device + * + * @param tc6 OA TC6 specific data + * + * @param pkt network packet to be send + * + * @return 0 if data send was successful, <0 otherwise. + */ +int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt); + +/** + * @brief Read data chunks from OA TC6 device + * + * @param tc6 OA TC6 specific data + * + * @param pkt network packet to store received data + * + * @return 0 if read was successful, <0 otherwise. + */ +int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt); + +/** + * @brief Perform SPI transfer of single chunk from/to OA TC6 device + * + * @param tc6 OA TC6 specific data + * + * @param buf_rx buffer to store read data + * + * @param buf_tx buffer with data to send + * + * @param hdr OA TC6 data transmission header value + * + * @param ftr poniter to OA TC6 data received footer + * + * @return 0 if transmission was successful, <0 otherwise. + */ +int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_tx, + uint32_t hdr, uint32_t *ftr); + +/** + * @brief Read status from OA TC6 device + * + * @param tc6 OA TC6 specific data + * + * @param ftr poniter to OA TC6 data received footer + * + * @return 0 if successful, <0 otherwise. + */ +int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr); + +/** + * @brief Read from OA TC6 device and update buffer information + * + * @param tc6 OA TC6 specific data + * + * @return 0 if successful, <0 otherwise. + */ +int oa_tc6_update_buf_info(struct oa_tc6 *tc6); +#endif /* OA_TC6_CFG_H__ */ From 12665a0dc12b1ed5dce71d232a6abcb8d6a6056b Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 6 Oct 2023 16:59:42 +0200 Subject: [PATCH 0146/1049] driver: eth: Support for lan8651 T1S ETH This patch set provides support for T1S ethernet device - LAN8651. For SPI communication the implementation of Open Alliance TC6 specification is used. The driver implementation focuses mostly on reducing memory footprint, as the used SoC (STM32G491) for development has only 32 KiB RAM in total. Signed-off-by: Lukasz Majewski --- CODEOWNERS | 1 + drivers/ethernet/CMakeLists.txt | 1 + drivers/ethernet/Kconfig | 1 + drivers/ethernet/Kconfig.lan865x | 50 ++ drivers/ethernet/eth_lan865x.c | 585 +++++++++++++++++++ drivers/ethernet/eth_lan865x_priv.h | 77 +++ dts/bindings/ethernet/microchip,lan865x.yaml | 46 ++ 7 files changed, 761 insertions(+) create mode 100644 drivers/ethernet/Kconfig.lan865x create mode 100644 drivers/ethernet/eth_lan865x.c create mode 100644 drivers/ethernet/eth_lan865x_priv.h create mode 100644 dts/bindings/ethernet/microchip,lan865x.yaml diff --git a/CODEOWNERS b/CODEOWNERS index f3d2bb732c90bf4..1db37fb9dd586f4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -306,6 +306,7 @@ /drivers/ethernet/*smsc91x* @sgrrzhf /drivers/ethernet/*adin2111* @GeorgeCGV /drivers/ethernet/*oa_tc6* @lmajewski +/drivers/ethernet/*lan865x* @lmajewski /drivers/ethernet/phy/ @rlubos @tbursztyka @arvinf @jukkar /drivers/ethernet/phy/*adin2111* @GeorgeCGV /drivers/mdio/ @rlubos @tbursztyka @arvinf diff --git a/drivers/ethernet/CMakeLists.txt b/drivers/ethernet/CMakeLists.txt index 20cc367fe5b4d49..1ae6ef58e82852f 100644 --- a/drivers/ethernet/CMakeLists.txt +++ b/drivers/ethernet/CMakeLists.txt @@ -34,6 +34,7 @@ zephyr_library_sources_ifdef(CONFIG_SLIP_TAP eth_slip_tap.c) zephyr_library_sources_ifdef(CONFIG_ETH_SMSC91X eth_smsc91x.c) zephyr_library_sources_ifdef(CONFIG_ETH_IVSHMEM eth_ivshmem.c eth_ivshmem_queue.c) zephyr_library_sources_ifdef(CONFIG_ETH_ADIN2111 eth_adin2111.c) +zephyr_library_sources_ifdef(CONFIG_ETH_LAN865X eth_lan865x.c oa_tc6.c) if(CONFIG_ETH_NXP_S32_NETC) zephyr_library_sources(eth_nxp_s32_netc.c) diff --git a/drivers/ethernet/Kconfig b/drivers/ethernet/Kconfig index eae83755af076ac..69b60e09bc2add9 100644 --- a/drivers/ethernet/Kconfig +++ b/drivers/ethernet/Kconfig @@ -62,6 +62,7 @@ source "drivers/ethernet/Kconfig.smsc91x" source "drivers/ethernet/Kconfig.ivshmem" source "drivers/ethernet/Kconfig.adin2111" source "drivers/ethernet/Kconfig.numaker" +source "drivers/ethernet/Kconfig.lan865x" source "drivers/ethernet/phy/Kconfig" diff --git a/drivers/ethernet/Kconfig.lan865x b/drivers/ethernet/Kconfig.lan865x new file mode 100644 index 000000000000000..c3bdc2f9b731e54 --- /dev/null +++ b/drivers/ethernet/Kconfig.lan865x @@ -0,0 +1,50 @@ +# Copyright (c) 2023 DENX Software Engineering GmbH +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ETH_LAN865X + bool "LAN865X 10BASE-T1S Controller" + default y + depends on DT_HAS_MICROCHIP_LAN865X_ENABLED + select SPI + help + The LAN865X is a low power, 10BASE-T1S transceiver compliant with + the IEEE® 802.3cg-2019™ Ethernet standard for long reach, 10 + Mbps single pair Ethernet (SPE). + + Featuring an integrated media access control (MAC) and a PHY, + the LAN865X enables direct connectivity with a variety of controllers + via a serial peripheral inter-face (SPI). + +if ETH_LAN865X + +config ETH_LAN865X_INIT_PRIORITY + int "LAN865X driver init priority" + default 72 + help + LAN865X device driver initialization priority. + Must be initialized after SPI. + + +config ETH_LAN865X_IRQ_THREAD_STACK_SIZE + int "Stack size for a thread that processes IRQ" + default 512 + help + Size of the stack used for internal thread which is ran to + process raised INT IRQ. + +config ETH_LAN865X_IRQ_THREAD_PRIO + int "Priority for internal incoming packet handler" + default 2 + help + Priority level for internal thread which is ran for LAN + INT IRQ processing. + +config ETH_LAN865X_TIMEOUT + int "IP buffer timeout" + default 100 + help + Given timeout in milliseconds. Maximum amount of time + that the driver will wait from the IP stack to get + a memory buffer before the Ethernet frame is dropped. + +endif # ETH_LAN865X diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c new file mode 100644 index 000000000000000..8107b7d3542b49c --- /dev/null +++ b/drivers/ethernet/eth_lan865x.c @@ -0,0 +1,585 @@ +/* + * Copyright (c) 2023 DENX Software Engineering GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_lan865x + +#include +LOG_MODULE_REGISTER(eth_lan865x, CONFIG_ETHERNET_LOG_LEVEL); + +#include +#include + +#include +#include + +#include +#include +#include + +#include "eth_lan865x_priv.h" + +static int lan865x_mac_rxtx_control(const struct device *dev, bool en) +{ + struct lan865x_data *ctx = dev->data; + uint32_t ctl = 0; + + if (en) { + ctl = LAN865x_MAC_NCR_TXEN | LAN865x_MAC_NCR_RXEN; + } + + return oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCR, ctl); +} + +static void lan865x_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct lan865x_data *ctx = dev->data; + + net_if_set_link_addr(iface, ctx->mac_address, sizeof(ctx->mac_address), + NET_LINK_ETHERNET); + + if (ctx->iface == NULL) { + ctx->iface = iface; + } + + ethernet_init(iface); + + net_eth_carrier_on(iface); + ctx->iface_initialized = true; +} + +static enum ethernet_hw_caps lan865x_port_get_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + return ETHERNET_LINK_10BASE_T | ETHERNET_PROMISC_MODE; +} + +static void lan865x_write_macaddress(const struct device *dev); +static int lan865x_set_config(const struct device *dev, enum ethernet_config_type type, + const struct ethernet_config *config) +{ + struct lan865x_data *ctx = dev->data; + int ret = -ENOTSUP; + + if (type == ETHERNET_CONFIG_TYPE_PROMISC_MODE) { + ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF); + if (ret) { + return ret; + } + + ret = oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCFGR, + LAN865x_MAC_NCFGR_CAF); + if (ret) { + return ret; + } + + return lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON); + } + + if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) { + ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF); + if (ret) { + return ret; + } + + memcpy(ctx->mac_address, config->mac_address.addr, + sizeof(ctx->mac_address)); + + lan865x_write_macaddress(dev); + + net_if_set_link_addr(ctx->iface, ctx->mac_address, + sizeof(ctx->mac_address), + NET_LINK_ETHERNET); + + return lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON); + } + + return ret; +} + +static int lan865x_wait_for_reset(const struct device *dev) +{ + struct lan865x_data *ctx = dev->data; + uint8_t i; + + /* Wait for end of LAN865x reset */ + for (i = 0; !ctx->reset && i < LAN865X_RESET_TIMEOUT; i++) { + k_msleep(1); + } + + if (i == LAN865X_RESET_TIMEOUT) { + LOG_ERR("LAN865x reset timeout reached!"); + return -ENODEV; + } + + return 0; +} + +static int lan865x_gpio_reset(const struct device *dev) +{ + const struct lan865x_config *cfg = dev->config; + + /* Perform (GPIO based) HW reset */ + /* assert RESET_N low for 10 µs (5 µs min) */ + gpio_pin_set_dt(&cfg->reset, 1); + k_busy_wait(10U); + /* deassert - end of reset indicated by IRQ_N low */ + gpio_pin_set_dt(&cfg->reset, 0); + + return lan865x_wait_for_reset(dev); +} + +static int lan865x_check_spi(const struct device *dev) +{ + struct lan865x_data *ctx = dev->data; + uint32_t val; + int ret; + + ret = oa_tc6_reg_read(ctx->tc6, LAN865x_DEVID, &val); + if (ret < 0) { + return -ENODEV; + } + + ctx->silicon_rev = val & LAN865X_REV_MASK; + if (ctx->silicon_rev != 1 && ctx->silicon_rev != 2) { + return -ENODEV; + } + + ctx->chip_id = (val >> 4) & 0xFFFF; + if (ctx->chip_id != LAN8650_DEVID && ctx->chip_id != LAN8651_DEVID) { + return -ENODEV; + } + + return ret; +} + +/* Implementation of pseudo code from AN1760 */ +static uint8_t lan865x_read_indirect_reg(const struct device *dev, uint8_t addr, + uint8_t mask) +{ + struct lan865x_data *ctx = dev->data; + uint32_t val; + + oa_tc6_reg_write(ctx->tc6, 0x000400D8, addr); + oa_tc6_reg_write(ctx->tc6, 0x000400DA, 0x02); + + oa_tc6_reg_read(ctx->tc6, 0x000400D9, &val); + + return (uint8_t) val & mask; +} + +static int lan865x_init_chip(const struct device *dev, uint8_t silicon_rev) +{ + struct lan865x_data *ctx = dev->data; + uint8_t value1, value2; + int8_t offset1 = 0, offset2 = 0, ret; + uint16_t value3, value4, value5, value6, value7; + uint16_t cfgparam1, cfgparam2, cfgparam3, cfgparam4, cfgparam5; + uint32_t val; + + ret = lan865x_read_indirect_reg(dev, 0x05, 0x40); + if (ret == 0) { + LOG_ERR("LAN865x error! Please contact microchip support for replacement."); + return -EIO; + } + + value1 = lan865x_read_indirect_reg(dev, 0x04, 0x1F); + if ((value1 & 0x10) != 0) { /* Convert uint8_t to int8_t */ + offset1 = value1 | 0xE0; + if (offset1 < -5) { + LOG_ERR("LAN865x internal error!"); + return -EIO; + } + } else { + offset1 = value1; + } + + value2 = lan865x_read_indirect_reg(dev, 0x08, 0x1F); + if ((value2 & 0x10) != 0) { /* Convert uint8_t to int8_t */ + offset2 = value2 | 0xE0; + } else { + offset2 = value2; + } + + oa_tc6_reg_read(ctx->tc6, 0x00040084, &val); + value3 = (uint16_t)val; + + oa_tc6_reg_read(ctx->tc6, 0x0004008A, &val); + value4 = (uint16_t)val; + + oa_tc6_reg_read(ctx->tc6, 0x000400AD, &val); + value5 = (uint16_t)val; + + oa_tc6_reg_read(ctx->tc6, 0x000400AE, &val); + value6 = (uint8_t)val; + + oa_tc6_reg_read(ctx->tc6, 0x000400AF, &val); + value7 = (uint8_t)val; + + cfgparam1 = (value3 & 0xF) | (((9 + offset1) << 10) | ((14 + offset1) << 4)); + cfgparam2 = (value4 & 0x3FF) | ((40 + offset2) << 10); + cfgparam3 = (value5 & 0xC0C0) | (((5 + offset1) << 8) | (9 + offset1)); + cfgparam4 = (value6 & 0xC0C0) | (((9 + offset1) << 8) | (14 + offset1)); + cfgparam5 = (value7 & 0xC0C0) | (((17 + offset1) << 8) | (22 + offset1)); + + oa_tc6_reg_write(ctx->tc6, 0x00040084, (uint32_t) cfgparam1); + oa_tc6_reg_write(ctx->tc6, 0x0004008A, (uint32_t) cfgparam2); + oa_tc6_reg_write(ctx->tc6, 0x000400AD, (uint32_t) cfgparam3); + oa_tc6_reg_write(ctx->tc6, 0x000400AE, (uint32_t) cfgparam4); + oa_tc6_reg_write(ctx->tc6, 0x000400AF, (uint32_t) cfgparam5); + + return 0; +} +/* Implementation of pseudo code from AN1760 - END */ + +static int lan865x_config_plca(const struct device *dev, uint8_t node_id, + uint8_t node_cnt, uint8_t burst_cnt, uint8_t burst_timer) +{ + struct lan865x_data *ctx = dev->data; + uint32_t val; + + /* Collision Detection */ + oa_tc6_reg_write(ctx->tc6, 0x00040087, 0x0083u); /* COL_DET_CTRL0 */ + + /* T1S Phy Node Id and Max Node Count */ + val = ((uint32_t)node_cnt << 8) | node_id; + oa_tc6_reg_write(ctx->tc6, 0x0004CA02, val); /* PLCA_CONTROL_1_REGISTER */ + + /* PLCA Burst Count and Burst Timer */ + val = ((uint32_t)burst_cnt << 8) | burst_timer; + oa_tc6_reg_write(ctx->tc6, 0x0004CA05, val); /* PLCA_BURST_MODE_REGISTER */ + + /* Enable PLCA */ + oa_tc6_reg_write(ctx->tc6, 0x0004CA01, BIT(15)); /* PLCA_CONTROL_0_REGISTER */ + + return 0; +} + +static void lan865x_write_macaddress(const struct device *dev) +{ + struct lan865x_data *ctx = dev->data; + uint8_t *mac = &ctx->mac_address[0]; + uint32_t val; + + /* SPEC_ADD2_BOTTOM */ + val = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]; + oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB2, val); + + /* SPEC_ADD2_TOP */ + val = (mac[5] << 8) | mac[4]; + oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAT2, val); + + /* SPEC_ADD1_BOTTOM */ + val = (mac[5] << 24) | (mac[4] << 16) | (mac[3] << 8) | mac[2]; + oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB1, val); +} + +static int lan865x_default_config(const struct device *dev, uint8_t silicon_rev) +{ + /* Values in the below table are the same for LAN865x rev. B0 and B1 */ + static const oa_mem_map_t lan865x_conf[] = { + { .address = 0x00010000, .value = 0x00000000 }, + { .address = 0x00040091, .value = 0x00009660 }, + { .address = 0x00040081, .value = 0x00000080 }, + { .address = 0x00010077, .value = 0x00000028 }, + { .address = 0x00040043, .value = 0x000000FF }, + { .address = 0x00040044, .value = 0x0000FFFF }, + { .address = 0x00040045, .value = 0x00000000 }, + { .address = 0x00040053, .value = 0x000000FF }, + { .address = 0x00040054, .value = 0x0000FFFF }, + { .address = 0x00040055, .value = 0x00000000 }, + { .address = 0x00040040, .value = 0x00000002 }, + { .address = 0x00040050, .value = 0x00000002 }, + { .address = 0x000400E9, .value = 0x00009E50 }, + { .address = 0x000400F5, .value = 0x00001CF8 }, + { .address = 0x000400F4, .value = 0x0000C020 }, + { .address = 0x000400F8, .value = 0x00009B00 }, + { .address = 0x000400F9, .value = 0x00004E53 }, + { .address = 0x000400B0, .value = 0x00000103 }, + { .address = 0x000400B1, .value = 0x00000910 }, + { .address = 0x000400B2, .value = 0x00001D26 }, + { .address = 0x000400B3, .value = 0x0000002A }, + { .address = 0x000400B4, .value = 0x00000103 }, + { .address = 0x000400B5, .value = 0x0000070D }, + { .address = 0x000400B6, .value = 0x00001720 }, + { .address = 0x000400B7, .value = 0x00000027 }, + { .address = 0x000400B8, .value = 0x00000509 }, + { .address = 0x000400B9, .value = 0x00000E13 }, + { .address = 0x000400BA, .value = 0x00001C25 }, + { .address = 0x000400BB, .value = 0x0000002B }, + { .address = 0x0000000C, .value = 0x00000100 }, + { .address = 0x00040081, .value = 0x000000E0 }, + }; + const struct lan865x_config *cfg = dev->config; + uint8_t i, size = ARRAY_SIZE(lan865x_conf); + struct lan865x_data *ctx = dev->data; + int ret; + + /* Enable protected control RW */ + oa_tc6_set_protected_ctrl(ctx->tc6, true); + + for (i = 0; i < size; i++) { + oa_tc6_reg_write(ctx->tc6, lan865x_conf[i].address, + lan865x_conf[i].value); + } + + if (silicon_rev == 1) { + /* For silicon rev 1 (B0): (bit [3..0] from 0x0A0084 */ + oa_tc6_reg_write(ctx->tc6, 0x000400D0, 0x5F21); + } + + lan865x_write_macaddress(dev); + + ret = lan865x_init_chip(dev, silicon_rev); + if (ret < 0) + return ret; + + if (cfg->plca_enable) { + ret = lan865x_config_plca(dev, cfg->plca_node_id, + cfg->plca_node_count, + cfg->plca_burst_count, + cfg->plca_burst_timer); + if (ret < 0) { + return ret; + } + } + return 0; +} + +static void lan865x_int_callback(const struct device *dev, + struct gpio_callback *cb, + uint32_t pins) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pins); + + struct lan865x_data *ctx = + CONTAINER_OF(cb, struct lan865x_data, gpio_int_callback); + + k_sem_give(&ctx->int_sem); +} + +static void lan865x_read_chunks(const struct device *dev) +{ + const struct lan865x_config *cfg = dev->config; + struct lan865x_data *ctx = dev->data; + struct oa_tc6 *tc6 = ctx->tc6; + struct net_pkt *pkt; + int ret; + + k_sem_take(&ctx->tx_rx_sem, K_FOREVER); + pkt = net_pkt_rx_alloc(K_MSEC(cfg->timeout)); + if (!pkt) { + LOG_ERR("OA RX: Could not allocate packet!"); + k_sem_give(&ctx->tx_rx_sem); + return; + } + + ret = oa_tc6_read_chunks(tc6, pkt); + k_sem_give(&ctx->tx_rx_sem); + if (ret < 0) { + eth_stats_update_errors_rx(ctx->iface); + net_pkt_unref(pkt); + return; + } + + /* Feed buffer frame to IP stack */ + ret = net_recv_data(ctx->iface, pkt); + if (ret < 0) { + LOG_ERR("OA RX: Could not process packet (%d)!", ret); + net_pkt_unref(pkt); + } +} + +static void lan865x_int_thread(const struct device *dev) +{ + struct lan865x_data *ctx = dev->data; + struct oa_tc6 *tc6 = ctx->tc6; + uint32_t sts, val, ftr; + + while (true) { + k_sem_take(&ctx->int_sem, K_FOREVER); + if (!ctx->reset) { + oa_tc6_reg_read(tc6, OA_STATUS0, &sts); + if (sts & OA_STATUS0_RESETC) { + oa_tc6_reg_write(tc6, OA_STATUS0, sts); + lan865x_default_config(dev, ctx->silicon_rev); + oa_tc6_reg_read(tc6, OA_CONFIG0, &val); + oa_tc6_reg_write(tc6, OA_CONFIG0, OA_CONFIG0_SYNC | val); + lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON); + + ctx->reset = true; + /* + * According to OA T1S standard - it is mandatory to + * read chunk of data to get the IRQ_N negated (deasserted). + */ + oa_tc6_read_status(tc6, &ftr); + continue; + } + } + + /* + * The IRQ_N is asserted when RCA becomes > 0, so update its value + * before reading chunks. + */ + oa_tc6_update_buf_info(tc6); + + while (tc6->rca > 0) { + lan865x_read_chunks(dev); + } + + if (tc6->exst) { + /* + * Just clear any pending interrupts - data RX will be served + * earlier. + * The RESETC is handled separately as it requires LAN865x device + * configuration. + */ + oa_tc6_reg_read(tc6, OA_STATUS0, &sts); + if (sts != 0) { + oa_tc6_reg_write(tc6, OA_STATUS0, sts); + } + + oa_tc6_reg_read(tc6, OA_STATUS1, &sts); + if (sts != 0) { + oa_tc6_reg_write(tc6, OA_STATUS1, sts); + } + } + } +} + +static int lan865x_init(const struct device *dev) +{ + const struct lan865x_config *cfg = dev->config; + struct lan865x_data *ctx = dev->data; + int ret; + + __ASSERT(cfg->spi.config.frequency <= LAN865X_SPI_MAX_FREQUENCY, + "SPI frequency exceeds supported maximum\n"); + + if (!spi_is_ready_dt(&cfg->spi)) { + LOG_ERR("SPI bus %s not ready", cfg->spi.bus->name); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&cfg->interrupt)) { + LOG_ERR("Interrupt GPIO device %s is not ready", + cfg->interrupt.port->name); + return -ENODEV; + } + + /* Check SPI communication after reset */ + ret = lan865x_check_spi(dev); + if (ret < 0) { + LOG_ERR("SPI communication not working, %d", ret); + return ret; + } + + /* + * Configure interrupt service routine for LAN865x IRQ + */ + ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure interrupt GPIO, %d", ret); + return ret; + } + + gpio_init_callback(&(ctx->gpio_int_callback), lan865x_int_callback, + BIT(cfg->interrupt.pin)); + + ret = gpio_add_callback(cfg->interrupt.port, &ctx->gpio_int_callback); + if (ret < 0) { + LOG_ERR("Failed to add INT callback, %d", ret); + return ret; + } + + gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_EDGE_TO_ACTIVE); + + /* Start interruption-poll thread */ + ctx->tid_int = + k_thread_create(&ctx->thread, ctx->thread_stack, + CONFIG_ETH_LAN865X_IRQ_THREAD_STACK_SIZE, + (k_thread_entry_t)lan865x_int_thread, + (void *)dev, NULL, NULL, + K_PRIO_COOP(CONFIG_ETH_LAN865X_IRQ_THREAD_PRIO), + 0, K_NO_WAIT); + k_thread_name_set(ctx->tid_int, "lan865x_interrupt"); + + ctx->reset = false; + + /* Perform HW reset - 'rst-gpios' required property set in DT */ + if (!gpio_is_ready_dt(&cfg->reset)) { + LOG_ERR("Reset GPIO device %s is not ready", + cfg->reset.port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&cfg->reset, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Failed to configure reset GPIO, %d", ret); + return ret; + } + + return lan865x_gpio_reset(dev); +} + +static int lan865x_port_send(const struct device *dev, struct net_pkt *pkt) +{ + struct lan865x_data *ctx = dev->data; + struct oa_tc6 *tc6 = ctx->tc6; + int ret; + + k_sem_take(&ctx->tx_rx_sem, K_FOREVER); + ret = oa_tc6_send_chunks(tc6, pkt); + k_sem_give(&ctx->tx_rx_sem); + if (ret < 0) { + LOG_ERR("TX transmission error, %d", ret); + eth_stats_update_errors_tx(net_pkt_iface(pkt)); + return ret; + } + + return 0; +} + +static const struct ethernet_api lan865x_api_func = { + .iface_api.init = lan865x_iface_init, + .get_capabilities = lan865x_port_get_capabilities, + .set_config = lan865x_set_config, + .send = lan865x_port_send, +}; + +#define LAN865X_DEFINE(inst) \ + static const struct lan865x_config lan865x_config_##inst = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0), \ + .interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \ + .reset = GPIO_DT_SPEC_INST_GET(inst, rst_gpios), \ + .timeout = CONFIG_ETH_LAN865X_TIMEOUT, \ + .plca_node_id = DT_INST_PROP(inst, plca_node_id), \ + .plca_node_count = DT_INST_PROP(inst, plca_node_count), \ + .plca_burst_count = DT_INST_PROP(inst, plca_burst_count), \ + .plca_burst_timer = DT_INST_PROP(inst, plca_burst_timer), \ + .plca_to_timer = DT_INST_PROP(inst, plca_to_timer), \ + .plca_enable = DT_INST_PROP(inst, plca_enable), \ + }; \ + \ + struct oa_tc6 oa_tc6_##inst = { \ + .cps = 64, \ + .protected = 0, \ + .spi = &lan865x_config_##inst.spi \ + }; \ + static struct lan865x_data lan865x_data_##inst = { \ + .mac_address = DT_INST_PROP(inst, local_mac_address), \ + .tx_rx_sem = \ + Z_SEM_INITIALIZER((lan865x_data_##inst).tx_rx_sem, 1, UINT_MAX), \ + .int_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).int_sem, 0, UINT_MAX), \ + .tc6 = &oa_tc6_##inst \ + }; \ + \ + ETH_NET_DEVICE_DT_INST_DEFINE(inst, lan865x_init, NULL, &lan865x_data_##inst, \ + &lan865x_config_##inst, CONFIG_ETH_INIT_PRIORITY, \ + &lan865x_api_func, NET_ETH_MTU); + +DT_INST_FOREACH_STATUS_OKAY(LAN865X_DEFINE); diff --git a/drivers/ethernet/eth_lan865x_priv.h b/drivers/ethernet/eth_lan865x_priv.h new file mode 100644 index 000000000000000..fa4af1a949a4eed --- /dev/null +++ b/drivers/ethernet/eth_lan865x_priv.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 DENX Software Engineering GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ETH_LAN865X_PRIV_H__ +#define ETH_LAN865X_PRIV_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "oa_tc6.h" + +#define LAN865X_SPI_MAX_FREQUENCY 25000000U +#define LAN865X_HW_BOOT_DELAY_MS 7 +#define LAN8650_DEVID 0x8650 +#define LAN8651_DEVID 0x8651 +#define LAN865X_REV_MASK GENMASK(3, 0) +#define LAN865X_RESET_TIMEOUT 10 + +/* Memory Map Sector (MMS) 1 (0x1) */ +#define LAN865x_MAC_NCR MMS_REG(0x1, 0x000) +#define LAN865x_MAC_NCR_TXEN BIT(3) +#define LAN865x_MAC_NCR_RXEN BIT(2) +#define LAN865x_MAC_NCFGR MMS_REG(0x1, 0x001) +#define LAN865x_MAC_NCFGR_CAF BIT(4) +#define LAN865x_MAC_SAB1 MMS_REG(0x1, 0x022) +#define LAN865x_MAC_SAB2 MMS_REG(0x1, 0x024) +#define LAN865x_MAC_SAT2 MMS_REG(0x1, 0x025) + +#define LAN865x_MAC_TXRX_ON 1 +#define LAN865x_MAC_TXRX_OFF 0 + +/* Memory Map Sector (MMS) 10 (0xA) */ +#define LAN865x_DEVID MMS_REG(0xA, 0x094) + +struct lan865x_config { + struct spi_dt_spec spi; + struct gpio_dt_spec interrupt; + struct gpio_dt_spec reset; + int32_t timeout; + + /* PLCA */ + bool plca_enable : 1; /* 1 - PLCA enable, 0 - CSMA/CD enable */ + uint8_t plca_node_id /* PLCA node id range: 0 to 254 */; + uint8_t plca_node_count; /* PLCA node count range: 1 to 255 */ + uint8_t plca_burst_count; /* PLCA burst count range: 0x0 to 0xFF */ + uint8_t plca_burst_timer; /* PLCA burst timer */ + uint8_t plca_to_timer; /* PLCA TO value */ + + /* MAC */ + bool tx_cut_through_mode; /* 1 - tx cut through, 0 - Store and forward */ + bool rx_cut_through_mode; /* 1 - rx cut through, 0 - Store and forward */ +}; + +struct lan865x_data { + struct net_if *iface; + struct gpio_callback gpio_int_callback; + struct k_sem tx_rx_sem; + struct k_sem int_sem; + struct oa_tc6 *tc6; + uint16_t chip_id; + uint8_t silicon_rev; + uint8_t mac_address[6]; + bool iface_initialized; + bool reset; + + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ETH_LAN865X_IRQ_THREAD_STACK_SIZE); + struct k_thread thread; + k_tid_t tid_int; +}; + +#endif /* ETH_LAN865X_PRIV_H__ */ diff --git a/dts/bindings/ethernet/microchip,lan865x.yaml b/dts/bindings/ethernet/microchip,lan865x.yaml new file mode 100644 index 000000000000000..699bfca7dc600bb --- /dev/null +++ b/dts/bindings/ethernet/microchip,lan865x.yaml @@ -0,0 +1,46 @@ +# Copyright (c) 2023 DENX Software Engineering GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + LAN865x standalone 10BASE-T1L Ethernet controller with SPI interface. + +compatible: "microchip,lan865x" + +include: [spi-device.yaml, ethernet-controller.yaml] + +properties: + tx-cut-through-mode: + type: boolean + description: Enable TX cut through mode + rx-cut-through-mode: + type: boolean + description: Enable RX cut through mode + plca-enable: + type: boolean + description: Enable or disable PLCA support + plca-node-id: + type: int + description: Specify the PLCA node ID number + plca-node-count: + type: int + description: Specify the PLCA node count + plca-burst-count: + type: int + description: Specify the PLCA burst count + plca-burst-timer: + type: int + description: Specify the PLCA burst timer value + plca-to-timer: + type: int + description: Specify the PLCA to timer value + int-gpios: + type: phandle-array + required: true + description: | + The interrupt pin of LAN865X is active low. + If connected directly the MCU pin should be configured + as active low. + rst-gpios: + type: phandle-array + required: true + description: The reset pin of LAN865X. From 8129307887e6f9385af5ef5dc98ec7e254fe0d59 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Tue, 7 Nov 2023 19:45:01 +0100 Subject: [PATCH 0147/1049] drivers: charger: add charger prefix for bq24190 Many (or almost all) drivers contain the specified prefixes related to the driver subsys so add the missing one for the BQ24190. Signed-off-by: Bartosz Bilas --- drivers/charger/CMakeLists.txt | 2 +- drivers/charger/Kconfig.bq24190 | 2 +- drivers/charger/{bq24190.c => charger_bq24190.c} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename drivers/charger/{bq24190.c => charger_bq24190.c} (100%) diff --git a/drivers/charger/CMakeLists.txt b/drivers/charger/CMakeLists.txt index 84b34009423629b..894561982a37c69 100644 --- a/drivers/charger/CMakeLists.txt +++ b/drivers/charger/CMakeLists.txt @@ -3,7 +3,7 @@ zephyr_library() zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/charger.h) -zephyr_library_sources_ifdef(CONFIG_BQ24190 bq24190.c) +zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ24190 charger_bq24190.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.bq24190 b/drivers/charger/Kconfig.bq24190 index 3327f671c692a0f..be3e29727a21baa 100644 --- a/drivers/charger/Kconfig.bq24190 +++ b/drivers/charger/Kconfig.bq24190 @@ -1,7 +1,7 @@ # Copyright 2023 Cirrus Logic, Inc. # SPDX-License-Identifier: Apache-2.0 -config BQ24190 +config CHARGER_BQ24190 bool "BQ24190 Battery Charger" default y depends on DT_HAS_TI_BQ24190_ENABLED diff --git a/drivers/charger/bq24190.c b/drivers/charger/charger_bq24190.c similarity index 100% rename from drivers/charger/bq24190.c rename to drivers/charger/charger_bq24190.c From 8a77ad406f3eb20ccfc97050e4d07df6a6608b4c Mon Sep 17 00:00:00 2001 From: Emil Lindqvist Date: Thu, 2 Nov 2023 08:25:49 +0100 Subject: [PATCH 0148/1049] lsm6dsl: add pm suspend and resume to lsm6dsl This commit implements the suspend and resume PM API for LSM6DSL accelerometer. Signed-off-by: Emil Lindqvist --- drivers/sensor/lsm6dsl/lsm6dsl.c | 62 ++++++++++++++++++++++++++++++-- drivers/sensor/lsm6dsl/lsm6dsl.h | 1 + 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/lsm6dsl/lsm6dsl.c b/drivers/sensor/lsm6dsl/lsm6dsl.c index b00df0be526d807..0a0f35258045e4b 100644 --- a/drivers/sensor/lsm6dsl/lsm6dsl.c +++ b/drivers/sensor/lsm6dsl/lsm6dsl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "lsm6dsl.h" @@ -26,7 +27,8 @@ LOG_MODULE_REGISTER(LSM6DSL, CONFIG_SENSOR_LOG_LEVEL); static const uint16_t lsm6dsl_odr_map[] = {0, 12, 26, 52, 104, 208, 416, 833, 1666, 3332, 6664, 1}; -#if defined(LSM6DSL_ACCEL_ODR_RUNTIME) || defined(LSM6DSL_GYRO_ODR_RUNTIME) +#if defined(LSM6DSL_ACCEL_ODR_RUNTIME) || defined(LSM6DSL_GYRO_ODR_RUNTIME) ||\ + defined(CONFIG_PM_DEVICE) static int lsm6dsl_freq_to_odr_val(uint16_t freq) { size_t i; @@ -169,6 +171,8 @@ static int lsm6dsl_gyro_set_odr_raw(const struct device *dev, uint8_t odr) return -EIO; } + data->gyro_freq = lsm6dsl_odr_to_freq_val(odr); + return 0; } @@ -826,6 +830,59 @@ static int lsm6dsl_init(const struct device *dev) return 0; } +#ifdef CONFIG_PM_DEVICE +static int lsm6dsl_pm_action(const struct device *dev, + enum pm_device_action action) +{ + struct lsm6dsl_data *data = dev->data; + int ret = -EIO; + uint8_t accel_odr = 0; + uint8_t gyro_odr = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + /* Restore saved ODR values */ + accel_odr = lsm6dsl_freq_to_odr_val(data->accel_freq); + ret = lsm6dsl_accel_set_odr_raw(dev, accel_odr); + if (ret < 0) { + LOG_ERR("Failed to resume accelerometer"); + break; + } + gyro_odr = lsm6dsl_freq_to_odr_val(data->gyro_freq); + ret = lsm6dsl_gyro_set_odr_raw(dev, gyro_odr); + if (ret < 0) { + LOG_ERR("Failed to resume gyro"); + break; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + /* + * Set accelerometer ODR to power-down. Don't use the direct + * function to not overwrite the saved value + */ + ret = data->hw_tf->update_reg(dev, LSM6DSL_REG_CTRL1_XL, + LSM6DSL_MASK_CTRL1_XL_ODR_XL, 0); + if (ret < 0) { + LOG_ERR("Failed to suspend accelerometer"); + break; + } + /* Set gyro ODR to power-down */ + ret = data->hw_tf->update_reg(dev, LSM6DSL_REG_CTRL2_G, + LSM6DSL_MASK_CTRL2_G_ODR_G, 0); + if (ret < 0) { + LOG_ERR("Failed to suspend gyro"); + break; + } + + break; + default: + return -ENOTSUP; + } + + return ret; +} +#endif + #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 #warning "LSM6DSL driver enabled without any devices" @@ -837,9 +894,10 @@ static int lsm6dsl_init(const struct device *dev) */ #define LSM6DSL_DEVICE_INIT(inst) \ + PM_DEVICE_DT_INST_DEFINE(inst, lsm6dsl_pm_action); \ SENSOR_DEVICE_DT_INST_DEFINE(inst, \ lsm6dsl_init, \ - NULL, \ + PM_DEVICE_DT_INST_GET(inst), \ &lsm6dsl_data_##inst, \ &lsm6dsl_config_##inst, \ POST_KERNEL, \ diff --git a/drivers/sensor/lsm6dsl/lsm6dsl.h b/drivers/sensor/lsm6dsl/lsm6dsl.h index f424cbf2326e0d5..da176f4f6923f52 100644 --- a/drivers/sensor/lsm6dsl/lsm6dsl.h +++ b/drivers/sensor/lsm6dsl/lsm6dsl.h @@ -667,6 +667,7 @@ struct lsm6dsl_data { #endif const struct lsm6dsl_transfer_function *hw_tf; uint16_t accel_freq; + uint16_t gyro_freq; #ifdef CONFIG_LSM6DSL_TRIGGER const struct device *dev; From b72e5c1f3d56c31734ccb5e69ee4e3a9ad28ce8a Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 1 Nov 2023 15:59:43 +0000 Subject: [PATCH 0149/1049] MAINTAINERS: more fixes and expansion of coverage More fixes and new areas that were not covered before. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 92 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index ccf6b933bf6fa9e..883f9afed53aa7f 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -184,6 +184,26 @@ ARM64 arch: labels: - "area: ARM64" +ARM Platforms: + status: odd fixes + files: + - boards/arm/mps*/ + - soc/arm/arm/ + - boards/arm/v2m_*/ + labels: + - "platform: ARM" + +ARM SiP SVC: + status: odd fixes + files: + - subsys/sip_svc/ + - tests/subsys/sip_svc/ + - include/zephyr/sip_svc/ + - include/zephyr/drivers/sip_svc/ + - drivers/sip_svc/ + labels: + - "area: ARM SiP SVC" + MIPS arch: status: odd fixes files: @@ -231,6 +251,7 @@ Binary Descriptors: - include/zephyr/bindesc.h - samples/subsys/bindesc/ - scripts/west_commands/bindesc.py + - tests/subsys/bindesc/ labels: - "area: Binary Descriptors" @@ -413,6 +434,20 @@ Board/SoC configuration: labels: - "area: C++" +Cache: + status: maintained + maintainers: + - carlocaione + collaborators: + - nashif + files: + - include/zephyr/drivers/cache.h + - include/zephyr/cache.h + - doc/hardware/cache/index.rst + - drivers/cache/ + labels: + - "area: Cache" + C library: status: maintained maintainers: @@ -433,7 +468,7 @@ CMSIS API layer: collaborators: - nashif files: - - subsys/portability/cmsis_rtos_v*/ + - subsys/portability/ - include/zephyr/portability/cmsis* - samples/subsys/portability/cmsis_rtos_v*/ - tests/subsys/portability/cmsis_rtos_v*/ @@ -523,6 +558,7 @@ Common Architecture Interface: - arch/common/ - include/zephyr/arch/common/ - tests/arch/common/ + - doc/hardware/porting/arch.rst labels: - "area: Architectures" @@ -551,7 +587,6 @@ Debug: labels: - "area: Debugging" - Demand Paging: status: maintained maintainers: @@ -614,6 +649,7 @@ Devicetree Bindings: - galak files: - dts/bindings/ + - include/zephyr/dt-bindings/ labels: - "area: Devicetree Binding" @@ -1226,7 +1262,7 @@ Release Notes: - dts/bindings/modem/ - include/zephyr/drivers/modem/ labels: - - "area: Modem" + - "area: Modem Drivers" "Drivers: Regulators": status: maintained @@ -1255,6 +1291,7 @@ Release Notes: - dts/bindings/retained_mem/ - include/zephyr/drivers/retained_mem.h - tests/drivers/retained_mem/ + - doc/hardware/peripherals/retained_mem.rst labels: - "area: Retained Memory" @@ -1703,6 +1740,8 @@ Kconfig: - scripts/kconfig/ - doc/build/kconfig/ - Kconfig.zephyr + - tests/kconfig/configdefault/ + - tests/misc/kconfigoptions/ labels: - "area: Kconfig" description: >- @@ -1752,6 +1791,9 @@ Base OS: - lib/os/cbprintf* - lib/os/Kconfig.cbprintf - include/zephyr/sys/mem_manage.h + - include/zephyr/sys/mpsc_pbuf.h + - include/zephyr/sys/mpsc_packet.h + - lib/os/mpsc_pbuf.c labels: - "area: Base OS" @@ -1790,11 +1832,17 @@ Logging: - dcpleung files: - include/zephyr/logging/ + - include/zephyr/sys/mpsc_pbuf.h + - include/zephyr/sys/mpsc_packet.h + - lib/os/mpsc_pbuf.c + - doc/kernel/data_structures/mpsc_pbuf.rst + - tests/lib/mpsc_pbuf/ - samples/subsys/logging/ - subsys/logging/ - tests/subsys/logging/ - scripts/logging/ - doc/services/logging/ + - tests/lib/spsc_pbuf/ labels: - "area: Logging" @@ -1883,6 +1931,8 @@ Modem Modules: - tests/subsys/modem/ - doc/services/modem/ - samples/net/cellular_modem/ + labels: + - "area: Modem" OSDP: status: maintained @@ -1927,6 +1977,7 @@ Native POSIX/Sim and POSIX arch: - aescolar files: - arch/posix/ + - boards/posix/common/ - boards/posix/native_*/ - boards/posix/doc/ - boards/posix/*.rst @@ -2149,6 +2200,8 @@ NIOS-2 arch: - nashif files: - arch/nios2/ + - boards/common/nios2.board.cmake + - boards/nios2/ - soc/nios2/ - include/zephyr/arch/nios2/ - tests/boards/altera_max10/ @@ -2265,6 +2318,14 @@ Sensor Subsystem: labels: - "area: Sensor Subsystem" +Stats: + status: odd fixes + files: + - subsys/stats/ + - include/zephyr/stats/stats.h + labels: + - "area: Stats" + Twister: status: maintained maintainers: @@ -2285,6 +2346,7 @@ Twister: - doc/develop/test/twister.rst - scripts/pylib/pytest-twister-harness/ - doc/develop/test/pytest.rst + - tests/test_config.yaml labels: - "area: Twister" @@ -2530,6 +2592,7 @@ Intel Platforms (Xtensa): - tests/boards/intel_adsp/ - samples/boards/intel_adsp/ - dts/bindings/*/intel,adsp* + - scripts/west_commands/runners/intel_adsp.py labels: - "platform: Intel ADSP" @@ -2600,6 +2663,7 @@ NXP Platforms: - dts/arm/nxp/ - dts/bindings/*/nxp* - soc/xtensa/nxp_adsp/ + - boards/xtensa/nxp_adsp_*/ - samples/boards/nxp*/ - include/zephyr/dt-bindings/*/nxp* - include/zephyr/drivers/*/*nxp* @@ -2901,6 +2965,18 @@ Task Watchdog: labels: - "area: Task Watchdog" +"Drivers: Time Aware GPIO": + status: maintained + maintainers: + - akanisetti + files: + - doc/hardware/peripherals/tgpio.rst + - drivers/misc/timeaware_gpio/ + - include/zephyr/drivers/misc/timeaware_gpio/ + - samples/drivers/misc/timeaware_gpio/ + labels: + - "area: Time Aware GPIO" + TF-M Integration: status: maintained maintainers: @@ -2927,6 +3003,7 @@ TF-M Integration: - cmake/linker/ - cmake/toolchain/ - include/zephyr/toolchain/ + - include/zephyr/toolchain.h labels: - "area: Toolchains" @@ -3026,6 +3103,7 @@ Userspace: collaborators: - ceolin files: + - include/zephyr/internal/syscall_handler.h - doc/kernel/usermode/kernelobjects.rst - include/zephyr/app_memory/ - include/zephyr/linker/app_smem*.ld @@ -3076,6 +3154,8 @@ West: maintainers: - najumon1980 - jhedberg + collaborators: + - tbursztyka files: - modules/acpica/ labels: @@ -3096,6 +3176,7 @@ West: - yperess files: - samples/modules/chre/ + - modules/Kconfig.chre labels: - "area: CHRE" @@ -3107,7 +3188,7 @@ West: - microbuilder - povergoing files: - - modules/cmsis/Kconfig + - modules/cmsis/ labels: - "area: ARM" @@ -3169,7 +3250,8 @@ West: collaborators: - tgorochowik - msobkowski - files: [] + files: + - modules/hal_ambiq/ labels: - "platform: Ambiq" From 76a7b3cf1c4bdf90836fa060dea73dec172b4fc4 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 21 Sep 2023 15:48:21 +0800 Subject: [PATCH 0150/1049] drivers: intc: plic: initial refactor for multi-instance support Use a config struct to store per-instance device config during init and connect the IRQ based on the devicetree instead of hardcoded value and instance number. The `get_plic_dev_from_irq` is still a placeholder for now and always return the first instance. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 145 ++++++++++++++++------- 1 file changed, 99 insertions(+), 46 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 42f6cbc1f069b16..e874de51ab62854 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -36,15 +36,6 @@ */ #define PLIC_REG_TRIG_TYPE_OFFSET 0x1080 -#define PLIC_MAX_PRIO DT_INST_PROP(0, riscv_max_priority) -#define PLIC_PRIO (PLIC_BASE_ADDR(0) + PLIC_REG_PRIO_OFFSET) -#define PLIC_IRQ_EN (PLIC_BASE_ADDR(0) + PLIC_REG_IRQ_EN_OFFSET) -#define PLIC_REG (PLIC_BASE_ADDR(0) + PLIC_REG_REGS_OFFSET) - -#define PLIC_IRQS (CONFIG_NUM_IRQS - CONFIG_2ND_LVL_ISR_TBL_OFFSET) -#define PLIC_EN_SIZE ((PLIC_IRQS >> 5) + 1) - -#define PLIC_EDGE_TRIG_TYPE (PLIC_BASE_ADDR(0) + PLIC_REG_TRIG_TYPE_OFFSET) #define PLIC_EDGE_TRIG_SHIFT 5 struct plic_regs_t { @@ -52,7 +43,39 @@ struct plic_regs_t { uint32_t claim_complete; }; -static int save_irq; +typedef void (*riscv_plic_irq_config_func_t)(void); +struct plic_config { + mem_addr_t prio; + mem_addr_t irq_en; + mem_addr_t reg; + mem_addr_t trig; + uint32_t max_prio; + uint32_t num_irqs; + riscv_plic_irq_config_func_t irq_config_func; +}; + +static uint32_t save_irq; + +static inline uint32_t get_plic_enabled_size(const struct device *dev) +{ + const struct plic_config *config = dev->config; + + return (config->num_irqs >> 5) + 1; +} + +/** + * @brief Determine the PLIC device from the IRQ + * + * FIXME: This function is currently hardcoded to return the first instance. + * + * @param irq IRQ number + * + * @return PLIC device of that IRQ + */ +static inline const struct device *get_plic_dev_from_irq(uint32_t irq) +{ + return DEVICE_DT_INST_GET(0); +} /** * @brief return edge irq value or zero @@ -61,16 +84,18 @@ static int save_irq; * value of the irq. In the event edge irq is not supported this * routine will return 0 * - * @param irq IRQ number to add to the trigger + * @param dev PLIC-instance device + * @param local_irq PLIC-instance IRQ number to add to the trigger * * @return irq value when enabled 0 otherwise */ -static int riscv_plic_is_edge_irq(uint32_t irq) +static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq) { - volatile uint32_t *trig = (volatile uint32_t *)PLIC_EDGE_TRIG_TYPE; + const struct plic_config *config = dev->config; + volatile uint32_t *trig = (volatile uint32_t *) config->trig; - trig += (irq >> PLIC_EDGE_TRIG_SHIFT); - return *trig & BIT(irq); + trig += (local_irq >> PLIC_EDGE_TRIG_SHIFT); + return *trig & BIT(local_irq); } /** @@ -85,8 +110,10 @@ static int riscv_plic_is_edge_irq(uint32_t irq) */ void riscv_plic_irq_enable(uint32_t irq) { + const struct device *dev = get_plic_dev_from_irq(irq); + const struct plic_config *config = dev->config; + volatile uint32_t *en = (volatile uint32_t *) config->irq_en; uint32_t key; - volatile uint32_t *en = (volatile uint32_t *)PLIC_IRQ_EN; key = irq_lock(); en += (irq >> 5); @@ -106,8 +133,10 @@ void riscv_plic_irq_enable(uint32_t irq) */ void riscv_plic_irq_disable(uint32_t irq) { + const struct device *dev = get_plic_dev_from_irq(irq); + const struct plic_config *config = dev->config; + volatile uint32_t *en = (volatile uint32_t *) config->irq_en; uint32_t key; - volatile uint32_t *en = (volatile uint32_t *)PLIC_IRQ_EN; key = irq_lock(); en += (irq >> 5); @@ -125,7 +154,9 @@ void riscv_plic_irq_disable(uint32_t irq) */ int riscv_plic_irq_is_enabled(uint32_t irq) { - volatile uint32_t *en = (volatile uint32_t *)PLIC_IRQ_EN; + const struct device *dev = get_plic_dev_from_irq(irq); + const struct plic_config *config = dev->config; + volatile uint32_t *en = (volatile uint32_t *) config->irq_en; en += (irq >> 5); return !!(*en & (1 << (irq & 31))); @@ -143,10 +174,12 @@ int riscv_plic_irq_is_enabled(uint32_t irq) */ void riscv_plic_set_priority(uint32_t irq, uint32_t priority) { - volatile uint32_t *prio = (volatile uint32_t *)PLIC_PRIO; + const struct device *dev = get_plic_dev_from_irq(irq); + const struct plic_config *config = dev->config; + volatile uint32_t *prio = (volatile uint32_t *) config->prio; - if (priority > PLIC_MAX_PRIO) - priority = PLIC_MAX_PRIO; + if (priority > config->max_prio) + priority = config->max_prio; prio += irq; *prio = priority; @@ -165,11 +198,10 @@ int riscv_plic_get_irq(void) return save_irq; } -static void plic_irq_handler(const void *arg) +static void plic_irq_handler(const struct device *dev) { - volatile struct plic_regs_t *regs = - (volatile struct plic_regs_t *) PLIC_REG; - + const struct plic_config *config = dev->config; + volatile struct plic_regs_t *regs = (volatile struct plic_regs_t *) config->reg; uint32_t irq; struct _isr_table_entry *ite; int edge_irq; @@ -189,10 +221,10 @@ static void plic_irq_handler(const void *arg) * If the IRQ is out of range, call z_irq_spurious. * A call to z_irq_spurious will not return. */ - if (irq == 0U || irq >= PLIC_IRQS) + if (irq == 0U || irq >= config->num_irqs) z_irq_spurious(NULL); - edge_irq = riscv_plic_is_edge_irq(irq); + edge_irq = riscv_plic_is_edge_irq(dev, irq); /* * For edge triggered interrupts, write to the claim_complete register @@ -220,25 +252,25 @@ static void plic_irq_handler(const void *arg) /** * @brief Initialize the Platform Level Interrupt Controller * + * @param dev PLIC device struct + * * @retval 0 on success. */ static int plic_init(const struct device *dev) { - - volatile uint32_t *en = (volatile uint32_t *)PLIC_IRQ_EN; - volatile uint32_t *prio = (volatile uint32_t *)PLIC_PRIO; - volatile struct plic_regs_t *regs = - (volatile struct plic_regs_t *)PLIC_REG; - int i; + const struct plic_config *config = dev->config; + volatile uint32_t *en = (volatile uint32_t *) config->irq_en; + volatile uint32_t *prio = (volatile uint32_t *) config->prio; + volatile struct plic_regs_t *regs = (volatile struct plic_regs_t *) config->reg; /* Ensure that all interrupts are disabled initially */ - for (i = 0; i < PLIC_EN_SIZE; i++) { + for (uint32_t i = 0; i < get_plic_enabled_size(dev); i++) { *en = 0U; en++; } /* Set priority of each interrupt line to 0 initially */ - for (i = 0; i < PLIC_IRQS; i++) { + for (uint32_t i = 0; i < config->num_irqs; i++) { *prio = 0U; prio++; } @@ -246,18 +278,39 @@ static int plic_init(const struct device *dev) /* Set threshold priority to 0 */ regs->threshold_prio = 0U; - /* Setup IRQ handler for PLIC driver */ - IRQ_CONNECT(RISCV_MACHINE_EXT_IRQ, - 0, - plic_irq_handler, - NULL, - 0); - - /* Enable IRQ for PLIC driver */ - irq_enable(RISCV_MACHINE_EXT_IRQ); + /* Configure IRQ for PLIC driver */ + config->irq_config_func(); return 0; } -DEVICE_DT_INST_DEFINE(0, plic_init, NULL, NULL, NULL, - PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL); +#define PLIC_INTC_IRQ_FUNC_DECLARE(n) static void plic_irq_config_func_##n(void) + +#define PLIC_INTC_IRQ_FUNC_DEFINE(n) \ + static void plic_irq_config_func_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), 0, plic_irq_handler, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } + +#define PLIC_INTC_CONFIG_INIT(n) \ + PLIC_INTC_IRQ_FUNC_DECLARE(n); \ + static const struct plic_config plic_config_##n = { \ + .prio = PLIC_BASE_ADDR(n) + PLIC_REG_PRIO_OFFSET, \ + .irq_en = PLIC_BASE_ADDR(n) + PLIC_REG_IRQ_EN_OFFSET, \ + .reg = PLIC_BASE_ADDR(n) + PLIC_REG_REGS_OFFSET, \ + .trig = PLIC_BASE_ADDR(n) + PLIC_REG_TRIG_TYPE_OFFSET, \ + .max_prio = DT_INST_PROP(n, riscv_max_priority), \ + .num_irqs = DT_INST_PROP(n, riscv_ndev), \ + .irq_config_func = plic_irq_config_func_##n, \ + }; \ + PLIC_INTC_IRQ_FUNC_DEFINE(n) + +#define PLIC_INTC_DEVICE_INIT(n) \ + PLIC_INTC_CONFIG_INIT(n) \ + DEVICE_DT_INST_DEFINE(n, &plic_init, NULL, \ + NULL, &plic_config_##n, \ + PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(PLIC_INTC_DEVICE_INIT) From e538b0e5a67e1ecc3073f892d8ff5e0d608793bd Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 20 Sep 2023 18:01:35 +0800 Subject: [PATCH 0151/1049] drivers: plic: support multiple instances for multi-level Most of the public APIs in `riscv_plic.h` (except `riscv_plic_get_irq` & `riscv_plic_get_dev`) expect the `irq` argument to be in Zephyr-encoded format, instead of the previously `irq_from_level_2`-stripped version. The first level IRQ is needed by `intc_plic` to differentiate between the parent interrupt controllers, so that correct ISR offset can be obtained using the LUT in `sw_isr_common`. Signed-off-by: Yong Cong Sin --- arch/riscv/core/irq_manage.c | 8 +-- drivers/interrupt_controller/CMakeLists.txt | 2 + drivers/interrupt_controller/intc_plic.c | 60 ++++++++++++------- .../drivers/interrupt_controller/riscv_plic.h | 19 ++++-- .../riscv-privileged/common/soc_common_irq.c | 4 -- 5 files changed, 60 insertions(+), 33 deletions(-) diff --git a/arch/riscv/core/irq_manage.c b/arch/riscv/core/irq_manage.c index f0a0eae2cd09db5..e0ef1374bf1565e 100644 --- a/arch/riscv/core/irq_manage.c +++ b/arch/riscv/core/irq_manage.c @@ -25,8 +25,10 @@ FUNC_NORETURN void z_irq_spurious(const void *unused) LOG_ERR("Spurious interrupt detected! IRQ: %ld", mcause); #if defined(CONFIG_RISCV_HAS_PLIC) if (mcause == RISCV_MACHINE_EXT_IRQ) { - LOG_ERR("PLIC interrupt line causing the IRQ: %d", - riscv_plic_get_irq()); + unsigned int save_irq = riscv_plic_get_irq(); + const struct device *save_dev = riscv_plic_get_dev(); + + LOG_ERR("PLIC interrupt line causing the IRQ: %d (%p)", save_irq, save_dev); } #endif z_riscv_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); @@ -43,8 +45,6 @@ int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, #if defined(CONFIG_RISCV_HAS_PLIC) if (irq_get_level(irq) == 2) { - irq = irq_from_level_2(irq); - riscv_plic_set_priority(irq, priority); } #else diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 71e3435e49a0091..5598d038940a802 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -41,3 +41,5 @@ zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_ra_icu.c) if(CONFIG_INTEL_VTD_ICTL) zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include) endif() + +zephyr_library_include_directories(${ZEPHYR_BASE}/arch/common/include) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index e874de51ab62854..7bfe6c288eaeb3e 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -12,6 +12,8 @@ * for RISC-V processors */ +#include "sw_isr_common.h" + #include #include #include @@ -55,6 +57,7 @@ struct plic_config { }; static uint32_t save_irq; +static const struct device *save_dev; static inline uint32_t get_plic_enabled_size(const struct device *dev) { @@ -66,15 +69,16 @@ static inline uint32_t get_plic_enabled_size(const struct device *dev) /** * @brief Determine the PLIC device from the IRQ * - * FIXME: This function is currently hardcoded to return the first instance. - * * @param irq IRQ number * * @return PLIC device of that IRQ */ static inline const struct device *get_plic_dev_from_irq(uint32_t irq) { - return DEVICE_DT_INST_GET(0); + const struct device *dev = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), + (z_get_sw_isr_device_from_irq(irq)), (NULL)); + + return dev == NULL ? DEVICE_DT_INST_GET(0) : dev; } /** @@ -113,11 +117,12 @@ void riscv_plic_irq_enable(uint32_t irq) const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; volatile uint32_t *en = (volatile uint32_t *) config->irq_en; + const uint32_t local_irq = irq_from_level_2(irq); uint32_t key; key = irq_lock(); - en += (irq >> 5); - *en |= (1 << (irq & 31)); + en += (local_irq >> 5); + *en |= (1 << (local_irq & 31)); irq_unlock(key); } @@ -136,11 +141,12 @@ void riscv_plic_irq_disable(uint32_t irq) const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; volatile uint32_t *en = (volatile uint32_t *) config->irq_en; + const uint32_t local_irq = irq_from_level_2(irq); uint32_t key; key = irq_lock(); - en += (irq >> 5); - *en &= ~(1 << (irq & 31)); + en += (local_irq >> 5); + *en &= ~(1 << (local_irq & 31)); irq_unlock(key); } @@ -157,9 +163,10 @@ int riscv_plic_irq_is_enabled(uint32_t irq) const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; volatile uint32_t *en = (volatile uint32_t *) config->irq_en; + const uint32_t local_irq = irq_from_level_2(irq); - en += (irq >> 5); - return !!(*en & (1 << (irq & 31))); + en += (local_irq >> 5); + return !!(*en & (1 << (local_irq & 31))); } /** @@ -177,11 +184,12 @@ void riscv_plic_set_priority(uint32_t irq, uint32_t priority) const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; volatile uint32_t *prio = (volatile uint32_t *) config->prio; + const uint32_t local_irq = irq_from_level_2(irq); if (priority > config->max_prio) priority = config->max_prio; - prio += irq; + prio += local_irq; *prio = priority; } @@ -191,23 +199,29 @@ void riscv_plic_set_priority(uint32_t irq, uint32_t priority) * This routine returns the RISCV PLIC-specific interrupt line causing an * interrupt. * + * @param dev Optional device pointer to get the interrupt line's controller + * * @return PLIC-specific interrupt line causing an interrupt. */ -int riscv_plic_get_irq(void) +unsigned int riscv_plic_get_irq(void) { return save_irq; } +const struct device *riscv_plic_get_dev(void) +{ + return save_dev; +} + static void plic_irq_handler(const struct device *dev) { const struct plic_config *config = dev->config; volatile struct plic_regs_t *regs = (volatile struct plic_regs_t *) config->reg; - uint32_t irq; struct _isr_table_entry *ite; int edge_irq; /* Get the IRQ number generating the interrupt */ - irq = regs->claim_complete; + const uint32_t local_irq = regs->claim_complete; /* * Save IRQ in save_irq. To be used, if need be, by @@ -215,16 +229,17 @@ static void plic_irq_handler(const struct device *dev) * as IRQ number held by the claim_complete register is * cleared upon read. */ - save_irq = irq; + save_irq = local_irq; + save_dev = dev; /* * If the IRQ is out of range, call z_irq_spurious. * A call to z_irq_spurious will not return. */ - if (irq == 0U || irq >= config->num_irqs) + if (local_irq == 0U || local_irq >= config->num_irqs) z_irq_spurious(NULL); - edge_irq = riscv_plic_is_edge_irq(dev, irq); + edge_irq = riscv_plic_is_edge_irq(dev, local_irq); /* * For edge triggered interrupts, write to the claim_complete register @@ -232,12 +247,17 @@ static void plic_irq_handler(const struct device *dev) * for edge triggered interrupts. */ if (edge_irq) - regs->claim_complete = save_irq; + regs->claim_complete = local_irq; - irq += CONFIG_2ND_LVL_ISR_TBL_OFFSET; + const uint32_t parent_irq = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), + (z_get_sw_isr_irq_from_device(dev)), (0U)); + const uint32_t irq = irq_to_level_2(local_irq) | parent_irq; + const unsigned int isr_offset = + COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), (z_get_sw_isr_table_idx(irq)), + (irq_from_level_2(irq) + CONFIG_2ND_LVL_ISR_TBL_OFFSET)); /* Call the corresponding IRQ handler in _sw_isr_table */ - ite = (struct _isr_table_entry *)&_sw_isr_table[irq]; + ite = (struct _isr_table_entry *)&_sw_isr_table[isr_offset]; ite->isr(ite->arg); /* @@ -246,7 +266,7 @@ static void plic_irq_handler(const struct device *dev) * for level triggered interrupts. */ if (!edge_irq) - regs->claim_complete = save_irq; + regs->claim_complete = local_irq; } /** diff --git a/include/zephyr/drivers/interrupt_controller/riscv_plic.h b/include/zephyr/drivers/interrupt_controller/riscv_plic.h index 1cec5cc810997cd..22c57a4b69673aa 100644 --- a/include/zephyr/drivers/interrupt_controller/riscv_plic.h +++ b/include/zephyr/drivers/interrupt_controller/riscv_plic.h @@ -12,24 +12,26 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_RISCV_PLIC_H_ #define ZEPHYR_INCLUDE_DRIVERS_RISCV_PLIC_H_ +#include + /** * @brief Enable interrupt * - * @param irq interrupt ID + * @param irq Multi-level encoded interrupt ID */ void riscv_plic_irq_enable(uint32_t irq); /** * @brief Disable interrupt * - * @param irq interrupt ID + * @param irq Multi-level encoded interrupt ID */ void riscv_plic_irq_disable(uint32_t irq); /** * @brief Check if an interrupt is enabled * - * @param irq interrupt ID + * @param irq Multi-level encoded interrupt ID * @return Returns true if interrupt is enabled, false otherwise */ int riscv_plic_irq_is_enabled(uint32_t irq); @@ -37,7 +39,7 @@ int riscv_plic_irq_is_enabled(uint32_t irq); /** * @brief Set interrupt priority * - * @param irq interrupt ID + * @param irq Multi-level encoded interrupt ID * @param prio interrupt priority */ void riscv_plic_set_priority(uint32_t irq, uint32_t prio); @@ -47,6 +49,13 @@ void riscv_plic_set_priority(uint32_t irq, uint32_t prio); * * @return Returns the ID of an active interrupt */ -int riscv_plic_get_irq(void); +unsigned int riscv_plic_get_irq(void); + +/** + * @brief Get active interrupt controller device + * + * @return Returns device pointer of the active interrupt device + */ +const struct device *riscv_plic_get_dev(void); #endif /* ZEPHYR_INCLUDE_DRIVERS_RISCV_PLIC_H_ */ diff --git a/soc/riscv/riscv-privileged/common/soc_common_irq.c b/soc/riscv/riscv-privileged/common/soc_common_irq.c index f33e4dceeefc3d1..24aee37bdafacec 100644 --- a/soc/riscv/riscv-privileged/common/soc_common_irq.c +++ b/soc/riscv/riscv-privileged/common/soc_common_irq.c @@ -47,7 +47,6 @@ void arch_irq_enable(unsigned int irq) unsigned int level = irq_get_level(irq); if (level == 2) { - irq = irq_from_level_2(irq); riscv_plic_irq_enable(irq); return; } @@ -68,7 +67,6 @@ void arch_irq_disable(unsigned int irq) unsigned int level = irq_get_level(irq); if (level == 2) { - irq = irq_from_level_2(irq); riscv_plic_irq_disable(irq); return; } @@ -89,7 +87,6 @@ int arch_irq_is_enabled(unsigned int irq) unsigned int level = irq_get_level(irq); if (level == 2) { - irq = irq_from_level_2(irq); return riscv_plic_irq_is_enabled(irq); } #endif @@ -105,7 +102,6 @@ void z_riscv_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flag unsigned int level = irq_get_level(irq); if (level == 2) { - irq = irq_from_level_2(irq); riscv_plic_set_priority(irq, prio); } } From efd1073ceb798d5c246a36c990090e6af738b65f Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 21 Sep 2023 16:45:10 +0800 Subject: [PATCH 0152/1049] tests: build_all: plic: multi instance Add PLIC multi-instance build-only test. Signed-off-by: Yong Cong Sin --- .../interrupt_controller/intc_plic/Kconfig | 7 ++++ .../intc_plic/app.multi_instance.overlay | 38 +++++++++++++++++++ .../intc_plic/testcase.yaml | 10 +++++ 3 files changed, 55 insertions(+) create mode 100644 tests/drivers/build_all/interrupt_controller/intc_plic/Kconfig create mode 100644 tests/drivers/build_all/interrupt_controller/intc_plic/app.multi_instance.overlay diff --git a/tests/drivers/build_all/interrupt_controller/intc_plic/Kconfig b/tests/drivers/build_all/interrupt_controller/intc_plic/Kconfig new file mode 100644 index 000000000000000..6d7b572d8773c18 --- /dev/null +++ b/tests/drivers/build_all/interrupt_controller/intc_plic/Kconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +config NUM_IRQS + int "" + +source "Kconfig" diff --git a/tests/drivers/build_all/interrupt_controller/intc_plic/app.multi_instance.overlay b/tests/drivers/build_all/interrupt_controller/intc_plic/app.multi_instance.overlay new file mode 100644 index 000000000000000..93d8c626aa7ed32 --- /dev/null +++ b/tests/drivers/build_all/interrupt_controller/intc_plic/app.multi_instance.overlay @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + + /{ + soc { + plic1: interrupt-controller@8000000 { + riscv,max-priority = <7>; + riscv,ndev = <0x35>; + reg = <0x08000000 0x04000000>; + interrupts-extended = < + &hlic0 0x03 + &hlic1 0x03 + &hlic2 0x03 + &hlic3 0x03 + &hlic4 0x03 + &hlic5 0x03 + &hlic6 0x03 + &hlic7 0x03 + >; + interrupt-controller; + compatible = "sifive,plic-1.0.0"; + #address-cells = <0x00>; + #interrupt-cells = <0x02>; + }; + }; + + uart1: uart@10000100 { + interrupts = <0x0a 1>; + interrupt-parent = <&plic1>; + clock-frequency = <0x384000>; + reg = <0x10000100 0x100>; + compatible = "ns16550"; + reg-shift = <0>; + }; +}; diff --git a/tests/drivers/build_all/interrupt_controller/intc_plic/testcase.yaml b/tests/drivers/build_all/interrupt_controller/intc_plic/testcase.yaml index 6d6164a3beda3d9..ea80ccf8d2627e5 100644 --- a/tests/drivers/build_all/interrupt_controller/intc_plic/testcase.yaml +++ b/tests/drivers/build_all/interrupt_controller/intc_plic/testcase.yaml @@ -10,3 +10,13 @@ common: - plic tests: drivers.interrupt_controller.intc_plic.build: {} + drivers.interrupt_controller.intc_plic.multi_instance.build: + extra_args: + DTC_OVERLAY_FILE="./app.multi_instance.overlay" + extra_configs: + - CONFIG_NUM_IRQS=116 + - CONFIG_MULTI_LEVEL_INTERRUPTS=y + - CONFIG_DYNAMIC_INTERRUPTS=y + - CONFIG_NUM_2ND_LEVEL_AGGREGATORS=2 + - CONFIG_2ND_LVL_INTR_01_OFFSET=3 + - CONFIG_UART_INTERRUPT_DRIVEN=y From 980fb4b84674af35c2870523a4ecf9a30cfd64fe Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 25 Sep 2023 15:44:39 +0800 Subject: [PATCH 0153/1049] drivers: intc: plic: make sense of magic number Added some defines and helper functions to help with the arithmetics so that the bit shifts and stuff do not look like magic number. Converted manual bit shift/set/unset to use macros provided by Zephyr. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 25 +++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 7bfe6c288eaeb3e..7ced9580123c43f 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -38,7 +38,9 @@ */ #define PLIC_REG_TRIG_TYPE_OFFSET 0x1080 -#define PLIC_EDGE_TRIG_SHIFT 5 +/* PLIC registers are 32-bit memory-mapped */ +#define PLIC_REG_SIZE 32 +#define PLIC_REG_MASK BIT_MASK(LOG2(PLIC_REG_SIZE)) struct plic_regs_t { uint32_t threshold_prio; @@ -59,11 +61,16 @@ struct plic_config { static uint32_t save_irq; static const struct device *save_dev; +static inline uint32_t local_irq_to_reg_offset(uint32_t local_irq) +{ + return local_irq >> LOG2(PLIC_REG_SIZE); +} + static inline uint32_t get_plic_enabled_size(const struct device *dev) { const struct plic_config *config = dev->config; - return (config->num_irqs >> 5) + 1; + return local_irq_to_reg_offset(config->num_irqs) + 1; } /** @@ -98,7 +105,7 @@ static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq) const struct plic_config *config = dev->config; volatile uint32_t *trig = (volatile uint32_t *) config->trig; - trig += (local_irq >> PLIC_EDGE_TRIG_SHIFT); + trig += local_irq_to_reg_offset(local_irq); return *trig & BIT(local_irq); } @@ -121,8 +128,8 @@ void riscv_plic_irq_enable(uint32_t irq) uint32_t key; key = irq_lock(); - en += (local_irq >> 5); - *en |= (1 << (local_irq & 31)); + en += local_irq_to_reg_offset(local_irq); + WRITE_BIT(*en, local_irq & PLIC_REG_MASK, true); irq_unlock(key); } @@ -145,8 +152,8 @@ void riscv_plic_irq_disable(uint32_t irq) uint32_t key; key = irq_lock(); - en += (local_irq >> 5); - *en &= ~(1 << (local_irq & 31)); + en += local_irq_to_reg_offset(local_irq); + WRITE_BIT(*en, local_irq & PLIC_REG_MASK, false); irq_unlock(key); } @@ -165,8 +172,8 @@ int riscv_plic_irq_is_enabled(uint32_t irq) volatile uint32_t *en = (volatile uint32_t *) config->irq_en; const uint32_t local_irq = irq_from_level_2(irq); - en += (local_irq >> 5); - return !!(*en & (1 << (local_irq & 31))); + en += local_irq_to_reg_offset(local_irq); + return !!(*en & BIT(local_irq & PLIC_REG_MASK)); } /** From ffb8f31bffd39b3a21e99e31deb7555d0585d81c Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 26 Sep 2023 14:43:22 +0800 Subject: [PATCH 0154/1049] drivers: intc: plic: Use sys IO APIs to access memory-mapped registers Use arch-specific sys IO APIs to access the memory-mapped registers to ensure safe memory operations fixes #62956 Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 79 ++++++++++++++---------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 7ced9580123c43f..41ee75823b044ca 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Jean-Paul Etienne + * Copyright (c) 2023 Meta * Contributors: 2018 Antmicro * * SPDX-License-Identifier: Apache-2.0 @@ -31,6 +32,8 @@ #define PLIC_REG_PRIO_OFFSET 0x0 #define PLIC_REG_IRQ_EN_OFFSET 0x2000 #define PLIC_REG_REGS_OFFSET 0x200000 +#define PLIC_REG_REGS_THRES_PRIORITY_OFFSET 0 +#define PLIC_REG_REGS_CLAIM_COMPLETE_OFFSET sizeof(uint32_t) /* * Trigger type is mentioned, but not defined in the RISCV PLIC specs. * However, it is defined and supported by at least the Andes & Telink datasheet, and supported @@ -42,11 +45,6 @@ #define PLIC_REG_SIZE 32 #define PLIC_REG_MASK BIT_MASK(LOG2(PLIC_REG_SIZE)) -struct plic_regs_t { - uint32_t threshold_prio; - uint32_t claim_complete; -}; - typedef void (*riscv_plic_irq_config_func_t)(void); struct plic_config { mem_addr_t prio; @@ -73,6 +71,20 @@ static inline uint32_t get_plic_enabled_size(const struct device *dev) return local_irq_to_reg_offset(config->num_irqs) + 1; } +static inline uint32_t get_claim_complete_offset(const struct device *dev) +{ + const struct plic_config *config = dev->config; + + return config->reg + PLIC_REG_REGS_CLAIM_COMPLETE_OFFSET; +} + +static inline uint32_t get_threshold_priority_offset(const struct device *dev) +{ + const struct plic_config *config = dev->config; + + return config->reg + PLIC_REG_REGS_THRES_PRIORITY_OFFSET; +} + /** * @brief Determine the PLIC device from the IRQ * @@ -103,10 +115,9 @@ static inline const struct device *get_plic_dev_from_irq(uint32_t irq) static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq) { const struct plic_config *config = dev->config; - volatile uint32_t *trig = (volatile uint32_t *) config->trig; + mem_addr_t trig_addr = config->trig + local_irq_to_reg_offset(local_irq); - trig += local_irq_to_reg_offset(local_irq); - return *trig & BIT(local_irq); + return sys_read32(trig_addr) & BIT(local_irq); } /** @@ -123,13 +134,15 @@ void riscv_plic_irq_enable(uint32_t irq) { const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; - volatile uint32_t *en = (volatile uint32_t *) config->irq_en; const uint32_t local_irq = irq_from_level_2(irq); + mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq); + uint32_t en_value; uint32_t key; key = irq_lock(); - en += local_irq_to_reg_offset(local_irq); - WRITE_BIT(*en, local_irq & PLIC_REG_MASK, true); + en_value = sys_read32(en_addr); + WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, true); + sys_write32(en_value, en_addr); irq_unlock(key); } @@ -147,13 +160,15 @@ void riscv_plic_irq_disable(uint32_t irq) { const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; - volatile uint32_t *en = (volatile uint32_t *) config->irq_en; const uint32_t local_irq = irq_from_level_2(irq); + mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq); + uint32_t en_value; uint32_t key; key = irq_lock(); - en += local_irq_to_reg_offset(local_irq); - WRITE_BIT(*en, local_irq & PLIC_REG_MASK, false); + en_value = sys_read32(en_addr); + WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, false); + sys_write32(en_value, en_addr); irq_unlock(key); } @@ -169,11 +184,14 @@ int riscv_plic_irq_is_enabled(uint32_t irq) { const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; - volatile uint32_t *en = (volatile uint32_t *) config->irq_en; const uint32_t local_irq = irq_from_level_2(irq); + mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq); + uint32_t en_value; + + en_value = sys_read32(en_addr); + en_value &= BIT(local_irq & PLIC_REG_MASK); - en += local_irq_to_reg_offset(local_irq); - return !!(*en & BIT(local_irq & PLIC_REG_MASK)); + return !!en_value; } /** @@ -190,14 +208,13 @@ void riscv_plic_set_priority(uint32_t irq, uint32_t priority) { const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; - volatile uint32_t *prio = (volatile uint32_t *) config->prio; const uint32_t local_irq = irq_from_level_2(irq); + mem_addr_t prio_addr = config->prio + (local_irq * sizeof(uint32_t)); if (priority > config->max_prio) priority = config->max_prio; - prio += local_irq; - *prio = priority; + sys_write32(priority, prio_addr); } /** @@ -223,12 +240,12 @@ const struct device *riscv_plic_get_dev(void) static void plic_irq_handler(const struct device *dev) { const struct plic_config *config = dev->config; - volatile struct plic_regs_t *regs = (volatile struct plic_regs_t *) config->reg; + mem_addr_t claim_complete_addr = get_claim_complete_offset(dev); struct _isr_table_entry *ite; int edge_irq; /* Get the IRQ number generating the interrupt */ - const uint32_t local_irq = regs->claim_complete; + const uint32_t local_irq = sys_read32(claim_complete_addr); /* * Save IRQ in save_irq. To be used, if need be, by @@ -254,7 +271,7 @@ static void plic_irq_handler(const struct device *dev) * for edge triggered interrupts. */ if (edge_irq) - regs->claim_complete = local_irq; + sys_write32(local_irq, claim_complete_addr); const uint32_t parent_irq = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), (z_get_sw_isr_irq_from_device(dev)), (0U)); @@ -273,7 +290,7 @@ static void plic_irq_handler(const struct device *dev) * for level triggered interrupts. */ if (!edge_irq) - regs->claim_complete = local_irq; + sys_write32(local_irq, claim_complete_addr); } /** @@ -286,24 +303,22 @@ static void plic_irq_handler(const struct device *dev) static int plic_init(const struct device *dev) { const struct plic_config *config = dev->config; - volatile uint32_t *en = (volatile uint32_t *) config->irq_en; - volatile uint32_t *prio = (volatile uint32_t *) config->prio; - volatile struct plic_regs_t *regs = (volatile struct plic_regs_t *) config->reg; + mem_addr_t en_addr = config->irq_en; + mem_addr_t prio_addr = config->prio; + mem_addr_t thres_prio_addr = get_threshold_priority_offset(dev); /* Ensure that all interrupts are disabled initially */ for (uint32_t i = 0; i < get_plic_enabled_size(dev); i++) { - *en = 0U; - en++; + sys_write32(0U, en_addr + (i * sizeof(uint32_t))); } /* Set priority of each interrupt line to 0 initially */ for (uint32_t i = 0; i < config->num_irqs; i++) { - *prio = 0U; - prio++; + sys_write32(0U, prio_addr + (i * sizeof(uint32_t))); } /* Set threshold priority to 0 */ - regs->threshold_prio = 0U; + sys_write32(0U, thres_prio_addr); /* Configure IRQ for PLIC driver */ config->irq_config_func(); From d45d323da2a5f443c2933e70a2ffaedf3097aeae Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Fri, 22 Sep 2023 14:05:44 +0300 Subject: [PATCH 0155/1049] manifest: Bump up hal_xtensa revision Bump up hal_xtensa revision to contain the overlays for i.MX8QM and i.MX8QXP. Signed-off-by: Laurentiu Mihalcea --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 17fe8066384de72..9f1317eb21db8a0 100644 --- a/west.yml +++ b/west.yml @@ -249,7 +249,7 @@ manifest: groups: - hal - name: hal_xtensa - revision: e6da34fc07dfe96161ab8743f5dbeb6e6307ab93 + revision: 08325d6fb7190a105f5382d35e64ed2812c57cf4 path: modules/hal/xtensa groups: - hal From 5e7a9e5e9f1e813f07469fc1f000d19d3eb6f034 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Mon, 16 Oct 2023 14:13:44 +0300 Subject: [PATCH 0156/1049] manifest: Bump up hal_nxp revision Bump up hal_nxp revision to contain the HAL headers for i.MX8QM's and i.MX8QXP's DSP. Signed-off-by: Laurentiu Mihalcea --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 9f1317eb21db8a0..6a9d1e743bbe68c 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 3731aefd0cd55f8507498c336b3256268ecd9d61 + revision: d5e5358e56542b94bc65b6483396f50ed8f3172d path: modules/hal/nxp groups: - hal From a0ecc05cdfa52d5b501ed8a25986767501ae57a1 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Fri, 22 Sep 2023 10:18:13 +0300 Subject: [PATCH 0157/1049] soc: xtensa: imx8: Split generic i.MX8 SoC into i.MX8QXP and i.MX8QM This commit attempts to split the generic i.MX8 SoC into its QXP and QM variants. As things are now, the i.MX8 SoC doesn't have any NXP HAL files to back it up. As a consequence, the native Zephyr drivers cannot be used. To solve this issue, the generic i.MX8 has been split into i.MX8QXP and i.MX8QM, each of them having different NXP HAL files. Signed-off-by: Laurentiu Mihalcea --- boards/xtensa/nxp_adsp_imx8/Kconfig.board | 2 ++ .../nxp_adsp_imx8/nxp_adsp_imx8_defconfig | 1 + boards/xtensa/nxp_adsp_imx8x/Kconfig.board | 2 ++ .../nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig | 1 + .../nxp_adsp/imx8/Kconfig.defconfig.imx8qm | 9 ++++++++ .../nxp_adsp/imx8/Kconfig.defconfig.imx8qxp | 9 ++++++++ .../nxp_adsp/imx8/Kconfig.defconfig.series | 6 ++---- soc/xtensa/nxp_adsp/imx8/Kconfig.soc | 21 +++++++++++++++++-- soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qm | 17 +++++++++++++++ soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qxp | 21 +++++++++++++++++++ 10 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qm create mode 100644 soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qxp create mode 100644 soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qm create mode 100644 soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qxp diff --git a/boards/xtensa/nxp_adsp_imx8/Kconfig.board b/boards/xtensa/nxp_adsp_imx8/Kconfig.board index e24c0a453169e44..4bb4f56404043f0 100644 --- a/boards/xtensa/nxp_adsp_imx8/Kconfig.board +++ b/boards/xtensa/nxp_adsp_imx8/Kconfig.board @@ -5,3 +5,5 @@ config BOARD_NXP_ADSP_IMX8 bool "NXP ADSP i.MX8" + depends on SOC_SERIES_NXP_IMX8 + select SOC_PART_NUMBER_MIMX8QM6AVUFF diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig index 3d0c02d5017c7f2..2a2a34f03296895 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig @@ -3,6 +3,7 @@ CONFIG_MAIN_STACK_SIZE=3072 CONFIG_SOC_SERIES_NXP_IMX8=y +CONFIG_SOC_MIMX8QM_ADSP=y CONFIG_BOARD_NXP_ADSP_IMX8=y CONFIG_GEN_ISR_TABLES=y diff --git a/boards/xtensa/nxp_adsp_imx8x/Kconfig.board b/boards/xtensa/nxp_adsp_imx8x/Kconfig.board index 7f4f7e0e3f90eb1..7d5336ce7a790ca 100644 --- a/boards/xtensa/nxp_adsp_imx8x/Kconfig.board +++ b/boards/xtensa/nxp_adsp_imx8x/Kconfig.board @@ -5,3 +5,5 @@ config BOARD_NXP_ADSP_IMX8X bool "NXP ADSP i.MX8X" + depends on SOC_SERIES_NXP_IMX8 + select SOC_PART_NUMBER_MIMX8QX6AVLFZ diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig index 92a66362cd03bdf..a424e54cd52312f 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig @@ -3,6 +3,7 @@ CONFIG_MAIN_STACK_SIZE=3072 CONFIG_SOC_SERIES_NXP_IMX8=y +CONFIG_SOC_MIMX8QXP_ADSP=y CONFIG_BOARD_NXP_ADSP_IMX8X=y CONFIG_GEN_ISR_TABLES=y diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qm b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qm new file mode 100644 index 000000000000000..e678be835925a29 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qm @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MIMX8QM_ADSP + +config SOC + default "mimx8qm6" + +endif # SOC_MIMX8QM_ADSP diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qxp b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qxp new file mode 100644 index 000000000000000..e4fcdd92fd05580 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qxp @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MIMX8QXP_ADSP + +config SOC + default "mimx8qx6" + +endif # SOC_MIMX8QXP_ADSP diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series index 1976bc119126b2e..517e2c52a8e321b 100644 --- a/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series @@ -11,10 +11,6 @@ config SOC_TOOLCHAIN_NAME string default "nxp_imx_adsp" -config SOC - string - default "nxp_imx8" - config SYS_CLOCK_HW_CYCLES_PER_SEC default 666000000 if XTENSA_TIMER @@ -27,4 +23,6 @@ config DYNAMIC_INTERRUPTS config LOG default y +source "soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8q*" + endif # SOC_SERIES_NXP_IMX8 diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.soc b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc index 16c36eb8a6eeb1e..33794a85c2be708 100644 --- a/soc/xtensa/nxp_adsp/imx8/Kconfig.soc +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc @@ -3,9 +3,26 @@ choice prompt "NXP i.MX SoC Selection" + depends on SOC_SERIES_NXP_IMX8 - config SOC_NXP_IMX8 - bool "i.MX8 SoC" + config SOC_MIMX8QM_ADSP + bool "NXP i.MX8QM Audio DSP" depends on SOC_SERIES_NXP_IMX8 + select HAS_MCUX + config SOC_MIMX8QXP_ADSP + bool "NXP i.MX8QXP Audio DSP" + depends on SOC_SERIES_NXP_IMX8 + select HAS_MCUX endchoice + +if SOC_SERIES_NXP_IMX8 + +config SOC_PART_NUMBER + string + default SOC_PART_NUMBER_MIMX8QM_DSP if SOC_MIMX8QM_ADSP + default SOC_PART_NUMBER_MIMX8QXP_DSP if SOC_MIMX8QXP_ADSP + +source "soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8q*" + +endif # SOC_SERIES_NXP_IMX8 diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qm b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qm new file mode 100644 index 000000000000000..fd5334cfee5d3b4 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qm @@ -0,0 +1,17 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MIMX8QM_ADSP + +config SOC_PART_NUMBER_MIMX8QM6AVUFF + bool + +config SOC_PART_NUMBER_MIMX8QM_DSP + string + default "MIMX8QM6AVUFF_dsp" if SOC_PART_NUMBER_MIMX8QM6AVUFF + help + This string holds the full part number of the SoC. It is a hidden + option that you should not set directly. The part number selection + choice defines the default value for this string. + +endif # SOC_MIMX8QM_ADSP diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qxp b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qxp new file mode 100644 index 000000000000000..20f0a13e11724fe --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qxp @@ -0,0 +1,21 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MIMX8QXP_ADSP + +config SOC_PART_NUMBER_MIMX8QX6AVLFZ + bool + +config SOC_PART_NUMBER_MIMX8QX6CVLDZ + bool + +config SOC_PART_NUMBER_MIMX8QXP_DSP + string + default "MIMX8QX6AVLFZ_dsp" if SOC_PART_NUMBER_MIMX8QX6AVLFZ + default "MIMX8QX6CVLDZ_dsp" if SOC_PART_NUMBER_MIMX8QX6CVLDZ + help + This string holds the full part number of the SoC. It is a hidden + option that you should not set directly. The part number selection + choice defines the default value for this string. + +endif # SOC_MIMX8QXP_ADSP From f29d6edece913b2f2ee417d382b2d02f63ab3a0b Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Fri, 22 Sep 2023 10:23:06 +0300 Subject: [PATCH 0158/1049] soc: xtensa: imx8: Remove include/soc directory Since platform.h is a SOF-specific header that's no longer used there's no point in keeping the include/soc directory. As such, move memory.h to include/ and modify the linker script to reflect this location change. Signed-off-by: Laurentiu Mihalcea --- .../nxp_adsp/imx8/include/{soc => }/memory.h | 0 .../nxp_adsp/imx8/include/soc/platform.h | 21 ------------------- soc/xtensa/nxp_adsp/imx8/linker.ld | 2 +- 3 files changed, 1 insertion(+), 22 deletions(-) rename soc/xtensa/nxp_adsp/imx8/include/{soc => }/memory.h (100%) delete mode 100644 soc/xtensa/nxp_adsp/imx8/include/soc/platform.h diff --git a/soc/xtensa/nxp_adsp/imx8/include/soc/memory.h b/soc/xtensa/nxp_adsp/imx8/include/memory.h similarity index 100% rename from soc/xtensa/nxp_adsp/imx8/include/soc/memory.h rename to soc/xtensa/nxp_adsp/imx8/include/memory.h diff --git a/soc/xtensa/nxp_adsp/imx8/include/soc/platform.h b/soc/xtensa/nxp_adsp/imx8/include/soc/platform.h deleted file mode 100644 index 44d8f46d1d41276..000000000000000 --- a/soc/xtensa/nxp_adsp/imx8/include/soc/platform.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2021 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __PLATFORM_PLATFORM_H__ -#define __PLATFORM_PLATFORM_H__ - -#define PLATFORM_PRIMARY_CORE_ID 0 - -#define MAX_CORE_COUNT 1 - -#if PLATFORM_CORE_COUNT > MAX_CORE_COUNT -#error "Invalid core count - exceeding core limit" -/* IPC Interrupt */ -#define PLATFORM_IPC_INTERRUPT IRQ_NUM_MU -#define PLATFORM_IPC_INTERRUPT_NAME NULL -#endif - -#endif /* __PLATFORM_PLATFORM_H__ */ diff --git a/soc/xtensa/nxp_adsp/imx8/linker.ld b/soc/xtensa/nxp_adsp/imx8/linker.ld index 599ef7339b802ec..7e5829c8d137f89 100644 --- a/soc/xtensa/nxp_adsp/imx8/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8/linker.ld @@ -15,7 +15,7 @@ OUTPUT_ARCH(xtensa) #include #include -#include +#include #include #include From ad7e85893802c36ce05eebefa231758a6a697979 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Fri, 22 Sep 2023 10:27:52 +0300 Subject: [PATCH 0159/1049] soc: xtensa: imx8: memory.h: Cleanup This commit attempts to clean the memory.h header by doing the following changes: 1) Change the include guard to the standard ZEPHYR_.... 2) Remove unused macro definitions. Signed-off-by: Laurentiu Mihalcea --- soc/xtensa/nxp_adsp/imx8/include/memory.h | 58 ++--------------------- 1 file changed, 3 insertions(+), 55 deletions(-) diff --git a/soc/xtensa/nxp_adsp/imx8/include/memory.h b/soc/xtensa/nxp_adsp/imx8/include/memory.h index ee4785995a89c9a..56bac21c780b148 100644 --- a/soc/xtensa/nxp_adsp/imx8/include/memory.h +++ b/soc/xtensa/nxp_adsp/imx8/include/memory.h @@ -4,13 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __INC_MEMORY_H -#define __INC_MEMORY_H - -#define PLATFORM_CORE_COUNT 1 - -/** Id of master DSP core */ -#define PLATFORM_PRIMARY_CORE_ID 0 +#ifndef ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ +#define ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ #define IRAM_RESERVE_HEADER_SPACE 0x400 @@ -164,51 +159,4 @@ + SRAM_DEBUG_SIZE + SRAM_EXCEPT_SIZE \ + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) -/* Heap section sizes for module pool */ -#define HEAP_RT_COUNT8 0 -#define HEAP_RT_COUNT16 48 -#define HEAP_RT_COUNT32 48 -#define HEAP_RT_COUNT64 32 -#define HEAP_RT_COUNT128 32 -#define HEAP_RT_COUNT256 32 -#define HEAP_RT_COUNT512 4 -#define HEAP_RT_COUNT1024 4 -#define HEAP_RT_COUNT2048 4 - -/* Heap section sizes for system runtime heap */ -#define HEAP_SYS_RT_COUNT64 128 -#define HEAP_SYS_RT_COUNT512 16 -#define HEAP_SYS_RT_COUNT1024 8 - -/* Heap configuration */ -#define HEAP_SYSTEM_BASE SDRAM1_BASE + SOF_MAILBOX_SIZE -#define HEAP_SYSTEM_SIZE 0xe000 - -#define HEAP_SYS_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) -#define HEAP_SYS_RUNTIME_SIZE \ - (HEAP_SYS_RT_COUNT64 * 64 + HEAP_SYS_RT_COUNT512 * 512 + \ - HEAP_SYS_RT_COUNT1024 * 1024) - -#define HEAP_RUNTIME_BASE (HEAP_SYS_RUNTIME_BASE + HEAP_SYS_RUNTIME_SIZE) -#define HEAP_RUNTIME_SIZE \ - (HEAP_RT_COUNT8 * 8 + HEAP_RT_COUNT16 * 16 + \ - HEAP_RT_COUNT32 * 32 + HEAP_RT_COUNT64 * 64 + \ - HEAP_RT_COUNT128 * 128 + HEAP_RT_COUNT256 * 256 + \ - HEAP_RT_COUNT512 * 512 + HEAP_RT_COUNT1024 * 1024 + \ - HEAP_RT_COUNT2048 * 2048) - -#define HEAP_BUFFER_BASE (HEAP_RUNTIME_BASE + HEAP_RUNTIME_SIZE) -#define HEAP_BUFFER_SIZE \ - (SDRAM1_SIZE - SOF_MAILBOX_SIZE - HEAP_RUNTIME_SIZE - SOF_STACK_TOTAL_SIZE -\ - HEAP_SYS_RUNTIME_SIZE - HEAP_SYSTEM_SIZE) - -/* Stack configuration */ -#define SOF_STACK_SIZE 0x1000 -#define SOF_STACK_TOTAL_SIZE SOF_STACK_SIZE -#define SOF_STACK_BASE (SDRAM1_BASE + SDRAM1_SIZE) -#define SOF_STACK_END (SOF_STACK_BASE - SOF_STACK_TOTAL_SIZE) - -/* Host page size */ -#define HOST_PAGE_SIZE 4096 - -#endif /* __INC_MEMORY_H */ +#endif /* ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ */ From eb12bae0486c1ab14ddb085448416b452a39b3fd Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Fri, 22 Sep 2023 10:56:42 +0300 Subject: [PATCH 0160/1049] soc: xtensa: imx8: Configuration cleanup As the name suggests, this commit attempts to cleanup some of the configurations for the i.MX8 series. This cleanup consists of either relocating the configuration or removing unnecessary configurations. As a rule of thumb, SoC-specific configurations have been moved to Kconfig.series. If the configuration is by default 'y' and needs to be set to 'n' or it has a numeric value then it has been moved to Kconfig.defconfig.series. Configurations that are default 'n' and were also explicitly set to 'n' have been removed. Also, enabling logging has been moved to the board level to avoid having to force all boards based on the same SoC to enable logging. Signed-off-by: Laurentiu Mihalcea --- boards/xtensa/nxp_adsp_imx8/Kconfig.defconfig | 11 ----------- .../nxp_adsp_imx8/nxp_adsp_imx8_defconfig | 17 ++++------------- boards/xtensa/nxp_adsp_imx8x/Kconfig.defconfig | 10 ---------- .../nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig | 17 ++++------------- .../nxp_adsp/imx8/Kconfig.defconfig.series | 8 ++++---- soc/xtensa/nxp_adsp/imx8/Kconfig.series | 2 ++ 6 files changed, 14 insertions(+), 51 deletions(-) diff --git a/boards/xtensa/nxp_adsp_imx8/Kconfig.defconfig b/boards/xtensa/nxp_adsp_imx8/Kconfig.defconfig index f72d1a4e11f9f17..04aa0aa6ed30e5d 100644 --- a/boards/xtensa/nxp_adsp_imx8/Kconfig.defconfig +++ b/boards/xtensa/nxp_adsp_imx8/Kconfig.defconfig @@ -7,15 +7,4 @@ if BOARD_NXP_ADSP_IMX8 config BOARD default "nxp_adsp_imx8" -config DUMMY_DMA - bool - default y - depends on DMA - -config IMX_EDMA - bool - default y - depends on DMA - - endif # BOARD_NXP_ADSP_IMX8 diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig index 2a2a34f03296895..2cf0553a8eb4d3f 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig @@ -2,22 +2,13 @@ CONFIG_MAIN_STACK_SIZE=3072 +# board/soc-related configurations CONFIG_SOC_SERIES_NXP_IMX8=y CONFIG_SOC_MIMX8QM_ADSP=y CONFIG_BOARD_NXP_ADSP_IMX8=y -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_XTENSA_RESET_VECTOR=y - -CONFIG_XTENSA_USE_CORE_CRT1=y - -CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY=y - -CONFIG_MULTI_LEVEL_INTERRUPTS=n -CONFIG_2ND_LEVEL_INTERRUPTS=n +CONFIG_LOG=y +# TODO: maybe move this to SOF? +CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_BUILD_OUTPUT_BIN=n - -CONFIG_DCACHE_LINE_SIZE=128 diff --git a/boards/xtensa/nxp_adsp_imx8x/Kconfig.defconfig b/boards/xtensa/nxp_adsp_imx8x/Kconfig.defconfig index 31d4239550396a2..a985696286afb9f 100644 --- a/boards/xtensa/nxp_adsp_imx8x/Kconfig.defconfig +++ b/boards/xtensa/nxp_adsp_imx8x/Kconfig.defconfig @@ -7,14 +7,4 @@ if BOARD_NXP_ADSP_IMX8X config BOARD default "nxp_adsp_imx8x" -config DUMMY_DMA - bool - default y - depends on DMA - -config IMX_EDMA - bool - default y - depends on DMA - endif # BOARD_NXP_ADSP_IMX8X diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig index a424e54cd52312f..87de9b515c52169 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig @@ -2,22 +2,13 @@ CONFIG_MAIN_STACK_SIZE=3072 +# board/soc-related configurations CONFIG_SOC_SERIES_NXP_IMX8=y CONFIG_SOC_MIMX8QXP_ADSP=y CONFIG_BOARD_NXP_ADSP_IMX8X=y -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_XTENSA_RESET_VECTOR=y - -CONFIG_XTENSA_USE_CORE_CRT1=y - -CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY=y - -CONFIG_MULTI_LEVEL_INTERRUPTS=n -CONFIG_2ND_LEVEL_INTERRUPTS=n +CONFIG_LOG=y +# TODO: maybe move this to SOF? +CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_BUILD_OUTPUT_BIN=n - -CONFIG_DCACHE_LINE_SIZE=128 diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series index 517e2c52a8e321b..a5f4597f06917ab 100644 --- a/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series @@ -17,11 +17,11 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config SYS_CLOCK_TICKS_PER_SEC default 50000 -config DYNAMIC_INTERRUPTS - default y +config DCACHE_LINE_SIZE + default 128 -config LOG - default y +config GEN_IRQ_VECTOR_TABLE + default n source "soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8q*" diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.series b/soc/xtensa/nxp_adsp/imx8/Kconfig.series index 396607a484709ca..003784e842b144b 100644 --- a/soc/xtensa/nxp_adsp/imx8/Kconfig.series +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.series @@ -9,5 +9,7 @@ config SOC_SERIES_NXP_IMX8 select XTENSA_RESET_VECTOR select XTENSA_USE_CORE_CRT1 select ATOMIC_OPERATIONS_BUILTIN + select GEN_ISR_TABLES + select XTENSA_SMALL_VECTOR_TABLE_ENTRY help NXP i.MX8 From ea99578b764a70b48755d22a5b3cde0e38b9af5c Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Fri, 22 Sep 2023 11:19:57 +0300 Subject: [PATCH 0161/1049] soc: xtensa: imx8: Enable clock control on i.MX8QM/QXP This commit enables clock control on the i.MX8QM and QXP boards. This is achieved through the following changes: 1) The "reg" property is no longer marked as required for the "nxp,imx-ccm" binding. This is necessary because in the case of i.MX8QM and i.MX8QXP the clock management is done through the SCFW, hence there's no need to access CCM's MMIO space (not that you could anyways). 2) The DTS now contains a scu_mu node. This node refers to the MU instance used by the DSP to communicate with the SCFW. 3) The CCM driver needs to support the LPUART clocks (which will be the only IP that's supported for now) and needs to perform an initialization so that the NXP HAL driver knows which MU to use to communicate with the SCFW. Signed-off-by: Laurentiu Mihalcea --- .../nxp_adsp_imx8/nxp_adsp_imx8_defconfig | 3 + .../nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig | 3 + .../clock_control/clock_control_mcux_ccm.c | 95 ++++++++++++++++++- dts/bindings/clock/nxp,imx-ccm.yaml | 3 - dts/xtensa/nxp/nxp_imx8.dtsi | 13 +++ 5 files changed, 112 insertions(+), 5 deletions(-) diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig index 2cf0553a8eb4d3f..64fdb3219d72ef4 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig @@ -12,3 +12,6 @@ CONFIG_LOG=y # TODO: maybe move this to SOF? CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_BUILD_OUTPUT_BIN=n + +# clock-related configurations +CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig index 87de9b515c52169..ceb0bf13a595f8f 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig @@ -12,3 +12,6 @@ CONFIG_LOG=y # TODO: maybe move this to SOF? CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_BUILD_OUTPUT_BIN=n + +# clock-related configurations +CONFIG_CLOCK_CONTROL=y diff --git a/drivers/clock_control/clock_control_mcux_ccm.c b/drivers/clock_control/clock_control_mcux_ccm.c index 93a495b9daea121..77736caa1c92fca 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -12,6 +12,10 @@ #include #include +#if defined(CONFIG_SOC_MIMX8QM_ADSP) || defined(CONFIG_SOC_MIMX8QXP_ADSP) +#include
+#endif + #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL #include LOG_MODULE_REGISTER(clock_control); @@ -52,6 +56,34 @@ static const clock_root_t lpuart_clk_root[] = { }; #endif +#ifdef CONFIG_UART_MCUX_LPUART + +#ifdef CONFIG_SOC_MIMX8QM_ADSP +static const clock_ip_name_t lpuart_clocks[] = { + kCLOCK_DMA_Lpuart0, + kCLOCK_DMA_Lpuart1, + kCLOCK_DMA_Lpuart2, + kCLOCK_DMA_Lpuart3, + kCLOCK_DMA_Lpuart4, +}; + +static const uint32_t lpuart_rate = MHZ(80); +#endif /* CONFIG_SOC_MIMX8QM_ADSP */ + +#ifdef CONFIG_SOC_MIMX8QXP_ADSP +static const clock_ip_name_t lpuart_clocks[] = { + kCLOCK_DMA_Lpuart0, + kCLOCK_DMA_Lpuart1, + kCLOCK_DMA_Lpuart2, + kCLOCK_DMA_Lpuart3, +}; + +static const uint32_t lpuart_rate = MHZ(80); +#endif /* CONFIG_SOC_MIMX8QXP_ADSP */ + +#endif /* CONFIG_UART_MCUX_LPUART */ + + static int mcux_ccm_on(const struct device *dev, clock_control_subsys_t sub_system) { @@ -67,6 +99,25 @@ static int mcux_ccm_on(const struct device *dev, CLOCK_EnableClock(uart_clocks[instance]); return 0; #endif + +#if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX8QM_ADSP) + case IMX_CCM_LPUART1_CLK: + case IMX_CCM_LPUART2_CLK: + case IMX_CCM_LPUART3_CLK: + case IMX_CCM_LPUART4_CLK: + case IMX_CCM_LPUART5_CLK: + CLOCK_EnableClock(lpuart_clocks[instance]); + return 0; +#endif + +#if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX8QXP_ADSP) + case IMX_CCM_LPUART1_CLK: + case IMX_CCM_LPUART2_CLK: + case IMX_CCM_LPUART3_CLK: + case IMX_CCM_LPUART4_CLK: + CLOCK_EnableClock(lpuart_clocks[instance]); + return 0; +#endif default: (void)instance; return 0; @@ -128,7 +179,31 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, #endif #ifdef CONFIG_UART_MCUX_LPUART -#ifdef CONFIG_SOC_MIMX93_A55 + +#if defined(CONFIG_SOC_MIMX8QM_ADSP) + case IMX_CCM_LPUART1_CLK: + case IMX_CCM_LPUART2_CLK: + case IMX_CCM_LPUART3_CLK: + case IMX_CCM_LPUART4_CLK: + case IMX_CCM_LPUART5_CLK: + uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK; + + CLOCK_SetIpFreq(lpuart_clocks[instance], lpuart_rate); + *rate = CLOCK_GetIpFreq(lpuart_clocks[instance]); + break; + +#elif defined(CONFIG_SOC_MIMX8QXP_ADSP) + case IMX_CCM_LPUART1_CLK: + case IMX_CCM_LPUART2_CLK: + case IMX_CCM_LPUART3_CLK: + case IMX_CCM_LPUART4_CLK: + uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK; + + CLOCK_SetIpFreq(lpuart_clocks[instance], lpuart_rate); + *rate = CLOCK_GetIpFreq(lpuart_clocks[instance]); + break; + +#elif defined(CONFIG_SOC_MIMX93_A55) case IMX_CCM_LPUART1_CLK: case IMX_CCM_LPUART2_CLK: case IMX_CCM_LPUART3_CLK: @@ -270,6 +345,22 @@ static const struct clock_control_driver_api mcux_ccm_driver_api = { .get_rate = mcux_ccm_get_subsys_rate, }; -DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, +static int mcux_ccm_init(const struct device *dev) +{ +#if defined(CONFIG_SOC_MIMX8QM_ADSP) || defined(CONFIG_SOC_MIMX8QXP_ADSP) + sc_ipc_t ipc_handle; + int ret; + + ret = sc_ipc_open(&ipc_handle, DT_REG_ADDR(DT_NODELABEL(scu_mu))); + if (ret != SC_ERR_NONE) { + return -ENODEV; + } + + CLOCK_Init(ipc_handle); +#endif + return 0; +} + +DEVICE_DT_INST_DEFINE(0, mcux_ccm_init, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &mcux_ccm_driver_api); diff --git a/dts/bindings/clock/nxp,imx-ccm.yaml b/dts/bindings/clock/nxp,imx-ccm.yaml index 9ddda734e8144be..f328b6f034a725c 100644 --- a/dts/bindings/clock/nxp,imx-ccm.yaml +++ b/dts/bindings/clock/nxp,imx-ccm.yaml @@ -8,9 +8,6 @@ compatible: "nxp,imx-ccm" include: [clock-controller.yaml, base.yaml] properties: - reg: - required: true - "#clock-cells": const: 3 diff --git a/dts/xtensa/nxp/nxp_imx8.dtsi b/dts/xtensa/nxp/nxp_imx8.dtsi index 06b38e1bbee1c34..b223fa108435e4f 100644 --- a/dts/xtensa/nxp/nxp_imx8.dtsi +++ b/dts/xtensa/nxp/nxp_imx8.dtsi @@ -6,6 +6,7 @@ #include #include +#include / { cpus { @@ -30,4 +31,16 @@ compatible = "mmio-sram"; reg = <0x92c00000 DT_SIZE_K(512)>; }; + + /* LSIO MU2, used to interact with the SCFW */ + scu_mu: mailbox@5d1d0000 { + reg = <0x5d1d0000 DT_SIZE_K(64)>; + }; + + scu: system-controller { + ccm: clock-controller { + compatible = "nxp,imx-ccm"; + #clock-cells = <3>; + }; + }; }; From 707759bd121a0fec8d1a65adc10edec120f349cc Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Fri, 22 Sep 2023 12:06:05 +0300 Subject: [PATCH 0162/1049] soc: xtensa: imx8: Add pinctrl support This commit introduces support for pinctrl-related operations on i.MX8QM/QXP. Signed-off-by: Laurentiu Mihalcea --- .../nxp_adsp_imx8/nxp_adsp_imx8-pinctrl.dtsi | 26 ++++++++++++ boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts | 1 + .../nxp_adsp_imx8x-pinctrl.dtsi | 26 ++++++++++++ .../xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts | 1 + drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig.imx | 7 ++++ drivers/pinctrl/pinctrl_imx_scu.c | 38 +++++++++++++++++ dts/bindings/pinctrl/nxp,imx-iomuxc-scu.yaml | 25 +++++++++++ dts/bindings/pinctrl/nxp,imx8-pinctrl.yaml | 17 ++++++++ dts/xtensa/nxp/nxp_imx8.dtsi | 7 ++++ .../dt-bindings/pinctrl/imx8qm-pinctrl.h | 18 ++++++++ .../dt-bindings/pinctrl/imx8qxp-pinctrl.h | 18 ++++++++ soc/xtensa/nxp_adsp/imx8/pinctrl_soc.h | 41 +++++++++++++++++++ 13 files changed, 226 insertions(+) create mode 100644 boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8-pinctrl.dtsi create mode 100644 boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x-pinctrl.dtsi create mode 100644 drivers/pinctrl/pinctrl_imx_scu.c create mode 100644 dts/bindings/pinctrl/nxp,imx-iomuxc-scu.yaml create mode 100644 dts/bindings/pinctrl/nxp,imx8-pinctrl.yaml create mode 100644 include/zephyr/dt-bindings/pinctrl/imx8qm-pinctrl.h create mode 100644 include/zephyr/dt-bindings/pinctrl/imx8qxp-pinctrl.h create mode 100644 soc/xtensa/nxp_adsp/imx8/pinctrl_soc.h diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8-pinctrl.dtsi b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8-pinctrl.dtsi new file mode 100644 index 000000000000000..a6291a5d4b853fb --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8-pinctrl.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&iomuxc { + iomuxc_uart2_rx_uart0_rts_b: IOMUXC_UART2_RX_UART0_RTS_B { + pinmux = ; + }; + + iomuxc_uart2_tx_uart0_cts_b: IOMUXC_UART2_TX_UART0_CTS_B { + pinmux = ; + }; +}; + +&pinctrl { + lpuart2_default: lpuart2_default { + group0 { + pinmux = <&iomuxc_uart2_rx_uart0_rts_b>, + <&iomuxc_uart2_tx_uart0_cts_b>; + }; + }; +}; diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts index 51d3162134afbba..2d26c61f13f9c66 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include "nxp_adsp_imx8-pinctrl.dtsi" / { model = "nxp_adsp_imx8"; diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x-pinctrl.dtsi b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x-pinctrl.dtsi new file mode 100644 index 000000000000000..18cfb4732573461 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x-pinctrl.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&iomuxc { + iomuxc_uart2_rx_uart2_rx: IOMUXC_UART2_RX_UART2_RX { + pinmux = ; + }; + + iomuxc_uart2_tx_uart2_tx: IOMUXC_UART2_TX_UART2_TX { + pinmux = ; + }; +}; + +&pinctrl { + lpuart2_default: lpuart2_default { + group0 { + pinmux = <&iomuxc_uart2_rx_uart2_rx>, + <&iomuxc_uart2_tx_uart2_tx>; + }; + }; +}; diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts index bee8ccdb1a15e8a..69e4a57dd640a63 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include "nxp_adsp_imx8x-pinctrl.dtsi" / { model = "nxp_adsp_imx8x"; diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 30b9f96eefc5a87..ba49a637689d981 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -36,3 +36,4 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_CC32XX pinctrl_ti_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NUMAKER pinctrl_numaker.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_QUICKLOGIC_EOS_S3 pinctrl_eos_s3.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_RA pinctrl_ra.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCU pinctrl_imx_scu.c) diff --git a/drivers/pinctrl/Kconfig.imx b/drivers/pinctrl/Kconfig.imx index b31a90e72911f4f..506f5b30016bcaa 100644 --- a/drivers/pinctrl/Kconfig.imx +++ b/drivers/pinctrl/Kconfig.imx @@ -7,6 +7,13 @@ config PINCTRL_IMX help Enable pin controller driver for NXP iMX series MCUs +config PINCTRL_IMX_SCU + bool "Pin controller driver for SCU-based i.MX SoCs" + depends on DT_HAS_NXP_IMX_IOMUXC_SCU_ENABLED + default y + help + Enable pin controller driver for SCU-based NXP i.MX SoCs. + # TODO: Find better place for this option config MCUX_XBARA bool "MCUX XBARA driver" diff --git a/drivers/pinctrl/pinctrl_imx_scu.c b/drivers/pinctrl/pinctrl_imx_scu.c new file mode 100644 index 000000000000000..67448ed599921d2 --- /dev/null +++ b/drivers/pinctrl/pinctrl_imx_scu.c @@ -0,0 +1,38 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include
+ +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, + uint8_t pin_cnt, uintptr_t reg) +{ + sc_ipc_t ipc_handle; + int ret, i; + + ret = sc_ipc_open(&ipc_handle, DT_REG_ADDR(DT_NODELABEL(scu_mu))); + if (ret != SC_ERR_NONE) { + return -ENODEV; + } + + for (i = 0; i < pin_cnt; i++) { + /* TODO: for now, pad configuration is not supported. As such, + * the state of the pad is the following: + * 1) Normal configuration (no OD) + * 2) ISO off + * 3) Pull select and drive strength initialized by another + * entity (e.g: SCFW, Linux etc...) or set to the default + * values as specified in the TRM. + */ + ret = sc_pad_set_mux(ipc_handle, pins[i].pad, pins[i].mux, 0, 0); + if (ret != SC_ERR_NONE) { + return -EINVAL; + } + } + + return 0; +} diff --git a/dts/bindings/pinctrl/nxp,imx-iomuxc-scu.yaml b/dts/bindings/pinctrl/nxp,imx-iomuxc-scu.yaml new file mode 100644 index 000000000000000..60dde5ae4c90599 --- /dev/null +++ b/dts/bindings/pinctrl/nxp,imx-iomuxc-scu.yaml @@ -0,0 +1,25 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + Use this compatible for i.MX boards on which the + IOMUXC is managed by the SCU. + +compatible: "nxp,imx-iomuxc-scu" + +include: base.yaml + +child-binding: + description: SCFW-based IOMUXC pin mux. + properties: + pinmux: + required: true + type: array + description: | + This is an array of values defining the pin mux selection + with the following format: + + + + pad: Which pad to configure. + mux: Select which signal to route. diff --git a/dts/bindings/pinctrl/nxp,imx8-pinctrl.yaml b/dts/bindings/pinctrl/nxp,imx8-pinctrl.yaml new file mode 100644 index 000000000000000..4f0427d5d95cce3 --- /dev/null +++ b/dts/bindings/pinctrl/nxp,imx8-pinctrl.yaml @@ -0,0 +1,17 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Use this compatible for i.MX8QM/QXP boards. + +compatible: "nxp,imx8-pinctrl" + +include: base.yaml + +child-binding: + description: i.MX8QM/QXP pin controller pin group + child-binding: + description: i.MX8QM/QXP pin controller pin configuration node. + properties: + pinmux: + required: true + type: phandles diff --git a/dts/xtensa/nxp/nxp_imx8.dtsi b/dts/xtensa/nxp/nxp_imx8.dtsi index b223fa108435e4f..5f14d220a067197 100644 --- a/dts/xtensa/nxp/nxp_imx8.dtsi +++ b/dts/xtensa/nxp/nxp_imx8.dtsi @@ -42,5 +42,12 @@ compatible = "nxp,imx-ccm"; #clock-cells = <3>; }; + + iomuxc: iomuxc { + compatible = "nxp,imx-iomuxc-scu"; + pinctrl: pinctrl { + compatible = "nxp,imx8-pinctrl"; + }; + }; }; }; diff --git a/include/zephyr/dt-bindings/pinctrl/imx8qm-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/imx8qm-pinctrl.h new file mode 100644 index 000000000000000..9748a2ce4aa8081 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/imx8qm-pinctrl.h @@ -0,0 +1,18 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QM_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QM_PINCTRL_H_ + +/* values for pad field */ +#define SC_P_UART0_RTS_B 23 +#define SC_P_UART0_CTS_B 24 + +/* mux values */ +#define IMX8QM_DMA_LPUART2_RX_UART0_RTS_B 2 /* UART0_RTS_B ---> DMA_LPUART2_RX */ +#define IMX8QM_DMA_LPUART2_TX_UART0_CTS_B 2 /* DMA_LPUART2_TX ---> UART0_CTS_B */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QM_PINCTRL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/imx8qxp-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/imx8qxp-pinctrl.h new file mode 100644 index 000000000000000..0143540f6bf6c22 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/imx8qxp-pinctrl.h @@ -0,0 +1,18 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QXP_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QXP_PINCTRL_H_ + +/* values for pad field */ +#define SC_P_UART2_TX 113 +#define SC_P_UART2_RX 114 + +/* mux values */ +#define IMX8QXP_DMA_LPUART2_RX_UART2_RX 0 /* UART2_RX ---> DMA_LPUART2_RX */ +#define IMX8QXP_DMA_LPUART2_TX_UART2_TX 0 /* DMA_LPUART2_TX ---> UART2_TX */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QXP_PINCTRL_H_ */ diff --git a/soc/xtensa/nxp_adsp/imx8/pinctrl_soc.h b/soc/xtensa/nxp_adsp/imx8/pinctrl_soc.h new file mode 100644 index 000000000000000..ac748220b560559 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/pinctrl_soc.h @@ -0,0 +1,41 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_XTENSA_NXP_ADSP_IMX8_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_XTENSA_NXP_ADSP_IMX8_PINCTRL_SOC_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct pinctrl_soc_pinmux { + uint32_t pad; + uint32_t mux; +}; + +typedef struct pinctrl_soc_pinmux pinctrl_soc_pin_t; + +#define IMX8_PINMUX(n) \ +{ \ + .pad = DT_PROP_BY_IDX(n, pinmux, 0), \ + .mux = DT_PROP_BY_IDX(n, pinmux, 1), \ +}, + +#define Z_PINCTRL_PINMUX(group_id, pin_prop, idx)\ + IMX8_PINMUX(DT_PHANDLE_BY_IDX(group_id, pin_prop, idx)) + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + { DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), \ + DT_FOREACH_PROP_ELEM, pinmux, Z_PINCTRL_PINMUX) }; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_XTENSA_NXP_ADSP_IMX8_PINCTRL_SOC_H_ */ From dcddb2e0f74c16c3c7172c09ec2a6b307ce6ca32 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Fri, 22 Sep 2023 12:08:40 +0300 Subject: [PATCH 0163/1049] dts: xtensa: nxp_imx8: Add dummy interrupt controller node Since the LPUART peripheral DTS binding requires the "interrupts" property be specified even if it's not going to be used for now we need to add a dummy interrupt controller node to make that possible. Logically speaking, this dummy interrupt controller should be used by peripherals which can assert interrupts directly routed to the DSP. Signed-off-by: Laurentiu Mihalcea --- dts/xtensa/nxp/nxp_imx8.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dts/xtensa/nxp/nxp_imx8.dtsi b/dts/xtensa/nxp/nxp_imx8.dtsi index 5f14d220a067197..2ec110adf1e3a38 100644 --- a/dts/xtensa/nxp/nxp_imx8.dtsi +++ b/dts/xtensa/nxp/nxp_imx8.dtsi @@ -17,6 +17,16 @@ device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + clic: interrupt-controller@0 { + compatible = "cdns,xtensa-core-intc"; + reg = <0>; + interrupt-controller; + #interrupt-cells = <3>; + }; }; }; From 5cdd377316e7cb18648c7ebe30a2485a94deb683 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Fri, 22 Sep 2023 12:23:06 +0300 Subject: [PATCH 0164/1049] boards: xtensa: nxp_adsp_imx8(x): Add serial support This commit introduces all changes necessary for utilizing the serial interface on i.MX8QM/QXP. Signed-off-by: Laurentiu Mihalcea --- boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts | 9 +++++++++ .../nxp_adsp_imx8/nxp_adsp_imx8_defconfig | 5 +++++ boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts | 9 +++++++++ .../nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig | 5 +++++ dts/xtensa/nxp/nxp_imx8.dtsi | 17 +++++++++++++++++ 5 files changed, 45 insertions(+) diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts index 2d26c61f13f9c66..a17690109eca596 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts @@ -15,5 +15,14 @@ chosen { zephyr,sram = &sram0; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; }; }; + +&lpuart2 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&lpuart2_default>; + pinctrl-names = "default"; +}; diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig index 64fdb3219d72ef4..a16d8be5e2e36e4 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig @@ -15,3 +15,8 @@ CONFIG_BUILD_OUTPUT_BIN=n # clock-related configurations CONFIG_CLOCK_CONTROL=y + +# serial-related configurations +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts index 69e4a57dd640a63..5aa0e59ebdd0782 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts @@ -15,5 +15,14 @@ chosen { zephyr,sram = &sram0; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; }; }; + +&lpuart2 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&lpuart2_default>; + pinctrl-names = "default"; +}; diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig index ceb0bf13a595f8f..0635e78adf88f69 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig @@ -15,3 +15,8 @@ CONFIG_BUILD_OUTPUT_BIN=n # clock-related configurations CONFIG_CLOCK_CONTROL=y + +# serial-related configurations +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/dts/xtensa/nxp/nxp_imx8.dtsi b/dts/xtensa/nxp/nxp_imx8.dtsi index 2ec110adf1e3a38..7a8c23cedc4302b 100644 --- a/dts/xtensa/nxp/nxp_imx8.dtsi +++ b/dts/xtensa/nxp/nxp_imx8.dtsi @@ -60,4 +60,21 @@ }; }; }; + + lpuart2: serial@5a080000 { + compatible = "nxp,imx-lpuart", "nxp,kinetis-lpuart"; + reg = <0x5a080000 DT_SIZE_K(4)>; + /* TODO: THIS INTID IS JUST A DUMMY ONE UNTIL IRQ_STEER + * DRIVER CAN BE USED ON i.MX8QM/QXP. DO NOT ATTEMPT TO + * ENABLE UART INTERRUPT SUPPORT. + * + * THE CURRENT INTID VALUE IS CHOSEN SUCH THAT gen_isr_tables.py + * WILL BREAK IF YOU ATTEMPT TO IRQ_CONNECT(). + */ + interrupt-parent = <&clic>; + interrupts = <259 0 0>; + /* this is actually LPUART2 clock but the macro indexing starts at 1 */ + clocks = <&ccm IMX_CCM_LPUART3_CLK 0x0 0x0>; + status = "disabled"; + }; }; From 595a9c11c8ea8f7e2e504a9a925643e45c05a83e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 7 Nov 2023 08:44:08 +0700 Subject: [PATCH 0165/1049] counter: nxp_s32_sys_timer: use instance-based DT macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At present, many of the NXP S32 shim drivers do not make use of devicetree instance-based macros because the NXP S32 HAL relies on an index-based approach, requiring knowledge of the peripheral instance index during both compilation and runtime, and this index might not align with the devicetree instance index. The proposed solution in this patch eliminates this limitation by determining the peripheral instance index during compilation through macrobatics and defining the driver's ISR within the shim driver itself. Note that for some peripheral instances is needed to redefine the HAL macros of the peripheral base address, since the naming is not uniform for all instances. Signed-off-by: Manuel Argüelles --- drivers/counter/counter_nxp_s32_sys_timer.c | 55 +++++++++------------ soc/arm/nxp_s32/s32ze/soc.h | 15 ++++++ 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/drivers/counter/counter_nxp_s32_sys_timer.c b/drivers/counter/counter_nxp_s32_sys_timer.c index 1c25039aab299e3..b6c7f8a1d96fdf2 100644 --- a/drivers/counter/counter_nxp_s32_sys_timer.c +++ b/drivers/counter/counter_nxp_s32_sys_timer.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_sys_timer + #include #include #include @@ -14,13 +16,8 @@ LOG_MODULE_REGISTER(nxp_s32_sys_timer, CONFIG_COUNTER_LOG_LEVEL); -#define SYS_TIMER_NODE(n) DT_NODELABEL(stm##n) #define SYS_TIMER_MAX_VALUE 0xFFFFFFFFU #define SYS_TIMER_NUM_CHANNELS 4 -#define SYS_TIMER_INSTANCE_ID(n) (n + 3 + CONFIG_NXP_S32_RTU_INDEX * 4) - -#define _SYS_TIMER_ISR(r, n) RTU##r##_STM_##n##_ISR -#define SYS_TIMER_ISR(r, n) _SYS_TIMER_ISR(r, n) struct nxp_s32_sys_timer_chan_data { counter_alarm_callback_t callback; @@ -209,15 +206,24 @@ static const struct counter_driver_api nxp_s32_sys_timer_driver_api = { .channelMode = STM_IP_CH_MODE_ONESHOT, \ } +#define _SYS_TIMER_ISR(r, n) RTU##r##_STM_##n##_ISR +#define SYS_TIMER_ISR(r, n) _SYS_TIMER_ISR(r, n) + #define SYS_TIMER_ISR_DECLARE(n) \ extern void SYS_TIMER_ISR(CONFIG_NXP_S32_RTU_INDEX, n)(void) +#define SYS_TIMER_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_STM_##i##_BASE) ? i : 0) + +#define SYS_TIMER_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET STM_INSTANCE_COUNT, SYS_TIMER_HW_INSTANCE_CHECK, (|), n) + #define SYS_TIMER_INIT_DEVICE(n) \ SYS_TIMER_ISR_DECLARE(n); \ \ void nxp_s32_sys_timer_##n##_callback(uint8_t chan_id) \ { \ - const struct device *dev = DEVICE_DT_GET(SYS_TIMER_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ const struct nxp_s32_sys_timer_config *config = dev->config; \ struct nxp_s32_sys_timer_data *data = dev->data; \ struct nxp_s32_sys_timer_chan_data *ch_data = &data->ch_data[chan_id]; \ @@ -233,12 +239,10 @@ static const struct counter_driver_api nxp_s32_sys_timer_driver_api = { \ static int nxp_s32_sys_timer_##n##_init(const struct device *dev) \ { \ - IRQ_CONNECT(DT_IRQN(SYS_TIMER_NODE(n)), \ - DT_IRQ(SYS_TIMER_NODE(n), priority), \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ SYS_TIMER_ISR(CONFIG_NXP_S32_RTU_INDEX, n), \ - DEVICE_DT_GET(SYS_TIMER_NODE(n)), \ - DT_IRQ(SYS_TIMER_NODE(n), flags)); \ - irq_enable(DT_IRQN(SYS_TIMER_NODE(n))); \ + DEVICE_DT_INST_GET(n), DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ \ return nxp_s32_sys_timer_init(dev); \ } \ @@ -252,19 +256,18 @@ static const struct counter_driver_api nxp_s32_sys_timer_driver_api = { .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ }, \ .hw_cfg = { \ - .stopInDebugMode = DT_PROP(SYS_TIMER_NODE(n), freeze), \ - .clockPrescaler = DT_PROP(SYS_TIMER_NODE(n), prescaler) - 1, \ + .stopInDebugMode = DT_INST_PROP(n, freeze), \ + .clockPrescaler = DT_INST_PROP(n, prescaler) - 1, \ }, \ .ch_cfg = { \ LISTIFY(SYS_TIMER_NUM_CHANNELS, SYS_TIMER_CHANNEL_CFG, (,), n) \ }, \ - .instance = SYS_TIMER_INSTANCE_ID(n), \ - .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(SYS_TIMER_NODE(n))), \ - .clock_subsys = (clock_control_subsys_t) \ - DT_CLOCKS_CELL(SYS_TIMER_NODE(n), name), \ + .instance = SYS_TIMER_HW_INSTANCE(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ }; \ \ - DEVICE_DT_DEFINE(SYS_TIMER_NODE(n), \ + DEVICE_DT_INST_DEFINE(n, \ nxp_s32_sys_timer_##n##_init, \ NULL, \ &nxp_s32_sys_timer_data_##n, \ @@ -273,18 +276,4 @@ static const struct counter_driver_api nxp_s32_sys_timer_driver_api = { CONFIG_COUNTER_INIT_PRIORITY, \ &nxp_s32_sys_timer_driver_api); -#if DT_NODE_HAS_STATUS(SYS_TIMER_NODE(0), okay) -SYS_TIMER_INIT_DEVICE(0) -#endif - -#if DT_NODE_HAS_STATUS(SYS_TIMER_NODE(1), okay) -SYS_TIMER_INIT_DEVICE(1) -#endif - -#if DT_NODE_HAS_STATUS(SYS_TIMER_NODE(2), okay) -SYS_TIMER_INIT_DEVICE(2) -#endif - -#if DT_NODE_HAS_STATUS(SYS_TIMER_NODE(3), okay) -SYS_TIMER_INIT_DEVICE(3) -#endif +DT_INST_FOREACH_STATUS_OKAY(SYS_TIMER_INIT_DEVICE) diff --git a/soc/arm/nxp_s32/s32ze/soc.h b/soc/arm/nxp_s32/s32ze/soc.h index 756774d7202f04e..a6a7ca51ced965e 100644 --- a/soc/arm/nxp_s32/s32ze/soc.h +++ b/soc/arm/nxp_s32/s32ze/soc.h @@ -33,4 +33,19 @@ #define IP_SWT_11_BASE IP_RTU1__SWT_4_BASE #define IP_SWT_12_BASE IP_SMU__SWT_BASE +/* STM */ +#define IP_STM_0_BASE IP_CE_STM_0_BASE +#define IP_STM_1_BASE IP_CE_STM_1_BASE +#define IP_STM_2_BASE IP_CE_STM_2_BASE +#define IP_STM_3_BASE IP_RTU0__STM_0_BASE +#define IP_STM_4_BASE IP_RTU0__STM_1_BASE +#define IP_STM_5_BASE IP_RTU0__STM_2_BASE +#define IP_STM_6_BASE IP_RTU0__STM_3_BASE +#define IP_STM_7_BASE IP_RTU1__STM_0_BASE +#define IP_STM_8_BASE IP_RTU1__STM_1_BASE +#define IP_STM_9_BASE IP_RTU1__STM_2_BASE +#define IP_STM_10_BASE IP_RTU1__STM_3_BASE +#define IP_STM_11_BASE IP_SMU__STM_0_BASE +#define IP_STM_12_BASE IP_SMU__STM_2_BASE + #endif /* _NXP_S32_S32ZE_SOC_H_ */ From ade72c2b3a193aad36d0830cc2c90495ce7cd6b7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Sep 2023 17:30:59 +0200 Subject: [PATCH 0166/1049] llext: remove a superfluous variable initialisation ret in llext_load() is always assigned before use, remove its redundant initialisation. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 9e3cbd79990f2bc..83f05f121c59b81 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -635,7 +635,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) { - int ret = 0; + int ret; elf_ehdr_t ehdr; ret = llext_seek(ldr, 0); From f0527b5571e947092457859e22d2426e780d9a64 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 7 Sep 2023 16:51:50 +0200 Subject: [PATCH 0167/1049] llext: add a weak arch_elf_relocate() stub The module linking API can be used for shared objects with no architecture-specific relocation code. Add a weak function for such cases. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 83f05f121c59b81..d46e021b894180b 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -403,6 +403,10 @@ static inline int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext return ret; } +__weak void arch_elf_relocate(elf_rel_t *rel, uintptr_t opaddr, uintptr_t opval) +{ +} + static int llext_link(struct llext_loader *ldr, struct llext *ext) { int ret = 0; From 6185da5d716fe5eb9493385e7879feb1c74fb031 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Sep 2023 10:22:58 +0200 Subject: [PATCH 0168/1049] llext: fix a typo in elf_rel_t 64-bit definition struct elf64_rela is undefined, use the correct structure name. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/llext/elf.h b/include/zephyr/llext/elf.h index 1e83142dcd3a4f3..6e2b62986dda149 100644 --- a/include/zephyr/llext/elf.h +++ b/include/zephyr/llext/elf.h @@ -435,7 +435,7 @@ typedef elf64_half elf_half; /** Machine sized integer */ typedef elf64_xword elf_word; /** Machine sized relocation struct */ -typedef struct elf64_rela elf_rel_t; +typedef struct elf64_rel elf_rel_t; /** Machine sized symbol struct */ typedef struct elf64_sym elf_sym_t; /** Machine sized macro alias for obtaining a relocation symbol */ From bca88b4b3a9d35d3ff47e6a41c0f6a2e5e0f6647 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Sep 2023 15:00:52 +0200 Subject: [PATCH 0169/1049] llext: fix exporting objects When exporting a symbol, we need to use "&" explicitly, otherwise it only works for functions and doesn't work for objects. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/symbol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/llext/symbol.h b/include/zephyr/llext/symbol.h index c7f7b829902f54a..b1aef67413e9d3c 100644 --- a/include/zephyr/llext/symbol.h +++ b/include/zephyr/llext/symbol.h @@ -75,7 +75,7 @@ struct llext_symtable { */ #define EXPORT_SYMBOL(x) \ static const STRUCT_SECTION_ITERABLE(llext_const_symbol, x ## _sym) = { \ - .name = STRINGIFY(x), .addr = x, \ + .name = STRINGIFY(x), .addr = &x, \ } /** From a9a82d557c72c615ede2fe1009c38b14a55c9e55 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Sep 2023 15:40:26 +0200 Subject: [PATCH 0170/1049] llext: use elf_rela_t instead of elf_rel_t elf_rela_t contains elf_rel_t exactly and contains an additional field at the end. Therefore pointers of that type can be used for both types, making the code generic. Signed-off-by: Guennadi Liakhovetski --- arch/arm/core/elf.c | 2 +- include/zephyr/llext/elf.h | 14 ++++++++++++++ include/zephyr/llext/llext.h | 2 +- subsys/llext/llext.c | 4 ++-- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/arch/arm/core/elf.c b/arch/arm/core/elf.c index 0a7aa6544794841..e16af6199e63ef9 100644 --- a/arch/arm/core/elf.c +++ b/arch/arm/core/elf.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL); * The relocation codes for arm are well documented * https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#relocation */ -void arch_elf_relocate(elf_rel_t *rel, uintptr_t opaddr, uintptr_t opval) +void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval) { elf_word reloc_type = ELF32_R_TYPE(rel->r_info); diff --git a/include/zephyr/llext/elf.h b/include/zephyr/llext/elf.h index 6e2b62986dda149..6dc3cc4e5c8e607 100644 --- a/include/zephyr/llext/elf.h +++ b/include/zephyr/llext/elf.h @@ -306,6 +306,12 @@ struct elf32_rel { elf32_word r_info; }; +struct elf32_rela { + elf32_addr r_offset; + elf32_word r_info; + elf32_word r_addend; +}; + /** * @brief Relocation symbol index from r_info * @@ -330,6 +336,12 @@ struct elf64_rel { elf64_xword r_info; }; +struct elf64_rela { + elf64_addr r_offset; + elf64_word r_info; + elf64_word r_addend; +}; + /** @brief Relocation symbol from r_info * * @param i Value of r_info @@ -436,6 +448,7 @@ typedef elf64_half elf_half; typedef elf64_xword elf_word; /** Machine sized relocation struct */ typedef struct elf64_rel elf_rel_t; +typedef struct elf64_rela elf_rela_t; /** Machine sized symbol struct */ typedef struct elf64_sym elf_sym_t; /** Machine sized macro alias for obtaining a relocation symbol */ @@ -461,6 +474,7 @@ typedef elf32_half elf_half; typedef elf32_word elf_word; /** Machine sized relocation struct */ typedef struct elf32_rel elf_rel_t; +typedef struct elf32_rela elf_rela_t; /** Machine sized symbol struct */ typedef struct elf32_sym elf_sym_t; /** Machine sized macro alias for obtaining a relocation symbol */ diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 6afb48682be5e2b..33feba50bd522e3 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -135,7 +135,7 @@ int llext_call_fn(struct llext *ext, const char *sym_name); * @param[in] opaddr Address of operation to rewrite with relocation * @param[in] opval Value of looked up symbol to relocate */ -void arch_elf_relocate(elf_rel_t *rel, uintptr_t opaddr, uintptr_t opval); +void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval); /** * @} diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index d46e021b894180b..24f48414ad8a2c4 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -403,7 +403,7 @@ static inline int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext return ret; } -__weak void arch_elf_relocate(elf_rel_t *rel, uintptr_t opaddr, uintptr_t opval) +__weak void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval) { } @@ -412,7 +412,7 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) int ret = 0; uintptr_t loc = 0; elf_shdr_t shdr; - elf_rel_t rel; + elf_rela_t rel; elf_sym_t sym; size_t pos = ldr->hdr.e_shoff; elf_word rel_cnt = 0; From 3508cd609c9e13b21b10d592ee4ef5f3817f787e Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Thu, 9 Nov 2023 11:33:31 +0100 Subject: [PATCH 0171/1049] net: openthread: upmerge to `6edb06e` Regular OpenThread upmerge to `6edb06e`. Also add `OPENTHREAD_CSL_RECEIVER_LOCAL_TIME_SYNC` config. Signed-off-by: Eduardo Montoya --- modules/openthread/CMakeLists.txt | 6 ++++++ modules/openthread/Kconfig.features | 7 +++++++ west.yml | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 826d9b3159057a8..bad6d131771747f 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -148,6 +148,12 @@ else() set(OT_CSL_RECEIVER OFF CACHE BOOL "Enable CSL receiver feature for Thread 1.2" FORCE) endif() +if(CONFIG_OPENTHREAD_CSL_RECEIVER_LOCAL_TIME_SYNC) + set(OT_CSL_RECEIVER_LOCAL_TIME_SYNC ON CACHE BOOL "Use local time for CSL sync" FORCE) +else() + set(OT_CSL_RECEIVER_LOCAL_TIME_SYNC OFF CACHE BOOL "Use local time for CSL sync" FORCE) +endif() + if(CONFIG_OPENTHREAD_DATASET_UPDATER) set(OT_DATASET_UPDATER ON CACHE BOOL "Enable Dataset updater" FORCE) else() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index 87c220944a49806..a75c9e8fd4886a5 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -92,6 +92,13 @@ config OPENTHREAD_CSL_RECEIVER help Enable CSL Receiver support for Thread 1.2 +config OPENTHREAD_CSL_RECEIVER_LOCAL_TIME_SYNC + bool "Use local time for CSL synchronization" + help + Use host time rather than radio platform time to track elapsed time + since last CSL synchronization. This reduces the usage of radio API + calls, and it is useful for platforms in which those are costly. + config OPENTHREAD_DEVICE_PROP_LEADER_WEIGHT bool "Device props for leader weight" default n if (OPENTHREAD_THREAD_VERSION_1_1 || \ diff --git a/west.yml b/west.yml index 6a9d1e743bbe68c..62194f60c193e2a 100644 --- a/west.yml +++ b/west.yml @@ -301,7 +301,7 @@ manifest: revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 path: modules/lib/open-amp - name: openthread - revision: d62167ee34b091e7025c9ec2820aae71e17a3944 + revision: 6edb06e4e0472411200ce2a084a783eaf3faffe3 path: modules/lib/openthread - name: percepio path: modules/debug/percepio From 1572ea16fc70c7bb0ab681f7b300e798592c7a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 9 Nov 2023 17:36:17 +0700 Subject: [PATCH 0172/1049] drivers: can: nxp_s32_canxl: use instance-based DT macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At present, many of the NXP S32 shim drivers do not make use of devicetree instance-based macros because the NXP S32 HAL relies on an index-based approach, requiring knowledge of the peripheral instance index during both compilation and runtime, and this index might not align with the devicetree instance index. The proposed solution in this patch eliminates this limitation by determining the peripheral instance index during compilation through macrobatics and defining the driver's ISR within the shim driver itself. Signed-off-by: Manuel Argüelles --- drivers/can/can_nxp_s32_canxl.c | 110 ++++++++++++++++--------------- dts/arm/nxp/nxp_s32z27x_r52.dtsi | 4 +- 2 files changed, 60 insertions(+), 54 deletions(-) diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index 9083569f7022f01..211e901055f252a 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -933,6 +933,20 @@ static int can_nxp_s32_init(const struct device *dev) return 0; } +static void can_nxp_s32_isr_rx_tx(const struct device *dev) +{ + const struct can_nxp_s32_config *config = dev->config; + + Canexcel_Ip_RxTxIRQHandler(config->instance); +} + +static void can_nxp_s32_isr_error(const struct device *dev) +{ + const struct can_nxp_s32_config *config = dev->config; + + Canexcel_Ip_ErrIRQHandler(config->instance); +} + static const struct can_driver_api can_nxp_s32_driver_api = { .get_capabilities = can_nxp_s32_get_capabilities, .start = can_nxp_s32_start, @@ -983,19 +997,13 @@ static const struct can_driver_api can_nxp_s32_driver_api = { #endif }; -#define CAN_NXP_S32_NODE(n) DT_NODELABEL(can##n) - -#define CAN_NXP_S32_IRQ_HANDLER(n, irq_name) DT_CAT5(CANXL, n, _, irq_name, Handler) - -#define _CAN_NXP_S32_IRQ_CONFIG(node_id, prop, idx, n) \ +#define _CAN_NXP_S32_IRQ_CONFIG(node_id, prop, idx) \ do { \ - extern void (CAN_NXP_S32_IRQ_HANDLER(n, \ - DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)))(void); \ IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \ DT_IRQ_BY_IDX(node_id, idx, priority), \ - CAN_NXP_S32_IRQ_HANDLER(n, \ + UTIL_CAT(can_nxp_s32_isr_, \ DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)), \ - NULL, \ + DEVICE_DT_GET(node_id), \ DT_IRQ_BY_IDX(node_id, idx, flags)); \ irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); \ } while (false); @@ -1003,15 +1011,14 @@ static const struct can_driver_api can_nxp_s32_driver_api = { #define CAN_NXP_S32_IRQ_CONFIG(n) \ static void can_irq_config_##n(void) \ { \ - DT_FOREACH_PROP_ELEM_VARGS(CAN_NXP_S32_NODE(n), interrupt_names, \ - _CAN_NXP_S32_IRQ_CONFIG, n); \ + DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, _CAN_NXP_S32_IRQ_CONFIG); \ } #define CAN_NXP_S32_ERR_CALLBACK(n) \ void nxp_s32_can_##n##_err_callback(uint8 instance, Canexcel_Ip_EventType eventType,\ uint32 u32SysStatus, const Canexcel_Ip_StateType *canexcelState) \ { \ - const struct device *dev = DEVICE_DT_GET(CAN_NXP_S32_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ can_nxp_s32_err_callback(dev, eventType, u32SysStatus, canexcelState); \ } @@ -1019,18 +1026,18 @@ static const struct can_driver_api can_nxp_s32_driver_api = { void nxp_s32_can_##n##_ctrl_callback(uint8 instance, Canexcel_Ip_EventType eventType,\ uint32 buffIdx, const Canexcel_Ip_StateType *canexcelState) \ { \ - const struct device *dev = DEVICE_DT_GET(CAN_NXP_S32_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ can_nxp_s32_ctrl_callback(dev, eventType, buffIdx, canexcelState); \ } #if defined(CONFIG_CAN_FD_MODE) #define CAN_NXP_S32_TIMING_DATA_CONFIG(n) \ - .bitrate_data = DT_PROP(CAN_NXP_S32_NODE(n), bus_speed_data), \ - .sjw_data = DT_PROP(CAN_NXP_S32_NODE(n), sjw_data), \ - .prop_seg_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), prop_seg_data, 0), \ - .phase_seg1_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg1_data, 0), \ - .phase_seg2_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg2_data, 0), \ - .sample_point_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), sample_point_data, 0), + .bitrate_data = DT_INST_PROP(n, bus_speed_data), \ + .sjw_data = DT_INST_PROP(n, sjw_data), \ + .prop_seg_data = DT_INST_PROP_OR(n, prop_seg_data, 0), \ + .phase_seg1_data = DT_INST_PROP_OR(n, phase_seg1_data, 0), \ + .phase_seg2_data = DT_INST_PROP_OR(n, phase_seg2_data, 0), \ + .sample_point_data = DT_INST_PROP_OR(n, sample_point_data, 0), #define CAN_NXP_S32_FD_MODE 1 #define CAN_NXP_S32_BRS 1 #else @@ -1045,11 +1052,17 @@ static const struct can_driver_api can_nxp_s32_driver_api = { #define CAN_NXP_S32_CTRL_OPTIONS 0 #endif +#define CAN_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_CANXL_##i##__SIC_BASE) ? i : 0) + +#define CAN_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET CANXL_SIC_INSTANCE_COUNT, CAN_NXP_S32_HW_INSTANCE_CHECK, (|), n) + #define CAN_NXP_S32_INIT_DEVICE(n) \ CAN_NXP_S32_CTRL_CALLBACK(n) \ CAN_NXP_S32_ERR_CALLBACK(n) \ CAN_NXP_S32_IRQ_CONFIG(n) \ - PINCTRL_DT_DEFINE(CAN_NXP_S32_NODE(n)); \ + PINCTRL_DT_INST_DEFINE(n); \ Canexcel_Ip_ConfigType can_nxp_s32_default_config##n = { \ .rx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_RX, \ .tx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_TX, \ @@ -1069,27 +1082,26 @@ static const struct can_driver_api can_nxp_s32_driver_api = { .rx_msg = rx_msg_##n, \ }; \ static struct can_nxp_s32_config can_nxp_s32_config_##n = { \ - .base_sic = (CANXL_SIC_Type *) \ - DT_REG_ADDR_BY_NAME(CAN_NXP_S32_NODE(n), sic), \ + .base_sic = (CANXL_SIC_Type *)DT_INST_REG_ADDR_BY_NAME(n, sic), \ .base_grp_ctrl = (CANXL_GRP_CONTROL_Type *) \ - DT_REG_ADDR_BY_NAME(CAN_NXP_S32_NODE(n), grp_ctrl), \ + DT_INST_REG_ADDR_BY_NAME(n, grp_ctrl), \ .base_dsc_ctrl = (CANXL_DSC_CONTROL_Type *) \ - DT_REG_ADDR_BY_NAME(CAN_NXP_S32_NODE(n), dsc_ctrl), \ - .instance = n, \ - .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(CAN_NXP_S32_NODE(n))), \ + DT_INST_REG_ADDR_BY_NAME(n, dsc_ctrl), \ + .instance = CAN_NXP_S32_HW_INSTANCE(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = (clock_control_subsys_t) \ - DT_CLOCKS_CELL(CAN_NXP_S32_NODE(n), name), \ - .bitrate = DT_PROP(CAN_NXP_S32_NODE(n), bus_speed), \ - .sjw = DT_PROP(CAN_NXP_S32_NODE(n), sjw), \ - .prop_seg = DT_PROP_OR(CAN_NXP_S32_NODE(n), prop_seg, 0), \ - .phase_seg1 = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg1, 0), \ - .phase_seg2 = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg2, 0), \ - .sample_point = DT_PROP_OR(CAN_NXP_S32_NODE(n), sample_point, 0), \ + DT_INST_CLOCKS_CELL(n, name), \ + .bitrate = DT_INST_PROP(n, bus_speed), \ + .sjw = DT_INST_PROP(n, sjw), \ + .prop_seg = DT_INST_PROP_OR(n, prop_seg, 0), \ + .phase_seg1 = DT_INST_PROP_OR(n, phase_seg1, 0), \ + .phase_seg2 = DT_INST_PROP_OR(n, phase_seg2, 0), \ + .sample_point = DT_INST_PROP_OR(n, sample_point, 0), \ CAN_NXP_S32_TIMING_DATA_CONFIG(n) \ - .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(CAN_NXP_S32_NODE(n), \ + .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(n, \ CAN_NXP_S32_MAX_BITRATE), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(CAN_NXP_S32_NODE(n), phys)), \ - .pin_cfg = PINCTRL_DT_DEV_CONFIG_GET(CAN_NXP_S32_NODE(n)), \ + .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(n, phys)), \ + .pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .can_cfg = (Canexcel_Ip_ConfigType *)&can_nxp_s32_default_config##n, \ .irq_config_func = can_irq_config_##n \ }; \ @@ -1097,19 +1109,13 @@ static const struct can_driver_api can_nxp_s32_driver_api = { { \ return can_nxp_s32_init(dev); \ } \ - CAN_DEVICE_DT_DEFINE(CAN_NXP_S32_NODE(n), \ - can_nxp_s32_##n##_init, \ - NULL, \ - &can_nxp_s32_data_##n, \ - &can_nxp_s32_config_##n, \ - POST_KERNEL, \ - CONFIG_CAN_INIT_PRIORITY, \ - &can_nxp_s32_driver_api); - -#if DT_NODE_HAS_STATUS(CAN_NXP_S32_NODE(0), okay) -CAN_NXP_S32_INIT_DEVICE(0) -#endif - -#if DT_NODE_HAS_STATUS(CAN_NXP_S32_NODE(1), okay) -CAN_NXP_S32_INIT_DEVICE(1) -#endif + CAN_DEVICE_DT_INST_DEFINE(n, \ + can_nxp_s32_##n##_init, \ + NULL, \ + &can_nxp_s32_data_##n, \ + &can_nxp_s32_config_##n, \ + POST_KERNEL, \ + CONFIG_CAN_INIT_PRIORITY, \ + &can_nxp_s32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(CAN_NXP_S32_INIT_DEVICE) diff --git a/dts/arm/nxp/nxp_s32z27x_r52.dtsi b/dts/arm/nxp/nxp_s32z27x_r52.dtsi index e26ae43686031a1..4f92c8ca71a0646 100644 --- a/dts/arm/nxp/nxp_s32z27x_r52.dtsi +++ b/dts/arm/nxp/nxp_s32z27x_r52.dtsi @@ -700,7 +700,7 @@ status = "disabled"; interrupts = , ; - interrupt-names = "RX_TX_DATA_IRQ", "INT_ERROR_IRQ"; + interrupt-names = "rx_tx", "error"; clocks = <&clock NXP_S32_P5_CANXL_PE_CLK>; }; @@ -713,7 +713,7 @@ status = "disabled"; interrupts = , ; - interrupt-names = "RX_TX_DATA_IRQ", "INT_ERROR_IRQ"; + interrupt-names = "rx_tx", "error"; clocks = <&clock NXP_S32_P5_CANXL_PE_CLK>; }; }; From 62b01532496d8b4ed7ede7b23bcabf351aaa1aba Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 9 Nov 2023 17:16:28 +0000 Subject: [PATCH 0173/1049] ci: doc-build: only rebase on pull requests Skip the rebase step if it's not a pull request. Schedule and push runs have no base ref to rebase against anyway, currently the step is failing and being skipped. Signed-off-by: Fabio Baltieri --- .github/workflows/doc-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index f4cad6bfa0d6adb..7bfeb25b26a4c48 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -50,6 +50,7 @@ jobs: fetch-depth: 0 - name: Rebase + if: github.event_name == 'pull_request' continue-on-error: true env: BASE_REF: ${{ github.base_ref }} From 35e9104de7a32a1cb2f7083015da0609a89f04b5 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 9 Nov 2023 17:28:26 +0000 Subject: [PATCH 0174/1049] ci: doc-build: add the container owner workaround step Seems like the PDF build hit the "detected dubious ownership in repository" issue that has already been worked around in other workflow. Add that step here as well. Signed-off-by: Fabio Baltieri --- .github/workflows/doc-build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 7bfeb25b26a4c48..fa83fe252c75ab9 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -161,6 +161,10 @@ jobs: cancel-in-progress: true steps: + - name: Apply container owner mismatch workaround + run: | + git config --global --add safe.directory ${GITHUB_WORKSPACE} + - name: checkout uses: actions/checkout@v3 From d291ef457702e1adbcb6c1ab95e6de50a9dab641 Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Fri, 3 Nov 2023 15:01:58 -0500 Subject: [PATCH 0175/1049] doc: charger: Removes misleading statement at introduction Removes a statement at the introduction claiming only getting properties is supported by the API. The charger API can get/set properties. Signed-off-by: Ricardo Rivera-Matos --- doc/hardware/peripherals/charger.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/hardware/peripherals/charger.rst b/doc/hardware/peripherals/charger.rst index a3e2c177e3eeee1..6158eaacdc85c49 100644 --- a/doc/hardware/peripherals/charger.rst +++ b/doc/hardware/peripherals/charger.rst @@ -3,8 +3,7 @@ Chargers ######## -The charger subsystem exposes an API to uniformly access battery charger devices. Currently, -only reading data is supported. +The charger subsystem exposes an API to uniformly access battery charger devices. Basic Operation *************** From 2253ba571bb330900e599b1ed363e27837956ab0 Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Fri, 3 Nov 2023 15:06:42 -0500 Subject: [PATCH 0176/1049] docs: charger: Corrects text in the Properties section Correct Properties subsection of the document to be accurate to the latest implementation of the charger API. Signed-off-by: Ricardo Rivera-Matos --- doc/hardware/peripherals/charger.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/hardware/peripherals/charger.rst b/doc/hardware/peripherals/charger.rst index 6158eaacdc85c49..b88876058b8f8ea 100644 --- a/doc/hardware/peripherals/charger.rst +++ b/doc/hardware/peripherals/charger.rst @@ -17,8 +17,8 @@ measure. Chargers typically support multiple properties, such as temperature readings of the battery-pack or present-time current/voltage. -Properties are fetched using a client allocated array of :c:struct:`charger_get_property`. This -array is then populated by values as according to its `property_type` field. +Properties are fetched by the client one at a time using :c:func:`charger_get_prop`. +Properties are set by the client one at a time using :c:func:`charger_set_prop`. .. _charger_api_reference: From 1a0b1124c6294b9f3851b54fc7d0aeeba12a5f34 Mon Sep 17 00:00:00 2001 From: Ricardo Rivera-Matos Date: Thu, 9 Nov 2023 11:17:22 -0600 Subject: [PATCH 0177/1049] MAINTAINERS: charger: Adds entry for "Chargers" Adds an entry for the charging API. Signed-off-by: Ricardo Rivera-Matos --- MAINTAINERS.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 883f9afed53aa7f..b65679cb6a1bb94 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -840,6 +840,20 @@ Release Notes: labels: - "area: CAN" +"Drivers: Charger": + status: maintained + maintainers: + - aaronemassey + - rriveramcrus + files: + - drivers/charger/ + - dts/bindings/charger/ + - include/zephyr/drivers/charger.h + - tests/drivers/charger/ + - doc/hardware/peripherals/charger.rst + labels: + - "area: Charger" + "Drivers: Clock control": status: maintained maintainers: From 38373aa599d884fedfbc94a921a0179cb8097384 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 9 Nov 2023 17:10:54 -0500 Subject: [PATCH 0178/1049] riscv: FPU trap: catch fused multiply-add instructions The FMADD, FMSUB, FNMSUB and FNMADD instructions occupy major opcode spaces of their own, separate from LOAD-FP/STORE-FP and OP-FP spaces. Insert code to cover them. Signed-off-by: Nicolas Pitre --- arch/riscv/core/isr.S | 17 +++++++++++++-- tests/arch/riscv/fpu_sharing/src/main.c | 28 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/arch/riscv/core/isr.S b/arch/riscv/core/isr.S index ab90d2b1d1e50d9..c36679ae6db9fef 100644 --- a/arch/riscv/core/isr.S +++ b/arch/riscv/core/isr.S @@ -187,10 +187,23 @@ SECTION_FUNC(exception.entry, _isr_wrapper) 1: #endif andi t0, t2, 0x7f /* keep only the opcode bits */ + /* + * Major FP opcodes: + * 0000111 = LOAD-FP + * 0100111 = STORE-FP + * 1000011 = MADD + * 1000111 = MSUB + * 1001011 = NMSUB + * 1001111 = NMADD + * 1010011 = OP-FP + */ xori t1, t0, 0b1010011 /* OP-FP */ beqz t1, is_fp - ori t0, t0, 0b0100000 - xori t1, t0, 0b0100111 /* LOAD-FP / STORE-FP */ + ori t1, t0, 0b0100000 + xori t1, t1, 0b0100111 /* LOAD-FP / STORE-FP */ + beqz t1, is_fp + ori t1, t0, 0b0001100 + xori t1, t1, 0b1001111 /* MADD / MSUB / NMSUB / NMADD */ beqz t1, is_fp /* * The FRCSR, FSCSR, FRRM, FSRM, FSRMI, FRFLAGS, FSFLAGS and FSFLAGSI diff --git a/tests/arch/riscv/fpu_sharing/src/main.c b/tests/arch/riscv/fpu_sharing/src/main.c index db44fe34c47901d..1884adde313f9bf 100644 --- a/tests/arch/riscv/fpu_sharing/src/main.c +++ b/tests/arch/riscv/fpu_sharing/src/main.c @@ -417,6 +417,34 @@ ZTEST(riscv_fpu_sharing, test_fp_insn_trap) "got %#llx instead", buf64); #endif #endif /* CONFIG_RISCV_ISA_EXT_C */ + + /* MADD major opcode space */ + reg = 3579; + TEST_TRAP("fcvt.s.w fa1, %0"); + TEST_TRAP("fmadd.s fa0, fa1, fa1, fa1"); + TEST_TRAP("fcvt.w.s %0, fa0"); + zassert_true(reg == 12812820, "got %ld instead", reg); + + /* NMSUB major opcode space */ + reg = 1234; + TEST_TRAP("fcvt.s.w fa1, %0"); + TEST_TRAP("fmsub.s fa0, fa1, fa1, fa0"); + TEST_TRAP("fcvt.w.s %0, fa0"); + zassert_true(reg == -11290064, "got %ld instead", reg); + + /* NMSUB major opcode space */ + reg = -23; + TEST_TRAP("fcvt.s.w fa1, %0"); + TEST_TRAP("fnmsub.s fa0, fa1, fa1, fa0"); + TEST_TRAP("fcvt.w.s %0, fa0"); + zassert_true(reg == -11290593, "got %ld instead", reg); + + /* NMADD major opcode space */ + reg = 765; + TEST_TRAP("fcvt.s.w fa1, %0"); + TEST_TRAP("fnmadd.s fa0, fa1, fa1, fa1"); + TEST_TRAP("fcvt.w.s %0, fa0"); + zassert_true(reg == -585990, "got %ld instead", reg); } ZTEST_SUITE(riscv_fpu_sharing, NULL, NULL, NULL, NULL, NULL); From b2fb5706357b2583f41b5049d85ac2a75c606da2 Mon Sep 17 00:00:00 2001 From: Maciej Zagrabski Date: Thu, 9 Nov 2023 21:33:17 +0100 Subject: [PATCH 0179/1049] net: wifi: Pass psk and sae as const There shouldn't be any reason to be able to modify the passed psk, and having this non-const gives application warnings if passing a constant string. Signed-off-by: Maciej Zagrabski --- include/zephyr/net/wifi_mgmt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index ae5bf27370d4d2d..faf83b42b84081d 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -302,11 +302,11 @@ struct wifi_connect_req_params { /** SSID length */ uint8_t ssid_length; /* Max 32 */ /** Pre-shared key */ - uint8_t *psk; + const uint8_t *psk; /** Pre-shared key length */ uint8_t psk_length; /* Min 8 - Max 64 */ /** SAE password (same as PSK but with no length restrictions), optional */ - uint8_t *sae_password; + const uint8_t *sae_password; /** SAE password length */ uint8_t sae_password_length; /* No length restrictions */ /** Frequency band */ From bcaa7c2bdbb3affd0e645c76505aaa3458588f4e Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Thu, 9 Nov 2023 13:14:23 +0200 Subject: [PATCH 0180/1049] boards: arm64: xenvm: read real frequency Read real frequncy from ARM Arch Timer instead of using define 'CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC' which can be incorrect for some run cases. If we run xenvm under qemu we get one frequency, but we can run this build as a DomU for Xen under different real platforms and thus with differenty arch timer frequencies. So, we need to read frequency from the timer registers. Signed-off-by: Mykola Kvach --- boards/arm64/xenvm/xenvm_defconfig | 2 ++ boards/arm64/xenvm/xenvm_gicv3_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/boards/arm64/xenvm/xenvm_defconfig b/boards/arm64/xenvm/xenvm_defconfig index ff8597199e7ad1c..39e8a20767cb270 100644 --- a/boards/arm64/xenvm/xenvm_defconfig +++ b/boards/arm64/xenvm/xenvm_defconfig @@ -16,3 +16,5 @@ CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=n CONFIG_USERSPACE=n + +CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME=y diff --git a/boards/arm64/xenvm/xenvm_gicv3_defconfig b/boards/arm64/xenvm/xenvm_gicv3_defconfig index 59a0c306cb7acc6..7b6b9afa888e1a5 100644 --- a/boards/arm64/xenvm/xenvm_gicv3_defconfig +++ b/boards/arm64/xenvm/xenvm_gicv3_defconfig @@ -15,3 +15,5 @@ CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=n CONFIG_USERSPACE=n + +CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME=y From 4ce5f7ebe118e466d7d69f9a09c22c2d82d08ae2 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Thu, 9 Nov 2023 13:50:31 +0900 Subject: [PATCH 0181/1049] arch: riscv: fix hangup of multicore boot This patch fixes hangup of RISC-V multicore boot. Currently boot sequence uses a riscv_cpu_wake_flag to notify wakeup request for secondary core(s). But initial value of riscv_cpu_wake_flag is undefined, so current mechanism is going to hangup if riscv_cpu_wake_flag and mhartid of secondary core have the same value. This is an example situation of this problem: - hart1: check riscv_cpu_wake_flag (value is 1) and end the loop - hart1: set riscv_cpu_wake_flag to 0 - hart0: set riscv_cpu_wake_flag to 1 hart0 expects it will be changed to 0 by hart1 but it has never happened Note: - hart0's mhartid is 0, hart1's mhartid is 1 - hart0 is main, hart1 is secondary in this example Signed-off-by: Katsuhiro Suzuki --- arch/riscv/core/reset.S | 14 +++++++++++--- arch/riscv/core/smp.c | 7 ++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/arch/riscv/core/reset.S b/arch/riscv/core/reset.S index 094e51b91836e1e..e2faa6fe94d8904 100644 --- a/arch/riscv/core/reset.S +++ b/arch/riscv/core/reset.S @@ -93,16 +93,24 @@ aa_loop: boot_secondary_core: #if CONFIG_MP_MAX_NUM_CPUS > 1 + la t0, riscv_cpu_wake_flag + li t1, -1 + sr t1, 0(t0) + la t0, riscv_cpu_boot_flag + sr zero, 0(t0) + +wait_secondary_wake_flag: la t0, riscv_cpu_wake_flag lr t0, 0(t0) - bne a0, t0, boot_secondary_core + bne a0, t0, wait_secondary_wake_flag /* Set up stack */ la t0, riscv_cpu_sp lr sp, 0(t0) - la t0, riscv_cpu_wake_flag - sr zero, 0(t0) + la t0, riscv_cpu_boot_flag + li t1, 1 + sr t1, 0(t0) j z_riscv_secondary_cpu_init #else j loop_unconfigured_cores diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index 7bcfff6828e3f99..a5499d4e16b6d95 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -17,6 +17,7 @@ volatile struct { } riscv_cpu_init[CONFIG_MP_MAX_NUM_CPUS]; volatile uintptr_t riscv_cpu_wake_flag; +volatile uintptr_t riscv_cpu_boot_flag; volatile void *riscv_cpu_sp; extern void __start(void); @@ -28,7 +29,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, riscv_cpu_init[cpu_num].arg = arg; riscv_cpu_sp = Z_KERNEL_STACK_BUFFER(stack) + sz; - riscv_cpu_wake_flag = _kernel.cpus[cpu_num].arch.hartid; + riscv_cpu_boot_flag = 0U; #ifdef CONFIG_PM_CPU_OPS if (pm_cpu_on(cpu_num, (uintptr_t)&__start)) { @@ -37,8 +38,8 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, } #endif - while (riscv_cpu_wake_flag != 0U) { - ; + while (riscv_cpu_boot_flag == 0U) { + riscv_cpu_wake_flag = _kernel.cpus[cpu_num].arch.hartid; } } From 344d24bcb7f6b5072b67cc7cc9f38556455cb603 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Wed, 8 Nov 2023 11:06:08 -0600 Subject: [PATCH 0182/1049] docs: Better document the DMA API and expectations The DMA API has several expectations for drivers and callers that were underdocumented or undocumented. Better clarify the driver expectations and caller expectations. The DMA API from the caller side is not a portable API and really cannot be as each DMA has unique properties and expectations of memory, peripheral interaction, and features. The API in effect provides a union of all useful DMA functionality drivers have needed in the tree. It can still be a good abstraction, with care, for peripheral devices for vendors where the DMA IP might be very similar but have slight variances. From the driver implementation side expectations around synchronization, state transitions, and memory management for transfer descriptors is now described in documentation rather than solely from me in github review comments. Signed-off-by: Tom Burdick --- doc/hardware/peripherals/dma.rst | 66 ++++++++++++++++++++++++++++++++ include/zephyr/drivers/dma.h | 26 ++++++++++--- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/doc/hardware/peripherals/dma.rst b/doc/hardware/peripherals/dma.rst index 198590905d369cc..53fd18a1aa70d80 100644 --- a/doc/hardware/peripherals/dma.rst +++ b/doc/hardware/peripherals/dma.rst @@ -6,6 +6,72 @@ Direct Memory Access (DMA) Overview ******** +Direct Memory Access (Controller) is a commonly provided type of co-processor that can typically +offload transferring data to and from peripherals and memory. + +The DMA API is not a portable API and really cannot be as each DMA has unique memory requirements, +peripheral interactions, and features. The API in effect provides a union of all useful DMA +functionality drivers have needed in the tree. It can still be a good abstraction, with care, for +peripheral devices for vendors where the DMA IP might be very similar but have slight variances. + +Driver Implementation Expectations +********************************** + +Synchronization and Ownership ++++++++++++++++++++++++++++++ + +From an API point of view, a DMA channel is a single-owner object, meaning the drivers should not +attempt to wrap a channel with kernel synchronization primitives such as mutexes or semaphores. If +DMA channels require mutating shared registers, those register updates should be wrapped in a spin +lock. + +This enables the entire API to be low-cost and callable from any call context, including ISRs where +it may be very useful to start/stop/suspend/resume/reload a channel transfer. + +Transfer Descriptor Memory Management ++++++++++++++++++++++++++++++++++++++ + +Drivers should not attempt to use heap allocations of any kind. If object pools are needed for +transfer descriptors then those should be setup in a way that does not break the promise of +ISR-allowable calls. Many drivers choose to create a simple static descriptor array per channel with +the size of the descriptor array adjustable using Kconfig. + +Channel State Machine Expectations +++++++++++++++++++++++++++++++++++ + +DMA channels should be viewed as state machines that the DMA API provides transition events for in +the form of API calls. Every driver is expected to maintain its own channel state tracking. The busy +state of the channel should be inspectable at any time with :c:func:`dma_get_status()`. + +A diagram showing those expectated possible state transitions and their API calls is provided here +for reference. + +.. graphviz:: + :caption: DMA state finite state machine + + digraph { + node [style=rounded]; + edge [fontname=Courier]; + init [shape=point]; + + CONFIGURED [label=Configured,shape=box]; + RUNNING [label=Running,shape=box]; + SUSPENDED [label=Suspended,shape=box]; + + init -> CONFIGURED [label=dma_config]; + + CONFIGURED -> RUNNING [label=dma_start]; + CONFIGURED -> CONFIGURED [label=dma_stop]; + + RUNNING -> CONFIGURED [label=dma_stop]; + RUNNING -> RUNNING [label=dma_start]; + RUNNING -> RUNNING [label=dma_resume, headport=w]; + RUNNING -> SUSPENDED [label=dma_suspend]; + + SUSPENDED -> SUSPENDED [label=dma_suspend]; + SUSPENDED -> RUNNING [label=dma_resume]; + SUSPENDED -> CONFIGURED [label=dma_stop]; + } API Reference ************* diff --git a/include/zephyr/drivers/dma.h b/include/zephyr/drivers/dma.h index eb04334101d0066..2dd8265150166c3 100644 --- a/include/zephyr/drivers/dma.h +++ b/include/zephyr/drivers/dma.h @@ -386,6 +386,8 @@ static inline int dma_reload(const struct device *dev, uint32_t channel, * Start is allowed on channels that have already been started and must report * success. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel where the transfer will * be processed @@ -412,6 +414,8 @@ static inline int z_impl_dma_start(const struct device *dev, uint32_t channel) * Stop is allowed on channels that have already been stopped and must report * success. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel where the transfer was * being processed @@ -436,6 +440,8 @@ static inline int z_impl_dma_stop(const struct device *dev, uint32_t channel) * Implementations must check the validity of the channel state and ID passed * in and return -EINVAL if either are invalid. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel to suspend * @@ -462,6 +468,8 @@ static inline int z_impl_dma_suspend(const struct device *dev, uint32_t channel) * Implementations must check the validity of the channel state and ID passed * in and return -EINVAL if either are invalid. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel to resume * @@ -488,6 +496,8 @@ static inline int z_impl_dma_resume(const struct device *dev, uint32_t channel) * request DMA channel resources * return -EINVAL if there is no valid channel available. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param filter_param filter function parameter * @@ -531,6 +541,8 @@ static inline int z_impl_dma_request_channel(const struct device *dev, * * release DMA channel resources * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel channel number * @@ -587,6 +599,8 @@ static inline int z_impl_dma_chan_filter(const struct device *dev, * Implementations must check the validity of the channel ID passed in and * return -EINVAL if it is invalid or -ENOSYS if not supported. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel where the transfer was * being processed @@ -616,6 +630,8 @@ static inline int dma_get_status(const struct device *dev, uint32_t channel, * Implementations must check the validity of the type passed in and * return -EINVAL if it is invalid or -ENOSYS if not supported. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param type Numeric identification of the attribute * @param value A non-NULL pointer to the variable where the read value is to be placed @@ -637,7 +653,7 @@ static inline int dma_get_attribute(const struct device *dev, uint32_t type, uin /** * @brief Look-up generic width index to be used in registers * - * WARNING: This look-up works for most controllers, but *may* not work for + * @warning This look-up works for most controllers, but *may* not work for * yours. Ensure your controller expects the most common register * bit values before using this convenience function. If your * controller does not support these values, you will have to write @@ -666,7 +682,7 @@ static inline uint32_t dma_width_index(uint32_t size) /** * @brief Look-up generic burst index to be used in registers * - * WARNING: This look-up works for most controllers, but *may* not work for + * @warning This look-up works for most controllers, but *may* not work for * yours. Ensure your controller expects the most common register * bit values before using this convenience function. If your * controller does not support these values, you will have to write @@ -693,7 +709,7 @@ static inline uint32_t dma_burst_index(uint32_t burst) } /** - * Get the device tree property describing the buffer address alignment + * @brief Get the device tree property describing the buffer address alignment * * Useful when statically defining or allocating buffers for DMA usage where * memory alignment often matters. @@ -704,7 +720,7 @@ static inline uint32_t dma_burst_index(uint32_t burst) #define DMA_BUF_ADDR_ALIGNMENT(node) DT_PROP(node, dma_buf_addr_alignment) /** - * Get the device tree property describing the buffer size alignment + * @brief Get the device tree property describing the buffer size alignment * * Useful when statically defining or allocating buffers for DMA usage where * memory alignment often matters. @@ -715,7 +731,7 @@ static inline uint32_t dma_burst_index(uint32_t burst) #define DMA_BUF_SIZE_ALIGNMENT(node) DT_PROP(node, dma_buf_size_alignment) /** - * Get the device tree property describing the minimal chunk of data possible to be copied + * @brief Get the device tree property describing the minimal chunk of data possible to be copied * * @param node Node identifier, e.g. DT_NODELABEL(dma_0) * @return minimal Minimal chunk of data possible to be copied From 986422f4f2461762ab86c16426381d2db4ab5bb2 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Thu, 9 Nov 2023 09:59:38 -0600 Subject: [PATCH 0183/1049] dma: Move struct member doc comments to fields To better cover the struct fields of the DMA API in doxygen the fields are now individually documented rather than documenting them ad-hoc in the struct header doc comment. A best attempt at marking fields that are HW specific has been done as well. That means almost all of them. Signed-off-by: Tom Burdick --- include/zephyr/drivers/dma.h | 224 +++++++++++++++++++++-------------- 1 file changed, 132 insertions(+), 92 deletions(-) diff --git a/include/zephyr/drivers/dma.h b/include/zephyr/drivers/dma.h index 2dd8265150166c3..2905c6fc43456d4 100644 --- a/include/zephyr/drivers/dma.h +++ b/include/zephyr/drivers/dma.h @@ -28,12 +28,21 @@ extern "C" { * @{ */ +/** + * @brief DMA channel direction + */ enum dma_channel_direction { + /** Memory to memory */ MEMORY_TO_MEMORY = 0x0, + /** Memory to peripheral */ MEMORY_TO_PERIPHERAL, + /** Peripheral to memory */ PERIPHERAL_TO_MEMORY, + /** Peripheral to peripheral */ PERIPHERAL_TO_PERIPHERAL, + /** Host to memory */ HOST_TO_MEMORY, + /** Memory to host */ MEMORY_TO_HOST, /** @@ -53,20 +62,31 @@ enum dma_channel_direction { DMA_CHANNEL_DIRECTION_MAX = 0x7 }; -/** Valid values for @a source_addr_adj and @a dest_addr_adj */ +/** + * @brief DMA address adjustment + * + * Valid values for @a source_addr_adj and @a dest_addr_adj + */ enum dma_addr_adj { + /** Increment the address */ DMA_ADDR_ADJ_INCREMENT, + /** Decrement the address */ DMA_ADDR_ADJ_DECREMENT, + /** No change the address */ DMA_ADDR_ADJ_NO_CHANGE, }; -/* channel attributes */ +/** + * @brief DMA channel attributes + */ enum dma_channel_filter { DMA_CHANNEL_NORMAL, /* normal DMA channel */ DMA_CHANNEL_PERIODIC, /* can be triggered by periodic sources */ }; -/* DMA attributes */ +/** + * @brief DMA attributes + */ enum dma_attribute_type { DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, DMA_ATTR_BUFFER_SIZE_ALIGNMENT, @@ -78,65 +98,73 @@ enum dma_attribute_type { * @struct dma_block_config * @brief DMA block configuration structure. * - * @param source_address is block starting address at source - * @param source_gather_interval is the address adjustment at gather boundary - * @param dest_address is block starting address at destination - * @param dest_scatter_interval is the address adjustment at scatter boundary - * @param dest_scatter_count is the continuous transfer count between scatter - * boundaries - * @param source_gather_count is the continuous transfer count between gather - * boundaries - * - * @param block_size is the number of bytes to be transferred for this block. - * - * @param config is a bit field with the following parts: - * - * source_gather_en [ 0 ] - 0-disable, 1-enable. - * dest_scatter_en [ 1 ] - 0-disable, 1-enable. - * source_addr_adj [ 2 : 3 ] - 00-increment, 01-decrement, - * 10-no change. - * dest_addr_adj [ 4 : 5 ] - 00-increment, 01-decrement, - * 10-no change. - * source_reload_en [ 6 ] - reload source address at the end of - * block transfer - * 0-disable, 1-enable. - * dest_reload_en [ 7 ] - reload destination address at the end - * of block transfer - * 0-disable, 1-enable. - * fifo_mode_control [ 8 : 11 ] - How full of the fifo before transfer - * start. HW specific. - * flow_control_mode [ 12 ] - 0-source request served upon data - * availability. - * 1-source request postponed until - * destination request happens. - * reserved [ 13 : 15 ] + * Aside from source address, destination address, and block size many of these options are hardware + * and driver dependent. */ struct dma_block_config { #ifdef CONFIG_DMA_64BIT + /** block starting address at source */ uint64_t source_address; + /** block starting address at destination */ uint64_t dest_address; #else + /** block starting address at source */ uint32_t source_address; + /** block starting address at destination */ uint32_t dest_address; #endif + /** Address adjustment at gather boundary */ uint32_t source_gather_interval; + /** Address adjustment at scatter boundary */ uint32_t dest_scatter_interval; + /** Continuous transfer count between scatter boundaries */ uint16_t dest_scatter_count; + /** Continuous transfer count between gather boundaries */ uint16_t source_gather_count; + /** Number of bytes to be transferred for this block */ uint32_t block_size; + /** Pointer to next block in a transfer list */ struct dma_block_config *next_block; + /** Enable source gathering when set to 1 */ uint16_t source_gather_en : 1; + /** Enable destination scattering when set to 1 */ uint16_t dest_scatter_en : 1; + /** + * Source address adjustment option + * + * - 0b00 increment + * - 0b01 decrement + * - 0b10 no change + */ uint16_t source_addr_adj : 2; + /** + * Destination address adjustment + * + * - 0b00 increment + * - 0b01 decrement + * - 0b10 no change + */ uint16_t dest_addr_adj : 2; + /** Reload source address at the end of block transfer */ uint16_t source_reload_en : 1; + /** Reload destination address at the end of block transfer */ uint16_t dest_reload_en : 1; + /** FIFO fill before starting transfer, HW specific meaning */ uint16_t fifo_mode_control : 4; + /** + * Transfer flow control mode + * + * - 0b0 source request service upon data availability + * - 0b1 source request postponed until destination request happens + */ uint16_t flow_control_mode : 1; - uint16_t reserved : 3; + + uint16_t _reserved : 3; }; +/** The DMA callback event has occurred at the completion of a transfer list */ #define DMA_STATUS_COMPLETE 0 +/** The DMA callback has occurred at the completion of a single transfer block in a transfer list */ #define DMA_STATUS_BLOCK 1 /** @@ -151,10 +179,11 @@ struct dma_block_config { * @param dev Pointer to the DMA device calling the callback. * @param user_data A pointer to some user data or NULL * @param channel The channel number - * @param status - 0-DMA_STATUS_COMPLETE buffer fully consumed - * - 1-DMA_STATUS_BLOCK buffer consumption reached a configured block + * @param status Status of the transfer + * - DMA_STATUS_COMPLETE buffer fully consumed + * - DMA_STATUS_BLOCK buffer consumption reached a configured block * or water mark - * - a negative errno otherwise + * - A negative errno otherwise */ typedef void (*dma_callback_t)(const struct device *dev, void *user_data, uint32_t channel, int status); @@ -162,86 +191,99 @@ typedef void (*dma_callback_t)(const struct device *dev, void *user_data, /** * @struct dma_config * @brief DMA configuration structure. - * - * @param dma_slot [ 0 : 7 ] - which peripheral and direction - * (HW specific) - * @param channel_direction [ 8 : 10 ] - 000-memory to memory, - * 001-memory to peripheral, - * 010-peripheral to memory, - * 011-peripheral to peripheral, - * 100-host to memory - * 101-memory to host - * ... - * @param complete_callback_en [ 11 ] - 0-callback invoked at completion only - * 1-callback invoked at completion of - * each block - * @param error_callback_en [ 12 ] - 0-error callback enabled - * 1-error callback disabled - * @param source_handshake [ 13 ] - 0-HW, 1-SW - * @param dest_handshake [ 14 ] - 0-HW, 1-SW - * @param channel_priority [ 15 : 18 ] - DMA channel priority - * @param source_chaining_en [ 19 ] - enable/disable source block chaining - * 0-disable, 1-enable - * @param dest_chaining_en [ 20 ] - enable/disable destination block - * chaining. - * 0-disable, 1-enable - * @param linked_channel [ 21 : 27 ] - after channel count exhaust will - * initiate a channel service request - * at this channel - * @param cyclic [ 28 ] - enable/disable cyclic buffer - * 0-disable, 1-enable - * @param reserved [ 29 : 31 ] - * @param source_data_size [ 0 : 15 ] - width of source data (in bytes) - * @param dest_data_size [ 16 : 31 ] - width of dest data (in bytes) - * @param source_burst_length [ 0 : 15 ] - number of source data units - * @param dest_burst_length [ 16 : 31 ] - number of destination data units - * @param block_count is the number of blocks used for block chaining, this - * depends on availability of the DMA controller. - * @param user_data private data from DMA client. - * @param dma_callback see dma_callback_t for details */ struct dma_config { + /** Which peripheral and direction, HW specific */ uint32_t dma_slot : 8; + /** + * Direction the transfers are occurring + * + * - 0b000 memory to memory, + * - 0b001 memory to peripheral, + * - 0b010 peripheral to memory, + * - 0b011 peripheral to peripheral, + * - 0b100 host to memory + * - 0b101 memory to host + * - others hardware specific + */ uint32_t channel_direction : 3; + /** + * Completion callback enable + * + * - 0b0 callback invoked at transfer list completion only + * - 0b1 callback invoked at completion of each block + */ uint32_t complete_callback_en : 1; + /** + * Error callback enable + * + * - 0b0 error callback enabled + * - 0b1 error callback disabled + */ uint32_t error_callback_en : 1; + /** + * Source handshake, HW specific + * + * - 0b0 HW + * - 0b1 SW + */ uint32_t source_handshake : 1; + /** + * Destination handshake, HW specific + * + * - 0b0 HW + * - 0b1 SW + */ uint32_t dest_handshake : 1; + /** + * Channel priority for arbitration, HW specific + */ uint32_t channel_priority : 4; + /** Source chaining enable, HW specific */ uint32_t source_chaining_en : 1; + /** Destination chaining enable, HW specific */ uint32_t dest_chaining_en : 1; + /** Linked channel, HW specific */ uint32_t linked_channel : 7; + /** Cyclic transfer list, HW specific */ uint32_t cyclic : 1; - uint32_t reserved : 3; + + uint32_t _reserved : 3; + /** Width of source data (in bytes) */ uint32_t source_data_size : 16; + /** Width of destination data (in bytes) */ uint32_t dest_data_size : 16; + /** Source burst length in bytes */ uint32_t source_burst_length : 16; + /** Destination burst length in bytes */ uint32_t dest_burst_length : 16; + /** Number of blocks in transfer list */ uint32_t block_count; + /** Pointer to the first block in the transfer list */ struct dma_block_config *head_block; + /** Optional attached user data for callbacks */ void *user_data; + /** Optional callback for completion and error events */ dma_callback_t dma_callback; }; /** * DMA runtime status structure - * - * busy - is current DMA transfer busy or idle - * dir - DMA transfer direction - * pending_length - data length pending to be transferred in bytes - * or platform dependent. - * free - free buffer space - * write_position - write position in a circular dma buffer - * read_position - read position in a circular dma buffer - * */ struct dma_status { + /** Is the current DMA transfer busy or idle */ bool busy; + /** Direction fo the transfer */ enum dma_channel_direction dir; + /** Pending length to be transferred in bytes, HW specific */ uint32_t pending_length; + /** Available buffers space, HW specific */ uint32_t free; + /** Write position in circular DMA buffer, HW specific */ uint32_t write_position; + /** Read position in circular DMA buffer, HW specific */ uint32_t read_position; + /** Total copied, HW specific */ uint64_t total_copied; }; @@ -249,19 +291,17 @@ struct dma_status { * DMA context structure * Note: the dma_context shall be the first member * of DMA client driver Data, got by dev->data - * - * magic - magic code to identify the context - * dma_channels - dma channels - * atomic - driver atomic_t pointer - * */ struct dma_context { + /** magic code to identify the context */ int32_t magic; + /** number of dma channels */ int dma_channels; + /** atomic holding bit flags for each channel to mark as used/unused */ atomic_t *atomic; }; -/* magic code to identify context content */ +/** Magic code to identify context content */ #define DMA_MAGIC 0x47494749 /** From adc30ff29448eab781928fdc4d2b415fe15478a2 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Wed, 8 Nov 2023 17:43:31 +0800 Subject: [PATCH 0184/1049] ITE: drivers/i2c: Bug in build assert when FIFO enable We need to do a build assert for the fifo enable status of 'I2C2'. There is a problem with using instance to obtain property when any one I2C port is not enabled. Signed-off-by: Tim Lin --- drivers/i2c/i2c_ite_it8xxx2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/i2c_ite_it8xxx2.c b/drivers/i2c/i2c_ite_it8xxx2.c index 57f69a6aaeb2bd9..b931a9320302970 100644 --- a/drivers/i2c/i2c_ite_it8xxx2.c +++ b/drivers/i2c/i2c_ite_it8xxx2.c @@ -1255,7 +1255,7 @@ static const struct i2c_driver_api i2c_it8xxx2_driver_api = { * that channel C may encounter wrong register being written due to FIFO2 * byte counter wrong write after channel B's write operation. */ -BUILD_ASSERT((DT_INST_PROP(SMB_CHANNEL_C, fifo_enable) == false), +BUILD_ASSERT((DT_PROP(DT_NODELABEL(i2c2), fifo_enable) == false), "Channel C cannot use FIFO mode."); #endif From ce4cdac3c0b57954caf35a129e8ca96f26ae4ecd Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Sep 2023 17:40:16 +0200 Subject: [PATCH 0185/1049] llext: add llext_peek() The only way so far to access extension images is via a memory buffer. Since this, supposedly, will also be a rather common method, it makes sense to add a method to access extension data quickly by obtaining a pointer instead of copying data into local buffers. Add a llext_peek() method for that. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/buf_loader.h | 4 +++- include/zephyr/llext/loader.h | 14 +++++++++++++- subsys/llext/buf_loader.c | 7 +++++++ subsys/llext/llext.c | 9 +++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/include/zephyr/llext/buf_loader.h b/include/zephyr/llext/buf_loader.h index c75d20e453084f5..5a50e215bd3cefc 100644 --- a/include/zephyr/llext/buf_loader.h +++ b/include/zephyr/llext/buf_loader.h @@ -37,6 +37,7 @@ struct llext_buf_loader { /** @cond ignore */ int llext_buf_read(struct llext_loader *ldr, void *buf, size_t len); int llext_buf_seek(struct llext_loader *ldr, size_t pos); +void *llext_buf_peek(struct llext_loader *ldr, size_t pos); /** @endcond */ /** @@ -49,7 +50,8 @@ int llext_buf_seek(struct llext_loader *ldr, size_t pos); { \ .loader = { \ .read = llext_buf_read, \ - .seek = llext_buf_seek \ + .seek = llext_buf_seek, \ + .peek = llext_buf_peek, \ }, \ .buf = (_buf), \ .len = (_buf_len), \ diff --git a/include/zephyr/llext/loader.h b/include/zephyr/llext/loader.h index db4157168aa6853..915a6278a443a58 100644 --- a/include/zephyr/llext/loader.h +++ b/include/zephyr/llext/loader.h @@ -73,7 +73,19 @@ struct llext_loader { * @retval 0 Success * @retval -errno Error reading (any errno) */ - int (*seek)(struct llext_loader *s, size_t pos); + int (*seek)(struct llext_loader *ldr, size_t pos); + + /** + * @brief Peek at an absolute location + * + * Return a pointer to the buffer at specified offset. + * + * @param[in] ldr Loader + * @param[in] pos Position to obtain a pointer to + * + * @retval pointer into the buffer + */ + void *(*peek)(struct llext_loader *ldr, size_t pos); /** @cond ignore */ elf_ehdr_t hdr; diff --git a/subsys/llext/buf_loader.c b/subsys/llext/buf_loader.c index 1b9fb576e7d6954..d744a85e473066f 100644 --- a/subsys/llext/buf_loader.c +++ b/subsys/llext/buf_loader.c @@ -29,3 +29,10 @@ int llext_buf_seek(struct llext_loader *l, size_t pos) return 0; } + +void *llext_buf_peek(struct llext_loader *l, size_t pos) +{ + struct llext_buf_loader *buf_l = CONTAINER_OF(l, struct llext_buf_loader, loader); + + return (void *)(buf_l->buf + pos); +} diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 24f48414ad8a2c4..50f98654baecf2b 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -31,6 +31,15 @@ static inline int llext_seek(struct llext_loader *l, size_t pos) return l->seek(l, pos); } +static inline void *llext_peek(struct llext_loader *l, size_t pos) +{ + if (l->peek) { + return l->peek(l, pos); + } + + return NULL; +} + static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list); sys_slist_t *llext_list(void) From 0bf08e5775b4664cdef42a1c69785ab644a43462 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 25 Oct 2023 17:05:38 +0200 Subject: [PATCH 0186/1049] llext: use llext_peek() for section pointers Try to use llext_peek() for section pointers. If it's supported and succeeds we don't need to allocate buffers. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/llext.h | 4 ++++ subsys/llext/llext.c | 32 +++++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 33feba50bd522e3..e0ceece0cf83d3f 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -52,6 +53,9 @@ struct llext { /** Lookup table of llext memory regions */ void *mem[LLEXT_MEM_COUNT]; + /** Memory allocated on heap */ + bool mem_on_heap[LLEXT_MEM_COUNT]; + /** Total size of the llext memory usage */ size_t mem_size; diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 50f98654baecf2b..93c03d18aba89b1 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -255,6 +255,14 @@ static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, return 0; } + if (ldr->sects[sect_idx].sh_type != SHT_NOBITS) { + ext->mem[mem_idx] = llext_peek(ldr, ldr->sects[sect_idx].sh_offset); + if (ext->mem[mem_idx]) { + ext->mem_on_heap[mem_idx] = false; + return 0; + } + } + ext->mem[mem_idx] = k_heap_aligned_alloc(&llext_heap, sizeof(uintptr_t), ldr->sects[sect_idx].sh_size, K_NO_WAIT); @@ -263,16 +271,22 @@ static int llext_copy_section(struct llext_loader *ldr, struct llext *ext, } ext->mem_size += ldr->sects[sect_idx].sh_size; - ret = llext_seek(ldr, ldr->sects[sect_idx].sh_offset); - if (ret != 0) { - goto err; - } + if (ldr->sects[sect_idx].sh_type == SHT_NOBITS) { + memset(ext->mem[mem_idx], 0, ldr->sects[sect_idx].sh_size); + } else { + ret = llext_seek(ldr, ldr->sects[sect_idx].sh_offset); + if (ret != 0) { + goto err; + } - ret = llext_read(ldr, ext->mem[mem_idx], ldr->sects[sect_idx].sh_size); - if (ret != 0) { - goto err; + ret = llext_read(ldr, ext->mem[mem_idx], ldr->sects[sect_idx].sh_size); + if (ret != 0) { + goto err; + } } + ext->mem_on_heap[mem_idx] = true; + return 0; err: @@ -633,7 +647,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) if (ret != 0) { LOG_DBG("Failed to load extension, freeing memory..."); for (enum llext_mem mem_idx = 0; mem_idx < LLEXT_MEM_COUNT; mem_idx++) { - if (ext->mem[mem_idx] != NULL) { + if (ext->mem_on_heap[mem_idx]) { k_heap_free(&llext_heap, ext->mem[mem_idx]); } } @@ -714,7 +728,7 @@ void llext_unload(struct llext *ext) sys_slist_find_and_remove(&_llext_list, &ext->_llext_list); for (int i = 0; i < LLEXT_MEM_COUNT; i++) { - if (ext->mem[i] != NULL) { + if (ext->mem_on_heap[i]) { LOG_DBG("freeing memory region %d", i); k_heap_free(&llext_heap, ext->mem[i]); ext->mem[i] = NULL; From 3a95c78545e1f3c20f4c0583ea982cef5b979b53 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Mon, 6 Nov 2023 21:40:18 +0100 Subject: [PATCH 0187/1049] tests: coredump: Enable code coverage Enable code coverage for debug.coredump.logging_backend test. Signed-off-by: Dmitrii Golovanov --- tests/subsys/debug/coredump/src/main.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/subsys/debug/coredump/src/main.c b/tests/subsys/debug/coredump/src/main.c index ace12f8a2966cec..ddad60f92300f00 100644 --- a/tests/subsys/debug/coredump/src/main.c +++ b/tests/subsys/debug/coredump/src/main.c @@ -8,6 +8,23 @@ #include #include +#ifdef CONFIG_COVERAGE_DUMP +#include +#endif + + +void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf) +{ + ARG_UNUSED(pEsf); + + printk("%s is expected; reason = %u; halting ...\n", __func__, reason); + +#ifdef CONFIG_COVERAGE_DUMP + gcov_coverage_dump(); /* LCOV_EXCL_LINE */ +#endif + k_fatal_halt(reason); +} + void func_3(uint32_t *addr) { #if defined(CONFIG_BOARD_M2GL025_MIV) || \ From c88a7b659bc1f9332cf6e363052b7b3031361846 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Mon, 6 Nov 2023 21:42:21 +0100 Subject: [PATCH 0188/1049] tests: coredump: Extend matching patterns Extend test matching patterns and fix cmake project name. Signed-off-by: Dmitrii Golovanov --- tests/subsys/debug/coredump/CMakeLists.txt | 2 +- tests/subsys/debug/coredump/testcase.yaml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/subsys/debug/coredump/CMakeLists.txt b/tests/subsys/debug/coredump/CMakeLists.txt index ecb7d24bb8ff753..2ed92da99af3327 100644 --- a/tests/subsys/debug/coredump/CMakeLists.txt +++ b/tests/subsys/debug/coredump/CMakeLists.txt @@ -3,6 +3,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(hello_world) +project(debug_coredump) target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/debug/coredump/testcase.yaml b/tests/subsys/debug/coredump/testcase.yaml index db407b3d774e641..5b7dde692b1cd90 100644 --- a/tests/subsys/debug/coredump/testcase.yaml +++ b/tests/subsys/debug/coredump/testcase.yaml @@ -14,8 +14,11 @@ tests: type: multi_line regex: - "Coredump: (.*)" + - ">>> ZEPHYR FATAL ERROR " - "E: #CD:BEGIN#" - "E: #CD:5([aA])45([0-9a-fA-F]+)" - "E: #CD:41([0-9a-fA-F]+)" - "E: #CD:4([dD])([0-9a-fA-F]+)" + - "E: #CD:4([dD])([0-9a-fA-F]+)" - "E: #CD:END#" + - "k_sys_fatal_error_handler" From 647207c0248a136ae82ee72c5b7e0cfba6af5966 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Mon, 6 Nov 2023 15:55:16 +0100 Subject: [PATCH 0189/1049] bluetooth: leaudio: Fix missing set of BIG_Encryption In the PTS BASS/SR/CP/BV-19-C test case a client executes Set Broadcast Code operation of Broadcast Audio Scan Control Point characteristic with Broadcast_Code set to an invalid value. After syncing to an ISO stream there is an expected failed attempt to decrypt the stream data, but the host does not set BIG_Encryption value to the expected value 0x03 (BT_BAP_BIG_ENC_STATE_BAD_CODE). Add missing BIG_Encryption state into the failing check. Signed-off-by: Magdalena Kasenberg --- subsys/bluetooth/audio/bap_broadcast_sink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index 86c7076174af8fa..4d2134455b880fe 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -157,7 +157,8 @@ static void update_recv_state_big_cleared(const struct bt_bap_broadcast_sink *si return; } - if (recv_state->encrypt_state == BT_BAP_BIG_ENC_STATE_BCODE_REQ && + if ((recv_state->encrypt_state == BT_BAP_BIG_ENC_STATE_BCODE_REQ || + recv_state->encrypt_state == BT_BAP_BIG_ENC_STATE_DEC) && reason == BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL) { /* Sync failed due to bad broadcast code */ mod_src_param.encrypt_state = BT_BAP_BIG_ENC_STATE_BAD_CODE; From 0b5e48985d3062e9708150e4f6cc04c0c73540f6 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 3 Nov 2023 10:27:57 -0500 Subject: [PATCH 0190/1049] dts: bindings: Add binding for NXP Multirate Timer Add binding for nxp,mrt and nxp,mrt-channel. MRT is NXP multirate timer, a simple timer with multiple independent channels. Signed-off-by: Declan Snyder --- dts/bindings/counter/nxp,mrt-channel.yaml | 15 ++++++++++++ dts/bindings/counter/nxp,mrt.yaml | 28 +++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 dts/bindings/counter/nxp,mrt-channel.yaml create mode 100644 dts/bindings/counter/nxp,mrt.yaml diff --git a/dts/bindings/counter/nxp,mrt-channel.yaml b/dts/bindings/counter/nxp,mrt-channel.yaml new file mode 100644 index 000000000000000..c3ab744fc5a878f --- /dev/null +++ b/dts/bindings/counter/nxp,mrt-channel.yaml @@ -0,0 +1,15 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP Multirate Timer Channel + + Must be a child node of an nxp,mrt compatible node. + +compatible: "nxp,mrt-channel" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/counter/nxp,mrt.yaml b/dts/bindings/counter/nxp,mrt.yaml new file mode 100644 index 000000000000000..e9e05b6c5b5b066 --- /dev/null +++ b/dts/bindings/counter/nxp,mrt.yaml @@ -0,0 +1,28 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Multirate Timer + +compatible: "nxp,mrt" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + num-channels: + type: int + required: true + description: Number of channels on the IP version + + num-bits: + type: int + required: true + description: Timer width in bits of IP version + + clocks: + required: true From c83037ceceb1da6dc1f9c1aa18acf5c90a74b670 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 3 Nov 2023 10:30:14 -0500 Subject: [PATCH 0191/1049] drivers: clock_control_mcux_syscon: Add MRT subsys Add code to handle MRT subsys clock to LPC syscon driver Signed-off-by: Declan Snyder --- .../clock_control/clock_control_mcux_syscon.c | 16 +++++++++++++--- .../dt-bindings/clock/mcux_lpc_syscon_clock.h | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/clock_control/clock_control_mcux_syscon.c b/drivers/clock_control/clock_control_mcux_syscon.c index 2349be21711bbb1..3dcc073954c2fc1 100644 --- a/drivers/clock_control/clock_control_mcux_syscon.c +++ b/drivers/clock_control/clock_control_mcux_syscon.c @@ -19,12 +19,19 @@ static int mcux_lpc_syscon_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system) { #if defined(CONFIG_CAN_MCUX_MCAN) - uint32_t clock_name = (uint32_t)sub_system; - - if (clock_name == MCUX_MCAN_CLK) { + if ((uint32_t)sub_system == MCUX_MCAN_CLK) { CLOCK_EnableClock(kCLOCK_Mcan); } #endif /* defined(CONFIG_CAN_MCUX_MCAN) */ +#if defined(CONFIG_COUNTER_NXP_MRT) + if ((uint32_t)sub_system == MCUX_MRT_CLK) { +#if defined(CONFIG_SOC_FAMILY_LPC) + CLOCK_EnableClock(kCLOCK_Mrt); +#elif defined(CONFIG_SOC_FAMILY_IMX) + CLOCK_EnableClock(kCLOCK_Mrt0); +#endif + } +#endif /* defined(CONFIG_COUNTER_NXP_MRT) */ return 0; } @@ -145,6 +152,9 @@ static int mcux_lpc_syscon_clock_control_get_subsys_rate( break; #endif +#if defined(CONFIG_COUNTER_NXP_MRT) + case MCUX_MRT_CLK: +#endif #if defined(CONFIG_PWM_MCUX_SCTIMER) case MCUX_SCTIMER_CLK: #endif diff --git a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h index 581c5b57e08f709..9f80b662c60b7ae 100644 --- a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h +++ b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h @@ -51,4 +51,6 @@ #define MCUX_SCTIMER_CLK 34 +#define MCUX_MRT_CLK 40 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCUX_LPC_SYSCON_H_ */ From 31722446aa4fa668e38e1d2374a1838d94fd9389 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 3 Nov 2023 10:34:09 -0500 Subject: [PATCH 0192/1049] drivers: counter: Add NXP MRT driver Add driver for NXP Multirate Timer Signed-off-by: Declan Snyder --- drivers/counter/CMakeLists.txt | 5 +- drivers/counter/Kconfig | 2 + drivers/counter/Kconfig.nxp_mrt | 9 + drivers/counter/counter_nxp_mrt.c | 341 ++++++++++++++++++++++++++++++ 4 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 drivers/counter/Kconfig.nxp_mrt create mode 100644 drivers/counter/counter_nxp_mrt.c diff --git a/drivers/counter/CMakeLists.txt b/drivers/counter/CMakeLists.txt index 3a59312da249b22..50a1ffad44193e7 100644 --- a/drivers/counter/CMakeLists.txt +++ b/drivers/counter/CMakeLists.txt @@ -44,7 +44,8 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_INFINEON_CAT1 counter_ifx_cat1 zephyr_library_sources_ifdef(CONFIG_ACE_V1X_ART_COUNTER counter_ace_v1x_art.c) zephyr_library_sources_ifdef(CONFIG_ACE_V1X_RTC_COUNTER counter_ace_v1x_rtc.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_NXP_S32_SYS_TIMER counter_nxp_s32_sys_timer.c) -zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_GD32 counter_gd32_timer.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_GD32 counter_gd32_timer.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_SNPS_DW counter_dw_timer.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_SHELL counter_timer_shell.c) -zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_RPI_PICO counter_rpi_pico_timer.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_RPI_PICO counter_rpi_pico_timer.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_NXP_MRT counter_nxp_mrt.c) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 956c5d59f642ab6..16adaee75b2728a 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -94,4 +94,6 @@ source "drivers/counter/Kconfig.dw" source "drivers/counter/Kconfig.rpi_pico" +source "drivers/counter/Kconfig.nxp_mrt" + endif # COUNTER diff --git a/drivers/counter/Kconfig.nxp_mrt b/drivers/counter/Kconfig.nxp_mrt new file mode 100644 index 000000000000000..a395ada36b459b6 --- /dev/null +++ b/drivers/counter/Kconfig.nxp_mrt @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config COUNTER_NXP_MRT + bool "NXP MRT driver" + default y if DT_HAS_NXP_MRT_CHANNEL_ENABLED && \ + DT_HAS_NXP_MRT_ENABLED + help + Enable driver for the NXP Multirate Timer (MRT). diff --git a/drivers/counter/counter_nxp_mrt.c b/drivers/counter/counter_nxp_mrt.c new file mode 100644 index 000000000000000..741e7b34d40c99f --- /dev/null +++ b/drivers/counter/counter_nxp_mrt.c @@ -0,0 +1,341 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * MRT (Multirate timer) is a lightweight timer with multiple independent channels, each capable + * of signalling the shared interrupt with a different period. This driver treats all the channels + * as separate devices adhering to the counter API. The parent device is responsible for the + * initialization, interrupt handling, and any other module-wide tasks. The current implementation + * of this driver prioritizes minimizing image size over speed, because it is not expected for the + * functions to be called very often, and this IP is mostly present on low memory devices. + */ + +#define DT_DRV_COMPAT nxp_mrt + +#include +#include +#include +#include +#include +#include + +#define LOG_MODULE_NAME counter_mrt +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_COUNTER_LOG_LEVEL); + +/* Device holds a pointer to pointer to data */ +#define MRT_CHANNEL_DATA(dev) \ + (*(struct nxp_mrt_channel_data *const *const)dev->data) + +/* Device config->data is an array of data pointers ordered by channel number, + * dev->data is a pointer to one of these pointers in that array, + * so the value of the dev->data - dev->config->data is the channel index + */ +#define MRT_CHANNEL_ID(dev) \ + (((struct nxp_mrt_channel_data *const *)dev->data) - \ + ((const struct nxp_mrt_config *)dev->config)->data) + +/* Specific for each channel */ +struct nxp_mrt_channel_data { + uint32_t top; + counter_top_callback_t cb; + void *user_data; +}; + +/* Shared between all channels */ +struct nxp_mrt_config { + struct counter_config_info info; + MRT_Type *base; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + void (*irq_config_func)(const struct device *dev); + struct nxp_mrt_channel_data *const *data; + const struct device *const *channels; +}; + +static int nxp_mrt_stop(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + int channel_id = MRT_CHANNEL_ID(dev); + + LOG_DBG("MRT@%p channel %d stopped", base, channel_id); + LOG_WRN("MRT channel resets upon stopping"); + + /* LOAD bit and 0 ivalue allows us to forcibly stop the timer */ + base->CHANNEL[channel_id].INTVAL = MRT_CHANNEL_INTVAL_LOAD(1); + + return 0; +} + +static int nxp_mrt_start(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + struct nxp_mrt_channel_data *data = MRT_CHANNEL_DATA(dev); + int channel_id = MRT_CHANNEL_ID(dev); + + if (data->top <= 1) { + /* Zephyr API says default should be max top value */ + LOG_INF("\"Started\" MRT@%p channel %d with default value %d", + base, channel_id, config->info.max_top_value); + data->top = config->info.max_top_value; + } + + /* Start with previously configured top value (if already running this has no effect) */ + base->CHANNEL[channel_id].INTVAL = data->top; + + LOG_DBG("MRT@%p channel %d started with top value %d", base, channel_id, data->top); + + return 0; +} + +static int nxp_mrt_get_value(const struct device *dev, uint32_t *ticks) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + int channel_id = MRT_CHANNEL_ID(dev); + + *ticks = base->CHANNEL[channel_id].TIMER & MRT_CHANNEL_TIMER_VALUE_MASK; + + return 0; +} + + +static int nxp_mrt_set_top_value(const struct device *dev, const struct counter_top_cfg *cfg) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + struct nxp_mrt_channel_data *data = MRT_CHANNEL_DATA(dev); + int channel_id = MRT_CHANNEL_ID(dev); + /* By default in Zephyr API, the counter resets on changing top value */ + bool reset = !(cfg->flags & COUNTER_TOP_CFG_DONT_RESET); + bool active = base->CHANNEL[channel_id].STAT & MRT_CHANNEL_STAT_RUN_MASK; + uint32_t current_val = base->CHANNEL[channel_id].TIMER & MRT_CHANNEL_TIMER_VALUE_MASK; + int ret = 0; + + /* Store for use by counter_start */ + data->top = cfg->ticks; + + /* Used by ISR */ + data->cb = cfg->callback; + data->user_data = cfg->user_data; + + + /* If not yet started, wait for counter_start because setting reg value starts timer */ + if (!active) { + LOG_DBG("Set MRT@%p channel %d top value to %d", base, channel_id, data->top); + return ret; + } + + /* Otherwise if currently running, need to check for lateness */ + if (cfg->ticks < current_val) { + LOG_WRN("MRT@%p channel %d received requested top value %d which is " + "smaller than current count %d", + base, channel_id, cfg->ticks, current_val); + /* Zephyr API says return this error in case of lateness + * when COUNTER_TOP_CFG_DONT_RESET is set but can still set period + */ + ret = reset ? 0 : -ETIME; + /* If user said not to reset, they can also clarify exception for lateness */ + reset |= cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE; + } + + /* Sets the top value. If we need to reset, LOAD bit does this */ + base->CHANNEL[channel_id].INTVAL = MRT_CHANNEL_INTVAL_IVALUE(cfg->ticks) | + MRT_CHANNEL_INTVAL_LOAD(reset ? 1 : 0); + + LOG_DBG("Changed MRT@%p channel %d top value while active to %d", + base, channel_id, + base->CHANNEL[channel_id].INTVAL & MRT_CHANNEL_INTVAL_IVALUE_MASK); + + return ret; +} + +static uint32_t nxp_mrt_get_top_value(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + int channel_id = MRT_CHANNEL_ID(dev); + + return base->CHANNEL[channel_id].INTVAL & MRT_CHANNEL_INTVAL_IVALUE_MASK; +} + +static uint32_t nxp_mrt_get_pending_int(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + int channel_id = MRT_CHANNEL_ID(dev); + + return base->CHANNEL[channel_id].STAT & MRT_CHANNEL_STAT_INTFLAG_MASK; +} + +static inline int nxp_mrt_set_alarm(const struct device *dev, + uint8_t chan_id, + const struct counter_alarm_cfg *alarm_cfg) +{ + ARG_UNUSED(dev); + ARG_UNUSED(chan_id); + ARG_UNUSED(alarm_cfg); + + LOG_ERR("MRT does not support alarms"); + return -ENOTSUP; +} + +static inline int nxp_mrt_cancel_alarm(const struct device *dev, uint8_t chan_id) +{ + ARG_UNUSED(dev); + ARG_UNUSED(chan_id); + + LOG_ERR("MRT does not support alarms"); + return -ENOTSUP; +} + +uint32_t nxp_mrt_get_freq(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + uint32_t freq; + + clock_control_get_rate(config->clock_dev, config->clock_subsys, &freq); + + return freq; +} + +static int nxp_mrt_init(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + uint32_t num_channels = (base->MODCFG & MRT_MODCFG_NOC_MASK) >> MRT_MODCFG_NOC_SHIFT; + + clock_control_on(config->clock_dev, config->clock_subsys); + + config->irq_config_func(dev); + + /* Enable interrupts for all the channels that have devices */ + for (int i = 0; i < num_channels; i++) { + if (config->channels[i]) { + base->CHANNEL[i].CTRL = MRT_CHANNEL_CTRL_INTEN_MASK; + } + } + + return 0; +} + +static void nxp_mrt_isr(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + uint32_t irq_pends = base->IRQ_FLAG; + uint32_t num_channels = (base->MODCFG & MRT_MODCFG_NOC_MASK) >> MRT_MODCFG_NOC_SHIFT; + + for (int i = 0; i < num_channels; i++) { + /* Channel IRQ pending flags lowest order bits in IRQ_FLAG register */ + if (!(irq_pends & (0x1 << i))) { + continue; + } + + LOG_DBG("Handling interrupt for MRT%p channel %d", base, i); + + /* W1C interrupt flag */ + base->CHANNEL[i].STAT |= MRT_CHANNEL_STAT_INTFLAG_MASK; + + /* Channel devs & pointer path to channel cbs is in shared config */ + if (config->data[i]->cb) { + config->data[i]->cb(config->channels[i], config->data[i]->user_data); + } + } +} + +struct counter_driver_api nxp_mrt_api = { + .get_value = nxp_mrt_get_value, + .start = nxp_mrt_start, + .stop = nxp_mrt_stop, + .set_top_value = nxp_mrt_set_top_value, + .get_top_value = nxp_mrt_get_top_value, + .get_pending_int = nxp_mrt_get_pending_int, + .set_alarm = nxp_mrt_set_alarm, + .cancel_alarm = nxp_mrt_cancel_alarm, + .get_freq = nxp_mrt_get_freq, +}; + +/* Creates a device for a channel (needed for counter API) */ +#define NXP_MRT_CHANNEL_DEV_INIT(node, mrt_inst) \ + DEVICE_DT_DEFINE(node, NULL, NULL, \ + (void *) \ + &nxp_mrt_##mrt_inst##_channel_datas[DT_REG_ADDR(node)], \ + &nxp_mrt_##mrt_inst##_config, \ + POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \ + &nxp_mrt_api); \ + +/* Creates a data struct for a channel device */ +#define NXP_MRT_CHANNEL_DATA_INIT(node) \ + static struct nxp_mrt_channel_data \ + nxp_mrt_channel_data_##node; \ + +/* Initializes an element of the channel data pointer array */ +#define NXP_MRT_CHANNEL_DATA_ARRAY_INIT(node) \ + [DT_REG_ADDR(node)] = \ + &nxp_mrt_channel_data_##node, + +/* Initializes an element of the channel device pointer array */ +#define NXP_MRT_CHANNEL_DEV_ARRAY_INIT(node) \ + [DT_REG_ADDR(node)] = DEVICE_DT_GET(node), + +#define NXP_MRT_INIT(n) \ + /* ISR is shared between all channels */ \ + static void nxp_mrt_##n##_irq_config_func(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + nxp_mrt_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } \ + \ + /* Initialize all the data structs for active channels */ \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, NXP_MRT_CHANNEL_DATA_INIT) \ + \ + /* Create an array of const pointers to the data structs */ \ + static struct nxp_mrt_channel_data *const nxp_mrt_##n##_channel_datas \ + [DT_INST_PROP(n, num_channels)] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, \ + NXP_MRT_CHANNEL_DATA_ARRAY_INIT) \ + }; \ + \ + /* Forward declaration */ \ + const static struct nxp_mrt_config nxp_mrt_##n##_config; \ + \ + /* Create all the channel/counter devices */ \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_VARGS(n, NXP_MRT_CHANNEL_DEV_INIT, n) \ + \ + /* This channel device array is needed by the module device ISR */ \ + const struct device *const nxp_mrt_##n##_channels \ + [DT_INST_PROP(n, num_channels)] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, \ + NXP_MRT_CHANNEL_DEV_ARRAY_INIT) \ + }; \ + \ + /* This config struct is shared by all the channels and parent device */\ + const static struct nxp_mrt_config nxp_mrt_##n##_config = { \ + .info = { \ + .max_top_value = \ + GENMASK(DT_INST_PROP(n, num_bits) - 1, 0), \ + .channels = 0, \ + }, \ + .base = (MRT_Type *)DT_INST_REG_ADDR(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t) \ + DT_INST_CLOCKS_CELL(n, name), \ + .irq_config_func = nxp_mrt_##n##_irq_config_func, \ + .data = nxp_mrt_##n##_channel_datas, \ + .channels = nxp_mrt_##n##_channels, \ + }; \ + \ + /* Init parent device in order to handle ISR and init. */ \ + DEVICE_DT_INST_DEFINE(n, &nxp_mrt_init, NULL, NULL, \ + &nxp_mrt_##n##_config, \ + POST_KERNEL, \ + CONFIG_COUNTER_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(NXP_MRT_INIT) From 8257ff8f6a7639cc8c986ec639d2a075b54f9c72 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 3 Nov 2023 10:34:52 -0500 Subject: [PATCH 0193/1049] tests: counter: Update for NXP MRT Update counter test to test NXP MRT devices Signed-off-by: Declan Snyder --- tests/drivers/counter/counter_basic_api/src/test_counter.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/drivers/counter/counter_basic_api/src/test_counter.c b/tests/drivers/counter/counter_basic_api/src/test_counter.c index 462de26d03750c9..f63ee5ce6c46cf6 100644 --- a/tests/drivers/counter/counter_basic_api/src/test_counter.c +++ b/tests/drivers/counter/counter_basic_api/src/test_counter.c @@ -66,6 +66,9 @@ static const struct device *const devices[] = { #ifdef CONFIG_COUNTER_MCUX_QTMR DEVS_FOR_DT_COMPAT(nxp_imx_tmr) #endif +#ifdef CONFIG_COUNTER_NXP_MRT + DEVS_FOR_DT_COMPAT(nxp_mrt_channel) +#endif #ifdef CONFIG_COUNTER_MCUX_LPC_RTC DEVS_FOR_DT_COMPAT(nxp_lpc_rtc) #endif From ff83745c9aedd36aef035372a76d11d49b7ee3f4 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 3 Nov 2023 10:36:15 -0500 Subject: [PATCH 0194/1049] soc: rt5xx: Enable NXP MRT Enable NXP MRT on RT5xx soc and MIMXRT595_EVK board Signed-off-by: Declan Snyder --- .../arm/mimxrt595_evk/mimxrt595_evk_cm33.dts | 4 +++ dts/arm/nxp/nxp_rt5xx_common.dtsi | 32 +++++++++++++++++++ soc/arm/nxp_imx/rt5xx/soc.c | 4 +++ 3 files changed, 40 insertions(+) diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts index 49dd4f424be44bc..b91a45f500815cf 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts @@ -478,3 +478,7 @@ zephyr_udc0: &usbhs { dmas = <&smartdma>; dma-names = "smartdma"; }; + +&mrt_channel0 { + status = "okay"; +}; diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 3f5319a7401d5f6..8a1a1aa3c3d1dcd 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -578,6 +578,38 @@ #mbox-cells = <1>; status = "disabled"; }; + + mrt: mrt@2d000 { + compatible = "nxp,mrt"; + reg = <0x2d000 0x100>; + interrupts = <9 0>; + num-channels = <4>; + num-bits = <24>; + clocks = <&clkctl1 MCUX_MRT_CLK>; + #address-cells = <1>; + #size-cells = <0>; + + mrt_channel0: mrt_channel@0 { + compatible = "nxp,mrt-channel"; + reg = <0>; + status = "disabled"; + }; + mrt_channel1: mrt_channel@1 { + compatible = "nxp,mrt-channel"; + reg = <1>; + status = "disabled"; + }; + mrt_channel2: mrt_channel@2 { + compatible = "nxp,mrt-channel"; + reg = <2>; + status = "disabled"; + }; + mrt_channel3: mrt_channel@3 { + compatible = "nxp,mrt-channel"; + reg = <3>; + status = "disabled"; + }; + }; }; &flexspi { diff --git a/soc/arm/nxp_imx/rt5xx/soc.c b/soc/arm/nxp_imx/rt5xx/soc.c index 72684393959bad3..f6af227b17cbb05 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.c +++ b/soc/arm/nxp_imx/rt5xx/soc.c @@ -419,6 +419,10 @@ void __weak rt5xx_clock_init(void) CLOCK_SetClkDiv(kCLOCK_DivAdcClk, 1); #endif +#if CONFIG_COUNTER_NXP_MRT + RESET_PeripheralReset(kMRT0_RST_SHIFT_RSTn); +#endif + /* Set SystemCoreClock variable. */ SystemCoreClock = CLOCK_INIT_CORE_CLOCK; From 93c59793c2741d845d9415236cc529ea1f5c290c Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 3 Nov 2023 10:38:16 -0500 Subject: [PATCH 0195/1049] soc: rt6xx: Add NXP MRT Add NXP MRT to RT6xx DT definition and add peripheral reset to soc.c Signed-off-by: Declan Snyder --- dts/arm/nxp/nxp_rt6xx_common.dtsi | 32 +++++++++++++++++++++++++++++++ soc/arm/nxp_imx/rt6xx/soc.c | 4 ++++ 2 files changed, 36 insertions(+) diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index e4acafbafa5f1da..0c81f71d140dabd 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -458,6 +458,38 @@ #address-cells = <3>; #size-cells = <0>; }; + + mrt: mrt@2d000 { + compatible = "nxp,mrt"; + reg = <0x2d000 0x100>; + interrupts = <9 0>; + num-channels = <4>; + num-bits = <24>; + clocks = <&clkctl1 MCUX_MRT_CLK>; + #address-cells = <1>; + #size-cells = <0>; + + mrt_channel0: mrt_channel@0 { + compatible = "nxp,mrt-channel"; + reg = <0>; + status = "disabled"; + }; + mrt_channel1: mrt_channel@1 { + compatible = "nxp,mrt-channel"; + reg = <1>; + status = "disabled"; + }; + mrt_channel2: mrt_channel@2 { + compatible = "nxp,mrt-channel"; + reg = <2>; + status = "disabled"; + }; + mrt_channel3: mrt_channel@3 { + compatible = "nxp,mrt-channel"; + reg = <3>; + status = "disabled"; + }; + }; }; &flexspi { diff --git a/soc/arm/nxp_imx/rt6xx/soc.c b/soc/arm/nxp_imx/rt6xx/soc.c index e04499b289d84ce..2d4eab6854d271d 100644 --- a/soc/arm/nxp_imx/rt6xx/soc.c +++ b/soc/arm/nxp_imx/rt6xx/soc.c @@ -321,6 +321,10 @@ static ALWAYS_INLINE void clock_init(void) flexspi_setup_clock(FLEXSPI, 1U, 9U); #endif +#if CONFIG_COUNTER_NXP_MRT + RESET_PeripheralReset(kMRT0_RST_SHIFT_RSTn); +#endif + /* Set SystemCoreClock variable. */ SystemCoreClock = CLOCK_INIT_CORE_CLOCK; From fef0018ccafb4241b4b788e9dfccd669ba3f47f3 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 3 Nov 2023 10:39:36 -0500 Subject: [PATCH 0196/1049] soc: lpc55xxx: Support, enable, test NXP MRT Support NXP MRT on LPC55XXX SOC series, enable on lpcxpresso55s69_cpu0, add test overlay to counter basic api test Signed-off-by: Declan Snyder --- .../lpcxpresso55s69/lpcxpresso55s69_cpu0.dts | 4 +++ dts/arm/nxp/nxp_lpc55S6x_common.dtsi | 32 +++++++++++++++++++ soc/arm/nxp_lpc/lpc55xxx/soc.c | 4 +++ .../boards/lpcxpresso55s69_cpu0.overlay | 15 +++++++++ 4 files changed, 55 insertions(+) create mode 100644 tests/drivers/counter/counter_basic_api/boards/lpcxpresso55s69_cpu0.overlay diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts index 5b29efecadf2ee4..14ba04fa448deab 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts @@ -204,3 +204,7 @@ i2s1: &flexcomm7 { &dma1 { status = "okay"; }; + +&mrt_channel0 { + status = "okay"; +}; diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index 411f8ac8f5fc56e..5095a96738ff648 100644 --- a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi @@ -410,6 +410,38 @@ prescaler = <2>; #pwm-cells = <3>; }; + + mrt: mrt@d000 { + compatible = "nxp,mrt"; + reg = <0xd000 0x100>; + interrupts = <9 0>; + num-channels = <4>; + num-bits = <24>; + clocks = <&syscon MCUX_MRT_CLK>; + #address-cells = <1>; + #size-cells = <0>; + + mrt_channel0: mrt_channel@0 { + compatible = "nxp,mrt-channel"; + reg = <0>; + status = "disabled"; + }; + mrt_channel1: mrt_channel@1 { + compatible = "nxp,mrt-channel"; + reg = <1>; + status = "disabled"; + }; + mrt_channel2: mrt_channel@2 { + compatible = "nxp,mrt-channel"; + reg = <2>; + status = "disabled"; + }; + mrt_channel3: mrt_channel@3 { + compatible = "nxp,mrt-channel"; + reg = <3>; + status = "disabled"; + }; + }; }; &nvic { diff --git a/soc/arm/nxp_lpc/lpc55xxx/soc.c b/soc/arm/nxp_lpc/lpc55xxx/soc.c index e3620782acb29c9..6730c6cfcff8007 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc55xxx/soc.c @@ -347,6 +347,10 @@ DT_FOREACH_STATUS_OKAY(nxp_lpc_ctimer, CTIMER_CLOCK_SETUP) #endif /* SOC platform */ #endif /* DAC */ +#ifdef CONFIG_COUNTER_NXP_MRT + RESET_PeripheralReset(kMRT_RST_SHIFT_RSTn); +#endif + } /** diff --git a/tests/drivers/counter/counter_basic_api/boards/lpcxpresso55s69_cpu0.overlay b/tests/drivers/counter/counter_basic_api/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 000000000000000..968741c51489244 --- /dev/null +++ b/tests/drivers/counter/counter_basic_api/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,15 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&mrt_channel1 { + status = "okay"; +}; + +/* channel 2 disabled to test disabled channel not breaking things */ + +&mrt_channel3 { + status = "okay"; +}; From f7761883446ef006462a05b3a2fe13dada3065b0 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 1 Nov 2023 13:52:28 +0200 Subject: [PATCH 0197/1049] doc: smbus: Make smbus fully api covered Add file description for full API coverage. Signed-off-by: Andrei Emeltchenko --- include/zephyr/drivers/smbus.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/drivers/smbus.h b/include/zephyr/drivers/smbus.h index b624462f4259704..ccb67a14d4a89e7 100644 --- a/include/zephyr/drivers/smbus.h +++ b/include/zephyr/drivers/smbus.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Public SMBus Driver APIs + */ + #ifndef ZEPHYR_INCLUDE_DRIVERS_SMBUS_H_ #define ZEPHYR_INCLUDE_DRIVERS_SMBUS_H_ From 44e4425ef7e4e96d3c61e6b5bc1ce687f0a1f54c Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 1 Nov 2023 14:09:18 +0200 Subject: [PATCH 0198/1049] doc: edac: Do not include hidden API Exclude hidden API marking them with INTERNAL_HIDDEN. Signed-off-by: Andrei Emeltchenko --- include/zephyr/drivers/edac.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/include/zephyr/drivers/edac.h b/include/zephyr/drivers/edac.h index 34dcb730dc3668d..6a30a0eaef778b8 100644 --- a/include/zephyr/drivers/edac.h +++ b/include/zephyr/drivers/edac.h @@ -16,8 +16,6 @@ #include -typedef void (*edac_notify_callback_f)(const struct device *dev, void *data); - /** * @defgroup edac EDAC API * @ingroup io_interfaces @@ -34,6 +32,14 @@ enum edac_error_type { EDAC_ERROR_TYPE_DRAM_UC = BIT(1) }; +/** + * @cond INTERNAL_HIDDEN + * + * For internal use only, skip these in public documentation. + */ + +typedef void (*edac_notify_callback_f)(const struct device *dev, void *data); + /** * @brief EDAC driver API * @@ -64,6 +70,10 @@ __subsystem struct edac_driver_api { edac_notify_callback_f cb); }; +/** + * INTERNAL_HIDDEN @endcond + */ + /* Optional interfaces */ /** From 1f03bad7cb34326a75c52fd658bba1e621f24eac Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 1 Nov 2023 14:31:37 +0200 Subject: [PATCH 0199/1049] doc: edac: Separate Optional and Mandatory APIs Make documentation more readable by separating API with help of @name instead of simple comment in the code. Signed-off-by: Andrei Emeltchenko --- include/zephyr/drivers/edac.h | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/include/zephyr/drivers/edac.h b/include/zephyr/drivers/edac.h index 6a30a0eaef778b8..bbdd304bb8e2b3c 100644 --- a/include/zephyr/drivers/edac.h +++ b/include/zephyr/drivers/edac.h @@ -74,7 +74,12 @@ __subsystem struct edac_driver_api { * INTERNAL_HIDDEN @endcond */ -/* Optional interfaces */ +/** + * @name Optional interfaces + * @{ + * + * EDAC Optional Interfaces + */ /** * @brief Set injection parameter param1 @@ -241,7 +246,14 @@ static inline int edac_inject_error_trigger(const struct device *dev) return api->inject_error_trigger(dev); } -/* Mandatory interfaces */ +/** @} */ /* End of EDAC Optional Interfaces */ + +/** + * @name Mandatory interfaces + * @{ + * + * EDAC Mandatory Interfaces + */ /** * @brief Get ECC Error Log @@ -398,8 +410,9 @@ static inline int edac_notify_callback_set(const struct device *dev, return api->notify_cb_set(dev, cb); } -/** - * @} - */ + +/** @} */ /* End of EDAC Mandatory Interfaces */ + +/** @} */ /* End of EDAC API */ #endif /* ZEPHYR_INCLUDE_DRIVERS_EDAC_H_ */ From 329ef222dd72ff79c44883f1965eaaf7ec93787a Mon Sep 17 00:00:00 2001 From: Benjamin Deuter Date: Tue, 31 Oct 2023 14:07:50 +0100 Subject: [PATCH 0200/1049] tests: drivers: serial: async: Add support for stm32h735g_disco On the STM32H735G-DK Discovery kit, when connecting a UART from pin PF7 to PF6, the test uart_async_api passes now. Signed-off-by: Benjamin Deuter --- .../boards/stm32h735g_disco.conf | 1 + .../boards/stm32h735g_disco.overlay | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/drivers/uart/uart_async_api/boards/stm32h735g_disco.conf create mode 100644 tests/drivers/uart/uart_async_api/boards/stm32h735g_disco.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/stm32h735g_disco.conf b/tests/drivers/uart/uart_async_api/boards/stm32h735g_disco.conf new file mode 100644 index 000000000000000..24be02d577c416c --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/stm32h735g_disco.conf @@ -0,0 +1 @@ +CONFIG_DCACHE=n diff --git a/tests/drivers/uart/uart_async_api/boards/stm32h735g_disco.overlay b/tests/drivers/uart/uart_async_api/boards/stm32h735g_disco.overlay new file mode 100644 index 000000000000000..58618373e6f48d2 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/stm32h735g_disco.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 STMicroelectronics + * Copyright (c) 2023 Benjamin Deuter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +dut: &uart7 { + dmas = <&dmamux1 2 80 STM32_DMA_PERIPH_TX>, + <&dmamux1 3 79 STM32_DMA_PERIPH_RX>; + dma-names = "tx", "rx"; + pinctrl-0 = <&uart7_tx_pf7 &uart7_rx_pf6>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + +&dma2 { + status = "okay"; +}; + +&dmamux1 { + status = "okay"; +}; From a5d85503fea9f1af0d705ae294ab85446695923a Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 26 Oct 2023 16:26:05 +0800 Subject: [PATCH 0201/1049] boards: riscv: adp_xc7k_ae350: doc: index.rst Due to the west build path in official sample doc is now change to root directory, we modify our west build command align the official sample doc. Signed-off-by: Kevin Wang --- boards/riscv/adp_xc7k_ae350/doc/index.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/boards/riscv/adp_xc7k_ae350/doc/index.rst b/boards/riscv/adp_xc7k_ae350/doc/index.rst index 62cae957f119c9e..c12c04cabc40d94 100644 --- a/boards/riscv/adp_xc7k_ae350/doc/index.rst +++ b/boards/riscv/adp_xc7k_ae350/doc/index.rst @@ -229,6 +229,7 @@ You can build applications in the usual way. Here is an example for the :ref:`hello_world` application. .. zephyr-app-commands:: + :zephyr-app: samples/hello_world :board: adp_xc7k_ae350 :goals: build @@ -264,7 +265,7 @@ and execute it. # Check the ICEman server is running # Load the program into RAM and execute it - riscv64-zephyr-elf-gdb zephyr/zephyr.elf + riscv64-zephyr-elf-gdb build/zephyr/zephyr.elf (gdb) target remote :1111 (gdb) monitor reset halt (gdb) load @@ -278,7 +279,7 @@ and execute it. # Check the ICEman server is running # Burn the program into flash and execute it /bin/target_burn_frontend \ - -P 4444 --unlock --verify --image=zephyr/zephyr.bin \ + -P 4444 --unlock --verify --image=build/zephyr/zephyr.bin \ --algorithm-bin=/target_bin/target_SPI_v5_[32|64].bin # Note: @@ -307,7 +308,7 @@ Debugging # Check the ICEman server is running # Load and debug program - ./riscv64-zephyr-elf-gdb zephyr/zephyr.elf + ./riscv64-zephyr-elf-gdb build/zephyr/zephyr.elf (gdb) target remote :1111 (gdb) monitor reset halt (gdb) load From 5bd18886e96a3deaa56eb8e5360cdd6598f0f2a4 Mon Sep 17 00:00:00 2001 From: Nick Kraus Date: Thu, 12 Oct 2023 23:55:57 -0400 Subject: [PATCH 0202/1049] sam: mdio: Fix Transfer Timeout at Initialization Initialize the MDIO peripheral clock (normally done during GMAC initialization) before trying any MDIO transfers, preventing startup errors. Signed-off-by: Nick Kraus --- drivers/mdio/mdio_sam.c | 19 +++++++++++++++++++ dts/arm/atmel/sam4e.dtsi | 1 + dts/arm/atmel/same70.dtsi | 1 + dts/bindings/mdio/atmel,sam-mdio.yaml | 4 ++++ 4 files changed, 25 insertions(+) diff --git a/drivers/mdio/mdio_sam.c b/drivers/mdio/mdio_sam.c index 078f12c93381a6f..5665057f7c91e41 100644 --- a/drivers/mdio/mdio_sam.c +++ b/drivers/mdio/mdio_sam.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,9 @@ struct mdio_sam_dev_data { struct mdio_sam_dev_config { Gmac * const regs; const struct pinctrl_dev_config *pcfg; +#ifdef CONFIG_SOC_FAMILY_SAM + const struct atmel_sam_pmc_config clock_cfg; +#endif }; static int mdio_transfer(const struct device *dev, uint8_t prtad, uint8_t regad, @@ -140,6 +144,15 @@ static int mdio_sam_initialize(const struct device *dev) k_sem_init(&data->sem, 1, 1); +#ifdef CONFIG_SOC_FAMILY_SAM + /* Enable GMAC module's clock */ + (void) clock_control_on(SAM_DT_PMC_CONTROLLER, (clock_control_subsys_t) &cfg->clock_cfg); +#else + /* Enable MCLK clock on GMAC */ + MCLK->AHBMASK.reg |= MCLK_AHBMASK_GMAC; + *MCLK_GMAC |= MCLK_GMAC_MASK; +#endif + retval = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); return retval; @@ -154,10 +167,16 @@ static const struct mdio_driver_api mdio_sam_driver_api = { .bus_disable = mdio_sam_bus_disable, }; +#define MDIO_SAM_CLOCK(n) \ + COND_CODE_1(CONFIG_SOC_FAMILY_SAM, \ + (.clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(n),), () \ + ) + #define MDIO_SAM_CONFIG(n) \ static const struct mdio_sam_dev_config mdio_sam_dev_config_##n = { \ .regs = (Gmac *)DT_INST_REG_ADDR(n), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + MDIO_SAM_CLOCK(n) \ }; #define MDIO_SAM_DEVICE(n) \ diff --git a/dts/arm/atmel/sam4e.dtsi b/dts/arm/atmel/sam4e.dtsi index 00212c4eaa366c9..2e9e916eef2c671 100644 --- a/dts/arm/atmel/sam4e.dtsi +++ b/dts/arm/atmel/sam4e.dtsi @@ -178,6 +178,7 @@ mdio: mdio@40034000 { compatible = "atmel,sam-mdio"; reg = <0x40034000 0x4000>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 44>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/atmel/same70.dtsi b/dts/arm/atmel/same70.dtsi index 002f0969ebb40f9..8c378d90d0d54bf 100644 --- a/dts/arm/atmel/same70.dtsi +++ b/dts/arm/atmel/same70.dtsi @@ -340,6 +340,7 @@ mdio: mdio@40050000 { compatible = "atmel,sam-mdio"; reg = <0x40050000 0x4000>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 39>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/bindings/mdio/atmel,sam-mdio.yaml b/dts/bindings/mdio/atmel,sam-mdio.yaml index 4eb649b5b24fa21..bc15ad2b76fc8ef 100644 --- a/dts/bindings/mdio/atmel,sam-mdio.yaml +++ b/dts/bindings/mdio/atmel,sam-mdio.yaml @@ -8,3 +8,7 @@ compatible: "atmel,sam-mdio" include: - name: mdio-controller.yaml - name: pinctrl-device.yaml + +properties: + clocks: + type: phandle-array From 318836af23aa1607342a019c01580fd87442f32b Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 9 Nov 2023 18:15:32 +0100 Subject: [PATCH 0203/1049] doc: gsg: macOS: Include instructions to add homebrew to the path Multiple users have failed to read the output from the Homebrew installation script, which instructs the user how to add it to the path. Include the instructions in the guide. Also add a step to include the Homebrew Python executable to the path, which allows then for invocation of python and pip as well as python3 and pip3. Signed-off-by: Carles Cufi --- doc/develop/getting_started/index.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/develop/getting_started/index.rst b/doc/develop/getting_started/index.rst index 35eafb385616499..8a36a6d2732127f 100644 --- a/doc/develop/getting_started/index.rst +++ b/doc/develop/getting_started/index.rst @@ -116,12 +116,32 @@ The current minimum required version for the main dependencies are: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + #. After the Homebrew installation script completes, follow the on-screen + instructions to add the Homebrew installation to the path. + + * On macOS running on Apple Silicon, this is achieved with: + + .. code-block:: bash + + (echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> ~/.zprofile + source ~/.zprofile + + * On macOS running on Intel, use the command for Apple Silicon, but replace ``/opt/homebrew/`` with ``/usr/local/``. + #. Use ``brew`` to install the required dependencies: .. code-block:: bash brew install cmake ninja gperf python3 ccache qemu dtc wget libmagic + #. Add the Homebrew Python folder to the path, in order to be able to + execute ``python`` and ``pip`` as well ``python3`` and ``pip3``. + + .. code-block:: bash + + (echo; echo 'export PATH="'$(brew --prefix)'/opt/python/libexec/bin:$PATH"') >> ~/.zprofile + source ~/.zprofile + .. group-tab:: Windows .. note:: From d817a8ebff2ceac1f3c7e4471b295dc58b0310a0 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 10 Nov 2023 12:19:19 +0200 Subject: [PATCH 0204/1049] drivers: timeaware_gpio: Fix include path Fixes CI after syscall_handler changes path. Signed-off-by: Andrei Emeltchenko --- drivers/misc/timeaware_gpio/timeaware_gpio_intel.c | 2 +- include/zephyr/drivers/misc/timeaware_gpio/timeaware_gpio.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/timeaware_gpio/timeaware_gpio_intel.c b/drivers/misc/timeaware_gpio/timeaware_gpio_intel.c index 5c1933895529287..ae0e519a4378b84 100644 --- a/drivers/misc/timeaware_gpio/timeaware_gpio_intel.c +++ b/drivers/misc/timeaware_gpio/timeaware_gpio_intel.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* TGPIO Register offsets */ #define ART_L 0x00 /* ART lower 32 bit reg */ diff --git a/include/zephyr/drivers/misc/timeaware_gpio/timeaware_gpio.h b/include/zephyr/drivers/misc/timeaware_gpio/timeaware_gpio.h index 68c305f9e1840e7..b65b697f54f3978 100644 --- a/include/zephyr/drivers/misc/timeaware_gpio/timeaware_gpio.h +++ b/include/zephyr/drivers/misc/timeaware_gpio/timeaware_gpio.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #ifdef __cplusplus extern "C" { From 9a44f7f583335e42223ffed2820a213e1b8b65d2 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 9 Nov 2023 16:24:36 +0100 Subject: [PATCH 0205/1049] doc: gsg: Windows: Clarify usage of terminal/cmd.exe Responding to feedback from the community, clarify that the cmd.exe window needs to be closed and reopened. Also be specific about the type of terminal window to be used. Signed-off-by: Carles Cufi --- doc/develop/getting_started/index.rst | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/doc/develop/getting_started/index.rst b/doc/develop/getting_started/index.rst index 8a36a6d2732127f..495a3792b94ce10 100644 --- a/doc/develop/getting_started/index.rst +++ b/doc/develop/getting_started/index.rst @@ -154,8 +154,9 @@ The current minimum required version for the main dependencies are: Therefore, we don't recommend using WSL when getting started. - These instructions must be run in a ``cmd.exe`` command prompt. The - required commands differ on PowerShell. + These instructions must be run in a ``cmd.exe`` command prompt terminal window. + In modern version of Windows (10 and later) it is recommended to install the Windows Terminal + application from the Microsoft Store. The required commands differ on PowerShell. These instructions rely on `Chocolatey`_. If Chocolatey isn't an option, you can install dependencies from their respective websites and ensure @@ -168,9 +169,9 @@ The current minimum required version for the main dependencies are: #. `Install chocolatey`_. - #. Open a ``cmd.exe`` window as **Administrator**. To do so, press the Windows key, - type "cmd.exe", right-click the result, and choose :guilabel:`Run as - Administrator`. + #. Open a ``cmd.exe`` terminal window as **Administrator**. To do so, press the Windows key, + type ``cmd.exe``, right-click the :guilabel:`Command Prompt`` search result, and choose + :guilabel:`Run as Administrator`. #. Disable global confirmation to avoid having to confirm the installation of individual programs: @@ -191,7 +192,7 @@ The current minimum required version for the main dependencies are: As of November 2023, Python 3.12 is not recommended for Zephyr development on Windows, as some required Python dependencies may be difficult to install. - #. Close the window and open a new ``cmd.exe`` window **as a regular user** to continue. + #. Close the terminal window. .. _Chocolatey: https://chocolatey.org/ .. _Install chocolatey: https://chocolatey.org/install @@ -411,6 +412,8 @@ additional Python dependencies. .. group-tab:: Install within virtual environment + #. Open a ``cmd.exe`` terminal window **as a regular user** + #. Create a new virtual environment: .. code-block:: bat @@ -464,6 +467,8 @@ additional Python dependencies. .. group-tab:: Install globally + #. Open a ``cmd.exe`` terminal window **as a regular user** + #. Install west: .. code-block:: bat @@ -618,7 +623,7 @@ that are used to emulate, flash and debug Zephyr applications. .. _windows_zephyr_sdk: - #. Open a ``cmd.exe`` window by pressing the Windows key typing "cmd.exe". + #. Open a ``cmd.exe`` terminal window **as a regular user** #. Download the `Zephyr SDK bundle `_: From ac450be5c80a8ef29f195f5e74d87f1eaaadc935 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 9 Nov 2023 19:04:13 +0000 Subject: [PATCH 0206/1049] i2c: gpio_i2c_switch: fix gpio api misuse Use GPIO_OUTPUT_INACTIVE to initialize the pin so that the ACTIVE_LOW DT flag is honored and use the gpio_pin_set_dt functions to set the (logical) value of the pin instead of gpio_pin_configure_dt, that tries to reconfigure the pin each time. Signed-off-by: Fabio Baltieri --- drivers/i2c/gpio_i2c_switch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/gpio_i2c_switch.c b/drivers/i2c/gpio_i2c_switch.c index 938ed11d769dce0..07183d82e621b07 100644 --- a/drivers/i2c/gpio_i2c_switch.c +++ b/drivers/i2c/gpio_i2c_switch.c @@ -51,13 +51,13 @@ static int gpio_i2c_switch_transfer(const struct device *dev, struct i2c_msg *ms } /* enable switch */ - gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT_HIGH); + gpio_pin_set_dt(&config->gpio, 1); k_busy_wait(GPIO_I2C_TOGGLE_DELAY_US); res = i2c_transfer(config->bus, msgs, num_msgs, addr); /* disable switch */ - gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT_LOW); + gpio_pin_set_dt(&config->gpio, 0); k_busy_wait(GPIO_I2C_TOGGLE_DELAY_US); k_mutex_unlock(&data->lock); @@ -76,7 +76,7 @@ static int gpio_i2c_switch_init(const struct device *dev) k_mutex_init(&data->lock); - return gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT_LOW); + return gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT_INACTIVE); } #define DEFINE_GPIO_I2C_SWITCH(inst) \ From 12e8490b8f0a00428e3bcafab39de8adcdc08ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 10 Nov 2023 11:09:01 +0100 Subject: [PATCH 0207/1049] boards: nxp: doc: Fix typo in imx8mn_evk board specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The M core on this board is an M7, not M47. Fixes #65047. Signed-off-by: Benjamin Cabé --- boards/arm64/mimx8mn_evk/doc/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm64/mimx8mn_evk/doc/index.rst b/boards/arm64/mimx8mn_evk/doc/index.rst index 546df0d5c2d4502..b9620176b6eb1d2 100644 --- a/boards/arm64/mimx8mn_evk/doc/index.rst +++ b/boards/arm64/mimx8mn_evk/doc/index.rst @@ -7,7 +7,7 @@ Overview ******** i.MX8M Nano LPDDR4 EVK board is based on NXP i.MX8M Nano applications -processor, composed of a quad Cortex®-A53 cluster and a single Cortex®-M47 core. +processor, composed of a quad Cortex®-A53 cluster and a single Cortex®-M7 core. Zephyr OS is ported to run on the Cortex®-A53 core. - Board features: From 7a3a6d0c030b3bc99e669797ceb387d404331ce0 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 8 Nov 2023 16:25:52 +0000 Subject: [PATCH 0208/1049] input: convert ite_it8xxx2_kbd driver from kscan to input Convert the ITE keyboard scanning driver from kscan to input, add the corresponding kscan compatibility node to the current board, build test only. Signed-off-by: Fabio Baltieri --- boards/riscv/it82xx2_evb/Kconfig.defconfig | 4 + boards/riscv/it82xx2_evb/it82xx2_evb.dts | 10 +- boards/riscv/it8xxx2_evb/Kconfig.defconfig | 3 + boards/riscv/it8xxx2_evb/it8xxx2_evb.dts | 10 +- drivers/input/CMakeLists.txt | 1 + drivers/input/Kconfig | 1 + drivers/{kscan => input}/Kconfig.it8xxx2 | 30 ++-- .../input_ite_it8xxx2_kbd.c} | 168 ++++++------------ drivers/kscan/CMakeLists.txt | 1 - drivers/kscan/Kconfig | 1 - .../ite,it8xxx2-kbd.yaml} | 2 +- dts/riscv/ite/it8xxx2.dtsi | 4 +- 12 files changed, 94 insertions(+), 141 deletions(-) rename drivers/{kscan => input}/Kconfig.it8xxx2 (56%) rename drivers/{kscan/kscan_ite_it8xxx2.c => input/input_ite_it8xxx2_kbd.c} (77%) rename dts/bindings/{kscan/ite,it8xxx2-kscan.yaml => input/ite,it8xxx2-kbd.yaml} (96%) diff --git a/boards/riscv/it82xx2_evb/Kconfig.defconfig b/boards/riscv/it82xx2_evb/Kconfig.defconfig index eb57ed1843129a2..37d6dc601c9e3af 100644 --- a/boards/riscv/it82xx2_evb/Kconfig.defconfig +++ b/boards/riscv/it82xx2_evb/Kconfig.defconfig @@ -5,4 +5,8 @@ if BOARD_IT82XX2_EVB config BOARD default "it82xx2_evb" + +config INPUT + default y if KSCAN + endif diff --git a/boards/riscv/it82xx2_evb/it82xx2_evb.dts b/boards/riscv/it82xx2_evb/it82xx2_evb.dts index fa8f3090973f5cc..3110363d88a8307 100644 --- a/boards/riscv/it82xx2_evb/it82xx2_evb.dts +++ b/boards/riscv/it82xx2_evb/it82xx2_evb.dts @@ -17,7 +17,7 @@ i2c-0 = &i2c0; peci-0 = &peci0; led0 = &led0; - kscan0 = &kscan0; + kscan0 = &kscan_input; watchdog0 = &twd0; pwm-0 = &pwm0; }; @@ -30,7 +30,7 @@ zephyr,flash = &flash0; zephyr,flash-controller = &flashctrl; zephyr,code-partition = &slot0_partition; - zephyr,keyboard-scan = &kscan0; + zephyr,keyboard-scan = &kscan_input; }; leds { @@ -162,7 +162,7 @@ pinctrl-names = "default"; }; -&kscan0 { +&kbd { status = "okay"; pinctrl-0 = <&ksi0_default &ksi1_default @@ -189,6 +189,10 @@ &kso14_default &kso15_default>; pinctrl-names = "default"; + + kscan_input: kscan-input { + compatible = "zephyr,kscan-input"; + }; }; &peci0 { diff --git a/boards/riscv/it8xxx2_evb/Kconfig.defconfig b/boards/riscv/it8xxx2_evb/Kconfig.defconfig index 588b0dd86412329..8c198316bed90d3 100644 --- a/boards/riscv/it8xxx2_evb/Kconfig.defconfig +++ b/boards/riscv/it8xxx2_evb/Kconfig.defconfig @@ -15,4 +15,7 @@ choice PM_POLICY endchoice endif # PM +config INPUT + default y if KSCAN + endif # BOARD_IT8XXX2_EVB diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts index ffac4a2ed9991cb..73f7ec1b1defb2d 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts @@ -17,7 +17,7 @@ i2c-0 = &i2c0; peci-0 = &peci0; led0 = &led0; - kscan0 = &kscan0; + kscan0 = &kscan_input; watchdog0 = &twd0; pwm-0 = &pwm0; }; @@ -30,7 +30,7 @@ zephyr,flash = &flash0; zephyr,flash-controller = &flashctrl; zephyr,code-partition = &slot0_partition; - zephyr,keyboard-scan = &kscan0; + zephyr,keyboard-scan = &kscan_input; }; leds { @@ -146,7 +146,7 @@ pinctrl-0 = <&tach0a_gpd6_default>; pinctrl-names = "default"; }; -&kscan0 { +&kbd { status = "okay"; pinctrl-0 = <&ksi0_default &ksi1_default @@ -173,6 +173,10 @@ &kso14_default &kso15_default>; pinctrl-names = "default"; + + kscan_input: kscan-input { + compatible = "zephyr,kscan-input"; + }; }; &peci0 { status = "okay"; diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 23da1afa2dbd437..e141652fe48961b 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -9,6 +9,7 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_FT5336 input_ft5336.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_QDEC input_gpio_qdec.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GT911 input_gt911.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT8XXX2_KBD input_ite_it8xxx2_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_KBD_MATRIX input_kbd_matrix.c) zephyr_library_sources_ifdef(CONFIG_INPUT_NPCX_KBD input_npcx_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_STMPE811 input_stmpe811.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index e10aed70e8ba1b5..21401d9dbdb35dd 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -11,6 +11,7 @@ source "drivers/input/Kconfig.ft5336" source "drivers/input/Kconfig.gpio_keys" source "drivers/input/Kconfig.gpio_qdec" source "drivers/input/Kconfig.gt911" +source "drivers/input/Kconfig.it8xxx2" source "drivers/input/Kconfig.kbd_matrix" source "drivers/input/Kconfig.npcx" source "drivers/input/Kconfig.sdl" diff --git a/drivers/kscan/Kconfig.it8xxx2 b/drivers/input/Kconfig.it8xxx2 similarity index 56% rename from drivers/kscan/Kconfig.it8xxx2 rename to drivers/input/Kconfig.it8xxx2 index da5cead4b78930b..bbd9699decc3d4c 100644 --- a/drivers/kscan/Kconfig.it8xxx2 +++ b/drivers/input/Kconfig.it8xxx2 @@ -1,47 +1,47 @@ # Copyright (c) 2021 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -menuconfig KSCAN_ITE_IT8XXX2 - bool "ITE KSCAN driver" +menuconfig INPUT_ITE_IT8XXX2_KBD + bool "ITE keyboard scanning driver" default y - depends on DT_HAS_ITE_IT8XXX2_KSCAN_ENABLED + depends on DT_HAS_ITE_IT8XXX2_KBD_ENABLED select MULTITHREADING help This option enables the ITE keyboard scan driver. -if KSCAN_ITE_IT8XXX2 +if INPUT_ITE_IT8XXX2_KBD -config KSCAN_ITE_IT8XXX2_COLUMN_SIZE - int "KSCAN_ITE_IT8XXX2_COLUMN_SIZE" +config INPUT_ITE_IT8XXX2_COLUMN_SIZE + int "INPUT_ITE_IT8XXX2_COLUMN_SIZE" range 16 18 default 16 help Adjust the value to your keyboard columns. The maximum column size for the ITE family is 18. -config KSCAN_ITE_IT8XXX2_ROW_SIZE - int "KSCAN_ITE_IT8XXX2_ROW_SIZE" +config INPUT_ITE_IT8XXX2_ROW_SIZE + int "INPUT_ITE_IT8XXX2_ROW_SIZE" default 8 help Adjust the value to your keyboard rows. The maximum row size for the ITE family is 8. -config KSCAN_ITE_IT8XXX2_DEBOUNCE_DOWN - int "KSCAN_ITE_IT8XXX2_DEBOUNCE_DOWN" +config INPUT_ITE_IT8XXX2_DEBOUNCE_DOWN + int "INPUT_ITE_IT8XXX2_DEBOUNCE_DOWN" default 9 help Determines the time in msecs for debouncing a key press. -config KSCAN_ITE_IT8XXX2_DEBOUNCE_UP - int "KSCAN_ITE_IT8XXX2_DEBOUNCE_UP" +config INPUT_ITE_IT8XXX2_DEBOUNCE_UP + int "INPUT_ITE_IT8XXX2_DEBOUNCE_UP" default 30 help Determines the time in msecs for debouncing a key release. -config KSCAN_ITE_IT8XXX2_POLL_PERIOD - int "KSCAN_ITE_IT8XXX2_POLL_PERIOD" +config INPUT_ITE_IT8XXX2_POLL_PERIOD + int "INPUT_ITE_IT8XXX2_POLL_PERIOD" default 3 help Defines the poll period in msecs between matrix scans. -endif # KSCAN_ITE_IT8XXX2 +endif diff --git a/drivers/kscan/kscan_ite_it8xxx2.c b/drivers/input/input_ite_it8xxx2_kbd.c similarity index 77% rename from drivers/kscan/kscan_ite_it8xxx2.c rename to drivers/input/input_ite_it8xxx2_kbd.c index 85d47d9d230e203..560f4fdd7d91a4a 100644 --- a/drivers/kscan/kscan_ite_it8xxx2.c +++ b/drivers/input/input_ite_it8xxx2_kbd.c @@ -3,23 +3,22 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT ite_it8xxx2_kscan +#define DT_DRV_COMPAT ite_it8xxx2_kbd +#include +#include +#include #include #include #include -#include #include #include -#include +#include #include -#include -#include #include #include -#define LOG_LEVEL CONFIG_KSCAN_LOG_LEVEL -LOG_MODULE_REGISTER(kscan_ite_it8xxx2); +LOG_MODULE_REGISTER(input_ite_it8xxx2_kbd); #define KEYBOARD_KSI_PIN_COUNT IT8XXX2_DT_INST_WUCCTRL_LEN(0) #define KEYBOARD_COLUMN_DRIVE_ALL -2 @@ -35,26 +34,20 @@ LOG_MODULE_REGISTER(kscan_ite_it8xxx2); /* Thread stack size */ #define TASK_STACK_SIZE 1024 -/* Device config */ -enum kscan_pin_func { - KSO16 = 0, - KSO17, -}; - -struct kscan_wuc_map_cfg { +struct input_it8xxx2_kbd_wuc_map_cfg { /* WUC control device structure */ const struct device *wucs; /* WUC pin mask */ uint8_t mask; }; -struct kscan_it8xxx2_config { +struct input_it8xxx2_kbd_config { /* Keyboard scan controller base address */ struct kscan_it8xxx2_regs *base; /* Keyboard scan input (KSI) wake-up irq */ int irq; /* KSI[7:0] wake-up input source configuration list */ - const struct kscan_wuc_map_cfg *wuc_map_list; + const struct input_it8xxx2_kbd_wuc_map_cfg *wuc_map_list; /* KSI[7:0]/KSO[17:0] keyboard scan alternate configuration */ const struct pinctrl_dev_config *pcfg; /* KSO16 GPIO cells */ @@ -64,18 +57,18 @@ struct kscan_it8xxx2_config { }; /* Device data */ -struct kscan_it8xxx2_data { +struct input_it8xxx2_kbd_data { /* Variables in usec units */ uint32_t deb_time_press; uint32_t deb_time_rel; int32_t poll_timeout; uint32_t poll_period; - uint8_t matrix_stable_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE]; - uint8_t matrix_unstable_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE]; - uint8_t matrix_previous_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE]; + uint8_t matrix_stable_state[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE]; + uint8_t matrix_unstable_state[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE]; + uint8_t matrix_previous_state[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE]; /* Index in to the scan_clock_cycle to indicate start of debouncing */ - uint8_t scan_cycle_idx[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE] - [CONFIG_KSCAN_ITE_IT8XXX2_ROW_SIZE]; + uint8_t scan_cycle_idx[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE] + [CONFIG_INPUT_ITE_IT8XXX2_ROW_SIZE]; /* * Track previous "elapsed clock cycles" per matrix scan. This * is used to calculate the debouncing time for every key @@ -83,9 +76,7 @@ struct kscan_it8xxx2_data { uint8_t scan_clk_cycle[SCAN_OCURRENCES]; struct k_sem poll_lock; uint8_t scan_cycles_idx; - kscan_callback_t callback; struct k_thread thread; - atomic_t enable_scan; /* KSI[7:0] wake-up interrupt status mask */ uint8_t ksi_pin_mask; @@ -94,7 +85,7 @@ struct kscan_it8xxx2_data { static void drive_keyboard_column(const struct device *dev, int col) { - const struct kscan_it8xxx2_config *const config = dev->config; + const struct input_it8xxx2_kbd_config *const config = dev->config; struct kscan_it8xxx2_regs *const inst = config->base; int mask; @@ -112,14 +103,14 @@ static void drive_keyboard_column(const struct device *dev, int col) /* Set KSO[17:0] output data */ inst->KBS_KSOL = (uint8_t) (mask & 0xff); inst->KBS_KSOH1 = (uint8_t) ((mask >> 8) & 0xff); -#if (CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE > 16) +#if (CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE > 16) inst->KBS_KSOH2 = (uint8_t) ((mask >> 16) & 0xff); #endif } static uint8_t read_keyboard_row(const struct device *dev) { - const struct kscan_it8xxx2_config *const config = dev->config; + const struct input_it8xxx2_kbd_config *const config = dev->config; struct kscan_it8xxx2_regs *const inst = config->base; /* Bits are active-low, so toggle it (return 1 means key pressed) */ @@ -143,11 +134,11 @@ static bool is_matrix_ghosting(const uint8_t *state) * w, q and a simultaneously. A block can also be formed, * with not adjacent columns. */ - for (int c = 0; c < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c++) { + for (int c = 0; c < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; c++) { if (!state[c]) continue; - for (int c_n = c + 1; c_n < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c_n++) { + for (int c_n = c + 1; c_n < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; c_n++) { /* * We AND the columns to detect a "block". * this is an indication of ghosting, due to current @@ -172,7 +163,7 @@ static bool read_keyboard_matrix(const struct device *dev, uint8_t *new_state) uint8_t row; uint8_t key_event = 0U; - for (int col = 0; col < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; col++) { + for (int col = 0; col < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; col++) { /* Drive specific column low and others high */ drive_keyboard_column(dev, col); /* Allow the matrix to stabilize before reading it */ @@ -190,8 +181,8 @@ static bool read_keyboard_matrix(const struct device *dev, uint8_t *new_state) static void keyboard_raw_interrupt(const struct device *dev) { - const struct kscan_it8xxx2_config *const config = dev->config; - struct kscan_it8xxx2_data *data = dev->data; + const struct input_it8xxx2_kbd_config *const config = dev->config; + struct input_it8xxx2_kbd_data *data = dev->data; /* * W/C wakeup interrupt status of KSI[7:0] pins @@ -211,8 +202,8 @@ static void keyboard_raw_interrupt(const struct device *dev) void keyboard_raw_enable_interrupt(const struct device *dev, int enable) { - const struct kscan_it8xxx2_config *const config = dev->config; - struct kscan_it8xxx2_data *data = dev->data; + const struct input_it8xxx2_kbd_config *const config = dev->config; + struct input_it8xxx2_kbd_data *data = dev->data; if (enable) { /* @@ -235,8 +226,8 @@ void keyboard_raw_enable_interrupt(const struct device *dev, int enable) static bool check_key_events(const struct device *dev) { - struct kscan_it8xxx2_data *data = dev->data; - uint8_t matrix_new_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE] = {0U}; + struct input_it8xxx2_kbd_data *data = dev->data; + uint8_t matrix_new_state[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE] = {0U}; bool key_pressed = false; uint32_t cycles_now = k_cycle_get_32(); uint8_t row_changed = 0U; @@ -260,7 +251,7 @@ static bool check_key_events(const struct device *dev) * The intent of this loop is to gather information related to key * changes */ - for (int c = 0; c < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c++) { + for (int c = 0; c < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; c++) { /* Check if there was an update from the previous scan */ row_changed = matrix_new_state[c] ^ data->matrix_previous_state[c]; @@ -268,7 +259,7 @@ static bool check_key_events(const struct device *dev) if (!row_changed) continue; - for (int r = 0; r < CONFIG_KSCAN_ITE_IT8XXX2_ROW_SIZE; r++) { + for (int r = 0; r < CONFIG_INPUT_ITE_IT8XXX2_ROW_SIZE; r++) { /* * Index all they keys that changed for each row * in order to debounce each key in terms of it @@ -282,14 +273,14 @@ static bool check_key_events(const struct device *dev) data->matrix_previous_state[c] = matrix_new_state[c]; } - for (int c = 0; c < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c++) { + for (int c = 0; c < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; c++) { deb_col = data->matrix_unstable_state[c]; if (!deb_col) continue; /* Debouncing for each row key occurs here */ - for (int r = 0; r < CONFIG_KSCAN_ITE_IT8XXX2_ROW_SIZE; r++) { + for (int r = 0; r < CONFIG_INPUT_ITE_IT8XXX2_ROW_SIZE; r++) { uint8_t mask = BIT(r); uint8_t row_bit = matrix_new_state[c] & mask; @@ -322,11 +313,10 @@ static bool check_key_events(const struct device *dev) * application about the keys pressed. */ data->matrix_stable_state[c] ^= mask; - if ((atomic_get(&data->enable_scan) == 1U) && - (data->callback != NULL)) { - data->callback(dev, r, c, - row_bit ? true : false); - } + + input_report_abs(dev, INPUT_ABS_X, c, false, K_FOREVER); + input_report_abs(dev, INPUT_ABS_Y, r, false, K_FOREVER); + input_report_key(dev, INPUT_BTN_TOUCH, row_bit, true, K_FOREVER); } } @@ -358,7 +348,7 @@ static bool poll_expired(uint32_t start_cycles, int32_t *timeout) void polling_task(const struct device *dev, void *dummy2, void *dummy3) { - struct kscan_it8xxx2_data *data = dev->data; + struct input_it8xxx2_kbd_data *data = dev->data; int32_t local_poll_timeout = data->poll_timeout; uint32_t current_cycles; uint32_t cycles_delta; @@ -379,7 +369,7 @@ void polling_task(const struct device *dev, void *dummy2, void *dummy3) uint32_t start_poll_cycles = k_cycle_get_32(); - while (atomic_get(&data->enable_scan) == 1U) { + while (true) { uint32_t start_period_cycles = k_cycle_get_32(); if (check_key_events(dev)) { @@ -420,17 +410,17 @@ void polling_task(const struct device *dev, void *dummy2, void *dummy3) } } -static int kscan_it8xxx2_init(const struct device *dev) +static int input_it8xxx2_kbd_init(const struct device *dev) { - const struct kscan_it8xxx2_config *const config = dev->config; - struct kscan_it8xxx2_data *data = dev->data; + const struct input_it8xxx2_kbd_config *const config = dev->config; + struct input_it8xxx2_kbd_data *data = dev->data; struct kscan_it8xxx2_regs *const inst = config->base; int status; /* Disable wakeup and interrupt of KSI pins before configuring */ keyboard_raw_enable_interrupt(dev, 0); -#if (CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE > 16) +#if (CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE > 16) /* * For KSO[16] and KSO[17]: * 1.GPOTRC: @@ -459,7 +449,7 @@ static int kscan_it8xxx2_init(const struct device *dev) /* KSO[17:0] pins output low */ inst->KBS_KSOL = 0x00; inst->KBS_KSOH1 = 0x00; -#if (CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE > 16) +#if (CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE > 16) inst->KBS_KSOH2 = 0x00; #endif @@ -492,22 +482,16 @@ static int kscan_it8xxx2_init(const struct device *dev) /* Kconfig.it8xxx2 time figures are transformed from msec to usec */ data->deb_time_press = - (uint32_t) (CONFIG_KSCAN_ITE_IT8XXX2_DEBOUNCE_DOWN * MS_TO_US); + (uint32_t) (CONFIG_INPUT_ITE_IT8XXX2_DEBOUNCE_DOWN * MS_TO_US); data->deb_time_rel = - (uint32_t) (CONFIG_KSCAN_ITE_IT8XXX2_DEBOUNCE_UP * MS_TO_US); + (uint32_t) (CONFIG_INPUT_ITE_IT8XXX2_DEBOUNCE_UP * MS_TO_US); data->poll_period = - (uint32_t) (CONFIG_KSCAN_ITE_IT8XXX2_POLL_PERIOD * MS_TO_US); + (uint32_t) (CONFIG_INPUT_ITE_IT8XXX2_POLL_PERIOD * MS_TO_US); data->poll_timeout = 100 * MS_TO_US; - /* Init null for callback function */ - data->callback = NULL; - /* Create poll lock semaphore */ k_sem_init(&data->poll_lock, 0, 1); - /* Enable keyboard scan loop */ - atomic_set(&data->enable_scan, 1); - irq_connect_dynamic(DT_INST_IRQN(0), 0, (void (*)(const void *))keyboard_raw_interrupt, (const void *)dev, 0); @@ -522,68 +506,22 @@ static int kscan_it8xxx2_init(const struct device *dev) return 0; } -static int kscan_it8xxx2_configure(const struct device *dev, - kscan_callback_t callback) -{ - struct kscan_it8xxx2_data *data = dev->data; - - if (!callback) { - return -EINVAL; - } - - /* Setup callback function */ - data->callback = callback; - - return 0; -} - -static int kscan_it8xxx2_disable_callback(const struct device *dev) -{ - struct kscan_it8xxx2_data *data = dev->data; - - /* Disable keyboard scan loop */ - atomic_set(&data->enable_scan, 0); - - return 0; -} - -static int kscan_it8xxx2_enable_callback(const struct device *dev) -{ - struct kscan_it8xxx2_data *data = dev->data; - - /* Enable keyboard scan loop */ - atomic_set(&data->enable_scan, 1); - - return 0; -} - -static const struct kscan_driver_api kscan_it8xxx2_driver_api = { - .config = kscan_it8xxx2_configure, - .disable_callback = kscan_it8xxx2_disable_callback, - .enable_callback = kscan_it8xxx2_enable_callback, -}; - -static const struct kscan_wuc_map_cfg kscan_wuc_0[IT8XXX2_DT_INST_WUCCTRL_LEN(0)] = - IT8XXX2_DT_WUC_ITEMS_LIST(0); +static const struct input_it8xxx2_kbd_wuc_map_cfg + input_it8xxx2_kbd_wuc[IT8XXX2_DT_INST_WUCCTRL_LEN(0)] = IT8XXX2_DT_WUC_ITEMS_LIST(0); PINCTRL_DT_INST_DEFINE(0); -static const struct kscan_it8xxx2_config kscan_it8xxx2_cfg_0 = { +static const struct input_it8xxx2_kbd_config input_it8xxx2_kbd_cfg = { .base = (struct kscan_it8xxx2_regs *)DT_INST_REG_ADDR_BY_IDX(0, 0), .irq = DT_INST_IRQN(0), - .wuc_map_list = kscan_wuc_0, + .wuc_map_list = input_it8xxx2_kbd_wuc, .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), .kso16_gpios = GPIO_DT_SPEC_INST_GET(0, kso16_gpios), .kso17_gpios = GPIO_DT_SPEC_INST_GET(0, kso17_gpios), }; -static struct kscan_it8xxx2_data kscan_it8xxx2_kbd_data; +static struct input_it8xxx2_kbd_data input_it8xxx2_kbd_kbd_data; -DEVICE_DT_INST_DEFINE(0, - &kscan_it8xxx2_init, - NULL, - &kscan_it8xxx2_kbd_data, - &kscan_it8xxx2_cfg_0, - POST_KERNEL, - CONFIG_KSCAN_INIT_PRIORITY, - &kscan_it8xxx2_driver_api); +DEVICE_DT_INST_DEFINE(0, &input_it8xxx2_kbd_init, NULL, + &input_it8xxx2_kbd_kbd_data, &input_it8xxx2_kbd_cfg, + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); diff --git a/drivers/kscan/CMakeLists.txt b/drivers/kscan/CMakeLists.txt index d650f17f9171019..005c53ab4b73a09 100644 --- a/drivers/kscan/CMakeLists.txt +++ b/drivers/kscan/CMakeLists.txt @@ -4,7 +4,6 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/kscan.h) zephyr_library() -zephyr_library_sources_ifdef(CONFIG_KSCAN_ITE_IT8XXX2 kscan_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_XEC kscan_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_HT16K33 kscan_ht16k33.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_INPUT kscan_input.c) diff --git a/drivers/kscan/Kconfig b/drivers/kscan/Kconfig index 02ef0987cc68a31..a2a786c31e39e36 100644 --- a/drivers/kscan/Kconfig +++ b/drivers/kscan/Kconfig @@ -10,7 +10,6 @@ menuconfig KSCAN if KSCAN -source "drivers/kscan/Kconfig.it8xxx2" source "drivers/kscan/Kconfig.xec" source "drivers/kscan/Kconfig.ht16k33" source "drivers/kscan/Kconfig.input" diff --git a/dts/bindings/kscan/ite,it8xxx2-kscan.yaml b/dts/bindings/input/ite,it8xxx2-kbd.yaml similarity index 96% rename from dts/bindings/kscan/ite,it8xxx2-kscan.yaml rename to dts/bindings/input/ite,it8xxx2-kbd.yaml index 47a06b44ee37bdf..1aec1e1e7a9a1b7 100644 --- a/dts/bindings/kscan/ite,it8xxx2-kscan.yaml +++ b/dts/bindings/input/ite,it8xxx2-kbd.yaml @@ -3,7 +3,7 @@ description: ITE it8xxx2 keyboard matrix controller -compatible: "ite,it8xxx2-kscan" +compatible: "ite,it8xxx2-kbd" include: [kscan.yaml, pinctrl-device.yaml] diff --git a/dts/riscv/ite/it8xxx2.dtsi b/dts/riscv/ite/it8xxx2.dtsi index 62734db267515ba..454e9c0c1778a94 100644 --- a/dts/riscv/ite/it8xxx2.dtsi +++ b/dts/riscv/ite/it8xxx2.dtsi @@ -691,8 +691,8 @@ status = "disabled"; }; - kscan0: kscan@f01d00 { - compatible = "ite,it8xxx2-kscan"; + kbd: kbd@f01d00 { + compatible = "ite,it8xxx2-kbd"; reg = <0x00f01d00 0x29>; interrupt-parent = <&intc>; interrupts = ; From 678b29386dadeba9090b3518845560eb2b3087fc Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 19 Oct 2023 11:06:37 +0300 Subject: [PATCH 0209/1049] dts: bindings: adxl367: add interrupt support Add int1-gpios property in the adxl367 dts bindings. Signed-off-by: Antoniu Miclaus --- dts/bindings/sensor/adi,adxl367-common.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/bindings/sensor/adi,adxl367-common.yaml b/dts/bindings/sensor/adi,adxl367-common.yaml index 07ffc8ba440e807..722d13d92e07f55 100644 --- a/dts/bindings/sensor/adi,adxl367-common.yaml +++ b/dts/bindings/sensor/adi,adxl367-common.yaml @@ -22,3 +22,10 @@ properties: - 3 - 4 - 5 + + int1-gpios: + type: phandle-array + description: | + The INT1 signal defaults to active high as produced by the + sensor. The property value should ensure the flags properly + describe the signal that is presented to the driver. From af0b6567090d6af78f13ccb96be4076e09f4bafc Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 19 Oct 2023 11:07:09 +0300 Subject: [PATCH 0210/1049] drivers: sensor: adxl367: add trigger support Add trigger support for the adxl367 Zephyr driver. Signed-off-by: Antoniu Miclaus --- drivers/sensor/adxl367/CMakeLists.txt | 1 + drivers/sensor/adxl367/Kconfig | 38 +++++ drivers/sensor/adxl367/adxl367.c | 26 ++++ drivers/sensor/adxl367/adxl367.h | 45 ++++++ drivers/sensor/adxl367/adxl367_trigger.c | 180 +++++++++++++++++++++++ 5 files changed, 290 insertions(+) create mode 100644 drivers/sensor/adxl367/adxl367_trigger.c diff --git a/drivers/sensor/adxl367/CMakeLists.txt b/drivers/sensor/adxl367/CMakeLists.txt index 3dafe9fffbfaee4..1496eb11266d769 100644 --- a/drivers/sensor/adxl367/CMakeLists.txt +++ b/drivers/sensor/adxl367/CMakeLists.txt @@ -8,3 +8,4 @@ zephyr_library() zephyr_library_sources(adxl367.c) zephyr_library_sources(adxl367_spi.c) zephyr_library_sources(adxl367_i2c.c) +zephyr_library_sources_ifdef(CONFIG_ADXL367_TRIGGER adxl367_trigger.c) diff --git a/drivers/sensor/adxl367/Kconfig b/drivers/sensor/adxl367/Kconfig index af77a9e12cb50b2..e0b4660b0f39e58 100644 --- a/drivers/sensor/adxl367/Kconfig +++ b/drivers/sensor/adxl367/Kconfig @@ -92,4 +92,42 @@ config ADXL367_REFERENCED_INACTIVITY_DETECTION_MODE compared directly to a user set threshold to determine whether motion is present. +choice ADXL367_TRIGGER_MODE + prompt "Trigger mode" + default ADXL367_TRIGGER_NONE + help + Specify the type of triggering used by the driver. + +config ADXL367_TRIGGER_NONE + bool "No trigger" + +config ADXL367_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select ADXL367_TRIGGER + +config ADXL367_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select ADXL367_TRIGGER + +endchoice + +config ADXL367_TRIGGER + bool + +config ADXL367_THREAD_PRIORITY + int "Thread priority" + depends on ADXL367_TRIGGER_OWN_THREAD && ADXL367_TRIGGER + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config ADXL367_THREAD_STACK_SIZE + int "Thread stack size" + depends on ADXL367_TRIGGER_OWN_THREAD && ADXL367_TRIGGER + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + endif # ADXL367 diff --git a/drivers/sensor/adxl367/adxl367.c b/drivers/sensor/adxl367/adxl367.c index 44eecf1c9753bc1..2979b945b62767d 100644 --- a/drivers/sensor/adxl367/adxl367.c +++ b/drivers/sensor/adxl367/adxl367.c @@ -846,6 +846,9 @@ static const struct sensor_driver_api adxl367_api_funcs = { .attr_set = adxl367_attr_set, .sample_fetch = adxl367_sample_fetch, .channel_get = adxl367_channel_get, +#ifdef CONFIG_ADXL367_TRIGGER + .trigger_set = adxl367_trigger_set, +#endif }; static int adxl367_probe(const struct device *dev) @@ -876,7 +879,11 @@ static int adxl367_probe(const struct device *dev) data->range = cfg->range; +#ifdef CONFIG_ADXL367_TRIGGER + data->act_proc_mode = ADXL367_LINKED; +#else data->act_proc_mode = ADXL367_LOOPED; +#endif ret = adxl367_self_test(dev); if (ret) { @@ -931,6 +938,14 @@ static int adxl367_probe(const struct device *dev) return ret; } +if (IS_ENABLED(CONFIG_ADXL367_TRIGGER)) { + ret = adxl367_init_interrupt(dev); + if (ret != 0) { + LOG_ERR("Failed to initialize interrupt!"); + return -EIO; + } +} + ret = adxl367_set_op_mode(dev, cfg->op_mode); if (ret) { return ret; @@ -977,6 +992,13 @@ static int adxl367_init(const struct device *dev) CONFIG_SENSOR_INIT_PRIORITY, \ &adxl367_api_funcs); +#ifdef CONFIG_ADXL367_TRIGGER +#define ADXL367_CFG_IRQ(inst) \ + .interrupt = GPIO_DT_SPEC_INST_GET(inst, int1_gpios), +#else +#define ADXL367_CFG_IRQ(inst) +#endif /* CONFIG_ADXL367_TRIGGER */ + #define ADXL367_CONFIG(inst) \ .odr = DT_INST_PROP(inst, odr), \ .autosleep = false, \ @@ -1011,6 +1033,8 @@ static int adxl367_init(const struct device *dev) .spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | \ SPI_TRANSFER_MSB, 0), \ ADXL367_CONFIG(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + (ADXL367_CFG_IRQ(inst)), ()) \ } #define ADXL367_DEFINE_SPI(inst) \ @@ -1028,6 +1052,8 @@ static int adxl367_init(const struct device *dev) .bus_init = adxl367_i2c_init, \ .i2c = I2C_DT_SPEC_INST_GET(inst), \ ADXL367_CONFIG(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + (ADXL367_CFG_IRQ(inst)), ()) \ } #define ADXL367_DEFINE_I2C(inst) \ diff --git a/drivers/sensor/adxl367/adxl367.h b/drivers/sensor/adxl367/adxl367.h index 0b7b44faea4e78f..8cef47420bbd82c 100644 --- a/drivers/sensor/adxl367/adxl367.h +++ b/drivers/sensor/adxl367/adxl367.h @@ -177,6 +177,25 @@ #define ADXL367_STATUS_FIFO_RDY BIT(1) #define ADXL367_STATUS_DATA_RDY BIT(0) +/* ADXL367_INTMAP_LOWER */ +#define ADXL367_INT_LOW BIT(7) +#define ADXL367_AWAKE_INT BIT(6) +#define ADXL367_INACT_INT BIT(5) +#define ADXL367_ACT_INT BIT(4) +#define ADXL367_FIFO_OVERRUN BIT(3) +#define ADXL367_FIFO_WATERMARK BIT(2) +#define ADXL367_FIFO_RDY BIT(1) +#define ADXL367_DATA_RDY BIT(0) + +/* ADXL367_INTMAP_UPPER */ +#define ADXL367_ERR_FUSE BIT(7) +#define ADXL367_ERR_USER_REGS BIT(6) +#define ADXL367_KPALV_TIMER BIT(4) +#define ADXL367_TEMP_ADC_HI BIT(3) +#define ADXL367_TEMP_ADC_LOW BIT(2) +#define ADXL367_TAP_TWO BIT(1) +#define ADXL367_TAP_ONE BIT(0) + /* Min change = 90mg. Sensitivity = 4LSB / mg */ #define ADXL367_SELF_TEST_MIN (90 * 100 / 25) /* Max change = 270mg. Sensitivity = 4LSB / mg */ @@ -280,6 +299,23 @@ struct adxl367_data { struct adxl367_fifo_config fifo_config; enum adxl367_act_proc_mode act_proc_mode; enum adxl367_range range; +#ifdef CONFIG_ADXL367_TRIGGER + struct gpio_callback gpio_cb; + + sensor_trigger_handler_t th_handler; + const struct sensor_trigger *th_trigger; + sensor_trigger_handler_t drdy_handler; + const struct sensor_trigger *drdy_trigger; + const struct device *dev; + +#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ADXL367_THREAD_STACK_SIZE); + struct k_sem gpio_sem; + struct k_thread thread; +#elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#endif /* CONFIG_ADXL367_TRIGGER */ }; struct adxl367_dev_config { @@ -291,6 +327,10 @@ struct adxl367_dev_config { #endif int (*bus_init)(const struct device *dev); +#ifdef CONFIG_ADXL367_TRIGGER + struct gpio_dt_spec interrupt; +#endif + enum adxl367_odr odr; /* Device Settings */ @@ -311,5 +351,10 @@ struct adxl367_dev_config { int adxl367_spi_init(const struct device *dev); int adxl367_i2c_init(const struct device *dev); +int adxl367_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int adxl367_init_interrupt(const struct device *dev); #endif /* ZEPHYR_DRIVERS_SENSOR_ADXL367_ADXL367_H_ */ diff --git a/drivers/sensor/adxl367/adxl367_trigger.c b/drivers/sensor/adxl367/adxl367_trigger.c new file mode 100644 index 000000000000000..4e86d466343cd05 --- /dev/null +++ b/drivers/sensor/adxl367/adxl367_trigger.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "adxl367.h" + +#include +LOG_MODULE_DECLARE(ADXL367, CONFIG_SENSOR_LOG_LEVEL); + +static void adxl367_thread_cb(const struct device *dev) +{ + const struct adxl367_dev_config *cfg = dev->config; + struct adxl367_data *drv_data = dev->data; + uint8_t status; + int ret; + + /* Clear the status */ + ret = drv_data->hw_tf->read_reg(dev, ADXL367_STATUS, &status); + if (ret != 0) { + return; + } + + if (drv_data->th_handler != NULL) { + if (((FIELD_GET(ADXL367_STATUS_INACT, status)) != 0) || + (FIELD_GET(ADXL367_STATUS_ACT, status)) != 0) { + drv_data->th_handler(dev, drv_data->th_trigger); + } + } + + if ((drv_data->drdy_handler != NULL) && + (FIELD_GET(ADXL367_STATUS_DATA_RDY, status) != 0)) { + drv_data->drdy_handler(dev, drv_data->drdy_trigger); + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt, + GPIO_INT_EDGE_TO_ACTIVE); + __ASSERT(ret == 0, "Interrupt configuration failed"); +} + +static void adxl367_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct adxl367_data *drv_data = + CONTAINER_OF(cb, struct adxl367_data, gpio_cb); + const struct adxl367_dev_config *cfg = drv_data->dev->config; + + gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_DISABLE); + +#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) + k_sem_give(&drv_data->gpio_sem); +#elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD) + k_work_submit(&drv_data->work); +#endif +} + +#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) +static void adxl367_thread(struct adxl367_data *drv_data) +{ + while (true) { + k_sem_take(&drv_data->gpio_sem, K_FOREVER); + adxl367_thread_cb(drv_data->dev); + } +} + +#elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD) +static void adxl367_work_cb(struct k_work *work) +{ + struct adxl367_data *drv_data = + CONTAINER_OF(work, struct adxl367_data, work); + + adxl367_thread_cb(drv_data->dev); +} +#endif + +int adxl367_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct adxl367_dev_config *cfg = dev->config; + struct adxl367_data *drv_data = dev->data; + uint8_t int_mask, int_en, status; + int ret; + + ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt, + GPIO_INT_DISABLE); + if (ret != 0) { + return ret; + } + + switch (trig->type) { + case SENSOR_TRIG_THRESHOLD: + drv_data->th_handler = handler; + drv_data->th_trigger = trig; + int_mask = ADXL367_ACT_INT | ADXL367_INACT_INT; + break; + case SENSOR_TRIG_DATA_READY: + drv_data->drdy_handler = handler; + drv_data->drdy_trigger = trig; + int_mask = ADXL367_DATA_RDY; + break; + default: + LOG_ERR("Unsupported sensor trigger"); + return -ENOTSUP; + } + + if (handler != NULL) { + int_en = int_mask; + } else { + int_en = 0U; + } + + ret = drv_data->hw_tf->write_reg_mask(dev, ADXL367_INTMAP1_LOWER, int_mask, int_en); + if (ret != 0) { + return ret; + } + + /* Clear status */ + ret = drv_data->hw_tf->read_reg(dev, ADXL367_STATUS, &status); + if (ret != 0) { + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret != 0) { + return ret; + } + + return 0; +} + +int adxl367_init_interrupt(const struct device *dev) +{ + const struct adxl367_dev_config *cfg = dev->config; + struct adxl367_data *drv_data = dev->data; + int ret; + + if (!gpio_is_ready_dt(&cfg->interrupt)) { + LOG_ERR("GPIO port %s not ready", cfg->interrupt.port->name); + return -EINVAL; + } + + ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT); + if (ret != 0) { + return ret; + } + + gpio_init_callback(&drv_data->gpio_cb, + adxl367_gpio_callback, + BIT(cfg->interrupt.pin)); + + ret = gpio_add_callback(cfg->interrupt.port, &drv_data->gpio_cb); + if (ret != 0) { + LOG_ERR("Failed to set gpio callback!"); + return ret; + } + + drv_data->dev = dev; + +#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) + k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&drv_data->thread, drv_data->thread_stack, + CONFIG_ADXL367_THREAD_STACK_SIZE, + (k_thread_entry_t)adxl367_thread, drv_data, + NULL, NULL, K_PRIO_COOP(CONFIG_ADXL367_THREAD_PRIORITY), + 0, K_NO_WAIT); +#elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD) + drv_data->work.handler = adxl367_work_cb; +#endif + + return 0; +} From 1088846e9a47dfcd72d6e49073addcf436434a4e Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 19 Oct 2023 14:09:08 +0300 Subject: [PATCH 0211/1049] tests: build_all: sensor: add adxl367 trigger Add trigger support for adxl367 build all sensor tests. Signed-off-by: Antoniu Miclaus --- tests/drivers/build_all/sensor/i2c.dtsi | 1 + tests/drivers/build_all/sensor/sensors_trigger_global.conf | 1 + tests/drivers/build_all/sensor/sensors_trigger_none.conf | 1 + tests/drivers/build_all/sensor/sensors_trigger_own.conf | 1 + tests/drivers/build_all/sensor/spi.dtsi | 1 + 5 files changed, 5 insertions(+) diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 4e54911f969a0c1..eda5bff0ff7401b 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -793,6 +793,7 @@ test_i2c_adxl367: adxl367@77 { compatible = "adi,adxl367"; reg = <0x77>; odr = <4>; + int1-gpios = <&test_gpio 0 0>; }; test_i2c_tsl2561: tsl2561@78 { diff --git a/tests/drivers/build_all/sensor/sensors_trigger_global.conf b/tests/drivers/build_all/sensor/sensors_trigger_global.conf index f0c34845ce0db02..74ba8f20239801d 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -1,6 +1,7 @@ CONFIG_ADT7310_TRIGGER_GLOBAL_THREAD=y CONFIG_ADT7420_TRIGGER_GLOBAL_THREAD=y CONFIG_ADXL362_TRIGGER_GLOBAL_THREAD=y +CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD=y CONFIG_ADXL372_TRIGGER_GLOBAL_THREAD=y CONFIG_AMG88XX_TRIGGER_GLOBAL_THREAD=y CONFIG_APDS9960_TRIGGER_GLOBAL_THREAD=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_none.conf b/tests/drivers/build_all/sensor/sensors_trigger_none.conf index 2c4b51c2184e9e1..905907928f522cd 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -1,6 +1,7 @@ CONFIG_ADT7310_TRIGGER_NONE=y CONFIG_ADT7420_TRIGGER_NONE=y CONFIG_ADXL362_TRIGGER_NONE=y +CONFIG_ADXL367_TRIGGER_NONE=y CONFIG_ADXL372_TRIGGER_NONE=y CONFIG_AMG88XX_TRIGGER_NONE=y CONFIG_APDS9960_TRIGGER_NONE=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_own.conf b/tests/drivers/build_all/sensor/sensors_trigger_own.conf index a64f6aa5c8baab4..92504b6c2f4d6e6 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -1,6 +1,7 @@ CONFIG_ADT7310_TRIGGER_OWN_THREAD=y CONFIG_ADT7420_TRIGGER_OWN_THREAD=y CONFIG_ADXL362_TRIGGER_OWN_THREAD=y +CONFIG_ADXL367_TRIGGER_OWN_THREAD=y CONFIG_ADXL372_TRIGGER_OWN_THREAD=y CONFIG_AMG88XX_TRIGGER_OWN_THREAD=y CONFIG_BMA280_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index bd734d98f68f9f2..d026e244f88aa2d 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -302,4 +302,5 @@ test_spi_adxl367: adxl367@26 { reg = <0x26>; spi-max-frequency = <0>; odr = <4>; + int1-gpios = <&test_gpio 0 0>; }; From 94dc05b3f2542c5035d6120f6e5e4ed825775626 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Mon, 5 Jun 2023 20:26:19 -0600 Subject: [PATCH 0212/1049] sensors: Add streaming APIs Introduce a streaming API that uses the same data path as the async API. This includes features to the decoder: * Checking if triggers are present Adding streaming features built ontop of existing triggers: * Adding 3 operations to be done on a trigger * include - include the data with the trigger information * nop - do nothing * drop - drop the data (flush) * Add a new sensor_stream() API to mirror sensor_read() but add an optional handler to be able to cancel the stream. Signed-off-by: Yuval Peress topic#sensor_stream --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 17 + drivers/sensor/default_rtio_sensor.c | 6 +- drivers/sensor/sensor_shell.c | 317 +++++++++++++++--- drivers/sensor/sensor_shell.h | 26 ++ drivers/sensor/sensor_shell_stream.c | 124 +++++++ include/zephyr/drivers/sensor.h | 111 +++++- .../sensor_shell/boards/tdk_robokit1.conf | 3 + samples/sensor/sensor_shell/sample.yaml | 2 + 9 files changed, 543 insertions(+), 64 deletions(-) create mode 100644 drivers/sensor/sensor_shell.h create mode 100644 drivers/sensor/sensor_shell_stream.c create mode 100644 samples/sensor/sensor_shell/boards/tdk_robokit1.conf diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index b0359f0254b9cc9..8ac3da6c937fda3 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -166,5 +166,6 @@ zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_USERSPACE sensor_handlers.c) zephyr_library_sources_ifdef(CONFIG_SENSOR_SHELL sensor_shell.c) +zephyr_library_sources_ifdef(CONFIG_SENSOR_SHELL_STREAM sensor_shell_stream.c) zephyr_library_sources_ifdef(CONFIG_SENSOR_SHELL_BATTERY shell_battery.c) zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API sensor_decoders_init.c default_rtio_sensor.c) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 31809dd07910f19..000c4bb1a3571b5 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -36,6 +36,23 @@ config SENSOR_SHELL help This shell provides access to basic sensor data. +config SENSOR_SHELL_STREAM + bool "Sensor shell 'stream' command" + depends on SENSOR_SHELL + help + Add the 'stream' subcommand to the sensor shell. When run on drivers that + support streaming (usually hardware FIFO backed), the shell will continue + to print new values as they come until the stream is closed. + +config SENSOR_SHELL_THREAD_STACK_SIZE + int "Stack size for the sensor shell data processing thread" + depends on SENSOR_SHELL_STREAM + default 1024 + help + The sensor shell uses a dedicated thread to process data coming from the + sensors in either one-shot or streaming mode. Use this config to control + the size of that thread's stack. + config SENSOR_SHELL_BATTERY bool "Sensor shell 'battery' command" depends on SHELL diff --git a/drivers/sensor/default_rtio_sensor.c b/drivers/sensor/default_rtio_sensor.c index e088b4f61c28895..3f9377c33b35916 100644 --- a/drivers/sensor/default_rtio_sensor.c +++ b/drivers/sensor/default_rtio_sensor.c @@ -28,8 +28,10 @@ static void sensor_iodev_submit(struct rtio_iodev_sqe *iodev_sqe) if (api->submit != NULL) { api->submit(dev, iodev_sqe); - } else { + } else if (!cfg->is_streaming) { sensor_submit_fallback(dev, iodev_sqe); + } else { + rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); } } @@ -235,7 +237,7 @@ static void sensor_submit_fallback(const struct device *dev, struct rtio_iodev_s } sample_idx += num_samples; } - LOG_DBG("Total channels in header: %u", header->num_channels); + LOG_DBG("Total channels in header: %" PRIu32, header->num_channels); rtio_iodev_sqe_ok(iodev_sqe, 0); } diff --git a/drivers/sensor/sensor_shell.c b/drivers/sensor/sensor_shell.c index a85eab23e43ec36..5d41663c491db8a 100644 --- a/drivers/sensor/sensor_shell.c +++ b/drivers/sensor/sensor_shell.c @@ -16,6 +16,8 @@ #include #include +#include "sensor_shell.h" + LOG_MODULE_REGISTER(sensor_shell); #define SENSOR_GET_HELP \ @@ -23,6 +25,11 @@ LOG_MODULE_REGISTER(sensor_shell); "when no channels are provided. Syntax:\n" \ " .. " +#define SENSOR_STREAM_HELP \ + "Start/stop streaming sensor data. Data ready trigger will be used if no triggers " \ + "are provided. Syntax:\n" \ + " on|off incl|drop|nop" + #define SENSOR_ATTR_GET_HELP \ "Get the sensor's channel attribute. Syntax:\n" \ " [ .. " \ @@ -38,7 +45,7 @@ LOG_MODULE_REGISTER(sensor_shell); "Get or set the trigger type on a sensor. Currently only supports `data_ready`.\n" \ " " -const char *sensor_channel_name[SENSOR_CHAN_ALL] = { +const char *sensor_channel_name[SENSOR_CHAN_COMMON_COUNT] = { [SENSOR_CHAN_ACCEL_X] = "accel_x", [SENSOR_CHAN_ACCEL_Y] = "accel_y", [SENSOR_CHAN_ACCEL_Z] = "accel_z", @@ -96,6 +103,7 @@ const char *sensor_channel_name[SENSOR_CHAN_ALL] = { [SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE] = "gauge_design_voltage", [SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE] = "gauge_desired_voltage", [SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT] = "gauge_desired_charging_current", + [SENSOR_CHAN_ALL] = "all", }; static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { @@ -114,6 +122,7 @@ static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { [SENSOR_ATTR_FEATURE_MASK] = "feature_mask", [SENSOR_ATTR_ALERT] = "alert", [SENSOR_ATTR_FF_DUR] = "ff_dur", + [SENSOR_ATTR_FIFO_WATERMARK] = "fifo_wm", }; /* Forward declaration */ @@ -146,12 +155,32 @@ static const struct { TRIGGER_DATA_ENTRY(SENSOR_TRIG_FREEFALL, freefall, NULL), TRIGGER_DATA_ENTRY(SENSOR_TRIG_MOTION, motion, NULL), TRIGGER_DATA_ENTRY(SENSOR_TRIG_STATIONARY, stationary, NULL), + TRIGGER_DATA_ENTRY(SENSOR_TRIG_FIFO_WATERMARK, fifo_wm, NULL), + TRIGGER_DATA_ENTRY(SENSOR_TRIG_FIFO_FULL, fifo_full, NULL), }; +/** + * Lookup the sensor trigger data by name + * + * @param name The name of the trigger + * @return < 0 on error + * @return >= 0 if found + */ +static int sensor_trigger_name_lookup(const char *name) +{ + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); ++i) { + if (strcmp(name, sensor_trigger_table[i].name) == 0) { + return i; + } + } + return -1; +} + enum dynamic_command_context { NONE, CTX_GET, CTX_ATTR_GET_SET, + CTX_STREAM_ON_OFF, }; static enum dynamic_command_context current_cmd_ctx = NONE; @@ -163,6 +192,7 @@ K_MUTEX_DEFINE(cmd_get_mutex); static enum sensor_channel iodev_sensor_shell_channels[SENSOR_CHAN_ALL]; static struct sensor_read_config iodev_sensor_shell_read_config = { .sensor = NULL, + .is_streaming = false, .channels = iodev_sensor_shell_channels, .count = 0, .max = ARRAY_SIZE(iodev_sensor_shell_channels), @@ -234,17 +264,18 @@ static int parse_sensor_value(const char *val_str, struct sensor_value *out) return 0; } -struct sensor_shell_processing_context { - const struct device *dev; - const struct shell *sh; -}; - -static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len, - void *userdata) +void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len, void *userdata) { struct sensor_shell_processing_context *ctx = userdata; const struct sensor_decoder_api *decoder; uint8_t decoded_buffer[128]; + struct { + uint64_t base_timestamp_ns; + int count; + uint64_t timestamp_delta; + int64_t values[3]; + int8_t shift; + } accumulator_buffer; int rc; ARG_UNUSED(buf_len); @@ -260,6 +291,17 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t return; } + for (int trigger = 0; decoder->has_trigger != NULL && trigger < SENSOR_TRIG_COMMON_COUNT; + ++trigger) { + if (!decoder->has_trigger(buf, trigger)) { + continue; + } + shell_info(ctx->sh, "Trigger (%d / %s) detected", trigger, + (sensor_trigger_table[trigger].name == NULL + ? "UNKNOWN" + : sensor_trigger_table[trigger].name)); + } + for (int channel = 0; channel < SENSOR_CHAN_ALL; ++channel) { uint32_t fit = 0; size_t base_size; @@ -292,6 +334,7 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t while (decoder->get_frame_count(buf, channel, channel_idx, &frame_count) == 0) { fit = 0; + memset(&accumulator_buffer, 0, sizeof(accumulator_buffer)); while (decoder->decode(buf, channel, channel_idx, &fit, 1, decoded_buffer) > 0) { @@ -303,41 +346,127 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t struct sensor_three_axis_data *data = (struct sensor_three_axis_data *)decoded_buffer; - shell_info(ctx->sh, - "channel idx=%d %s shift=%d " - "value=%" PRIsensor_three_axis_data, - channel, sensor_channel_name[channel], - data->shift, - PRIsensor_three_axis_data_arg(*data, 0)); + if (accumulator_buffer.count == 0) { + accumulator_buffer.base_timestamp_ns = + data->header.base_timestamp_ns; + } + accumulator_buffer.count++; + accumulator_buffer.shift = data->shift; + accumulator_buffer.timestamp_delta += + data->readings[0].timestamp_delta; + accumulator_buffer.values[0] += data->readings[0].values[0]; + accumulator_buffer.values[1] += data->readings[0].values[1]; + accumulator_buffer.values[2] += data->readings[0].values[2]; break; } case SENSOR_CHAN_PROX: { struct sensor_byte_data *data = (struct sensor_byte_data *)decoded_buffer; - shell_info(ctx->sh, - "channel idx=%d %s value=%" PRIsensor_byte_data( - is_near), - channel, sensor_channel_name[channel], - PRIsensor_byte_data_arg(*data, 0, is_near)); + if (accumulator_buffer.count == 0) { + accumulator_buffer.base_timestamp_ns = + data->header.base_timestamp_ns; + } + accumulator_buffer.count++; + accumulator_buffer.timestamp_delta += + data->readings[0].timestamp_delta; + accumulator_buffer.values[0] += data->readings[0].is_near; break; } default: { struct sensor_q31_data *data = (struct sensor_q31_data *)decoded_buffer; - shell_info(ctx->sh, - "channel idx=%d %s shift=%d " - "value=%" PRIsensor_q31_data, - channel, - (channel >= ARRAY_SIZE(sensor_channel_name)) - ? "" - : sensor_channel_name[channel], - data->shift, PRIsensor_q31_data_arg(*data, 0)); + if (accumulator_buffer.count == 0) { + accumulator_buffer.base_timestamp_ns = + data->header.base_timestamp_ns; + } + accumulator_buffer.count++; + accumulator_buffer.shift = data->shift; + accumulator_buffer.timestamp_delta += + data->readings[0].timestamp_delta; + accumulator_buffer.values[0] += data->readings[0].value; break; } } } + + /* Print the accumulated value average */ + switch (channel) { + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_MAGN_XYZ: + case SENSOR_CHAN_POS_DX: { + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)decoded_buffer; + + data->header.base_timestamp_ns = + accumulator_buffer.base_timestamp_ns; + data->header.reading_count = 1; + data->shift = accumulator_buffer.shift; + data->readings[0].timestamp_delta = + (uint32_t)(accumulator_buffer.timestamp_delta / + accumulator_buffer.count); + data->readings[0].values[0] = (q31_t)(accumulator_buffer.values[0] / + accumulator_buffer.count); + data->readings[0].values[1] = (q31_t)(accumulator_buffer.values[1] / + accumulator_buffer.count); + data->readings[0].values[2] = (q31_t)(accumulator_buffer.values[2] / + accumulator_buffer.count); + shell_info(ctx->sh, + "channel idx=%d %s shift=%d num_samples=%d " + "value=%" PRIsensor_three_axis_data, + channel, sensor_channel_name[channel], + data->shift, accumulator_buffer.count, + PRIsensor_three_axis_data_arg(*data, 0)); + break; + } + case SENSOR_CHAN_PROX: { + struct sensor_byte_data *data = + (struct sensor_byte_data *)decoded_buffer; + + data->header.base_timestamp_ns = + accumulator_buffer.base_timestamp_ns; + data->header.reading_count = 1; + data->readings[0].timestamp_delta = + (uint32_t)(accumulator_buffer.timestamp_delta / + accumulator_buffer.count); + data->readings[0].is_near = + accumulator_buffer.values[0] / accumulator_buffer.count; + + shell_info(ctx->sh, + "channel idx=%d %s num_samples=%d " + "value=%" PRIsensor_byte_data(is_near), + channel, sensor_channel_name[channel], + accumulator_buffer.count, + PRIsensor_byte_data_arg(*data, 0, is_near)); + break; + } + default: { + struct sensor_q31_data *data = + (struct sensor_q31_data *)decoded_buffer; + + data->header.base_timestamp_ns = + accumulator_buffer.base_timestamp_ns; + data->header.reading_count = 1; + data->shift = accumulator_buffer.shift; + data->readings[0].timestamp_delta = + (uint32_t)(accumulator_buffer.timestamp_delta / + accumulator_buffer.count); + data->readings[0].value = (q31_t)(accumulator_buffer.values[0] / + accumulator_buffer.count); + + shell_info(ctx->sh, + "channel idx=%d %s shift=%d num_samples=%d " + "value=%" PRIsensor_q31_data, + channel, + (channel >= ARRAY_SIZE(sensor_channel_name)) + ? "" + : sensor_channel_name[channel], + data->shift, accumulator_buffer.count, + PRIsensor_q31_data_arg(*data, 0)); + } + } ++channel_idx; } } @@ -345,6 +474,7 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) { + static struct sensor_shell_processing_context ctx; const struct device *dev; int count = 0; int err; @@ -392,21 +522,27 @@ static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) iodev_sensor_shell_read_config.sensor = dev; iodev_sensor_shell_read_config.count = count; - struct sensor_shell_processing_context ctx = { - .dev = dev, - .sh = sh, - }; + ctx.dev = dev; + ctx.sh = sh; err = sensor_read(&iodev_sensor_shell_read, &sensor_read_rtio, &ctx); if (err < 0) { shell_error(sh, "Failed to read sensor: %d", err); } - sensor_processing_with_callback(&sensor_read_rtio, sensor_shell_processing_callback); + if (!IS_ENABLED(CONFIG_SENSOR_SHELL_STREAM)) { + /* + * Streaming enables a thread that polls the RTIO context, so if it's enabled, we + * don't need a blocking read here. + */ + sensor_processing_with_callback(&sensor_read_rtio, + sensor_shell_processing_callback); + } k_mutex_unlock(&cmd_get_mutex); return 0; } + static int cmd_sensor_attr_set(const struct shell *shell_ptr, size_t argc, char *argv[]) { const struct device *dev; @@ -517,9 +653,37 @@ static int cmd_sensor_attr_get(const struct shell *shell_ptr, size_t argc, char } static void channel_name_get(size_t idx, struct shell_static_entry *entry); - SHELL_DYNAMIC_CMD_CREATE(dsub_channel_name, channel_name_get); +static void attribute_name_get(size_t idx, struct shell_static_entry *entry); +SHELL_DYNAMIC_CMD_CREATE(dsub_attribute_name, attribute_name_get); + +static void channel_name_get(size_t idx, struct shell_static_entry *entry) +{ + int cnt = 0; + + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + if (current_cmd_ctx == CTX_GET) { + entry->subcmd = &dsub_channel_name; + } else if (current_cmd_ctx == CTX_ATTR_GET_SET) { + entry->subcmd = &dsub_attribute_name; + } else { + entry->subcmd = NULL; + } + + for (int i = 0; i < ARRAY_SIZE(sensor_channel_name); i++) { + if (sensor_channel_name[i] != NULL) { + if (cnt == idx) { + entry->syntax = sensor_channel_name[i]; + break; + } + cnt++; + } + } +} + static void attribute_name_get(size_t idx, struct shell_static_entry *entry) { int cnt = 0; @@ -529,7 +693,7 @@ static void attribute_name_get(size_t idx, struct shell_static_entry *entry) entry->help = NULL; entry->subcmd = &dsub_channel_name; - for (int i = 0; i < SENSOR_ATTR_COMMON_COUNT; i++) { + for (int i = 0; i < ARRAY_SIZE(sensor_attribute_name); i++) { if (sensor_attribute_name[i] != NULL) { if (cnt == idx) { entry->syntax = sensor_attribute_name[i]; @@ -539,27 +703,46 @@ static void attribute_name_get(size_t idx, struct shell_static_entry *entry) } } } -SHELL_DYNAMIC_CMD_CREATE(dsub_attribute_name, attribute_name_get); -static void channel_name_get(size_t idx, struct shell_static_entry *entry) +static void trigger_opt_get_for_stream(size_t idx, struct shell_static_entry *entry); +SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_opt_get_for_stream, trigger_opt_get_for_stream); + +static void trigger_opt_get_for_stream(size_t idx, struct shell_static_entry *entry) +{ + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; + + switch (idx) { + case SENSOR_STREAM_DATA_INCLUDE: + entry->syntax = "incl"; + break; + case SENSOR_STREAM_DATA_DROP: + entry->syntax = "drop"; + break; + case SENSOR_STREAM_DATA_NOP: + entry->syntax = "nop"; + break; + } +} + +static void trigger_name_get_for_stream(size_t idx, struct shell_static_entry *entry); +SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_name_for_stream, trigger_name_get_for_stream); + +static void trigger_name_get_for_stream(size_t idx, struct shell_static_entry *entry) { int cnt = 0; entry->syntax = NULL; entry->handler = NULL; entry->help = NULL; - if (current_cmd_ctx == CTX_GET) { - entry->subcmd = &dsub_channel_name; - } else if (current_cmd_ctx == CTX_ATTR_GET_SET) { - entry->subcmd = &dsub_attribute_name; - } else { - entry->subcmd = NULL; - } + entry->subcmd = &dsub_trigger_opt_get_for_stream; - for (int i = 0; i < SENSOR_CHAN_ALL; i++) { - if (sensor_channel_name[i] != NULL) { + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); i++) { + if (sensor_trigger_table[i].name != NULL) { if (cnt == idx) { - entry->syntax = sensor_channel_name[i]; + entry->syntax = sensor_trigger_table[i].name; break; } cnt++; @@ -567,6 +750,22 @@ static void channel_name_get(size_t idx, struct shell_static_entry *entry) } } +static void stream_on_off(size_t idx, struct shell_static_entry *entry) +{ + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + + if (idx == 0) { + entry->syntax = "on"; + entry->subcmd = &dsub_trigger_name_for_stream; + } else if (idx == 1) { + entry->syntax = "off"; + entry->subcmd = NULL; + } +} +SHELL_DYNAMIC_CMD_CREATE(dsub_stream_on_off, stream_on_off); + static void device_name_get(size_t idx, struct shell_static_entry *entry); SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); @@ -603,7 +802,7 @@ static void trigger_name_get(size_t idx, struct shell_static_entry *entry) entry->help = NULL; entry->subcmd = NULL; - for (int i = 0; i < SENSOR_TRIG_COMMON_COUNT; i++) { + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); i++) { if (sensor_trigger_table[i].name != NULL) { if (cnt == idx) { entry->syntax = sensor_trigger_table[i].name; @@ -649,6 +848,18 @@ static void device_name_get_for_trigger(size_t idx, struct shell_static_entry *e SHELL_DYNAMIC_CMD_CREATE(dsub_trigger, device_name_get_for_trigger); +static void device_name_get_for_stream(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, NULL); + + current_cmd_ctx = CTX_STREAM_ON_OFF; + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = &dsub_stream_on_off; +} +SHELL_DYNAMIC_CMD_CREATE(dsub_device_name_for_stream, device_name_get_for_stream); + static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv) { ARG_UNUSED(argc); @@ -738,7 +949,7 @@ static void data_ready_trigger_handler(const struct device *sensor, static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; - enum sensor_trigger_type trigger; + int trigger; int err; if (argc < 4) { @@ -754,12 +965,8 @@ static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) } /* Map the trigger string to an enum value */ - for (trigger = 0; trigger < ARRAY_SIZE(sensor_trigger_table); trigger++) { - if (strcmp(argv[3], sensor_trigger_table[trigger].name) == 0) { - break; - } - } - if (trigger >= SENSOR_TRIG_COMMON_COUNT || sensor_trigger_table[trigger].handler == NULL) { + trigger = sensor_trigger_name_lookup(argv[3]); + if (trigger < 0 || sensor_trigger_table[trigger].handler == NULL) { shell_error(sh, "Unsupported trigger type (%s)", argv[3]); return -ENOTSUP; } @@ -792,6 +999,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_sensor, cmd_sensor_attr_set, 2, 255), SHELL_CMD_ARG(attr_get, &dsub_device_name_for_attr, SENSOR_ATTR_GET_HELP, cmd_sensor_attr_get, 2, 255), + SHELL_COND_CMD(CONFIG_SENSOR_SHELL_STREAM, stream, &dsub_device_name_for_stream, + SENSOR_STREAM_HELP, cmd_sensor_stream), SHELL_COND_CMD(CONFIG_SENSOR_INFO, info, NULL, SENSOR_INFO_HELP, cmd_get_sensor_info), SHELL_CMD_ARG(trig, &dsub_trigger, SENSOR_TRIG_HELP, cmd_trig_sensor, diff --git a/drivers/sensor/sensor_shell.h b/drivers/sensor/sensor_shell.h new file mode 100644 index 000000000000000..cfc8b2489db3cfc --- /dev/null +++ b/drivers/sensor/sensor_shell.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_SENSOR_SHELL_H +#define ZEPHYR_DRIVERS_SENSOR_SENSOR_SHELL_H + +#include +#include +#include +#include + +struct sensor_shell_processing_context { + const struct device *dev; + const struct shell *sh; +}; + +extern struct rtio sensor_read_rtio; + +int cmd_sensor_stream(const struct shell *shell_ptr, size_t argc, char *argv[]); + +void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len, void *userdata); + +#endif /* ZEPHYR_DRIVERS_SENSOR_SENSOR_SHELL_H */ diff --git a/drivers/sensor/sensor_shell_stream.c b/drivers/sensor/sensor_shell_stream.c new file mode 100644 index 000000000000000..ab3b835aa103865 --- /dev/null +++ b/drivers/sensor/sensor_shell_stream.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +#include "sensor_shell.h" + +/* Create a single common config for streaming */ +static struct sensor_stream_trigger iodev_sensor_shell_trigger; +static struct sensor_read_config iodev_sensor_shell_stream_config = { + .sensor = NULL, + .is_streaming = true, + .triggers = &iodev_sensor_shell_trigger, + .count = 0, + .max = 1, +}; +RTIO_IODEV_DEFINE(iodev_sensor_shell_stream, &__sensor_iodev_api, + &iodev_sensor_shell_stream_config); + +static void sensor_shell_processing_entry_point(void *a, void *b, void *c) +{ + ARG_UNUSED(a); + ARG_UNUSED(b); + ARG_UNUSED(c); + + while (true) { + sensor_processing_with_callback(&sensor_read_rtio, + sensor_shell_processing_callback); + } +} +K_THREAD_DEFINE(sensor_shell_processing_tid, CONFIG_SENSOR_SHELL_THREAD_STACK_SIZE, + sensor_shell_processing_entry_point, NULL, NULL, NULL, 0, 0, 0); + +int cmd_sensor_stream(const struct shell *shell_ptr, size_t argc, char *argv[]) +{ + static struct rtio_sqe *current_streaming_handle; + static struct sensor_shell_processing_context ctx; + const struct device *dev = device_get_binding(argv[1]); + + if (argc != 5 && argc != 3) { + shell_error(shell_ptr, "Wrong number of arguments (%zu)", argc); + return -EINVAL; + } + + if (dev == NULL) { + shell_error(shell_ptr, "Device unknown (%s)", argv[1]); + return -ENODEV; + } + + if (current_streaming_handle != NULL) { + shell_info(shell_ptr, "Disabling existing stream"); + rtio_sqe_cancel(current_streaming_handle); + } + + if (strcmp("off", argv[2]) == 0) { + return 0; + } + + if (strcmp("on", argv[2]) != 0) { + shell_error(shell_ptr, "Unknown streaming operation (%s)", argv[2]); + return -EINVAL; + } + + if (strcmp("double_tap", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_DOUBLE_TAP; + } else if (strcmp("data_ready", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_DATA_READY; + } else if (strcmp("delta", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_DELTA; + } else if (strcmp("freefall", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_FREEFALL; + } else if (strcmp("motion", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_MOTION; + } else if (strcmp("near_far", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_NEAR_FAR; + } else if (strcmp("stationary", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_STATIONARY; + } else if (strcmp("threshold", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_THRESHOLD; + } else if (strcmp("fifo_wm", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_FIFO_WATERMARK; + } else if (strcmp("fifo_full", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_FIFO_FULL; + } else if (strcmp("tap", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_TAP; + } else { + shell_error(shell_ptr, "Invalid trigger (%s)", argv[3]); + return -EINVAL; + } + + if (strcmp("incl", argv[4]) == 0) { + iodev_sensor_shell_trigger.opt = SENSOR_STREAM_DATA_INCLUDE; + } else if (strcmp("drop", argv[4]) == 0) { + iodev_sensor_shell_trigger.opt = SENSOR_STREAM_DATA_DROP; + } else if (strcmp("nop", argv[4]) == 0) { + iodev_sensor_shell_trigger.opt = SENSOR_STREAM_DATA_NOP; + } else { + shell_error(shell_ptr, "Unknown trigger op (%s)", argv[4]); + return -EINVAL; + } + + shell_print(shell_ptr, "Enabling stream..."); + iodev_sensor_shell_stream_config.sensor = dev; + + iodev_sensor_shell_stream_config.count = 1; + + ctx.dev = dev; + ctx.sh = shell_ptr; + + int rc = sensor_stream(&iodev_sensor_shell_stream, &sensor_read_rtio, &ctx, + ¤t_streaming_handle); + + if (rc != 0) { + shell_error(shell_ptr, "Failed to start stream"); + } + return rc; +} diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index bbc85fda86d6187..80fda1b163483eb 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -251,6 +251,12 @@ enum sensor_trigger_type { /** Trigger fires when no motion has been detected for a while. */ SENSOR_TRIG_STATIONARY, + + /** Trigger fires when the FIFO watermark has been reached. */ + SENSOR_TRIG_FIFO_WATERMARK, + + /** Trigger fires when the FIFO becomes full. */ + SENSOR_TRIG_FIFO_FULL, /** * Number of all common sensor triggers. */ @@ -328,6 +334,8 @@ enum sensor_attribute { * to the new sampling frequency. */ SENSOR_ATTR_FF_DUR, + /** Watermark % for the hardware fifo interrupt */ + SENSOR_ATTR_FIFO_WATERMARK, /** * Number of all common sensor attributes. */ @@ -466,6 +474,15 @@ struct sensor_decoder_api { */ int (*decode)(const uint8_t *buffer, enum sensor_channel channel, size_t channel_idx, uint32_t *fit, uint16_t max_count, void *data_out); + + /** + * @brief Check if the given trigger type is present + * + * @param[in] buffer The buffer provided on the @ref rtio context + * @param[in] trigger The trigger type in question + * @return Whether the trigger is present in the buffer + */ + bool (*has_trigger)(const uint8_t *buffer, enum sensor_trigger_type trigger); }; /** @@ -538,13 +555,38 @@ int sensor_natively_supported_channel_size_info(enum sensor_channel channel, siz typedef int (*sensor_get_decoder_t)(const struct device *dev, const struct sensor_decoder_api **api); +/** + * @brief Options for what to do with the associated data when a trigger is consumed + */ +enum sensor_stream_data_opt { + /** @brief Include whatever data is associated with the trigger */ + SENSOR_STREAM_DATA_INCLUDE = 0, + /** @brief Do nothing with the associated trigger data, it may be consumed later */ + SENSOR_STREAM_DATA_NOP = 1, + /** @brief Flush/clear whatever data is associated with the trigger */ + SENSOR_STREAM_DATA_DROP = 2, +}; + +struct sensor_stream_trigger { + enum sensor_trigger_type trigger; + enum sensor_stream_data_opt opt; +}; + +#define SENSOR_STREAM_TRIGGER_PREP(_trigger, _opt) \ + { \ + .trigger = (_trigger), .opt = (_opt), \ + } /* * Internal data structure used to store information about the IODevice for async reading and * streaming sensor data. */ struct sensor_read_config { const struct device *sensor; - enum sensor_channel *const channels; + const bool is_streaming; + union { + enum sensor_channel *const channels; + struct sensor_stream_trigger *const triggers; + }; size_t count; const size_t max; }; @@ -564,14 +606,45 @@ struct sensor_read_config { * @endcode */ #define SENSOR_DT_READ_IODEV(name, dt_node, ...) \ - static enum sensor_channel __channel_array_##name[] = {__VA_ARGS__}; \ - static struct sensor_read_config __sensor_read_config_##name = { \ + static enum sensor_channel _CONCAT(__channel_array_, name)[] = {__VA_ARGS__}; \ + static struct sensor_read_config _CONCAT(__sensor_read_config_, name) = { \ .sensor = DEVICE_DT_GET(dt_node), \ - .channels = __channel_array_##name, \ - .count = ARRAY_SIZE(__channel_array_##name), \ - .max = ARRAY_SIZE(__channel_array_##name), \ + .is_streaming = false, \ + .channels = _CONCAT(__channel_array_, name), \ + .count = ARRAY_SIZE(_CONCAT(__channel_array_, name)), \ + .max = ARRAY_SIZE(_CONCAT(__channel_array_, name)), \ }; \ - RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, &__sensor_read_config_##name) + RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, _CONCAT(&__sensor_read_config_, name)) + +/** + * @brief Define a stream instance of a sensor + * + * Use this macro to generate a @ref rtio_iodev for starting a stream that's triggered by specific + * interrupts. Example: + * + * @code(.c) + * SENSOR_DT_STREAM_IODEV(imu_stream, DT_ALIAS(imu), + * {SENSOR_TRIG_FIFO_WATERMARK, SENSOR_STREAM_DATA_INCLUDE}, + * {SENSOR_TRIG_FIFO_FULL, SENSOR_STREAM_DATA_NOP}); + * + * int main(void) { + * struct rtio_sqe *handle; + * sensor_stream(&imu_stream, &rtio, NULL, &handle); + * k_msleep(1000); + * rtio_sqe_cancel(handle); + * } + * @endcode + */ +#define SENSOR_DT_STREAM_IODEV(name, dt_node, ...) \ + static struct sensor_stream_trigger _CONCAT(__trigger_array_, name)[] = {__VA_ARGS__}; \ + static struct sensor_read_config _CONCAT(__sensor_read_config_, name) = { \ + .sensor = DEVICE_DT_GET(dt_node), \ + .is_streaming = true, \ + .triggers = _CONCAT(__trigger_array_, name), \ + .count = ARRAY_SIZE(_CONCAT(__trigger_array_, name)), \ + .max = ARRAY_SIZE(_CONCAT(__trigger_array_, name)), \ + }; \ + RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, &_CONCAT(__sensor_read_config_, name)) /* Used to submit an RTIO sqe to the sensor's iodev */ typedef int (*sensor_submit_t)(const struct device *sensor, struct rtio_iodev_sqe *sqe); @@ -880,7 +953,7 @@ static inline int z_impl_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, { struct sensor_read_config *cfg = (struct sensor_read_config *)iodev->data; - if (cfg->max < num_channels) { + if (cfg->max < num_channels || cfg->is_streaming) { return -ENOMEM; } @@ -888,6 +961,28 @@ static inline int z_impl_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, memcpy(cfg->channels, channels, num_channels * sizeof(enum sensor_channel)); cfg->count = num_channels; return 0; +} + +static inline int sensor_stream(struct rtio_iodev *iodev, struct rtio *ctx, void *userdata, + struct rtio_sqe **handle) +{ + if (IS_ENABLED(CONFIG_USERSPACE)) { + struct rtio_sqe sqe; + + rtio_sqe_prep_read_multishot(&sqe, iodev, RTIO_PRIO_NORM, userdata); + rtio_sqe_copy_in_get_handles(ctx, &sqe, handle, 1); + } else { + struct rtio_sqe *sqe = rtio_sqe_acquire(ctx); + + if (sqe == NULL) { + return -ENOMEM; + } + if (handle != NULL) { + *handle = sqe; + } + rtio_sqe_prep_read_multishot(sqe, iodev, RTIO_PRIO_NORM, userdata); + } + rtio_submit(ctx, 0); return 0; } diff --git a/samples/sensor/sensor_shell/boards/tdk_robokit1.conf b/samples/sensor/sensor_shell/boards/tdk_robokit1.conf new file mode 100644 index 000000000000000..aee20b8b10049ce --- /dev/null +++ b/samples/sensor/sensor_shell/boards/tdk_robokit1.conf @@ -0,0 +1,3 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 +CONFIG_SPI_RTIO=y diff --git a/samples/sensor/sensor_shell/sample.yaml b/samples/sensor/sensor_shell/sample.yaml index 7b194f4d6227819..d89dfebc21aae23 100644 --- a/samples/sensor/sensor_shell/sample.yaml +++ b/samples/sensor/sensor_shell/sample.yaml @@ -4,6 +4,8 @@ tests: sample.sensor.shell: integration_platforms: - frdm_k64f + # TODO Remove once #63414 is resolved + platform_exclude: gd32l233r_eval filter: ( CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_INTERRUPT ) tags: shell harness: keyboard From 1326c7c4543d56ee961a7ea07099c4b7df8936d1 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Wed, 5 Jul 2023 13:42:04 -0600 Subject: [PATCH 0213/1049] icm42688: Implement streaming APIs Add streaming implementation for icm42688 using both threshold and full FIFO triggers. Signed-off-by: Yuval Peress topic#sensor_stream --- drivers/sensor/icm42688/CMakeLists.txt | 1 + drivers/sensor/icm42688/Kconfig | 10 + drivers/sensor/icm42688/icm42688.c | 32 +- drivers/sensor/icm42688/icm42688.h | 12 + drivers/sensor/icm42688/icm42688_common.c | 9 +- drivers/sensor/icm42688/icm42688_decoder.c | 352 +++++++++++++++++- drivers/sensor/icm42688/icm42688_decoder.h | 9 + drivers/sensor/icm42688/icm42688_reg.h | 8 + drivers/sensor/icm42688/icm42688_rtio.c | 16 +- drivers/sensor/icm42688/icm42688_rtio.h | 7 + .../sensor/icm42688/icm42688_rtio_stream.c | 319 ++++++++++++++++ drivers/sensor/icm42688/icm42688_trigger.c | 24 +- drivers/sensor/icm42688/icm42688_trigger.h | 3 +- 13 files changed, 773 insertions(+), 29 deletions(-) create mode 100644 drivers/sensor/icm42688/icm42688_rtio_stream.c diff --git a/drivers/sensor/icm42688/CMakeLists.txt b/drivers/sensor/icm42688/CMakeLists.txt index cf9308bb95c4478..fbc63b6a4b22918 100644 --- a/drivers/sensor/icm42688/CMakeLists.txt +++ b/drivers/sensor/icm42688/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources( zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API icm42688_rtio.c) zephyr_library_sources_ifdef(CONFIG_ICM42688_DECODER icm42688_decoder.c) +zephyr_library_sources_ifdef(CONFIG_ICM42688_STREAM icm42688_rtio_stream.c) zephyr_library_sources_ifdef(CONFIG_ICM42688_TRIGGER icm42688_trigger.c) zephyr_library_sources_ifdef(CONFIG_EMUL_ICM42688 icm42688_emul.c) zephyr_include_directories_ifdef(CONFIG_EMUL_ICM42688 .) diff --git a/drivers/sensor/icm42688/Kconfig b/drivers/sensor/icm42688/Kconfig index 2944a9d1183ad41..d7ee43bc7618bff 100644 --- a/drivers/sensor/icm42688/Kconfig +++ b/drivers/sensor/icm42688/Kconfig @@ -33,6 +33,7 @@ if ICM42688 choice prompt "Trigger mode" + default ICM42688_TRIGGER_NONE if ICM42688_STREAM default ICM42688_TRIGGER_GLOBAL_THREAD help Specify the type of triggering to be used by the driver @@ -50,6 +51,15 @@ config ICM42688_TRIGGER_OWN_THREAD endchoice +config ICM42688_STREAM + bool "Use hardware FIFO to stream data" + select ICM42688_TRIGGER + default y + depends on SPI_RTIO + depends on SENSOR_ASYNC_API + help + Use this config option to enable streaming sensor data via RTIO subsystem. + config ICM42688_TRIGGER bool diff --git a/drivers/sensor/icm42688/icm42688.c b/drivers/sensor/icm42688/icm42688.c index 43fd6a72f47f684..ee92c30987ecfce 100644 --- a/drivers/sensor/icm42688/icm42688.c +++ b/drivers/sensor/icm42688/icm42688.c @@ -82,7 +82,7 @@ int icm42688_channel_parse_readings(enum sensor_channel chan, int16_t readings[7 } static int icm42688_channel_get(const struct device *dev, enum sensor_channel chan, - struct sensor_value *val) + struct sensor_value *val) { struct icm42688_dev_data *data = dev->data; @@ -156,6 +156,19 @@ static int icm42688_attr_set(const struct device *dev, enum sensor_channel chan, res = -EINVAL; } break; + case SENSOR_CHAN_ALL: + if (attr == SENSOR_ATTR_FIFO_WATERMARK) { + int64_t mval = sensor_value_to_micro(val); + + if (mval < 0 || mval > 1000000) { + return -EINVAL; + } + new_config.fifo_wm = CLAMP(mval * 2048 / 1000000, 0, 2048); + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; default: LOG_ERR("Unsupported channel"); res = -EINVAL; @@ -257,7 +270,13 @@ int icm42688_init(const struct device *dev) data->cfg.gyro_mode = ICM42688_GYRO_LN; data->cfg.gyro_fs = ICM42688_GYRO_FS_125; data->cfg.gyro_odr = ICM42688_GYRO_ODR_1000; - data->cfg.fifo_en = false; + data->cfg.temp_dis = false; + data->cfg.fifo_en = IS_ENABLED(CONFIG_ICM42688_STREAM); + data->cfg.fifo_wm = 0; + data->cfg.fifo_hires = 0; + data->cfg.interrupt1_drdy = 0; + data->cfg.interrupt1_fifo_ths = 0; + data->cfg.interrupt1_fifo_full = 0; res = icm42688_configure(dev, &data->cfg); if (res != 0) { @@ -283,8 +302,15 @@ void icm42688_unlock(const struct device *dev) #define ICM42688_SPI_CFG \ SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_TRANSFER_MSB +#define ICM42688_RTIO_DEFINE(inst) \ + SPI_DT_IODEV_DEFINE(icm42688_spi_iodev_##inst, DT_DRV_INST(inst), ICM42688_SPI_CFG, 0U); \ + RTIO_DEFINE(icm42688_rtio_##inst, 8, 4); + #define ICM42688_DEFINE_DATA(inst) \ - static struct icm42688_dev_data icm42688_driver_##inst; + IF_ENABLED(CONFIG_ICM42688_STREAM, (ICM42688_RTIO_DEFINE(inst))); \ + static struct icm42688_dev_data icm42688_driver_##inst = { \ + IF_ENABLED(CONFIG_ICM42688_STREAM, (.r = &icm42688_rtio_##inst, \ + .spi_iodev = &icm42688_spi_iodev_##inst,))}; #define ICM42688_INIT(inst) \ ICM42688_DEFINE_DATA(inst); \ diff --git a/drivers/sensor/icm42688/icm42688.h b/drivers/sensor/icm42688/icm42688.h index 18ae4606e72593a..c4167e6a3b9cf4b 100644 --- a/drivers/sensor/icm42688/icm42688.h +++ b/drivers/sensor/icm42688/icm42688.h @@ -385,6 +385,9 @@ struct icm42688_cfg { /* TODO additional FIFO options */ /* TODO interrupt options */ + bool interrupt1_drdy; + bool interrupt1_fifo_ths; + bool interrupt1_fifo_full; }; struct icm42688_trigger_entry { @@ -405,6 +408,15 @@ struct icm42688_dev_data { #elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) struct k_work work; #endif +#ifdef CONFIG_ICM42688_STREAM + struct rtio_iodev_sqe *streaming_sqe; + struct rtio *r; + struct rtio_iodev *spi_iodev; + uint8_t int_status; + uint16_t fifo_count; + uint64_t timestamp; + atomic_t reading_fifo; +#endif /* CONFIG_ICM42688_STREAM */ const struct device *dev; struct gpio_callback gpio_cb; sensor_trigger_handler_t data_ready_handler; diff --git a/drivers/sensor/icm42688/icm42688_common.c b/drivers/sensor/icm42688/icm42688_common.c index 3ccd107cfbb3ef7..9cb3037ed06ea3b 100644 --- a/drivers/sensor/icm42688/icm42688_common.c +++ b/drivers/sensor/icm42688/icm42688_common.c @@ -12,6 +12,7 @@ #include "icm42688.h" #include "icm42688_reg.h" #include "icm42688_spi.h" +#include "icm42688_trigger.h" #include LOG_MODULE_REGISTER(ICM42688_LL, CONFIG_SENSOR_LOG_LEVEL); @@ -165,8 +166,12 @@ int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) } /* Pulse mode with async reset (resets interrupt line on int status read) */ - res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG, - BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY); + if (IS_ENABLED(CONFIG_ICM42688_TRIGGER)) { + res = icm42688_trigger_enable_interrupt(dev, cfg); + } else { + res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG, + BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY); + } if (res) { LOG_ERR("Error writing to INT_CONFIG"); return res; diff --git a/drivers/sensor/icm42688/icm42688_decoder.c b/drivers/sensor/icm42688/icm42688_decoder.c index 0a340aff3695672..3dc556ac61c7c3c 100644 --- a/drivers/sensor/icm42688/icm42688_decoder.c +++ b/drivers/sensor/icm42688/icm42688_decoder.c @@ -198,9 +198,262 @@ int icm42688_encode(const struct device *dev, const enum sensor_channel *const c return 0; } +#define IS_ACCEL(chan) ((chan) >= SENSOR_CHAN_ACCEL_X && (chan) <= SENSOR_CHAN_ACCEL_XYZ) +#define IS_GYRO(chan) ((chan) >= SENSOR_CHAN_GYRO_X && (chan) <= SENSOR_CHAN_GYRO_XYZ) + +static inline q31_t icm42688_read_temperature_from_packet(const uint8_t *pkt) +{ + int32_t temperature; + int32_t whole; + int32_t fraction; + + /* Temperature always assumes a shift of 9 for a range of (-273,273) C */ + if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) { + temperature = (pkt[0xd] << 8) | pkt[0xe]; + + icm42688_temp_c(temperature, &whole, &fraction); + } else { + if (FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1 && + FIELD_GET(FIFO_HEADER_GYRO, pkt[0]) == 1) { + temperature = pkt[0xd]; + } else { + temperature = pkt[0x7]; + } + + int64_t sensitivity = 207; + int64_t temperature100 = (temperature * 100) + (25 * sensitivity); + + whole = temperature100 / sensitivity; + fraction = + ((temperature100 - whole * sensitivity) * INT64_C(1000000)) / sensitivity; + } + __ASSERT_NO_MSG(whole >= -512 && whole <= 511); + return FIELD_PREP(GENMASK(31, 22), whole) | (fraction * GENMASK64(21, 0) / 1000000); +} + +static int icm42688_read_imu_from_packet(const uint8_t *pkt, bool is_accel, int fs, + uint8_t axis_offset, q31_t *out) +{ + int32_t value; + int64_t scale = 0; + int32_t max = BIT(15); + int offset = 1 + (axis_offset * 2); + + if (is_accel) { + switch (fs) { + case ICM42688_ACCEL_FS_2G: + scale = INT64_C(2) * BIT(31 - 5) * 9.80665; + break; + case ICM42688_ACCEL_FS_4G: + scale = INT64_C(4) * BIT(31 - 6) * 9.80665; + break; + case ICM42688_ACCEL_FS_8G: + scale = INT64_C(8) * BIT(31 - 7) * 9.80665; + break; + case ICM42688_ACCEL_FS_16G: + scale = INT64_C(16) * BIT(31 - 8) * 9.80665; + break; + } + } else { + switch (fs) { + case ICM42688_GYRO_FS_2000: + scale = 164; + break; + case ICM42688_GYRO_FS_1000: + scale = 328; + break; + case ICM42688_GYRO_FS_500: + scale = 655; + break; + case ICM42688_GYRO_FS_250: + scale = 1310; + break; + case ICM42688_GYRO_FS_125: + scale = 2620; + break; + case ICM42688_GYRO_FS_62_5: + scale = 5243; + break; + case ICM42688_GYRO_FS_31_25: + scale = 10486; + break; + case ICM42688_GYRO_FS_15_625: + scale = 20972; + break; + } + } + + if (!is_accel && FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1) { + offset += 7; + } + + value = (int16_t)sys_le16_to_cpu((pkt[offset] << 8) | pkt[offset + 1]); + + if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) { + uint32_t mask = is_accel ? GENMASK(7, 4) : GENMASK(3, 0); + + offset = 0x11 + axis_offset; + value = (value << 4) | FIELD_GET(mask, pkt[offset]); + /* In 20 bit mode, FS can only be +/-16g and +/-2000dps */ + scale = is_accel ? (INT64_C(16) * BIT(8) * 9.80665) : 131; + max = is_accel ? BIT(18) : BIT(19); + if (value == -524288) { + /* Invalid 20 bit value */ + return -ENODATA; + } + } else { + if (value <= -32767) { + /* Invalid 16 bit value */ + return -ENODATA; + } + } + + *out = (q31_t)(value * scale / max); + return 0; +} + +static uint32_t accel_period_ns[] = { + [ICM42688_ACCEL_ODR_1_5625] = UINT32_C(10000000000000) / 15625, + [ICM42688_ACCEL_ODR_3_125] = UINT32_C(10000000000000) / 31250, + [ICM42688_ACCEL_ODR_6_25] = UINT32_C(10000000000000) / 62500, + [ICM42688_ACCEL_ODR_12_5] = UINT32_C(10000000000000) / 12500, + [ICM42688_ACCEL_ODR_25] = UINT32_C(1000000000) / 25, + [ICM42688_ACCEL_ODR_50] = UINT32_C(1000000000) / 50, + [ICM42688_ACCEL_ODR_100] = UINT32_C(1000000000) / 100, + [ICM42688_ACCEL_ODR_200] = UINT32_C(1000000000) / 200, + [ICM42688_ACCEL_ODR_500] = UINT32_C(1000000000) / 500, + [ICM42688_ACCEL_ODR_1000] = UINT32_C(1000000), + [ICM42688_ACCEL_ODR_2000] = UINT32_C(1000000) / 2, + [ICM42688_ACCEL_ODR_4000] = UINT32_C(1000000) / 4, + [ICM42688_ACCEL_ODR_8000] = UINT32_C(1000000) / 8, + [ICM42688_ACCEL_ODR_16000] = UINT32_C(1000000) / 16, + [ICM42688_ACCEL_ODR_32000] = UINT32_C(1000000) / 32, +}; + +static uint32_t gyro_period_ns[] = { + [ICM42688_GYRO_ODR_12_5] = UINT32_C(10000000000000) / 12500, + [ICM42688_GYRO_ODR_25] = UINT32_C(1000000000) / 25, + [ICM42688_GYRO_ODR_50] = UINT32_C(1000000000) / 50, + [ICM42688_GYRO_ODR_100] = UINT32_C(1000000000) / 100, + [ICM42688_GYRO_ODR_200] = UINT32_C(1000000000) / 200, + [ICM42688_GYRO_ODR_500] = UINT32_C(1000000000) / 500, + [ICM42688_GYRO_ODR_1000] = UINT32_C(1000000), + [ICM42688_GYRO_ODR_2000] = UINT32_C(1000000) / 2, + [ICM42688_GYRO_ODR_4000] = UINT32_C(1000000) / 4, + [ICM42688_GYRO_ODR_8000] = UINT32_C(1000000) / 8, + [ICM42688_GYRO_ODR_16000] = UINT32_C(1000000) / 16, + [ICM42688_GYRO_ODR_32000] = UINT32_C(1000000) / 32, +}; + +static int icm42688_fifo_decode(const uint8_t *buffer, enum sensor_channel channel, + size_t channel_idx, uint32_t *fit, uint16_t max_count, + void *data_out) +{ + const struct icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer; + const uint8_t *buffer_end = buffer + sizeof(struct icm42688_fifo_data) + edata->fifo_count; + int accel_frame_count = 0; + int gyro_frame_count = 0; + int count = 0; + int rc; + + if ((uintptr_t)buffer_end <= *fit || channel_idx != 0) { + return 0; + } + + ((struct sensor_data_header *)data_out)->base_timestamp_ns = edata->header.timestamp; + + buffer += sizeof(struct icm42688_fifo_data); + while (count < max_count && buffer < buffer_end) { + const bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]) == 1; + const bool has_accel = FIELD_GET(FIFO_HEADER_ACCEL, buffer[0]) == 1; + const bool has_gyro = FIELD_GET(FIFO_HEADER_GYRO, buffer[0]) == 1; + const uint8_t *frame_end = buffer; + + if (is_20b) { + frame_end += 20; + } else if (has_accel && has_gyro) { + frame_end += 16; + } else { + frame_end += 8; + } + if (has_accel) { + accel_frame_count++; + } + if (has_gyro) { + gyro_frame_count++; + } + + if ((uintptr_t)buffer < *fit) { + /* This frame was already decoded, move on to the next frame */ + buffer = frame_end; + continue; + } + if (channel == SENSOR_CHAN_DIE_TEMP) { + struct sensor_q31_data *data = (struct sensor_q31_data *)data_out; + + data->shift = 9; + if (has_accel) { + data->readings[count].timestamp_delta = + accel_period_ns[edata->accel_odr] * (accel_frame_count - 1); + } else { + data->readings[count].timestamp_delta = + gyro_period_ns[edata->gyro_odr] * (gyro_frame_count - 1); + } + data->readings[count].temperature = + icm42688_read_temperature_from_packet(buffer); + } else if (IS_ACCEL(channel) && has_accel) { + /* Decode accel */ + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)data_out; + uint64_t period_ns = accel_period_ns[edata->accel_odr]; + + icm42688_get_shift(SENSOR_CHAN_ACCEL_XYZ, edata->header.accel_fs, + edata->header.gyro_fs, &data->shift); + + data->readings[count].timestamp_delta = (accel_frame_count - 1) * period_ns; + rc = icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 0, + &data->readings[count].x); + rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 1, + &data->readings[count].y); + rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 2, + &data->readings[count].z); + if (rc != 0) { + accel_frame_count--; + buffer = frame_end; + continue; + } + } else if (IS_GYRO(channel) && has_gyro) { + /* Decode gyro */ + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)data_out; + uint64_t period_ns = accel_period_ns[edata->gyro_odr]; + + icm42688_get_shift(SENSOR_CHAN_GYRO_XYZ, edata->header.accel_fs, + edata->header.gyro_fs, &data->shift); + + data->readings[count].timestamp_delta = (gyro_frame_count - 1) * period_ns; + rc = icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 0, + &data->readings[count].x); + rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 1, + &data->readings[count].y); + rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 2, + &data->readings[count].z); + if (rc != 0) { + gyro_frame_count--; + buffer = frame_end; + continue; + } + } + buffer = frame_end; + *fit = (uintptr_t)frame_end; + count++; + } + return count; +} + static int icm42688_one_shot_decode(const uint8_t *buffer, enum sensor_channel channel, - size_t channel_idx, uint32_t *fit, - uint16_t max_count, void *data_out) + size_t channel_idx, uint32_t *fit, uint16_t max_count, + void *data_out) { const struct icm42688_encoded_data *edata = (const struct icm42688_encoded_data *)buffer; const struct icm42688_decoder_header *header = &edata->header; @@ -318,34 +571,76 @@ static int icm42688_one_shot_decode(const uint8_t *buffer, enum sensor_channel c } static int icm42688_decoder_decode(const uint8_t *buffer, enum sensor_channel channel, - size_t channel_idx, uint32_t *fit, - uint16_t max_count, void *data_out) + size_t channel_idx, uint32_t *fit, uint16_t max_count, + void *data_out) { + const struct icm42688_decoder_header *header = + (const struct icm42688_decoder_header *)buffer; + + if (header->is_fifo) { + return icm42688_fifo_decode(buffer, channel, channel_idx, fit, max_count, data_out); + } return icm42688_one_shot_decode(buffer, channel, channel_idx, fit, max_count, data_out); } static int icm42688_decoder_get_frame_count(const uint8_t *buffer, enum sensor_channel channel, size_t channel_idx, uint16_t *frame_count) { - ARG_UNUSED(buffer); + const struct icm42688_fifo_data *data = (const struct icm42688_fifo_data *)buffer; + const struct icm42688_decoder_header *header = &data->header; + if (channel_idx != 0) { return -ENOTSUP; } - switch (channel) { - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_ACCEL_XYZ: - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - case SENSOR_CHAN_GYRO_XYZ: - case SENSOR_CHAN_DIE_TEMP: - *frame_count = 1; + + if (!header->is_fifo) { + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_DIE_TEMP: + *frame_count = 1; + return 0; + default: + return -ENOTSUP; + } return 0; - default: - return -ENOTSUP; } + + /* Skip the header */ + buffer += sizeof(struct icm42688_fifo_data); + + uint16_t count = 0; + const uint8_t *end = buffer + data->fifo_count; + + while (buffer < end) { + bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]); + int size = is_20b ? 3 : 2; + + if (FIELD_GET(FIFO_HEADER_ACCEL, buffer[0])) { + size += 6; + } + if (FIELD_GET(FIFO_HEADER_GYRO, buffer[0])) { + size += 6; + } + if (FIELD_GET(FIFO_HEADER_TIMESTAMP_FSYNC, buffer[0])) { + size += 2; + } + if (is_20b) { + size += 3; + } + + buffer += size; + ++count; + } + + *frame_count = count; + return 0; } static int icm42688_decoder_get_size_info(enum sensor_channel channel, size_t *base_size, @@ -372,10 +667,31 @@ static int icm42688_decoder_get_size_info(enum sensor_channel channel, size_t *b } } +static bool icm24688_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) +{ + const struct icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer; + + if (!edata->header.is_fifo) { + return false; + } + + switch (trigger) { + case SENSOR_TRIG_DATA_READY: + return FIELD_GET(BIT_INT_STATUS_DATA_RDY, edata->int_status); + case SENSOR_TRIG_FIFO_WATERMARK: + return FIELD_GET(BIT_INT_STATUS_FIFO_THS, edata->int_status); + case SENSOR_TRIG_FIFO_FULL: + return FIELD_GET(BIT_INT_STATUS_FIFO_FULL, edata->int_status); + default: + return false; + } +} + SENSOR_DECODER_API_DT_DEFINE() = { .get_frame_count = icm42688_decoder_get_frame_count, .get_size_info = icm42688_decoder_get_size_info, .decode = icm42688_decoder_decode, + .has_trigger = icm24688_decoder_has_trigger, }; int icm42688_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) diff --git a/drivers/sensor/icm42688/icm42688_decoder.h b/drivers/sensor/icm42688/icm42688_decoder.h index 2ef806373c94021..499cf3d0801554d 100644 --- a/drivers/sensor/icm42688/icm42688_decoder.h +++ b/drivers/sensor/icm42688/icm42688_decoder.h @@ -18,6 +18,15 @@ struct icm42688_decoder_header { uint8_t reserved: 2; } __attribute__((__packed__)); +struct icm42688_fifo_data { + struct icm42688_decoder_header header; + uint8_t int_status; + uint16_t gyro_odr: 4; + uint16_t accel_odr: 4; + uint16_t fifo_count: 11; + uint16_t reserved: 5; +} __attribute__((__packed__)); + struct icm42688_encoded_data { struct icm42688_decoder_header header; struct { diff --git a/drivers/sensor/icm42688/icm42688_reg.h b/drivers/sensor/icm42688/icm42688_reg.h index dfc348c072c8c75..5f3b58f0b3c074d 100644 --- a/drivers/sensor/icm42688/icm42688_reg.h +++ b/drivers/sensor/icm42688/icm42688_reg.h @@ -286,4 +286,12 @@ #define MCLK_POLL_ATTEMPTS 100 #define SOFT_RESET_TIME_MS 2 /* 1ms + elbow room */ +/* FIFO header */ +#define FIFO_HEADER_ACCEL BIT(6) +#define FIFO_HEADER_GYRO BIT(5) +#define FIFO_HEADER_20 BIT(4) +#define FIFO_HEADER_TIMESTAMP_FSYNC GENMASK(3, 2) +#define FIFO_HEADER_ODR_ACCEL BIT(1) +#define FIFO_HEADER_ODR_GYRO BIT(0) + #endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_REG_H_ */ diff --git a/drivers/sensor/icm42688/icm42688_rtio.c b/drivers/sensor/icm42688/icm42688_rtio.c index c1b20689393d6c0..ccb9532ee45a2c8 100644 --- a/drivers/sensor/icm42688/icm42688_rtio.c +++ b/drivers/sensor/icm42688/icm42688_rtio.c @@ -8,6 +8,7 @@ #include "icm42688.h" #include "icm42688_decoder.h" #include "icm42688_reg.h" +#include "icm42688_rtio.h" #include "icm42688_spi.h" #include @@ -42,7 +43,7 @@ static int icm42688_rtio_sample_fetch(const struct device *dev, int16_t readings return 0; } -int icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +static int icm42688_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) { const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; const enum sensor_channel *const channels = cfg->channels; @@ -78,4 +79,17 @@ int icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) return 0; } +int icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + + if (!cfg->is_streaming) { + return icm42688_submit_one_shot(dev, iodev_sqe); + } else if (IS_ENABLED(CONFIG_ICM42688_STREAM)) { + return icm42688_submit_stream(dev, iodev_sqe); + } else { + return -ENOTSUP; + } +} + BUILD_ASSERT(sizeof(struct icm42688_decoder_header) == 9); diff --git a/drivers/sensor/icm42688/icm42688_rtio.h b/drivers/sensor/icm42688/icm42688_rtio.h index 748c8a022b09238..888e8e95357aeae 100644 --- a/drivers/sensor/icm42688/icm42688_rtio.h +++ b/drivers/sensor/icm42688/icm42688_rtio.h @@ -7,6 +7,13 @@ #ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ #define ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ +#include +#include + int icm42688_submit(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); +int icm42688_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); + +void icm42688_fifo_event(const struct device *dev); + #endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ */ diff --git a/drivers/sensor/icm42688/icm42688_rtio_stream.c b/drivers/sensor/icm42688/icm42688_rtio_stream.c new file mode 100644 index 000000000000000..57d1a66cfde9ccf --- /dev/null +++ b/drivers/sensor/icm42688/icm42688_rtio_stream.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "icm42688.h" +#include "icm42688_decoder.h" +#include "icm42688_reg.h" +#include "icm42688_rtio.h" + +LOG_MODULE_DECLARE(ICM42688_RTIO); + +int icm42688_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe) +{ + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + struct icm42688_dev_data *data = sensor->data; + struct icm42688_cfg new_config = data->cfg; + + new_config.interrupt1_drdy = false; + new_config.interrupt1_fifo_ths = false; + new_config.interrupt1_fifo_full = false; + for (int i = 0; i < cfg->count; ++i) { + switch (cfg->triggers[i].trigger) { + case SENSOR_TRIG_DATA_READY: + new_config.interrupt1_drdy = true; + break; + case SENSOR_TRIG_FIFO_WATERMARK: + new_config.interrupt1_fifo_ths = true; + break; + case SENSOR_TRIG_FIFO_FULL: + new_config.interrupt1_fifo_full = true; + break; + default: + LOG_DBG("Trigger (%d) not supported", cfg->triggers[i].trigger); + break; + } + } + + if (new_config.interrupt1_drdy != data->cfg.interrupt1_drdy || + new_config.interrupt1_fifo_ths != data->cfg.interrupt1_fifo_ths || + new_config.interrupt1_fifo_full != data->cfg.interrupt1_fifo_full) { + int rc = icm42688_safely_configure(sensor, &new_config); + + if (rc != 0) { + LOG_ERR("Failed to configure sensor"); + return rc; + } + } + + data->streaming_sqe = iodev_sqe; + return 0; +} + +static void icm42688_complete_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +{ + const struct device *dev = arg; + struct icm42688_dev_data *drv_data = dev->data; + const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct rtio_iodev_sqe *iodev_sqe = sqe->userdata; + + rtio_iodev_sqe_ok(iodev_sqe, drv_data->fifo_count); + + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); +} + +static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +{ + const struct device *dev = arg; + struct icm42688_dev_data *drv_data = dev->data; + const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct rtio_iodev *spi_iodev = drv_data->spi_iodev; + uint8_t *fifo_count_buf = (uint8_t *)&drv_data->fifo_count; + uint16_t fifo_count = ((fifo_count_buf[0] << 8) | fifo_count_buf[1]); + + drv_data->fifo_count = fifo_count; + + /* Pull a operation from our device iodev queue, validated to only be reads */ + struct rtio_iodev_sqe *iodev_sqe = drv_data->streaming_sqe; + + drv_data->streaming_sqe = NULL; + + /* Not inherently an underrun/overrun as we may have a buffer to fill next time */ + if (iodev_sqe == NULL) { + LOG_DBG("No pending SQE"); + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + const size_t packet_size = drv_data->cfg.fifo_hires ? 20 : 16; + const size_t min_read_size = sizeof(struct icm42688_fifo_data) + packet_size; + const size_t ideal_read_size = sizeof(struct icm42688_fifo_data) + fifo_count; + uint8_t *buf; + uint32_t buf_len; + + if (rtio_sqe_rx_buf(iodev_sqe, min_read_size, ideal_read_size, &buf, &buf_len) != 0) { + LOG_ERR("Failed to get buffer"); + rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); + return; + } + LOG_DBG("Requesting buffer [%u, %u] got %u", (unsigned int)min_read_size, + (unsigned int)ideal_read_size, buf_len); + + /* Read FIFO and call back to rtio with rtio_sqe completion */ + /* TODO is packet format even needed? the fifo has a header per packet + * already + */ + struct icm42688_fifo_data hdr = { + .header = { + .is_fifo = true, + .gyro_fs = drv_data->cfg.gyro_fs, + .accel_fs = drv_data->cfg.accel_fs, + .timestamp = drv_data->timestamp, + }, + .int_status = drv_data->int_status, + .gyro_odr = drv_data->cfg.gyro_odr, + .accel_odr = drv_data->cfg.accel_odr, + }; + uint32_t buf_avail = buf_len; + + memcpy(buf, &hdr, sizeof(hdr)); + buf_avail -= sizeof(hdr); + + uint32_t read_len = MIN(fifo_count, buf_avail); + uint32_t pkts = read_len / packet_size; + + read_len = pkts * packet_size; + ((struct icm42688_fifo_data *)buf)->fifo_count = read_len; + + __ASSERT_NO_MSG(read_len % pkt_size == 0); + + uint8_t *read_buf = buf + sizeof(hdr); + + /* Flush out completions */ + struct rtio_cqe *cqe; + + do { + cqe = rtio_cqe_consume(r); + if (cqe != NULL) { + rtio_cqe_release(r, cqe); + } + } while (cqe != NULL); + + /* Setup new rtio chain to read the fifo data and report then check the + * result + */ + struct rtio_sqe *write_fifo_addr = rtio_sqe_acquire(r); + struct rtio_sqe *read_fifo_data = rtio_sqe_acquire(r); + struct rtio_sqe *complete_op = rtio_sqe_acquire(r); + const uint8_t reg_addr = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_DATA); + + rtio_sqe_prep_tiny_write(write_fifo_addr, spi_iodev, RTIO_PRIO_NORM, ®_addr, 1, NULL); + write_fifo_addr->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_fifo_data, spi_iodev, RTIO_PRIO_NORM, read_buf, read_len, + iodev_sqe); + + rtio_sqe_prep_callback(complete_op, icm42688_complete_cb, (void *)dev, iodev_sqe); + + rtio_submit(r, 0); +} + +static struct sensor_stream_trigger * +icm42688_get_read_config_trigger(const struct sensor_read_config *cfg, + enum sensor_trigger_type trig) +{ + for (int i = 0; i < cfg->count; ++i) { + if (cfg->triggers[i].trigger == trig) { + return &cfg->triggers[i]; + } + } + LOG_DBG("Unsupported trigger (%d)", trig); + return NULL; +} + +static void icm42688_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, void *arg) +{ + const struct device *dev = arg; + struct icm42688_dev_data *drv_data = dev->data; + const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct rtio_iodev *spi_iodev = drv_data->spi_iodev; + struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; + struct sensor_read_config *read_config; + + if (streaming_sqe == NULL) { + return; + } + + read_config = (struct sensor_read_config *)streaming_sqe->sqe.iodev->data; + __ASSERT_NO_MSG(read_config != NULL); + + if (!read_config->is_streaming) { + /* Oops, not really configured for streaming data */ + return; + } + + struct sensor_stream_trigger *fifo_ths_cfg = + icm42688_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_WATERMARK); + bool has_fifo_ths_trig = fifo_ths_cfg != NULL && + FIELD_GET(BIT_INT_STATUS_FIFO_THS, drv_data->int_status) != 0; + + struct sensor_stream_trigger *fifo_full_cfg = + icm42688_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_FULL); + bool has_fifo_full_trig = fifo_full_cfg != NULL && + FIELD_GET(BIT_INT_STATUS_FIFO_FULL, drv_data->int_status) != 0; + + if (!has_fifo_ths_trig && !has_fifo_full_trig) { + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + /* Flush completions */ + struct rtio_cqe *cqe; + + do { + cqe = rtio_cqe_consume(r); + if (cqe != NULL) { + rtio_cqe_release(r, cqe); + } + } while (cqe != NULL); + + enum sensor_stream_data_opt data_opt; + + if (has_fifo_ths_trig && !has_fifo_full_trig) { + /* Only care about fifo threshold */ + data_opt = fifo_ths_cfg->opt; + } else if (!has_fifo_ths_trig && has_fifo_full_trig) { + /* Only care about fifo full */ + data_opt = fifo_full_cfg->opt; + } else { + /* Both fifo threshold and full */ + data_opt = MIN(fifo_ths_cfg->opt, fifo_full_cfg->opt); + } + + if (data_opt == SENSOR_STREAM_DATA_NOP || data_opt == SENSOR_STREAM_DATA_DROP) { + uint8_t *buf; + uint32_t buf_len; + + /* Clear streaming_sqe since we're done with the call */ + drv_data->streaming_sqe = NULL; + if (rtio_sqe_rx_buf(streaming_sqe, sizeof(struct icm42688_fifo_data), + sizeof(struct icm42688_fifo_data), &buf, &buf_len) != 0) { + rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); + return; + } + + struct icm42688_fifo_data *data = (struct icm42688_fifo_data *)buf; + + memset(buf, 0, buf_len); + data->header.timestamp = drv_data->timestamp; + data->int_status = drv_data->int_status; + data->fifo_count = 0; + rtio_iodev_sqe_ok(streaming_sqe, 0); + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + if (data_opt == SENSOR_STREAM_DATA_DROP) { + /* Flush the FIFO */ + struct rtio_sqe *write_signal_path_reset = rtio_sqe_acquire(r); + uint8_t write_buffer[] = { + FIELD_GET(REG_ADDRESS_MASK, REG_SIGNAL_PATH_RESET), + BIT_FIFO_FLUSH, + }; + + rtio_sqe_prep_tiny_write(write_signal_path_reset, spi_iodev, RTIO_PRIO_NORM, + write_buffer, ARRAY_SIZE(write_buffer), NULL); + /* TODO Add a new flag for fire-and-forget so we don't have to block here */ + rtio_submit(r, 1); + ARG_UNUSED(rtio_cqe_consume(r)); + } + return; + } + + /* We need the data, read the fifo length */ + struct rtio_sqe *write_fifo_count_reg = rtio_sqe_acquire(r); + struct rtio_sqe *read_fifo_count = rtio_sqe_acquire(r); + struct rtio_sqe *check_fifo_count = rtio_sqe_acquire(r); + uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_COUNTH); + uint8_t *read_buf = (uint8_t *)&drv_data->fifo_count; + + rtio_sqe_prep_tiny_write(write_fifo_count_reg, spi_iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_fifo_count_reg->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_fifo_count, spi_iodev, RTIO_PRIO_NORM, read_buf, 2, NULL); + rtio_sqe_prep_callback(check_fifo_count, icm42688_fifo_count_cb, arg, NULL); + + rtio_submit(r, 0); +} + +void icm42688_fifo_event(const struct device *dev) +{ + struct icm42688_dev_data *drv_data = dev->data; + struct rtio_iodev *spi_iodev = drv_data->spi_iodev; + struct rtio *r = drv_data->r; + + if (drv_data->streaming_sqe == NULL) { + return; + } + + drv_data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + + /* + * Setup rtio chain of ops with inline calls to make decisions + * 1. read int status + * 2. call to check int status and get pending RX operation + * 4. read fifo len + * 5. call to determine read len + * 6. read fifo + * 7. call to report completion + */ + struct rtio_sqe *write_int_reg = rtio_sqe_acquire(r); + struct rtio_sqe *read_int_reg = rtio_sqe_acquire(r); + struct rtio_sqe *check_int_status = rtio_sqe_acquire(r); + uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_INT_STATUS); + + rtio_sqe_prep_tiny_write(write_int_reg, spi_iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_int_reg->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_int_reg, spi_iodev, RTIO_PRIO_NORM, &drv_data->int_status, 1, NULL); + rtio_sqe_prep_callback(check_int_status, icm42688_int_status_cb, (void *)dev, NULL); + rtio_submit(r, 0); +} diff --git a/drivers/sensor/icm42688/icm42688_trigger.c b/drivers/sensor/icm42688/icm42688_trigger.c index adaecf84baa6566..32b60f3cd75945d 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.c +++ b/drivers/sensor/icm42688/icm42688_trigger.c @@ -12,6 +12,7 @@ #include "icm42688.h" #include "icm42688_reg.h" +#include "icm42688_rtio.h" #include "icm42688_spi.h" #include "icm42688_trigger.h" @@ -30,6 +31,9 @@ static void icm42688_gpio_callback(const struct device *dev, struct gpio_callbac #elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) k_work_submit(&data->work); #endif + if (IS_ENABLED(CONFIG_ICM42688_STREAM)) { + icm42688_fifo_event(data->dev); + } } #if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) || defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) @@ -90,6 +94,8 @@ int icm42688_trigger_set(const struct device *dev, const struct sensor_trigger * switch (trig->type) { case SENSOR_TRIG_DATA_READY: + case SENSOR_TRIG_FIFO_WATERMARK: + case SENSOR_TRIG_FIFO_FULL: data->data_ready_handler = handler; data->data_ready_trigger = trig; @@ -146,7 +152,7 @@ int icm42688_trigger_init(const struct device *dev) return gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); } -int icm42688_trigger_enable_interrupt(const struct device *dev) +int icm42688_trigger_enable_interrupt(const struct device *dev, struct icm42688_cfg *new_cfg) { int res; const struct icm42688_dev_cfg *cfg = dev->config; @@ -164,9 +170,19 @@ int icm42688_trigger_enable_interrupt(const struct device *dev) return res; } - /* enable data ready interrupt on INT1 pin */ - return icm42688_spi_single_write(&cfg->spi, REG_INT_SOURCE0, - FIELD_PREP(BIT_UI_DRDY_INT1_EN, 1)); + /* enable interrupts on INT1 pin */ + uint8_t value = 0; + + if (new_cfg->interrupt1_drdy) { + value |= FIELD_PREP(BIT_UI_DRDY_INT1_EN, 1); + } + if (new_cfg->interrupt1_fifo_ths) { + value |= FIELD_PREP(BIT_FIFO_THS_INT1_EN, 1); + } + if (new_cfg->interrupt1_fifo_full) { + value |= FIELD_PREP(BIT_FIFO_FULL_INT1_EN, 1); + } + return icm42688_spi_single_write(&cfg->spi, REG_INT_SOURCE0, value); } void icm42688_lock(const struct device *dev) diff --git a/drivers/sensor/icm42688/icm42688_trigger.h b/drivers/sensor/icm42688/icm42688_trigger.h index 5ed382eb0d403a1..e03975916181203 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.h +++ b/drivers/sensor/icm42688/icm42688_trigger.h @@ -26,9 +26,10 @@ int icm42688_trigger_init(const struct device *dev); * @brief enable the trigger gpio interrupt * * @param dev icm42688 device pointer + * @param new_cfg New configuration to use for the device * @return int 0 on success, negative error code otherwise */ -int icm42688_trigger_enable_interrupt(const struct device *dev); +int icm42688_trigger_enable_interrupt(const struct device *dev, struct icm42688_cfg *new_cfg); /** * @brief lock access to the icm42688 device driver From 3c6e66e5b576d774a0357dc2af61d6c4eb4f3307 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Tue, 10 Oct 2023 01:59:04 -0600 Subject: [PATCH 0214/1049] sensors: convert fifo_wm to batch_dur Having a % FIFO watermark isn't very useful as it doesn't convey how long the SoC can sleep (or do other work) while batching sensor data. Convert the attribute to a batch duration using ticks. Currently the ticks are in system ticks, but eventually when an external clock is attached to the sensor it will be in the external clock's ticks. Signed-off-by: Yuval Peress --- drivers/sensor/icm42688/icm42688.c | 19 ++++--- drivers/sensor/icm42688/icm42688.h | 2 +- drivers/sensor/icm42688/icm42688_common.c | 61 ++++++++++++++++++++++- drivers/sensor/sensor_shell.c | 2 +- include/zephyr/drivers/sensor.h | 6 ++- 5 files changed, 78 insertions(+), 12 deletions(-) diff --git a/drivers/sensor/icm42688/icm42688.c b/drivers/sensor/icm42688/icm42688.c index ee92c30987ecfce..a6b4cd06c521978 100644 --- a/drivers/sensor/icm42688/icm42688.c +++ b/drivers/sensor/icm42688/icm42688.c @@ -157,13 +157,11 @@ static int icm42688_attr_set(const struct device *dev, enum sensor_channel chan, } break; case SENSOR_CHAN_ALL: - if (attr == SENSOR_ATTR_FIFO_WATERMARK) { - int64_t mval = sensor_value_to_micro(val); - - if (mval < 0 || mval > 1000000) { + if (attr == SENSOR_ATTR_BATCH_DURATION) { + if (val->val1 < 0) { return -EINVAL; } - new_config.fifo_wm = CLAMP(mval * 2048 / 1000000, 0, 2048); + new_config.batch_ticks = val->val1; } else { LOG_ERR("Unsupported attribute"); res = -EINVAL; @@ -217,6 +215,15 @@ static int icm42688_attr_get(const struct device *dev, enum sensor_channel chan, res = -EINVAL; } break; + case SENSOR_CHAN_ALL: + if (attr == SENSOR_ATTR_BATCH_DURATION) { + val->val1 = cfg->batch_ticks; + val->val2 = 0; + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; default: LOG_ERR("Unsupported channel"); res = -EINVAL; @@ -272,7 +279,7 @@ int icm42688_init(const struct device *dev) data->cfg.gyro_odr = ICM42688_GYRO_ODR_1000; data->cfg.temp_dis = false; data->cfg.fifo_en = IS_ENABLED(CONFIG_ICM42688_STREAM); - data->cfg.fifo_wm = 0; + data->cfg.batch_ticks = 0; data->cfg.fifo_hires = 0; data->cfg.interrupt1_drdy = 0; data->cfg.interrupt1_fifo_ths = 0; diff --git a/drivers/sensor/icm42688/icm42688.h b/drivers/sensor/icm42688/icm42688.h index c4167e6a3b9cf4b..5ec470cff270c38 100644 --- a/drivers/sensor/icm42688/icm42688.h +++ b/drivers/sensor/icm42688/icm42688.h @@ -380,7 +380,7 @@ struct icm42688_cfg { /* TODO timestamp options */ bool fifo_en; - uint16_t fifo_wm; + int32_t batch_ticks; bool fifo_hires; /* TODO additional FIFO options */ diff --git a/drivers/sensor/icm42688/icm42688_common.c b/drivers/sensor/icm42688/icm42688_common.c index 9cb3037ed06ea3b..4df2f7870927665 100644 --- a/drivers/sensor/icm42688/icm42688_common.c +++ b/drivers/sensor/icm42688/icm42688_common.c @@ -62,6 +62,62 @@ int icm42688_reset(const struct device *dev) return 0; } +static uint16_t icm42688_compute_fifo_wm(const struct icm42688_cfg *cfg) +{ + const bool accel_enabled = cfg->accel_mode != ICM42688_ACCEL_OFF; + const bool gyro_enabled = cfg->gyro_mode != ICM42688_GYRO_OFF; + const int pkt_size = cfg->fifo_hires ? 20 : (accel_enabled && gyro_enabled ? 16 : 8); + int accel_modr = 0; + int gyro_modr = 0; + int64_t modr; + + if (cfg->batch_ticks == 0 || (!accel_enabled && !gyro_enabled)) { + return 0; + } + + if (accel_enabled) { + struct sensor_value val = {0}; + + icm42688_accel_reg_to_hz(cfg->accel_odr, &val); + accel_modr = sensor_value_to_micro(&val) / 1000; + } + if (gyro_enabled) { + struct sensor_value val = {0}; + + icm42688_gyro_reg_to_odr(cfg->gyro_odr, &val); + gyro_modr = sensor_value_to_micro(&val) / 1000; + } + + if (accel_modr == 0) { + modr = gyro_modr; + } else if (gyro_modr == 0) { + modr = accel_modr; + } else { + /* Need to find the least common multiplier (LCM) */ + int n1 = accel_modr; + int n2 = gyro_modr; + + while (n1 != n2) { + if (n1 > n2) { + n1 -= n2; + } else { + n2 -= n1; + } + } + LOG_DBG("GCD=%d", n1); + modr = ((int64_t)accel_modr * (int64_t)gyro_modr) / n1; + } + /* At this point we have 'modr' as mHz which is 1 / msec. */ + + /* Convert 'modr' to bytes * batch_ticks / msec */ + modr *= (int64_t)cfg->batch_ticks * pkt_size; + + /* 'modr' = byte_ticks_per_msec / kticks_per_sec */ + modr = DIV_ROUND_UP(modr, CONFIG_SYS_CLOCK_TICKS_PER_SEC * INT64_C(1000)); + + return (uint16_t)MIN(modr, 0x7ff); +} + int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) { struct icm42688_dev_data *dev_data = dev->data; @@ -210,7 +266,8 @@ int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) } /* Set watermark and interrupt handling first */ - uint8_t fifo_wml = (cfg->fifo_wm) & 0xFF; + uint16_t fifo_wm = icm42688_compute_fifo_wm(cfg); + uint8_t fifo_wml = fifo_wm & 0xFF; LOG_DBG("FIFO_CONFIG2( (0x%x)) (WM Low) 0x%x", REG_FIFO_CONFIG2, fifo_wml); res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG2, fifo_wml); @@ -219,7 +276,7 @@ int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) return -EINVAL; } - uint8_t fifo_wmh = (cfg->fifo_wm >> 8) & 0x0F; + uint8_t fifo_wmh = (fifo_wm >> 8) & 0x0F; LOG_DBG("FIFO_CONFIG3 (0x%x) (WM High) 0x%x", REG_FIFO_CONFIG3, fifo_wmh); res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG3, fifo_wmh); diff --git a/drivers/sensor/sensor_shell.c b/drivers/sensor/sensor_shell.c index 5d41663c491db8a..bfeac4e452fd6ce 100644 --- a/drivers/sensor/sensor_shell.c +++ b/drivers/sensor/sensor_shell.c @@ -122,7 +122,7 @@ static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { [SENSOR_ATTR_FEATURE_MASK] = "feature_mask", [SENSOR_ATTR_ALERT] = "alert", [SENSOR_ATTR_FF_DUR] = "ff_dur", - [SENSOR_ATTR_FIFO_WATERMARK] = "fifo_wm", + [SENSOR_ATTR_BATCH_DURATION] = "batch_dur", }; /* Forward declaration */ diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 80fda1b163483eb..e652c3a2040563e 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -334,8 +334,10 @@ enum sensor_attribute { * to the new sampling frequency. */ SENSOR_ATTR_FF_DUR, - /** Watermark % for the hardware fifo interrupt */ - SENSOR_ATTR_FIFO_WATERMARK, + + /** Hardware batch duration in ticks */ + SENSOR_ATTR_BATCH_DURATION, + /** * Number of all common sensor attributes. */ From 155f866ecc2c3117f8665a53408bef6fd9bd3a97 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Fri, 3 Nov 2023 13:03:46 +0100 Subject: [PATCH 0215/1049] dts: intel_adsp: ace remove dw watchdog DW watchdog driver is not used on ACE, Intel ADSP watchdog driver will be used in DTS when ready to use Signed-off-by: Adrian Bonislawski --- dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi | 26 --------------------- 1 file changed, 26 deletions(-) diff --git a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi index 564ee3fe26df187..de8aa8ed6fd39b7 100644 --- a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi @@ -513,32 +513,6 @@ interrupt-parent = <&ace_intc>; }; - watchdog0: watchdog@78300 { - compatible = "snps,designware-watchdog"; - reg = <0x78300 0x100>; - interrupts = <8 0 0>; - interrupt-parent = <&core_intc>; - clock-frequency = <32768>; - reset-pulse-length = <2>; - status = "okay"; - }; - - watchdog1: watchdog@78400 { - compatible = "snps,designware-watchdog"; - reg = <0x78400 0x100>; - clock-frequency = <32768>; - reset-pulse-length = <2>; - status = "okay"; - }; - - watchdog2: watchdog@78500 { - compatible = "snps,designware-watchdog"; - reg = <0x78500 0x100>; - clock-frequency = <32768>; - reset-pulse-length = <2>; - status = "okay"; - }; - /* This is actually an array of per-core designware * controllers, but the special setup and extra * masking layer makes it easier for MTL to handle From 6bd0b54526cda9dcbcb77c0adf933517ca46fecd Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Mon, 6 Nov 2023 13:48:51 -0700 Subject: [PATCH 0216/1049] twister: Fix gtest harness Some platforms prefix extra logging information before the standard [] blocks so I've added `.\*` to the regex. Also, removed the static values so they're only referenced using 'self.' and stopped parsing lines after the FINISHED_PATTERN is matched since some versions of gTest also print out a test summary after and it's not useful for the processing. Signed-off-by: Yuval Peress --- scripts/pylib/twister/twisterlib/harness.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index 53765f6da384524..ef24ef577204d13 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -450,17 +450,23 @@ def _parse_report_file(self, report): class Gtest(Harness): ANSI_ESCAPE = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') - TEST_START_PATTERN = r"\[ RUN \] (?P.*)\.(?P.*)$" - TEST_PASS_PATTERN = r"\[ OK \] (?P.*)\.(?P.*)$" - TEST_FAIL_PATTERN = r"\[ FAILED \] (?P.*)\.(?P.*)$" - FINISHED_PATTERN = r"\[==========\] Done running all tests\.$" - has_failures = False - tc = None + TEST_START_PATTERN = r".*\[ RUN \] (?P.*)\.(?P.*)$" + TEST_PASS_PATTERN = r".*\[ OK \] (?P.*)\.(?P.*)$" + TEST_FAIL_PATTERN = r".*\[ FAILED \] (?P.*)\.(?P.*)$" + FINISHED_PATTERN = r".*\[==========\] Done running all tests\.$" + + def __init__(self): + super().__init__() + self.tc = None + self.has_failures = False def handle(self, line): # Strip the ANSI characters, they mess up the patterns non_ansi_line = self.ANSI_ESCAPE.sub('', line) + if self.state: + return + # Check if we started running a new test test_start_match = re.search(self.TEST_START_PATTERN, non_ansi_line) if test_start_match: From 27fe62c33ff73b066fe8fc4ccd2e8fe45e64a058 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 10 Nov 2023 14:31:28 +0530 Subject: [PATCH 0217/1049] ieee802154: ieee802154_cc13xx_cc26xx_subg: Add cc1352p7 support - Add support cc1352p7 used by beagleconnect_freedom - Since this is a multi interface device, auto config does not work. Signed-off-by: Ayush Singh --- drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 780700aac4f65df..ea626908d168db8 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -82,7 +82,7 @@ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = { }; /* Radio values for CC13X2P */ -#elif defined(CONFIG_SOC_CC1352P) +#elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7) /* CC1352P overrides from SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW) */ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = { /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4:3]=0x1) */ @@ -141,7 +141,7 @@ static uint32_t rf_prop_overrides_tx_20[] = { #if defined(CONFIG_SOC_CC1352R) static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_subg_radio_div_setup = { .commandNo = CMD_PROP_RADIO_DIV_SETUP, -#elif defined(CONFIG_SOC_CC1352P) +#elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7) static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_subg_radio_div_setup = { .commandNo = CMD_PROP_RADIO_DIV_SETUP_PA, #endif /* CONFIG_SOC_CC1352x */ @@ -207,7 +207,7 @@ static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = { #endif RF_TxPowerTable_TERMINATION_ENTRY }; -#elif defined(CONFIG_SOC_CC1352P) +#elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7) /* Sub GHz power table */ static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = { { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) }, From 26f30db8adabe40983ca2501e1c866dc7ebe2d5c Mon Sep 17 00:00:00 2001 From: Jason Kridner Date: Fri, 10 Nov 2023 15:48:41 +0530 Subject: [PATCH 0218/1049] soc: arm: ti_simplelink: cc13x2x7_cc26x2x7: add caparray delta config - Make caparray delta a Kconfig variable - Set caparray delta for beagle_bcf at beagleconnect_freedom_defconfig Signed-off-by: Ayush Singh Signed-off-by: Jason Kridner --- boards/arm/beagle_bcf/beagleconnect_freedom_defconfig | 3 +++ soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.soc | 7 +++++++ soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/boards/arm/beagle_bcf/beagleconnect_freedom_defconfig b/boards/arm/beagle_bcf/beagleconnect_freedom_defconfig index d1d9ff8f84ef798..a2c05f40f32331f 100644 --- a/boards/arm/beagle_bcf/beagleconnect_freedom_defconfig +++ b/boards/arm/beagle_bcf/beagleconnect_freedom_defconfig @@ -25,3 +25,6 @@ CONFIG_HW_STACK_PROTECTION=y CONFIG_SERIAL=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y + +# Adjust for oscillator capacitors +CONFIG_CC13X2_CC26X2_XOSC_CAPARRAY_DELTA=0x02 diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.soc b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.soc index 74fae9acafd0eee..96bd6cfce941886 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.soc +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.soc @@ -65,4 +65,11 @@ config CC13X2_CC26X2_BOOTLOADER_BACKDOOR_LEVEL help Set the active level of the pin selected for the bootloader backdoor. +config CC13X2_CC26X2_XOSC_CAPARRAY_DELTA + hex "Cap array tuning delta" + range 0 0xFF + default 0xD5 + help + Enable a specific cap array tunning delta. + endmenu diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c index 74f34acac0d5788..de7b81c32bfbd8c 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c @@ -28,7 +28,7 @@ * https://software-dl.ti.com/simplelink/esd/simplelink_cc13xx_cc26xx_sdk/6.20.00.29/exports/release_notes_simplelink_cc13xx_cc26xx_sdk_6_20_00_29.html#known-issues */ #define SET_CCFG_MODE_CONF_XOSC_CAP_MOD 0x0 -#define SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA 0xD5 +#define SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA CONFIG_CC13X2_CC26X2_XOSC_CAPARRAY_DELTA #endif /* TI recommends setting CCFG values and then including the TI provided ccfg.c */ From 6ae03d98a0e5b636c62f8191f464e12d3782d6b1 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 22 May 2023 13:57:55 +0000 Subject: [PATCH 0219/1049] drivers, subsys: sort the lists again, mark the blocks for checking Sort the Kconfig and CMakeLists include blocks again, and mark the start and end of the blocks so that the CI can keep them sorted. Signed-off-by: Fabio Baltieri --- drivers/CMakeLists.txt | 16 +++++++++------- drivers/Kconfig | 10 ++++++---- subsys/CMakeLists.txt | 6 ++++-- subsys/Kconfig | 4 +++- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index b7fcdbed373a7cd..6310146bb3d47e3 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -5,6 +5,7 @@ add_compile_options($) add_definitions(-D__ZEPHYR_SUPERVISOR__) +# zephyr-keep-sorted-start add_subdirectory(disk) add_subdirectory(interrupt_controller) add_subdirectory(misc) @@ -13,14 +14,15 @@ add_subdirectory(usb) add_subdirectory(usb_c) add_subdirectory_ifdef(CONFIG_ADC adc) +add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_DRIVER sip_svc) add_subdirectory_ifdef(CONFIG_AUDIO audio) +add_subdirectory_ifdef(CONFIG_AUXDISPLAY auxdisplay) add_subdirectory_ifdef(CONFIG_BBRAM bbram) -add_subdirectory_ifdef(CONFIG_XEN xen) add_subdirectory_ifdef(CONFIG_BT_DRIVERS bluetooth) add_subdirectory_ifdef(CONFIG_CACHE_MANAGEMENT cache) add_subdirectory_ifdef(CONFIG_CAN can) -add_subdirectory_ifdef(CONFIG_CLOCK_CONTROL clock_control) add_subdirectory_ifdef(CONFIG_CHARGER charger) +add_subdirectory_ifdef(CONFIG_CLOCK_CONTROL clock_control) add_subdirectory_ifdef(CONFIG_CONSOLE console) add_subdirectory_ifdef(CONFIG_COREDUMP_DEVICE coredump) add_subdirectory_ifdef(CONFIG_COUNTER counter) @@ -28,7 +30,6 @@ add_subdirectory_ifdef(CONFIG_CRYPTO crypto) add_subdirectory_ifdef(CONFIG_DAC dac) add_subdirectory_ifdef(CONFIG_DAI dai) add_subdirectory_ifdef(CONFIG_DISPLAY display) -add_subdirectory_ifdef(CONFIG_AUXDISPLAY auxdisplay) add_subdirectory_ifdef(CONFIG_DMA dma) add_subdirectory_ifdef(CONFIG_EDAC edac) add_subdirectory_ifdef(CONFIG_EEPROM eeprom) @@ -40,8 +41,8 @@ add_subdirectory_ifdef(CONFIG_FUEL_GAUGE fuel_gauge) add_subdirectory_ifdef(CONFIG_GNSS gnss) add_subdirectory_ifdef(CONFIG_GPIO gpio) add_subdirectory_ifdef(CONFIG_HWINFO hwinfo) +add_subdirectory_ifdef(CONFIG_HWSPINLOCK hwspinlock) add_subdirectory_ifdef(CONFIG_I2C i2c) -add_subdirectory_ifdef(CONFIG_SMBUS smbus) add_subdirectory_ifdef(CONFIG_I2S i2s) add_subdirectory_ifdef(CONFIG_I3C i3c) add_subdirectory_ifdef(CONFIG_IEEE802154 ieee802154) @@ -70,9 +71,11 @@ add_subdirectory_ifdef(CONFIG_PWM pwm) add_subdirectory_ifdef(CONFIG_REGULATOR regulator) add_subdirectory_ifdef(CONFIG_RESET reset) add_subdirectory_ifdef(CONFIG_RETAINED_MEM retained_mem) +add_subdirectory_ifdef(CONFIG_RTC rtc) add_subdirectory_ifdef(CONFIG_SDHC sdhc) add_subdirectory_ifdef(CONFIG_SENSOR sensor) add_subdirectory_ifdef(CONFIG_SERIAL serial) +add_subdirectory_ifdef(CONFIG_SMBUS smbus) add_subdirectory_ifdef(CONFIG_SPI spi) add_subdirectory_ifdef(CONFIG_SYSCON syscon) add_subdirectory_ifdef(CONFIG_SYS_CLOCK_EXISTS timer) @@ -81,6 +84,5 @@ add_subdirectory_ifdef(CONFIG_VIRTUALIZATION virtualization) add_subdirectory_ifdef(CONFIG_W1 w1) add_subdirectory_ifdef(CONFIG_WATCHDOG watchdog) add_subdirectory_ifdef(CONFIG_WIFI wifi) -add_subdirectory_ifdef(CONFIG_RTC rtc) -add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_DRIVER sip_svc) -add_subdirectory_ifdef(CONFIG_HWSPINLOCK hwspinlock) +add_subdirectory_ifdef(CONFIG_XEN xen) +# zephyr-keep-sorted-stop diff --git a/drivers/Kconfig b/drivers/Kconfig index 1eca764fce22454..45b03e4829c6b4f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -5,9 +5,10 @@ menu "Device Drivers" +# zephyr-keep-sorted-start source "drivers/adc/Kconfig" -source "drivers/auxdisplay/Kconfig" source "drivers/audio/Kconfig" +source "drivers/auxdisplay/Kconfig" source "drivers/bbram/Kconfig" source "drivers/bluetooth/Kconfig" source "drivers/cache/Kconfig" @@ -34,10 +35,10 @@ source "drivers/fuel_gauge/Kconfig" source "drivers/gnss/Kconfig" source "drivers/gpio/Kconfig" source "drivers/hwinfo/Kconfig" +source "drivers/hwspinlock/Kconfig" source "drivers/i2c/Kconfig" source "drivers/i2s/Kconfig" source "drivers/i3c/Kconfig" -source "drivers/smbus/Kconfig" source "drivers/ieee802154/Kconfig" source "drivers/input/Kconfig" source "drivers/interrupt_controller/Kconfig" @@ -71,6 +72,8 @@ source "drivers/rtc/Kconfig" source "drivers/sdhc/Kconfig" source "drivers/sensor/Kconfig" source "drivers/serial/Kconfig" +source "drivers/sip_svc/Kconfig" +source "drivers/smbus/Kconfig" source "drivers/spi/Kconfig" source "drivers/syscon/Kconfig" source "drivers/timer/Kconfig" @@ -82,7 +85,6 @@ source "drivers/w1/Kconfig" source "drivers/watchdog/Kconfig" source "drivers/wifi/Kconfig" source "drivers/xen/Kconfig" -source "drivers/sip_svc/Kconfig" -source "drivers/hwspinlock/Kconfig" +# zephyr-keep-sorted-stop endmenu diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index bef01e0f24a73d0..ccd2c8c88bff70d 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory_ifdef(CONFIG_LORAWAN lorawan) # FIXME: SHADOW_VARS: Remove this once we have enabled -Wshadow globally. add_compile_options($) +# zephyr-keep-sorted-start add_subdirectory(canbus) add_subdirectory(debug) add_subdirectory(fb) @@ -32,6 +33,7 @@ add_subdirectory(testsuite) add_subdirectory(tracing) add_subdirectory(usb) +add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_SUBSYS sip_svc) add_subdirectory_ifdef(CONFIG_BINDESC bindesc) add_subdirectory_ifdef(CONFIG_BT bluetooth) add_subdirectory_ifdef(CONFIG_CONSOLE_SUBSYS console) @@ -42,8 +44,8 @@ add_subdirectory_ifdef(CONFIG_EMUL emul) add_subdirectory_ifdef(CONFIG_IMG_MANAGER dfu) add_subdirectory_ifdef(CONFIG_INPUT input) add_subdirectory_ifdef(CONFIG_JWT jwt) -add_subdirectory_ifdef(CONFIG_MODEM_MODULES modem) add_subdirectory_ifdef(CONFIG_LLEXT llext) +add_subdirectory_ifdef(CONFIG_MODEM_MODULES modem) add_subdirectory_ifdef(CONFIG_NET_BUF net) add_subdirectory_ifdef(CONFIG_RETENTION retention) add_subdirectory_ifdef(CONFIG_SENSING sensing) @@ -51,4 +53,4 @@ add_subdirectory_ifdef(CONFIG_SETTINGS settings) add_subdirectory_ifdef(CONFIG_SHELL shell) add_subdirectory_ifdef(CONFIG_TIMING_FUNCTIONS timing) add_subdirectory_ifdef(CONFIG_ZBUS zbus) -add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_SUBSYS sip_svc) +# zephyr-keep-sorted-stop diff --git a/subsys/Kconfig b/subsys/Kconfig index e4fa9212ab04255..f0dab7c8c72757e 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -6,6 +6,7 @@ menu "Subsystems and OS Services" +# zephyr-keep-sorted-start source "subsys/bindesc/Kconfig" source "subsys/bluetooth/Kconfig" source "subsys/canbus/Kconfig" @@ -38,6 +39,7 @@ source "subsys/sd/Kconfig" source "subsys/sensing/Kconfig" source "subsys/settings/Kconfig" source "subsys/shell/Kconfig" +source "subsys/sip_svc/Kconfig" source "subsys/stats/Kconfig" source "subsys/storage/Kconfig" source "subsys/task_wdt/Kconfig" @@ -49,6 +51,6 @@ source "subsys/usb/device_next/Kconfig" source "subsys/usb/host/Kconfig" source "subsys/usb/usb_c/Kconfig" source "subsys/zbus/Kconfig" -source "subsys/sip_svc/Kconfig" +# zephyr-keep-sorted-stop endmenu From 98d9a7f86f5af8bebb98bda445ff3bbc3321c330 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 22 May 2023 14:22:35 +0000 Subject: [PATCH 0220/1049] scripts: compliance: add a compliance check to keep blocks of code sorted This allows defining a list within two marker (zephyr-keep-sorted-start and zephyr-keep-sorted-stop), and have the CI validate that the block is kept sorted every time stuff gets added to it. This is mainly for Kconfig and CMake include lists so that there's no ambiguity on where to add new stuff. Signed-off-by: Fabio Baltieri --- .gitignore | 1 + scripts/ci/check_compliance.py | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/.gitignore b/.gitignore index fae5aabbf3087f6..13c99731c52966b 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ ImageSize.txt Kconfig.txt KconfigBasic.txt KconfigBasicNoModules.txt +KeepSorted.txt MaintainersFormat.txt ModulesMaintainers.txt Nits.txt diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 779da01f2c58c3a..cbbd0da9b667ff2 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -1163,6 +1163,59 @@ def run(self): p.line, col=p.column, desc=p.desc) +class KeepSorted(ComplianceTest): + """ + Check for blocks of code or config that should be kept sorted. + """ + name = "KeepSorted" + doc = "Check for blocks of code or config that should be kept sorted." + path_hint = "" + + MARKER = "zephyr-keep-sorted" + + def check_file(self, file, fp): + lines = [] + in_block = False + + start_marker = f"{self.MARKER}-start" + stop_marker = f"{self.MARKER}-stop" + + for line_num, line in enumerate(fp.readlines(), start=1): + if start_marker in line: + if in_block: + desc = f"nested {start_marker}" + self.fmtd_failure("error", "KeepSorted", file, line_num, + desc=desc) + in_block = True + lines = [] + elif stop_marker in line: + if not in_block: + desc = f"{stop_marker} without {start_marker}" + self.fmtd_failure("error", "KeepSorted", file, line_num, + desc=desc) + in_block = False + + if lines != sorted(lines): + desc = f"sorted block is not sorted" + self.fmtd_failure("error", "KeepSorted", file, line_num, + desc=desc) + elif not line.strip() or line.startswith("#"): + # Ignore comments and blank lines + continue + elif in_block: + if line.startswith((" ", "\t")): + lines[-1] += line + else: + lines.append(line) + + if in_block: + self.failure(f"unterminated {start_marker} in {file}") + + def run(self): + for file in get_files(filter="d"): + with open(file, "r") as fp: + self.check_file(file, fp) + def init_logs(cli_arg): # Initializes logging From 3003cc1938f53074ad717af79d1ff1e7ff15b514 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 11 Nov 2023 18:41:29 +0000 Subject: [PATCH 0221/1049] input: keep CMakeLists and Kconfig sorted Add zephyr-keep-sorted tags to CMakeLists and Kconfig in input. Signed-off-by: Fabio Baltieri --- drivers/input/CMakeLists.txt | 2 ++ drivers/input/Kconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index e141652fe48961b..96f85ba0e72ef27 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) +# zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_INPUT_CAP1203 input_cap1203.c) zephyr_library_sources_ifdef(CONFIG_INPUT_CST816S input_cst816s.c) zephyr_library_sources_ifdef(CONFIG_INPUT_FT5336 input_ft5336.c) @@ -14,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_KBD_MATRIX input_kbd_matrix.c) zephyr_library_sources_ifdef(CONFIG_INPUT_NPCX_KBD input_npcx_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_STMPE811 input_stmpe811.c) zephyr_library_sources_ifdef(CONFIG_INPUT_XPT2046 input_xpt2046.c) +# zephyr-keep-sorted-stop if (CONFIG_INPUT_SDL_TOUCH) zephyr_library_sources(input_sdl_touch.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 21401d9dbdb35dd..2a0f8ac8526d9dd 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -5,6 +5,7 @@ if INPUT menu "Input drivers" +# zephyr-keep-sorted-start source "drivers/input/Kconfig.cap1203" source "drivers/input/Kconfig.cst816s" source "drivers/input/Kconfig.ft5336" @@ -17,6 +18,7 @@ source "drivers/input/Kconfig.npcx" source "drivers/input/Kconfig.sdl" source "drivers/input/Kconfig.stmpe811" source "drivers/input/Kconfig.xpt2046" +# zephyr-keep-sorted-stop endmenu # Input Drivers From 6db785404ac13e8692833cbc440f699c7d50432c Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Wed, 27 Sep 2023 19:04:12 -0400 Subject: [PATCH 0222/1049] tests: drivers: uart_async_api: Be more robust to early buf release Commit eb44414af99a44447afa52bb81ac0767f2ff791e modified test_single_read for early rx buf release. The commit assumed that tdata.last_rx_buf points to either &tdata.rx_buf[0] if the driver releases the first buffer or at &rx_buf[5] if the first buffer is not released. However, where tdata.last_rx_buf points to depends on the timeout given to uart_rx_enable(), making the test flaky. This commit modifies the test by keeping track how many bytes have been received in the first and second buffers. The function tdata_check_recv_buffer() validates that the sent data matches the received bytes which may have been split between first and second buffer. This fixes the uart_async_api test on the xmc45_relax_kit. Signed-off-by: Andriy Gelman --- .../uart/uart_async_api/src/test_uart_async.c | 91 +++++++++++++------ 1 file changed, 63 insertions(+), 28 deletions(-) diff --git a/tests/drivers/uart/uart_async_api/src/test_uart_async.c b/tests/drivers/uart/uart_async_api/src/test_uart_async.c index af3a63b197dcabd..9579e49c759bebf 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart_async.c +++ b/tests/drivers/uart/uart_async_api/src/test_uart_async.c @@ -79,10 +79,11 @@ static void uart_async_test_init(void) struct test_data { volatile uint32_t tx_aborted_count; - uint8_t rx_buf[5]; - bool rx_buf_req_done; - bool supply_next_buffer; - uint8_t *last_rx_buf; + uint8_t rx_first_buffer[10]; + uint32_t recv_bytes_first_buffer; + uint8_t rx_second_buffer[5]; + uint32_t recv_bytes_second_buffer; + bool supply_second_buffer; }; ZTEST_BMEM struct test_data tdata; @@ -101,17 +102,22 @@ static void test_single_read_callback(const struct device *dev, data->tx_aborted_count++; break; case UART_RX_RDY: - data->last_rx_buf = &evt->data.rx.buf[evt->data.rx.offset]; + if ((uintptr_t)evt->data.rx.buf < (uintptr_t)tdata.rx_second_buffer) { + data->recv_bytes_first_buffer += evt->data.rx.len; + } else { + data->recv_bytes_second_buffer += evt->data.rx.len; + } k_sem_give(&rx_rdy); break; case UART_RX_BUF_RELEASED: k_sem_give(&rx_buf_released); break; case UART_RX_BUF_REQUEST: - if (data->supply_next_buffer) { + if (data->supply_second_buffer) { /* Reply to one buffer request. */ - uart_rx_buf_rsp(dev, data->rx_buf, sizeof(data->rx_buf)); - data->supply_next_buffer = false; + uart_rx_buf_rsp(dev, data->rx_second_buffer, + sizeof(data->rx_second_buffer)); + data->supply_second_buffer = false; } break; case UART_RX_DISABLED: @@ -129,7 +135,7 @@ static void *single_read_setup(void) uart_async_test_init(); memset(&tdata, 0, sizeof(tdata)); - tdata.supply_next_buffer = true; + tdata.supply_second_buffer = true; uart_callback_set(uart_dev, test_single_read_callback, (void *) &tdata); @@ -137,30 +143,57 @@ static void *single_read_setup(void) return NULL; } -ZTEST_USER(uart_async_single_read, test_single_read) +static void tdata_check_recv_buffers(const uint8_t *tx_buf, uint32_t sent_bytes) { - uint8_t rx_buf[10] = {0}; + uint32_t recv_bytes_total; + + recv_bytes_total = tdata.recv_bytes_first_buffer + tdata.recv_bytes_second_buffer; + zassert_equal(recv_bytes_total, sent_bytes, "Incorrect number of bytes received"); + + zassert_equal(memcmp(tx_buf, tdata.rx_first_buffer, tdata.recv_bytes_first_buffer), 0, + "Invalid data received in first buffer"); + zassert_equal(memcmp(tx_buf + tdata.recv_bytes_first_buffer, tdata.rx_second_buffer, + tdata.recv_bytes_second_buffer), + 0, "Invalid data received in second buffer"); + + /* check that the remaining bytes in the buffers are zero */ + for (int i = tdata.recv_bytes_first_buffer; i < sizeof(tdata.rx_first_buffer); i++) { + zassert_equal(tdata.rx_first_buffer[i], 0, + "Received extra data to the first buffer"); + } + for (int i = tdata.recv_bytes_second_buffer; i < sizeof(tdata.rx_second_buffer); i++) { + zassert_equal(tdata.rx_second_buffer[i], 0, + "Received extra data to the second buffer"); + } +} + +ZTEST_USER(uart_async_single_read, test_single_read) +{ /* Check also if sending from read only memory (e.g. flash) works. */ - static const uint8_t tx_buf[5] = "test\0"; + static const uint8_t tx_buf[] = "0123456789"; + uint32_t sent_bytes = 0; - zassert_not_equal(memcmp(tx_buf, rx_buf, 5), 0, + zassert_not_equal(memcmp(tx_buf, tdata.rx_first_buffer, 5), 0, "Initial buffer check failed"); - uart_rx_enable(uart_dev, rx_buf, 10, 50 * USEC_PER_MSEC); + uart_rx_enable(uart_dev, tdata.rx_first_buffer, 10, 50 * USEC_PER_MSEC); zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, "RX_RDY not expected at this point"); - uart_tx(uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); + uart_tx(uart_dev, tx_buf, 5, 100 * USEC_PER_MSEC); + sent_bytes += 5; + zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, "Extra RX_RDY received"); - zassert_equal(memcmp(tx_buf, tdata.last_rx_buf, 5), 0, "Buffers not equal"); - zassert_not_equal(memcmp(tx_buf, rx_buf+5, 5), 0, "Buffers not equal"); + tdata_check_recv_buffers(tx_buf, sent_bytes); + + uart_tx(uart_dev, tx_buf + sent_bytes, 5, 100 * USEC_PER_MSEC); + sent_bytes += 5; - uart_tx(uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), @@ -173,7 +206,8 @@ ZTEST_USER(uart_async_single_read, test_single_read) zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, "Extra RX_RDY received"); - zassert_equal(memcmp(tx_buf, tdata.last_rx_buf, 5), 0, "Buffers not equal"); + tdata_check_recv_buffers(tx_buf, sent_bytes); + zassert_equal(tdata.tx_aborted_count, 0, "TX aborted triggered"); } @@ -196,11 +230,13 @@ ZTEST_USER(uart_async_multi_rx, test_multiple_rx_enable) { /* Check also if sending from read only memory (e.g. flash) works. */ static const uint8_t tx_buf[] = "test"; - uint8_t rx_buf[sizeof(tx_buf)] = {0}; + const uint32_t rx_buf_size = sizeof(tx_buf); int ret; + BUILD_ASSERT(rx_buf_size <= sizeof(tdata.rx_first_buffer), "Invalid buf size"); + /* Enable RX without a timeout. */ - ret = uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), SYS_FOREVER_US); + ret = uart_rx_enable(uart_dev, tdata.rx_first_buffer, rx_buf_size, SYS_FOREVER_US); zassert_equal(ret, 0, "uart_rx_enable failed"); zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, "RX_RDY not expected at this point"); @@ -221,7 +257,7 @@ ZTEST_USER(uart_async_multi_rx, test_multiple_rx_enable) k_sem_reset(&rx_disabled); /* Check that RX can be reenabled after "manual" disabling. */ - ret = uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), + ret = uart_rx_enable(uart_dev, tdata.rx_first_buffer, rx_buf_size, 50 * USEC_PER_MSEC); zassert_equal(ret, 0, "uart_rx_enable failed"); zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, @@ -240,17 +276,17 @@ ZTEST_USER(uart_async_multi_rx, test_multiple_rx_enable) "RX_DISABLED timeout"); zassert_equal(tx_aborted_count, 0, "Unexpected TX abort"); - zassert_equal(memcmp(tx_buf, rx_buf, sizeof(tx_buf)), 0, - "Buffers not equal"); + tdata_check_recv_buffers(tx_buf, sizeof(tx_buf)); k_sem_reset(&rx_rdy); k_sem_reset(&rx_buf_released); k_sem_reset(&rx_disabled); k_sem_reset(&tx_done); - memset(rx_buf, 0, sizeof(rx_buf)); + + memset(&tdata, 0, sizeof(tdata)); /* Check that RX can be reenabled after automatic disabling. */ - ret = uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), + ret = uart_rx_enable(uart_dev, tdata.rx_first_buffer, rx_buf_size, 50 * USEC_PER_MSEC); zassert_equal(ret, 0, "uart_rx_enable failed"); zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, @@ -269,8 +305,7 @@ ZTEST_USER(uart_async_multi_rx, test_multiple_rx_enable) "RX_DISABLED timeout"); zassert_equal(tx_aborted_count, 0, "Unexpected TX abort"); - zassert_equal(memcmp(tx_buf, rx_buf, sizeof(tx_buf)), 0, - "Buffers not equal"); + tdata_check_recv_buffers(tx_buf, sizeof(tx_buf)); } ZTEST_BMEM uint8_t chained_read_buf[2][8]; From 1946dd829d1e11c1bd4b6dbe8b4fb1876a162fb6 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 8 Sep 2023 11:14:38 +0200 Subject: [PATCH 0223/1049] tests: Bluetooth: Add inval testing of bt_bap_broadcast_source_get_id Add invalid parameter and state testing of bt_bap_broadcast_source_get_id Signed-off-by: Emil Gydesen --- .../audio/bap_broadcast_source/src/main.c | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/bluetooth/audio/bap_broadcast_source/src/main.c b/tests/bluetooth/audio/bap_broadcast_source/src/main.c index ff974565240268f..5ba0e624276b545 100644 --- a/tests/bluetooth/audio/bap_broadcast_source/src/main.c +++ b/tests/bluetooth/audio/bap_broadcast_source/src/main.c @@ -1164,6 +1164,57 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_id) fixture->source = NULL; } +ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_id_inval_source_null) +{ + uint32_t broadcast_id; + int err; + + err = bt_bap_broadcast_source_get_id(NULL, &broadcast_id); + zassert_not_equal(0, err, "Did not fail with null source"); +} + +ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_id_inval_id_null) +{ + struct bt_bap_broadcast_source_param *create_param = fixture->param; + int err; + + printk("Creating broadcast source with %zu subgroups with %zu streams\n", + create_param->params_count, fixture->stream_cnt); + + err = bt_bap_broadcast_source_create(create_param, &fixture->source); + zassert_equal(0, err, "Unable to create broadcast source: err %d", err); + + err = bt_bap_broadcast_source_get_id(fixture->source, NULL); + zassert_not_equal(0, err, "Did not fail with null ID"); + + err = bt_bap_broadcast_source_delete(fixture->source); + zassert_equal(0, err, "Unable to delete broadcast source: err %d", err); + fixture->source = NULL; +} + +ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_id_inval_state) +{ + struct bt_bap_broadcast_source_param *create_param = fixture->param; + struct bt_bap_broadcast_source *source; + uint32_t broadcast_id; + int err; + + printk("Creating broadcast source with %zu subgroups with %zu streams\n", + create_param->params_count, fixture->stream_cnt); + + err = bt_bap_broadcast_source_create(create_param, &fixture->source); + zassert_equal(0, err, "Unable to create broadcast source: err %d", err); + + source = fixture->source; + + err = bt_bap_broadcast_source_delete(fixture->source); + zassert_equal(0, err, "Unable to delete broadcast source: err %d", err); + fixture->source = NULL; + + err = bt_bap_broadcast_source_get_id(source, &broadcast_id); + zassert_not_equal(0, err, "Did not fail with deleted broadcast source"); +} + ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base_single_bis) { struct bt_bap_broadcast_source_param *create_param = fixture->param; From 475e0673795603e68f3a635ecb2bf720b26802af Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 8 Sep 2023 11:22:24 +0200 Subject: [PATCH 0224/1049] tests: Bluetooth: Add inval testing of bt_bap_broadcast_source_get_base Add invalid parameter and state testing of bt_bap_broadcast_source_get_base Signed-off-by: Emil Gydesen --- .../audio/bap_broadcast_source/src/main.c | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tests/bluetooth/audio/bap_broadcast_source/src/main.c b/tests/bluetooth/audio/bap_broadcast_source/src/main.c index 5ba0e624276b545..8d85eb321ac41e3 100644 --- a/tests/bluetooth/audio/bap_broadcast_source/src/main.c +++ b/tests/bluetooth/audio/bap_broadcast_source/src/main.c @@ -1334,3 +1334,101 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base) zassert_equal(0, err, "Unable to delete broadcast source: err %d", err); fixture->source = NULL; } + +ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base_inval_source_null) +{ + int err; + + NET_BUF_SIMPLE_DEFINE(base_buf, 64); + + err = bt_bap_broadcast_source_get_base(NULL, &base_buf); + zassert_not_equal(0, err, "Did not fail with null source"); +} + +ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base_inval_base_buf_null) +{ + struct bt_bap_broadcast_source_param *create_param = fixture->param; + int err; + + printk("Creating broadcast source with %zu subgroups with %zu streams\n", + create_param->params_count, fixture->stream_cnt); + + err = bt_bap_broadcast_source_create(create_param, &fixture->source); + zassert_equal(0, err, "Unable to create broadcast source: err %d", err); + + err = bt_bap_broadcast_source_get_base(fixture->source, NULL); + zassert_not_equal(0, err, "Did not fail with null BASE buffer"); + + err = bt_bap_broadcast_source_delete(fixture->source); + zassert_equal(0, err, "Unable to delete broadcast source: err %d", err); + fixture->source = NULL; +} + +ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base_inval_state) +{ + struct bt_bap_broadcast_source_param *create_param = fixture->param; + struct bt_bap_broadcast_source *source; + int err; + + NET_BUF_SIMPLE_DEFINE(base_buf, 64); + + printk("Creating broadcast source with %zu subgroups with %zu streams\n", + create_param->params_count, fixture->stream_cnt); + + err = bt_bap_broadcast_source_create(create_param, &fixture->source); + zassert_equal(0, err, "Unable to create broadcast source: err %d", err); + + source = fixture->source; + + err = bt_bap_broadcast_source_delete(fixture->source); + zassert_equal(0, err, "Unable to delete broadcast source: err %d", err); + fixture->source = NULL; + + err = bt_bap_broadcast_source_get_base(source, &base_buf); + zassert_not_equal(0, err, "Did not fail with deleted broadcast source"); +} + +/** This tests that providing a buffer too small for _any_ BASE fails correctly */ +ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base_inval_very_small_buf) +{ + struct bt_bap_broadcast_source_param *create_param = fixture->param; + int err; + + NET_BUF_SIMPLE_DEFINE(base_buf, 15); /* Too small to hold any BASE */ + + printk("Creating broadcast source with %zu subgroups with %zu streams\n", + create_param->params_count, fixture->stream_cnt); + + err = bt_bap_broadcast_source_create(create_param, &fixture->source); + zassert_equal(0, err, "Unable to create broadcast source: err %d", err); + + err = bt_bap_broadcast_source_get_base(fixture->source, &base_buf); + zassert_not_equal(0, err, "Did not fail with too small base_buf (%u)", base_buf.size); + + err = bt_bap_broadcast_source_delete(fixture->source); + zassert_equal(0, err, "Unable to delete broadcast source: err %d", err); + fixture->source = NULL; +} + +/** This tests that providing a buffer too small for the BASE we want to setup fails correctly */ +ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base_inval_small_buf) +{ + struct bt_bap_broadcast_source_param *create_param = fixture->param; + int err; + + /* Can hold a base, but not large enough for this configuration */ + NET_BUF_SIMPLE_DEFINE(base_buf, 64); + + printk("Creating broadcast source with %zu subgroups with %zu streams\n", + create_param->params_count, fixture->stream_cnt); + + err = bt_bap_broadcast_source_create(create_param, &fixture->source); + zassert_equal(0, err, "Unable to create broadcast source: err %d", err); + + err = bt_bap_broadcast_source_get_base(fixture->source, &base_buf); + zassert_not_equal(0, err, "Did not fail with too small base_buf (%u)", base_buf.size); + + err = bt_bap_broadcast_source_delete(fixture->source); + zassert_equal(0, err, "Unable to delete broadcast source: err %d", err); + fixture->source = NULL; +} From 175a2f3287af96107c4f7e3ff7092dd372eee33f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 8 Sep 2023 11:28:09 +0200 Subject: [PATCH 0225/1049] tests: bsim: Bluetooth: Remove broadcast_source_get_id_inval Removed the tests for invalid bt_bap_broadcast_source_get_id parameters and state, as those tests now implemented as unit tests. Signed-off-by: Emil Gydesen --- .../audio/src/bap_broadcast_source_test.c | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c index 773240a0c36837c..fcc72701e34e7d6 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -149,26 +149,6 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source) return 0; } -static void test_broadcast_source_get_id_inval(struct bt_bap_broadcast_source *source, - uint32_t *broadcast_id_out) -{ - int err; - - printk("Test bt_bap_broadcast_source_get_id with NULL source\n"); - err = bt_bap_broadcast_source_get_id(NULL, broadcast_id_out); - if (err == 0) { - FAIL("bt_bap_broadcast_source_get_id with NULL source did not fail\n"); - return; - } - - printk("Test bt_bap_broadcast_source_get_id with NULL broadcast_id\n"); - err = bt_bap_broadcast_source_get_id(source, NULL); - if (err == 0) { - FAIL("bt_bap_broadcast_source_get_id with NULL ID did not fail\n"); - return; - } -} - static void test_broadcast_source_get_id(struct bt_bap_broadcast_source *source, uint32_t *broadcast_id_out) { @@ -256,7 +236,6 @@ static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_ return err; } - test_broadcast_source_get_id_inval(source, &broadcast_id); test_broadcast_source_get_id(source, &broadcast_id); /* Setup extended advertising data */ From 9f3858aad967e7477cdc7180fa7978d8367237d5 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 8 Sep 2023 11:28:47 +0200 Subject: [PATCH 0226/1049] tests: bsim: Bluetooth: Remove broadcast_source_get_base_inval Removed the tests for invalid bt_bap_broadcast_source_get_base parameters and state, as those tests now implemented as unit tests. Signed-off-by: Emil Gydesen --- .../audio/src/bap_broadcast_source_test.c | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c index fcc72701e34e7d6..2c6c5bc18289423 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -161,43 +161,6 @@ static void test_broadcast_source_get_id(struct bt_bap_broadcast_source *source, } } -static void test_broadcast_source_get_base_inval(struct bt_bap_broadcast_source *source, - struct net_buf_simple *base_buf) -{ - /* Large enough for minimum, but not large enough for any CC or Meta data */ - NET_BUF_SIMPLE_DEFINE(small_base_buf, BT_BAP_BASE_MIN_SIZE + 2); - NET_BUF_SIMPLE_DEFINE(very_small_base_buf, 4); - int err; - - printk("Test bt_bap_broadcast_source_get_base with NULL source\n"); - err = bt_bap_broadcast_source_get_base(NULL, base_buf); - if (err == 0) { - FAIL("bt_bap_broadcast_source_get_base with NULL source did not fail\n"); - return; - } - - printk("Test bt_bap_broadcast_source_get_base with NULL buf\n"); - err = bt_bap_broadcast_source_get_base(source, NULL); - if (err == 0) { - FAIL("bt_bap_broadcast_source_get_base with NULL buf did not fail\n"); - return; - } - - printk("Test bt_bap_broadcast_source_get_base with very small buf\n"); - err = bt_bap_broadcast_source_get_base(source, &very_small_base_buf); - if (err == 0) { - FAIL("bt_bap_broadcast_source_get_base with very small buf did not fail\n"); - return; - } - - printk("Test bt_bap_broadcast_source_get_base with small buf\n"); - err = bt_bap_broadcast_source_get_base(source, &small_base_buf); - if (err == 0) { - FAIL("bt_bap_broadcast_source_get_base with small buf did not fail\n"); - return; - } -} - static void test_broadcast_source_get_base(struct bt_bap_broadcast_source *source, struct net_buf_simple *base_buf) { @@ -251,7 +214,6 @@ static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_ } /* Setup periodic advertising data */ - test_broadcast_source_get_base_inval(source, &base_buf); test_broadcast_source_get_base(source, &base_buf); per_ad.type = BT_DATA_SVC_DATA16; From a2f971795f96b6c6785565b1e9bedef55188767d Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Fri, 8 Sep 2023 14:21:39 -0700 Subject: [PATCH 0227/1049] soc: arm: ti_k3: am62x_m4: Lower Initialization level for init Other drivers like the pinctrl_ti_k3 rely on a fully initialized system. Move the am62x_init to an earlier stage than PRE_KERNEL_1 to keep both PRE_KERNEL_{1,2} free for drivers. Signed-off-by: Daniel Schultz --- soc/arm/ti_k3/am62x_m4/soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/arm/ti_k3/am62x_m4/soc.c b/soc/arm/ti_k3/am62x_m4/soc.c index 1010e045ea59a76..9c86eb09a1d5838 100644 --- a/soc/arm/ti_k3/am62x_m4/soc.c +++ b/soc/arm/ti_k3/am62x_m4/soc.c @@ -70,4 +70,4 @@ static int am62x_m4_init(void) return 0; } -SYS_INIT(am62x_m4_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(am62x_m4_init, EARLY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From fbd2b84e0ea72babad4ae14a0265e0965a5dfca1 Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Mon, 4 Sep 2023 09:58:35 -0700 Subject: [PATCH 0228/1049] drivers: gpio: davinci: Add pinctrl Add pinctrl to the Davinci GPIO driver to allow muxing pins dirctly in this driver. Also aligned the macro backslashes as line continuation character at the end of each line with each at the same position and removed the GPIO_DAVINCI_DEVICE_INIT macro which seems to be not used. Signed-off-by: Daniel Schultz --- drivers/gpio/gpio_davinci.c | 77 ++++++++++---------- dts/bindings/gpio/ti,davinci-gpio-nexus.yaml | 2 +- dts/bindings/gpio/ti,davinci-gpio.yaml | 2 +- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/drivers/gpio/gpio_davinci.c b/drivers/gpio/gpio_davinci.c index 5726ed1bf32e83b..205e0112cde8f66 100644 --- a/drivers/gpio/gpio_davinci.c +++ b/drivers/gpio/gpio_davinci.c @@ -17,10 +17,14 @@ #include #include #include +#include +#include + +LOG_MODULE_REGISTER(gpio_davinci, CONFIG_GPIO_LOG_LEVEL); /* Helper Macros for GPIO */ #define DEV_CFG(dev) \ - ((const struct gpio_davinci_config * const)((dev)->config)) + ((const struct gpio_davinci_config *)((dev)->config)) #define DEV_DATA(dev) ((struct gpio_davinci_data *)(dev)->data) #define DEV_GPIO_CFG_BASE(dev) \ ((struct gpio_davinci_regs *)DEVICE_MMIO_NAMED_GET(dev, port_base)) @@ -55,6 +59,7 @@ struct gpio_davinci_config { DEVICE_MMIO_NAMED_ROM(port_base); uint32_t port_num; + const struct pinctrl_dev_config *pcfg; }; static int gpio_davinci_configure(const struct device *dev, gpio_pin_t pin, @@ -76,11 +81,9 @@ static int gpio_davinci_configure(const struct device *dev, gpio_pin_t pin, } else { regs->clr_data = BIT(pin); } - - regs->dir &= (~(BIT(pin))); - + regs->dir &= ~(BIT(pin)); } else { - regs->dir |= (BIT(pin)); + regs->dir |= BIT(pin); } return 0; @@ -149,6 +152,7 @@ static int gpio_davinci_init(const struct device *dev) { const struct gpio_davinci_config *config = DEV_CFG(dev); volatile struct gpio_davinci_regs *regs = DEV_GPIO_CFG_BASE(dev); + int ret; DEVICE_MMIO_NAMED_MAP(dev, port_base, K_MEM_CACHE_NONE); @@ -156,44 +160,43 @@ static int gpio_davinci_init(const struct device *dev) config->bank_config(dev); + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("failed to apply pinctrl"); + return ret; + } return 0; } -#define GPIO_DAVINCI_INIT_FUNC(n) \ - static void gpio_davinci_bank_##n##_config(const struct device *dev) \ - { \ +#define GPIO_DAVINCI_INIT_FUNC(n) \ + static void gpio_davinci_bank_##n##_config(const struct device *dev) \ + { \ volatile struct gpio_davinci_regs *regs = DEV_GPIO_CFG_BASE(dev); \ - ARG_UNUSED(regs); \ + ARG_UNUSED(regs); \ } -#define GPIO_DAVINCI_DEVICE_INIT(n) \ - DEVICE_DT_INST_DEFINE(n, &gpio_davinci_##n##_init, \ - NULL, &gpio_davinci_##n##_data, \ - &gpio_davinci_##n##_config, \ - POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \ - &api_funcs) - -#define GPIO_DAVINCI_INIT(n) \ - \ - GPIO_DAVINCI_INIT_FUNC(n) \ - static const struct gpio_davinci_config gpio_davinci_##n##_config = { \ - .bank_config = gpio_davinci_bank_##n##_config, \ - .common = { \ - .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ - }, \ - DEVICE_MMIO_NAMED_ROM_INIT(port_base, DT_DRV_INST(n)), \ - .port_num = n \ - }; \ - \ - static struct gpio_davinci_data gpio_davinci_##n##_data; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - &gpio_davinci_init, \ - NULL, \ - &gpio_davinci_##n##_data, \ - &gpio_davinci_##n##_config, \ - PRE_KERNEL_2, \ - CONFIG_GPIO_INIT_PRIORITY, \ +#define GPIO_DAVINCI_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + GPIO_DAVINCI_INIT_FUNC(n); \ + static const struct gpio_davinci_config gpio_davinci_##n##_config = { \ + .bank_config = gpio_davinci_bank_##n##_config, \ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + DEVICE_MMIO_NAMED_ROM_INIT(port_base, DT_DRV_INST(n)), \ + .port_num = n, \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + \ + static struct gpio_davinci_data gpio_davinci_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + &gpio_davinci_init, \ + NULL, \ + &gpio_davinci_##n##_data, \ + &gpio_davinci_##n##_config, \ + PRE_KERNEL_2, \ + CONFIG_GPIO_INIT_PRIORITY, \ &gpio_davinci_driver_api); DT_INST_FOREACH_STATUS_OKAY(GPIO_DAVINCI_INIT) diff --git a/dts/bindings/gpio/ti,davinci-gpio-nexus.yaml b/dts/bindings/gpio/ti,davinci-gpio-nexus.yaml index 3cfccfa5ee32343..1b38fe927ca223a 100644 --- a/dts/bindings/gpio/ti,davinci-gpio-nexus.yaml +++ b/dts/bindings/gpio/ti,davinci-gpio-nexus.yaml @@ -7,7 +7,7 @@ description: GPIO controller for Davinci and Keystone devices compatible: "ti,davinci-gpio-nexus" -include: [base.yaml, gpio-nexus.yaml] +include: [base.yaml, gpio-nexus.yaml, pinctrl-device.yaml] properties: "#gpio-cells": diff --git a/dts/bindings/gpio/ti,davinci-gpio.yaml b/dts/bindings/gpio/ti,davinci-gpio.yaml index 0472dfa1aa13775..64c0bbd5db56e82 100644 --- a/dts/bindings/gpio/ti,davinci-gpio.yaml +++ b/dts/bindings/gpio/ti,davinci-gpio.yaml @@ -7,7 +7,7 @@ description: GPIO controller for Davinci and Keystone devices. compatible: "ti,davinci-gpio" -include: [gpio-controller.yaml, base.yaml] +include: [base.yaml, gpio-controller.yaml, pinctrl-device.yaml] properties: reg: From 474bbd12e94513d08314bb67c0a783499f43cdec Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Mon, 4 Sep 2023 09:55:44 -0700 Subject: [PATCH 0229/1049] dts: arm: ti: am62x_m4: Add gpio0 node The M4F subsystem has a dedicated GPIO controller with 24 available pins. Add the node definition for the recently added driver. Signed-off-by: Daniel Schultz --- dts/arm/ti/am62x_m4.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dts/arm/ti/am62x_m4.dtsi b/dts/arm/ti/am62x_m4.dtsi index 22de7a14f82bfa8..8d5e5a14c40b8ba 100644 --- a/dts/arm/ti/am62x_m4.dtsi +++ b/dts/arm/ti/am62x_m4.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include / { @@ -54,6 +55,16 @@ reg-shift = <2>; status = "disabled"; }; + + gpio0: gpio@4201010 { + compatible = "ti,davinci-gpio"; + reg = <0x4201010 0x100>; + #address-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <24>; + status = "disabled"; + }; }; &nvic { From da1427406da4778d4f76dbe78c5828126a0a145b Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Mon, 4 Sep 2023 10:01:03 -0700 Subject: [PATCH 0230/1049] boards: arm: am62x_m4: Add GPIO0 to phyBOARD-lyra Enable the gpio0 node and mux the heartbeat LED. Moreover, add the heartbeart LED as LED node and create an alias with 'led0'. Signed-off-by: Daniel Schultz --- .../arm/am62x_m4/am62x_m4_phyboard_lyra.dts | 21 +++++++++++++++++++ .../am62x_m4/am62x_m4_phyboard_lyra_defconfig | 3 +++ 2 files changed, 24 insertions(+) diff --git a/boards/arm/am62x_m4/am62x_m4_phyboard_lyra.dts b/boards/arm/am62x_m4/am62x_m4_phyboard_lyra.dts index 3fac130ee9068dc..ba370240340c272 100644 --- a/boards/arm/am62x_m4/am62x_m4_phyboard_lyra.dts +++ b/boards/arm/am62x_m4/am62x_m4_phyboard_lyra.dts @@ -20,6 +20,10 @@ zephyr,sram1 = &ddr0; }; + aliases { + led0 = &heartbeat_led; + }; + cpus { cpu@0 { status = "okay"; @@ -32,6 +36,14 @@ reg = <0x9CC00000 DT_SIZE_K(4)>; zephyr,memory-region = "DDR"; }; + + leds: leds { + compatible = "gpio-leds"; + heartbeat_led: led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Heartbeat LED"; + }; + }; }; &pinctrl { @@ -41,6 +53,9 @@ mcu_uart0_tx_default: mcu_uart0_tx_default { pinmux = ; }; + mcu_gpio0_led_default: mcu_gpio0_led_default { + pinmux = ; + }; }; &uart0 { @@ -49,3 +64,9 @@ pinctrl-names = "default"; status = "okay"; }; + +&gpio0 { + pinctrl-0 = <&mcu_gpio0_led_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/am62x_m4/am62x_m4_phyboard_lyra_defconfig b/boards/arm/am62x_m4/am62x_m4_phyboard_lyra_defconfig index 15d2b0f5b28d77a..822222a8900fedb 100644 --- a/boards/arm/am62x_m4/am62x_m4_phyboard_lyra_defconfig +++ b/boards/arm/am62x_m4/am62x_m4_phyboard_lyra_defconfig @@ -20,6 +20,9 @@ CONFIG_PINCTRL=y # Serial Driver CONFIG_SERIAL=y +# GPIO Driver +CONFIG_GPIO=y + # Enable Console CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y From 71b0db21189b49b0402ecdf9fa03c26a6edf04ac Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 8 Sep 2023 21:08:51 -0500 Subject: [PATCH 0231/1049] dts: bindings: Add nxp,flexram binding Add binding for NXP FlexRAM Signed-off-by: Declan Snyder --- .../memory-controllers/nxp,flexram.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 dts/bindings/memory-controllers/nxp,flexram.yaml diff --git a/dts/bindings/memory-controllers/nxp,flexram.yaml b/dts/bindings/memory-controllers/nxp,flexram.yaml new file mode 100644 index 000000000000000..76248c063948df0 --- /dev/null +++ b/dts/bindings/memory-controllers/nxp,flexram.yaml @@ -0,0 +1,52 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP FlexRAM on-chip ram controller + +include: base.yaml + +compatible: "nxp,flexram" + +properties: + reg: + required: true + + interrupts: + required: true + + flexram,has-magic-addr: + type: boolean + description: | + Whether or not the flexram on the SOC has the + magic address feature, which allows for an interrupt + on arbitrary address access in any on chip RAM region. + + flexram,num-ram-banks: + type: int + required: true + description: | + Number of RAM banks in the SOC ram array + + flexram,bank-size: + type: int + required: true + description: | + Size of each RAM bank in KB + + flexram,bank-spec: + type: array + description: | + Custom mapping of runtime RAM bank partitions. If this + property is present, then it will be used. If this + property is not present, then the fusemap configuration + will be used. + + flexram,tcm-read-wait-mode: + type: boolean + description: | + TCM RAM read will finish in 2 cycles instead of 1. + + flexram,tcm-write-wait-mode: + type: boolean + description: | + TCM RAM write will finish in 2 cycles instead of 1. From 97d991f7d6d4628a6a742e2dcbb5503672342f26 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 8 Sep 2023 21:09:45 -0500 Subject: [PATCH 0232/1049] drivers: memc: Add NXP FlexRAM driver Add driver for NXP FlexRAM Signed-off-by: Declan Snyder --- drivers/memc/CMakeLists.txt | 1 + drivers/memc/Kconfig.mcux | 23 +- drivers/memc/memc_nxp_flexram.c | 231 ++++++++++++++++++ drivers/memc/memc_nxp_flexram.h | 98 ++++++++ .../memory-controller/nxp,flexram.h | 15 ++ 5 files changed, 366 insertions(+), 2 deletions(-) create mode 100644 drivers/memc/memc_nxp_flexram.c create mode 100644 drivers/memc/memc_nxp_flexram.h create mode 100644 include/zephyr/dt-bindings/memory-controller/nxp,flexram.h diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index ca967b1a045bfef..8aaedc2207352f3 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI memc_mcux_flexspi.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_W956A8MBYA memc_mcux_flexspi_w956a8mbya.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_S27KS0641 memc_mcux_flexspi_s27ks0641.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_APS6408L memc_mcux_flexspi_aps6408l.c) +zephyr_library_sources_ifdef(CONFIG_MEMC_NXP_FLEXRAM memc_nxp_flexram.c) zephyr_library_sources_ifdef(CONFIG_MEMC_SAM_SMC memc_sam_smc.c) diff --git a/drivers/memc/Kconfig.mcux b/drivers/memc/Kconfig.mcux index ed7e73929dbee31..e801e7577aeaeb6 100644 --- a/drivers/memc/Kconfig.mcux +++ b/drivers/memc/Kconfig.mcux @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2022 NXP +# Copyright 2020-2023 NXP # Copyright (c) 2021 Basalte bv # Copyright (c) 2023, ithinx GmbH # Copyright (c) 2023, Tonies GmbH @@ -28,4 +28,23 @@ config MEMC_MCUX_FLEXSPI bool select PINCTRL -endif +endif # DT_HAS_NXP_IMX_FLEXSPI_ENABLED + + +if DT_HAS_NXP_FLEXRAM_ENABLED + +config MEMC_NXP_FLEXRAM + bool + default y + +config MEMC_NXP_FLEXRAM_MAGIC_ADDR_API + bool "NXP FlexRAM magic addr API" + help + Enable API to use flexRAM magic address functionality + +config MEMC_NXP_FLEXRAM_ERROR_INTERRUPT + bool "NXP FlexRAM error interrupt" + help + Allow flexram to generate error interrupts + +endif # DT_HAS_NXP_FLEXRAM_ENABLED diff --git a/drivers/memc/memc_nxp_flexram.c b/drivers/memc/memc_nxp_flexram.c new file mode 100644 index 000000000000000..39da8349e1ab657 --- /dev/null +++ b/drivers/memc/memc_nxp_flexram.c @@ -0,0 +1,231 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "memc_nxp_flexram.h" +#include +#include +#include +#include +#include +#include + +#include "fsl_device_registers.h" + + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) +BUILD_ASSERT(DT_PROP(FLEXRAM_DT_NODE, flexram_has_magic_addr), + "SOC does not support magic flexram addresses"); +#endif + +#define BANK_SIZE (DT_PROP(FLEXRAM_DT_NODE, flexram_bank_size) * 1024) +#define NUM_BANKS DT_PROP(FLEXRAM_DT_NODE, flexram_num_ram_banks) + +#define IS_CHILD_RAM_TYPE(node_id, compat) DT_NODE_HAS_COMPAT(node_id, compat) +#define DOES_RAM_TYPE_EXIST(compat) \ + DT_FOREACH_CHILD_SEP_VARGS(FLEXRAM_DT_NODE, IS_CHILD_RAM_TYPE, (+), compat) + +#if DOES_RAM_TYPE_EXIST(mmio_sram) +#define FIND_OCRAM_NODE(node_id) \ + COND_CODE_1(DT_NODE_HAS_COMPAT(node_id, mmio_sram), (node_id), ()) +#define OCRAM_DT_NODE DT_FOREACH_CHILD(FLEXRAM_DT_NODE, FIND_OCRAM_NODE) +#define OCRAM_START (DT_REG_ADDR(OCRAM_DT_NODE)) +#define OCRAM_END (OCRAM_START + DT_REG_SIZE(OCRAM_DT_NODE)) +#endif /* OCRAM */ +#if DOES_RAM_TYPE_EXIST(nxp_imx_dtcm) +#define FIND_DTCM_NODE(node_id) \ + COND_CODE_1(DT_NODE_HAS_COMPAT(node_id, nxp_imx_dtcm), (node_id), ()) +#define DTCM_DT_NODE DT_FOREACH_CHILD(FLEXRAM_DT_NODE, FIND_DTCM_NODE) +#define DTCM_START (DT_REG_ADDR(DTCM_DT_NODE)) +#define DTCM_END (DTCM_START + DT_REG_SIZE(DTCM_DT_NODE)) +#endif /* DTCM */ +#if DOES_RAM_TYPE_EXIST(nxp_imx_itcm) +#define FIND_ITCM_NODE(node_id) \ + COND_CODE_1(DT_NODE_HAS_COMPAT(node_id, nxp_imx_itcm), (node_id), ()) +#define ITCM_DT_NODE DT_FOREACH_CHILD(FLEXRAM_DT_NODE, FIND_ITCM_NODE) +#define ITCM_START (DT_REG_ADDR(ITCM_DT_NODE)) +#define ITCM_END (ITCM_START + DT_REG_SIZE(ITCM_DT_NODE)) +#endif /* ITCM */ + + +#ifdef FLEXRAM_RUNTIME_BANKS_USED + +#define PLUS_ONE_BANK(node_id, prop, idx) 1 +#define COUNT_BANKS \ + DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, PLUS_ONE_BANK, (+)) +BUILD_ASSERT(COUNT_BANKS == NUM_BANKS, "wrong number of flexram banks defined"); + +#ifdef OCRAM_DT_NODE +#define ADD_BANK_IF_OCRAM(node_id, prop, idx) \ + COND_CODE_1(IS_EQ(DT_PROP_BY_IDX(node_id, prop, idx), FLEXRAM_OCRAM), \ + (BANK_SIZE), (0)) +#define OCRAM_TOTAL \ + DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, ADD_BANK_IF_OCRAM, (+)) +BUILD_ASSERT((OCRAM_TOTAL) == DT_REG_SIZE(OCRAM_DT_NODE), "OCRAM node size is wrong"); +#endif /* OCRAM */ + +#ifdef DTCM_DT_NODE +#define ADD_BANK_IF_DTCM(node_id, prop, idx) \ + COND_CODE_1(IS_EQ(DT_PROP_BY_IDX(node_id, prop, idx), FLEXRAM_DTCM), \ + (BANK_SIZE), (0)) +#define DTCM_TOTAL \ + DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, ADD_BANK_IF_DTCM, (+)) +BUILD_ASSERT((DTCM_TOTAL) == DT_REG_SIZE(DTCM_DT_NODE), "DTCM node size is wrong"); +#endif /* DTCM */ + +#ifdef ITCM_DT_NODE +#define ADD_BANK_IF_ITCM(node_id, prop, idx) \ + COND_CODE_1(IS_EQ(DT_PROP_BY_IDX(node_id, prop, idx), FLEXRAM_ITCM), \ + (BANK_SIZE), (0)) +#define ITCM_TOTAL \ + DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, ADD_BANK_IF_ITCM, (+)) +BUILD_ASSERT((ITCM_TOTAL) == DT_REG_SIZE(ITCM_DT_NODE), "ITCM node size is wrong"); +#endif /* ITCM */ + +#endif /* FLEXRAM_RUNTIME_BANKS_USED */ + +static FLEXRAM_Type *const base = (FLEXRAM_Type *) DT_REG_ADDR(FLEXRAM_DT_NODE); + +#ifdef FLEXRAM_INTERRUPTS_USED +static flexram_callback_t flexram_callback; +static void *flexram_user_data; + +void memc_flexram_register_callback(flexram_callback_t callback, void *user_data) +{ + flexram_callback = callback; + flexram_user_data = user_data; +} + +static void nxp_flexram_isr(void *arg) +{ + ARG_UNUSED(arg); + + if (flexram_callback == NULL) { + return; + } + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT) + if (base->INT_STATUS & FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK; + flexram_callback(flexram_ocram_access_error, flexram_user_data); + } + if (base->INT_STATUS & FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK; + flexram_callback(flexram_dtcm_access_error, flexram_user_data); + } + if (base->INT_STATUS & FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK; + flexram_callback(flexram_itcm_access_error, flexram_user_data); + } +#endif /* CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT */ + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) + if (base->INT_STATUS & FLEXRAM_INT_STATUS_OCRAM_MAM_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_OCRAM_MAM_STATUS_MASK; + flexram_callback(flexram_ocram_magic_addr, flexram_user_data); + } + if (base->INT_STATUS & FLEXRAM_INT_STATUS_DTCM_MAM_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_DTCM_MAM_STATUS_MASK; + flexram_callback(flexram_dtcm_magic_addr, flexram_user_data); + } + if (base->INT_STATUS & FLEXRAM_INT_STATUS_ITCM_MAM_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_ITCM_MAM_STATUS_MASK; + flexram_callback(flexram_itcm_magic_addr, flexram_user_data); + } +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ +} + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) +int memc_flexram_set_ocram_magic_addr(uint32_t ocram_addr) +{ +#ifdef OCRAM_DT_NODE + ocram_addr -= DT_REG_ADDR(OCRAM_DT_NODE); + if (ocram_addr >= DT_REG_SIZE(OCRAM_DT_NODE)) { + return -EINVAL; + } + + base->OCRAM_MAGIC_ADDR &= ~FLEXRAM_OCRAM_MAGIC_ADDR_OCRAM_MAGIC_ADDR_MASK; + base->OCRAM_MAGIC_ADDR |= FLEXRAM_OCRAM_MAGIC_ADDR_OCRAM_MAGIC_ADDR(ocram_addr); + + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_OCRAM_MAM_STAT_EN_MASK; + return 0; +#else + return -ENODEV; +#endif +} + +int memc_flexram_set_itcm_magic_addr(uint32_t itcm_addr) +{ +#ifdef ITCM_DT_NODE + itcm_addr -= DT_REG_ADDR(ITCM_DT_NODE); + if (itcm_addr >= DT_REG_SIZE(ITCM_DT_NODE)) { + return -EINVAL; + } + + base->ITCM_MAGIC_ADDR &= ~FLEXRAM_ITCM_MAGIC_ADDR_ITCM_MAGIC_ADDR_MASK; + base->ITCM_MAGIC_ADDR |= FLEXRAM_ITCM_MAGIC_ADDR_ITCM_MAGIC_ADDR(itcm_addr); + + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_ITCM_MAM_STAT_EN_MASK; + return 0; +#else + return -ENODEV; +#endif +} + +int memc_flexram_set_dtcm_magic_addr(uint32_t dtcm_addr) +{ +#ifdef DTCM_DT_NODE + dtcm_addr -= DT_REG_ADDR(DTCM_DT_NODE); + if (dtcm_addr >= DT_REG_SIZE(DTCM_DT_NODE)) { + return -EINVAL; + } + + base->DTCM_MAGIC_ADDR &= ~FLEXRAM_DTCM_MAGIC_ADDR_DTCM_MAGIC_ADDR_MASK; + base->DTCM_MAGIC_ADDR |= FLEXRAM_DTCM_MAGIC_ADDR_DTCM_MAGIC_ADDR(dtcm_addr); + + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_DTCM_MAM_STAT_EN_MASK; + return 0; +#else + return -ENODEV; +#endif +} +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ + +#endif /* FLEXRAM_INTERRUPTS_USED */ + +static int nxp_flexram_init(void) +{ + if (DT_PROP(FLEXRAM_DT_NODE, flexram_tcm_read_wait_mode)) { + base->TCM_CTRL |= FLEXRAM_TCM_CTRL_TCM_WWAIT_EN_MASK; + } + if (DT_PROP(FLEXRAM_DT_NODE, flexram_tcm_write_wait_mode)) { + base->TCM_CTRL |= FLEXRAM_TCM_CTRL_TCM_RWAIT_EN_MASK; + } + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT) + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_OCRAM_ERR_SIG_EN_MASK; + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_DTCM_ERR_SIG_EN_MASK; + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_ITCM_ERR_SIG_EN_MASK; + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_OCRAM_ERR_STAT_EN_MASK; + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_DTCM_ERR_STAT_EN_MASK; + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_ITCM_ERR_STAT_EN_MASK; +#endif /* CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT */ + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_OCRAM_MAM_SIG_EN_MASK; + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_DTCM_MAM_SIG_EN_MASK; + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_ITCM_MAM_SIG_EN_MASK; +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ + +#ifdef FLEXRAM_INTERRUPTS_USED + IRQ_CONNECT(DT_IRQN(FLEXRAM_DT_NODE), DT_IRQ(FLEXRAM_DT_NODE, priority), + nxp_flexram_isr, NULL, 0); + irq_enable(DT_IRQN(FLEXRAM_DT_NODE)); +#endif /* FLEXRAM_INTERRUPTS_USED */ + + return 0; +} + +SYS_INIT(nxp_flexram_init, EARLY, 0); diff --git a/drivers/memc/memc_nxp_flexram.h b/drivers/memc/memc_nxp_flexram.h new file mode 100644 index 000000000000000..34f606e6b86c1f8 --- /dev/null +++ b/drivers/memc/memc_nxp_flexram.h @@ -0,0 +1,98 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define FLEXRAM_DT_NODE DT_INST(0, nxp_flexram) +#define IOMUXC_GPR_DT_NODE DT_INST(0, nxp_imx_gpr) + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) || \ + defined(CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT) +#define FLEXRAM_INTERRUPTS_USED +#endif + +#if DT_PROP_HAS_IDX(FLEXRAM_DT_NODE, flexram_bank_spec, 0) +#define FLEXRAM_RUNTIME_BANKS_USED 1 +#endif + +#ifdef FLEXRAM_INTERRUPTS_USED +enum memc_flexram_interrupt_cause { +#ifdef CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT + flexram_ocram_access_error, + flexram_itcm_access_error, + flexram_dtcm_access_error, +#endif +#ifdef CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API + flexram_ocram_magic_addr, + flexram_itcm_magic_addr, + flexram_dtcm_magic_addr, +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ +}; + +typedef void (*flexram_callback_t)(enum memc_flexram_interrupt_cause, void *user_data); + +void memc_flexram_register_callback(flexram_callback_t callback, void *user_data); +#endif /* FLEXRAM_INTERRUPTS_USED */ + +#ifdef FLEXRAM_RUNTIME_BANKS_USED + +/* + * call from platform_init to set up flexram if using runtime map + * must be inlined because cannot use stack + */ +#define GPR17_REG_FILL(node_id, prop, idx) + (DT_PROP_BY_IDX(node_id, prop, idx) << idx) +static inline void memc_flexram_dt_partition(void) +{ + /* iomuxc_gpr must be const (in ROM region) because used in reconfiguring ram */ + static IOMUXC_GPR_Type *const iomuxc_gpr = + (IOMUXC_GPR_Type *) DT_REG_ADDR(IOMUXC_GPR_DT_NODE); + /* do not create stack variables or use any data from ram in this function */ + iomuxc_gpr->GPR17 = DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, + flexram_bank_spec, GPR17_REG_FILL, (+)); + iomuxc_gpr->GPR16 |= IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL_MASK; +} +#endif /* FLEXRAM_RUNTIME_BANKS_USED */ + + +#ifdef CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API +/** @brief Sets magic address for OCRAM + * + * Magic address allows core interrupt from FlexRAM when address + * is accessed. + * + * @param ocram_addr: An address in OCRAM to set magic function on. + * @retval 0 on success + * @retval -EINVAL if ocram_addr is not in OCRAM + * @retval -ENODEV if there is no OCRAM allocation in flexram + */ +int memc_flexram_set_ocram_magic_addr(uint32_t ocram_addr); + +/** @brief Sets magic address for ITCM + * + * Magic address allows core interrupt from FlexRAM when address + * is accessed. + * + * @param itcm_addr: An address in ITCM to set magic function on. + * @retval 0 on success + * @retval -EINVAL if itcm_addr is not in ITCM + * @retval -ENODEV if there is no ITCM allocation in flexram + */ +int memc_flexram_set_itcm_magic_addr(uint32_t itcm_addr); + +/** @brief Sets magic address for DTCM + * + * Magic address allows core interrupt from FlexRAM when address + * is accessed. + * + * @param dtcm_addr: An address in DTCM to set magic function on. + * @retval 0 on success + * @retval -EINVAL if dtcm_addr is not in DTCM + * @retval -ENODEV if there is no DTCM allocation in flexram + */ +int memc_flexram_set_dtcm_magic_addr(uint32_t dtcm_addr); + +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ diff --git a/include/zephyr/dt-bindings/memory-controller/nxp,flexram.h b/include/zephyr/dt-bindings/memory-controller/nxp,flexram.h new file mode 100644 index 000000000000000..2c35e655fc995de --- /dev/null +++ b/include/zephyr/dt-bindings/memory-controller/nxp,flexram.h @@ -0,0 +1,15 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEMORY_CONTROLLER_NXP_FLEXRAM_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_MEMORY_CONTROLLER_NXP_FLEXRAM_H_ + +#define FLEXRAM_NONE 0 +#define FLEXRAM_OCRAM 1 +#define FLEXRAM_DTCM 2 +#define FLEXRAM_ITCM 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEMORY_CONTROLLER_NXP_FLEXRAM_H_ */ From 2d1fdb5586d219bb1e27e5e335bd216bf46a09c9 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 14 Sep 2023 19:40:17 -0500 Subject: [PATCH 0233/1049] soc: nxp: rt1xxx: Enable NXP FlexRAM Enable NXP FlexRAM in DTS and SOC code. Do not configure flexram at runtime if the code is in the RAM. Fix RT1060 DT to be more accurate. Signed-off-by: Declan Snyder --- dts/arm/nxp/nxp_rt1010.dtsi | 9 +++++ dts/arm/nxp/nxp_rt1015.dtsi | 9 +++++ dts/arm/nxp/nxp_rt1020.dtsi | 13 ++++++ dts/arm/nxp/nxp_rt1024.dtsi | 13 ++++++ dts/arm/nxp/nxp_rt1040.dtsi | 4 ++ dts/arm/nxp/nxp_rt1050.dtsi | 21 ++++++++++ dts/arm/nxp/nxp_rt1060.dtsi | 44 ++++++++++++++++----- dts/arm/nxp/nxp_rt1064.dtsi | 21 ++++++++++ dts/arm/nxp/nxp_rt10xx.dtsi | 7 +++- dts/arm/nxp/nxp_rt11xx_cm7.dtsi | 28 ++++++++++++- soc/arm/nxp_imx/rt/CMakeLists.txt | 3 ++ soc/arm/nxp_imx/rt/Kconfig.defconfig.series | 3 ++ soc/arm/nxp_imx/rt/soc_rt10xx.c | 7 ++++ soc/arm/nxp_imx/rt/soc_rt11xx.c | 8 +++- 14 files changed, 178 insertions(+), 12 deletions(-) diff --git a/dts/arm/nxp/nxp_rt1010.dtsi b/dts/arm/nxp/nxp_rt1010.dtsi index 1afed91a45ca775..84d47e0f35eb527 100644 --- a/dts/arm/nxp/nxp_rt1010.dtsi +++ b/dts/arm/nxp/nxp_rt1010.dtsi @@ -6,6 +6,15 @@ #include +&flexram { + flexram,num-ram-banks = <4>; + /* default fuse */ + flexram,bank-spec = , + , + , + ; +}; + &sysclk { clock-frequency = <500000000>; }; diff --git a/dts/arm/nxp/nxp_rt1015.dtsi b/dts/arm/nxp/nxp_rt1015.dtsi index 05aeeb86be13dae..59c62eb4452d8fc 100644 --- a/dts/arm/nxp/nxp_rt1015.dtsi +++ b/dts/arm/nxp/nxp_rt1015.dtsi @@ -7,6 +7,15 @@ #include +&flexram { + flexram,num-ram-banks = <4>; + /* default fuse */ + flexram,bank-spec = , + , + , + ; +}; + &sysclk { clock-frequency = <500000000>; }; diff --git a/dts/arm/nxp/nxp_rt1020.dtsi b/dts/arm/nxp/nxp_rt1020.dtsi index 6b2a26f5242a810..b42a17960fa66dd 100644 --- a/dts/arm/nxp/nxp_rt1020.dtsi +++ b/dts/arm/nxp/nxp_rt1020.dtsi @@ -7,6 +7,19 @@ #include +&flexram { + flexram,num-ram-banks = <8>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + ; +}; + &sysclk { clock-frequency = <500000000>; }; diff --git a/dts/arm/nxp/nxp_rt1024.dtsi b/dts/arm/nxp/nxp_rt1024.dtsi index c8332df17e08bc5..62262bb211873ff 100644 --- a/dts/arm/nxp/nxp_rt1024.dtsi +++ b/dts/arm/nxp/nxp_rt1024.dtsi @@ -7,6 +7,19 @@ #include +&flexram { + flexram,num-ram-banks = <8>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + ; +}; + &sysclk { clock-frequency = <500000000>; }; diff --git a/dts/arm/nxp/nxp_rt1040.dtsi b/dts/arm/nxp/nxp_rt1040.dtsi index 110680f44a75999..c4aa2d578917446 100644 --- a/dts/arm/nxp/nxp_rt1040.dtsi +++ b/dts/arm/nxp/nxp_rt1040.dtsi @@ -6,6 +6,10 @@ #include +&flexram { + flexram,num-ram-banks = <16>; +}; + &sysclk { clock-frequency = <500000000>; }; diff --git a/dts/arm/nxp/nxp_rt1050.dtsi b/dts/arm/nxp/nxp_rt1050.dtsi index 16b2669b416a981..0a66b9b791ec259 100644 --- a/dts/arm/nxp/nxp_rt1050.dtsi +++ b/dts/arm/nxp/nxp_rt1050.dtsi @@ -5,6 +5,27 @@ */ #include +&flexram { + flexram,num-ram-banks = <16>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; +}; + &ccm { arm-podf { clock-div = <2>; diff --git a/dts/arm/nxp/nxp_rt1060.dtsi b/dts/arm/nxp/nxp_rt1060.dtsi index 62e01a5f60923ac..8a9cba715e0c411 100644 --- a/dts/arm/nxp/nxp_rt1060.dtsi +++ b/dts/arm/nxp/nxp_rt1060.dtsi @@ -6,14 +6,33 @@ #include -/* i.MX rt1060 has two continuous on-chip RAM, one is part of the - * FlexRAM mapped at 0x20280000 (vs 0x20280000 on rt1050) and is - * configurable (256KB by defaults), the other one is dedicated 512KB - * ram (OCRAM2) mapped at 0x20200000. In order to have a continuous - * region, we describe them in one 768Kb unique node. - */ -&ocram { - reg = <0x20200000 DT_SIZE_K(768)>; +&flexram { + /* FlexRAM OCRAM is at a different address on RT1060 */ + /delete-node/ ocram@20200000; + ocram: ocram@20280000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20280000 DT_SIZE_K(256)>; + zephyr,memory-region = "OCRAM"; + }; + + flexram,num-ram-banks = <16>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; &ccm { @@ -26,9 +45,9 @@ }; }; -/* i.MX rt1060 has a second Ethernet controller. */ / { soc { + /* i.MX rt1060 has a second Ethernet controller. */ enet2: ethernet@402d4000 { compatible = "nxp,kinetis-ethernet"; reg = <0x402D4000 0x628>; @@ -42,6 +61,13 @@ interrupt-names = "IEEE1588_TMR"; }; }; + + /* RT1060 has a dedicated OCRAM region */ + ocram2: ocram@20200000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20200000 DT_SIZE_K(512)>; + zephyr,memory-region = "OCRAM2"; + }; }; }; diff --git a/dts/arm/nxp/nxp_rt1064.dtsi b/dts/arm/nxp/nxp_rt1064.dtsi index fcb909e0cfcd630..73ed88277382d69 100644 --- a/dts/arm/nxp/nxp_rt1064.dtsi +++ b/dts/arm/nxp/nxp_rt1064.dtsi @@ -7,6 +7,27 @@ #include +&flexram { + flexram,num-ram-banks = <16>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; +}; + &flexspi2 { status = "okay"; reg = <0x402a4000 0x4000>, <0x70000000 DT_SIZE_M(4)>; diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 23bd7255301bb45..e7e4e6448b28786 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -11,6 +11,7 @@ #include #include #include +#include / { chosen { @@ -87,13 +88,17 @@ soc { flexram: flexram@400b0000 { - compatible = "nxp,imx-flexram"; + compatible = "nxp,flexram"; reg = <0x400b0000 0x4000>; interrupts = <38 0>; #address-cells = <1>; #size-cells = <1>; + status = "okay"; + + flexram,bank-size = <32>; + itcm: itcm@0 { compatible = "zephyr,memory-region", "nxp,imx-itcm"; reg = <0x00000000 DT_SIZE_K(128)>; diff --git a/dts/arm/nxp/nxp_rt11xx_cm7.dtsi b/dts/arm/nxp/nxp_rt11xx_cm7.dtsi index 28cc4ff020da6ff..88d1035ddc39f4c 100644 --- a/dts/arm/nxp/nxp_rt11xx_cm7.dtsi +++ b/dts/arm/nxp/nxp_rt11xx_cm7.dtsi @@ -1,10 +1,11 @@ /* - * Copyright (c) 2021, NXP + * Copyright 2021-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ #include +#include / { cpus { @@ -22,12 +23,35 @@ /delete-node/ dma-controller@40c14000; flexram: flexram@40028000 { + compatible = "nxp,flexram"; + reg = <0x40028000 0x4000>; interrupts = <50 0>; #address-cells = <1>; #size-cells = <1>; + flexram,bank-size = <32>; + flexram,num-ram-banks = <16>; + flexram,has-magic-addr; + /* same as default fuse value */ + flexram,bank-spec = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + itcm: itcm@0 { compatible = "zephyr,memory-region", "nxp,imx-itcm"; reg = <0x00000000 DT_SIZE_K(256)>; @@ -39,6 +63,8 @@ reg = <0x20000000 DT_SIZE_K(256)>; zephyr,memory-region = "DTCM"; }; + + /* no ocram node for this bank-spec */ }; /* diff --git a/soc/arm/nxp_imx/rt/CMakeLists.txt b/soc/arm/nxp_imx/rt/CMakeLists.txt index 125db4957f8299a..92ab665a0efbf21 100644 --- a/soc/arm/nxp_imx/rt/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt/CMakeLists.txt @@ -50,6 +50,9 @@ zephyr_compile_definitions_ifdef(CONFIG_ENTROPY_MCUX_CAAM CACHE_MODE_WRITE_THROU zephyr_compile_definitions_ifdef(CONFIG_USB_DEVICE_DRIVER DATA_SECTION_IS_CACHEABLE=1) +# flexram header +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/memc) + zephyr_linker_section_configure( SECTION .rom_start INPUT ".boot_hdr.ivt" diff --git a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series index 7a1aac41ce32517..b4e8aeb74220267 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series +++ b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series @@ -92,6 +92,9 @@ config FLASH_SIZE default $(dt_node_int_prop_int,$(DT_CHOSEN_FLASH_NODE),size,Kb) \ if $(DT_FLASH_HAS_SIZE_PROP) +config MEMC + default y + choice USB_MCUX_CONTROLLER_TYPE default USB_DC_NXP_EHCI endchoice diff --git a/soc/arm/nxp_imx/rt/soc_rt10xx.c b/soc/arm/nxp_imx/rt/soc_rt10xx.c index ba22a633a506eab..91ec748a61ae700 100644 --- a/soc/arm/nxp_imx/rt/soc_rt10xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt10xx.c @@ -21,6 +21,8 @@ #include "usb.h" #endif +#include "memc_nxp_flexram.h" + #include #define CCM_NODE DT_INST(0, nxp_imx_ccm) @@ -345,6 +347,11 @@ void z_arm_platform_init(void) { /* Call CMSIS SystemInit */ SystemInit(); + +#if defined(FLEXRAM_RUNTIME_BANKS_USED) + /* Configure flexram if not running from RAM */ + memc_flexram_dt_partition(); +#endif } #endif diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c index ca3ebd08c662bf3..f9eb7b7e381ac9a 100644 --- a/soc/arm/nxp_imx/rt/soc_rt11xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NXP + * Copyright 2021-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,6 +33,7 @@ #include "usb_phy.h" #include "usb.h" #endif +#include "memc_nxp_flexram.h" #include @@ -689,6 +690,11 @@ static int imxrt_init(void) void z_arm_platform_init(void) { SystemInit(); + +#if defined(FLEXRAM_RUNTIME_BANKS_USED) + /* Configure flexram if not running from RAM */ + memc_flexram_dt_partition(); +#endif } #endif From 31eb944fcdf0d30630d56a76ac543c7c5dce34d9 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 14 Sep 2023 23:25:32 -0500 Subject: [PATCH 0234/1049] samples: boards: mimxrt11xx_cm7: Magic addr sample Add magic address sample to show how to use flexram magic address using memc flexram driver. Signed-off-by: Declan Snyder --- .../magic_addr/CMakeLists.txt | 10 ++++ .../mimxrt1170_evk_cm7/magic_addr/README.rst | 18 ++++++ .../mimxrt1170_evk_cm7/magic_addr/prj.conf | 3 + .../mimxrt1170_evk_cm7/magic_addr/sample.yaml | 12 ++++ .../mimxrt1170_evk_cm7/magic_addr/src/main.c | 58 +++++++++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 samples/boards/mimxrt1170_evk_cm7/magic_addr/CMakeLists.txt create mode 100644 samples/boards/mimxrt1170_evk_cm7/magic_addr/README.rst create mode 100644 samples/boards/mimxrt1170_evk_cm7/magic_addr/prj.conf create mode 100644 samples/boards/mimxrt1170_evk_cm7/magic_addr/sample.yaml create mode 100644 samples/boards/mimxrt1170_evk_cm7/magic_addr/src/main.c diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/CMakeLists.txt b/samples/boards/mimxrt1170_evk_cm7/magic_addr/CMakeLists.txt new file mode 100644 index 000000000000000..b8af716702a085e --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(magic_addr) + +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/memc) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/README.rst b/samples/boards/mimxrt1170_evk_cm7/magic_addr/README.rst new file mode 100644 index 000000000000000..679343d84ff10d3 --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/README.rst @@ -0,0 +1,18 @@ +.. _flexram_magic_addr: + +FLEXRAM Magic Addr +################## + +Overview +******** + +A sample that shows how to use RT11XX FLEXRAM Magic Addr functionality + +Magic Addr is a feature of FlexRAM that allows user to configure an interrupt +on an arbitrary RAM/TCM address access. This sample shows how to use the custom +API for the flexram in zephyr to use this unique feature. + +Building and Running +******************** + +see board documentation diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/prj.conf b/samples/boards/mimxrt1170_evk_cm7/magic_addr/prj.conf new file mode 100644 index 000000000000000..b58887f49985ba0 --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/prj.conf @@ -0,0 +1,3 @@ +CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API=y +CONFIG_CONSOLE_SUBSYS=y +CONFIG_CONSOLE_GETCHAR=y diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/sample.yaml b/samples/boards/mimxrt1170_evk_cm7/magic_addr/sample.yaml new file mode 100644 index 000000000000000..10e876847f7310f --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/sample.yaml @@ -0,0 +1,12 @@ +sample: + description: RT1170 FLEXRAM Magic Addr example + name: magic addr +common: + integration_platforms: + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 +tests: + sample.boards.mimxrt1170_evk.magic_addr: + platform_allow: + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/src/main.c b/samples/boards/mimxrt1170_evk_cm7/magic_addr/src/main.c new file mode 100644 index 000000000000000..6856ca8f10f9d97 --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/src/main.c @@ -0,0 +1,58 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "memc_nxp_flexram.h" +#include +#include +#include + +K_SEM_DEFINE(dtcm_magic, 0, 1); + +__dtcm_bss_section uint8_t var; +int cnt; + +void flexram_magic_addr_isr_cb(enum memc_flexram_interrupt_cause cause, + void *data) +{ + ARG_UNUSED(data); + + if (cause == flexram_dtcm_magic_addr) { + printf("Magic DTCM address accessed %d times\n", ++cnt); + k_sem_give(&dtcm_magic); + } +} + + +int main(void) +{ + memc_flexram_register_callback(flexram_magic_addr_isr_cb, NULL); + + console_init(); + + printf("%s is opening spellbook...\n", CONFIG_BOARD); + printf("Cast some characters:\n"); + + uint32_t dtcm_addr = (uint32_t)&var; + + memc_flexram_set_dtcm_magic_addr(dtcm_addr); + + uint8_t tmp; + + while (1) { + printf("\n"); + tmp = console_getchar(); + printf("Writing %c to magic addr...\n", tmp); + var = tmp; + k_sem_take(&dtcm_magic, K_FOREVER); + printf("Reading from magic addr...\n"); + printf("Magic variable got: %c\n", var); + k_sem_take(&dtcm_magic, K_FOREVER); + } + + return 0; +} From c35e677d823d4684fc26beeeaac154b1b83ddc3f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 28 Sep 2023 11:57:43 +0200 Subject: [PATCH 0235/1049] Bluetooth: Audio: Split ltv_set_val from codec_cfg_set_val Add a new function, ltv_set_val, that did most of the data manipulation from codec_cfg_set_val, so that we can reuse that code for the codec cap and codec meta functions as well. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/codec.c | 184 ++++++++++++++++++--------------- 1 file changed, 101 insertions(+), 83 deletions(-) diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 5b064987a257d60..1c156d87028e9fa 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -112,6 +112,11 @@ int bt_audio_codec_cfg_frame_dur_us_to_frame_dur(uint32_t frame_dur_us) } } +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 || \ + CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ + CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 || \ + CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 + struct search_type_param { bool found; uint8_t type; @@ -134,6 +139,94 @@ static bool parse_cb(struct bt_data *data, void *user_data) return true; } +static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t *data, + size_t data_len) +{ + for (uint16_t i = 0U; i < buf->len;) { + uint8_t *len = &buf->data[i++]; + const uint8_t data_type = buf->data[i++]; + const uint8_t value_len = *len - sizeof(data_type); + + if (data_type == type) { + uint8_t *value = &buf->data[i]; + + if (data_len == value_len) { + memcpy(value, data, data_len); + } else { + const int16_t diff = data_len - value_len; + uint8_t *old_next_data_start; + uint8_t *new_next_data_start; + uint8_t data_len_to_move; + + /* Check if this is the last value in the buffer */ + if (value + value_len == buf->data + buf->len) { + data_len_to_move = 0U; + } else { + old_next_data_start = value + value_len + 1; + new_next_data_start = value + data_len + 1; + data_len_to_move = + buf->len - (old_next_data_start - buf->data); + } + + if (diff < 0) { + /* In this case we need to move memory around after the copy + * to fit the new shorter data + */ + + memcpy(value, data, data_len); + if (data_len_to_move > 0U) { + memmove(new_next_data_start, old_next_data_start, + data_len_to_move); + } + } else { + /* In this case we need to move memory around before + * the copy to fit the new longer data + */ + if ((buf->len + diff) > buf->size) { + LOG_DBG("Cannot fit data_len %zu in buf with len " + "%u and size %u", + data_len, buf->len, buf->size); + return -ENOMEM; + } + + if (data_len_to_move > 0) { + memmove(new_next_data_start, old_next_data_start, + data_len_to_move); + } + memcpy(value, data, data_len); + } + + buf->len += diff; + *len += diff; + } + + return buf->len; + } + + i += value_len; + } + + /* If we reach here, we did not find the data in the buffer, so we simply add it */ + if ((buf->len + data_len) <= buf->size) { + net_buf_simple_add_u8(buf, data_len + sizeof(type)); + net_buf_simple_add_u8(buf, type); + if (data_len > 0) { + net_buf_simple_add_mem(buf, data, data_len); + } + } else { + LOG_DBG("Cannot fit data_len %zu in codec_cfg with len %u and size %u", data_len, + buf->len, buf->size); + return -ENOMEM; + } + + return buf->len; +} +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 || \ + * CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ + * CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 || \ + * CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 \ + */ + #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 static void init_net_buf_simple_from_codec_cfg(struct net_buf_simple *buf, @@ -185,6 +278,9 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, u int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t type, const uint8_t *data, size_t data_len) { + struct net_buf_simple buf; + int ret; + CHECKIF(codec_cfg == NULL) { LOG_DBG("codec_cfg is NULL"); return -EINVAL; @@ -200,92 +296,14 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t typ return -EINVAL; } - for (uint16_t i = 0U; i < codec_cfg->data_len;) { - uint8_t *len = &codec_cfg->data[i++]; - const uint8_t data_type = codec_cfg->data[i++]; - const uint8_t value_len = *len - sizeof(data_type); - - if (data_type == type) { - uint8_t *value = &codec_cfg->data[i]; - - if (data_len == value_len) { - memcpy(value, data, data_len); - } else { - const int16_t diff = data_len - value_len; - uint8_t *old_next_data_start; - uint8_t *new_next_data_start; - uint8_t data_len_to_move; - - /* Check if this is the last value in the buffer */ - if (value + value_len == codec_cfg->data + codec_cfg->data_len) { - data_len_to_move = 0U; - } else { - old_next_data_start = value + value_len + 1; - new_next_data_start = value + data_len + 1; - data_len_to_move = codec_cfg->data_len - - (old_next_data_start - codec_cfg->data); - } - - if (diff < 0) { - /* In this case we need to move memory around after the copy - * to fit the new shorter data - */ - - memcpy(value, data, data_len); - if (data_len_to_move > 0U) { - memmove(new_next_data_start, old_next_data_start, - data_len_to_move); - } - } else { - /* In this case we need to move memory around before - * the copy to fit the new longer data - */ - if ((codec_cfg->data_len + diff) > - ARRAY_SIZE(codec_cfg->data)) { - LOG_DBG("Cannot fit data_len %zu in buf with len " - "%u and size %u", - data_len, codec_cfg->data_len, - ARRAY_SIZE(codec_cfg->data)); - return -ENOMEM; - } - - if (data_len_to_move > 0) { - memmove(new_next_data_start, old_next_data_start, - data_len_to_move); - } - - memcpy(value, data, data_len); - } - - codec_cfg->data_len += diff; - *len += diff; - } - - return codec_cfg->data_len; - } - - i += value_len; - } - - /* If we reach here, we did not find the data in the buffer, so we simply add it */ - if ((codec_cfg->data_len + data_len) <= ARRAY_SIZE(codec_cfg->data)) { - struct net_buf_simple buf; - - init_net_buf_simple_from_codec_cfg(&buf, codec_cfg); + init_net_buf_simple_from_codec_cfg(&buf, codec_cfg); - net_buf_simple_add_u8(&buf, data_len + sizeof(type)); - net_buf_simple_add_u8(&buf, type); - if (data_len > 0) { - net_buf_simple_add_mem(&buf, data, data_len); - } - codec_cfg->data_len = buf.len; - } else { - LOG_DBG("Cannot fit data_len %zu in codec_cfg with len %u and size %u", data_len, - codec_cfg->data_len, ARRAY_SIZE(codec_cfg->data)); - return -ENOMEM; + ret = ltv_set_val(&buf, type, data, data_len); + if (ret >= 0) { + codec_cfg->data_len = ret; } - return codec_cfg->data_len; + return ret; } int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg) From de0c543e6243d69726cbbc3712bf112c9e2f7324 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 28 Sep 2023 14:13:21 +0200 Subject: [PATCH 0236/1049] Bluetooth: Audio: Update some codec cap assigned numbers Update codec capabiliy frequency, frame duration and channel count to use enums, and add additional documentation and missing values. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/lc3.h | 184 ++++++++++++++++++--------- 1 file changed, 123 insertions(+), 61 deletions(-) diff --git a/include/zephyr/bluetooth/audio/lc3.h b/include/zephyr/bluetooth/audio/lc3.h index 80fec536f89e6b9..ab42f9fdbdf7160 100644 --- a/include/zephyr/bluetooth/audio/lc3.h +++ b/include/zephyr/bluetooth/audio/lc3.h @@ -67,67 +67,129 @@ enum bt_audio_codec_capability_type { BT_AUDIO_CODEC_LC3_FRAME_COUNT = 0x05, }; -/** - * @brief LC3 8 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_8KHZ BIT(0) -/** - * @brief LC3 11.025 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_11KHZ BIT(1) -/** - * @brief LC3 16 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_16KHZ BIT(2) -/** - * @brief LC3 22.05 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_22KHZ BIT(3) -/** - * @brief LC3 24 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_24KHZ BIT(4) -/** - * @brief LC3 32 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_32KHZ BIT(5) -/** - * @brief LC3 44.1 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_44KHZ BIT(6) -/** - * @brief LC3 48 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_48KHZ BIT(7) -/** - * @brief LC3 any frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_ANY \ - (BT_AUDIO_CODEC_LC3_FREQ_8KHZ | BT_AUDIO_CODEC_LC3_FREQ_16KHZ | \ - BT_AUDIO_CODEC_LC3_FREQ_24KHZ | BT_AUDIO_CODEC_LC3_FREQ_32KHZ | \ - BT_AUDIO_CODEC_LC3_FREQ_44KHZ | BT_AUDIO_CODEC_LC3_FREQ_48KHZ) +/** @brief Supported frequencies bitfield */ +enum bt_audio_codec_cap_freq { + /** + * @brief LC3 8 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_8KHZ = BIT(0), + /** + * @brief LC3 11.025 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_11KHZ = BIT(1), + /** + * @brief LC3 16 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_16KHZ = BIT(2), + /** + * @brief LC3 22.05 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_22KHZ = BIT(3), + /** + * @brief LC3 24 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_24KHZ = BIT(4), + /** + * @brief LC3 32 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_32KHZ = BIT(5), + /** + * @brief LC3 44.1 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_44KHZ = BIT(6), + /** + * @brief LC3 48 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_48KHZ = BIT(7), + /** + * @brief LC3 88.2 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_88KHZ = BIT(8), + /** + * @brief LC3 96 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_96KHZ = BIT(9), + /** + * @brief LC3 176.4 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_176KHZ = BIT(10), + /** + * @brief LC3 192 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_192KHZ = BIT(11), + /** + * @brief LC3 384 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_384KHZ = BIT(12), + /** + * @brief LC3 any frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_ANY = + (BT_AUDIO_CODEC_LC3_FREQ_8KHZ | BT_AUDIO_CODEC_LC3_FREQ_11KHZ | + BT_AUDIO_CODEC_LC3_FREQ_16KHZ | BT_AUDIO_CODEC_LC3_FREQ_22KHZ | + BT_AUDIO_CODEC_LC3_FREQ_24KHZ | BT_AUDIO_CODEC_LC3_FREQ_32KHZ | + BT_AUDIO_CODEC_LC3_FREQ_44KHZ | BT_AUDIO_CODEC_LC3_FREQ_48KHZ | + BT_AUDIO_CODEC_LC3_FREQ_88KHZ | BT_AUDIO_CODEC_LC3_FREQ_96KHZ | + BT_AUDIO_CODEC_LC3_FREQ_176KHZ | BT_AUDIO_CODEC_LC3_FREQ_192KHZ | + BT_AUDIO_CODEC_LC3_FREQ_384KHZ), +}; -/** - * @brief LC3 7.5 msec frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_7_5 BIT(0) -/** - * @brief LC3 10 msec frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_10 BIT(1) -/** - * @brief LC3 any frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_ANY \ - (BT_AUDIO_CODEC_LC3_DURATION_7_5 | BT_AUDIO_CODEC_LC3_DURATION_10) -/** - * @brief LC3 7.5 msec preferred frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5 BIT(4) -/** - * @brief LC3 10 msec preferred frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_PREFER_10 BIT(5) +/** @brief Supported frame durations bitfield */ +enum bt_audio_codec_cap_frame_dur { + /** + * @brief LC3 7.5 msec frame duration capability + */ + BT_AUDIO_CODEC_LC3_DURATION_7_5 = BIT(0), + /** + * @brief LC3 10 msec frame duration capability + */ + BT_AUDIO_CODEC_LC3_DURATION_10 = BIT(1), + /** + * @brief LC3 any frame duration capability + */ + BT_AUDIO_CODEC_LC3_DURATION_ANY = + (BT_AUDIO_CODEC_LC3_DURATION_7_5 | BT_AUDIO_CODEC_LC3_DURATION_10), + + /** + * @brief LC3 7.5 msec preferred frame duration capability. + * + * This shall only be set if @ref BT_AUDIO_CODEC_LC3_DURATION_7_5 is also set, and if @ref + * BT_AUDIO_CODEC_LC3_DURATION_PREFER_10 is not set. + */ + BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5 = BIT(4), + /** + * @brief LC3 10 msec preferred frame duration capability + * + * This shall only be set if @ref BT_AUDIO_CODEC_LC3_DURATION_10 is also set, and if @ref + * BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5 is not set. + */ + BT_AUDIO_CODEC_LC3_DURATION_PREFER_10 = BIT(5), +}; + +enum bt_audio_codec_cap_chan_count { + /** Supporting 1 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_1 = BIT(0), + /** Supporting 2 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_2 = BIT(1), + /** Supporting 3 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_3 = BIT(2), + /** Supporting 4 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_4 = BIT(3), + /** Supporting 5 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_5 = BIT(4), + /** Supporting 6 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_6 = BIT(5), + /** Supporting 7 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_7 = BIT(6), + /** Supporting 8 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_8 = BIT(7), + /** Supporting all channels */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_ALL = + (BT_AUDIO_CODEC_CAP_CHAN_COUNT_1 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_2 | + BT_AUDIO_CODEC_CAP_CHAN_COUNT_3 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_4 | + BT_AUDIO_CODEC_CAP_CHAN_COUNT_5 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_6 | + BT_AUDIO_CODEC_CAP_CHAN_COUNT_7 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_8), +}; /** * @brief LC3 minimum supported channel counts @@ -148,7 +210,7 @@ enum bt_audio_codec_capability_type { * BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 3) */ #define BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(...) \ - ((uint8_t)((FOR_EACH(BIT, (|), __VA_ARGS__)) >> 1)) + ((enum bt_audio_codec_cap_chan_count)((FOR_EACH(BIT, (|), __VA_ARGS__)) >> 1)) struct BT_AUDIO_CODEC_LC3_frame_len { uint16_t min; From 06d5a625a60981ce08f69fd1f787f57f5d6270ed Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 28 Sep 2023 14:14:17 +0200 Subject: [PATCH 0237/1049] Bluetooth: Audio: Add codec cap set functions Add set functions for codec capability, to set all assigned number values in the bt_audio_codec_cap struct. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/audio.h | 85 +++++++++++-- subsys/bluetooth/audio/codec.c | 163 ++++++++++++++++++++++++- tests/bluetooth/audio/codec/src/main.c | 106 +++++++++++++++- 3 files changed, 342 insertions(+), 12 deletions(-) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index 403993172ea9b66..597e49ade9c0563 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -994,31 +994,57 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, u /** * @brief Extract the frequency from a codec capability. * - * @param codec_cap The codec configuration to extract data from. + * @param codec_cap The codec capabilities to extract data from. * - * @retval Bitfield of supported frequencies if 0 or positive + * @retval Bitfield of supported frequencies (@ref bt_audio_codec_cap_freq) if 0 or positive * @retval -EINVAL if arguments are invalid * @retval -ENODATA if not found * @retval -EBADMSG if found value has invalid size or value */ int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the supported frequencies of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param freq The supported frequencies to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_freq(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_freq freq); + /** * @brief Extract the frequency from a codec capability. * - * @param codec_cap The codec configuration to extract data from. + * @param codec_cap The codec capabilities to extract data from. * * @retval Bitfield of supported frame durations if 0 or positive * @retval -EINVAL if arguments are invalid * @retval -ENODATA if not found * @retval -EBADMSG if found value has invalid size or value */ -int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec_cap); +int bt_audio_codec_cap_get_frame_dur(const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the frame duration of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param frame_dur The frame duration to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_frame_dur(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_frame_dur frame_dur); /** * @brief Extract the frequency from a codec capability. * - * @param codec_cap The codec configuration to extract data from. + * @param codec_cap The codec capabilities to extract data from. * * @retval Bitfield of supported channel counts if 0 or positive * @retval -EINVAL if arguments are invalid @@ -1028,9 +1054,22 @@ int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_codec_cap *codec_cap); /** - * @brief Extract the frequency from a codec capability. + * @brief Set the channel count of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param chan_count The channel count frequency to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_supported_audio_chan_counts( + struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_cap_chan_count chan_count); + +/** + * @brief Extract the supported octets per codec frame from a codec capability. * - * @param[in] codec_cap The codec configuration to extract data from. + * @param[in] codec_cap The codec capabilities to extract data from. * @param[out] codec_frame Struct to place the resulting values in * * @retval 0 on success @@ -1043,9 +1082,23 @@ int bt_audio_codec_cap_get_octets_per_frame( struct bt_audio_codec_octets_per_codec_frame *codec_frame); /** - * @brief Extract the frequency from a codec capability. + * @brief Set the octets per codec frame of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param codec_frame The octets per codec frame to set. * - * @param codec_cap The codec configuration to extract data from. + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_octets_per_frame( + struct bt_audio_codec_cap *codec_cap, + const struct bt_audio_codec_octets_per_codec_frame *codec_frame); + +/** + * @brief Extract the maximum codec frames per SDU from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. * * @retval Maximum number of codec frames per SDU supported * @retval -EINVAL if arguments are invalid @@ -1054,6 +1107,19 @@ int bt_audio_codec_cap_get_octets_per_frame( */ int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the maximum codec frames per SDU of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param codec_frames_per_sdu The maximum codec frames per SDU to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_max_codec_frames_per_sdu(struct bt_audio_codec_cap *codec_cap, + uint8_t codec_frames_per_sdu); + /** @brief Lookup a specific metadata value based on type * * @param[in] codec_cap The codec data to search in. @@ -1214,6 +1280,7 @@ int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_ */ int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_cap, const uint8_t **vendor_meta); + /** @} */ /* End of bt_audio_codec_cap */ #ifdef __cplusplus diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 1c156d87028e9fa..382c6f370b03dda 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -1074,6 +1074,15 @@ int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_ca #if CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 +static void init_net_buf_simple_from_codec_cap(struct net_buf_simple *buf, + struct bt_audio_codec_cap *codec_cap) +{ + buf->__buf = codec_cap->data; + buf->data = codec_cap->data; + buf->size = sizeof(codec_cap->data); + buf->len = codec_cap->data_len; +} + uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, const uint8_t **data) { @@ -1110,6 +1119,37 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, u return param.data_len; } +int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, uint8_t type, + const uint8_t *data, size_t data_len) +{ + struct net_buf_simple buf; + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + CHECKIF(data == NULL) { + LOG_DBG("data is NULL"); + return -EINVAL; + } + + CHECKIF(data_len == 0U || data_len > UINT8_MAX) { + LOG_DBG("Invalid data_len %zu", data_len); + return -EINVAL; + } + + init_net_buf_simple_from_codec_cap(&buf, codec_cap); + + ret = ltv_set_val(&buf, type, data, data_len); + if (ret >= 0) { + codec_cap->data_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; @@ -1132,7 +1172,28 @@ int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap) return sys_get_le16(data); } -int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec_cap) +int bt_audio_codec_cap_set_freq(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_freq freq) +{ + uint16_t freq_le16; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + if ((freq & BT_AUDIO_CODEC_LC3_FREQ_ANY) != freq) { + LOG_DBG("Invalid freq value: %d", freq); + return -EINVAL; + } + + freq_le16 = sys_cpu_to_le16((uint16_t)freq); + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_FREQ, (uint8_t *)&freq_le16, + sizeof(freq_le16)); +} + +int bt_audio_codec_cap_get_frame_dur(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; uint8_t data_len; @@ -1154,6 +1215,45 @@ int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec return data[0]; } +int bt_audio_codec_cap_set_frame_dur(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_frame_dur frame_dur) +{ + uint8_t frame_dur_u8; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_ANY) == 0) { + LOG_DBG("Invalid frame_dur value: %d", frame_dur); + return -EINVAL; + } + + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5) != 0) { + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_PREFER_10) != 0) { + LOG_DBG("Cannot prefer both 7.5 and 10ms: %d", frame_dur); + return -EINVAL; + } + + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_7_5) == 0) { + LOG_DBG("Cannot prefer 7.5ms when not supported: %d", frame_dur); + return -EINVAL; + } + } + + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_PREFER_10) != 0 && + (frame_dur & BT_AUDIO_CODEC_LC3_DURATION_10) == 0) { + LOG_DBG("Cannot prefer 10ms when not supported: %d", frame_dur); + return -EINVAL; + } + + frame_dur_u8 = (uint8_t)frame_dur; + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_DURATION, &frame_dur_u8, + sizeof(frame_dur_u8)); +} + int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; @@ -1176,6 +1276,27 @@ int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_cod return data[0]; } +int bt_audio_codec_cap_set_supported_audio_chan_counts( + struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_cap_chan_count chan_count) +{ + uint8_t chan_count_u8; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + if ((chan_count & BT_AUDIO_CODEC_CAP_CHAN_COUNT_ALL) != chan_count) { + LOG_DBG("Invalid chan_count value: %d", chan_count); + return -EINVAL; + } + + chan_count_u8 = (uint8_t)chan_count; + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_CHAN_COUNT, &chan_count_u8, + sizeof(chan_count_u8)); +} + int bt_audio_codec_cap_get_octets_per_frame( const struct bt_audio_codec_cap *codec_cap, struct bt_audio_codec_octets_per_codec_frame *codec_frame) @@ -1208,6 +1329,34 @@ int bt_audio_codec_cap_get_octets_per_frame( return 0; } +int bt_audio_codec_cap_set_octets_per_frame( + struct bt_audio_codec_cap *codec_cap, + const struct bt_audio_codec_octets_per_codec_frame *codec_frame) +{ + uint8_t codec_frame_le32[4]; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + CHECKIF(codec_frame == NULL) { + LOG_DBG("codec_frame is NULL"); + return -EINVAL; + } + + if (codec_frame->min > codec_frame->max) { + LOG_DBG("Invalid codec_frame values: %u/%u", codec_frame->min, codec_frame->max); + return -EINVAL; + } + + sys_put_le16(codec_frame->min, codec_frame_le32); + sys_put_le16(codec_frame->max, codec_frame_le32 + 2); + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_FRAME_LEN, codec_frame_le32, + sizeof(codec_frame_le32)); +} + int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; @@ -1230,4 +1379,16 @@ int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_ return data[0]; } +int bt_audio_codec_cap_set_max_codec_frames_per_sdu(struct bt_audio_codec_cap *codec_cap, + uint8_t codec_frames_per_sdu) +{ + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_FRAME_COUNT, + &codec_frames_per_sdu, sizeof(codec_frames_per_sdu)); +} + #endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 */ diff --git a/tests/bluetooth/audio/codec/src/main.c b/tests/bluetooth/audio/codec/src/main.c index edc87c560075d2f..99d5d6f21fdff54 100644 --- a/tests/bluetooth/audio/codec/src/main.c +++ b/tests/bluetooth/audio/codec/src/main.c @@ -376,7 +376,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_freq) zassert_equal(ret, 4, "Unexpected return value %d", ret); } -ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_frame_duration) +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_freq) +{ + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( + BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U, + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); + + int ret; + + ret = bt_audio_codec_cap_get_freq(&codec_cap); + zassert_equal(ret, 4, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_set_freq(&codec_cap, BT_AUDIO_CODEC_LC3_FREQ_22KHZ); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_freq(&codec_cap); + zassert_equal(ret, 8, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_frame_dur) { const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10, @@ -385,8 +404,27 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_frame_duration) int ret; - ret = bt_audio_codec_cap_get_frame_duration(&codec_cap); + ret = bt_audio_codec_cap_get_frame_dur(&codec_cap); + zassert_equal(ret, 2, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_frame_dur) +{ + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( + BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U, + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); + + int ret; + + ret = bt_audio_codec_cap_get_frame_dur(&codec_cap); zassert_equal(ret, 2, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_set_frame_dur(&codec_cap, BT_AUDIO_CODEC_LC3_DURATION_7_5); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_frame_dur(&codec_cap); + zassert_equal(ret, 1, "Unexpected return value %d", ret); } ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_supported_audio_chan_counts) @@ -402,6 +440,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_supported_audio_chan_c zassert_equal(ret, 2, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_supported_audio_chan_counts) +{ + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( + BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U, + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); + + int ret; + + ret = bt_audio_codec_cap_get_supported_audio_chan_counts(&codec_cap); + zassert_equal(ret, 1, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_set_frame_dur(&codec_cap, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(2)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_frame_dur(&codec_cap); + zassert_equal(ret, 2, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_octets_per_frame) { struct bt_audio_codec_octets_per_codec_frame expected = { @@ -424,6 +482,31 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_octets_per_frame) codec_frame.max); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_octets_per_frame) +{ + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( + BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U, + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); + struct bt_audio_codec_octets_per_codec_frame codec_frame; + int ret; + + ret = bt_audio_codec_cap_get_octets_per_frame(&codec_cap, &codec_frame); + zassert_equal(ret, 0, "Unexpected return value %d", ret); + zassert_equal(codec_frame.min, 40U, "Unexpected minimum value %d", codec_frame.min); + zassert_equal(codec_frame.max, 120U, "Unexpected maximum value %d", codec_frame.max); + + codec_frame.min = 50U; + codec_frame.max = 100U; + ret = bt_audio_codec_cap_set_octets_per_frame(&codec_cap, &codec_frame); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_octets_per_frame(&codec_cap, &codec_frame); + zassert_equal(ret, 0, "Unexpected return value %d", ret); + zassert_equal(codec_frame.min, 50U, "Unexpected minimum value %d", codec_frame.min); + zassert_equal(codec_frame.max, 100U, "Unexpected maximum value %d", codec_frame.max); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_max_codec_frames_per_sdu) { const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( @@ -437,6 +520,25 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_max_codec_frames_per_s zassert_equal(ret, 2, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_max_codec_frames_per_sdu) +{ + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( + BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U, + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); + + int ret; + + ret = bt_audio_codec_cap_get_max_codec_frames_per_sdu(&codec_cap); + zassert_equal(ret, 2, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_set_max_codec_frames_per_sdu(&codec_cap, 4U); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_max_codec_frames_per_sdu(&codec_cap); + zassert_equal(ret, 4, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_pref_context) { const enum bt_audio_context ctx = From dbed2512490687083aca4b97d159763a6c8e0004 Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Tue, 24 Oct 2023 00:39:25 +0800 Subject: [PATCH 0238/1049] test: twister: testplan.py use normpath when load test plan it is possible the plan is built in another os so the case key would be 'samples/hello_world/samples.baseic.hello_world' but the testsuite is scaned in current os may in window and the key is like 'samples\\hello_world\\samples.baseic.hello_world' so update the uniq path with only backslash in path Signed-off-by: Hake Huang --- scripts/pylib/twister/twisterlib/testsuite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/testsuite.py b/scripts/pylib/twister/twisterlib/testsuite.py index ecb7c8b40007155..419d0f3959682e7 100644 --- a/scripts/pylib/twister/twisterlib/testsuite.py +++ b/scripts/pylib/twister/twisterlib/testsuite.py @@ -450,7 +450,7 @@ def get_unique(testsuite_root, workdir, name): relative_ts_root = "" # workdir can be "." - unique = os.path.normpath(os.path.join(relative_ts_root, workdir, name)) + unique = os.path.normpath(os.path.join(relative_ts_root, workdir, name)).replace(os.sep, '/') return unique @staticmethod From da4e3e713b9510f3c3a453faebe92e7de8ef5061 Mon Sep 17 00:00:00 2001 From: Ethan Duckett Date: Wed, 25 Oct 2023 17:13:54 +0100 Subject: [PATCH 0239/1049] drivers: adc: ltc2451: Add ltc2451 driver Adds support for the Linear Technologies LTC2451 ADC. Signed-off-by: Ethan Duckett --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.ltc2451 | 8 ++ drivers/adc/adc_ltc2451.c | 105 ++++++++++++++++++ dts/bindings/adc/lltc,ltc2451.yaml | 16 +++ .../build_all/adc/boards/native_posix.overlay | 7 ++ tests/drivers/build_all/adc/testcase.yaml | 1 + 7 files changed, 140 insertions(+) create mode 100644 drivers/adc/Kconfig.ltc2451 create mode 100644 drivers/adc/adc_ltc2451.c create mode 100644 dts/bindings/adc/lltc,ltc2451.yaml diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 4738aaa891c922b..34536f4c4e009df 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -47,3 +47,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_NXP_S32_ADC_SAR adc_nxp_s32_adc_sar.c) zephyr_library_sources_ifdef(CONFIG_ADC_MAX1125X adc_max1125x.c) zephyr_library_sources_ifdef(CONFIG_ADC_MAX11102_17 adc_max11102_17.c) zephyr_library_sources_ifdef(CONFIG_ADC_AD5592 adc_ad5592.c) +zephyr_library_sources_ifdef(CONFIG_ADC_LTC2451 adc_ltc2451.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 14f4d89657e4a65..b52183c2b476bc5 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -118,4 +118,6 @@ source "drivers/adc/Kconfig.max11102_17" source "drivers/adc/Kconfig.ad5592" +source "drivers/adc/Kconfig.ltc2451" + endif # ADC diff --git a/drivers/adc/Kconfig.ltc2451 b/drivers/adc/Kconfig.ltc2451 new file mode 100644 index 000000000000000..8f3cb384cfbc724 --- /dev/null +++ b/drivers/adc/Kconfig.ltc2451 @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Brill Power +# SPDX-License-Identifier: Apache-2.0 + +config ADC_LTC2451 + bool "LTC2451 driver" + default y + depends on DT_HAS_LLTC_LTC2451_ENABLED + select I2C diff --git a/drivers/adc/adc_ltc2451.c b/drivers/adc/adc_ltc2451.c new file mode 100644 index 000000000000000..95b86f30d68a56a --- /dev/null +++ b/drivers/adc/adc_ltc2451.c @@ -0,0 +1,105 @@ +/* LLTC LTC2451 ADC + * + * Copyright (c) 2023 Brill Power Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(ltc2451, CONFIG_ADC_LOG_LEVEL); + +#define DT_DRV_COMPAT lltc_ltc2451 + +struct ltc2451_config { + struct i2c_dt_spec i2c; + uint8_t conversion_speed; +}; + +static int ltc2451_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + ARG_UNUSED(dev); + + if (channel_cfg->channel_id != 0) { + LOG_ERR("Invalid channel id '%d'", channel_cfg->channel_id); + return -EINVAL; + } + + return 0; +} + +static int ltc2451_set_conversion_speed(const struct device *dev, uint8_t conversion_speed) +{ + const struct ltc2451_config *config = dev->config; + uint8_t wr_buf[1]; + int err; + + if (conversion_speed == 60) { + wr_buf[0] = 0; + } else if (conversion_speed == 30) { + wr_buf[0] = 1; + } else { + LOG_ERR("Invalid conversion speed selected"); + return -EINVAL; + } + + err = i2c_write_dt(&config->i2c, wr_buf, sizeof(wr_buf)); + + if (err != 0) { + LOG_ERR("LTC write failed (err %d)", err); + } + + return err; +} + +static int ltc2451_read_latest_conversion(const struct device *dev, + const struct adc_sequence *sequence) +{ + const struct ltc2451_config *config = dev->config; + uint8_t rd_buf[2]; + uint16_t *value_buf; + int err = i2c_read_dt(&config->i2c, rd_buf, sizeof(rd_buf)); + + if (err == 0) { + value_buf = (uint16_t *)sequence->buffer; + value_buf[0] = sys_get_be16(rd_buf); + } else { + LOG_ERR("LTC read failed (err %d)", err); + } + + return err; +} + +static int ltc2451_init(const struct device *dev) +{ + const struct ltc2451_config *config = dev->config; + + if (!device_is_ready(config->i2c.bus)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + + return ltc2451_set_conversion_speed(dev, config->conversion_speed); +} + +static const struct adc_driver_api ltc2451_api = { + .channel_setup = ltc2451_channel_setup, + .read = ltc2451_read_latest_conversion, +}; + +#define LTC2451_DEFINE(index) \ + static const struct ltc2451_config ltc2451_cfg_##index = { \ + .i2c = I2C_DT_SPEC_INST_GET(index), \ + .conversion_speed = DT_INST_PROP(index, conversion_speed), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(index, <c2451_init, NULL, NULL, \ + <c2451_cfg_##index, POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ + <c2451_api); + +DT_INST_FOREACH_STATUS_OKAY(LTC2451_DEFINE) diff --git a/dts/bindings/adc/lltc,ltc2451.yaml b/dts/bindings/adc/lltc,ltc2451.yaml new file mode 100644 index 000000000000000..b68f127337f7b93 --- /dev/null +++ b/dts/bindings/adc/lltc,ltc2451.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Brill Power Ltd. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: Linear Technology LTC2451 ADC + +compatible: "lltc,ltc2451" + +include: i2c-device.yaml + +properties: + conversion-speed: + type: int + enum: + - 30 + - 60 + description: Set conversion speed in Hz diff --git a/tests/drivers/build_all/adc/boards/native_posix.overlay b/tests/drivers/build_all/adc/boards/native_posix.overlay index 5e787d8932f5285..120e05dcfb0726c 100644 --- a/tests/drivers/build_all/adc/boards/native_posix.overlay +++ b/tests/drivers/build_all/adc/boards/native_posix.overlay @@ -87,6 +87,13 @@ reg = <0x7>; #io-channel-cells = <1>; }; + + test_i2c_ltc2451: ltc2451@8{ + compatible = "lltc,ltc2451"; + reg = <0x8>; + conversion-speed = <60>; + #io-channel-cells = <1>; + }; }; test_spi: spi@33334444 { diff --git a/tests/drivers/build_all/adc/testcase.yaml b/tests/drivers/build_all/adc/testcase.yaml index cde46e57a09492c..c8a6fe5e3a7786b 100644 --- a/tests/drivers/build_all/adc/testcase.yaml +++ b/tests/drivers/build_all/adc/testcase.yaml @@ -18,6 +18,7 @@ tests: - adc_ads114s08 - adc_emul - adc_max1125x + - adc_ltc2451 extra_args: "CONFIG_GPIO=y" drivers.adc.cc32xx.build: platform_allow: cc3220sf_launchxl From 9ddc94e0d49f0e2a499bc5200ec4d275e4c1546c Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Sat, 28 Oct 2023 11:12:35 -0700 Subject: [PATCH 0240/1049] drivers: i3c: specify start addr when searching for a free addr For example, if a driver needed to reserve address before it does a ENTDAA, it would need to get free address in a loop, but the get free address func would return the same address everytime. It needs the start address, which would be the last free address it go, to be passed in to get the next free address. Signed-off-by: Ryan McClelland --- drivers/i3c/i3c_cdns.c | 2 +- drivers/i3c/i3c_common.c | 10 +++++----- include/zephyr/drivers/i3c/addresses.h | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index cad6bab65664371..cad71e5cae62073 100644 --- a/drivers/i3c/i3c_cdns.c +++ b/drivers/i3c/i3c_cdns.c @@ -703,7 +703,7 @@ static void cdns_i3c_program_controller_retaining_reg(const struct device *dev) if (!i3c_addr_slots_is_free(&data->common.attached_dev.addr_slots, controller_da)) { controller_da = - i3c_addr_slots_next_free_find(&data->common.attached_dev.addr_slots); + i3c_addr_slots_next_free_find(&data->common.attached_dev.addr_slots, 0); LOG_DBG("%s: 0x%02x DA selected for controller", dev->name, controller_da); } sys_write32(prepare_rr0_dev_address(controller_da), config->base + DEV_ID_RR0(0)); diff --git a/drivers/i3c/i3c_common.c b/drivers/i3c/i3c_common.c index 29746f3cf68eae5..6c170edb9e33b93 100644 --- a/drivers/i3c/i3c_common.c +++ b/drivers/i3c/i3c_common.c @@ -157,13 +157,13 @@ bool i3c_addr_slots_is_free(struct i3c_addr_slots *slots, return (status == I3C_ADDR_SLOT_STATUS_FREE); } -uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots) +uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots, uint8_t start_addr) { uint8_t addr; enum i3c_addr_slot_status status; /* Addresses 0 to 7 are reserved. So start at 8. */ - for (addr = 8; addr < I3C_MAX_ADDR; addr++) { + for (addr = MAX(start_addr, 8); addr < I3C_MAX_ADDR; addr++) { status = i3c_addr_slots_status(slots, addr); if (status == I3C_ADDR_SLOT_STATUS_FREE) { return addr; @@ -252,7 +252,7 @@ int i3c_determine_default_addr(struct i3c_device_desc *target, uint8_t *addr) } else { /* address is not free, get the next one */ *addr = i3c_addr_slots_next_free_find( - &data->attached_dev.addr_slots); + &data->attached_dev.addr_slots, 0); } } else { /* Use the init dynamic address as it's DA, but the RR will need to @@ -281,7 +281,7 @@ int i3c_determine_default_addr(struct i3c_device_desc *target, uint8_t *addr) } else { /* pick a DA to use */ *addr = i3c_addr_slots_next_free_find( - &data->attached_dev.addr_slots); + &data->attached_dev.addr_slots, 0); } } } else { @@ -488,7 +488,7 @@ int i3c_dev_list_daa_addr_helper(struct i3c_addr_slots *addr_slots, /* * Find the next available address. */ - dyn_addr = i3c_addr_slots_next_free_find(addr_slots); + dyn_addr = i3c_addr_slots_next_free_find(addr_slots, 0); if (dyn_addr == 0U) { /* No free addresses available */ diff --git a/include/zephyr/drivers/i3c/addresses.h b/include/zephyr/drivers/i3c/addresses.h index 191e7f881da9c88..c85255d8a691221 100644 --- a/include/zephyr/drivers/i3c/addresses.h +++ b/include/zephyr/drivers/i3c/addresses.h @@ -113,10 +113,11 @@ bool i3c_addr_slots_is_free(struct i3c_addr_slots *slots, * assigned to a new device. * * @param slots Pointer to the address slots structure. + * @param start_addr Where to start searching * * @return The next free address, or 0 if none found. */ -uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots); +uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots, uint8_t start_addr); /** * @brief Mark the address as free (not used) in device list. From fc2a54b80cf0950f615b0259d751c94b64147f5a Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 30 Oct 2023 18:17:33 +0100 Subject: [PATCH 0241/1049] doc: Bluetooth: Audio Stack status table Adds table of the status of the LE Audio stack in the Bluetooth subsystem. Signed-off-by: Emil Gydesen --- .../bluetooth/bluetooth-audio-arch.rst | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) diff --git a/doc/connectivity/bluetooth/bluetooth-audio-arch.rst b/doc/connectivity/bluetooth/bluetooth-audio-arch.rst index 494611282706f29..aa62b4261604e9e 100644 --- a/doc/connectivity/bluetooth/bluetooth-audio-arch.rst +++ b/doc/connectivity/bluetooth/bluetooth-audio-arch.rst @@ -43,6 +43,178 @@ GAF has been implemented in Zephyr with the following structure. Zephyr Generic Audio Framework +Bluetooth Audio Stack Status +============================ + +The following table shows the current status and support of the profiles in the +Bluetooth Audio Stack. + +.. table:: Bluetooth Audio Profile status + :widths: auto + + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | Module | Role | Version | Added in Release | Status | Remaining | + +========+===============================+=========+==================+=======================+==================================================+ + | VCP | Volume Renderer | 1.0 | 2.6 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Volume Controller | 1.0 | 2.6 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | MICP | Microphone Device | 1.0 | 2.7 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Microphone Controller | 1.0 | 2.7 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | CSIP | Set Member | 1.0.1 | 3.0 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Set Coordinator | 1.0.1 | 3.0 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | CCP | Call Control Server | 1.0 | 3.0 | - Feature complete | - API refactor | + | | | | | - Shell Module | - Sample Application | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Call Control Client | 1.0 | 3.0 | - Feature complete | - API refactor | + | | | | | - Shell Module | - Sample Application | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | MCP | Media Control Server | 1.0 | 3.0 | - Feature complete | - API refactor | + | | | | | - Shell Module | - Support for multiple instances and connections | + | | | | | - BSIM test | - Sample Application | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Media Control Client | 1.0 | 3.0 | - Feature complete | - API refactor | + | | | | | - Shell Module | - Sample Application | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | BAP | Unicast Server | 1.0.1 | 3.0 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Unicast Client | 1.0.1 | 3.0 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Source | 1.0.1 | 3.0 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Sink | 1.0.1 | 3.0 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Scan Delegator | 1.0.1 | 3.3 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Assistant | 1.0.1 | 3.3 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | CAP | Acceptor | 1.0 | 3.2 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Initiator | 1.0 | 3.3 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Commander | | | - Not Started | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | HAP | Hearing Aid | 1.0 | 3.1 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Hearing Aid Unicast Client | 1.0 | 3.1 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Hearing Aid Remote Controller | | | - WIP | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | TMAP | Call Gateway | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Call Terminal | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Unicast Media Sender | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Unicast Media Receiver | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Media Sender | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Media Receiver | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | PBP | Public Broadcast Source | | | - WIP :github:`60777` | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Public Broadcast Sink | | | - WIP :github:`60777` | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Public Broadcast Assistant | | | | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | GMAP | Unicast Game Gateway | | | - WIP :github:`57032` | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Unicast Game Terminal | | | - WIP :github:`57032` | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Game Sender | | | - WIP :github:`57032` | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Game Receiver | | | - WIP :github:`57032` | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + Using the Bluetooth Audio Stack =============================== From 0127d000a2871a2868067001ad55cfce40a4986e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Thu, 2 Nov 2023 08:43:26 +0100 Subject: [PATCH 0242/1049] usb: device: cdc_acm: Use ZLP to detect initial host read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent ECHO on Linux by arming IN endpoint with ZLP when interface is configured and making sure that actual payload is only sent after initialization timeout. The ZLP is not visible to host side applications because the applications are really accessing tty buffer and received ZLP does not modify tty buffer in any way. Signed-off-by: Tomasz Moń --- subsys/usb/device/class/Kconfig.cdc | 7 ++++++ subsys/usb/device/class/cdc_acm.c | 33 ++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/subsys/usb/device/class/Kconfig.cdc b/subsys/usb/device/class/Kconfig.cdc index 7c74802802387ed..59a72e25b6e3b68 100644 --- a/subsys/usb/device/class/Kconfig.cdc +++ b/subsys/usb/device/class/Kconfig.cdc @@ -37,6 +37,13 @@ config CDC_ACM_BULK_EP_MPS help CDC ACM class bulk endpoints size +config CDC_ACM_TX_DELAY_MS + int + default 100 + help + Time in milliseconds to wait before sending actual payload to host. + This is needed to prevent tty ECHO on Linux. + config CDC_ACM_IAD bool "Force using Interface Association Descriptor" default y diff --git a/subsys/usb/device/class/cdc_acm.c b/subsys/usb/device/class/cdc_acm.c index 1530813ab475888..fabe0d8e9d9d188 100644 --- a/subsys/usb/device/class/cdc_acm.c +++ b/subsys/usb/device/class/cdc_acm.c @@ -223,12 +223,27 @@ static void cdc_acm_write_cb(uint8_t ep, int size, void *priv) k_work_submit_to_queue(&USB_WORK_Q, &dev_data->cb_work); } - if (ring_buf_is_empty(dev_data->tx_ringbuf)) { + /* If size is 0, we want to schedule tx work even if ringbuf is empty to + * ensure that actual payload will not be sent before initialization + * timeout passes. + */ + if (ring_buf_is_empty(dev_data->tx_ringbuf) && size) { LOG_DBG("tx_ringbuf is empty"); return; } - k_work_schedule_for_queue(&USB_WORK_Q, &dev_data->tx_work, K_NO_WAIT); + /* If size is 0, it means that host started polling IN data because it + * has read the ZLP we armed when interface was configured. This ZLP is + * probably the best indication that host has started to read the data. + * Wait initialization timeout before sending actual payload to make it + * possible for application to disable ECHO. The echo is long known + * problem related to the fact that POSIX defaults to ECHO ON and thus + * every application that opens tty device (on Linux) will have ECHO + * enabled in the short window between open() and ioctl() that disables + * the echo (if application wishes to disable the echo). + */ + k_work_schedule_for_queue(&USB_WORK_Q, &dev_data->tx_work, size ? + K_NO_WAIT : K_MSEC(CONFIG_CDC_ACM_TX_DELAY_MS)); } static void tx_work_handler(struct k_work *work) @@ -247,6 +262,10 @@ static void tx_work_handler(struct k_work *work) return; } + if (!dev_data->configured) { + return; + } + len = ring_buf_get_claim(dev_data->tx_ringbuf, &data, CONFIG_USB_CDC_ACM_RINGBUF_SIZE); @@ -375,12 +394,10 @@ static void cdc_acm_do_cb(struct cdc_acm_dev_data_t *dev_data, dev_data->configured = true; cdc_acm_read_cb(cfg->endpoint[ACM_OUT_EP_IDX].ep_addr, 0, dev_data); - } - if (!dev_data->tx_ready) { - dev_data->tx_ready = true; - /* if wait tx irq, invoke callback */ - if (dev_data->cb != NULL && dev_data->tx_irq_ena) { - k_work_submit_to_queue(&USB_WORK_Q, &dev_data->cb_work); + /* Queue ZLP on IN endpoint so we know when host starts polling */ + if (!dev_data->tx_ready) { + usb_transfer(cfg->endpoint[ACM_IN_EP_IDX].ep_addr, NULL, 0, + USB_TRANS_WRITE, cdc_acm_write_cb, dev_data); } } break; From c275fa737ba4346ff69fbf95f3c4d190924d8b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Thu, 9 Nov 2023 08:33:17 +0100 Subject: [PATCH 0243/1049] doc: connectivity: usb: Document CDC ACM ECHO mitigation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explain the root cause behind garbage characters received in shell applications, what Zephyr does to mitigate the issue and what is expected from host userspace applications. Signed-off-by: Tomasz Moń --- doc/connectivity/usb/device/usb_device.rst | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/doc/connectivity/usb/device/usb_device.rst b/doc/connectivity/usb/device/usb_device.rst index c770c57bc797a45..3362f07840fe467 100644 --- a/doc/connectivity/usb/device/usb_device.rst +++ b/doc/connectivity/usb/device/usb_device.rst @@ -175,6 +175,37 @@ CDC ACM UART as backend for a subsystem or application: for example see :zephyr_file:`samples/subsys/shell/shell_module` * ``zephyr,uart-mcumgr`` used by :zephyr:code-sample:`smp-svr` sample +POSIX default tty ECHO mitigation +--------------------------------- + +POSIX systems, like Linux, default to enabling ECHO on tty devices. Host side +application can disable ECHO by calling ``open()`` on the tty device and issuing +``ioctl()`` (preferably via ``tcsetattr()``) to disable echo if it is not desired. +Unfortunately, there is an inherent race between the ``open()`` and ``ioctl()`` +where the ECHO is enabled and any characters received (even if host application +does not call ``read()``) will be echoed back. This issue is especially visible +when the CDC ACM port is used without any real UART on the other side because +there is no arbitrary delay due to baud rate. + +To mitigate the issue, Zephyr CDC ACM implementation arms IN endpoint with ZLP +after device is configured. When the host reads the ZLP, which is pretty much +the best indication that host application has opened the tty device, Zephyr will +force :kconfig:option:`CONFIG_CDC_ACM_TX_DELAY_MS` millisecond delay before real +payload is sent. This should allow sufficient time for first, and only first, +application that opens the tty device to disable ECHO if ECHO is not desired. +If ECHO is not desired at all from CDC ACM device it is best to set up udev rule +to disable ECHO as soon as device is connected. + +ECHO is particurarly unwanted when CDC ACM instance is used for Zephyr shell, +because the control characters to set color sent back to shell are interpreted +as (invalid) command and user will see garbage as a result. While minicom does +disable ECHO by default, on exit with reset it will restore the termios settings +to whatever was set on entry. Therefore, if minicom is the first application to +open the tty device, the exit with reset will enable ECHO back and thus set up +a problem for the next application (which cannot be mitigated at Zephyr side). +To prevent the issue it is recommended either to leave minicom without reset or +to disable ECHO before minicom is started. + DFU === From f12e1d75ed02de34afdb2d507d6f190568f59583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Wed, 8 Nov 2023 10:37:11 +0100 Subject: [PATCH 0244/1049] usb: device: cdc_acm: Always buffer poll out data if possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Queue characters in TX ring buffer regardless of interface state. This allows simple applications that print basic output to CDC ACM port to not care about connection or DTR state. Note that depending on actual application requirements it might be still wise to wait for DTR before trying to send data. Signed-off-by: Tomasz Moń --- subsys/usb/device/class/cdc_acm.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/subsys/usb/device/class/cdc_acm.c b/subsys/usb/device/class/cdc_acm.c index fabe0d8e9d9d188..fedccf5fdc02196 100644 --- a/subsys/usb/device/class/cdc_acm.c +++ b/subsys/usb/device/class/cdc_acm.c @@ -1029,11 +1029,6 @@ static void cdc_acm_poll_out(const struct device *dev, unsigned char c) { struct cdc_acm_dev_data_t * const dev_data = dev->data; - if (!dev_data->configured || dev_data->suspended) { - LOG_INF("USB device not ready, drop data"); - return; - } - dev_data->tx_ready = false; while (!ring_buf_put(dev_data->tx_ringbuf, &c, 1)) { From f0715fcbb3ebaacee805cb1431a6c8460f1e67b4 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 7 Nov 2023 14:23:15 +0100 Subject: [PATCH 0245/1049] tests: bsim: testlib: Fix compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes compilation error seen if CONFIG_BT_EATT is unset testlib/src/att_read.c:179:73: error: expected expression before ‘,’ token 179 | IF_ENABLED(CONFIG_BT_EATT, (.chan_opt = bearer)), | ^ Signed-off-by: Mariusz Skamra --- tests/bluetooth/common/testlib/src/att_read.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bluetooth/common/testlib/src/att_read.c b/tests/bluetooth/common/testlib/src/att_read.c index 5e4990f02b5667e..d7dd17ee07c21d8 100644 --- a/tests/bluetooth/common/testlib/src/att_read.c +++ b/tests/bluetooth/common/testlib/src/att_read.c @@ -149,7 +149,7 @@ int bt_testlib_att_read_by_handle_sync(struct net_buf_simple *result_data, uint1 .params = { .handle_count = 1, .single = {.handle = handle, .offset = offset}, - IF_ENABLED(CONFIG_BT_EATT, (.chan_opt = bearer)), + IF_ENABLED(CONFIG_BT_EATT, (.chan_opt = bearer,)) }}; if (bearer == BT_ATT_CHAN_OPT_ENHANCED_ONLY) { @@ -176,7 +176,7 @@ int bt_testlib_gatt_long_read(struct net_buf_simple *result_data, uint16_t *resu .params = { .handle_count = 1, .single = {.handle = handle, .offset = offset}, - IF_ENABLED(CONFIG_BT_EATT, (.chan_opt = bearer)), + IF_ENABLED(CONFIG_BT_EATT, (.chan_opt = bearer,)) }}; if (bearer == BT_ATT_CHAN_OPT_ENHANCED_ONLY) { From f434198a2bca29faac455a5df21bf7a845f071a5 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 3 Nov 2023 16:22:05 +0100 Subject: [PATCH 0246/1049] Bluetooth: att: Retry ATT request if security elevation is in progress If the conn security elevation is already in progress, retry the ATT request if failed due to security reasons. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/host/att.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index dd953115c5c3ffd..cb8c17983cb0d01 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -2519,9 +2519,13 @@ static uint8_t att_error_rsp(struct bt_att_chan *chan, struct net_buf *buf) } err = rsp->error; + #if defined(CONFIG_BT_ATT_RETRY_ON_SEC_ERR) + int ret; + /* Check if error can be handled by elevating security. */ - if (!att_change_security(chan->chan.chan.conn, err)) { + ret = att_change_security(chan->chan.chan.conn, err); + if (ret == 0 || ret == -EBUSY) { /* ATT timeout work is normally cancelled in att_handle_rsp. * However retrying is special case, so the timeout shall * be cancelled here. From f80b237e306a02aa4f7ba6beecc972cee9c28f70 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 3 Nov 2023 13:21:43 +0100 Subject: [PATCH 0247/1049] tests: Bluetooth: Add tests for ATT automatic security elevation This adds tests for automatic security elevation and retry on security errors. This includes two tests: 1. where the security is elevated by the central 2. the security is elevated by security request, so pairing is already in progress. Signed-off-by: Mariusz Skamra --- .../retry_on_sec_err/client/CMakeLists.txt | 22 ++ .../host/att/retry_on_sec_err/client/main.c | 195 ++++++++++++++++++ .../host/att/retry_on_sec_err/client/prj.conf | 12 ++ .../host/att/retry_on_sec_err/common_defs.h | 12 ++ .../retry_on_sec_err/server/CMakeLists.txt | 22 ++ .../host/att/retry_on_sec_err/server/main.c | 98 +++++++++ .../host/att/retry_on_sec_err/server/prj.conf | 13 ++ .../retry_on_sec_err/test_scripts/_compile.sh | 18 ++ .../att/retry_on_sec_err/test_scripts/_env.sh | 15 ++ .../retry_on_sec_err/test_scripts/run_test.sh | 27 +++ .../test_scripts/run_test_security_request.sh | 27 +++ .../host/att/retry_on_sec_err/test_utils.c | 21 ++ .../host/att/retry_on_sec_err/test_utils.h | 29 +++ tests/bsim/bluetooth/host/compile.sh | 2 + 14 files changed, 513 insertions(+) create mode 100644 tests/bsim/bluetooth/host/att/retry_on_sec_err/client/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c create mode 100644 tests/bsim/bluetooth/host/att/retry_on_sec_err/client/prj.conf create mode 100644 tests/bsim/bluetooth/host/att/retry_on_sec_err/common_defs.h create mode 100644 tests/bsim/bluetooth/host/att/retry_on_sec_err/server/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/att/retry_on_sec_err/server/main.c create mode 100644 tests/bsim/bluetooth/host/att/retry_on_sec_err/server/prj.conf create mode 100755 tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/_compile.sh create mode 100755 tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/_env.sh create mode 100755 tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/run_test.sh create mode 100755 tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/run_test_security_request.sh create mode 100644 tests/bsim/bluetooth/host/att/retry_on_sec_err/test_utils.c create mode 100644 tests/bsim/bluetooth/host/att/retry_on_sec_err/test_utils.h diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/CMakeLists.txt b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/CMakeLists.txt new file mode 100644 index 000000000000000..b244078e7610c19 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) +project(app) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) + +target_sources(app PRIVATE + ../test_utils.c + main.c +) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ +) + +target_link_libraries(app PRIVATE + testlib +) diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c new file mode 100644 index 000000000000000..2a3c005515c7b83 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c @@ -0,0 +1,195 @@ +/* Copyright (c) 2023 Codecoup + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../common_defs.h" +#include "../test_utils.h" + +#include "testlib/connect.h" +#include "testlib/scan.h" +#include "testlib/security.h" + +LOG_MODULE_REGISTER(client, LOG_LEVEL_DBG); + +DEFINE_FLAG(flag_attr_read_success); + +static uint8_t gatt_attr_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + __ASSERT_NO_MSG(!att_err); + + SET_FLAG(flag_attr_read_success); + + return BT_GATT_ITER_STOP; +} + +static void gatt_attr_read(struct bt_conn *conn) +{ + static struct bt_gatt_read_params params; + static struct bt_uuid_128 uuid; + int err; + + memset(¶ms, 0, sizeof(params)); + params.func = gatt_attr_read_cb; + params.by_uuid.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + params.by_uuid.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + memcpy(&uuid.uuid, TEST_CHRC_UUID, sizeof(uuid)); + params.by_uuid.uuid = &uuid.uuid; + + err = bt_gatt_read(conn, ¶ms); + __ASSERT_NO_MSG(!err); +} + +DEFINE_FLAG(flag_conn_encrypted); + +static void security_changed_cb(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err) +{ + if (err != BT_SECURITY_ERR_SUCCESS || level < BT_SECURITY_L2) { + return; + } + + SET_FLAG(flag_conn_encrypted); +} + +static struct bt_conn_cb conn_cb = { + .security_changed = security_changed_cb, +}; + +static void test_client(void) +{ + struct bt_conn *conn = NULL; + bt_addr_le_t scan_result; + int err; + + err = bt_enable(NULL); + __ASSERT_NO_MSG(!err); + + bt_conn_cb_register(&conn_cb); + + err = bt_testlib_scan_find_name(&scan_result, "d1"); + __ASSERT_NO_MSG(!err); + + err = bt_testlib_connect(&scan_result, &conn); + __ASSERT_NO_MSG(!err); + + /* Read characteristic value that requires encryption */ + gatt_attr_read(conn); + + /* Expect link encryption */ + WAIT_FOR_FLAG(flag_conn_encrypted); + + /* Wait for successful Read Response */ + WAIT_FOR_FLAG(flag_attr_read_success); + + err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + __ASSERT_NO_MSG(!err); + + bt_conn_unref(conn); + conn = NULL; + + PASS("PASS\n"); +} + +DEFINE_FLAG(flag_pairing_in_progress); + +static void auth_cancel_cb(struct bt_conn *conn) +{ + +} + +static void auth_pairing_confirm_cb(struct bt_conn *conn) +{ + SET_FLAG(flag_pairing_in_progress); +} + +static struct bt_conn_auth_cb auth_cb = { + .cancel = auth_cancel_cb, + .pairing_confirm = auth_pairing_confirm_cb, +}; + +static void test_client_security_request(void) +{ + struct bt_conn *conn = NULL; + bt_addr_le_t scan_result; + int err; + + err = bt_enable(NULL); + __ASSERT_NO_MSG(!err); + + bt_conn_cb_register(&conn_cb); + + err = bt_conn_auth_cb_register(&auth_cb); + __ASSERT_NO_MSG(!err); + + err = bt_testlib_scan_find_name(&scan_result, "d1"); + __ASSERT_NO_MSG(!err); + + err = bt_testlib_connect(&scan_result, &conn); + __ASSERT_NO_MSG(!err); + + /* Wait for peripheral to initaiate pairing */ + WAIT_FOR_FLAG(flag_pairing_in_progress); + + /* Read characteristic value that requires encryption */ + gatt_attr_read(conn); + + /* Accept pairing */ + err = bt_conn_auth_pairing_confirm(conn); + __ASSERT_NO_MSG(!err); + + /* Expect link encryption */ + WAIT_FOR_FLAG(flag_conn_encrypted); + + /* Wait for successful Read Response */ + WAIT_FOR_FLAG(flag_attr_read_success); + + err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + __ASSERT_NO_MSG(!err); + + bt_conn_unref(conn); + conn = NULL; + + PASS("PASS\n"); +} + +static const struct bst_test_instance client_tests[] = { + { + .test_id = "test_client", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_client, + }, + { + .test_id = "test_client_security_request", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_client_security_request, + }, + BSTEST_END_MARKER, +}; + +static struct bst_test_list *client_tests_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, client_tests); +}; + +bst_test_install_t test_installers[] = { + client_tests_install, + NULL +}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/prj.conf b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/prj.conf new file mode 100644 index 000000000000000..32e911d43968e29 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/prj.conf @@ -0,0 +1,12 @@ +CONFIG_ASSERT=y + +CONFIG_BT=y +CONFIG_BT_CENTRAL=y + +CONFIG_BT_SMP=y + +CONFIG_BT_GATT_CLIENT=y +CONFIG_BT_ATT_RETRY_ON_SEC_ERR=y + +CONFIG_LOG=y +CONFIG_BT_ATT_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/common_defs.h b/tests/bsim/bluetooth/host/att/retry_on_sec_err/common_defs.h new file mode 100644 index 000000000000000..7f9a091203be2c6 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/common_defs.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2023 Codecoup + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#define TEST_SERVICE_UUID \ + BT_UUID_DECLARE_128(0x1f, 0x5c, 0x31, 0x85, 0x05, 0xe8, 0x4d, 0x58, 0xb9, 0xf5, 0xae, \ + 0xf1, 0x7a, 0x88, 0xbe, 0x82) +#define TEST_CHRC_UUID \ + BT_UUID_DECLARE_128(0x68, 0xb4, 0x35, 0x19, 0x01, 0x65, 0x4d, 0xdc, 0xb9, 0xf3, 0x91, \ + 0x0f, 0xf3, 0x18, 0x46, 0x7b) diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/CMakeLists.txt b/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/CMakeLists.txt new file mode 100644 index 000000000000000..b244078e7610c19 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) +project(app) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) + +target_sources(app PRIVATE + ../test_utils.c + main.c +) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ +) + +target_link_libraries(app PRIVATE + testlib +) diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/main.c b/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/main.c new file mode 100644 index 000000000000000..b07f0034aab0fa0 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/main.c @@ -0,0 +1,98 @@ +/* Copyright (c) 2023 Codecoup + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +#include "testlib/adv.h" +#include "testlib/security.h" + +#include "../common_defs.h" +#include "../test_utils.h" + +LOG_MODULE_REGISTER(server, LOG_LEVEL_DBG); + +static ssize_t read_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t buf_len, uint16_t offset) +{ + return 0; +} + +BT_GATT_SERVICE_DEFINE(test_svc, + BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID), + BT_GATT_CHARACTERISTIC(TEST_CHRC_UUID, BT_GATT_CHRC_READ, + BT_GATT_PERM_READ_ENCRYPT, read_chrc, NULL, NULL)); + +static void test_common(struct bt_conn **conn) +{ + int err; + + err = bt_enable(NULL); + __ASSERT_NO_MSG(!err); + + __ASSERT_NO_MSG(get_device_nbr() == 1); + err = bt_set_name("d1"); + __ASSERT_NO_MSG(!err); + + err = bt_testlib_adv_conn(conn, BT_ID_DEFAULT, + (BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_FORCE_NAME_IN_AD)); + __ASSERT_NO_MSG(!err); +} + +static void test_server(void) +{ + test_common(NULL); + + PASS("PASS\n"); +} + +static void test_server_security_request(void) +{ + struct bt_conn *conn = NULL; + int err; + + test_common(&conn); + + err = bt_testlib_secure(conn, BT_SECURITY_L2); + __ASSERT(!err, "err %d", err); + + PASS("PASS\n"); +} + +static const struct bst_test_instance server_tests[] = { + { + .test_id = "test_server", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_server, + }, + { + .test_id = "test_server_security_request", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_server_security_request, + }, + BSTEST_END_MARKER, +}; + +static struct bst_test_list *server_tests_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, server_tests); +}; + +bst_test_install_t test_installers[] = { + server_tests_install, + NULL +}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/prj.conf b/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/prj.conf new file mode 100644 index 000000000000000..1b3a186979edd0b --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/prj.conf @@ -0,0 +1,13 @@ +CONFIG_ASSERT=y + +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y + +CONFIG_BT_DEVICE_NAME_DYNAMIC=y + +CONFIG_BT_SMP=y + +CONFIG_BT_EXT_ADV=y + +CONFIG_LOG=y +CONFIG_BT_ATT_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/_compile.sh b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/_compile.sh new file mode 100755 index 000000000000000..88a5454b6749a0b --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/_compile.sh @@ -0,0 +1,18 @@ +#!/bin/env bash +# Copyright 2023 Codecoup +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +source "${bash_source_dir}/_env.sh" + +pushd client +west build -b nrf52_bsim && \ + cp -v build/zephyr/zephyr.exe "${test_exe_d0}" +popd + +pushd server +west build -b nrf52_bsim && \ + cp -v build/zephyr/zephyr.exe "${test_exe_d1}" +popd diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/_env.sh b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/_env.sh new file mode 100755 index 000000000000000..66b074ca3d80d6f --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/_env.sh @@ -0,0 +1,15 @@ +#!/bin/env bash +# Copyright 2023 Codecoup +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}" + +test_name="$(basename "$(realpath "$bash_source_dir/..")")" +bsim_bin="${BSIM_OUT_PATH}/bin" +verbosity_level=2 +BOARD="${BOARD:-nrf52_bsim}" +test_exe_d0="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_att_${test_name}_client_prj_conf" +test_exe_d1="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_att_${test_name}_server_prj_conf" diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/run_test.sh b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/run_test.sh new file mode 100755 index 000000000000000..8ea8f38cddc323e --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/run_test.sh @@ -0,0 +1,27 @@ +#!/bin/env bash +# Copyright 2023 Codecoup +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +simulation_id=$(basename "$0") +source "${bash_source_dir}/_env.sh" +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +printf "\n\n===== ATT retry on security error (auto security elevation) ======\n\n" + +Execute "$test_exe_d0" \ + -v=${verbosity_level} -s="${simulation_id}" -d=0 -testid=test_client \ + -RealEncryption=1 + +Execute "$test_exe_d1" \ + -v=${verbosity_level} -s="${simulation_id}" -d=1 -testid=test_server \ + -RealEncryption=1 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s="${simulation_id}" \ + -D=2 -sim_length=60e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/run_test_security_request.sh b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/run_test_security_request.sh new file mode 100755 index 000000000000000..8d7c86c4d047167 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_scripts/run_test_security_request.sh @@ -0,0 +1,27 @@ +#!/bin/env bash +# Copyright 2023 Codecoup +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +simulation_id=$(basename "$0") +source "${bash_source_dir}/_env.sh" +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +printf "\n\n==== ATT retry on security error (peripheral security request) ====\n\n" + +Execute "$test_exe_d0" \ + -v=${verbosity_level} -s="${simulation_id}" -d=0 -testid=test_client_security_request \ + -RealEncryption=1 + +Execute "$test_exe_d1" \ + -v=${verbosity_level} -s="${simulation_id}" -d=1 -testid=test_server_security_request \ + -RealEncryption=1 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s="${simulation_id}" \ + -D=2 -sim_length=60e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_utils.c b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_utils.c new file mode 100644 index 000000000000000..cacb0fa9e539dac --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_utils.c @@ -0,0 +1,21 @@ +/* Copyright (c) 2023 Codecoup + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_utils.h" + +void test_init(void) +{ + bst_result = In_progress; + bst_ticker_set_next_tick_absolute(SIMULATED_TEST_TIMEOUT); +} + +void test_tick(bs_time_t HW_device_time) +{ + bs_trace_debug_time(0, "Simulation ends now.\n"); + if (bst_result == In_progress) { + bst_result = Failed; + bs_trace_error("Test did not pass before simulation ended. Consider increasing " + "simulation length.\n"); + } +} diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_utils.h b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_utils.h new file mode 100644 index 000000000000000..0d5113f00f60c32 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/test_utils.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2023 Codecoup + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define DECLARE_FLAG(flag) extern atomic_t flag +#define DEFINE_FLAG(flag) atomic_t flag = (atomic_t) false +#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true) +#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false) +#define WAIT_FOR_FLAG(flag) \ + while (!(bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } + +#define PASS(...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(1, __VA_ARGS__); \ + } while (0) + +#define BS_SECONDS(dur_sec) ((bs_time_t)dur_sec * 1000000) +#define SIMULATED_TEST_TIMEOUT BS_SECONDS(60) + +extern enum bst_result_t bst_result; + +void test_init(void); +void test_tick(bs_time_t HW_device_time); diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 7a9757e3e4aea97..9840083305c2739 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -35,6 +35,8 @@ app=tests/bsim/bluetooth/host/att/eatt_notif conf_file=prj.conf compile app=tests/bsim/bluetooth/host/att/mtu_update compile app=tests/bsim/bluetooth/host/att/read_fill_buf/client compile app=tests/bsim/bluetooth/host/att/read_fill_buf/server compile +app=tests/bsim/bluetooth/host/att/retry_on_sec_err/client compile +app=tests/bsim/bluetooth/host/att/retry_on_sec_err/server compile app=tests/bsim/bluetooth/host/att/sequential/dut compile app=tests/bsim/bluetooth/host/att/sequential/tester compile app=tests/bsim/bluetooth/host/att/long_read compile From 9439c816e95b9453389981c76d293a628e18c7ce Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 3 Nov 2023 16:31:25 +0000 Subject: [PATCH 0248/1049] input: split npcx generic keyboard code into input_kbd_matrix.c Move all the generic code from the Nuvoton NPCX keyboard scanning driver into input_kbd_matrix.c. While doing that convert few configs into devicetree properties and tweak few other things to enable the generic code to support multiple instances. This is limited to 8 rows for now, and that's fine for all the current in-tree drivers, the limit could be removed down the road but this should be fine for now, added few generic build checks to make sure a driver does not go over the limit, as well and some more implementation specific checks. Signed-off-by: Fabio Baltieri --- drivers/input/Kconfig.npcx | 20 +- drivers/input/input_kbd_matrix.c | 281 +++++++++++++++++- drivers/input/input_kbd_matrix.h | 90 +++++- drivers/input/input_npcx_kbd.c | 343 +++------------------- dts/bindings/input/kbd-matrix-common.yaml | 52 ++++ dts/bindings/input/nuvoton,npcx-kbd.yaml | 32 -- 6 files changed, 454 insertions(+), 364 deletions(-) diff --git a/drivers/input/Kconfig.npcx b/drivers/input/Kconfig.npcx index ad738ac6563e5ea..ef380b0ca4be478 100644 --- a/drivers/input/Kconfig.npcx +++ b/drivers/input/Kconfig.npcx @@ -3,7 +3,7 @@ # Copyright (c) 2022 Nuvoton Technology Corporation. # SPDX-License-Identifier: Apache-2.0 -menuconfig INPUT_NPCX_KBD +config INPUT_NPCX_KBD bool "Nuvoton NPCX embedded controller (EC) keyboard scan driver" default y depends on DT_HAS_NUVOTON_NPCX_KBD_ENABLED @@ -13,26 +13,10 @@ menuconfig INPUT_NPCX_KBD This option enables the keyboard scan driver for NPCX family of processors. -if INPUT_NPCX_KBD - -config INPUT_NPCX_KBD_POLL_PERIOD_MS - int "Keyscan NPCX Poll Period" - default 5 - help - Defines the poll period in msecs between between matrix scans. - config INPUT_NPCX_KBD_KSO_HIGH_DRIVE bool "Select quasi-bidirectional buffers for KSO pins" default y + depends on INPUT_NPCX_KBD help Select quasi-bidirectional buffers for KSO pins to reduce the low-to-high transition time. - -config INPUT_NPCX_KBD_POLL_COL_OUTPUT_SETTLE_TIME_US - int "keyboard matrix poll column output settle time" - default 50 - help - Delay (us) between setting column output and waiting for it - to settle - -endif # INPUT_NPCX_KBD diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 0ac6d4b177775e8..d6da7764f739e58 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -1,23 +1,298 @@ /* + * Copyright 2019 Intel Corporation + * Copyright 2022 Nuvoton Technology Corporation. * Copyright 2023 Google LLC * * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include +#include +#include + +#define LOG_LEVEL CONFIG_INPUT_LOG_LEVEL +LOG_MODULE_REGISTER(input_kbd_matrix); #include "input_kbd_matrix.h" -int input_kbd_matrix_common_init(const struct device *dev) +#define INPUT_KBD_MATRIX_ROW_MASK UINT8_MAX + +void input_kbd_matrix_poll_start(const struct device *dev) +{ + struct input_kbd_matrix_common_data *data = dev->data; + + k_sem_give(&data->poll_lock); +} + +static bool input_kbd_matrix_ghosting(const struct device *dev) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + const uint8_t *state = cfg->matrix_new_state; + + /* + * Matrix keyboard designs are suceptible to ghosting. + * An extra key appears to be pressed when 3 keys belonging to the same + * block are pressed. For example, in the following block: + * + * . . w . q . + * . . . . . . + * . . . . . . + * . . m . a . + * + * the key m would look as pressed if the user pressed keys w, q and a + * simultaneously. A block can also be formed, with not adjacent + * columns. + */ + for (int c = 0; c < cfg->col_size; c++) { + if (!state[c]) { + continue; + } + + for (int c_next = c + 1; c_next < cfg->col_size; c_next++) { + /* + * We AND the columns to detect a "block". This is an + * indication of ghosting, due to current flowing from + * a key which was never pressed. In our case, current + * flowing is a bit set to 1 as we flipped the bits + * when the matrix was scanned. Now we OR the colums + * using z&(z-1) which is non-zero only if z has more + * than one bit set. + */ + uint8_t common_row_bits = state[c] & state[c_next]; + + if (common_row_bits & (common_row_bits - 1)) { + return true; + } + } + } + + return false; +} + +static bool input_kbd_matrix_scan(const struct device *dev) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + const struct input_kbd_matrix_api *api = &cfg->api; + int row; + uint8_t key_event = 0U; + + for (int col = 0; col < cfg->col_size; col++) { + api->drive_column(dev, col); + + /* Allow the matrix to stabilize before reading it */ + k_busy_wait(cfg->settle_time_us); + + row = api->read_row(dev) & INPUT_KBD_MATRIX_ROW_MASK; + cfg->matrix_new_state[col] = row; + key_event |= row; + } + + api->drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); + + return key_event != 0U; +} + +static void input_kbd_matrix_update_state(const struct device *dev) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + struct input_kbd_matrix_common_data *data = dev->data; + uint8_t *matrix_new_state = cfg->matrix_new_state; + uint32_t cycles_now = k_cycle_get_32(); + uint8_t row_changed; + uint8_t deb_col; + + data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now; + + /* + * The intent of this loop is to gather information related to key + * changes. + */ + for (int c = 0; c < cfg->col_size; c++) { + /* Check if there was an update from the previous scan */ + row_changed = matrix_new_state[c] ^ cfg->matrix_previous_state[c]; + + if (!row_changed) { + continue; + } + + for (int r = 0; r < cfg->row_size; r++) { + uint8_t cyc_idx = c * cfg->row_size + r; + + /* + * Index all they keys that changed for each row in + * order to debounce each key in terms of it + */ + if (row_changed & BIT(r)) { + cfg->scan_cycle_idx[cyc_idx] = data->scan_cycles_idx; + } + } + + cfg->matrix_unstable_state[c] |= row_changed; + cfg->matrix_previous_state[c] = matrix_new_state[c]; + } + + for (int c = 0; c < cfg->col_size; c++) { + deb_col = cfg->matrix_unstable_state[c]; + + if (!deb_col) { + continue; + } + + /* Debouncing for each row key occurs here */ + for (int r = 0; r < cfg->row_size; r++) { + uint8_t mask = BIT(r); + uint8_t row_bit = matrix_new_state[c] & mask; + + /* Continue if we already debounce a key */ + if (!(deb_col & mask)) { + continue; + } + + uint8_t cyc_idx = c * cfg->row_size + r; + uint8_t scan_cyc_idx = cfg->scan_cycle_idx[cyc_idx]; + uint8_t scan_clk_cycle = data->scan_clk_cycle[scan_cyc_idx]; + + /* Convert the clock cycle differences to usec */ + uint32_t debt = k_cyc_to_us_floor32(cycles_now - scan_clk_cycle); + + /* Does the key requires more time to be debounced? */ + if (debt < (row_bit ? cfg->debounce_down_ms : cfg->debounce_up_ms)) { + /* Need more time to debounce */ + continue; + } + + cfg->matrix_unstable_state[c] &= ~row_bit; + + /* Check if there was a change in the stable state */ + if ((cfg->matrix_stable_state[c] & mask) == row_bit) { + /* Key state did not change */ + continue; + } + + /* + * The current row has been debounced, therefore update + * the stable state. Then, proceed to notify the + * application about the keys pressed. + */ + cfg->matrix_stable_state[c] ^= mask; + + input_report_abs(dev, INPUT_ABS_X, c, false, K_FOREVER); + input_report_abs(dev, INPUT_ABS_Y, r, false, K_FOREVER); + input_report_key(dev, INPUT_BTN_TOUCH, row_bit, true, K_FOREVER); + } + } +} + +static bool input_kbd_matrix_check_key_events(const struct device *dev) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + struct input_kbd_matrix_common_data *data = dev->data; + bool key_pressed; + + if (++data->scan_cycles_idx >= INPUT_KBD_MATRIX_SCAN_OCURRENCES) { + data->scan_cycles_idx = 0U; + } + + /* Scan the matrix */ + key_pressed = input_kbd_matrix_scan(dev); + + for (int c = 0; c < cfg->col_size; c++) { + LOG_DBG("U%x, P%x, N%x", + cfg->matrix_unstable_state[c], + cfg->matrix_previous_state[c], + cfg->matrix_new_state[c]); + } + + /* Abort if ghosting is detected */ + if (cfg->ghostkey_check && input_kbd_matrix_ghosting(dev)) { + return key_pressed; + } + + input_kbd_matrix_update_state(dev); + + return key_pressed; +} + +static void input_kbd_matrix_poll(const struct device *dev) { + const struct input_kbd_matrix_common_config *cfg = dev->config; + k_timepoint_t poll_time_end = sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); + uint32_t current_cycles; + uint32_t cycles_diff; + uint32_t wait_period_us; + + while (true) { + uint32_t start_period_cycles = k_cycle_get_32(); + + if (input_kbd_matrix_check_key_events(dev)) { + poll_time_end = sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); + } else if (sys_timepoint_expired(poll_time_end)) { + break; + } + + /* + * Subtract the time invested from the sleep period in order to + * compensate for the time invested in debouncing a key + */ + current_cycles = k_cycle_get_32(); + cycles_diff = current_cycles - start_period_cycles; + wait_period_us = cfg->poll_period_us - k_cyc_to_us_floor32(cycles_diff); + + /* Wait for at least 1ms */ + if (wait_period_us < USEC_PER_MSEC) { + wait_period_us = USEC_PER_MSEC; + } + + /* + * Wait period results in a larger number when current cycles + * counter wrap. In this case, the whole poll period is used + */ + if (wait_period_us > cfg->poll_period_us) { + LOG_DBG("wait_period_us: %u", wait_period_us); + + wait_period_us = cfg->poll_period_us; + } + + /* Allow other threads to run while we sleep */ + k_usleep(wait_period_us); + } +} + +static void input_kbd_matrix_polling_thread(void *arg1, void *unused2, void *unused3) +{ + const struct device *dev = arg1; const struct input_kbd_matrix_common_config *cfg = dev->config; const struct input_kbd_matrix_api *api = &cfg->api; - struct input_kbd_matrix_common_data *const data = dev->data; + struct input_kbd_matrix_common_data *data = dev->data; + + ARG_UNUSED(unused2); + ARG_UNUSED(unused3); + + while (true) { + api->drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL); + api->set_detect_mode(dev, true); + + k_sem_take(&data->poll_lock, K_FOREVER); + LOG_DBG("Start KB scan"); + + /* Disable interrupt of KSI pins and start polling */ + api->set_detect_mode(dev, false); + + input_kbd_matrix_poll(dev); + } +} + +int input_kbd_matrix_common_init(const struct device *dev) +{ + struct input_kbd_matrix_common_data *data = dev->data; + + k_sem_init(&data->poll_lock, 0, 1); k_thread_create(&data->thread, data->thread_stack, CONFIG_INPUT_KBD_MATRIX_THREAD_STACK_SIZE, - api->polling_thread, (void *)dev, NULL, NULL, + input_kbd_matrix_polling_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(4), 0, K_NO_WAIT); k_thread_name_set(&data->thread, dev->name); diff --git a/drivers/input/input_kbd_matrix.h b/drivers/input/input_kbd_matrix.h index b70e0d5c4d10ba3..ec286ab5520294d 100644 --- a/drivers/input/input_kbd_matrix.h +++ b/drivers/input/input_kbd_matrix.h @@ -6,13 +6,26 @@ #include #include +#include +#include #include +/** Special drive_column argument for not driving any column */ +#define INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE -1 + +/** Special drive_column argument for driving all the columns */ +#define INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL -2 + +/** Number of tracked scan cycles */ +#define INPUT_KBD_MATRIX_SCAN_OCURRENCES 30U + /** * @brief Keyboard matrix internal APIs. */ struct input_kbd_matrix_api { - k_thread_entry_t polling_thread; + void (*drive_column)(const struct device *dev, int col); + int (*read_row)(const struct device *dev); + void (*set_detect_mode)(const struct device *dev, bool enabled); }; /** @@ -22,8 +35,53 @@ struct input_kbd_matrix_api { */ struct input_kbd_matrix_common_config { struct input_kbd_matrix_api api; + uint8_t row_size; + uint8_t col_size; + uint32_t poll_period_us; + uint32_t poll_timeout_ms; + uint32_t debounce_down_ms; + uint32_t debounce_up_ms; + uint32_t settle_time_us; + bool ghostkey_check; + + /* extra data pointers */ + uint8_t *matrix_stable_state; + uint8_t *matrix_unstable_state; + uint8_t *matrix_previous_state; + uint8_t *matrix_new_state; + uint8_t *scan_cycle_idx; }; +#define INPUT_KBD_MATRIX_DATA_NAME(node_id, name) \ + _CONCAT(__input_kbd_matrix_, \ + _CONCAT(name, DEVICE_DT_NAME_GET(node_id))) + +/** + * @brief Defines the common keyboard matrix support data from devicetree. + */ +#define INPUT_KBD_MATRIX_DT_DEFINE(node_id) \ + BUILD_ASSERT(IN_RANGE(DT_PROP(node_id, row_size), 1, 8), "invalid row-size"); \ + BUILD_ASSERT(IN_RANGE(DT_PROP(node_id, col_size), 1, UINT8_MAX), "invalid col-size"); \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ + node_id, stable_state)[DT_PROP(node_id, col_size)]; \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ + node_id, unstable_state)[DT_PROP(node_id, col_size)]; \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ + node_id, previous_state)[DT_PROP(node_id, col_size)]; \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ + node_id, new_state)[DT_PROP(node_id, col_size)]; \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ + node_id, scan_cycle_idx)[DT_PROP(node_id, row_size) * \ + DT_PROP(node_id, col_size)]; + +/** + * @brief Defines the common keyboard matrix support data from devicetree instance. + * + * @param inst Instance. + */ +#define INPUT_KBD_MATRIX_DT_INST_DEFINE(inst) \ + INPUT_KBD_MATRIX_DT_DEFINE(DT_DRV_INST(inst)) + /** * @brief Initialize common keyboard matrix config from devicetree. * @@ -32,6 +90,20 @@ struct input_kbd_matrix_common_config { #define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(node_id, _api) \ { \ .api = _api, \ + .row_size = DT_PROP(node_id, row_size), \ + .col_size = DT_PROP(node_id, col_size), \ + .poll_period_us = DT_PROP(node_id, poll_period_ms) * USEC_PER_MSEC, \ + .poll_timeout_ms = DT_PROP(node_id, poll_timeout_ms), \ + .debounce_down_ms = DT_PROP(node_id, debounce_down_ms), \ + .debounce_up_ms = DT_PROP(node_id, debounce_up_ms), \ + .settle_time_us = DT_PROP(node_id, settle_time_us), \ + .ghostkey_check = !DT_PROP(node_id, no_ghostkey_check), \ + \ + .matrix_stable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state), \ + .matrix_unstable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state), \ + .matrix_previous_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state), \ + .matrix_new_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state), \ + .scan_cycle_idx = INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx), \ } /** @@ -49,6 +121,12 @@ struct input_kbd_matrix_common_config { * This structure **must** be placed first in the driver's data structure. */ struct input_kbd_matrix_common_data { + /* Track previous cycles, used for debouncing. */ + uint8_t scan_clk_cycle[INPUT_KBD_MATRIX_SCAN_OCURRENCES]; + uint8_t scan_cycles_idx; + + struct k_sem poll_lock; + struct k_thread thread; K_KERNEL_STACK_MEMBER(thread_stack, @@ -67,6 +145,16 @@ struct input_kbd_matrix_common_data { BUILD_ASSERT(offsetof(data, common) == 0, \ "struct input_kbd_matrix_common_data must be placed first") +/** + * @brief Start scanning the keyboard matrix + * + * Starts the keyboard matrix scanning cycle, this should be called in reaction + * of a press event, after the device has been put in detect mode. + * + * @param dev Keyboard matrix device instance. + */ +void input_kbd_matrix_poll_start(const struct device *dev); + /** * @brief Common function to initialize a keyboard matrix device at init time. * diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index 2b3284e6d9c241a..65ef7747875b724 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -12,24 +12,16 @@ #include #include -#include #include #include +#include +#include #include #define LOG_LEVEL CONFIG_INPUT_LOG_LEVEL LOG_MODULE_REGISTER(input_npcx_kbd); -#define KEYBOARD_COLUMN_DRIVE_ALL -2 -#define KEYBOARD_COLUMN_DRIVE_NONE -1 - -/* Number of tracked scan times */ -#define SCAN_OCURRENCES 30U - -#define KSCAN_ROW_SIZE DT_INST_PROP(0, row_size) -#define KSCAN_COL_SIZE DT_INST_PROP(0, col_size) - -#define HAS_GHOSTING_ENABLED !DT_INST_PROP(0, no_ghostkey_check) +#define ROW_SIZE DT_INST_PROP(0, row_size) /* Driver config */ struct input_npcx_kbd_config { @@ -44,31 +36,13 @@ struct input_npcx_kbd_config { int irq; /* Size of keyboard inputs-wui mapping array */ int wui_size; - uint8_t row_size; - uint8_t col_size; - uint32_t deb_time_press; - uint32_t deb_time_rel; /* Mapping table between keyboard inputs and wui */ struct npcx_wui wui_maps[]; }; struct input_npcx_kbd_data { struct input_kbd_matrix_common_data common; - int64_t poll_timeout_us; - uint32_t poll_period_us; - uint8_t matrix_stable_state[KSCAN_COL_SIZE]; - uint8_t matrix_unstable_state[KSCAN_COL_SIZE]; - uint8_t matrix_previous_state[KSCAN_COL_SIZE]; - uint8_t matrix_new_state[KSCAN_COL_SIZE]; - /* Index in to the scan_clock_cycle to indicate start of debouncing */ - uint8_t scan_cycle_idx[KSCAN_COL_SIZE * KSCAN_ROW_SIZE]; - struct miwu_callback ksi_callback[KSCAN_ROW_SIZE]; - /* Track previous "elapsed clock cycles" per matrix scan. This - * is used to calculate the debouncing time for every key - */ - uint8_t scan_clk_cycle[SCAN_OCURRENCES]; - struct k_sem poll_lock; - uint8_t scan_cycles_idx; + struct miwu_callback ksi_callback[ROW_SIZE]; }; INPUT_KBD_STRUCT_CHECK(struct input_npcx_kbd_config, struct input_npcx_kbd_data); @@ -77,40 +51,39 @@ INPUT_KBD_STRUCT_CHECK(struct input_npcx_kbd_config, struct input_npcx_kbd_data) static void input_npcx_kbd_ksi_isr(const struct device *dev, struct npcx_wui *wui) { ARG_UNUSED(wui); - struct input_npcx_kbd_data *const data = dev->data; - k_sem_give(&data->poll_lock); + input_kbd_matrix_poll_start(dev); } -static int input_npcx_kbd_resume_detection(const struct device *dev, bool resume) +static void input_npcx_kbd_set_detect_mode(const struct device *dev, bool enabled) { const struct input_npcx_kbd_config *const config = dev->config; - if (resume) { + if (enabled) { irq_enable(config->irq); } else { irq_disable(config->irq); } - - return 0; } -static int input_npcx_kbd_drive_column(const struct device *dev, int col) +static void input_npcx_kbd_drive_column(const struct device *dev, int col) { const struct input_npcx_kbd_config *config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; struct kbs_reg *const inst = config->base; uint32_t mask; - if (col >= config->col_size) { - return -EINVAL; + if (col >= common->col_size) { + LOG_ERR("invalid column: %d", col); + return; } - if (col == KEYBOARD_COLUMN_DRIVE_NONE) { + if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) { /* Drive all lines to high: key detection is disabled */ mask = ~0; - } else if (col == KEYBOARD_COLUMN_DRIVE_ALL) { + } else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) { /* Drive all lines to low for detection any key press */ - mask = ~(BIT(config->col_size) - 1); + mask = ~BIT_MASK(common->col_size); } else { /* * Drive one line to low for determining which key's state @@ -123,275 +96,23 @@ static int input_npcx_kbd_drive_column(const struct device *dev, int col) inst->KBSOUT0 = (mask & 0xFFFF); inst->KBSOUT1 = ((mask >> 16) & 0x03); - - return 0; } static int input_npcx_kbd_read_row(const struct device *dev) { const struct input_npcx_kbd_config *config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; struct kbs_reg *const inst = config->base; int val; val = inst->KBSIN; /* 1 means key pressed, otherwise means key released. */ - val = (~val & (BIT(config->row_size) - 1)); + val = ~val & BIT_MASK(common->row_size); return val; } -static bool is_matrix_ghosting(const struct device *dev, const uint8_t *state) -{ - const struct input_npcx_kbd_config *const config = dev->config; - - /* - * Matrix keyboard designs are suceptible to ghosting. - * An extra key appears to be pressed when 3 keys belonging to the same - * block are pressed. For example, in the following block: - * - * . . w . q . - * . . . . . . - * . . . . . . - * . . m . a . - * - * the key m would look as pressed if the user pressed keys w, q and a - * simultaneously. A block can also be formed, with not adjacent - * columns. - */ - for (int c = 0; c < config->col_size; c++) { - if (!state[c]) { - continue; - } - - for (int c_next = c + 1; c_next < config->col_size; c_next++) { - /* - * We AND the columns to detect a "block". This is an - * indication of ghosting, due to current flowing from - * a key which was never pressed. In our case, current - * flowing is a bit set to 1 as we flipped the bits - * when the matrix was scanned. Now we OR the colums - * using z&(z-1) which is non-zero only if z has more - * than one bit set. - */ - uint8_t common_row_bits = state[c] & state[c_next]; - - if (common_row_bits & (common_row_bits - 1)) { - return true; - } - } - } - - return false; -} - -static bool read_keyboard_matrix(const struct device *dev, uint8_t *new_state) -{ - const struct input_npcx_kbd_config *const config = dev->config; - int row; - uint8_t key_event = 0U; - - for (int col = 0; col < config->col_size; col++) { - input_npcx_kbd_drive_column(dev, col); - - /* Allow the matrix to stabilize before reading it */ - k_busy_wait(CONFIG_INPUT_NPCX_KBD_POLL_COL_OUTPUT_SETTLE_TIME_US); - - row = input_npcx_kbd_read_row(dev); - new_state[col] = row & 0xFF; - key_event |= row; - } - - input_npcx_kbd_drive_column(dev, KEYBOARD_COLUMN_DRIVE_NONE); - - return key_event != 0U; -} - -static void update_matrix_state(const struct device *dev, uint8_t *matrix_new_state) -{ - const struct input_npcx_kbd_config *const config = dev->config; - struct input_npcx_kbd_data *const data = dev->data; - uint32_t cycles_now = k_cycle_get_32(); - uint8_t row_changed = 0U; - uint8_t deb_col; - - data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now; - - /* - * The intent of this loop is to gather information related to key - * changes. - */ - for (int c = 0; c < config->col_size; c++) { - /* Check if there was an update from the previous scan */ - row_changed = matrix_new_state[c] ^ data->matrix_previous_state[c]; - - if (!row_changed) { - continue; - } - - for (int r = 0; r < config->row_size; r++) { - uint8_t cyc_idx = c * config->row_size + r; - - /* - * Index all they keys that changed for each row in - * order to debounce each key in terms of it - */ - if (row_changed & BIT(r)) { - data->scan_cycle_idx[cyc_idx] = data->scan_cycles_idx; - } - } - - data->matrix_unstable_state[c] |= row_changed; - data->matrix_previous_state[c] = matrix_new_state[c]; - } - - for (int c = 0; c < config->col_size; c++) { - deb_col = data->matrix_unstable_state[c]; - - if (!deb_col) { - continue; - } - - /* Debouncing for each row key occurs here */ - for (int r = 0; r < config->row_size; r++) { - uint8_t mask = BIT(r); - uint8_t row_bit = matrix_new_state[c] & mask; - - /* Continue if we already debounce a key */ - if (!(deb_col & mask)) { - continue; - } - - uint8_t cyc_idx = c * config->row_size + r; - /* Convert the clock cycle differences to usec */ - uint32_t debt = k_cyc_to_us_floor32( - cycles_now - data->scan_clk_cycle[data->scan_cycle_idx[cyc_idx]]); - - /* Does the key requires more time to be debounced? */ - if (debt < (row_bit ? config->deb_time_press : config->deb_time_rel)) { - /* Need more time to debounce */ - continue; - } - - data->matrix_unstable_state[c] &= ~row_bit; - - /* Check if there was a change in the stable state */ - if ((data->matrix_stable_state[c] & mask) == row_bit) { - /* Key state did not change */ - continue; - } - - /* - * The current row has been debounced, therefore update - * the stable state. Then, proceed to notify the - * application about the keys pressed. - */ - data->matrix_stable_state[c] ^= mask; - - input_report_abs(dev, INPUT_ABS_X, c, false, K_FOREVER); - input_report_abs(dev, INPUT_ABS_Y, r, false, K_FOREVER); - input_report_key(dev, INPUT_BTN_TOUCH, row_bit, true, K_FOREVER); - } - } -} - -static bool check_key_events(const struct device *dev) -{ - const struct input_npcx_kbd_config *const config = dev->config; - struct input_npcx_kbd_data *const data = dev->data; - uint8_t *matrix_new_state = data->matrix_new_state; - bool key_pressed = false; - - if (++data->scan_cycles_idx >= SCAN_OCURRENCES) { - data->scan_cycles_idx = 0U; - } - - /* Scan the matrix */ - key_pressed = read_keyboard_matrix(dev, matrix_new_state); - - for (int c = 0; c < config->col_size; c++) { - LOG_DBG("U%x, P%x, N%x", data->matrix_unstable_state[c], - data->matrix_previous_state[c], matrix_new_state[c]); - } - - /* Abort if ghosting is detected */ - if (HAS_GHOSTING_ENABLED && is_matrix_ghosting(dev, matrix_new_state)) { - return key_pressed; - } - - update_matrix_state(dev, matrix_new_state); - - return key_pressed; -} - -static void kbd_matrix_poll(const struct device *dev) -{ - struct input_npcx_kbd_data *const data = dev->data; - k_timepoint_t poll_time_end = sys_timepoint_calc(K_USEC(data->poll_timeout_us)); - uint32_t current_cycles; - uint32_t cycles_diff; - uint32_t wait_period; - - while (true) { - uint32_t start_period_cycles = k_cycle_get_32(); - - if (check_key_events(dev)) { - poll_time_end = sys_timepoint_calc(K_USEC(data->poll_timeout_us)); - } else if (sys_timepoint_expired(poll_time_end)) { - break; - } - - /* - * Subtract the time invested from the sleep period in order to - * compensate for the time invested in debouncing a key - */ - current_cycles = k_cycle_get_32(); - cycles_diff = current_cycles - start_period_cycles; - wait_period = data->poll_period_us - k_cyc_to_us_floor32(cycles_diff); - - /* Override wait_period in case it is less than 1 ms */ - if (wait_period < USEC_PER_MSEC) { - wait_period = USEC_PER_MSEC; - } - - /* - * Wait period results in a larger number when current cycles - * counter wrap. In this case, the whole poll period is used - */ - if (wait_period > data->poll_period_us) { - LOG_DBG("wait_period: %u", wait_period); - - wait_period = data->poll_period_us; - } - - /* Allow other threads to run while we sleep */ - k_usleep(wait_period); - } -} - -static void kbd_matrix_polling_thread(void *dummy1, void *dummy2, void *dummy3) -{ - const struct device *dev = dummy1; - struct input_npcx_kbd_data *const data = dev->data; - - ARG_UNUSED(dummy2); - ARG_UNUSED(dummy3); - - while (true) { - /* Enable interrupt of KSI pins */ - input_npcx_kbd_resume_detection(dev, true); - - input_npcx_kbd_drive_column(dev, KEYBOARD_COLUMN_DRIVE_ALL); - k_sem_take(&data->poll_lock, K_FOREVER); - LOG_DBG("Start KB scan"); - - /* Disable interrupt of KSI pins and start polling */ - input_npcx_kbd_resume_detection(dev, false); - - kbd_matrix_poll(dev); - } -} - static void input_npcx_kbd_init_ksi_wui_callback(const struct device *dev, struct miwu_callback *callback, const struct npcx_wui *wui, @@ -415,6 +136,7 @@ static int input_npcx_kbd_init(const struct device *dev) { const struct device *clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); const struct input_npcx_kbd_config *const config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; struct input_npcx_kbd_data *const data = dev->data; struct kbs_reg *const inst = config->base; int ret; @@ -428,6 +150,7 @@ static int input_npcx_kbd_init(const struct device *dev) ret = clock_control_on(clk_dev, (clock_control_subsys_t)&config->clk_cfg); if (ret < 0) { LOG_ERR("Turn on KBSCAN clock fail %d", ret); + return -EIO; } /* Pull-up KBSIN0-7 internally */ @@ -453,10 +176,15 @@ static int input_npcx_kbd_init(const struct device *dev) } /* Drive all column lines to low for detection any key press */ - input_npcx_kbd_drive_column(dev, KEYBOARD_COLUMN_DRIVE_NONE); + input_npcx_kbd_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); + + if (common->row_size != ROW_SIZE) { + LOG_ERR("Unexpected ROW_SIZE: %d != %d", common->row_size, ROW_SIZE); + return -EINVAL; + } /* Configure wake-up input and callback for keyboard input signal */ - for (int i = 0; i < config->row_size; i++) { + for (int i = 0; i < common->row_size; i++) { input_npcx_kbd_init_ksi_wui_callback( dev, &data->ksi_callback[i], &config->wui_maps[i], input_npcx_kbd_ksi_isr); @@ -469,20 +197,17 @@ static int input_npcx_kbd_init(const struct device *dev) return ret; } - /* Initialize semaphore used by keyboard scan task and driver */ - k_sem_init(&data->poll_lock, 0, 1); - - /* Time figures are transformed from msec to usec */ - data->poll_period_us = (uint32_t)(CONFIG_INPUT_NPCX_KBD_POLL_PERIOD_MS * USEC_PER_MSEC); - data->poll_timeout_us = 100 * USEC_PER_MSEC; - return input_kbd_matrix_common_init(dev); } PINCTRL_DT_INST_DEFINE(0); +INPUT_KBD_MATRIX_DT_INST_DEFINE(0); + static const struct input_kbd_matrix_api npcx_kbd_api = { - .polling_thread = kbd_matrix_polling_thread, + .drive_column = input_npcx_kbd_drive_column, + .read_row = input_npcx_kbd_read_row, + .set_detect_mode = input_npcx_kbd_set_detect_mode, }; static const struct input_npcx_kbd_config npcx_kbd_cfg = { @@ -493,10 +218,6 @@ static const struct input_npcx_kbd_config npcx_kbd_cfg = { .irq = DT_INST_IRQN(0), .wui_size = NPCX_DT_WUI_ITEMS_LEN(0), .wui_maps = NPCX_DT_WUI_ITEMS_LIST(0), - .row_size = KSCAN_ROW_SIZE, - .col_size = KSCAN_COL_SIZE, - .deb_time_press = DT_INST_PROP(0, debounce_down_ms), - .deb_time_rel = DT_INST_PROP(0, debounce_up_ms), }; static struct input_npcx_kbd_data npcx_kbd_data; @@ -507,3 +228,5 @@ DEVICE_DT_INST_DEFINE(0, input_npcx_kbd_init, NULL, BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "only one nuvoton,npcx-kbd compatible node can be supported"); +BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, row_size), 1, 8), "invalid row-size"); +BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, col_size), 1, 18), "invalid col-size"); diff --git a/dts/bindings/input/kbd-matrix-common.yaml b/dts/bindings/input/kbd-matrix-common.yaml index 87dbec147b48779..53efd29dc9f97d2 100644 --- a/dts/bindings/input/kbd-matrix-common.yaml +++ b/dts/bindings/input/kbd-matrix-common.yaml @@ -4,3 +4,55 @@ description: Keyboard matrix device include: base.yaml + +properties: + row-size: + type: int + required: true + description: | + The number of rows in the keyboard matrix. + + col-size: + type: int + required: true + description: | + The number of column in the keyboard matrix. + + poll-period-ms: + type: int + default: 5 + description: | + Defines the poll period in msecs between between matrix scans. Defaults + to 5ms if unsepcified. + + poll-timeout-ms: + type: int + default: 100 + description: | + How long to wait before going from polling back to idle state. Defaults + to 100ms if unspecified. + + debounce-down-ms: + type: int + default: 10 + description: | + Debouncing time for a key press event. Defaults to 10ms if unspecified. + + debounce-up-ms: + type: int + default: 20 + description: | + Debouncing time for a key release event. Defaults to 20ms if unspecified. + + settle-time-us: + type: int + default: 50 + description: | + Delay between setting column output and reading the row values. Defaults + to 50us if unspecified. + + no-ghostkey-check: + type: boolean + description: | + Ignore the ghost key checking in the driver if the diodes are used + in the matrix hardware. diff --git a/dts/bindings/input/nuvoton,npcx-kbd.yaml b/dts/bindings/input/nuvoton,npcx-kbd.yaml index 130a003d1a4b456..7ba9956cb6b2443 100644 --- a/dts/bindings/input/nuvoton,npcx-kbd.yaml +++ b/dts/bindings/input/nuvoton,npcx-kbd.yaml @@ -29,35 +29,3 @@ properties: For example the WUI mapping on 8 KSI pads would be wui-maps = <&wui_io30 &wui_io31 &wui_io27 &wui_io26 &wui_io25 &wui_io24 &wui_io23 &wui_io22>; - - row-size: - type: int - default: 8 - required: true - description: | - The row size is used in the keyboard matrix. - valid range: 1 - 8 - - col-size: - type: int - default: 18 - required: true - description: | - The column size is used in the keyboard matrix. - valid range: 1 - 18 - - debounce-down-ms: - type: int - default: 10 - description: Determines the time in msecs for debouncing a key press. - - debounce-up-ms: - type: int - default: 20 - description: Determines the time in msecs for debouncing a key release. - - no-ghostkey-check: - type: boolean - description: | - Ignore the ghost key checking in the driver if the diodes are used - in the matrix hardware. From e5dbb26c723894d05bd548f9ea38ffc1c44df381 Mon Sep 17 00:00:00 2001 From: Daniel Istvan Nemeth Date: Wed, 8 Nov 2023 00:34:26 +0100 Subject: [PATCH 0249/1049] samples: drivers: led_ws2812: nRF5340DK support New config files to support nrf5340-based boards Signed-off-by: Daniel Istvan Nemeth --- samples/drivers/led_ws2812/README.rst | 2 ++ .../led_ws2812/boards/nrf5340dk_nrf5340.conf | 5 +++ .../boards/nrf5340dk_nrf5340.overlay | 36 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.conf create mode 100644 samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.overlay diff --git a/samples/drivers/led_ws2812/README.rst b/samples/drivers/led_ws2812/README.rst index 5529604b0a8caeb..183875520f2d27d 100644 --- a/samples/drivers/led_ws2812/README.rst +++ b/samples/drivers/led_ws2812/README.rst @@ -102,6 +102,8 @@ This sample uses different drivers depending on the selected board: I2S driver: - thingy52_nrf52832 +- nrf5340dk_nrf5340 (3.3V logic level, a logic level shifter may be required) + - should work for other boards featuring an nRF5340 host processor SPI driver: diff --git a/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.conf b/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.conf new file mode 100644 index 000000000000000..f5d64aaf5da02e0 --- /dev/null +++ b/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.conf @@ -0,0 +1,5 @@ +CONFIG_SPI=n + +CONFIG_I2S=y +CONFIG_WS2812_STRIP=y +CONFIG_WS2812_STRIP_I2S=y diff --git a/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.overlay b/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.overlay new file mode 100644 index 000000000000000..738e79115326fee --- /dev/null +++ b/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.overlay @@ -0,0 +1,36 @@ +#include + +&pinctrl { + i2s0_default_alt: i2s0_default_alt { + group1 { + /* Default I2S config for the nRF5340, P1.13 is the output */ + psels = , + , + , + ; + }; + }; +}; + +i2s_led: &i2s0 { + status = "okay"; + pinctrl-0 = <&i2s0_default_alt>; + pinctrl-names = "default"; +}; + +/ { + led_strip: ws2812 { + compatible = "worldsemi,ws2812-i2s"; + + i2s-dev = <&i2s_led>; + chain-length = <42>; /* arbitrary; change at will */ + color-mapping = ; + reset-delay = <500>; + }; + + aliases { + led-strip = &led_strip; + }; +}; From 8aba7740b8b190a95daf2ec145fba6a3f78139a5 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 6 Nov 2023 16:47:05 +0100 Subject: [PATCH 0250/1049] net: lwm2m: Fix core objects version reporting Core objects version reporting was broken for LwM2M version 1.1, as the default object version not necessarily matches the LwM2M version. Therefore, implement a table with default object versions for particular LwM2M version, which can be looked up when determining whether it's needed to include object version or not during Registration/Discovery. Signed-off-by: Robert Lubos --- include/zephyr/net/lwm2m.h | 1 + subsys/net/lib/lwm2m/lwm2m_registry.c | 53 +++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 6262f6d103df86c..a57b5542f8884df 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -49,6 +49,7 @@ #define LWM2M_OBJECT_PORTFOLIO_ID 16 /**< Portfolio object */ #define LWM2M_OBJECT_BINARYAPPDATACONTAINER_ID 19 /**< Binary App Data Container object */ #define LWM2M_OBJECT_EVENT_LOG_ID 20 /**< Event Log object */ +#define LWM2M_OBJECT_OSCORE_ID 21 /**< OSCORE object */ #define LWM2M_OBJECT_GATEWAY_ID 25 /**< Gateway object */ /* clang-format on */ diff --git a/subsys/net/lib/lwm2m/lwm2m_registry.c b/subsys/net/lib/lwm2m/lwm2m_registry.c index fc297149d84902f..210c55257563659 100644 --- a/subsys/net/lib/lwm2m/lwm2m_registry.c +++ b/subsys/net/lib/lwm2m/lwm2m_registry.c @@ -50,6 +50,41 @@ void lwm2m_registry_unlock(void) { (void)k_mutex_unlock(®istry_lock); } + +/* Default core object version */ +struct default_obj_version { + uint16_t obj_id; + uint8_t version_major; + uint8_t version_minor; +}; + +/* Based on Appendix E of the respective LwM2M specification. */ +static const struct default_obj_version default_obj_versions[] = { +#if defined(CONFIG_LWM2M_VERSION_1_0) + { LWM2M_OBJECT_SECURITY_ID, 1, 0 }, + { LWM2M_OBJECT_SERVER_ID, 1, 0 }, + { LWM2M_OBJECT_ACCESS_CONTROL_ID, 1, 0 }, + { LWM2M_OBJECT_DEVICE_ID, 1, 0 }, + { LWM2M_OBJECT_CONNECTIVITY_MONITORING_ID, 1, 0 }, + { LWM2M_OBJECT_FIRMWARE_ID, 1, 0 }, + { LWM2M_OBJECT_LOCATION_ID, 1, 0 }, + { LWM2M_OBJECT_CONNECTIVITY_STATISTICS_ID, 1, 0 }, +#elif defined(CONFIG_LWM2M_VERSION_1_1) + { LWM2M_OBJECT_SECURITY_ID, 1, 1 }, + { LWM2M_OBJECT_SERVER_ID, 1, 1 }, + { LWM2M_OBJECT_ACCESS_CONTROL_ID, 1, 0 }, + { LWM2M_OBJECT_DEVICE_ID, 1, 1 }, + { LWM2M_OBJECT_CONNECTIVITY_MONITORING_ID, 1, 2 }, + { LWM2M_OBJECT_FIRMWARE_ID, 1, 0 }, + { LWM2M_OBJECT_LOCATION_ID, 1, 0 }, + { LWM2M_OBJECT_CONNECTIVITY_STATISTICS_ID, 1, 0 }, + /* OSCORE object not implemented yet, but include it for completeness */ + { LWM2M_OBJECT_OSCORE_ID, 1, 0 }, +#else +#error "Default core object versions not defined for LwM2M version" +#endif +}; + /* Resources */ static sys_slist_t engine_obj_list; static sys_slist_t engine_obj_inst_list; @@ -1975,12 +2010,22 @@ struct lwm2m_engine_res_inst *lwm2m_engine_get_res_inst(const struct lwm2m_obj_p bool lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj *obj) { - if (obj->is_core) { - return obj->version_major != LWM2M_PROTOCOL_VERSION_MAJOR || - obj->version_minor != LWM2M_PROTOCOL_VERSION_MINOR; + /* For non-core objects, report version other than 1.0 */ + if (!obj->is_core) { + return obj->version_major != 1 || obj->version_minor != 0; } - return obj->version_major != 1 || obj->version_minor != 0; + /* For core objects, report version based on default version array. */ + for (size_t i = 0; i < ARRAY_SIZE(default_obj_versions); i++) { + if (obj->obj_id != default_obj_versions[i].obj_id) { + continue; + } + + return obj->version_major != default_obj_versions[i].version_major || + obj->version_minor != default_obj_versions[i].version_minor; + } + + return true; } #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT) From e338299bd4ad2324d882e15c1f7ebb8096f0b44d Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Fri, 3 Nov 2023 19:55:25 +1100 Subject: [PATCH 0251/1049] drivers: adc: adc_ads114s0x: fix incorrect type Affected CONFIG_ADC_ADS114S0X_GPIO=y build. register_addresses was wrong type for ads114s0x_write_multiple_registers() Signed-off-by: Nick Ward --- drivers/adc/adc_ads114s0x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/adc/adc_ads114s0x.c b/drivers/adc/adc_ads114s0x.c index 4ad78c7246a9b74..e5ab699bcbd2934 100644 --- a/drivers/adc/adc_ads114s0x.c +++ b/drivers/adc/adc_ads114s0x.c @@ -1080,7 +1080,7 @@ static int ads114s0x_gpio_write_config(const struct device *dev) { struct ads114s0x_data *data = dev->data; const struct ads114s0x_config *config = dev->config; - uint8_t register_addresses[2]; + enum ads114s0x_register register_addresses[2]; uint8_t register_values[ARRAY_SIZE(register_addresses)]; uint8_t gpio_dat = 0; uint8_t gpio_con = 0; From 2612aa02ced24ea6b6407c569495d212660177f9 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Fri, 3 Nov 2023 19:58:51 +1100 Subject: [PATCH 0252/1049] tests: drivers: build_all: gpio: add ads1145s0x testcase This fixes multiple CI issues for the ads1145s0x driver. Having a special testcase for the driver limits the CONFIG_ADC=y and CONFIG_ADC_INIT_PRIORITY adjustment requirements. Also fixes address not matching warning for pcal6416a@2 Signed-off-by: Nick Ward --- .../build_all/gpio/adc_ads1145s0x_gpio.conf | 3 +++ .../gpio/adc_ads1145s0x_gpio.overlay | 21 +++++++++++++++ tests/drivers/build_all/gpio/app.overlay | 26 +++---------------- tests/drivers/build_all/gpio/prj.conf | 1 - tests/drivers/build_all/gpio/testcase.yaml | 11 ++++++++ 5 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.conf create mode 100644 tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.overlay diff --git a/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.conf b/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.conf new file mode 100644 index 000000000000000..64290a4a4918409 --- /dev/null +++ b/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.conf @@ -0,0 +1,3 @@ +CONFIG_ADC=y +CONFIG_ADC_ADS114S0X_GPIO=y +CONFIG_ADC_INIT_PRIORITY=80 diff --git a/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.overlay b/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.overlay new file mode 100644 index 000000000000000..60078a4efff7cf3 --- /dev/null +++ b/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.overlay @@ -0,0 +1,21 @@ +&test_spi { + test_spi_ads114s08: ads114s08@0 { + compatible = "ti,ads114s08"; + status = "okay"; + spi-max-frequency = <10000000>; + reg = <0x00>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + reset-gpios = <&test_gpio 0 0>; + drdy-gpios = <&test_gpio 0 0>; + start-sync-gpios = <&test_gpio 0 0>; + + test_spi_ads114s08_gpio: ads114s0x_gpio { + compatible = "ti,ads114s0x-gpio"; + gpio-controller; + ngpios = <4>; + #gpio-cells = <2>; + }; + }; +}; diff --git a/tests/drivers/build_all/gpio/app.overlay b/tests/drivers/build_all/gpio/app.overlay index 715480a94f0ac81..231d05a792f281f 100644 --- a/tests/drivers/build_all/gpio/app.overlay +++ b/tests/drivers/build_all/gpio/app.overlay @@ -51,7 +51,7 @@ test_i2c_pcal6416a: pcal6416a@2 { compatible = "nxp,pcal6416a"; - reg = <0x1>; + reg = <0x2>; gpio-controller; #gpio-cells = <2>; ngpios = <16>; @@ -244,30 +244,10 @@ reset-gpios = <&test_gpio 0 0>; }; - test_spi_ads114s08: ads114s08@3 { - compatible = "ti,ads114s08"; - status = "okay"; - spi-max-frequency = <10000000>; - reg = <0x03>; - #address-cells = <1>; - #size-cells = <0>; - #io-channel-cells = <1>; - reset-gpios = <&test_gpio 0 0>; - drdy-gpios = <&test_gpio 0 0>; - start-sync-gpios = <&test_gpio 0 0>; - - test_spi_ads114s08_gpio: ads114s0x_gpio { - compatible = "ti,ads114s0x-gpio"; - gpio-controller; - ngpios = <4>; - #gpio-cells = <2>; - }; - }; - - test_spi_ad5592: ad5592@4 { + test_spi_ad5592: ad5592@3 { compatible = "adi,ad5592"; status = "okay"; - reg = <0x04>; + reg = <0x03>; spi-max-frequency = <0>; reset-gpios = <&test_gpio 0 0>; diff --git a/tests/drivers/build_all/gpio/prj.conf b/tests/drivers/build_all/gpio/prj.conf index 1517e7a4b760c61..6e24ab48c84c5f0 100644 --- a/tests/drivers/build_all/gpio/prj.conf +++ b/tests/drivers/build_all/gpio/prj.conf @@ -4,4 +4,3 @@ CONFIG_TEST_USERSPACE=y CONFIG_I2C=y CONFIG_GPIO_PCA95XX_INTERRUPT=y CONFIG_SPI=y -CONFIG_ADC_ADS114S0X_GPIO=y diff --git a/tests/drivers/build_all/gpio/testcase.yaml b/tests/drivers/build_all/gpio/testcase.yaml index a95b46257257888..88d62c5b7707edd 100644 --- a/tests/drivers/build_all/gpio/testcase.yaml +++ b/tests/drivers/build_all/gpio/testcase.yaml @@ -23,3 +23,14 @@ tests: platform_allow: niosv_m niosv_g depends_on: gpio extra_args: DTC_OVERLAY_FILE="altera.overlay" + + drivers.gpio.build.adc_ads1145s0x_gpio: + min_ram: 32 + platform_allow: m5stack_core2 nrf52840dk_nrf52840 + depends_on: + - gpio + - adc + - spi + extra_args: + - DTC_OVERLAY_FILE="app.overlay;adc_ads1145s0x_gpio.overlay" + - CONF_FILE="adc_ads1145s0x_gpio.conf" From 89612932b028c06977325ca5d40ac8792b0bc97c Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 7 Nov 2023 13:46:46 +0100 Subject: [PATCH 0253/1049] tests: Bluetooth: Enable passing CAP AC 441 tests Enable some previously disabled CAP AC tests for 44.1 KHz, as they are now passing. Signed-off-by: Emil Gydesen --- tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_1.sh | 4 ++-- tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_10.sh | 4 ++-- tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_2.sh | 4 ++-- tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_3.sh | 4 ++-- tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_4.sh | 4 ++-- tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_i.sh | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_1.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_1.sh index 070c0f72820fd6e..199b0144b34cf8c 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_1.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_1.sh @@ -40,8 +40,8 @@ Execute_AC_1 24_1_1 Execute_AC_1 24_2_1 Execute_AC_1 32_1_1 Execute_AC_1 32_2_1 -# Execute_AC_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] -# Execute_AC_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_1 441_1_1 +Execute_AC_1 441_2_1 Execute_AC_1 48_1_1 Execute_AC_1 48_2_1 Execute_AC_1 48_3_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_10.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_10.sh index 2a2179b7b36b304..af35c7ad66b42ec 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_10.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_10.sh @@ -40,8 +40,8 @@ Execute_AC_10 24_1_1 Execute_AC_10 24_2_1 Execute_AC_10 32_1_1 Execute_AC_10 32_2_1 -# Execute_AC_10 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] -# Execute_AC_10 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_10 441_1_1 +Execute_AC_10 441_2_1 Execute_AC_10 48_1_1 Execute_AC_10 48_2_1 Execute_AC_10 48_3_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_2.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_2.sh index dae30f9dead408e..76a9b762fd10d09 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_2.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_2.sh @@ -41,8 +41,8 @@ Execute_AC_2 24_1_1 Execute_AC_2 24_2_1 Execute_AC_2 32_1_1 Execute_AC_2 32_2_1 -# Execute_AC_2 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] -# Execute_AC_2 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_2 441_1_1 +Execute_AC_2 441_2_1 Execute_AC_2 48_1_1 Execute_AC_2 48_2_1 Execute_AC_2 48_3_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_3.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_3.sh index 4d51d8e3a087eca..e4682d1019706fd 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_3.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_3.sh @@ -41,8 +41,8 @@ Execute_AC_3 24_1_1 24_1_1 Execute_AC_3 24_2_1 24_2_1 Execute_AC_3 32_1_1 32_1_1 Execute_AC_3 32_2_1 32_2_1 -# Execute_AC_3 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] -# Execute_AC_3 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_3 441_1_1 441_1_1 +Execute_AC_3 441_2_1 441_2_1 Execute_AC_3 48_1_1 48_1_1 Execute_AC_3 48_2_1 48_2_1 Execute_AC_3 48_3_1 48_3_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_4.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_4.sh index 251e87e0382b0b4..a863b35925261b7 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_4.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_4.sh @@ -38,8 +38,8 @@ Execute_AC_4 24_1_1 Execute_AC_4 24_2_1 Execute_AC_4 32_1_1 Execute_AC_4 32_2_1 -# Execute_AC_4 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] -# Execute_AC_4 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_4 441_1_1 +Execute_AC_4 441_2_1 Execute_AC_4 48_1_1 Execute_AC_4 48_2_1 Execute_AC_4 48_3_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_i.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_i.sh index af439378c20faa9..279322562edea60 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_i.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_i.sh @@ -40,8 +40,8 @@ Execute_AC_7_I 24_1_1 24_1_1 Execute_AC_7_I 24_2_1 24_2_1 Execute_AC_7_I 32_1_1 32_1_1 Execute_AC_7_I 32_2_1 32_2_1 -# Execute_AC_7_I 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] -# Execute_AC_7_I 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_7_I 441_1_1 441_1_1 +Execute_AC_7_I 441_2_1 441_2_1 Execute_AC_7_I 48_1_1 48_1_1 Execute_AC_7_I 48_2_1 48_2_1 Execute_AC_7_I 48_3_1 48_3_1 From b89095cf12f3ac1660411709117995835891f840 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 9 Nov 2023 11:03:40 +0800 Subject: [PATCH 0254/1049] tests: logging: log_syst: set backend ctx to its cb ctx when enable Set the backend's context to its control block's context instead of NULL when doing `log_backend_enable`, as the log backend UART uses that later. Signed-off-by: Yong Cong Sin --- tests/subsys/logging/log_syst/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/subsys/logging/log_syst/src/main.c b/tests/subsys/logging/log_syst/src/main.c index 45b7f34bf1a134f..bc0e6b2c556ea21 100644 --- a/tests/subsys/logging/log_syst/src/main.c +++ b/tests/subsys/logging/log_syst/src/main.c @@ -152,7 +152,7 @@ static void after(void *unused) if (backend == &log_backend_mock) { log_backend_disable(backend); } else { - log_backend_enable(backend, NULL, 4); + log_backend_enable(backend, backend->cb->ctx, 4); } } } From c0064f1de88a04146b55e059ae40dc4ebf1eb0a9 Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 8 Nov 2023 17:29:26 +0800 Subject: [PATCH 0255/1049] logging: uart: support multiple instances Extends the log_backend_uart to support logging to multiple UART instances. Signed-off-by: Christopher Friedt --- doc/build/dts/api/api.rst | 3 + dts/bindings/misc/zephyr,log-uart.yaml | 16 +++ subsys/logging/backends/log_backend_uart.c | 115 +++++++++++++++------ 3 files changed, 103 insertions(+), 31 deletions(-) create mode 100644 dts/bindings/misc/zephyr,log-uart.yaml diff --git a/doc/build/dts/api/api.rst b/doc/build/dts/api/api.rst index f452d0f52812ebb..44b87653cc3fe14 100644 --- a/doc/build/dts/api/api.rst +++ b/doc/build/dts/api/api.rst @@ -424,6 +424,9 @@ device. interprocess-communication (IPC) * - zephyr,itcm - Instruction Tightly Coupled Memory node on some Arm SoCs + * - zephyr,log-uart + - Sets the UART device(s) used by the logging subsystem's UART backend. + If defined, the UART log backend would output to the devices listed in this node. * - zephyr,ocm - On-chip memory node on Xilinx Zynq-7000 and ZynqMP SoCs * - zephyr,osdp-uart diff --git a/dts/bindings/misc/zephyr,log-uart.yaml b/dts/bindings/misc/zephyr,log-uart.yaml new file mode 100644 index 000000000000000..2e0a065e3b238d3 --- /dev/null +++ b/dts/bindings/misc/zephyr,log-uart.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +description: Log Backend UART + +compatible: "zephyr,log-uart" + +include: [base.yaml] + +properties: + + uarts: + type: phandles + required: true + description: | + UART devices to be used by the UART log backend. diff --git a/subsys/logging/backends/log_backend_uart.c b/subsys/logging/backends/log_backend_uart.c index 5bfcbdd89b117ef..7c58ea1774e444b 100644 --- a/subsys/logging/backends/log_backend_uart.c +++ b/subsys/logging/backends/log_backend_uart.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2023 Meta * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,32 +19,43 @@ #include LOG_MODULE_REGISTER(log_uart); +struct lbu_data { + struct k_sem sem; + uint32_t log_format_current; + volatile bool in_panic; + bool use_async; +}; + +struct lbu_cb_ctx { + const struct log_output *output; + const struct device *device; + struct lbu_data *data; +}; + /* Fixed size to avoid auto-added trailing '\0'. * Used if CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX. */ static const char LOG_HEX_SEP[10] = "##ZLOGV1##"; -static const struct device *const uart_dev = - DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); -static struct k_sem sem; -static volatile bool in_panic; -static bool use_async; -static uint32_t log_format_current = CONFIG_LOG_BACKEND_UART_OUTPUT_DEFAULT; - static void uart_callback(const struct device *dev, struct uart_event *evt, void *user_data) { + const struct lbu_cb_ctx *ctx = user_data; + struct lbu_data *data = ctx->data; + + ARG_UNUSED(dev); + switch (evt->type) { case UART_TX_DONE: - k_sem_give(&sem); + k_sem_give(&data->sem); break; default: break; } } -static void dict_char_out_hex(uint8_t *data, size_t length) +static void dict_char_out_hex(const struct device *uart_dev, uint8_t *data, size_t length) { for (size_t i = 0; i < length; i++) { char c; @@ -63,8 +75,10 @@ static void dict_char_out_hex(uint8_t *data, size_t length) static int char_out(uint8_t *data, size_t length, void *ctx) { - ARG_UNUSED(ctx); int err; + const struct lbu_cb_ctx *cb_ctx = ctx; + struct lbu_data *lb_data = cb_ctx->data; + const struct device *uart_dev = cb_ctx->device; if (pm_device_runtime_is_enabled(uart_dev) && !k_is_in_isr()) { if (pm_device_runtime_get(uart_dev) < 0) { @@ -76,11 +90,12 @@ static int char_out(uint8_t *data, size_t length, void *ctx) } if (IS_ENABLED(CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX)) { - dict_char_out_hex(data, length); + dict_char_out_hex(uart_dev, data, length); goto cleanup; } - if (!IS_ENABLED(CONFIG_LOG_BACKEND_UART_ASYNC) || in_panic || !use_async) { + if (!IS_ENABLED(CONFIG_LOG_BACKEND_UART_ASYNC) || lb_data->in_panic || + !lb_data->use_async) { for (size_t i = 0; i < length; i++) { uart_poll_out(uart_dev, data[i]); } @@ -90,7 +105,7 @@ static int char_out(uint8_t *data, size_t length, void *ctx) err = uart_tx(uart_dev, data, length, SYS_FOREVER_US); __ASSERT_NO_MSG(err == 0); - err = k_sem_take(&sem, K_FOREVER); + err = k_sem_take(&lb_data->sem, K_FOREVER); __ASSERT_NO_MSG(err == 0); (void)err; @@ -103,29 +118,37 @@ static int char_out(uint8_t *data, size_t length, void *ctx) return length; } -static uint8_t uart_output_buf[CONFIG_LOG_BACKEND_UART_BUFFER_SIZE]; -LOG_OUTPUT_DEFINE(log_output_uart, char_out, uart_output_buf, sizeof(uart_output_buf)); - static void process(const struct log_backend *const backend, union log_msg_generic *msg) { + const struct lbu_cb_ctx *ctx = backend->cb->ctx; + struct lbu_data *data = ctx->data; uint32_t flags = log_backend_std_get_flags(); + log_format_func_t log_output_func = log_format_func_t_get(data->log_format_current); - log_format_func_t log_output_func = log_format_func_t_get(log_format_current); - - log_output_func(&log_output_uart, &msg->log, flags); + log_output_func(ctx->output, &msg->log, flags); } static int format_set(const struct log_backend *const backend, uint32_t log_type) { - log_format_current = log_type; + const struct lbu_cb_ctx *ctx = backend->cb->ctx; + struct lbu_data *data = ctx->data; + + data->log_format_current = log_type; + return 0; } static void log_backend_uart_init(struct log_backend const *const backend) { + const struct lbu_cb_ctx *ctx = backend->cb->ctx; + const struct device *uart_dev = ctx->device; + struct lbu_data *data = ctx->data; + __ASSERT_NO_MSG(device_is_ready(uart_dev)); + log_output_ctx_set(ctx->output, (void *)ctx); + if (IS_ENABLED(CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX)) { /* Print a separator so the output can be fed into * log parser directly. This is useful when capturing @@ -140,20 +163,25 @@ static void log_backend_uart_init(struct log_backend const *const backend) } if (IS_ENABLED(CONFIG_LOG_BACKEND_UART_ASYNC)) { - int err = uart_callback_set(uart_dev, uart_callback, NULL); + int err = uart_callback_set(uart_dev, uart_callback, (void *)ctx); if (err == 0) { - use_async = true; - k_sem_init(&sem, 0, 1); + data->use_async = true; + k_sem_init(&data->sem, 0, 1); } else { LOG_WRN("Failed to initialize asynchronous mode (err:%d). " - "Fallback to polling.", err); + "Fallback to polling.", + err); } } } static void panic(struct log_backend const *const backend) { + const struct lbu_cb_ctx *ctx = backend->cb->ctx; + struct lbu_data *data = ctx->data; + const struct device *uart_dev = ctx->device; + /* Ensure that the UART device is in active mode */ #if defined(CONFIG_PM_DEVICE_RUNTIME) if (pm_device_runtime_is_enabled(uart_dev)) { @@ -172,20 +200,22 @@ static void panic(struct log_backend const *const backend) if ((rc == 0) && (pm_state == PM_DEVICE_STATE_SUSPENDED)) { pm_device_action_run(uart_dev, PM_DEVICE_ACTION_RESUME); } +#else + ARG_UNUSED(uart_dev); #endif /* CONFIG_PM_DEVICE */ - in_panic = true; - log_backend_std_panic(&log_output_uart); + data->in_panic = true; + log_backend_std_panic(ctx->output); } static void dropped(const struct log_backend *const backend, uint32_t cnt) { - ARG_UNUSED(backend); + const struct lbu_cb_ctx *ctx = backend->cb->ctx; if (IS_ENABLED(CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY)) { - log_dict_output_dropped_process(&log_output_uart, cnt); + log_dict_output_dropped_process(ctx->output, cnt); } else { - log_backend_std_dropped(&log_output_uart, cnt); + log_backend_std_dropped(ctx->output, cnt); } } @@ -197,5 +227,28 @@ const struct log_backend_api log_backend_uart_api = { .format_set = format_set, }; -LOG_BACKEND_DEFINE(log_backend_uart, log_backend_uart_api, - IS_ENABLED(CONFIG_LOG_BACKEND_UART_AUTOSTART)); +#define LBU_DEFINE(node_id, idx) \ + static uint8_t lbu_buffer_##idx[CONFIG_LOG_BACKEND_UART_BUFFER_SIZE]; \ + LOG_OUTPUT_DEFINE(lbu_output_##idx, char_out, lbu_buffer_##idx, \ + CONFIG_LOG_BACKEND_UART_BUFFER_SIZE); \ + \ + static struct lbu_data lbu_data_##idx = { \ + .log_format_current = CONFIG_LOG_BACKEND_UART_OUTPUT_DEFAULT, \ + }; \ + \ + static const struct lbu_cb_ctx lbu_cb_ctx_##idx = { \ + .output = &lbu_output_##idx, \ + .device = DEVICE_DT_GET(node_id), \ + .data = &lbu_data_##idx, \ + }; \ + \ + LOG_BACKEND_DEFINE(log_backend_uart##idx, log_backend_uart_api, \ + IS_ENABLED(CONFIG_LOG_BACKEND_UART_AUTOSTART), \ + (void *)&lbu_cb_ctx_##idx); + +#if DT_HAS_CHOSEN(zephyr_log_uart) +#define LBU_PHA_FN(node_id, prop, idx) LBU_DEFINE(DT_PHANDLE_BY_IDX(node_id, prop, idx), idx) +DT_FOREACH_PROP_ELEM_SEP(DT_CHOSEN(zephyr_log_uart), uarts, LBU_PHA_FN, ()); +#else +LBU_DEFINE(DT_CHOSEN(zephyr_console), 0); +#endif From 6d9fcd83a940938a06baf625d7c5c40d32a6f9ab Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 8 Nov 2023 17:31:23 +0800 Subject: [PATCH 0256/1049] test: logging: add testcase for multi-instance log backend uart Add testcase for the multi-instance log backend uart using emulated uart. Signed-off-by: Yong Cong Sin --- .../logging/log_backend_uart/CMakeLists.txt | 9 +++ tests/subsys/logging/log_backend_uart/Kconfig | 8 ++ .../logging/log_backend_uart/multi.overlay | 32 ++++++++ .../subsys/logging/log_backend_uart/prj.conf | 11 +++ .../logging/log_backend_uart/single.overlay | 24 ++++++ .../logging/log_backend_uart/src/main.c | 73 +++++++++++++++++++ .../logging/log_backend_uart/testcase.yaml | 14 ++++ 7 files changed, 171 insertions(+) create mode 100644 tests/subsys/logging/log_backend_uart/CMakeLists.txt create mode 100644 tests/subsys/logging/log_backend_uart/Kconfig create mode 100644 tests/subsys/logging/log_backend_uart/multi.overlay create mode 100644 tests/subsys/logging/log_backend_uart/prj.conf create mode 100644 tests/subsys/logging/log_backend_uart/single.overlay create mode 100644 tests/subsys/logging/log_backend_uart/src/main.c create mode 100644 tests/subsys/logging/log_backend_uart/testcase.yaml diff --git a/tests/subsys/logging/log_backend_uart/CMakeLists.txt b/tests/subsys/logging/log_backend_uart/CMakeLists.txt new file mode 100644 index 000000000000000..055b71fd7486a5a --- /dev/null +++ b/tests/subsys/logging/log_backend_uart/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(log_backend_uart_test) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/logging/log_backend_uart/Kconfig b/tests/subsys/logging/log_backend_uart/Kconfig new file mode 100644 index 000000000000000..89a0fefa76f259d --- /dev/null +++ b/tests/subsys/logging/log_backend_uart/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +module = SAMPLE_MODULE +module-str = Test logging API +source "subsys/logging/Kconfig.template.log_config" + +source "Kconfig.zephyr" diff --git a/tests/subsys/logging/log_backend_uart/multi.overlay b/tests/subsys/logging/log_backend_uart/multi.overlay new file mode 100644 index 000000000000000..799a4602cf94bf3 --- /dev/null +++ b/tests/subsys/logging/log_backend_uart/multi.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,log-uart = &log_uarts; + }; + + log_uarts: log_uarts { + compatible = "zephyr,log-uart"; + uarts = <&euart0 &euart1>; + }; + + euart0: uart-emul0 { + compatible = "zephyr,uart-emul"; + status = "okay"; + current-speed = <0>; + rx-fifo-size = <256>; + tx-fifo-size = <256>; + }; + + euart1: uart-emul1 { + compatible = "zephyr,uart-emul"; + status = "okay"; + current-speed = <0>; + rx-fifo-size = <256>; + tx-fifo-size = <256>; + }; +}; diff --git a/tests/subsys/logging/log_backend_uart/prj.conf b/tests/subsys/logging/log_backend_uart/prj.conf new file mode 100644 index 000000000000000..ef6894f355ea1e6 --- /dev/null +++ b/tests/subsys/logging/log_backend_uart/prj.conf @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_ASSERT=y +CONFIG_TEST_LOGGING_DEFAULTS=n + +CONFIG_LOG=y +CONFIG_LOG_BACKEND_UART=y +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_LOG_PRINTK=n diff --git a/tests/subsys/logging/log_backend_uart/single.overlay b/tests/subsys/logging/log_backend_uart/single.overlay new file mode 100644 index 000000000000000..3bdcff1c882303f --- /dev/null +++ b/tests/subsys/logging/log_backend_uart/single.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,log-uart = &log_uarts; + }; + + log_uarts: log_uarts { + compatible = "zephyr,log-uart"; + uarts = <&euart0>; + }; + + euart0: uart-emul0 { + compatible = "zephyr,uart-emul"; + status = "okay"; + current-speed = <0>; + rx-fifo-size = <256>; + tx-fifo-size = <256>; + }; +}; diff --git a/tests/subsys/logging/log_backend_uart/src/main.c b/tests/subsys/logging/log_backend_uart/src/main.c new file mode 100644 index 000000000000000..078d2e02f6383ec --- /dev/null +++ b/tests/subsys/logging/log_backend_uart/src/main.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(test, CONFIG_SAMPLE_MODULE_LOG_LEVEL); + +#define EMUL_UART_NUM DT_NUM_INST_STATUS_OKAY(zephyr_uart_emul) +#define EMUL_UART_NODE(i) DT_NODELABEL(euart##i) +#define EMUL_UART_DEV_INIT(i, _) DEVICE_DT_GET(EMUL_UART_NODE(i)) +#define EMUL_UART_TX_FIFO_SIZE(i) DT_PROP(EMUL_UART_NODE(i), tx_fifo_size) +#define SAMPLE_DATA_SIZE EMUL_UART_TX_FIFO_SIZE(0) + +#define TEST_DATA "0123456789ABCDEF" +BUILD_ASSERT(strlen(TEST_DATA) < SAMPLE_DATA_SIZE); + +struct log_backend_uart_fixture { + const struct device *dev[EMUL_UART_NUM]; +}; + +static void *uart_emul_setup(void) +{ + static struct log_backend_uart_fixture fixture = { + .dev = {LISTIFY(EMUL_UART_NUM, EMUL_UART_DEV_INIT, (,))}}; + + for (size_t i = 0; i < EMUL_UART_NUM; i++) { + zassert_not_null(fixture.dev[i]); + } + + return &fixture; +} + +static void uart_emul_before(void *f) +{ + struct log_backend_uart_fixture *fixture = f; + + for (size_t i = 0; i < EMUL_UART_NUM; i++) { + uart_irq_tx_disable(fixture->dev[i]); + uart_irq_rx_disable(fixture->dev[i]); + + uart_emul_flush_rx_data(fixture->dev[i]); + uart_emul_flush_tx_data(fixture->dev[i]); + + uart_err_check(fixture->dev[i]); + } +} + +ZTEST_F(log_backend_uart, test_log_backend_uart_multi_instance) +{ + zassert_equal(log_backend_count_get(), EMUL_UART_NUM, "Unexpected number of instance(s)"); + + LOG_RAW(TEST_DATA); + + for (size_t i = 0; i < EMUL_UART_NUM; i++) { + uint8_t tx_content[SAMPLE_DATA_SIZE] = {0}; + size_t tx_len; + + tx_len = uart_emul_get_tx_data(fixture->dev[i], tx_content, sizeof(tx_content)); + zassert_equal(tx_len, strlen(TEST_DATA), + "%d: TX buffer length does not match. Expected %d, got %d", + i, strlen(TEST_DATA), tx_len); + zassert_mem_equal(tx_content, TEST_DATA, strlen(tx_content)); + } +} + +ZTEST_SUITE(log_backend_uart, NULL, uart_emul_setup, uart_emul_before, NULL, NULL); diff --git a/tests/subsys/logging/log_backend_uart/testcase.yaml b/tests/subsys/logging/log_backend_uart/testcase.yaml new file mode 100644 index 000000000000000..70eb49920f15f70 --- /dev/null +++ b/tests/subsys/logging/log_backend_uart/testcase.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +common: + tags: + - logging + - backend + - uart + platform_allow: qemu_x86 +tests: + logging.backend.uart.single: + extra_args: DTC_OVERLAY_FILE="./single.overlay" + logging.backend.uart.multi: + extra_args: DTC_OVERLAY_FILE="./multi.overlay" From 28c5b1d76daa2d7510477532d0bd3260a110f6ef Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Tue, 7 Nov 2023 10:18:41 -0500 Subject: [PATCH 0257/1049] west: linkserver: update to reflect logging changes in 1.3.15 NXP released the linkserver update 1.3.15, which corrects an issue with logging that by default went out to stderr when flashing. Signed-off-by: Yves Vandervennet --- scripts/west_commands/runners/linkserver.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/west_commands/runners/linkserver.py b/scripts/west_commands/runners/linkserver.py index 5108d780aebd94c..a4ae5c622d448c8 100644 --- a/scripts/west_commands/runners/linkserver.py +++ b/scripts/west_commands/runners/linkserver.py @@ -111,7 +111,7 @@ def linkserver_version_str(self): if not hasattr(self, '_linkserver_version'): linkserver_version_cmd=[self.linkserver, "-v"] ls_output=self.check_output(linkserver_version_cmd) - self.linkserver_version = str(ls_output.split()[1].decode()) + self.linkserver_version = str(ls_output.split()[1].decode()).lower() return self.linkserver_version @@ -214,5 +214,9 @@ def flash(self, **kwargs): self.logger.debug("flash command = " + str(linkserver_cmd)) kwargs = {} if not self.logger.isEnabledFor(logging.DEBUG): - kwargs['stderr'] = subprocess.DEVNULL + if self.linkserver_version_str < "v1.3.15": + kwargs['stderr'] = subprocess.DEVNULL + else: + kwargs['stdout'] = subprocess.DEVNULL + self.check_call(linkserver_cmd, **kwargs) From 6c4b89cb007cf7b8337c4a310cc51089ee57214f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 9 Nov 2023 18:16:52 +0000 Subject: [PATCH 0258/1049] mgmt: mcumgr: grp: os_mgmt: Add datetime get/set functions Adds datetime set and get functions which allow for setting and getting the current time to/from the rtc alias device Signed-off-by: Jamie McCrae --- .../zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h | 6 + include/zephyr/mgmt/mcumgr/mgmt/callbacks.h | 6 + subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig | 21 ++ subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c | 268 ++++++++++++++++++ 4 files changed, 301 insertions(+) diff --git a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h index e1ac45e63897aae..505ee6554748271 100644 --- a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h @@ -41,6 +41,12 @@ enum os_mgmt_err_code_t { /** Query was not recognized. */ OS_MGMT_ERR_QUERY_YIELDS_NO_ANSWER, + + /** RTC is not set */ + OS_MGMT_ERR_RTC_NOT_SET, + + /** RTC command failed */ + OS_MGMT_ERR_RTC_COMMAND_FAILED, }; /* Bitmask values used by the os info command handler. Note that the width of this variable is diff --git a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h index c3a9a5687d855e6..43ee5ed6f95d3d3 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h @@ -197,6 +197,12 @@ enum os_mgmt_group_events { /** Callback when an info command needs to output data, data is os_mgmt_info_append. */ MGMT_EVT_OP_OS_MGMT_INFO_APPEND = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 2), + /** Callback when a datetime get command has been received. */ + MGMT_EVT_OP_OS_MGMT_DATETIME_GET = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 3), + + /** Callback when a datetime set command has been received, data is struct rtc_time(). */ + MGMT_EVT_OP_OS_MGMT_DATETIME_SET = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 4), + /** Used to enable all os_mgmt_group events. */ MGMT_EVT_OP_OS_MGMT_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_OS), }; diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig index fa743b53caf14c8..62245760a4757a0 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig @@ -135,6 +135,27 @@ config MCUMGR_GRP_OS_ECHO default y select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_2 +config MCUMGR_GRP_OS_DATETIME + bool "Support for datetime command" + depends on RTC + depends on $(dt_alias_enabled,rtc) + select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_2 + help + Enables support for the datetime get and set functions, this allows for using the + `rtc` alias device as a timesource from which the current time can be written or read. + +config MCUMGR_GRP_OS_DATETIME_MS + bool "Support millisecond field in datetime commands" + depends on MCUMGR_GRP_OS_DATETIME + +config MCUMGR_GRP_OS_DATETIME_HOOK + bool "Datetime hook" + depends on MCUMGR_GRP_OS_DATETIME + depends on MCUMGR_MGMT_NOTIFICATION_HOOKS + help + Allows applications to control and get notifications of when a datetime set/get + command has been issued via an MCUmgr command. + config MCUMGR_GRP_OS_MCUMGR_PARAMS bool "MCUMGR Parameters retrieval command" diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c index a42e2f4022fd42d..13de45f02a9f57a 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c @@ -33,6 +33,11 @@ #include #endif +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME +#include +#include +#endif + #if defined(CONFIG_MCUMGR_GRP_OS_INFO) || defined(CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO) #include #include @@ -78,6 +83,52 @@ struct thread_iterator_info { }; #endif +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME +/* Iterator for extracting values from the provided datetime string, min and max values are + * checked against the provided value, then the offset is added after. If the value is not + * within the min and max values, the set operation will be aborted. + */ +struct datetime_parser { + int *value; + int min_value; + int max_value; + int offset; +}; + +/* RTC device alias to use for datetime functions, "rtc" */ +#define RTC_DEVICE DEVICE_DT_GET(DT_ALIAS(rtc)) + +#define RTC_DATETIME_YEAR_OFFSET 1900 +#define RTC_DATETIME_MONTH_OFFSET 1 +#define RTC_DATETIME_NUMERIC_BASE 10 +#define RTC_DATETIME_MS_TO_NS 1000000 +#define RTC_DATETIME_YEAR_MIN 1900 +#define RTC_DATETIME_YEAR_MAX 11899 +#define RTC_DATETIME_MONTH_MIN 1 +#define RTC_DATETIME_MONTH_MAX 12 +#define RTC_DATETIME_DAY_MIN 1 +#define RTC_DATETIME_DAY_MAX 31 +#define RTC_DATETIME_HOUR_MIN 0 +#define RTC_DATETIME_HOUR_MAX 23 +#define RTC_DATETIME_MINUTE_MIN 0 +#define RTC_DATETIME_MINUTE_MAX 59 +#define RTC_DATETIME_SECOND_MIN 0 +#define RTC_DATETIME_SECOND_MAX 59 +#define RTC_DATETIME_MILLISECOND_MIN 0 +#define RTC_DATETIME_MILLISECOND_MAX 999 + +/* Size used for datetime creation buffer */ +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS +#define RTC_DATETIME_STRING_SIZE 32 +#else +#define RTC_DATETIME_STRING_SIZE 26 +#endif + +/* Minimum/maximum size of a datetime string that a client can provide */ +#define RTC_DATETIME_MIN_STRING_SIZE 19 +#define RTC_DATETIME_MAX_STRING_SIZE 26 +#endif + /* Specifies what the "all" ('a') of info parameter shows */ #define OS_MGMT_INFO_FORMAT_ALL \ OS_MGMT_INFO_FORMAT_KERNEL_NAME | OS_MGMT_INFO_FORMAT_NODE_NAME | \ @@ -744,6 +795,210 @@ static int os_mgmt_info(struct smp_streamer *ctxt) } #endif +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME +/** + * Command handler: os datetime get + */ +static int os_mgmt_datetime_read(struct smp_streamer *ctxt) +{ + zcbor_state_t *zse = ctxt->writer->zs; + struct rtc_time current_time; + char date_string[RTC_DATETIME_STRING_SIZE]; + int rc; + bool ok; + +#if defined(CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK) + enum mgmt_cb_return status; + int32_t err_rc; + uint16_t err_group; + + status = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_DATETIME_GET, NULL, 0, &err_rc, + &err_group); + + if (status != MGMT_CB_OK) { + if (status == MGMT_CB_ERROR_RC) { + return err_rc; + } + + ok = smp_add_cmd_err(zse, err_group, (uint16_t)err_rc); + return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; + } +#endif + + rc = rtc_get_time(RTC_DEVICE, ¤t_time); + + if (rc == -ENODATA) { + /* RTC not set */ + ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_OS, OS_MGMT_ERR_RTC_NOT_SET); + goto finished; + } else if (rc != 0) { + /* Other RTC error */ + ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_OS, OS_MGMT_ERR_RTC_COMMAND_FAILED); + goto finished; + } + + sprintf(date_string, "%4d-%02d-%02dT%02d:%02d:%02d" +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS + ".%d" +#endif + , (uint16_t)(current_time.tm_year + RTC_DATETIME_YEAR_OFFSET), + (uint8_t)(current_time.tm_mon + RTC_DATETIME_MONTH_OFFSET), + (uint8_t)current_time.tm_mday, (uint8_t)current_time.tm_hour, + (uint8_t)current_time.tm_min, (uint8_t)current_time.tm_sec +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS + , (uint16_t)(current_time.tm_nsec / RTC_DATETIME_MS_TO_NS) +#endif + ); + + ok = zcbor_tstr_put_lit(zse, "datetime") && + zcbor_tstr_encode_ptr(zse, date_string, strlen(date_string)); + +finished: + return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; +} + +/** + * Command handler: os datetime set + */ +static int os_mgmt_datetime_write(struct smp_streamer *ctxt) +{ + zcbor_state_t *zsd = ctxt->reader->zs; + zcbor_state_t *zse = ctxt->writer->zs; + size_t decoded; + struct zcbor_string datetime = { 0 }; + int rc; + uint8_t i = 0; + bool ok = true; + char *pos; + char *new_pos; + char date_string[RTC_DATETIME_MAX_STRING_SIZE]; + struct rtc_time new_time = { + .tm_wday = -1, + .tm_yday = -1, + .tm_isdst = -1, + .tm_nsec = 0, + }; + struct datetime_parser parser[] = { + { + .value = &new_time.tm_year, + .min_value = RTC_DATETIME_YEAR_MIN, + .max_value = RTC_DATETIME_YEAR_MAX, + .offset = -RTC_DATETIME_YEAR_OFFSET, + }, + { + .value = &new_time.tm_mon, + .min_value = RTC_DATETIME_MONTH_MIN, + .max_value = RTC_DATETIME_MONTH_MAX, + .offset = -RTC_DATETIME_MONTH_OFFSET, + }, + { + .value = &new_time.tm_mday, + .min_value = RTC_DATETIME_DAY_MIN, + .max_value = RTC_DATETIME_DAY_MAX, + }, + { + .value = &new_time.tm_hour, + .min_value = RTC_DATETIME_HOUR_MIN, + .max_value = RTC_DATETIME_HOUR_MAX, + }, + { + .value = &new_time.tm_min, + .min_value = RTC_DATETIME_MINUTE_MIN, + .max_value = RTC_DATETIME_MINUTE_MAX, + }, + { + .value = &new_time.tm_sec, + .min_value = RTC_DATETIME_SECOND_MIN, + .max_value = RTC_DATETIME_SECOND_MAX, + }, + }; + +#if defined(CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK) + enum mgmt_cb_return status; + int32_t err_rc; + uint16_t err_group; +#endif + + struct zcbor_map_decode_key_val datetime_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &datetime), + }; + + if (zcbor_map_decode_bulk(zsd, datetime_decode, ARRAY_SIZE(datetime_decode), &decoded)) { + return MGMT_ERR_EINVAL; + } else if (datetime.len < RTC_DATETIME_MIN_STRING_SIZE || + datetime.len >= RTC_DATETIME_MAX_STRING_SIZE) { + return MGMT_ERR_EINVAL; + } + + memcpy(date_string, datetime.value, datetime.len); + date_string[datetime.len] = '\0'; + + pos = date_string; + + while (i < ARRAY_SIZE(parser)) { + if (pos == (date_string + datetime.len)) { + /* Encountered end of string early, this is invalid */ + return MGMT_ERR_EINVAL; + } + + *parser[i].value = strtol(pos, &new_pos, RTC_DATETIME_NUMERIC_BASE); + + if (pos == new_pos) { + /* Missing or unable to convert field */ + return MGMT_ERR_EINVAL; + } + + if (*parser[i].value < parser[i].min_value || + *parser[i].value > parser[i].max_value) { + /* Value is not within the allowed bounds of this field */ + return MGMT_ERR_EINVAL; + } + + *parser[i].value += parser[i].offset; + + /* Skip a character as there is always a delimiter between the fields */ + ++i; + pos = new_pos + 1; + } + +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS + if (*(pos - 1) == '.' && *pos != '\0') { + /* Provided value has a ms value, extract it */ + new_time.tm_nsec = strtol(pos, &new_pos, RTC_DATETIME_NUMERIC_BASE); + + if (new_time.tm_nsec < RTC_DATETIME_MILLISECOND_MIN || + new_time.tm_nsec > RTC_DATETIME_MILLISECOND_MAX) { + return MGMT_ERR_EINVAL; + } + + new_time.tm_nsec *= RTC_DATETIME_MS_TO_NS; + } +#endif + +#if defined(CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK) + status = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_DATETIME_SET, &new_time, + sizeof(new_time), &err_rc, &err_group); + + if (status != MGMT_CB_OK) { + if (status == MGMT_CB_ERROR_RC) { + return err_rc; + } + + ok = smp_add_cmd_err(zse, err_group, (uint16_t)err_rc); + return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; + } +#endif + + rc = rtc_set_time(RTC_DEVICE, &new_time); + + if (rc != 0) { + ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_OS, OS_MGMT_ERR_RTC_COMMAND_FAILED); + } + + return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; +} +#endif + #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL /* * @brief Translate OS mgmt group error code into MCUmgr error code @@ -761,7 +1016,13 @@ static int os_mgmt_translate_error_code(uint16_t err) rc = MGMT_ERR_EINVAL; break; + case OS_MGMT_ERR_QUERY_YIELDS_NO_ANSWER: + case OS_MGMT_ERR_RTC_NOT_SET: + rc = MGMT_ERR_ENOENT; + break; + case OS_MGMT_ERR_UNKNOWN: + case OS_MGMT_ERR_RTC_COMMAND_FAILED: default: rc = MGMT_ERR_EUNKNOWN; } @@ -781,6 +1042,13 @@ static const struct mgmt_handler os_mgmt_group_handlers[] = { os_mgmt_taskstat_read, NULL }, #endif + +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME + [OS_MGMT_ID_DATETIME_STR] = { + os_mgmt_datetime_read, os_mgmt_datetime_write + }, +#endif + #ifdef CONFIG_REBOOT [OS_MGMT_ID_RESET] = { NULL, os_mgmt_reset From 1855fd16f795a91b296e02dd4e6b2a44fa6e84b4 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 9 Nov 2023 18:17:08 +0000 Subject: [PATCH 0259/1049] tests: mgmt: mcumgr: Add os_mgmt_datetime test Adds a test which tests datetime set/get and hook callbacks Signed-off-by: Jamie McCrae --- .../mcumgr/os_mgmt_datetime/CMakeLists.txt | 17 + .../boards/native_posix.overlay | 14 + .../boards/qemu_arc_hs6x.overlay | 14 + .../boards/qemu_cortex_m0.overlay | 14 + .../boards/qemu_leon3.overlay | 14 + .../boards/qemu_malta.overlay | 14 + .../os_mgmt_datetime/boards/qemu_riscv64.conf | 1 + .../boards/qemu_riscv64.overlay | 14 + .../boards/qemu_riscv64_smp.conf | 1 + .../boards/qemu_riscv64_smp.overlay | 14 + .../mgmt/mcumgr/os_mgmt_datetime/prj.conf | 21 + .../mgmt/mcumgr/os_mgmt_datetime/src/main.c | 1495 +++++++++++++++++ .../os_mgmt_datetime/src/smp_test_util.c | 77 + .../os_mgmt_datetime/src/smp_test_util.h | 35 + .../mcumgr/os_mgmt_datetime/testcase.yaml | 19 + 15 files changed, 1764 insertions(+) create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/CMakeLists.txt create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/native_posix.overlay create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_arc_hs6x.overlay create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_cortex_m0.overlay create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_leon3.overlay create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_malta.overlay create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64.conf create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64.overlay create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64_smp.conf create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64_smp.overlay create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/prj.conf create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.h create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/CMakeLists.txt new file mode 100644 index 000000000000000..5f75eeb5bfa14b0 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Copyright (c) 2023 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(os_mgmt_info) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/grp/os_mgmt/include/) diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/native_posix.overlay b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/native_posix.overlay new file mode 100644 index 000000000000000..4021ce2ae8683e7 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/native_posix.overlay @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + }; +}; diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_arc_hs6x.overlay b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_arc_hs6x.overlay new file mode 100644 index 000000000000000..4021ce2ae8683e7 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_arc_hs6x.overlay @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + }; +}; diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_cortex_m0.overlay b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_cortex_m0.overlay new file mode 100644 index 000000000000000..4021ce2ae8683e7 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_cortex_m0.overlay @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + }; +}; diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_leon3.overlay b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_leon3.overlay new file mode 100644 index 000000000000000..4021ce2ae8683e7 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_leon3.overlay @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + }; +}; diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_malta.overlay b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_malta.overlay new file mode 100644 index 000000000000000..4021ce2ae8683e7 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_malta.overlay @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + }; +}; diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64.conf new file mode 100644 index 000000000000000..1ede042960b6076 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64.conf @@ -0,0 +1 @@ +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64.overlay b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64.overlay new file mode 100644 index 000000000000000..4021ce2ae8683e7 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64.overlay @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + }; +}; diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64_smp.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64_smp.conf new file mode 100644 index 000000000000000..1ede042960b6076 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64_smp.conf @@ -0,0 +1 @@ +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64_smp.overlay b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64_smp.overlay new file mode 100644 index 000000000000000..4021ce2ae8683e7 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/boards/qemu_riscv64_smp.overlay @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + }; +}; diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/prj.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/prj.conf new file mode 100644 index 000000000000000..0cf01e6335b6f0e --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/prj.conf @@ -0,0 +1,21 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_ZTEST=y +CONFIG_RTC=y +CONFIG_NET_BUF=y +CONFIG_BASE64=y +CONFIG_ZCBOR=y +CONFIG_CRC=y +CONFIG_MCUMGR=y +CONFIG_MCUMGR_TRANSPORT_DUMMY=y +CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE=256 +CONFIG_MCUMGR_GRP_OS=y +CONFIG_MCUMGR_GRP_OS_ECHO=n +CONFIG_MCUMGR_GRP_OS_DATETIME=y +CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK=y +CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=y +CONFIG_ZTEST_STACK_SIZE=2048 +CONFIG_REBOOT=n diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c new file mode 100644 index 000000000000000..c387c3b4812a842 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c @@ -0,0 +1,1495 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2023 Jamie M. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_test_util.h" + +#define SMP_RESPONSE_WAIT_TIME 3 +#define ZCBOR_BUFFER_SIZE 256 +#define OUTPUT_BUFFER_SIZE 256 +#define ZCBOR_HISTORY_ARRAY_SIZE 4 + +/* Test sets */ +enum { + OS_MGMT_DATETIME_TEST_SET_TIME_NOT_SET = 0, + OS_MGMT_DATETIME_TEST_SET_TIME_SET, +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK + OS_MGMT_DATETIME_TEST_SET_HOOKS, +#endif + + OS_MGMT_DATETIME_TEST_SET_COUNT +}; + +static struct net_buf *nb; + +struct state { + uint8_t test_set; +}; + +static struct state test_state = { + .test_set = 0, +}; + +static struct rtc_time valid_time = { + .tm_sec = 13, + .tm_min = 40, + .tm_hour = 4, + .tm_mday = 4, + .tm_mon = 8, + .tm_year = 2023, +}; + +static struct rtc_time valid_time2 = { + .tm_sec = 5, + .tm_min = 4, + .tm_hour = 3, + .tm_mday = 2, + .tm_mon = 1, + .tm_year = 2001, +}; + +static const char valid_time_string[] = "2023-08-04T04:40:13"; +static const char valid_time2_string[] = "2001-01-02T03:04:05"; +static const char invalid_time_string[] = "abcdefghij"; +static const char invalid_time2_string[] = "20a1-b1-aTbb:dd:qq"; +static const char invalid_time3_string[] = "1820-01-02T03:04:05"; + +struct group_error { + uint16_t group; + uint16_t rc; + bool found; +}; + +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK +static bool hook_get_ran; +static bool hook_set_ran; +static bool hook_other_ran; +static uint8_t hook_set_data_size; +static uint8_t hook_set_data[64]; +#endif + +static void cleanup_test(void *p); + +static bool mcumgr_ret_decode(zcbor_state_t *state, struct group_error *result) +{ + bool ok; + size_t decoded; + uint32_t tmp_group; + uint32_t tmp_rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("group", zcbor_uint32_decode, &tmp_group), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_uint32_decode, &tmp_rc), + }; + + result->found = false; + + ok = zcbor_map_decode_bulk(state, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + if (ok && + zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "group") && + zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "rc")) { + result->group = (uint16_t)tmp_group; + result->rc = (uint16_t)tmp_rc; + result->found = true; + } + + return ok; +} + +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK +static enum mgmt_cb_return os_mgmt_datetime_callback(uint32_t event, + enum mgmt_cb_return prev_status, int32_t *rc, + uint16_t *group, bool *abort_more, + void *data, size_t data_size) +{ + if (event == MGMT_EVT_OP_OS_MGMT_DATETIME_GET) { + hook_get_ran = true; + + *rc = MGMT_ERR_EBUSY; + return MGMT_CB_ERROR_RC; + } else if (event == MGMT_EVT_OP_OS_MGMT_DATETIME_SET) { + hook_set_ran = true; + hook_set_data_size = data_size; + memcpy(hook_set_data, data, data_size); + + *rc = MGMT_ERR_EACCESSDENIED; + return MGMT_CB_ERROR_RC; + } + + hook_other_ran = true; + return MGMT_CB_OK; +} + +static struct mgmt_callback os_datetime_callbacks = { + .callback = os_mgmt_datetime_callback, + .event_id = (MGMT_EVT_OP_OS_MGMT_DATETIME_GET | MGMT_EVT_OP_OS_MGMT_DATETIME_SET), +}; +#endif + +ZTEST(os_mgmt_datetime_not_set, test_datetime_get_not_set_v1) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, false, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Expected to receive err element"); + zassert_equal(rc, MGMT_ERR_ENOENT, "Expected 'rc' to be no entity"); +} + +ZTEST(os_mgmt_datetime_not_set, test_datetime_get_not_set_v2) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, true, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Expected to receive err element"); + zassert_equal(group_error.group, MGMT_GROUP_ID_OS, "Expected 'err' -> 'group' to be OS"); + zassert_equal(group_error.rc, OS_MGMT_ERR_RTC_NOT_SET, + "Expected 'err' -> 'rc' to be RTC not set"); +} + +ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v1_1) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet_str(zse, false, invalid_time_string, buffer, + buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected 'rc' to be invalid value"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is not set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, false, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Expected to receive err element"); + zassert_equal(rc, MGMT_ERR_ENOENT, "Expected 'rc' to be no entity"); +} + +ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v1_2) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet_str(zse, false, invalid_time2_string, buffer, + buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected 'rc' to be invalid value"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is not set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, false, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Expected to receive err element"); + zassert_equal(rc, MGMT_ERR_ENOENT, "Expected 'rc' to be no entity"); +} + +ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v1_3) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet_str(zse, false, invalid_time3_string, buffer, + buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected 'rc' to be invalid value"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is not set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, false, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Expected to receive err element"); + zassert_equal(rc, MGMT_ERR_ENOENT, "Expected 'rc' to be no entity"); +} + +ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v2_1) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet_str(zse, true, invalid_time2_string, buffer, + buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected 'rc' to be invalid value"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is not set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, true, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Expected to receive err element"); + zassert_equal(group_error.group, MGMT_GROUP_ID_OS, "Expected 'err' -> 'group' to be OS"); + zassert_equal(group_error.rc, OS_MGMT_ERR_RTC_NOT_SET, + "Expected 'err' -> 'rc' to be RTC not set"); +} + +ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v2_2) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet_str(zse, true, invalid_time2_string, buffer, + buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected 'rc' to be invalid value"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is not set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, true, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Expected to receive err element"); + zassert_equal(group_error.group, MGMT_GROUP_ID_OS, "Expected 'err' -> 'group' to be OS"); + zassert_equal(group_error.rc, OS_MGMT_ERR_RTC_NOT_SET, + "Expected 'err' -> 'rc' to be RTC not set"); +} + +ZTEST(os_mgmt_datetime_not_set, test_datetime_set_invalid_v2_3) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet_str(zse, true, invalid_time3_string, buffer, + buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected 'rc' to be invalid value"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is not set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, true, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Expected to receive err element"); + zassert_equal(group_error.group, MGMT_GROUP_ID_OS, "Expected 'err' -> 'group' to be OS"); + zassert_equal(group_error.rc, OS_MGMT_ERR_RTC_NOT_SET, + "Expected 'err' -> 'rc' to be RTC not set"); +} + +ZTEST(os_mgmt_datetime_set, test_datetime_set_v1) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet(zse, false, &valid_time, buffer, buffer_out, + &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 0, "Did not expect to receive any decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, false, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Expected to receive datetime element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expected to receive err element"); + + /* Check that the date/time is as expected */ + zassert_equal(output.len, strlen(valid_time_string), + "Expected received datetime length mismatch"); + zassert_mem_equal(output.value, valid_time_string, strlen(valid_time_string), + "Expected received datetime value mismatch"); +} + +ZTEST(os_mgmt_datetime_set, test_datetime_set_v2) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet(zse, true, &valid_time2, buffer, buffer_out, + &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 0, "Did not expect to receive any decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, false, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Expected to receive datetime element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Did not expect to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expected to receive err element"); + + /* Check that the date/time is as expected */ + zassert_equal(output.len, strlen(valid_time2_string), + "Expected received datetime length mismatch"); + zassert_mem_equal(output.value, valid_time2_string, strlen(valid_time2_string), + "Expected received datetime value mismatch"); +} + +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK +static void *setup_os_datetime_callbacks(void) +{ + mgmt_callback_register(&os_datetime_callbacks); + return NULL; +} + +static void destroy_os_datetime_callbacks(void *p) +{ + mgmt_callback_unregister(&os_datetime_callbacks); +} + +ZTEST(os_mgmt_datetime_hook, test_datetime_set_valid_hook_v1) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + struct rtc_time *hook_data; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet(zse, false, &valid_time2, buffer, buffer_out, + &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EACCESSDENIED, "Expected 'rc' to be access denied"); + + /* Check hook actions are as expected */ + hook_data = (struct rtc_time *)hook_set_data; + zassert_false(hook_get_ran, "Did not expect get hook to run"); + zassert_true(hook_set_ran, "Expected set hook to run"); + zassert_false(hook_other_ran, "Did not expect other hooks to run"); + zassert_equal(hook_set_data_size, sizeof(valid_time2), + "Expected data size to match time struct size"); + zassert_equal(valid_time2.tm_sec, hook_data->tm_sec, "Expected value mismatch"); + zassert_equal(valid_time2.tm_min, hook_data->tm_min, "Expected value mismatch"); + zassert_equal(valid_time2.tm_hour, hook_data->tm_hour, "Expected value mismatch"); + zassert_equal(valid_time2.tm_mday, hook_data->tm_mday, "Expected value mismatch"); + zassert_equal(valid_time2.tm_mon, (hook_data->tm_mon + 1), "Expected value mismatch"); + zassert_equal(valid_time2.tm_year, (hook_data->tm_year + 1900), + "Expected value mismatch"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is not set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, false, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EBUSY, "Expected 'rc' to be busy"); + + /* Check hook actions are as expected */ + zassert_true(hook_get_ran, "Expected get hook to run"); + zassert_false(hook_set_ran, "Did not expect set hook to run"); + zassert_false(hook_other_ran, "Did not expect other hooks to run"); + zassert_equal(hook_set_data_size, 0, "Expected data size to be 0"); +} + +ZTEST(os_mgmt_datetime_hook, test_datetime_set_valid_hook_v2) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + struct group_error group_error; + int rc; + struct rtc_time *hook_data; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 4, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_set_packet(zse, true, &valid_time2, buffer, buffer_out, + &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EACCESSDENIED, "Expected 'rc' to be access denied"); + + /* Check hook actions are as expected */ + hook_data = (struct rtc_time *)hook_set_data; + zassert_false(hook_get_ran, "Did not expect get hook to run"); + zassert_true(hook_set_ran, "Expected set hook to run"); + zassert_false(hook_other_ran, "Did not expect other hooks to run"); + zassert_equal(hook_set_data_size, sizeof(valid_time2), + "Expected data size to match time struct size"); + zassert_equal(valid_time2.tm_sec, hook_data->tm_sec, "Expected value mismatch"); + zassert_equal(valid_time2.tm_min, hook_data->tm_min, "Expected value mismatch"); + zassert_equal(valid_time2.tm_hour, hook_data->tm_hour, "Expected value mismatch"); + zassert_equal(valid_time2.tm_mday, hook_data->tm_mday, "Expected value mismatch"); + zassert_equal(valid_time2.tm_mon, (hook_data->tm_mon + 1), "Expected value mismatch"); + zassert_equal(valid_time2.tm_year, (hook_data->tm_year + 1900), "Expected value mismatch"); + + /* Clean up test */ + cleanup_test(NULL); + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + output_decode[0].found = false; + output_decode[1].found = false; + output_decode[2].found = false; + + /* Query time and ensure it is not set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, true, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), "Did not expect to receive datetime element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "rc"), "Expected to receive rc element"); + zassert_false(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "err"), "Did not expect to receive err element"); + zassert_equal(rc, MGMT_ERR_EBUSY, "Expected 'rc' to be busy"); + + /* Check hook actions are as expected */ + zassert_true(hook_get_ran, "Expected get hook to run"); + zassert_false(hook_set_ran, "Did not expect set hook to run"); + zassert_false(hook_other_ran, "Did not expect other hooks to run"); + zassert_equal(hook_set_data_size, 0, "Expected data size to be 0"); +} +#endif + +static void cleanup_test(void *p) +{ + if (nb != NULL) { + net_buf_unref(nb); + nb = NULL; + } + +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK + hook_get_ran = false; + hook_set_ran = false; + hook_other_ran = false; + hook_set_data_size = 0; + hook_set_data[0] = 0; +#endif +} + +void test_main(void) +{ + while (test_state.test_set < OS_MGMT_DATETIME_TEST_SET_COUNT) { + ztest_run_all(&test_state); + ++test_state.test_set; + } + + ztest_verify_all_test_suites_ran(); +} + +static bool time_not_set_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_DATETIME_TEST_SET_TIME_NOT_SET; +} + +static bool time_set_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_DATETIME_TEST_SET_TIME_SET; +} + +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK +static bool hooks_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_DATETIME_TEST_SET_HOOKS; +} +#endif + +/* Time not set test set */ +ZTEST_SUITE(os_mgmt_datetime_not_set, time_not_set_predicate, NULL, NULL, cleanup_test, NULL); + +#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK +/* Hook test set */ +ZTEST_SUITE(os_mgmt_datetime_hook, hooks_predicate, setup_os_datetime_callbacks, NULL, + cleanup_test, destroy_os_datetime_callbacks); +#endif + +/* Time set test set */ +ZTEST_SUITE(os_mgmt_datetime_set, time_set_predicate, NULL, NULL, cleanup_test, NULL); diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c new file mode 100644 index 000000000000000..927089c3ee360f8 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023 Jamie M. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "smp_test_util.h" +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt datetime command header with sequence number set + * to 1 + */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len, bool version2, bool write) +{ + *rsp_hdr = (struct smp_hdr) { + .nh_len = sys_cpu_to_be16(len), + .nh_flags = 0, + .nh_version = (version2 == true ? SMP_MCUMGR_VERSION_2 : SMP_MCUMGR_VERSION_1), + .nh_op = (write == true ? MGMT_OP_WRITE : MGMT_OP_READ), + .nh_group = sys_cpu_to_be16(MGMT_GROUP_ID_OS), + .nh_seq = 1, + .nh_id = OS_MGMT_ID_DATETIME_STR, + }; +} + +/* Function for creating an os_mgmt datetime get command */ +bool create_mcumgr_datetime_get_packet(zcbor_state_t *zse, bool version2, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size) +{ + bool ok; + + ok = zcbor_map_start_encode(zse, 2) && + zcbor_map_end_encode(zse, 2); + + *buffer_size = (zse->payload_mut - buffer); + smp_make_hdr((struct smp_hdr *)output_buffer, *buffer_size, version2, false); + memcpy(&output_buffer[sizeof(struct smp_hdr)], buffer, *buffer_size); + *buffer_size += sizeof(struct smp_hdr); + + return ok; +} + +/* Functions for creating an os_mgmt datetime set command */ +bool create_mcumgr_datetime_set_packet_str(zcbor_state_t *zse, bool version2, const char *data, + uint8_t *buffer, uint8_t *output_buffer, + uint16_t *buffer_size) +{ + bool ok = zcbor_map_start_encode(zse, 2) && + zcbor_tstr_put_lit(zse, "datetime") && + zcbor_tstr_put_term(zse, data) && + zcbor_map_end_encode(zse, 2); + + *buffer_size = (zse->payload_mut - buffer); + smp_make_hdr((struct smp_hdr *)output_buffer, *buffer_size, version2, true); + memcpy(&output_buffer[sizeof(struct smp_hdr)], buffer, *buffer_size); + *buffer_size += sizeof(struct smp_hdr); + + return ok; +} + +bool create_mcumgr_datetime_set_packet(zcbor_state_t *zse, bool version2, struct rtc_time *a_time, + uint8_t *buffer, uint8_t *output_buffer, + uint16_t *buffer_size) +{ + char tmp_str[32]; + + sprintf(tmp_str, "%4d-%02d-%02dT%02d:%02d:%02d", (uint16_t)a_time->tm_year, + (uint8_t)a_time->tm_mon, (uint8_t)a_time->tm_mday, (uint8_t)a_time->tm_hour, + (uint8_t)a_time->tm_min, (uint8_t)a_time->tm_sec); + + return create_mcumgr_datetime_set_packet_str(zse, version2, tmp_str, buffer, + output_buffer, buffer_size); +} diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.h b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.h new file mode 100644 index 000000000000000..958ccfdd5ad34b4 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023 Jamie M. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_SMP_TEST_UTIL_ +#define H_SMP_TEST_UTIL_ + +#include +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt datetime command header with sequence number set + * to 1 + */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len, bool version2, bool write); + +/* Function for creating an os_mgmt datetime get command */ +bool create_mcumgr_datetime_get_packet(zcbor_state_t *zse, bool version2, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size); + +/* Function for creating an os_mgmt datetime set command */ +bool create_mcumgr_datetime_set_packet_str(zcbor_state_t *zse, bool version2, const char *data, + uint8_t *buffer, uint8_t *output_buffer, + uint16_t *buffer_size); + +bool create_mcumgr_datetime_set_packet(zcbor_state_t *zse, bool version2, struct rtc_time *a_time, + uint8_t *buffer, uint8_t *output_buffer, + uint16_t *buffer_size); + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml new file mode 100644 index 000000000000000..013a371c9a02400 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml @@ -0,0 +1,19 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +common: + tags: + - mcumgr + - os_mgmt_datetime + platform_allow: + - native_posix + - qemu_cortex_m0 + - qemu_riscv64 + - qemu_riscv64_smp + - qemu_malta + - qemu_arc_hs6x + - qemu_leon3 +tests: + mgmt.mcumgr.os.datetime: {} From 20f0e37413863986064a2c00241afb09232761d0 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 9 Nov 2023 18:18:57 +0000 Subject: [PATCH 0260/1049] doc: release: 3.6: Add note on MCUmgr OS mgmt datetime Adds a note that datetime support has been added to MCUmgr Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index 3c1248222ee5d88..676e16fa77cdcfa 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -247,6 +247,9 @@ Libraries / Subsystems * Fixed an issue in MCUmgr which would cause a user data buffer overflow if the UDP transport was enabled on IPv4 only but IPv6 support was enabled in the kernel. + * Implemented datetime functionality in MCUmgr OS management group, this makes use of the RTC + driver API. + * File systems * Modem modules From 5c05b61ecde1fa407173ba936fab94b151ca5400 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 10 Nov 2023 08:02:45 +0000 Subject: [PATCH 0261/1049] doc: mgmt: mcumgr: Remove OS mgmt datetime unimplemented note This functionality is now implemented Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/smp_groups/smp_group_0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/device_mgmt/smp_groups/smp_group_0.rst b/doc/services/device_mgmt/smp_groups/smp_group_0.rst index ba15ac22a1d23d8..7fb91463e336f6a 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_0.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_0.rst @@ -20,7 +20,7 @@ OS management group defines following commands: +-------------------+-----------------------------------------------+ | ``3`` | Memory pool statistics | +-------------------+-----------------------------------------------+ - | ``4`` | Date-time string; unimplemented by Zephyr | + | ``4`` | Date-time string | +-------------------+-----------------------------------------------+ | ``5`` | System reset | +-------------------+-----------------------------------------------+ From 1032fe3b5c18e52c952a705014f91327a0ce3928 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Tue, 7 Nov 2023 18:57:11 +0100 Subject: [PATCH 0262/1049] tests: coredump: Extend backends test coverage Extend coredump_backend tests: * fix COREDUMP_CMD_VERIFY_STORED_DUMP test was not executed. * add tests for these coredump commands: - COREDUMP_QUERY_GET_STORED_DUMP_SIZE, - COREDUMP_CMD_INVALIDATE_STORED_DUMP, - COREDUMP_CMD_ERASE_STORED_DUMP, - COREDUMP_CMD_CLEAR_ERROR. * extend the out-of-the-treee example 'empty' backend to execute the new tests. * fix the test's cmake project name. Signed-off-by: Dmitrii Golovanov --- .../debug/coredump_backends/CMakeLists.txt | 2 +- tests/subsys/debug/coredump_backends/Kconfig | 17 ++ .../src/coredump_backend_empty.c | 11 + .../subsys/debug/coredump_backends/src/main.c | 198 ++++++++++++++++-- .../debug/coredump_backends/testcase.yaml | 6 + 5 files changed, 217 insertions(+), 17 deletions(-) create mode 100644 tests/subsys/debug/coredump_backends/Kconfig diff --git a/tests/subsys/debug/coredump_backends/CMakeLists.txt b/tests/subsys/debug/coredump_backends/CMakeLists.txt index a7d48d53d4fc175..5ae2b1f792cf09b 100644 --- a/tests/subsys/debug/coredump_backends/CMakeLists.txt +++ b/tests/subsys/debug/coredump_backends/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(hello_world) +project(debug_coredump_backends) target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/debug/coredump_backends/Kconfig b/tests/subsys/debug/coredump_backends/Kconfig new file mode 100644 index 000000000000000..dc02b1341a2e37e --- /dev/null +++ b/tests/subsys/debug/coredump_backends/Kconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config TEST_STORED_COREDUMP + bool "Expected backend has coredump storage." + help + Set if the test expects coredump backend with storage. + +config TEST_STORED_DUMP_SIZE + int "Expected backend's coredump storage size." + default 0 + help + Test expects coredump backend storage with the size given. + If zero, then it is ignored and not compared with the actual size. diff --git a/tests/subsys/debug/coredump_backends/src/coredump_backend_empty.c b/tests/subsys/debug/coredump_backends/src/coredump_backend_empty.c index 82cee0b70d9671f..ce3229bbeba444d 100644 --- a/tests/subsys/debug/coredump_backends/src/coredump_backend_empty.c +++ b/tests/subsys/debug/coredump_backends/src/coredump_backend_empty.c @@ -42,6 +42,9 @@ static int coredump_empty_backend_query(enum coredump_query_id query_id, ret = 1; } break; + case COREDUMP_QUERY_GET_STORED_DUMP_SIZE: + ret = 0; + break; default: ret = -ENOTSUP; break; @@ -66,6 +69,14 @@ static int coredump_empty_backend_cmd(enum coredump_cmd_id cmd_id, ret = 1; } break; + case COREDUMP_CMD_INVALIDATE_STORED_DUMP: + is_valid = false; + ret = 0; + break; + case COREDUMP_CMD_ERASE_STORED_DUMP: + is_valid = false; + ret = 0; + break; default: ret = -ENOTSUP; break; diff --git a/tests/subsys/debug/coredump_backends/src/main.c b/tests/subsys/debug/coredump_backends/src/main.c index f855d0477518338..8b7636edbd9f694 100644 --- a/tests/subsys/debug/coredump_backends/src/main.c +++ b/tests/subsys/debug/coredump_backends/src/main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2014 Wind River Systems, Inc. + * Copyright (c) 2020-2023, Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ @@ -34,7 +35,7 @@ void dump_entry(void *p1, void *p2, void *p3) irq_unlock(key); } -static void check_errors(void) +void check_error(void) { int ret; @@ -45,10 +46,23 @@ static void check_errors(void) } } -void test_coredump(void) +void clear_error(void) +{ + int ret; + + /* Clear backend error if backend supports this query */ + ret = coredump_cmd(COREDUMP_CMD_CLEAR_ERROR, NULL); + if (ret != -ENOTSUP) { + zassert_equal(ret, 0, "Error encountered! (%d)", ret); + } +} + +static void *raise_coredump(void) { k_tid_t tid; + clear_error(); + /* Create a thread that crashes */ tid = k_thread_create(&dump_thread, dump_stack, K_THREAD_STACK_SIZEOF(dump_stack), @@ -57,28 +71,46 @@ void test_coredump(void) k_thread_join(tid, K_FOREVER); - check_errors(); + return &dump_thread; } -void test_query_stored_dump(void) +void test_has_stored_dump(bool is_expected) { int ret; /* Cannot proceed with previous errors */ - check_errors(); + check_error(); /* There should be a stored coredump now if backend has storage */ ret = coredump_query(COREDUMP_QUERY_HAS_STORED_DUMP, NULL); if (ret == -ENOTSUP) { +#ifdef CONFIG_TEST_STORED_COREDUMP + TC_ERROR("Can't query stored dump: unexpectedly not supported.\n"); + ztest_test_fail(); +#else + TC_PRINT("Can't query stored dump: expectedly not supported.\n"); ztest_test_skip(); +#endif } else if (ret == 1) { - check_errors(); +#ifdef CONFIG_TEST_STORED_COREDUMP + check_error(); + zassert_true(is_expected, "Unexpected coredump found.\n"); ztest_test_pass(); +#else + TC_ERROR("Can't have a stored dump: not supported.\n"); + ztest_test_fail(); +#endif } else if (ret == 0) { - TC_PRINT("Should have stored dump!\n"); +#ifdef CONFIG_TEST_STORED_COREDUMP + check_error(); + zassert_false(is_expected, "Should have stored dump!\n"); + ztest_test_pass(); +#else + TC_ERROR("Can't have an empty stored dump: not supported.\n"); ztest_test_fail(); +#endif } else { - TC_PRINT("Error reading stored dump! (%d)\n", ret); + TC_ERROR("Error reading stored dump! (%d)\n", ret); ztest_test_fail(); } } @@ -88,28 +120,162 @@ void test_verify_stored_dump(void) int ret; /* Cannot proceed with previous errors */ - check_errors(); + check_error(); /* There should be a stored coredump now if backend has storage */ ret = coredump_cmd(COREDUMP_CMD_VERIFY_STORED_DUMP, NULL); if (ret == -ENOTSUP) { +#ifdef CONFIG_TEST_STORED_COREDUMP + TC_ERROR("Can't verify stored dump: unexpectedly not supported.\n"); + ztest_test_fail(); +#else + TC_PRINT("Can't verify stored dump: expectedly not supported.\n"); ztest_test_skip(); +#endif } else if (ret == 1) { - check_errors(); +#ifdef CONFIG_TEST_STORED_COREDUMP + check_error(); ztest_test_pass(); +#else + TC_ERROR("Can't have a stored dump: not supported.\n"); + ztest_test_fail(); +#endif + } else if (ret == 0) { +#ifdef CONFIG_TEST_STORED_COREDUMP + TC_ERROR("Verification of stored dump failed!\n"); + ztest_test_fail(); +#else + TC_ERROR("Can't have a stored dump: not supported.\n"); + ztest_test_fail(); +#endif + } else { + TC_ERROR("Error reading stored dump! (%d)\n", ret); + ztest_test_fail(); + } +} + +void test_invalidate_stored_dump(void) +{ + int ret; + + /* Cannot proceed with previous errors */ + check_error(); + + /* There should be a stored coredump now if backend has storage */ + ret = coredump_cmd(COREDUMP_CMD_INVALIDATE_STORED_DUMP, NULL); + if (ret == -ENOTSUP) { +#ifdef CONFIG_TEST_STORED_COREDUMP + TC_ERROR("Can't invalidate stored dump: unexpectedly not supported.\n"); + ztest_test_fail(); +#else + TC_PRINT("Can't invalidate stored dump: expectedly not supported.\n"); + ztest_test_skip(); +#endif } else if (ret == 0) { - TC_PRINT("Verification of stored dump failed!\n"); +#ifdef CONFIG_TEST_STORED_COREDUMP + check_error(); + ztest_test_pass(); +#else + TC_ERROR("Can't invalidate the stored dump: not supported.\n"); ztest_test_fail(); +#endif } else { - TC_PRINT("Error reading stored dump! (%d)\n", ret); + TC_ERROR("Error invalidating stored dump! (%d)\n", ret); ztest_test_fail(); } } -ZTEST(coredump_backends, test_coredump_backend) { - test_coredump(); - test_query_stored_dump(); +void test_erase_stored_dump(void) +{ + int ret; + + /* Cannot proceed with previous errors */ + check_error(); + + /* There should be a stored coredump now if backend has storage */ + ret = coredump_cmd(COREDUMP_CMD_ERASE_STORED_DUMP, NULL); + if (ret == -ENOTSUP) { +#ifdef CONFIG_TEST_STORED_COREDUMP + TC_ERROR("Can't erase stored dump: unexpectedly not supported.\n"); + ztest_test_fail(); +#else + TC_PRINT("Can't erase stored dump: expectedly not supported.\n"); + ztest_test_skip(); +#endif + } else if (ret == 0) { +#ifdef CONFIG_TEST_STORED_COREDUMP + check_error(); + ztest_test_pass(); +#else + TC_ERROR("Can't erase the stored dump: not supported.\n"); + ztest_test_fail(); +#endif + } else { + TC_ERROR("Error erasing stored dump! (%d)\n", ret); + ztest_test_fail(); + } +} + +void test_get_stored_dump_size(int size_expected) +{ + int ret; + + /* Cannot proceed with previous errors */ + check_error(); + + ret = coredump_query(COREDUMP_QUERY_GET_STORED_DUMP_SIZE, NULL); + if (ret == -ENOTSUP) { +#ifdef CONFIG_TEST_STORED_COREDUMP + TC_ERROR("Can't query stored dump size: unexpectedly not supported.\n"); + ztest_test_fail(); +#else + TC_PRINT("Can't query stored dump size: expectedly not supported.\n"); + ztest_test_skip(); +#endif + } else if (ret >= 0) { +#ifdef CONFIG_TEST_STORED_COREDUMP + check_error(); + if (size_expected > 0) { + zassert_equal(ret, size_expected, + "Coredump size %d != %d size expected.\n", + ret, size_expected); + } + ztest_test_pass(); +#else + TC_ERROR("Can't have a stored dump: not supported.\n"); + ztest_test_fail(); +#endif + } else { + TC_ERROR("Error reading stored dump size! (%d)\n", ret); + ztest_test_fail(); + } +} + +/* Excecute tests in exact sequence with the stored core dump. */ + +ZTEST(coredump_backends, test_coredump_0_ready) { + check_error(); + ztest_test_pass(); +} + +ZTEST(coredump_backends, test_coredump_1_stored) { + test_has_stored_dump(true); +} + +ZTEST(coredump_backends, test_coredump_2_size) { + test_get_stored_dump_size(CONFIG_TEST_STORED_DUMP_SIZE); +} + +ZTEST(coredump_backends, test_coredump_3_verify) { test_verify_stored_dump(); } -ZTEST_SUITE(coredump_backends, NULL, NULL, NULL, NULL, NULL); +ZTEST(coredump_backends, test_coredump_4_invalidate) { + test_invalidate_stored_dump(); +} + +ZTEST(coredump_backends, test_coredump_5_erase) { + test_erase_stored_dump(); +} + +ZTEST_SUITE(coredump_backends, NULL, raise_coredump, NULL, NULL, NULL); diff --git a/tests/subsys/debug/coredump_backends/testcase.yaml b/tests/subsys/debug/coredump_backends/testcase.yaml index 6055c52906e447e..b8fc6078f78d423 100644 --- a/tests/subsys/debug/coredump_backends/testcase.yaml +++ b/tests/subsys/debug/coredump_backends/testcase.yaml @@ -10,6 +10,8 @@ tests: debug.coredump.backends.logging: filter: CONFIG_ARCH_SUPPORTS_COREDUMP platform_exclude: acrn_ehl_crb + extra_configs: + - CONFIG_TEST_STORED_COREDUMP=n harness: console harness_config: type: multi_line @@ -20,6 +22,8 @@ tests: debug.coredump.backends.flash: filter: CONFIG_ARCH_SUPPORTS_COREDUMP extra_args: CONF_FILE=prj_flash_partition.conf + extra_configs: + - CONFIG_TEST_STORED_COREDUMP=y platform_allow: - qemu_x86 - esp32_devkitc_wroom @@ -30,4 +34,6 @@ tests: debug.coredump.backends.other: filter: CONFIG_ARCH_SUPPORTS_COREDUMP extra_args: CONF_FILE=prj_backend_other.conf + extra_configs: + - CONFIG_TEST_STORED_COREDUMP=y platform_exclude: acrn_ehl_crb From 4d394f9d23438681d01aac60e932f472e52a70e5 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Wed, 8 Nov 2023 12:11:15 +0100 Subject: [PATCH 0263/1049] tests: coredump: Fix backend.logging test misconfig The debug.coredump.backends.logging testcase did use 'console' Twister harness whereas the test suite itself and the rest of the testcases are implemented as Ztest. This misalignment allowed to check basic output expected from the logging backend, but caused inconsistency of the test suite results because the 'console' Twister Harness can't use test cases' ID provided by the 'Ztest' Twister Handler. It is decided to focus the debug.coredump.backends.* suite on the coredump backend API testing with Ztest. The logging backend's resulting output should be tested by its dedicated test suite debug.coredump.logging_backend (tests/subsys/debug/coredump). Signed-off-by: Dmitrii Golovanov --- tests/subsys/debug/coredump_backends/testcase.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/subsys/debug/coredump_backends/testcase.yaml b/tests/subsys/debug/coredump_backends/testcase.yaml index b8fc6078f78d423..d7b5f722f3783a9 100644 --- a/tests/subsys/debug/coredump_backends/testcase.yaml +++ b/tests/subsys/debug/coredump_backends/testcase.yaml @@ -12,13 +12,6 @@ tests: platform_exclude: acrn_ehl_crb extra_configs: - CONFIG_TEST_STORED_COREDUMP=n - harness: console - harness_config: - type: multi_line - regex: - - "E: #CD:BEGIN#" - - "E: #CD:5([aA])45([0-9a-fA-F]+)" - - "E: #CD:END#" debug.coredump.backends.flash: filter: CONFIG_ARCH_SUPPORTS_COREDUMP extra_args: CONF_FILE=prj_flash_partition.conf From 39eb124c81e88a6b2da3d42c9f76a91f29fbbb28 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 8 Nov 2023 15:45:30 +0100 Subject: [PATCH 0264/1049] drivers: add MAX20335 charger driver Add a MAX20335 MFD subdriver for the built-in battery charger. Signed-off-by: Bartosz Bilas --- drivers/charger/CMakeLists.txt | 1 + drivers/charger/Kconfig | 1 + drivers/charger/Kconfig.max20335 | 11 + drivers/charger/charger_max20335.c | 287 ++++++++++++++++++ .../charger/maxim,max20335-charger.yaml | 8 + tests/drivers/build_all/charger/i2c.dtsi | 13 + 6 files changed, 321 insertions(+) create mode 100644 drivers/charger/Kconfig.max20335 create mode 100644 drivers/charger/charger_max20335.c create mode 100644 dts/bindings/charger/maxim,max20335-charger.yaml diff --git a/drivers/charger/CMakeLists.txt b/drivers/charger/CMakeLists.txt index 894561982a37c69..ce70f0590c601bf 100644 --- a/drivers/charger/CMakeLists.txt +++ b/drivers/charger/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_library() zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/charger.h) zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ24190 charger_bq24190.c) +zephyr_library_sources_ifdef(CONFIG_CHARGER_MAX20335 charger_max20335.c) zephyr_library_sources_ifdef(CONFIG_SBS_CHARGER sbs_charger.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE charger_handlers.c) zephyr_library_sources_ifdef(CONFIG_EMUL_SBS_CHARGER emul_sbs_charger.c) diff --git a/drivers/charger/Kconfig b/drivers/charger/Kconfig index 4a6071fd8f82708..9c7873168a5c9e9 100644 --- a/drivers/charger/Kconfig +++ b/drivers/charger/Kconfig @@ -21,5 +21,6 @@ config CHARGER_INIT_PRIORITY source "drivers/charger/Kconfig.sbs_charger" source "drivers/charger/Kconfig.bq24190" +source "drivers/charger/Kconfig.max20335" endif # CHARGER diff --git a/drivers/charger/Kconfig.max20335 b/drivers/charger/Kconfig.max20335 new file mode 100644 index 000000000000000..7104e5daab67f71 --- /dev/null +++ b/drivers/charger/Kconfig.max20335 @@ -0,0 +1,11 @@ +# Copyright 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +config CHARGER_MAX20335 + bool "MAX20335 battery charger driver" + default y + depends on DT_HAS_MAXIM_MAX20335_CHARGER_ENABLED + select I2C + select MFD + help + Enable the MAX20335 battery charger driver. diff --git a/drivers/charger/charger_max20335.c b/drivers/charger/charger_max20335.c new file mode 100644 index 000000000000000..75eae16f8881c80 --- /dev/null +++ b/drivers/charger/charger_max20335.c @@ -0,0 +1,287 @@ +/* + * Copyright 2023 Grinn + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT maxim_max20335_charger + +#include +#include +#include +#include +#include +#include + +#include "zephyr/logging/log.h" +LOG_MODULE_REGISTER(max20335_charger); + +#define MAX20335_REG_STATUS_A 0x02 +#define MAX20335_REG_ILIMCNTL 0x09 +#define MAX20335_REG_CHG_CNTL_A 0x0A +#define MAX20335_CHGCNTLA_BAT_REG_CFG_MASK GENMASK(4, 1) +#define MAX20335_ILIMCNTL_MASK GENMASK(1, 0) +#define MAX20335_STATUS_A_CHG_STAT_MASK GENMASK(2, 0) +#define MAX20335_CHRG_EN_MASK BIT(0) +#define MAX20335_CHRG_EN BIT(0) +#define MAX20335_REG_CVC_VREG_MIN_UV 4050000U +#define MAX20335_REG_CVC_VREG_STEP_UV 50000U +#define MAX20335_REG_CVC_VREG_MIN_IDX 0x0U +#define MAX20335_REG_CVC_VREG_MAX_IDX 0x0CU + +struct charger_max20335_config { + struct i2c_dt_spec bus; + uint32_t max_ichg_ua; + uint32_t max_vreg_uv; +}; + +enum { + MAX20335_CHARGER_OFF, + MAX20335_CHARGING_SUSPENDED_DUE_TO_TEMPERATURE, + MAX20335_PRE_CHARGE_IN_PROGRESS, + MAX20335_FAST_CHARGE_IN_PROGRESS_1, + MAX20335_FAST_CHARGE_IN_PROGRESS_2, + MAX20335_MAINTAIN_CHARGE_IN_PROGRESS, + MAX20335_MAIN_CHARGER_TIMER_DONE, + MAX20335_CHARGER_FAULT_CONDITION, +}; + +static const struct linear_range charger_uv_range = + LINEAR_RANGE_INIT(MAX20335_REG_CVC_VREG_MIN_UV, + MAX20335_REG_CVC_VREG_STEP_UV, + MAX20335_REG_CVC_VREG_MIN_IDX, + MAX20335_REG_CVC_VREG_MAX_IDX); + +static int max20335_get_status(const struct device *dev, enum charger_status *status) +{ + const struct charger_max20335_config *const config = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_REG_STATUS_A, &val); + if (ret) { + return ret; + } + + val = FIELD_GET(MAX20335_STATUS_A_CHG_STAT_MASK, val); + + switch (val) { + case MAX20335_CHARGER_OFF: + __fallthrough; + case MAX20335_CHARGING_SUSPENDED_DUE_TO_TEMPERATURE: + __fallthrough; + case MAX20335_CHARGER_FAULT_CONDITION: + *status = CHARGER_STATUS_NOT_CHARGING; + break; + case MAX20335_PRE_CHARGE_IN_PROGRESS: + __fallthrough; + case MAX20335_FAST_CHARGE_IN_PROGRESS_1: + __fallthrough; + case MAX20335_FAST_CHARGE_IN_PROGRESS_2: + __fallthrough; + case MAX20335_MAINTAIN_CHARGE_IN_PROGRESS: + *status = CHARGER_STATUS_CHARGING; + break; + case MAX20335_MAIN_CHARGER_TIMER_DONE: + *status = CHARGER_STATUS_FULL; + break; + default: + *status = CHARGER_STATUS_UNKNOWN; + break; + }; + + return 0; +} + +static int max20335_set_constant_charge_voltage(const struct device *dev, + uint32_t voltage_uv) +{ + const struct charger_max20335_config *const config = dev->config; + uint16_t idx; + uint8_t val; + int ret; + + if (voltage_uv > config->max_vreg_uv) { + LOG_WRN("Exceeded max constant charge voltage!"); + return -EINVAL; + } + + ret = linear_range_get_index(&charger_uv_range, voltage_uv, &idx); + if (ret == -EINVAL) { + return ret; + } + + val = FIELD_PREP(MAX20335_CHGCNTLA_BAT_REG_CFG_MASK, idx); + + return i2c_reg_update_byte_dt(&config->bus, + MAX20335_REG_CHG_CNTL_A, + MAX20335_CHGCNTLA_BAT_REG_CFG_MASK, + val); +} + +static int max20335_set_constant_charge_current(const struct device *dev, + uint32_t current_ua) +{ + const struct charger_max20335_config *const config = dev->config; + uint8_t val; + + if (current_ua > config->max_ichg_ua) { + LOG_WRN("Exceeded max constant charge current!"); + return -EINVAL; + } + + switch (current_ua) { + case 0: + val = 0x00; + break; + case 100000: + val = 0x01; + break; + case 500000: + val = 0x02; + break; + case 1000000: + val = 0x03; + break; + default: + return -ENOTSUP; + }; + + val = FIELD_PREP(MAX20335_ILIMCNTL_MASK, val); + + return i2c_reg_update_byte_dt(&config->bus, + MAX20335_REG_ILIMCNTL, + MAX20335_ILIMCNTL_MASK, + val); +} + +static int max20335_get_constant_charge_current(const struct device *dev, + uint32_t *current_ua) +{ + const struct charger_max20335_config *const config = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_REG_ILIMCNTL, &val); + if (ret) { + return ret; + } + + switch (val) { + case 0x00: + *current_ua = 0; + break; + case 0x01: + *current_ua = 100000; + break; + case 0x02: + *current_ua = 500000; + break; + case 0x03: + *current_ua = 1000000; + break; + default: + return -ENOTSUP; + }; + + return 0; +} + +static int max20335_get_constant_charge_voltage(const struct device *dev, + uint32_t *current_uv) +{ + const struct charger_max20335_config *const config = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_REG_CHG_CNTL_A, &val); + if (ret) { + return ret; + } + + val = FIELD_GET(MAX20335_CHGCNTLA_BAT_REG_CFG_MASK, val); + + return linear_range_get_value(&charger_uv_range, val, current_uv); +} + +static int max20335_set_enabled(const struct device *dev, bool enable) +{ + const struct charger_max20335_config *const config = dev->config; + + return i2c_reg_update_byte_dt(&config->bus, + MAX20335_REG_CHG_CNTL_A, + MAX20335_CHRG_EN_MASK, + enable ? MAX20335_CHRG_EN : 0); +} + +static int max20335_get_prop(const struct device *dev, charger_prop_t prop, + union charger_propval *val) +{ + switch (prop) { + case CHARGER_PROP_STATUS: + return max20335_get_status(dev, &val->status); + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + return max20335_get_constant_charge_current(dev, + &val->const_charge_current_ua); + case CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV: + return max20335_get_constant_charge_voltage(dev, + &val->const_charge_voltage_uv); + default: + return -ENOTSUP; + } +} + +static int max20335_set_prop(const struct device *dev, charger_prop_t prop, + const union charger_propval *val) +{ + switch (prop) { + case CHARGER_PROP_STATUS: + switch (val->status) { + case CHARGER_STATUS_CHARGING: + return max20335_set_enabled(dev, true); + case CHARGER_STATUS_NOT_CHARGING: + return max20335_set_enabled(dev, false); + default: + return -ENOTSUP; + } + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + return max20335_set_constant_charge_current(dev, + val->const_charge_current_ua); + case CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV: + return max20335_set_constant_charge_voltage(dev, + val->const_charge_voltage_uv); + default: + return -ENOTSUP; + } + +} + +static int max20335_init(const struct device *dev) +{ + const struct charger_max20335_config *config = dev->config; + + if (!i2c_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + return 0; +} + +static const struct charger_driver_api max20335_driver_api = { + .get_property = max20335_get_prop, + .set_property = max20335_set_prop, +}; + +#define MAX20335_DEFINE(inst) \ + static const struct charger_max20335_config charger_max20335_config_##inst = { \ + .bus = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ + .max_ichg_ua = DT_INST_PROP(inst, constant_charge_current_max_microamp), \ + .max_vreg_uv = DT_INST_PROP(inst, constant_charge_voltage_max_microvolt), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &max20335_init, NULL, NULL, \ + &charger_max20335_config_##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &max20335_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MAX20335_DEFINE) diff --git a/dts/bindings/charger/maxim,max20335-charger.yaml b/dts/bindings/charger/maxim,max20335-charger.yaml new file mode 100644 index 000000000000000..45b7cc87997da37 --- /dev/null +++ b/dts/bindings/charger/maxim,max20335-charger.yaml @@ -0,0 +1,8 @@ +# Copyright (c), 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +description: Maxim MAX20335 battery charger + +include: battery.yaml + +compatible: "maxim,max20335-charger" diff --git a/tests/drivers/build_all/charger/i2c.dtsi b/tests/drivers/build_all/charger/i2c.dtsi index 53cbcf0e59bf445..c30efdcfcb8e3d6 100644 --- a/tests/drivers/build_all/charger/i2c.dtsi +++ b/tests/drivers/build_all/charger/i2c.dtsi @@ -15,3 +15,16 @@ bq24190@0 { constant-charge-current-max-microamp = <1000000>; constant-charge-voltage-max-microvolt = <4208000>; }; + +max20335@1 { + compatible = "maxim,max20335"; + reg = <0x01>; + status = "okay"; + + charger: charger { + compatible = "maxim,max20335-charger"; + + constant-charge-current-max-microamp = <100000>; + constant-charge-voltage-max-microvolt = <4050000>; + }; +}; From 18a0660be084bfe3525d448af3d849960eb8f7cf Mon Sep 17 00:00:00 2001 From: Dat Nguyen Duy Date: Thu, 9 Nov 2023 02:36:25 +0700 Subject: [PATCH 0265/1049] samples/tests: skip samples/tests disable MPU for s32ze series On SoC series s32ze, Zephyr application cannot run with MPU disabled, skipping relevant samples/tests Signed-off-by: Dat Nguyen Duy --- samples/subsys/llext/shell_loader/sample.yaml | 2 +- tests/subsys/llext/testcase.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/subsys/llext/shell_loader/sample.yaml b/samples/subsys/llext/shell_loader/sample.yaml index 5ef2a080286decf..acb30def4daa6ad 100644 --- a/samples/subsys/llext/shell_loader/sample.yaml +++ b/samples/subsys/llext/shell_loader/sample.yaml @@ -5,7 +5,7 @@ tests: sample.llext.shell: tags: shell llext harness: keyboard - filter: not CONFIG_CPU_HAS_MMU + filter: not CONFIG_CPU_HAS_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 arch_allow: arm extra_configs: - CONFIG_ARM_MPU=n diff --git a/tests/subsys/llext/testcase.yaml b/tests/subsys/llext/testcase.yaml index 6d493276b9314ad..79d8f5a1fd9acbb 100644 --- a/tests/subsys/llext/testcase.yaml +++ b/tests/subsys/llext/testcase.yaml @@ -2,7 +2,7 @@ common: tags: llext tests: llext.simple.arm: - filter: not CONFIG_CPU_HAS_MMU + filter: not CONFIG_CPU_HAS_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 arch_allow: arm extra_configs: - CONFIG_ARM_MPU=n From b3f950c64858c384a677f6b4d59229e2c1cb3496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 5 Oct 2023 14:51:26 +0700 Subject: [PATCH 0266/1049] drivers: mdio: nxp_s32_netc: use instance-based DT macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At present, many of the NXP S32 shim drivers do not make use of devicetree instance-based macros because the NXP S32 HAL relies on an index-based approach, requiring knowledge of the peripheral instance index during both compilation and runtime, and this index might not align with the devicetree instance index. The proposed solution in this patch eliminates this limitation by determining the peripheral instance index during compilation through macrobatics and defining the driver's ISR within the shim driver itself. Note that for some peripheral instances is needed to redefine the HAL macros of the peripheral base address, since the naming is not uniform for all instances. Signed-off-by: Manuel Argüelles --- drivers/mdio/mdio_nxp_s32_netc.c | 51 +++++++++++++++++++------------- soc/arm/nxp_s32/s32ze/soc.h | 3 ++ 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/drivers/mdio/mdio_nxp_s32_netc.c b/drivers/mdio/mdio_nxp_s32_netc.c index c8ce0e731b30c8e..ff8a561d974511a 100644 --- a/drivers/mdio/mdio_nxp_s32_netc.c +++ b/drivers/mdio/mdio_nxp_s32_netc.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_netc_emdio + #include #include #include @@ -12,11 +14,9 @@ LOG_MODULE_REGISTER(nxp_s32_emdio, CONFIG_MDIO_LOG_LEVEL); #include -#define MDIO_NODE DT_NODELABEL(emdio) -#define NETC_SWT_IDX 0 - struct nxp_s32_mdio_config { const struct pinctrl_dev_config *pincfg; + uint8_t instance; }; struct nxp_s32_mdio_data { @@ -26,11 +26,12 @@ struct nxp_s32_mdio_data { static int nxp_s32_mdio_read(const struct device *dev, uint8_t prtad, uint8_t regad, uint16_t *regval) { + const struct nxp_s32_mdio_config *cfg = dev->config; struct nxp_s32_mdio_data *data = dev->data; Std_ReturnType status; k_mutex_lock(&data->rw_mutex, K_FOREVER); - status = Netc_EthSwt_Ip_ReadTrcvRegister(NETC_SWT_IDX, prtad, regad, regval); + status = Netc_EthSwt_Ip_ReadTrcvRegister(cfg->instance, prtad, regad, regval); k_mutex_unlock(&data->rw_mutex); return status == E_OK ? 0 : -EIO; @@ -39,11 +40,12 @@ static int nxp_s32_mdio_read(const struct device *dev, uint8_t prtad, static int nxp_s32_mdio_write(const struct device *dev, uint8_t prtad, uint8_t regad, uint16_t regval) { + const struct nxp_s32_mdio_config *cfg = dev->config; struct nxp_s32_mdio_data *data = dev->data; Std_ReturnType status; k_mutex_lock(&data->rw_mutex, K_FOREVER); - status = Netc_EthSwt_Ip_WriteTrcvRegister(NETC_SWT_IDX, prtad, regad, regval); + status = Netc_EthSwt_Ip_WriteTrcvRegister(cfg->instance, prtad, regad, regval); k_mutex_unlock(&data->rw_mutex); return status == E_OK ? 0 : -EIO; @@ -78,19 +80,26 @@ static const struct mdio_driver_api nxp_s32_mdio_api = { .bus_disable = nxp_s32_mdio_noop, }; -PINCTRL_DT_DEFINE(MDIO_NODE); - -static struct nxp_s32_mdio_data nxp_s32_mdio0_data; - -static const struct nxp_s32_mdio_config nxp_s32_mdio0_cfg = { - .pincfg = PINCTRL_DT_DEV_CONFIG_GET(MDIO_NODE), -}; - -DEVICE_DT_DEFINE(MDIO_NODE, - &nxp_s32_mdio_initialize, - NULL, - &nxp_s32_mdio0_data, - &nxp_s32_mdio0_cfg, - POST_KERNEL, - CONFIG_MDIO_INIT_PRIORITY, - &nxp_s32_mdio_api); +#define NXP_S32_MDIO_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_NETC_EMDIO_##n##_BASE) ? i : 0) + +#define NXP_S32_MDIO_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET NETC_F1_INSTANCE_COUNT, NXP_S32_MDIO_HW_INSTANCE_CHECK, (|), n) + +#define NXP_S32_MDIO_INSTANCE_DEFINE(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static struct nxp_s32_mdio_data nxp_s32_mdio##n##_data; \ + static const struct nxp_s32_mdio_config nxp_s32_mdio##n##_cfg = { \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .instance = NXP_S32_MDIO_HW_INSTANCE(n), \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + &nxp_s32_mdio_initialize, \ + NULL, \ + &nxp_s32_mdio##n##_data, \ + &nxp_s32_mdio##n##_cfg, \ + POST_KERNEL, \ + CONFIG_MDIO_INIT_PRIORITY, \ + &nxp_s32_mdio_api); + +DT_INST_FOREACH_STATUS_OKAY(NXP_S32_MDIO_INSTANCE_DEFINE) diff --git a/soc/arm/nxp_s32/s32ze/soc.h b/soc/arm/nxp_s32/s32ze/soc.h index a6a7ca51ced965e..17289511f7dfe6d 100644 --- a/soc/arm/nxp_s32/s32ze/soc.h +++ b/soc/arm/nxp_s32/s32ze/soc.h @@ -48,4 +48,7 @@ #define IP_STM_11_BASE IP_SMU__STM_0_BASE #define IP_STM_12_BASE IP_SMU__STM_2_BASE +/* NETC */ +#define IP_NETC_EMDIO_0_BASE IP_NETC__EMDIO_BASE_BASE + #endif /* _NXP_S32_S32ZE_SOC_H_ */ From 250ff71c64f8067bd81cd21c22016e107a71e304 Mon Sep 17 00:00:00 2001 From: Marcus Penate Date: Thu, 9 Nov 2023 15:17:15 -0500 Subject: [PATCH 0267/1049] zbus: Fix parameter order of net buf pool fixed define Fixed order of pool-size and data-size parameters in use of `NET_BUF_POOL_FIXED_DEFINE()` Signed-off-by: Marcus Penate --- subsys/zbus/zbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/zbus/zbus.c b/subsys/zbus/zbus.c index 4ea2d986a3f22fb..b1178b1fea756b2 100644 --- a/subsys/zbus/zbus.c +++ b/subsys/zbus/zbus.c @@ -29,8 +29,8 @@ static inline struct net_buf *_zbus_create_net_buf(struct net_buf_pool *pool, si #else NET_BUF_POOL_FIXED_DEFINE(_zbus_msg_subscribers_pool, - (CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC_DATA_SIZE), (CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE), + (CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC_DATA_SIZE), sizeof(struct zbus_channel *), NULL); static inline struct net_buf *_zbus_create_net_buf(struct net_buf_pool *pool, size_t size, From 61c392c5b13fbc448ca0e4c047848c72c3096a07 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 10 Nov 2023 10:23:34 +0100 Subject: [PATCH 0268/1049] net: iface: Introduce TX mutex locking A recent iface lock removal in ed17320c3d2e43c76b09dc359d3b371e9d23732d exposed issues with concurrent access on TX to drivers that are not re-entrant. Reverting that commit does not really solve the problem, as it would still exist if multiple Traffic Class queues are in use. Therefore, introduce a separate mutex for TX data path, protecting the L2/driver from concurrent transfers from several threads. Signed-off-by: Robert Lubos --- include/zephyr/net/net_if.h | 29 +++++++++++++++++++++++++++++ subsys/net/ip/net_if.c | 3 +++ subsys/net/l2/ethernet/arp.c | 2 ++ 3 files changed, 34 insertions(+) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 79fc2c79b317a85..ab056d05e151e6f 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -212,6 +212,9 @@ enum net_if_flag { /** IPv6 Multicast Listener Discovery disabled. */ NET_IF_IPV6_NO_MLD, + /** Mutex locking on TX data path disabled on the interface. */ + NET_IF_NO_TX_LOCK, + /** @cond INTERNAL_HIDDEN */ /* Total number of flags - must be at the end of the enum */ NET_IF_NUM_FLAGS @@ -613,6 +616,7 @@ struct net_if { #endif struct k_mutex lock; + struct k_mutex tx_lock; }; static inline void net_if_lock(struct net_if *iface) @@ -629,6 +633,31 @@ static inline void net_if_unlock(struct net_if *iface) k_mutex_unlock(&iface->lock); } +static inline bool net_if_flag_is_set(struct net_if *iface, + enum net_if_flag value); + +static inline void net_if_tx_lock(struct net_if *iface) +{ + NET_ASSERT(iface); + + if (net_if_flag_is_set(iface, NET_IF_NO_TX_LOCK)) { + return; + } + + (void)k_mutex_lock(&iface->tx_lock, K_FOREVER); +} + +static inline void net_if_tx_unlock(struct net_if *iface) +{ + NET_ASSERT(iface); + + if (net_if_flag_is_set(iface, NET_IF_NO_TX_LOCK)) { + return; + } + + k_mutex_unlock(&iface->tx_lock); +} + /** * @brief Set a value in network interface flags * diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 099618b84761443..dbf20af3cc0a0a9 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -254,7 +254,9 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt) } } + net_if_tx_lock(iface); status = net_if_l2(iface)->send(iface, pkt); + net_if_tx_unlock(iface); if (IS_ENABLED(CONFIG_NET_PKT_TXTIME_STATS)) { uint32_t end_tick = k_cycle_get_32(); @@ -426,6 +428,7 @@ static inline void init_iface(struct net_if *iface) #endif k_mutex_init(&iface->lock); + k_mutex_init(&iface->tx_lock); api->init(iface); } diff --git a/subsys/net/l2/ethernet/arp.c b/subsys/net/l2/ethernet/arp.c index 35a2ec63a64489a..39a06ed64a0faf6 100644 --- a/subsys/net/l2/ethernet/arp.c +++ b/subsys/net/l2/ethernet/arp.c @@ -534,7 +534,9 @@ static void arp_update(struct net_if *iface, * the pkt are not counted twice and the packet filter * callbacks are only called once. */ + net_if_tx_lock(iface); ret = net_if_l2(iface)->send(iface, pkt); + net_if_tx_unlock(iface); if (ret < 0) { net_pkt_unref(pkt); } From 592292c182d5d0d978d22c55e48071e9f6aec958 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Fri, 10 Nov 2023 12:27:42 +0200 Subject: [PATCH 0269/1049] drivers: sensor: adxl367: use explicit conditions Make the adxl367 compliant with the Zephyr code guidelines by using explicit conditions. Signed-off-by: Antoniu Miclaus --- drivers/sensor/adxl367/adxl367.c | 102 +++++++++++++-------------- drivers/sensor/adxl367/adxl367_i2c.c | 4 +- drivers/sensor/adxl367/adxl367_spi.c | 6 +- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/drivers/sensor/adxl367/adxl367.c b/drivers/sensor/adxl367/adxl367.c index 2979b945b62767d..020ee476b2b72a1 100644 --- a/drivers/sensor/adxl367/adxl367.c +++ b/drivers/sensor/adxl367/adxl367.c @@ -46,13 +46,13 @@ static int adxl367_setup_activity_detection(const struct device *dev, FIELD_PREP(ADXL367_ACT_INACT_CTL_ACT_EN_MSK, th->enable) | FIELD_PREP(ADXL367_ACT_INACT_CTL_ACT_REF_MSK, th->referenced)); - if (ret) { + if (ret != 0) { return ret; } ret = data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_ACT_H, ADXL367_THRESH_H_MSK, FIELD_PREP(ADXL367_THRESH_H_MSK, th->value >> 6)); - if (ret) { + if (ret != 0) { return ret; } @@ -84,13 +84,13 @@ static int adxl367_setup_inactivity_detection(const struct device *dev, th->enable) | FIELD_PREP(ADXL367_ACT_INACT_CTL_INACT_REF_MSK, th->referenced)); - if (ret) { + if (ret != 0) { return ret; } ret = data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_INACT_H, ADXL367_THRESH_H_MSK, FIELD_PREP(ADXL367_THRESH_H_MSK, th->value >> 6)); - if (ret) { + if (ret != 0) { return ret; } @@ -117,7 +117,7 @@ static int adxl367_set_op_mode(const struct device *dev, ret = data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL, ADXL367_POWER_CTL_MEASURE_MSK, FIELD_PREP(ADXL367_POWER_CTL_MEASURE_MSK, op_mode)); - if (ret) { + if (ret != 0) { return ret; } @@ -259,7 +259,7 @@ static int adxl367_set_inactivity_time(const struct device *dev, struct adxl367_data *data = dev->data; ret = data->hw_tf->write_reg(dev, ADXL367_TIME_INACT_H, time >> 8); - if (ret) { + if (ret != 0) { return ret; } @@ -281,13 +281,13 @@ int adxl367_self_test(const struct device *dev) uint8_t read_val[2]; ret = adxl367_set_op_mode(dev, ADXL367_MEASURE); - if (ret) { + if (ret != 0) { return ret; } ret = data->hw_tf->write_reg_mask(dev, ADXL367_SELF_TEST, ADXL367_SELF_TEST_ST_MSK, FIELD_PREP(ADXL367_SELF_TEST_ST_MSK, 1)); - if (ret) { + if (ret != 0) { return ret; } @@ -295,21 +295,21 @@ int adxl367_self_test(const struct device *dev) k_sleep(K_MSEC(40)); ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, read_val, 2); - if (ret) { + if (ret != 0) { return ret; } x_axis_1 = ((int16_t)read_val[0] << 6) + (read_val[1] >> 2); /* extend sign to 16 bits */ - if (x_axis_1 & BIT(13)) { + if ((x_axis_1 & BIT(13)) != 0) { x_axis_1 |= GENMASK(15, 14); } ret = data->hw_tf->write_reg_mask(dev, ADXL367_SELF_TEST, ADXL367_SELF_TEST_ST_FORCE_MSK, FIELD_PREP(ADXL367_SELF_TEST_ST_FORCE_MSK, 1)); - if (ret) { + if (ret != 0) { return ret; } @@ -317,18 +317,18 @@ int adxl367_self_test(const struct device *dev) k_sleep(K_MSEC(40)); ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, read_val, 2); - if (ret) { + if (ret != 0) { return ret; } x_axis_2 = ((int16_t)read_val[0] << 6) + (read_val[1] >> 2); /* extend sign to 16 bits */ - if (x_axis_2 & BIT(13)) + if ((x_axis_2 & BIT(13)) != 0) x_axis_2 |= GENMASK(15, 14); ret = adxl367_set_op_mode(dev, ADXL367_STANDBY); - if (ret) { + if (ret != 0) { return ret; } @@ -336,7 +336,7 @@ int adxl367_self_test(const struct device *dev) ADXL367_SELF_TEST_ST_MSK, FIELD_PREP(ADXL367_SELF_TEST_ST_FORCE_MSK, 0) | FIELD_PREP(ADXL367_SELF_TEST_ST_MSK, 0)); - if (ret) { + if (ret != 0) { return ret; } @@ -395,7 +395,7 @@ int adxl367_set_fifo_sample_sets_nb(const struct device *dev, ADXL367_FIFO_CONTROL_FIFO_SAMPLES_MSK, FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_SAMPLES_MSK, fifo_samples_msb)); - if (ret) { + if (ret != 0) { return ret; } @@ -478,7 +478,7 @@ int adxl367_set_fifo_format(const struct device *dev, ADXL367_FIFO_CONTROL, ADXL367_FIFO_CONTROL_FIFO_CHANNEL_MSK, FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_CHANNEL_MSK, format)); - if (ret) { + if (ret != 0) { return ret; } @@ -551,17 +551,17 @@ int adxl367_fifo_setup(const struct device *dev, int ret; ret = adxl367_set_fifo_mode(dev, mode); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_set_fifo_format(dev, format); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_set_fifo_sample_sets_nb(dev, sets_nb); - if (ret) { + if (ret != 0) { return ret; } @@ -581,13 +581,13 @@ static int adxl367_reset(const struct device *dev) struct adxl367_data *data = dev->data; ret = adxl367_set_op_mode(dev, ADXL367_STANDBY); - if (ret) { + if (ret != 0) { return ret; } /* Writing code 0x52 resets the device */ ret = data->hw_tf->write_reg(dev, ADXL367_SOFT_RESET, ADXL367_RESET_CODE); - if (ret) { + if (ret != 0) { return ret; } @@ -614,19 +614,19 @@ int adxl367_get_accel_data(const struct device *dev, uint8_t reg_data, nready = 1U; struct adxl367_data *data = dev->data; - while (nready) { + while (nready != 0) { ret = data->hw_tf->read_reg(dev, ADXL367_STATUS, ®_data); - if (ret) { + if (ret != 0) { return ret; } - if (reg_data & ADXL367_STATUS_DATA_RDY) { + if ((reg_data & ADXL367_STATUS_DATA_RDY) != 0) { nready = 0U; } } ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, xyz_values, 6); - if (ret) { + if (ret != 0) { return ret; } @@ -636,15 +636,15 @@ int adxl367_get_accel_data(const struct device *dev, accel_data->z = ((int16_t)xyz_values[4] << 6) + (xyz_values[5] >> 2); /* extend sign to 16 bits */ - if (accel_data->x & BIT(13)) { + if ((accel_data->x & BIT(13)) != 0) { accel_data->x |= GENMASK(15, 14); } - if (accel_data->y & BIT(13)) { + if ((accel_data->y & BIT(13)) != 0) { accel_data->y |= GENMASK(15, 14); } - if (accel_data->z & BIT(13)) { + if ((accel_data->z & BIT(13)) != 0) { accel_data->z |= GENMASK(15, 14); } @@ -667,25 +667,25 @@ int adxl367_get_temp_data(const struct device *dev, int16_t *raw_temp) uint8_t reg_data, nready = 1U; struct adxl367_data *data = dev->data; - while (nready) { + while (nready != 0) { ret = data->hw_tf->read_reg(dev, ADXL367_STATUS, ®_data); - if (ret) { + if (ret != 0) { return ret; } - if (reg_data & ADXL367_STATUS_DATA_RDY) { + if ((reg_data & ADXL367_STATUS_DATA_RDY) != 0) { nready = 0U; } } ret = data->hw_tf->read_reg_multiple(dev, ADXL367_TEMP_H, temp, 2); - if (ret) { + if (ret != 0) { return ret; } *raw_temp = ((int16_t)temp[0] << 6) + (temp[1] >> 2); /* extend sign to 16 bits */ - if (*raw_temp & BIT(13)) { + if ((*raw_temp & BIT(13)) != 0) { *raw_temp |= GENMASK(15, 14); } @@ -785,7 +785,7 @@ static int adxl367_sample_fetch(const struct device *dev, int ret; ret = adxl367_get_accel_data(dev, &data->sample); - if (ret) { + if (ret != 0) { return ret; } @@ -859,16 +859,16 @@ static int adxl367_probe(const struct device *dev) int ret; ret = adxl367_reset(dev); - if (ret) { + if (ret != 0) { return ret; } ret = data->hw_tf->read_reg(dev, ADXL367_DEVID, &dev_id); - if (ret) { + if (ret != 0) { return ret; } ret = data->hw_tf->read_reg(dev, ADXL367_PART_ID, &part_id); - if (ret) { + if (ret != 0) { return ret; } @@ -886,47 +886,47 @@ static int adxl367_probe(const struct device *dev) #endif ret = adxl367_self_test(dev); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_temp_read_en(dev, cfg->temp_en); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_set_autosleep(dev, cfg->autosleep); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_set_low_noise(dev, cfg->low_noise); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_setup_activity_detection(dev, &cfg->activity_th); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_setup_inactivity_detection(dev, &cfg->inactivity_th); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_set_activity_time(dev, cfg->activity_time); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_set_inactivity_time(dev, cfg->inactivity_time); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_set_output_rate(dev, cfg->odr); - if (ret) { + if (ret != 0) { return ret; } @@ -934,7 +934,7 @@ static int adxl367_probe(const struct device *dev) cfg->fifo_config.fifo_format, cfg->fifo_config.fifo_read_mode, cfg->fifo_config.fifo_samples); - if (ret) { + if (ret != 0) { return ret; } @@ -947,12 +947,12 @@ if (IS_ENABLED(CONFIG_ADXL367_TRIGGER)) { } ret = adxl367_set_op_mode(dev, cfg->op_mode); - if (ret) { + if (ret != 0) { return ret; } ret = adxl367_set_range(dev, data->range); - if (ret) { + if (ret != 0) { return ret; } @@ -965,7 +965,7 @@ static int adxl367_init(const struct device *dev) const struct adxl367_dev_config *cfg = dev->config; ret = cfg->bus_init(dev); - if (ret) { + if (ret != 0) { LOG_ERR("Failed to initialize sensor bus\n"); return ret; } diff --git a/drivers/sensor/adxl367/adxl367_i2c.c b/drivers/sensor/adxl367/adxl367_i2c.c index 2c7d168c224e64c..762334ad8dafd2e 100644 --- a/drivers/sensor/adxl367/adxl367_i2c.c +++ b/drivers/sensor/adxl367/adxl367_i2c.c @@ -23,7 +23,7 @@ static int adxl367_bus_access(const struct device *dev, uint8_t reg, { const struct adxl367_dev_config *config = dev->config; - if (reg & ADXL367_READ) { + if ((reg & ADXL367_READ) != 0) { return i2c_burst_read_dt(&config->i2c, ADXL367_TO_REG(reg), (uint8_t *) data, length); @@ -70,7 +70,7 @@ int adxl367_i2c_reg_write_mask(const struct device *dev, uint8_t tmp; ret = adxl367_i2c_reg_read(dev, reg_addr, &tmp); - if (ret) { + if (ret != 0) { return ret; } diff --git a/drivers/sensor/adxl367/adxl367_spi.c b/drivers/sensor/adxl367/adxl367_spi.c index 174fcf0bf0a2395..a5b9c633b68eeac 100644 --- a/drivers/sensor/adxl367/adxl367_spi.c +++ b/drivers/sensor/adxl367/adxl367_spi.c @@ -24,7 +24,7 @@ static int adxl367_bus_access(const struct device *dev, uint8_t reg, const struct adxl367_dev_config *config = dev->config; uint8_t rw_reg, addr_reg; - if (reg & ADXL367_READ) { + if ((reg & ADXL367_READ) != 0) { rw_reg = ADXL367_SPI_READ_REG; } else { rw_reg = ADXL367_SPI_WRITE_REG; @@ -49,7 +49,7 @@ static int adxl367_bus_access(const struct device *dev, uint8_t reg, .buffers = buf, }; - if (reg & ADXL367_READ) { + if ((reg & ADXL367_READ) != 0) { const struct spi_buf_set rx = { .buffers = buf, .count = 3 @@ -97,7 +97,7 @@ int adxl367_spi_reg_write_mask(const struct device *dev, uint8_t tmp; ret = adxl367_spi_reg_read(dev, reg_addr, &tmp); - if (ret) { + if (ret != 0) { return ret; } From cbf9680f962041e1bedd335603ef5810fcecf793 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 10 Nov 2023 12:21:55 +0100 Subject: [PATCH 0270/1049] net: lib: coap: Add coap_find_observer Add a function to the public CoAP API to find and return the unique observer based on the address and token. Signed-off-by: Pieter De Gendt --- include/zephyr/net/coap.h | 24 ++++++++++++++++++++++++ subsys/net/lib/coap/coap.c | 22 ++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index ef9eb660ff496f9..a907d1311e16550 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -934,6 +934,24 @@ bool coap_register_observer(struct coap_resource *resource, bool coap_remove_observer(struct coap_resource *resource, struct coap_observer *observer); +/** + * @brief Returns the observer that matches address @a addr + * and has token @a token. + * + * @param observers Pointer to the array of observers + * @param len Size of the array of observers + * @param addr Address of the endpoint observing a resource + * @param token Pointer to the token + * @param token_len Length of valid bytes in the token + * + * @return A pointer to a observer if a match is found, NULL + * otherwise. + */ +struct coap_observer *coap_find_observer( + struct coap_observer *observers, size_t len, + const struct sockaddr *addr, + const uint8_t *token, uint8_t token_len); + /** * @brief Returns the observer that matches address @a addr. * @@ -941,6 +959,9 @@ bool coap_remove_observer(struct coap_resource *resource, * @param len Size of the array of observers * @param addr Address of the endpoint observing a resource * + * @note The function coap_find_observer() should be preferred + * if both the observer's address and token are known. + * * @return A pointer to a observer if a match is found, NULL * otherwise. */ @@ -956,6 +977,9 @@ struct coap_observer *coap_find_observer_by_addr( * @param token Pointer to the token * @param token_len Length of valid bytes in the token * + * @note The function coap_find_observer() should be preferred + * if both the observer's address and token are known. + * * @return A pointer to a observer if a match is found, NULL * otherwise. */ diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 9747e33fc56b4bc..3ecc077aa64f450 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1913,6 +1913,28 @@ static bool sockaddr_equal(const struct sockaddr *a, return false; } +struct coap_observer *coap_find_observer( + struct coap_observer *observers, size_t len, + const struct sockaddr *addr, + const uint8_t *token, uint8_t token_len) +{ + if (token_len == 0U || token_len > COAP_TOKEN_MAX_LEN) { + return NULL; + } + + for (size_t i = 0; i < len; i++) { + struct coap_observer *o = &observers[i]; + + if (o->tkl == token_len && + memcmp(o->token, token, token_len) == 0 && + sockaddr_equal(&o->addr, addr)) { + return o; + } + } + + return NULL; +} + struct coap_observer *coap_find_observer_by_addr( struct coap_observer *observers, size_t len, const struct sockaddr *addr) From 655c72c52e1d16f4414bd84513074ddeeb4378e8 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 10 Nov 2023 12:23:51 +0100 Subject: [PATCH 0271/1049] net: lib: coap: coap_server: Allow clients to refresh observe requests A CoAP client can re-issue an observe request (same endpoint and token) to refresh it's subscription. No new observer should be registered in this case. Signed-off-by: Pieter De Gendt --- subsys/net/lib/coap/coap_server.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index fbcbe1721b2b421..4b4f1719f46fefe 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -91,8 +91,11 @@ static int coap_service_remove_observer(const struct coap_service *service, { struct coap_observer *obs; - /* Prefer token to find the observer */ - if (tkl > 0 && token != NULL) { + if (tkl > 0 && addr != NULL) { + /* Prefer addr+token to find the observer */ + obs = coap_find_observer(service->data->observers, MAX_OBSERVERS, addr, token, tkl); + } else if (tkl > 0) { + /* Then try to to find the observer by token */ obs = coap_find_observer_by_token(service->data->observers, MAX_OBSERVERS, token, tkl); } else if (addr != NULL) { @@ -550,6 +553,8 @@ int coap_resource_parse_observe(struct coap_resource *resource, const struct coa { const struct coap_service *service = NULL; int ret; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint8_t tkl; if (!coap_packet_is_request(request)) { return -EINVAL; @@ -572,11 +577,25 @@ int coap_resource_parse_observe(struct coap_resource *resource, const struct coa return -ENOENT; } + tkl = coap_header_get_token(request, token); + if (tkl == 0) { + return -EINVAL; + } + (void)k_mutex_lock(&lock, K_FOREVER); if (ret == 0) { struct coap_observer *observer; + /* RFC7641 section 4.1 - Check if the current observer already exists */ + observer = coap_find_observer(service->data->observers, MAX_OBSERVERS, addr, token, + tkl); + if (observer != NULL) { + /* Client refresh */ + goto unlock; + } + + /* New client */ observer = coap_observer_next_unused(service->data->observers, MAX_OBSERVERS); if (observer == NULL) { ret = -ENOMEM; @@ -586,10 +605,6 @@ int coap_resource_parse_observe(struct coap_resource *resource, const struct coa coap_observer_init(observer, request, addr); coap_register_observer(resource, observer); } else if (ret == 1) { - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t tkl; - - tkl = coap_header_get_token(request, token); ret = coap_service_remove_observer(service, resource, addr, token, tkl); if (ret < 0) { LOG_WRN("Failed to remove observer (%d)", ret); From f9e0a3dbd025e8ca3c47b333af75d2d05d6d5494 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 11:07:10 +0100 Subject: [PATCH 0272/1049] doc: pytest: Correct native device type name The native device type name is "native", "native posix" is just one of the possible target boards (which is going to be deprecated in the next release). Signed-off-by: Alberto Escolar Piedras --- doc/develop/test/pytest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index 087c45bcce8d4c0..e644882191ef7db 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -67,7 +67,7 @@ Give access to a DeviceAdapter type object, that represents Device Under Test. This fixture is the core of pytest harness plugin. It is required to launch DUT (initialize logging, flash device, connect serial etc). This fixture yields a device prepared according to the requested type -(native posix, qemu, hardware, etc.). All types of devices share the same API. +(``native``, ``qemu``, ``hardware``, etc.). All types of devices share the same API. This allows for writing tests which are device-type-agnostic. Scope of this fixture is determined by the ``pytest_dut_scope`` keyword placed under ``harness_config`` section. From 64e1d0c3be487f2d6765050d8056bf9fdfd2afaa Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Fri, 10 Nov 2023 14:50:41 +0100 Subject: [PATCH 0273/1049] bluetooth: mesh: Don't write to const value `bt_mesh_default_key` is declared as const and thus located in flash. `bt_mesh_cdb_subnet_key_export` tries to copy to that address which results in a Bus Fault. Use separate array for storing net_key. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/shell/shell.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index 6ee825d4c09aafc..c1bad5d24adb181 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -944,7 +944,7 @@ static int cmd_provision_adv(const struct shell *sh, size_t argc, static int cmd_provision_local(const struct shell *sh, size_t argc, char *argv[]) { - uint8_t *net_key = (uint8_t *)bt_mesh_shell_default_key; + uint8_t net_key[16]; uint16_t net_idx, addr; uint32_t iv_index; int err = 0; @@ -963,6 +963,8 @@ static int cmd_provision_local(const struct shell *sh, size_t argc, char *argv[] return err; } + memcpy(net_key, bt_mesh_shell_default_key, sizeof(net_key)); + if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { struct bt_mesh_cdb_subnet *sub; From 171cecb1d6b3fcf765d5d793f6a6d0ee4432715f Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 10 Nov 2023 11:10:27 -0500 Subject: [PATCH 0274/1049] riscv: FPU trap: test case comment typo fix Test case comment typo fix. Signed-off-by: Nicolas Pitre --- tests/arch/riscv/fpu_sharing/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/arch/riscv/fpu_sharing/src/main.c b/tests/arch/riscv/fpu_sharing/src/main.c index 1884adde313f9bf..55ab1a2e4a047f5 100644 --- a/tests/arch/riscv/fpu_sharing/src/main.c +++ b/tests/arch/riscv/fpu_sharing/src/main.c @@ -425,7 +425,7 @@ ZTEST(riscv_fpu_sharing, test_fp_insn_trap) TEST_TRAP("fcvt.w.s %0, fa0"); zassert_true(reg == 12812820, "got %ld instead", reg); - /* NMSUB major opcode space */ + /* MSUB major opcode space */ reg = 1234; TEST_TRAP("fcvt.s.w fa1, %0"); TEST_TRAP("fmsub.s fa0, fa1, fa1, fa0"); From 498888d764d4bec3ad92c72555e4cd2071e53bb7 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Fri, 10 Nov 2023 15:18:36 +0100 Subject: [PATCH 0275/1049] samples: sockets: echo_client: assume connected without connmgr When connection manager (CONFIG_NET_CONNECTION_MANAGER) is disabled, application starts right away. Scenario that it covers is when static networking is used, like with emulators (QEMU, Native Sim, ...). Since 'connected' flag was not set in such scenario, the internal loop inside start_client() has ended up early and stop_udp_and_tcp() was called quickly after starting TCP and UDP clients. Set 'connected = true', when connection manager is disabled, so that it is assumed that connection is working for the whole duration of the echo-client sample. Signed-off-by: Marcin Niestroj --- samples/net/sockets/echo_client/src/echo-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/net/sockets/echo_client/src/echo-client.c b/samples/net/sockets/echo_client/src/echo-client.c index c78b14952e6dccb..3e4aff0f2d0bdd5 100644 --- a/samples/net/sockets/echo_client/src/echo-client.c +++ b/samples/net/sockets/echo_client/src/echo-client.c @@ -320,6 +320,7 @@ int main(void) * app only after we have a connection, then we can start * it right away. */ + connected = true; k_sem_give(&run_app); } From c30c9b97b46a86db5ea2d5d8c5c87ba565a10037 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Fri, 10 Nov 2023 15:26:09 +0100 Subject: [PATCH 0276/1049] drivers: eth: cmake: narrow scope of 'native_posix_source_files' 'native_posix_source_files' is used only when CONFIG_NATIVE_APPLICATION=y, but it was set unconditionally regardless of this Kconfig option. Set 'native_posix_source_files' under CONFIG_NATIVE_APPLICATION=y to narrow scope of this variable. Signed-off-by: Marcin Niestroj --- drivers/ethernet/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/ethernet/CMakeLists.txt b/drivers/ethernet/CMakeLists.txt index 1ae6ef58e82852f..8c8795509fded4d 100644 --- a/drivers/ethernet/CMakeLists.txt +++ b/drivers/ethernet/CMakeLists.txt @@ -46,12 +46,12 @@ zephyr_library_sources_ifdef(CONFIG_ETH_NXP_S32_GMAC eth_nxp_s32_gmac.c) zephyr_library_sources_ifdef(CONFIG_ETH_NUMAKER eth_numaker.c) if(CONFIG_ETH_NATIVE_POSIX) - set(native_posix_source_files eth_native_posix.c eth_native_posix_adapt.c) - set_source_files_properties(${native_posix_source_files} - PROPERTIES COMPILE_DEFINITIONS - "NO_POSIX_CHEATS;_BSD_SOURCE;_DEFAULT_SOURCE" - ) if (CONFIG_NATIVE_APPLICATION) + set(native_posix_source_files eth_native_posix.c eth_native_posix_adapt.c) + set_source_files_properties(${native_posix_source_files} + PROPERTIES COMPILE_DEFINITIONS + "NO_POSIX_CHEATS;_BSD_SOURCE;_DEFAULT_SOURCE" + ) zephyr_library_sources(${native_posix_source_files}) else() zephyr_library_sources(eth_native_posix.c) From 31200fb33d38631614d4aaa383ce7d10f2d14f85 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 11 Nov 2023 14:52:21 +1000 Subject: [PATCH 0277/1049] scripts: twister: config_parser: copy common values Create copys of the common configuration values when constructing test scenarios, to avoid mutating the common value with test specific appends. Signed-off-by: Jordan Yates --- scripts/pylib/twister/twisterlib/config_parser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/config_parser.py b/scripts/pylib/twister/twisterlib/config_parser.py index f431e2d57c2f6b1..5373287624751c3 100644 --- a/scripts/pylib/twister/twisterlib/config_parser.py +++ b/scripts/pylib/twister/twisterlib/config_parser.py @@ -3,6 +3,7 @@ # Copyright (c) 2018-2022 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +import copy import scl import warnings from typing import Union @@ -176,7 +177,8 @@ def get_scenario(self, name): {"CONF_FILE", "OVERLAY_CONFIG", "DTC_OVERLAY_FILE"}, v ) else: - d[k] = v + # Copy common value to avoid mutating it with test specific values below + d[k] = copy.copy(v) for k, v in self.scenarios[name].items(): if k == "extra_args": From 8b7c8b09ecc083bdff676e1bf1a29a0c255c6389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Sat, 11 Nov 2023 11:02:43 +0100 Subject: [PATCH 0278/1049] lorawan: rename lorawan_set_battery_level_callback and make it void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the lorawan_set_battery_level_callback to lorawan_register_battery_level_callback to make it consistent with other functions for downlink and data rate changed callbacks. Also making the function void for consistency. The get_battery_level already checks if the callback is NULL before invoking it. Signed-off-by: Martin Jäger --- doc/releases/migration-guide-3.6.rst | 8 ++++++++ include/zephyr/lorawan/lorawan.h | 4 +--- subsys/lorawan/lorawan.c | 8 +------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 42a485d633e4a72..6afd6969452ef9b 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -73,6 +73,14 @@ Bluetooth been renamed, from ``samples/bluetooth/hci_rpmsg`` to ``samples/bluetooth/hci_ipc``. +LoRaWAN +======= + +* The API to register a callback to provide battery level information to the LoRaWAN stack has been + renamed from ``lorawan_set_battery_level_callback`` to + :c:func:`lorawan_register_battery_level_callback` and the return type is now ``void``. This + is more consistent with similar functions for downlink and data rate changed callbacks. + Networking ========== diff --git a/include/zephyr/lorawan/lorawan.h b/include/zephyr/lorawan/lorawan.h index 519e6e4bea16e5a..5ce84f6f727a007 100644 --- a/include/zephyr/lorawan/lorawan.h +++ b/include/zephyr/lorawan/lorawan.h @@ -187,10 +187,8 @@ struct lorawan_downlink_cb { * Should no callback be provided the lorawan backend will report 255. * * @param battery_lvl_cb Pointer to the battery level function - * - * @return 0 if successful, negative errno code if failure */ -int lorawan_set_battery_level_callback(uint8_t (*battery_lvl_cb)(void)); +void lorawan_register_battery_level_callback(uint8_t (*battery_lvl_cb)(void)); /** * @brief Register a callback to be run on downlink packets diff --git a/subsys/lorawan/lorawan.c b/subsys/lorawan/lorawan.c index d73691cfde8d05d..b325ffc87d887f5 100644 --- a/subsys/lorawan/lorawan.c +++ b/subsys/lorawan/lorawan.c @@ -621,15 +621,9 @@ int lorawan_send(uint8_t port, uint8_t *data, uint8_t len, return ret; } -int lorawan_set_battery_level_callback(uint8_t (*battery_lvl_cb)(void)) +void lorawan_register_battery_level_callback(uint8_t (*battery_lvl_cb)(void)) { - if (battery_lvl_cb == NULL) { - return -EINVAL; - } - get_battery_level_user = battery_lvl_cb; - - return 0; } void lorawan_register_downlink_callback(struct lorawan_downlink_cb *cb) From c72b9f5048b0c4d523a40043248ef089d5b9363f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Sat, 11 Nov 2023 11:09:46 +0100 Subject: [PATCH 0279/1049] lorawan: use callback function signature typedefs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids duplication of the function signature in several places and makes the API documentation more clean. Signed-off-by: Martin Jäger --- include/zephyr/lorawan/lorawan.h | 35 ++++++++++++++++++++------------ subsys/lorawan/lorawan.c | 24 +++++++++++----------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/include/zephyr/lorawan/lorawan.h b/include/zephyr/lorawan/lorawan.h index 5ce84f6f727a007..2e07e99d69416e7 100644 --- a/include/zephyr/lorawan/lorawan.h +++ b/include/zephyr/lorawan/lorawan.h @@ -175,20 +175,32 @@ struct lorawan_downlink_cb { }; /** - * @brief Add battery level callback function. + * @brief Defines the battery level callback handler function signature. + * + * @retval 0 if the node is connected to an external power source + * @retval 1..254 battery level, where 1 is the minimum and 254 is the maximum value + * @retval 255 if the node was not able to measure the battery level + */ +typedef uint8_t (*lorawan_battery_level_cb_t)(void); + +/** + * @brief Defines the datarate changed callback handler function signature. + * + * @param dr Updated datarate. + */ +typedef void (*lorawan_dr_changed_cb_t)(enum lorawan_datarate dr); + +/** + * @brief Register a battery level callback function. * * Provide the LoRaWAN stack with a function to be called whenever a battery - * level needs to be read. As per LoRaWAN specification the callback needs to - * return "0: node is connected to an external power source, - * 1..254: battery level, where 1 is the minimum and 254 is the maximum - * value, - * 255: the node was not able to measure the battery level" + * level needs to be read. * * Should no callback be provided the lorawan backend will report 255. * - * @param battery_lvl_cb Pointer to the battery level function + * @param cb Pointer to the battery level function */ -void lorawan_register_battery_level_callback(uint8_t (*battery_lvl_cb)(void)); +void lorawan_register_battery_level_callback(lorawan_battery_level_cb_t cb); /** * @brief Register a callback to be run on downlink packets @@ -203,12 +215,9 @@ void lorawan_register_downlink_callback(struct lorawan_downlink_cb *cb); * The callback is called once upon successfully joining a network and again * each time the datarate changes due to ADR. * - * The callback function takes one parameter: - * - dr - updated datarate - * - * @param dr_cb Pointer to datarate update callback + * @param cb Pointer to datarate update callback */ -void lorawan_register_dr_changed_callback(void (*dr_cb)(enum lorawan_datarate)); +void lorawan_register_dr_changed_callback(lorawan_dr_changed_cb_t cb); /** * @brief Join the LoRaWAN network diff --git a/subsys/lorawan/lorawan.c b/subsys/lorawan/lorawan.c index b325ffc87d887f5..56731dfc4542dc7 100644 --- a/subsys/lorawan/lorawan.c +++ b/subsys/lorawan/lorawan.c @@ -72,8 +72,8 @@ static LoRaMacEventInfoStatus_t last_mlme_indication_status; static LoRaMacRegion_t selected_region = DEFAULT_LORAWAN_REGION; -static uint8_t (*get_battery_level_user)(void); -static void (*dr_change_cb)(enum lorawan_datarate dr); +static lorawan_battery_level_cb_t battery_level_cb; +static lorawan_dr_changed_cb_t dr_changed_cb; /* implementation required by the soft-se (software secure element) */ void BoardGetUniqueId(uint8_t *id) @@ -83,11 +83,11 @@ void BoardGetUniqueId(uint8_t *id) static uint8_t get_battery_level(void) { - if (get_battery_level_user != NULL) { - return get_battery_level_user(); + if (battery_level_cb != NULL) { + return battery_level_cb(); + } else { + return 255; } - - return 255; } static void mac_process_notify(void) @@ -105,8 +105,8 @@ static void datarate_observe(bool force_notification) if ((mib_req.Param.ChannelsDatarate != current_datarate) || (force_notification)) { current_datarate = mib_req.Param.ChannelsDatarate; - if (dr_change_cb) { - dr_change_cb(current_datarate); + if (dr_changed_cb != NULL) { + dr_changed_cb(current_datarate); } LOG_INF("Datarate changed: DR_%d", current_datarate); } @@ -621,9 +621,9 @@ int lorawan_send(uint8_t port, uint8_t *data, uint8_t len, return ret; } -void lorawan_register_battery_level_callback(uint8_t (*battery_lvl_cb)(void)) +void lorawan_register_battery_level_callback(lorawan_battery_level_cb_t cb) { - get_battery_level_user = battery_lvl_cb; + battery_level_cb = cb; } void lorawan_register_downlink_callback(struct lorawan_downlink_cb *cb) @@ -631,9 +631,9 @@ void lorawan_register_downlink_callback(struct lorawan_downlink_cb *cb) sys_slist_append(&dl_callbacks, &cb->node); } -void lorawan_register_dr_changed_callback(void (*cb)(enum lorawan_datarate)) +void lorawan_register_dr_changed_callback(lorawan_dr_changed_cb_t cb) { - dr_change_cb = cb; + dr_changed_cb = cb; } int lorawan_start(void) From 679d82c48411973a477da05d4e77fca875902e73 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Sat, 11 Nov 2023 09:35:49 +1300 Subject: [PATCH 0280/1049] libc: Add GCC fno-builtin-malloc flag to common stdlib compilation This prevents the compiler from optimizing calloc into an infinite recursive call. For example a call to malloc + memset zero at GCC -O2 will be replaced by a call to calloc. This causes infinite recursion if the function being implemented *is* calloc. fno-builtin-malloc forces the compiler to avoid this optimization. Signed-off-by: Grant Ramsay --- lib/libc/common/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index 48372158ea569f4..3aa869379d5c2d3 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -6,3 +6,6 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ABORT source/stdlib/abort.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c) + +# Prevent compiler from optimizing calloc into an infinite recursive call +zephyr_library_cc_option(-fno-builtin-malloc) From a3ff19a39eb18bc10ae38698f5c91ad50c5748d7 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Mon, 13 Nov 2023 09:34:50 +1300 Subject: [PATCH 0281/1049] cmake: compiler: Add compiler property for no-builtin Abstracts these flags for multiple toolchain support Signed-off-by: Grant Ramsay --- arch/posix/CMakeLists.txt | 4 ++-- cmake/compiler/arcmwdt/compiler_flags.cmake | 3 +++ cmake/compiler/compiler_flags_template.cmake | 4 ++++ cmake/compiler/gcc/compiler_flags.cmake | 3 +++ lib/libc/common/CMakeLists.txt | 2 +- lib/libc/minimal/CMakeLists.txt | 2 +- modules/openthread/CMakeLists.txt | 6 ++++-- 7 files changed, 18 insertions(+), 6 deletions(-) diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index 86cf051ccdef1ac..1573ef82ea167ff 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -94,12 +94,12 @@ elseif (CONFIG_NATIVE_LIBRARY) # Do not use the C library from this compiler/host, # but still use the basic compiler headers - # -fno-builtin to avoid the compiler using builtin replacements for std library functions + # no_builtin to avoid the compiler using builtin replacements for std library functions zephyr_compile_options( -nostdinc -isystem ${COMPILER_OWN_INCLUDE_PATH} $ - -fno-builtin + $ ) endif() endif() diff --git a/cmake/compiler/arcmwdt/compiler_flags.cmake b/cmake/compiler/arcmwdt/compiler_flags.cmake index 8eeaf2fa37a5e62..7ab83ba507de497 100644 --- a/cmake/compiler/arcmwdt/compiler_flags.cmake +++ b/cmake/compiler/arcmwdt/compiler_flags.cmake @@ -206,3 +206,6 @@ endif() # Remove after testing that -Wshadow works set_compiler_property(PROPERTY warning_shadow_variables) + +set_compiler_property(PROPERTY no_builtin -fno-builtin) +set_compiler_property(PROPERTY no_builtin_malloc -fno-builtin-malloc) diff --git a/cmake/compiler/compiler_flags_template.cmake b/cmake/compiler/compiler_flags_template.cmake index 1476c45e85197dd..53e37287b9fd2d9 100644 --- a/cmake/compiler/compiler_flags_template.cmake +++ b/cmake/compiler/compiler_flags_template.cmake @@ -133,3 +133,7 @@ set_compiler_property(PROPERTY no_global_merge) # Compiler flag for warning about shadow variables set_compiler_property(PROPERTY warning_shadow_variables) + +# Compiler flags to avoid recognizing built-in functions +set_compiler_property(PROPERTY no_builtin) +set_compiler_property(PROPERTY no_builtin_malloc) diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index b77dfa4123f0c9d..5b1dbde49c6b030 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -227,3 +227,6 @@ set_compiler_property(PROPERTY no_position_independent set_compiler_property(PROPERTY no_global_merge "") set_compiler_property(PROPERTY warning_shadow_variables -Wshadow) + +set_compiler_property(PROPERTY no_builtin -fno-builtin) +set_compiler_property(PROPERTY no_builtin_malloc -fno-builtin-malloc) diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index 3aa869379d5c2d3..048977511869b82 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -8,4 +8,4 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c) # Prevent compiler from optimizing calloc into an infinite recursive call -zephyr_library_cc_option(-fno-builtin-malloc) +zephyr_library_compile_options($) diff --git a/lib/libc/minimal/CMakeLists.txt b/lib/libc/minimal/CMakeLists.txt index 71a404e7870926a..abcab108e524e05 100644 --- a/lib/libc/minimal/CMakeLists.txt +++ b/lib/libc/minimal/CMakeLists.txt @@ -7,7 +7,7 @@ zephyr_library() set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) set(STRERROR_TABLE_H ${GEN_DIR}/libc/minimal/strerror_table.h) -zephyr_library_cc_option(-fno-builtin) +zephyr_library_compile_options($) zephyr_library_sources( source/stdlib/atoi.c diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index bad6d131771747f..2b2b593f82f7dff 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -547,7 +547,8 @@ target_compile_definitions(ot-config INTERFACE # libraries do not include this header. So we add the defines to all # OpenThread files through the gcc flag -imacros instead. target_compile_options(ot-config INTERFACE - $ -fno-builtin + $ + $ -imacros ${AUTOCONF_H} ) @@ -600,7 +601,8 @@ endif() if(CONFIG_OPENTHREAD_SETTINGS_RAM) target_compile_options(openthread-platform-utils PRIVATE - $ -fno-builtin) + $ + $) add_dependencies(openthread-platform-utils syscall_list_h_target) list(APPEND ot_libs openthread-platform-utils-static) From 28df44946f09c02c5b967927710bebafa28f6a6a Mon Sep 17 00:00:00 2001 From: Dominik Kilian Date: Thu, 9 Nov 2023 11:41:07 +0100 Subject: [PATCH 0282/1049] ipc: add dynamically allocated buffers to icmsg The icmsg and icmsg_me backends has limitations in context of concurrent access to single instance. Some limitations are: * sending by more thread at the same time may cause -EBUSY * allocating TX buffer will cause errors in other threads that want to allocate before first thread sent the message, * during no-copy receive, when RX buffer is on hold receiving is totally blocked. This backend resolves those limitations by adding dynamically allocated buffers on shared memory next to ICmsg circular buffer. The data is passed using those buffers, so concurrency is not a problem. The ICmsg is used only to pass short 2-byte messages containing references to those buffers. The backend also supports multiple endpoint. The ipc/icmsg_me sample was modified to support this backend. Signed-off-by: Dominik Kilian --- .../backends/ipc_service_icbmsg.rst | 83 ++ doc/services/ipc/ipc_service/ipc_service.rst | 1 + dts/bindings/ipc/zephyr,ipc-icbmsg.yaml | 22 + include/zephyr/ipc/pbuf.h | 10 + .../ipc/ipc_service/backends/CMakeLists.txt | 1 + subsys/ipc/ipc_service/backends/Kconfig | 1 + .../ipc/ipc_service/backends/Kconfig.icbmsg | 31 + subsys/ipc/ipc_service/backends/ipc_icbmsg.c | 1303 +++++++++++++++++ 8 files changed, 1452 insertions(+) create mode 100644 doc/services/ipc/ipc_service/backends/ipc_service_icbmsg.rst create mode 100644 dts/bindings/ipc/zephyr,ipc-icbmsg.yaml create mode 100644 subsys/ipc/ipc_service/backends/Kconfig.icbmsg create mode 100644 subsys/ipc/ipc_service/backends/ipc_icbmsg.c diff --git a/doc/services/ipc/ipc_service/backends/ipc_service_icbmsg.rst b/doc/services/ipc/ipc_service/backends/ipc_service_icbmsg.rst new file mode 100644 index 000000000000000..26b9006ae81d348 --- /dev/null +++ b/doc/services/ipc/ipc_service/backends/ipc_service_icbmsg.rst @@ -0,0 +1,83 @@ +.. _ipc_service_backend_icbmsg: + +ICMsg with dynamically allocated buffers backend +################################################ + +This backend is built on top of the :ref:`ipc_service_backend_icmsg`. +Data transferred over this backend travels in dynamically allocated buffers on shared memory. +The ICMsg just sends references to the buffers. +It also supports multiple endpoints. + +This architecture allows for overcoming some common problems with other backends (mostly related to multithread access and zero-copy). +This backend provides an alternative with no significant limitations. + +Overview +======== + +The shared memory is divided into two parts. +One is reserved for the ICMsg and the other contains equal-sized blocks. +The number of blocks is configured in the devicetree. + +The data sending process is following: + +* The sender allocates one or more blocks. + If there are not enough sequential blocks, it waits using the timeout provided in the parameter that also includes K_FOREVER and K_NO_WAIT. +* The allocated blocks are filled with data. + For the zero-copy case, this is done by the caller, otherwise, it is copied automatically. + During this time other threads are not blocked in any way as long as there are enough free blocks for them. + They can allocate, send data and receive data. +* A message containing the block index is sent over ICMsg to the receiver. + The size of the ICMsg queue is large enough to hold messages for all blocks, so it will never overflow. +* The receiver can hold the data as long as desired. + Again, other threads are not blocked as long as there are enough free blocks for them. +* When data is no longer needed, the backend sends a release message over ICMsg. +* When the backend receives this message, it deallocates all blocks. + It is done internally by the backend and it is invisible to the caller. + +Configuration +============= + +The backend is configured using Kconfig and devicetree. +When configuring the backend, do the following: + +* Define two memory regions and assign them to ``tx-region`` and ``rx-region`` of an instance. + Ensure that the memory regions used for data exchange are unique (not overlapping any other region) and accessible by both domains (or CPUs). +* Define the number of allocable blocks for each region with ``tx-blocks`` and ``rx-blocks``. +* Define MBOX devices for sending a signal that informs the other domain (or CPU) of the written data. + Ensure that the other domain (or CPU) can receive the signal. + +See the following configuration example for one of the instances: + +.. code-block:: devicetree + + reserved-memory { + tx: memory@20070000 { + reg = <0x20070000 0x0800>; + }; + + rx: memory@20078000 { + reg = <0x20078000 0x0800>; + }; + }; + + ipc { + ipc0: ipc0 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&tx>; + rx-region = <&rx>; + tx-blocks = <16>; + rx-blocks = <32>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "tx", "rx"; + status = "okay"; + }; + }; + + +You must provide a similar configuration for the other side of the communication (domain or CPU). +Swap the MBOX channels, memory regions (``tx-region`` and ``rx-region``), and block count (``tx-blocks`` and ``rx-blocks``). + +Samples +======= + +* :ref:`ipc_multi_endpoint_sample` diff --git a/doc/services/ipc/ipc_service/ipc_service.rst b/doc/services/ipc/ipc_service/ipc_service.rst index 35cdfbf1ddeb557..286ded7580124cc 100644 --- a/doc/services/ipc/ipc_service/ipc_service.rst +++ b/doc/services/ipc/ipc_service/ipc_service.rst @@ -185,6 +185,7 @@ backend. :maxdepth: 1 backends/ipc_service_icmsg.rst + backends/ipc_service_icbmsg.rst API Reference ************* diff --git a/dts/bindings/ipc/zephyr,ipc-icbmsg.yaml b/dts/bindings/ipc/zephyr,ipc-icbmsg.yaml new file mode 100644 index 000000000000000..0fc6be01a494b6d --- /dev/null +++ b/dts/bindings/ipc/zephyr,ipc-icbmsg.yaml @@ -0,0 +1,22 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Inter-core messaging backend with dynamically allocated buffers + +compatible: "zephyr,ipc-icbmsg" + +include: zephyr,ipc-icmsg.yaml + +properties: + tx-blocks: + description: number of allocable TX blocks + required: true + type: int + + rx-blocks: + description: number of allocable RX blocks + required: true + type: int diff --git a/include/zephyr/ipc/pbuf.h b/include/zephyr/ipc/pbuf.h index f8eff0b1ad1753e..5f953522d3bdd63 100644 --- a/include/zephyr/ipc/pbuf.h +++ b/include/zephyr/ipc/pbuf.h @@ -116,6 +116,16 @@ struct pbuf { .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. * diff --git a/subsys/ipc/ipc_service/backends/CMakeLists.txt b/subsys/ipc/ipc_service/backends/CMakeLists.txt index 0f5629a14c55dbc..d6ca8fb76c334cf 100644 --- a/subsys/ipc/ipc_service/backends/CMakeLists.txt +++ b/subsys/ipc/ipc_service/backends/CMakeLists.txt @@ -3,4 +3,5 @@ zephyr_sources_ifdef(CONFIG_IPC_SERVICE_BACKEND_ICMSG ipc_icmsg.c) zephyr_sources_ifdef(CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_INITIATOR ipc_icmsg_me_initiator.c) zephyr_sources_ifdef(CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_FOLLOWER ipc_icmsg_me_follower.c) +zephyr_sources_ifdef(CONFIG_IPC_SERVICE_BACKEND_ICBMSG ipc_icbmsg.c) zephyr_sources_ifdef(CONFIG_IPC_SERVICE_BACKEND_RPMSG ipc_rpmsg_static_vrings.c) diff --git a/subsys/ipc/ipc_service/backends/Kconfig b/subsys/ipc/ipc_service/backends/Kconfig index 61d113aac3fc3a8..8230465e246aa9a 100644 --- a/subsys/ipc/ipc_service/backends/Kconfig +++ b/subsys/ipc/ipc_service/backends/Kconfig @@ -49,4 +49,5 @@ config IPC_SERVICE_BACKEND_ICMSG_ME_FOLLOWER role. rsource "Kconfig.icmsg_me" +rsource "Kconfig.icbmsg" rsource "Kconfig.rpmsg" diff --git a/subsys/ipc/ipc_service/backends/Kconfig.icbmsg b/subsys/ipc/ipc_service/backends/Kconfig.icbmsg new file mode 100644 index 000000000000000..e31b5cadd77a34d --- /dev/null +++ b/subsys/ipc/ipc_service/backends/Kconfig.icbmsg @@ -0,0 +1,31 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menuconfig IPC_SERVICE_BACKEND_ICBMSG + bool "ICMSG backend with dynamically allocated buffers" + default y + depends on MBOX + depends on DT_HAS_ZEPHYR_IPC_ICBMSG_ENABLED + select IPC_SERVICE_ICMSG + help + Choosing this backend results in multi endpoint implementation based + on dynamically allocated buffers. References to them are send over + ICMsg circular buffer. + +if IPC_SERVICE_BACKEND_ICBMSG + +config IPC_SERVICE_BACKEND_ICBMSG_NUM_EP + int "Endpoints count" + range 1 254 + default 4 + help + Number of endpoints supported by the ICBMsg IPC service + backend. The number of endpoints are applied to all the instances, + so this value should be maximum number among all the instances. + +module = IPC_SERVICE_BACKEND_ICBMSG +module-str = ICMSG backend with separate buffers +module-help = Sets log level for ICMsg backend with buffers +source "subsys/logging/Kconfig.template.log_config" + +endif # IPC_SERVICE_BACKEND_ICBMSG diff --git a/subsys/ipc/ipc_service/backends/ipc_icbmsg.c b/subsys/ipc/ipc_service/backends/ipc_icbmsg.c new file mode 100644 index 000000000000000..cb4d91d7e8ad6ba --- /dev/null +++ b/subsys/ipc/ipc_service/backends/ipc_icbmsg.c @@ -0,0 +1,1303 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * ICBMsg backend. + * + * This is an IPC service backend that dynamically allocates buffers for data storage + * and uses ICMsg to send references to them. + * + * Shared memory organization + * -------------------------- + * + * Single channel (RX or TX) of the shared memory is divided into two areas: ICMsg area + * followed by Blocks area. ICMsg is used to send and receive short 3-byte messages. + * Blocks area is evenly divided into aligned blocks. Blocks are used to allocate + * buffers containing actual data. Data buffers can span multiple blocks. The first block + * starts with the size of the following data. + * + * +------------+-------------+ + * | ICMsg area | Blocks area | + * +------------+-------------+ + * _______/ \_________________________________________ + * / \ + * +-----------+-----------+-----------+-----------+- -+-----------+ + * | Block 0 | Block 1 | Block 2 | Block 3 | ... | Block N-1 | + * +-----------+-----------+-----------+-----------+- -+-----------+ + * _____/ \_____ + * / \ + * +------+--------------------------------+---------+ + * | size | data_buffer[size] ... | padding | + * +------+--------------------------------+---------+ + * + * The sender holds information about reserved blocks using bitarray and it is responsible + * for allocating and releasing the blocks. The receiver just tells the sender that it + * does not need a specific buffer anymore. + * + * Control messages + * ---------------- + * + * ICMsg is used to send and receive small 3-byte control messages. + * + * - Send data + * | MSG_DATA | endpoint address | block index | + * This message is used to send data buffer to specific endpoint. + * + * - Release data + * | MSG_RELEASE_DATA | 0 | block index | + * This message is a response to the "Send data" message and it is used to inform that + * specific buffer is not used anymore and can be released. Endpoint addresses does + * not matter here, so it is zero. + * + * - Bound endpoint + * | MSG_BOUND | endpoint address | block index | + * This message starts the bounding of the endpoint. The buffer contains a + * null-terminated endpoint name. + * + * - Release bound endpoint + * | MSG_RELEASE_BOUND | endpoint address | block index | + * This message is a response to the "Bound endpoint" message and it is used to inform + * that a specific buffer (starting at "block index") is not used anymore and + * a the endpoint is bounded and can now receive a data. + * + * Bounding endpoints + * ------------------ + * + * When ICMsg is bounded and user registers an endpoint on initiator side, the backend + * sends "Bound endpoint". Endpoint address is assigned by the initiator. When follower + * gets the message and user on follower side also registered the same endpoint, + * the backend calls "bound" callback and sends back "Release bound endpoint". + * The follower saves the endpoint address. The follower's endpoint is ready to send + * and receive data. When the initiator gets "Release bound endpoint" message or any + * data messages, it calls bound endpoint and it is ready to send data. + */ + +#include + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(ipc_icbmsg, + CONFIG_IPC_SERVICE_BACKEND_ICBMSG_LOG_LEVEL); + +#define DT_DRV_COMPAT zephyr_ipc_icbmsg + +/** Allowed number of endpoints. */ +#define NUM_EPT CONFIG_IPC_SERVICE_BACKEND_ICBMSG_NUM_EP + +/** Special endpoint address indicating invalid (or empty) entry. */ +#define EPT_ADDR_INVALID 0xFF + +/** Special value for empty entry in bound message waiting table. */ +#define WAITING_BOUND_MSG_EMPTY 0xFFFF + +/** Size of the header (size field) of the block. */ +#define BLOCK_HEADER_SIZE (sizeof(struct block_header)) + +/** Flag indicating that ICMsg was bounded for this instance. */ +#define CONTROL_BOUNDED BIT(31) + +/** Registered endpoints count mask in flags. */ +#define FLAG_EPT_COUNT_MASK 0xFFFF + +enum msg_type { + MSG_DATA = 0, /* Data message. */ + MSG_RELEASE_DATA, /* Release data buffer message. */ + MSG_BOUND, /* Endpoint bounding message. */ + MSG_RELEASE_BOUND, /* Release endpoint bound message. + * This message is also indicator for the receiving side + * that the endpoint bounding was fully processed on + * the sender side. + */ +}; + +enum ept_bounding_state { + EPT_UNCONFIGURED = 0, /* Endpoint in not configured (initial state). */ + EPT_CONFIGURED, /* Endpoint is configured, waiting for work queue to + * start bounding process. + */ + EPT_BOUNDING, /* Only on initiator. Bound message was send, + * but bound callback was not called yet, because + * we are waiting for any incoming messages. + */ + EPT_READY, /* Bounding is done. Bound callback was called. */ +}; + +struct channel_config { + uint8_t *blocks_ptr; /* Address where the blocks start. */ + size_t block_size; /* Size of one block. */ + size_t block_count; /* Number of blocks. */ +}; + +struct icbmsg_config { + struct icmsg_config_t control_config; /* Configuration of the ICMsg. */ + struct channel_config rx; /* RX channel config. */ + struct channel_config tx; /* TX channel config. */ + sys_bitarray_t *tx_usage_bitmap; /* Bit is set when TX block is in use */ + sys_bitarray_t *rx_hold_bitmap; /* Bit is set, if the buffer starting at + * this block should be kept after exit + * from receive handler. + */ +}; + +struct ept_data { + const struct ipc_ept_cfg *cfg; /* Endpoint configuration. */ + atomic_t state; /* Bounding state. */ + uint8_t addr; /* Endpoint address. */ +}; + +struct backend_data { + const struct icbmsg_config *conf;/* Backend instance config. */ + struct icmsg_data_t control_data;/* ICMsg data. */ + struct k_mutex mutex; /* Mutex to protect: ICMsg send call and + * waiting_bound field. + */ + struct k_work ep_bound_work; /* Work item for bounding processing. */ + struct k_sem block_wait_sem; /* Semaphore for waiting for free blocks. */ + struct ept_data ept[NUM_EPT]; /* Array of registered endpoints. */ + uint8_t ept_map[NUM_EPT]; /* Array that maps endpoint address to index. */ + uint16_t waiting_bound[NUM_EPT];/* The bound messages waiting to be registered. */ + atomic_t flags; /* Flags on higher bits, number of registered + * endpoints on lower. + */ + bool is_initiator; /* This side has an initiator role. */ +}; + +struct block_header { + volatile size_t size; /* Size of the data field. It must be volatile, because + * when this value is read and validated for security + * reasons, compiler cannot generate code that reads + * it again after validation. + */ +}; + +struct block_content { + struct block_header header; + uint8_t data[]; /* Buffer data. */ +}; + +struct control_message { + uint8_t msg_type; /* Message type. */ + uint8_t ept_addr; /* Endpoint address or zero for MSG_RELEASE_DATA. */ + uint8_t block_index; /* Block index to send or release. */ +}; + +BUILD_ASSERT(NUM_EPT <= EPT_ADDR_INVALID, "Too many endpoints"); + +/** + * Calculate pointer to block from its index and channel configuration (RX or TX). + * No validation is performed. + */ +static struct block_content *block_from_index(const struct channel_config *ch_conf, + size_t block_index) +{ + return (struct block_content *)(ch_conf->blocks_ptr + + block_index * ch_conf->block_size); +} + +/** + * Calculate pointer to data buffer from block index and channel configuration (RX or TX). + * Also validate the index and optionally the buffer size allocated on the this block. + * + * @param[in] ch_conf The channel + * @param[in] block_index Block index + * @param[out] size Size of the buffer allocated on the block if not NULL. + * The size is also checked if it fits in the blocks area. + * If it is NULL, no size validation is performed. + * @param[in] invalidate_cache If size is not NULL, invalidates cache for entire buffer + * (all blocks). Otherwise, it is ignored. + * @return Pointer to data buffer or NULL if validation failed. + */ +static uint8_t *buffer_from_index_validate(const struct channel_config *ch_conf, + size_t block_index, size_t *size, + bool invalidate_cache) +{ + size_t allocable_size; + size_t buffer_size; + uint8_t *end_ptr; + struct block_content *block; + + if (block_index >= ch_conf->block_count) { + LOG_ERR("Block index invalid"); + return NULL; + } + + block = block_from_index(ch_conf, block_index); + + if (size != NULL) { + if (invalidate_cache) { + sys_cache_data_invd_range(block, BLOCK_HEADER_SIZE); + __sync_synchronize(); + } + allocable_size = ch_conf->block_count * ch_conf->block_size; + end_ptr = ch_conf->blocks_ptr + allocable_size; + buffer_size = block->header.size; + + if ((buffer_size > allocable_size - BLOCK_HEADER_SIZE) || + (&block->data[buffer_size] > end_ptr)) { + LOG_ERR("Block corrupted"); + return NULL; + } + + *size = buffer_size; + if (invalidate_cache) { + sys_cache_data_invd_range(block->data, buffer_size); + __sync_synchronize(); + } + } + + return block->data; +} + +/** + * Calculate block index based on data buffer pointer and validate it. + * + * @param[in] ch_conf The channel + * @param[in] buffer Pointer to data buffer + * @param[out] size Size of the allocated buffer if not NULL. + * The size is also checked if it fits in the blocks area. + * If it is NULL, no size validation is performed. + * @return Block index or negative error code + * @retval -EINVAL The buffer is not correct + */ +static int buffer_to_index_validate(const struct channel_config *ch_conf, + const uint8_t *buffer, size_t *size) +{ + size_t block_index; + uint8_t *expected; + + block_index = (buffer - ch_conf->blocks_ptr) / ch_conf->block_size; + + expected = buffer_from_index_validate(ch_conf, block_index, size, false); + + if (expected == NULL || expected != buffer) { + LOG_ERR("Pointer invalid"); + return -EINVAL; + } + + return block_index; +} + +/** + * Allocate buffer for transmission + * + * @param[in,out] size Required size of the buffer. If zero, first available block is + * allocated and all subsequent available blocks. Size actually + * allocated which is not less than requested. + * @param[out] buffer Allocated buffer data. + * @param[in] timeout Timeout. + * + * @return Positive index of the first allocated block or negative error. + * @retval -EINVAL If requested size is bigger than entire allocable space. + * @retval -ENOSPC If timeout was K_NO_WAIT and there was not enough space. + * @retval -EAGAIN If timeout occurred. + */ +static int alloc_tx_buffer(struct backend_data *dev_data, uint32_t *size, + uint8_t **buffer, k_timeout_t timeout) +{ + const struct icbmsg_config *conf = dev_data->conf; + size_t total_size = *size + BLOCK_HEADER_SIZE; + size_t num_blocks = DIV_ROUND_UP(total_size, conf->tx.block_size); + struct block_content *block; + bool sem_taken = false; + size_t tx_block_index; + size_t next_bit; + int prev_bit_val; + int r; + + do { + /* Try to allocate specified number of blocks. */ + r = sys_bitarray_alloc(conf->tx_usage_bitmap, num_blocks, + &tx_block_index); + if (r == -ENOSPC && !K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { + /* Wait for releasing if there is no enough space and exit loop + * on timeout. + */ + r = k_sem_take(&dev_data->block_wait_sem, timeout); + if (r < 0) { + break; + } + sem_taken = true; + } else { + /* Exit loop if space was allocated or other error occurred. */ + break; + } + } while (true); + + /* If semaphore was taken, give it back because this thread does not + * necessary took all available space, so other thread may need it. + */ + if (sem_taken) { + k_sem_give(&dev_data->block_wait_sem); + } + + if (r < 0) { + if (r != -ENOSPC && r != -EAGAIN) { + LOG_ERR("Failed to allocate buffer, err: %d", r); + /* Only -EINVAL is allowed in this place. Any other code + * indicates something wrong with the logic. + */ + __ASSERT_NO_MSG(r == -EINVAL); + } + + if (r == -ENOSPC || r == -EINVAL) { + /* IPC service require -ENOMEM error in case of no memory. */ + r = -ENOMEM; + } + return r; + } + + /* If size is 0 try to allocate more blocks after already allocated. */ + if (*size == 0) { + prev_bit_val = 0; + for (next_bit = tx_block_index + 1; next_bit < conf->tx.block_count; + next_bit++) { + r = sys_bitarray_test_and_set_bit(conf->tx_usage_bitmap, next_bit, + &prev_bit_val); + /** Setting bit should always success. */ + __ASSERT_NO_MSG(r == 0); + if (prev_bit_val) { + break; + } + } + num_blocks = next_bit - tx_block_index; + } + + /* Get block pointer and adjust size to actually allocated space. */ + *size = conf->tx.block_size * num_blocks - BLOCK_HEADER_SIZE; + block = block_from_index(&conf->tx, tx_block_index); + block->header.size = *size; + *buffer = block->data; + return tx_block_index; +} + +/** + * Release all or part of the blocks occupied by the buffer. + * + * @param[in] tx_block_index First block index to release, no validation is performed, + * so caller is responsible for passing valid index. + * @param[in] size Size of data buffer, no validation is performed, + * so caller is responsible for passing valid size. + * @param[in] new_size If less than zero, release all blocks, otherwise reduce + * size to this value and update size in block header. + * + * @returns Positive block index where the buffer starts or negative error. + * @retval -EINVAL If invalid buffer was provided or size is greater than already + * allocated size. + */ +static int release_tx_blocks(struct backend_data *dev_data, size_t tx_block_index, + size_t size, int new_size) +{ + const struct icbmsg_config *conf = dev_data->conf; + struct block_content *block; + size_t num_blocks; + size_t total_size; + size_t new_total_size; + size_t new_num_blocks; + size_t release_index; + int r; + + /* Calculate number of blocks. */ + total_size = size + BLOCK_HEADER_SIZE; + num_blocks = DIV_ROUND_UP(total_size, conf->tx.block_size); + + if (new_size >= 0) { + /* Calculate and validate new values. */ + new_total_size = new_size + BLOCK_HEADER_SIZE; + new_num_blocks = DIV_ROUND_UP(new_total_size, conf->tx.block_size); + if (new_num_blocks > num_blocks) { + LOG_ERR("Requested %d blocks, allocated %d", new_num_blocks, + num_blocks); + return -EINVAL; + } + /* Update actual buffer size and number of blocks to release. */ + block = block_from_index(&conf->tx, tx_block_index); + block->header.size = new_size; + release_index = tx_block_index + new_num_blocks; + num_blocks = num_blocks - new_num_blocks; + } else { + /* If size is negative, release all blocks. */ + release_index = tx_block_index; + } + + if (num_blocks > 0) { + /* Free bits in the bitmap. */ + r = sys_bitarray_free(conf->tx_usage_bitmap, num_blocks, + release_index); + if (r < 0) { + LOG_ERR("Cannot free bits, err %d", r); + return r; + } + + /* Wake up all waiting threads. */ + k_sem_give(&dev_data->block_wait_sem); + } + + return tx_block_index; +} + +/** + * Release all or part of the blocks occupied by the buffer. + * + * @param[in] buffer Buffer to release. + * @param[in] new_size If less than zero, release all blocks, otherwise reduce size to + * this value and update size in block header. + * + * @returns Positive block index where the buffer starts or negative error. + * @retval -EINVAL If invalid buffer was provided or size is greater than already + * allocated size. + */ +static int release_tx_buffer(struct backend_data *dev_data, const uint8_t *buffer, + int new_size) +{ + const struct icbmsg_config *conf = dev_data->conf; + size_t size; + int tx_block_index; + + tx_block_index = buffer_to_index_validate(&conf->tx, buffer, &size); + if (tx_block_index < 0) { + return tx_block_index; + } + + return release_tx_blocks(dev_data, tx_block_index, size, new_size); +} + +/** + * Send control message over ICMsg with mutex locked. Mutex must be locked because + * ICMsg may return error on concurrent invocations even when there is enough space + * in queue. + */ +static int send_control_message(struct backend_data *dev_data, enum msg_type msg_type, + uint8_t ept_addr, uint8_t block_index) +{ + const struct icbmsg_config *conf = dev_data->conf; + const struct control_message message = { + .msg_type = (uint8_t)msg_type, + .ept_addr = ept_addr, + .block_index = block_index, + }; + int r; + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + r = icmsg_send(&conf->control_config, &dev_data->control_data, &message, + sizeof(message)); + k_mutex_unlock(&dev_data->mutex); + if (r < 0) { + LOG_ERR("Cannot send over ICMsg, err %d", r); + } + return r; +} + +/** + * Release received buffer. This function will just send release control message. + * + * @param[in] buffer Buffer to release. + * @param[in] msg_type Message type: MSG_RELEASE_BOUND or MSG_RELEASE_DATA. + * @param[in] ept_addr Endpoint address or zero for MSG_RELEASE_DATA. + * + * @return zero or ICMsg send error. + */ +static int send_release(struct backend_data *dev_data, const uint8_t *buffer, + enum msg_type msg_type, uint8_t ept_addr) +{ + const struct icbmsg_config *conf = dev_data->conf; + int rx_block_index; + + rx_block_index = buffer_to_index_validate(&conf->rx, buffer, NULL); + if (rx_block_index < 0) { + return rx_block_index; + } + + return send_control_message(dev_data, msg_type, ept_addr, rx_block_index); +} + +/** + * Send data contained in specified block. It will adjust data size and flush cache + * if necessary. If sending failed, allocated blocks will be released. + * + * @param[in] msg_type Message type: MSG_BOUND or MSG_DATA. + * @param[in] ept_addr Endpoints address. + * @param[in] tx_block_index Index of first block containing data, it is not validated, + * so caller is responsible for passing only valid index. + * @param[in] size Actual size of the data, can be smaller than allocated, + * but it cannot change number of required blocks. + * + * @return O or negative error code. + */ +static int send_block(struct backend_data *dev_data, enum msg_type msg_type, + uint8_t ept_addr, size_t tx_block_index, size_t size) +{ + struct block_content *block; + int r; + + block = block_from_index(&dev_data->conf->tx, tx_block_index); + + block->header.size = size; + __sync_synchronize(); + sys_cache_data_flush_range(block, size + BLOCK_HEADER_SIZE); + + r = send_control_message(dev_data, msg_type, ept_addr, tx_block_index); + if (r < 0) { + release_tx_blocks(dev_data, tx_block_index, size, -1); + } + + return r; +} + +/** + * Find endpoint that was registered with name that matches name + * contained in the endpoint bound message received from remote. + * + * @param[in] name Endpoint name, it must be in a received block. + * + * @return Found endpoint index or -ENOENT if not found. + */ +static int find_ept_by_name(struct backend_data *dev_data, const char *name) +{ + const struct channel_config *rx_conf = &dev_data->conf->rx; + const char *buffer_end = (const char *)rx_conf->blocks_ptr + + rx_conf->block_count * rx_conf->block_size; + struct ept_data *ept; + size_t name_size; + size_t i; + + /* Requested name is in shared memory, so we have to assume that it + * can be corrupted. Extra care must be taken to avoid out of + * bounds reads. + */ + name_size = strnlen(name, buffer_end - name - 1) + 1; + + for (i = 0; i < NUM_EPT; i++) { + ept = &dev_data->ept[i]; + if (atomic_get(&ept->state) == EPT_CONFIGURED && + strncmp(ept->cfg->name, name, name_size) == 0) { + return i; + } + } + + return -ENOENT; +} + +/** + * Find registered endpoint that matches given "bound endpoint" message. When found, + * the "release bound endpoint" message is send. + * + * @param[in] rx_block_index Block containing the "bound endpoint" message. + * @param[in] ept_addr Endpoint address. + * + * @return negative error code or non-negative search result. + * @retval 0 match not found. + * @retval 1 match found and processing was successful. + */ +static int match_bound_msg(struct backend_data *dev_data, size_t rx_block_index, + uint8_t ept_addr) +{ + const struct icbmsg_config *conf = dev_data->conf; + struct block_content *block; + uint8_t *buffer; + int ept_index; + struct ept_data *ept; + int r; + bool valid_state; + + /* Find endpoint that matches requested name. */ + block = block_from_index(&conf->rx, rx_block_index); + buffer = block->data; + ept_index = find_ept_by_name(dev_data, buffer); + if (ept_index < 0) { + return 0; + } + + /* Set endpoint address and mapping. Move it to "ready" state. */ + ept = &dev_data->ept[ept_index]; + ept->addr = ept_addr; + dev_data->ept_map[ept->addr] = ept_index; + valid_state = atomic_cas(&ept->state, EPT_CONFIGURED, EPT_READY); + if (!valid_state) { + LOG_ERR("Unexpected bounding from remote on endpoint %d", ept_addr); + return -EINVAL; + } + + /* Endpoint is ready to send messages, so call bound callback. */ + if (ept->cfg->cb.bound != NULL) { + ept->cfg->cb.bound(ept->cfg->priv); + } + + /* Release the bound message and inform remote that we are ready to receive. */ + r = send_release(dev_data, buffer, MSG_RELEASE_BOUND, ept_addr); + if (r < 0) { + return r; + } + + return 1; +} + +/** + * Send bound message on specified endpoint. + * + * @param[in] ept Endpoint to use. + * + * @return O or negative error code. + */ +static int send_bound_message(struct backend_data *dev_data, struct ept_data *ept) +{ + size_t msg_len; + uint32_t alloc_size; + uint8_t *buffer; + int r; + + msg_len = strlen(ept->cfg->name) + 1; + alloc_size = msg_len; + r = alloc_tx_buffer(dev_data, &alloc_size, &buffer, K_FOREVER); + if (r >= 0) { + strcpy(buffer, ept->cfg->name); + r = send_block(dev_data, MSG_BOUND, ept->addr, r, msg_len); + } + + return r; +} + +/** + * Put endpoint bound processing into system workqueue. + */ +static void schedule_ept_bound_process(struct backend_data *dev_data) +{ + k_work_submit(&dev_data->ep_bound_work); +} + +/** + * Work handler that is responsible to start bounding when ICMsg is bound. + */ +static void ept_bound_process(struct k_work *item) +{ + struct backend_data *dev_data = CONTAINER_OF(item, struct backend_data, + ep_bound_work); + struct ept_data *ept = NULL; + size_t i; + int r = 0; + bool matching_state; + + /* Skip processing if ICMsg was not bounded yet. */ + if (!(atomic_get(&dev_data->flags) & CONTROL_BOUNDED)) { + return; + } + + if (dev_data->is_initiator) { + /* Initiator just sends bound message after endpoint was registered. */ + for (i = 0; i < NUM_EPT; i++) { + ept = &dev_data->ept[i]; + matching_state = atomic_cas(&ept->state, EPT_CONFIGURED, + EPT_BOUNDING); + if (matching_state) { + r = send_bound_message(dev_data, ept); + if (r < 0) { + atomic_set(&ept->state, EPT_UNCONFIGURED); + LOG_ERR("Failed to send bound, err %d", r); + } + } + } + } else { + /* Walk over all waiting bound messages and match to local endpoints. */ + k_mutex_lock(&dev_data->mutex, K_FOREVER); + for (i = 0; i < NUM_EPT; i++) { + if (dev_data->waiting_bound[i] != WAITING_BOUND_MSG_EMPTY) { + k_mutex_unlock(&dev_data->mutex); + r = match_bound_msg(dev_data, + dev_data->waiting_bound[i], i); + k_mutex_lock(&dev_data->mutex, K_FOREVER); + if (r != 0) { + dev_data->waiting_bound[i] = + WAITING_BOUND_MSG_EMPTY; + if (r < 0) { + LOG_ERR("Failed bound, err %d", r); + } + } + } + } + k_mutex_unlock(&dev_data->mutex); + } +} + +/** + * Get endpoint from endpoint address. Also validates if the address is correct and + * endpoint is in correct state for receiving. If bounding callback was not called yet, + * then call it. + */ +static struct ept_data *get_ept_and_rx_validate(struct backend_data *dev_data, + uint8_t ept_addr) +{ + struct ept_data *ept; + enum ept_bounding_state state; + + if (ept_addr >= NUM_EPT || dev_data->ept_map[ept_addr] >= NUM_EPT) { + LOG_ERR("Received invalid endpoint addr %d", ept_addr); + return NULL; + } + + ept = &dev_data->ept[dev_data->ept_map[ept_addr]]; + + state = atomic_get(&ept->state); + + if (state == EPT_READY) { + /* Valid state - nothing to do. */ + } else if (state == EPT_BOUNDING) { + /* Endpoint bound callback was not called yet - call it. */ + atomic_set(&ept->state, EPT_READY); + if (ept->cfg->cb.bound != NULL) { + ept->cfg->cb.bound(ept->cfg->priv); + } + } else { + LOG_ERR("Invalid state %d of receiving endpoint %d", state, ept->addr); + return NULL; + } + + return ept; +} + +/** + * Data message received. + */ +static int received_data(struct backend_data *dev_data, size_t rx_block_index, + uint8_t ept_addr) +{ + const struct icbmsg_config *conf = dev_data->conf; + uint8_t *buffer; + struct ept_data *ept; + size_t size; + int bit_val; + + /* Validate. */ + buffer = buffer_from_index_validate(&conf->rx, rx_block_index, &size, true); + ept = get_ept_and_rx_validate(dev_data, ept_addr); + if (buffer == NULL || ept == NULL) { + LOG_ERR("Received invalid block index %d or addr %d", rx_block_index, + ept_addr); + return -EINVAL; + } + + /* Clear bit. If cleared, specific block will not be hold after the callback. */ + sys_bitarray_clear_bit(conf->rx_hold_bitmap, rx_block_index); + + /* Call the endpoint callback. It can set the hold bit. */ + ept->cfg->cb.received(buffer, size, ept->cfg->priv); + + /* If the bit is still cleared, request release of the buffer. */ + sys_bitarray_test_bit(conf->rx_hold_bitmap, rx_block_index, &bit_val); + if (!bit_val) { + send_release(dev_data, buffer, MSG_RELEASE_DATA, 0); + } + + return 0; +} + +/** + * Release data message received. + */ +static int received_release_data(struct backend_data *dev_data, size_t tx_block_index) +{ + const struct icbmsg_config *conf = dev_data->conf; + uint8_t *buffer; + size_t size; + int r; + + /* Validate. */ + buffer = buffer_from_index_validate(&conf->tx, tx_block_index, &size, false); + if (buffer == NULL) { + LOG_ERR("Received invalid block index %d", tx_block_index); + return -EINVAL; + } + + /* Release. */ + r = release_tx_blocks(dev_data, tx_block_index, size, -1); + if (r < 0) { + return r; + } + + return r; +} + +/** + * Bound endpoint message received. + */ +static int received_bound(struct backend_data *dev_data, size_t rx_block_index, + uint8_t ept_addr) +{ + const struct icbmsg_config *conf = dev_data->conf; + size_t size; + uint8_t *buffer; + + /* Validate */ + buffer = buffer_from_index_validate(&conf->rx, rx_block_index, &size, true); + if (buffer == NULL) { + LOG_ERR("Received invalid block index %d", rx_block_index); + return -EINVAL; + } + + /* Put message to waiting array. */ + k_mutex_lock(&dev_data->mutex, K_FOREVER); + dev_data->waiting_bound[ept_addr] = rx_block_index; + k_mutex_unlock(&dev_data->mutex); + + /* Schedule processing the message. */ + schedule_ept_bound_process(dev_data); + + return 0; +} + +/** + * Callback called by ICMsg that handles message (data or endpoint bound) received + * from the remote. + * + * @param[in] data Message received from the ICMsg. + * @param[in] len Number of bytes of data. + * @param[in] priv Opaque pointer to device instance. + */ +static void control_received(const void *data, size_t len, void *priv) +{ + const struct device *instance = priv; + struct backend_data *dev_data = instance->data; + const struct control_message *message = (const struct control_message *)data; + struct ept_data *ept; + uint8_t ept_addr; + int r = 0; + + /* Allow messages longer than 3 bytes, e.g. for future protocol versions. */ + if (len < sizeof(struct control_message)) { + r = -EINVAL; + goto exit; + } + + ept_addr = message->ept_addr; + if (ept_addr >= NUM_EPT) { + r = -EINVAL; + goto exit; + } + + switch (message->msg_type) { + case MSG_RELEASE_DATA: + r = received_release_data(dev_data, message->block_index); + break; + case MSG_RELEASE_BOUND: + r = received_release_data(dev_data, message->block_index); + if (r >= 0) { + ept = get_ept_and_rx_validate(dev_data, ept_addr); + if (ept == NULL) { + r = -EINVAL; + } + } + break; + case MSG_BOUND: + r = received_bound(dev_data, message->block_index, ept_addr); + break; + case MSG_DATA: + r = received_data(dev_data, message->block_index, ept_addr); + break; + default: + /* Silently ignore other messages types. They can be used in future + * protocol version. + */ + break; + } + +exit: + if (r < 0) { + LOG_ERR("Failed to receive, err %d", r); + } +} + +/** + * Callback called when ICMsg is bound. + */ +static void control_bound(void *priv) +{ + const struct device *instance = priv; + struct backend_data *dev_data = instance->data; + + /* Set flag that ICMsg is bounded and now, endpoint bounding may start. */ + atomic_or(&dev_data->flags, CONTROL_BOUNDED); + schedule_ept_bound_process(dev_data); +} + +/** + * Open the backend instance callback. + */ +static int open(const struct device *instance) +{ + const struct icbmsg_config *conf = instance->config; + struct backend_data *dev_data = instance->data; + + static const struct ipc_service_cb cb = { + .bound = control_bound, + .received = control_received, + .error = NULL, + }; + + LOG_DBG("Open instance 0x%08X, initiator=%d", (uint32_t)instance, + dev_data->is_initiator ? 1 : 0); + LOG_DBG(" TX %d blocks of %d bytes at 0x%08X, max allocable %d bytes", + (uint32_t)conf->tx.block_count, + (uint32_t)conf->tx.block_size, + (uint32_t)conf->tx.blocks_ptr, + (uint32_t)(conf->tx.block_size * conf->tx.block_count - + BLOCK_HEADER_SIZE)); + LOG_DBG(" RX %d blocks of %d bytes at 0x%08X, max allocable %d bytes", + (uint32_t)conf->rx.block_count, + (uint32_t)conf->rx.block_size, + (uint32_t)conf->rx.blocks_ptr, + (uint32_t)(conf->rx.block_size * conf->rx.block_count - + BLOCK_HEADER_SIZE)); + + return icmsg_open(&conf->control_config, &dev_data->control_data, &cb, + (void *)instance); +} + +/** + * Endpoint send callback function (with copy). + */ +static int send(const struct device *instance, void *token, const void *msg, size_t len) +{ + struct backend_data *dev_data = instance->data; + struct ept_data *ept = token; + uint32_t alloc_size; + uint8_t *buffer; + int r; + + /* Allocate the buffer. */ + alloc_size = len; + r = alloc_tx_buffer(dev_data, &alloc_size, &buffer, K_NO_WAIT); + if (r < 0) { + return r; + } + + /* Copy data to allocated buffer. */ + memcpy(buffer, msg, len); + + /* Send data message. */ + return send_block(dev_data, MSG_DATA, ept->addr, r, len); +} + +/** + * Backend endpoint registration callback. + */ +static int register_ept(const struct device *instance, void **token, + const struct ipc_ept_cfg *cfg) +{ + struct backend_data *dev_data = instance->data; + struct ept_data *ept = NULL; + int ept_index; + int r = 0; + + /* Reserve new endpoint index. */ + ept_index = atomic_inc(&dev_data->flags) & FLAG_EPT_COUNT_MASK; + if (ept_index >= NUM_EPT) { + LOG_ERR("Too many endpoints"); + __ASSERT_NO_MSG(false); + return -ENOMEM; + } + + /* Add new endpoint. */ + ept = &dev_data->ept[ept_index]; + ept->cfg = cfg; + if (dev_data->is_initiator) { + ept->addr = ept_index; + dev_data->ept_map[ept->addr] = ept->addr; + } + atomic_set(&ept->state, EPT_CONFIGURED); + + /* Keep endpoint address in token. */ + *token = ept; + + /* Rest of the bounding will be done in the system workqueue. */ + schedule_ept_bound_process(dev_data); + + return r; +} + +/** + * Returns maximum TX buffer size. + */ +static int get_tx_buffer_size(const struct device *instance, void *token) +{ + const struct icbmsg_config *conf = instance->config; + + return conf->tx.block_size * conf->tx.block_count - BLOCK_HEADER_SIZE; +} + +/** + * Endpoint TX buffer allocation callback for nocopy sending. + */ +static int get_tx_buffer(const struct device *instance, void *token, void **data, + uint32_t *user_len, k_timeout_t wait) +{ + struct backend_data *dev_data = instance->data; + int r; + + r = alloc_tx_buffer(dev_data, user_len, (uint8_t **)data, wait); + if (r < 0) { + return r; + } + return 0; +} + +/** + * Endpoint TX buffer release callback for nocopy sending. + */ +static int drop_tx_buffer(const struct device *instance, void *token, const void *data) +{ + struct backend_data *dev_data = instance->data; + int r; + + r = release_tx_buffer(dev_data, data, -1); + if (r < 0) { + return r; + } + + return 0; +} + +/** + * Endpoint nocopy sending. + */ +static int send_nocopy(const struct device *instance, void *token, const void *data, + size_t len) +{ + struct backend_data *dev_data = instance->data; + struct ept_data *ept = token; + int r; + + /* Actual size may be smaller than requested, so shrink if possible. */ + r = release_tx_buffer(dev_data, data, len); + if (r < 0) { + release_tx_buffer(dev_data, data, -1); + return r; + } + + return send_block(dev_data, MSG_DATA, ept->addr, r, len); +} + +/** + * Holding RX buffer for nocopy receiving. + */ +static int hold_rx_buffer(const struct device *instance, void *token, void *data) +{ + const struct icbmsg_config *conf = instance->config; + int rx_block_index; + uint8_t *buffer = data; + + /* Calculate block index and set associated bit. */ + rx_block_index = buffer_to_index_validate(&conf->rx, buffer, NULL); + __ASSERT_NO_MSG(rx_block_index >= 0); + return sys_bitarray_set_bit(conf->rx_hold_bitmap, rx_block_index); +} + +/** + * Release RX buffer that was previously held. + */ +static int release_rx_buffer(const struct device *instance, void *token, void *data) +{ + struct backend_data *dev_data = instance->data; + + return send_release(dev_data, (uint8_t *)data, MSG_RELEASE_DATA, 0); +} + +/** + * Backend device initialization. + */ +static int backend_init(const struct device *instance) +{ + const struct icbmsg_config *conf = instance->config; + struct backend_data *dev_data = instance->data; + + dev_data->conf = conf; + dev_data->is_initiator = (conf->rx.blocks_ptr < conf->tx.blocks_ptr); + k_mutex_init(&dev_data->mutex); + k_work_init(&dev_data->ep_bound_work, ept_bound_process); + k_sem_init(&dev_data->block_wait_sem, 0, 1); + memset(&dev_data->waiting_bound, 0xFF, sizeof(dev_data->waiting_bound)); + memset(&dev_data->ept_map, EPT_ADDR_INVALID, sizeof(dev_data->ept_map)); + return 0; +} + +/** + * IPC service backend callbacks. + */ +const static struct ipc_service_backend backend_ops = { + .open_instance = open, + .close_instance = NULL, /* not implemented */ + .send = send, + .register_endpoint = register_ept, + .deregister_endpoint = NULL, /* not implemented */ + .get_tx_buffer_size = get_tx_buffer_size, + .get_tx_buffer = get_tx_buffer, + .drop_tx_buffer = drop_tx_buffer, + .send_nocopy = send_nocopy, + .hold_rx_buffer = hold_rx_buffer, + .release_rx_buffer = release_rx_buffer, +}; + +/** + * Number of bytes per each ICMsg message. It is used to calculate size of ICMsg area. + */ +#define BYTES_PER_ICMSG_MESSAGE (ROUND_UP(sizeof(struct control_message), \ + sizeof(void *)) + PBUF_PACKET_LEN_SZ) + +/** + * Maximum ICMsg overhead. It is used to calculate size of ICMsg area. + */ +#define ICMSG_BUFFER_OVERHEAD(i) \ + (PBUF_HEADER_OVERHEAD(GET_CACHE_ALIGNMENT(i)) + 2 * BYTES_PER_ICMSG_MESSAGE) + +/** + * Returns required block alignment for instance "i". + */ +#define GET_CACHE_ALIGNMENT(i) \ + MAX(sizeof(uint32_t), DT_INST_PROP_OR(i, dcache_alignment, 0)) + +/** + * Calculates minimum size required for ICMsg region for specific number of local + * and remote blocks. The minimum size ensures that ICMsg queue is will never overflow + * because it can hold data message for each local block and release message + * for each remote block. + */ +#define GET_ICMSG_MIN_SIZE(i, local_blocks, remote_blocks) \ + (ICMSG_BUFFER_OVERHEAD(i) + BYTES_PER_ICMSG_MESSAGE * \ + (local_blocks + remote_blocks)) + +/** + * Calculate aligned block size by evenly dividing remaining space after removing + * the space for ICMsg. + */ +#define GET_BLOCK_SIZE(i, total_size, local_blocks, remote_blocks) ROUND_DOWN( \ + ((total_size) - GET_ICMSG_MIN_SIZE(i, (local_blocks), (remote_blocks))) / \ + (local_blocks), GET_CACHE_ALIGNMENT(i)) + +/** + * Calculate offset where area for blocks starts which is just after the ICMsg. + */ +#define GET_BLOCKS_OFFSET(i, total_size, local_blocks, remote_blocks) \ + ((total_size) - GET_BLOCK_SIZE(i, (total_size), (local_blocks), \ + (remote_blocks)) * (local_blocks)) + +/** + * Return shared memory start address aligned to block alignment and cache line. + */ +#define GET_MEM_ADDR_INST(i, direction) \ + ROUND_UP(DT_REG_ADDR(DT_INST_PHANDLE(i, direction##_region)), \ + GET_CACHE_ALIGNMENT(i)) + +/** + * Return shared memory end address aligned to block alignment and cache line. + */ +#define GET_MEM_END_INST(i, direction) \ + ROUND_DOWN(DT_REG_ADDR(DT_INST_PHANDLE(i, direction##_region)) + \ + DT_REG_SIZE(DT_INST_PHANDLE(i, direction##_region)), \ + GET_CACHE_ALIGNMENT(i)) + +/** + * Return shared memory size aligned to block alignment and cache line. + */ +#define GET_MEM_SIZE_INST(i, direction) \ + (GET_MEM_END_INST(i, direction) - GET_MEM_ADDR_INST(i, direction)) + +/** + * Returns GET_ICMSG_SIZE, but for specific instance and direction. + * 'loc' and 'rem' parameters tells the direction. They can be either "tx, rx" + * or "rx, tx". + */ +#define GET_ICMSG_SIZE_INST(i, loc, rem) \ + GET_BLOCKS_OFFSET( \ + i, \ + GET_MEM_SIZE_INST(i, loc), \ + DT_INST_PROP(i, loc##_blocks), \ + DT_INST_PROP(i, rem##_blocks)) + +/** + * Returns address where area for blocks starts for specific instance and direction. + * 'loc' and 'rem' parameters tells the direction. They can be either "tx, rx" + * or "rx, tx". + */ +#define GET_BLOCKS_ADDR_INST(i, loc, rem) \ + GET_MEM_ADDR_INST(i, loc) + \ + GET_BLOCKS_OFFSET( \ + i, \ + GET_MEM_SIZE_INST(i, loc), \ + DT_INST_PROP(i, loc##_blocks), \ + DT_INST_PROP(i, rem##_blocks)) + +/** + * Returns block size for specific instance and direction. + * 'loc' and 'rem' parameters tells the direction. They can be either "tx, rx" + * or "rx, tx". + */ +#define GET_BLOCK_SIZE_INST(i, loc, rem) \ + GET_BLOCK_SIZE( \ + i, \ + GET_MEM_SIZE_INST(i, loc), \ + DT_INST_PROP(i, loc##_blocks), \ + DT_INST_PROP(i, rem##_blocks)) + +#define DEFINE_BACKEND_DEVICE(i) \ + SYS_BITARRAY_DEFINE_STATIC(tx_usage_bitmap_##i, DT_INST_PROP(i, tx_blocks)); \ + SYS_BITARRAY_DEFINE_STATIC(rx_hold_bitmap_##i, DT_INST_PROP(i, rx_blocks)); \ + PBUF_DEFINE(tx_icbmsg_pb_##i, \ + GET_MEM_ADDR_INST(i, tx), \ + GET_ICMSG_SIZE_INST(i, tx, rx), \ + GET_CACHE_ALIGNMENT(i)); \ + PBUF_DEFINE(rx_icbmsg_pb_##i, \ + GET_MEM_ADDR_INST(i, rx), \ + GET_ICMSG_SIZE_INST(i, rx, tx), \ + GET_CACHE_ALIGNMENT(i)); \ + static struct backend_data backend_data_##i = { \ + .control_data = { \ + .tx_pb = &tx_icbmsg_pb_##i, \ + .rx_pb = &rx_icbmsg_pb_##i, \ + } \ + }; \ + static const struct icbmsg_config backend_config_##i = \ + { \ + .control_config = { \ + .mbox_tx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(i), tx), \ + .mbox_rx = MBOX_DT_CHANNEL_GET(DT_DRV_INST(i), rx), \ + }, \ + .tx = { \ + .blocks_ptr = (uint8_t *)GET_BLOCKS_ADDR_INST(i, tx, rx), \ + .block_count = DT_INST_PROP(i, tx_blocks), \ + .block_size = GET_BLOCK_SIZE_INST(i, tx, rx), \ + }, \ + .rx = { \ + .blocks_ptr = (uint8_t *)GET_BLOCKS_ADDR_INST(i, rx, tx), \ + .block_count = DT_INST_PROP(i, rx_blocks), \ + .block_size = GET_BLOCK_SIZE_INST(i, rx, tx), \ + }, \ + .tx_usage_bitmap = &tx_usage_bitmap_##i, \ + .rx_hold_bitmap = &rx_hold_bitmap_##i, \ + }; \ + BUILD_ASSERT(IS_POWER_OF_TWO(GET_CACHE_ALIGNMENT(i)), \ + "This module supports only power of two cache alignment"); \ + BUILD_ASSERT((GET_BLOCK_SIZE_INST(i, tx, rx) > GET_CACHE_ALIGNMENT(i)) && \ + (GET_BLOCK_SIZE_INST(i, tx, rx) < \ + GET_MEM_SIZE_INST(i, tx)), \ + "TX region is too small for provided number of blocks"); \ + BUILD_ASSERT((GET_BLOCK_SIZE_INST(i, rx, tx) > GET_CACHE_ALIGNMENT(i)) && \ + (GET_BLOCK_SIZE_INST(i, rx, tx) < \ + GET_MEM_SIZE_INST(i, rx)), \ + "RX region is too small for provided number of blocks"); \ + BUILD_ASSERT(DT_INST_PROP(i, rx_blocks) <= 256, "Too many RX blocks"); \ + BUILD_ASSERT(DT_INST_PROP(i, tx_blocks) <= 256, "Too many TX blocks"); \ + 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) From 23254f2a160e8e955a4545c1cd098b0085a9fac9 Mon Sep 17 00:00:00 2001 From: Dominik Kilian Date: Thu, 9 Nov 2023 12:00:34 +0100 Subject: [PATCH 0283/1049] samples: ipc: Modify icmsg_me sample allowing any multiendpoint backend There are more ipc_service backends that supports multiple endpoint. This sample can be used for any of those backends, so this commits makes the sample more generic. The default backend it still icmsg_me, but now, the sample has files and instructions for icmsg_with_buf backend. Signed-off-by: Dominik Kilian --- .../ipc/ipc_service/icmsg_me/sample.yaml | 10 --- .../CMakeLists.txt | 2 - .../Kconfig.sysbuild | 0 .../ipc/ipc_service/multi_endpoint/README.rst | 73 +++++++++++++++++++ .../boards/nrf5340dk_nrf5340_cpuapp.conf | 0 .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 0 .../nrf5340dk_nrf5340_cpuapp_icbmsg.overlay | 57 +++++++++++++++ .../{icmsg_me => multi_endpoint}/prj.conf | 1 + .../remote/CMakeLists.txt | 0 .../boards/nrf5340dk_nrf5340_cpunet.conf | 0 .../boards/nrf5340dk_nrf5340_cpunet.overlay | 0 .../nrf5340dk_nrf5340_cpunet_icbmsg.overlay | 57 +++++++++++++++ .../remote/prj.conf | 1 + .../remote/src/main.c | 0 .../ipc_service/multi_endpoint/sample.yaml | 19 +++++ .../{icmsg_me => multi_endpoint}/src/main.c | 0 .../sysbuild.cmake | 0 17 files changed, 208 insertions(+), 12 deletions(-) delete mode 100644 samples/subsys/ipc/ipc_service/icmsg_me/sample.yaml rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/CMakeLists.txt (93%) rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/Kconfig.sysbuild (100%) create mode 100644 samples/subsys/ipc/ipc_service/multi_endpoint/README.rst rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/boards/nrf5340dk_nrf5340_cpuapp.conf (100%) rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/boards/nrf5340dk_nrf5340_cpuapp.overlay (100%) create mode 100644 samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/prj.conf (83%) rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/remote/CMakeLists.txt (100%) rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/remote/boards/nrf5340dk_nrf5340_cpunet.conf (100%) rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/remote/boards/nrf5340dk_nrf5340_cpunet.overlay (100%) create mode 100644 samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/remote/prj.conf (83%) rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/remote/src/main.c (100%) create mode 100644 samples/subsys/ipc/ipc_service/multi_endpoint/sample.yaml rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/src/main.c (100%) rename samples/subsys/ipc/ipc_service/{icmsg_me => multi_endpoint}/sysbuild.cmake (100%) diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/sample.yaml b/samples/subsys/ipc/ipc_service/icmsg_me/sample.yaml deleted file mode 100644 index 2fe7f79ef405584..000000000000000 --- a/samples/subsys/ipc/ipc_service/icmsg_me/sample.yaml +++ /dev/null @@ -1,10 +0,0 @@ -sample: - name: IPC Service example integration (icmsg multi endpoint backend) -tests: - sample.ipc.icmsg_me: - platform_allow: nrf5340dk_nrf5340_cpuapp - integration_platforms: - - nrf5340dk_nrf5340_cpuapp - tags: ipc - sysbuild: true - harness: remote diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/CMakeLists.txt b/samples/subsys/ipc/ipc_service/multi_endpoint/CMakeLists.txt similarity index 93% rename from samples/subsys/ipc/ipc_service/icmsg_me/CMakeLists.txt rename to samples/subsys/ipc/ipc_service/multi_endpoint/CMakeLists.txt index 18a138548cfbadb..b342f55061637fa 100644 --- a/samples/subsys/ipc/ipc_service/icmsg_me/CMakeLists.txt +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/CMakeLists.txt @@ -15,5 +15,3 @@ endif() project(ipc_service) target_sources(app PRIVATE src/main.c) - -include(ExternalProject) diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/Kconfig.sysbuild b/samples/subsys/ipc/ipc_service/multi_endpoint/Kconfig.sysbuild similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/Kconfig.sysbuild rename to samples/subsys/ipc/ipc_service/multi_endpoint/Kconfig.sysbuild diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/README.rst b/samples/subsys/ipc/ipc_service/multi_endpoint/README.rst new file mode 100644 index 000000000000000..faff69e007fbc5a --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/README.rst @@ -0,0 +1,73 @@ +.. _ipc_multi_endpoint_sample: + +IPC Service - Multi-endpoint Sample Application +############################################### + +This application demonstrates how to use IPC Service with multiple endpoints. +By default, it uses the ``icmsg_me`` backend. +You can also configure it to use the ``icbmsg`` backend. + +Building the application for nrf5340dk_nrf5340_cpuapp +***************************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/ipc/ipc_service/multi_endpoint + :board: nrf5340dk_nrf5340_cpuapp + :goals: debug + +Open a serial terminal (for example Minicom or PuTTY) and connect the board with the following settings: + +* Speed: 115200 +* Data: 8 bits +* Parity: None +* Stop bits: 1 + +After resetting the board, the following message will appear on the corresponding +serial port: + +.. code-block:: console + + *** Booting Zephyr OS build v3.4.0-rc1-108-gccfbac8b0721 *** + IPC-service HOST [INST 0 - ENDP A] demo started + IPC-service HOST [INST 0 - ENDP B] demo started + IPC-service HOST [INST 1] demo started + HOST [0A]: 1 + HOST [0A]: 3 + HOST [0B]: 1 + HOST [1]: 1 + ... + HOST [0A]: 99 + IPC-service HOST [INST 0 - ENDP A] demo ended. + HOST [0B]: 99 + IPC-service HOST [INST 0 - ENDP B] demo ended. + HOST [1]: 99 + IPC-service HOST [INST 1] demo ended. + +.. code-block:: console + + *** Booting Zephyr OS build v3.4.0-rc1-108-gccfbac8b0721 *** + IPC-service REMOTE [INST 0 - ENDP A] demo started + IPC-service REMOTE [INST 0 - ENDP B] demo started + IPC-service REMOTE [INST 1] demo started + REMOTE [0A]: 0 + REMOTE [0A]: 2 + ... + REMOTE [0A]: 98 + IPC-service REMOTE [INST 0 - ENDP A] demo ended. + REMOTE [0B]: 98 + IPC-service REMOTE [INST 0 - ENDP B] demo ended. + REMOTE [1]: 98 + IPC-service REMOTE [INST 1] demo ended. + + +Changing the backend +******************** + +To change the backend to ``icbmsg``, switch the devicetree +overlay files as follows: + +.. code-block:: console + + west build -b nrf5340dk_nrf5340_cpuapp --sysbuild -- \ + -DDTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay \ + -Dremote_DTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp.conf similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/boards/nrf5340dk_nrf5340_cpuapp.conf rename to samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp.conf diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp.overlay similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/boards/nrf5340dk_nrf5340_cpuapp.overlay rename to samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp.overlay diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay b/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay new file mode 100644 index 000000000000000..3db9db032f4c465 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /delete-property/ zephyr,ipc_shm; + }; + + reserved-memory { + /delete-node/ memory@20070000; + + sram_ipc0_tx: memory@20070000 { + reg = <0x20070000 0x4000>; + }; + + sram_ipc0_rx: memory@20074000 { + reg = <0x20074000 0x4000>; + }; + + sram_ipc1_tx: memory@20078000 { + reg = <0x20078000 0x4000>; + }; + + sram_ipc1_rx: memory@2007C000 { + reg = <0x2007C000 0x4000>; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&sram_ipc0_tx>; + rx-region = <&sram_ipc0_rx>; + tx-blocks = <16>; + rx-blocks = <24>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "tx", "rx"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&sram_ipc1_tx>; + rx-region = <&sram_ipc1_rx>; + tx-blocks = <32>; + rx-blocks = <48>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "tx", "rx"; + status = "okay"; + }; + }; +}; diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/prj.conf b/samples/subsys/ipc/ipc_service/multi_endpoint/prj.conf similarity index 83% rename from samples/subsys/ipc/ipc_service/icmsg_me/prj.conf rename to samples/subsys/ipc/ipc_service/multi_endpoint/prj.conf index 4c5326d139769e2..3d2c799c4eb607c 100644 --- a/samples/subsys/ipc/ipc_service/icmsg_me/prj.conf +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/prj.conf @@ -1,4 +1,5 @@ CONFIG_PRINTK=y +CONFIG_LOG_PRINTK=n CONFIG_IPC_SERVICE=y CONFIG_MBOX=y diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/CMakeLists.txt b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/CMakeLists.txt similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/remote/CMakeLists.txt rename to samples/subsys/ipc/ipc_service/multi_endpoint/remote/CMakeLists.txt diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/boards/nrf5340dk_nrf5340_cpunet.conf b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet.conf similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/remote/boards/nrf5340dk_nrf5340_cpunet.conf rename to samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet.conf diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/boards/nrf5340dk_nrf5340_cpunet.overlay b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet.overlay similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/remote/boards/nrf5340dk_nrf5340_cpunet.overlay rename to samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet.overlay diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay new file mode 100644 index 000000000000000..6247ed812aa8382 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /delete-property/ zephyr,ipc_shm; + }; + + reserved-memory { + /delete-node/ memory@20070000; + + sram_ipc0_rx: memory@20070000 { + reg = <0x20070000 0x4000>; + }; + + sram_ipc0_tx: memory@20074000 { + reg = <0x20074000 0x4000>; + }; + + sram_ipc1_rx: memory@20078000 { + reg = <0x20078000 0x4000>; + }; + + sram_ipc1_tx: memory@2007C000 { + reg = <0x2007C000 0x4000>; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&sram_ipc0_tx>; + rx-region = <&sram_ipc0_rx>; + tx-blocks = <24>; + rx-blocks = <16>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "rx", "tx"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&sram_ipc1_tx>; + rx-region = <&sram_ipc1_rx>; + tx-blocks = <48>; + rx-blocks = <32>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "rx", "tx"; + status = "okay"; + }; + }; +}; diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/prj.conf similarity index 83% rename from samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf rename to samples/subsys/ipc/ipc_service/multi_endpoint/remote/prj.conf index 4c5326d139769e2..3d2c799c4eb607c 100644 --- a/samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/prj.conf @@ -1,4 +1,5 @@ CONFIG_PRINTK=y +CONFIG_LOG_PRINTK=n CONFIG_IPC_SERVICE=y CONFIG_MBOX=y diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/src/main.c b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/remote/src/main.c rename to samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/sample.yaml b/samples/subsys/ipc/ipc_service/multi_endpoint/sample.yaml new file mode 100644 index 000000000000000..fdb3c707d8e5adc --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/sample.yaml @@ -0,0 +1,19 @@ +sample: + name: IPC Service example integration (icmsg multi endpoint backend) +tests: + sample.ipc.multi_endpoint: + platform_allow: nrf5340dk_nrf5340_cpuapp + integration_platforms: + - nrf5340dk_nrf5340_cpuapp + tags: ipc + sysbuild: true + harness: remote + sample.ipc.multi_endpoint.icbmsg: + platform_allow: nrf5340dk_nrf5340_cpuapp + integration_platforms: + - nrf5340dk_nrf5340_cpuapp + tags: ipc + sysbuild: true + extra_args: + DTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay + remote_DTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/src/main.c b/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/src/main.c rename to samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/sysbuild.cmake b/samples/subsys/ipc/ipc_service/multi_endpoint/sysbuild.cmake similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/sysbuild.cmake rename to samples/subsys/ipc/ipc_service/multi_endpoint/sysbuild.cmake From 8334f1d3854a9c6bd5031e1e46196da946823d83 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 13 Nov 2023 08:42:08 +0000 Subject: [PATCH 0284/1049] doc: migration-guide: 3.6: Fix spurious character Fixes a spurious tilde character at the end of a change Signed-off-by: Jamie McCrae --- doc/releases/migration-guide-3.6.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 6afd6969452ef9b..aaad9dfea3f620a 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -99,7 +99,7 @@ Other Subsystems * Touchscreen drivers :dtcompatible:`focaltech,ft5336` and :dtcompatible:`goodix,gt911` were using the incorrect polarity for the respective ``reset-gpios``. This has been fixed so those signals now have to - be flagged as :c:macro:`GPIO_ACTIVE_LOW` in the devicetree.` + be flagged as :c:macro:`GPIO_ACTIVE_LOW` in the devicetree. Recommended Changes ******************* From 78acf5e64876d5c26cb005bf74795672b62c8eb5 Mon Sep 17 00:00:00 2001 From: Tim Guite Date: Fri, 3 Nov 2023 21:12:41 +0000 Subject: [PATCH 0285/1049] board: mimxrt1170_evk Add pyOCD runner to docs Added a short paragraph explaining how to use pyOCD to flash and debug this board, as well as a disclaimer requested by NXP Signed-off-by: Tim Guite --- boards/arm/mimxrt1170_evk/doc/index.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index 1582861ffc9bb31..15a66875d31bd91 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -349,6 +349,11 @@ Use the ``-r linkserver`` option with West to use the LinkServer runner. west flash -r linkserver +Alternatively, pyOCD can be used to flash and debug the board by using the +``-r pyocd`` option with West. pyOCD is installed when you complete the +:ref:`gs_python_deps` step in the Getting Started Guide. The runners supported +by NXP are LinkServer and JLink. pyOCD is another potential option, but NXP +does not test or support the pyOCD runner. Configuring a Console ===================== From a2ad2d71f64b785a10e43f4feb81bf5f45503577 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 3 Oct 2023 11:44:53 +0300 Subject: [PATCH 0286/1049] drivers: sensor: adxl372: fix define comment Replace unrelated part name with the actual driver name in the adxl372.h header file. Fixes: a3e7cea ("adxl372: Add driver for ADXL372 high-g accelerometer") Signed-off-by: Antoniu Miclaus --- drivers/sensor/adxl372/adxl372.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/adxl372/adxl372.h b/drivers/sensor/adxl372/adxl372.h index 39d1959b220455a..c891413088239c9 100644 --- a/drivers/sensor/adxl372/adxl372.h +++ b/drivers/sensor/adxl372/adxl372.h @@ -373,6 +373,6 @@ int adxl372_trigger_set(const struct device *dev, sensor_trigger_handler_t handler); int adxl372_init_interrupt(const struct device *dev); -#endif /* CONFIG_ADT7420_TRIGGER */ +#endif /* CONFIG_ADXL372_TRIGGER */ #endif /* ZEPHYR_DRIVERS_SENSOR_ADXL372_ADXL372_H_ */ From d6ff5122fded8380688ffa875ee6be99f2cc5fd3 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Sat, 14 Oct 2023 23:24:39 +0530 Subject: [PATCH 0287/1049] dts: x86: intel: raptor_lake: Remove unavailable UARTs Remove unavailable UART instances on RPL platform. Signed-off-by: Anisetti Avinash Krishna --- dts/x86/intel/raptor_lake.dtsi | 48 ---------------------------------- 1 file changed, 48 deletions(-) diff --git a/dts/x86/intel/raptor_lake.dtsi b/dts/x86/intel/raptor_lake.dtsi index c479d54dd9e836f..797a3fa0e544a14 100644 --- a/dts/x86/intel/raptor_lake.dtsi +++ b/dts/x86/intel/raptor_lake.dtsi @@ -307,54 +307,6 @@ current-speed = <115200>; status = "disabled"; }; - - uart3: uart3 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7adc>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "disabled"; - }; - - uart4: uart4 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7add>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "disabled"; - }; - - uart5: uart5 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7ade>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "disabled"; - }; - - uart6: uart6 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7adf>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "disabled"; - }; }; soc { From 316707b7cdd43dff6b391744b40950b4864878b2 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Fri, 13 Oct 2023 15:50:46 +0530 Subject: [PATCH 0288/1049] drivers: dma: dma_intel_lpss: Enhance LPSS DMA to support UART Enhance LPSS DMA to support UART and I2C DMA transfer by enabling init priority of DMA based on dependency on parent device. Signed-off-by: Anisetti Avinash Krishna --- drivers/dma/dma_intel_lpss.c | 41 ++++++++++++++++----- include/zephyr/drivers/dma/dma_intel_lpss.h | 3 +- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/dma/dma_intel_lpss.c b/drivers/dma/dma_intel_lpss.c index b76d0820815beaa..c39fb9dd5acf422 100644 --- a/drivers/dma/dma_intel_lpss.c +++ b/drivers/dma/dma_intel_lpss.c @@ -27,22 +27,36 @@ struct dma_intel_lpss_cfg { const struct device *parent; }; +int dma_intel_lpss_setup(const struct device *dev) +{ + struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; + + if (dev_cfg->dw_cfg.base != 0) { + return dw_dma_setup(dev); + } + + return 0; +} + +void dma_intel_lpss_set_base(const struct device *dev, uintptr_t base) +{ + struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; + + dev_cfg->dw_cfg.base = base; +} + static int dma_intel_lpss_init(const struct device *dev) { struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; uint32_t base; int ret; - if (!device_is_ready(dev_cfg->parent)) { - LOG_ERR("LPSS DMA parent not ready"); - ret = -ENODEV; - goto out; + if (device_is_ready(dev_cfg->parent)) { + base = DEVICE_MMIO_GET(dev_cfg->parent) + DMA_INTEL_LPSS_OFFSET; + dev_cfg->dw_cfg.base = base; } - base = DEVICE_MMIO_GET(dev_cfg->parent) + DMA_INTEL_LPSS_OFFSET; - dev_cfg->dw_cfg.base = base; - - ret = dw_dma_setup(dev); + ret = dma_intel_lpss_setup(dev); if (ret != 0) { LOG_ERR("failed to initialize LPSS DMA %s", dev->name); @@ -64,6 +78,12 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { .stop = dw_dma_stop, }; +#define DMA_LPSS_INIT_VAL_0 49 /* When parent device depends on DMA */ +#define DMA_LPSS_INIT_VAL_1 80 /* When DMA device depends on parent */ + +#define DMA_LPSS_INIT_VAL(n)\ + _CONCAT(DMA_LPSS_INIT_VAL_, DT_INST_NODE_HAS_PROP(n, dma_parent)) + #define DMA_INTEL_LPSS_INIT(n) \ \ static struct dw_drv_plat_data dma_intel_lpss##n = { \ @@ -82,7 +102,8 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { .dw_cfg = { \ .base = 0, \ }, \ - .parent = DEVICE_DT_GET(DT_INST_PHANDLE(n, dma_parent)),\ + IF_ENABLED(DT_INST_NODE_HAS_PROP(n, dma_parent), \ + (.parent = DEVICE_DT_GET(DT_INST_PHANDLE(n, dma_parent)),))\ }; \ \ static struct dw_dma_dev_data dma_intel_lpss##n##_data = { \ @@ -94,7 +115,7 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { NULL, \ &dma_intel_lpss##n##_data, \ &dma_intel_lpss##n##_config, POST_KERNEL, \ - DMA_INTEL_LPSS_INIT_PRIORITY, \ + DMA_LPSS_INIT_VAL(n), \ &dma_intel_lpss_driver_api); \ DT_INST_FOREACH_STATUS_OKAY(DMA_INTEL_LPSS_INIT) diff --git a/include/zephyr/drivers/dma/dma_intel_lpss.h b/include/zephyr/drivers/dma/dma_intel_lpss.h index c3cf3bef81e4fe4..8ef05b688f953c5 100644 --- a/include/zephyr/drivers/dma/dma_intel_lpss.h +++ b/include/zephyr/drivers/dma/dma_intel_lpss.h @@ -7,7 +7,6 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ #define ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ -#define DMA_INTEL_LPSS_INIT_PRIORITY 80 #define DMA_INTEL_LPSS_OFFSET 0x800 #define DMA_INTEL_LPSS_REMAP_LOW 0x240 #define DMA_INTEL_LPSS_REMAP_HI 0x244 @@ -16,5 +15,7 @@ #define DMA_INTEL_LPSS_ADDR_RIGHT_SHIFT 32 void dma_intel_lpss_isr(const struct device *dev); +int dma_intel_lpss_setup(const struct device *dev); +void dma_intel_lpss_set_base(const struct device *dev, uintptr_t base); #endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ */ From 3306eb7d912ad0ceac89561b9e19284dc1c2743b Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Fri, 13 Oct 2023 16:25:36 +0530 Subject: [PATCH 0289/1049] drivers: dma: dma_intel_lpss: Enable dma_status and dma_reload Enable dma_get_status and dma_reload features for LPSS DMA. Signed-off-by: Anisetti Avinash Krishna --- drivers/dma/dma_intel_lpss.c | 77 ++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/dma/dma_intel_lpss.c b/drivers/dma/dma_intel_lpss.c index c39fb9dd5acf422..7d0fec200453bf5 100644 --- a/drivers/dma/dma_intel_lpss.c +++ b/drivers/dma/dma_intel_lpss.c @@ -67,6 +67,81 @@ static int dma_intel_lpss_init(const struct device *dev) return ret; } +int dma_intel_lpss_reload(const struct device *dev, uint32_t channel, + uint64_t src, uint64_t dst, size_t size) +{ + struct dw_dma_dev_data *const dev_data = dev->data; + struct dma_intel_lpss_cfg *lpss_dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; + struct dw_dma_dev_cfg *const dev_cfg = &lpss_dev_cfg->dw_cfg; + struct dw_dma_chan_data *chan_data; + uint32_t ctrl_hi = 0; + + if (channel >= DW_MAX_CHAN) { + return -EINVAL; + } + + chan_data = &dev_data->chan[channel]; + + chan_data->lli_current->sar = src; + chan_data->lli_current->dar = dst; + chan_data->ptr_data.current_ptr = dst; + chan_data->ptr_data.buffer_bytes = size; + + ctrl_hi = dw_read(dev_cfg->base, DW_CTRL_HIGH(channel)); + ctrl_hi &= ~(DW_CTLH_DONE(1) | DW_CTLH_BLOCK_TS_MASK); + ctrl_hi |= size & DW_CTLH_BLOCK_TS_MASK; + + chan_data->lli_current->ctrl_hi = ctrl_hi; + chan_data->ptr_data.start_ptr = DW_DMA_LLI_ADDRESS(chan_data->lli_current, + chan_data->direction); + chan_data->ptr_data.end_ptr = chan_data->ptr_data.start_ptr + + chan_data->ptr_data.buffer_bytes; + chan_data->ptr_data.hw_ptr = chan_data->ptr_data.start_ptr; + + chan_data->state = DW_DMA_PREPARED; + + return 0; +} + +int dma_intel_lpss_get_status(const struct device *dev, uint32_t channel, + struct dma_status *stat) +{ + struct dma_intel_lpss_cfg *lpss_dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; + struct dw_dma_dev_cfg *const dev_cfg = &lpss_dev_cfg->dw_cfg; + struct dw_dma_dev_data *const dev_data = dev->data; + struct dw_dma_chan_data *chan_data; + uint32_t ctrl_hi; + size_t current_length; + bool done; + + if (channel >= DW_CHAN_COUNT) { + return -EINVAL; + } + + chan_data = &dev_data->chan[channel]; + ctrl_hi = dw_read(dev_cfg->base, DW_CTRL_HIGH(channel)); + current_length = ctrl_hi & DW_CTLH_BLOCK_TS_MASK; + done = ctrl_hi & DW_CTLH_DONE(1); + + if (!(dw_read(dev_cfg->base, DW_DMA_CHAN_EN) & DW_CHAN(channel))) { + stat->busy = false; + stat->pending_length = chan_data->ptr_data.buffer_bytes; + return 0; + } + stat->busy = true; + + if (done) { + stat->pending_length = 0; + } else if (current_length == chan_data->ptr_data.buffer_bytes) { + stat->pending_length = chan_data->ptr_data.buffer_bytes; + } else { + stat->pending_length = + chan_data->ptr_data.buffer_bytes - current_length; + } + + return 0; +} + void dma_intel_lpss_isr(const struct device *dev) { dw_dma_isr(dev); @@ -75,6 +150,8 @@ void dma_intel_lpss_isr(const struct device *dev) static const struct dma_driver_api dma_intel_lpss_driver_api = { .config = dw_dma_config, .start = dw_dma_start, + .reload = dma_intel_lpss_reload, + .get_status = dma_intel_lpss_get_status, .stop = dw_dma_stop, }; From 2c19de53bc3b0d31d2f338d48c8eccfbd7463118 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Fri, 13 Oct 2023 16:28:57 +0530 Subject: [PATCH 0290/1049] drivers: dma: dma_dw_common: Corrected compare value of dma_is_enabled Corrected comapare value of dma_is_enabled as it is compare with wrong macro to check if channel is enabled or not. Signed-off-by: Anisetti Avinash Krishna --- drivers/dma/dma_dw_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/dma_dw_common.c b/drivers/dma/dma_dw_common.c index bb000298385f431..0a5040980b2ff07 100644 --- a/drivers/dma/dma_dw_common.c +++ b/drivers/dma/dma_dw_common.c @@ -434,7 +434,7 @@ bool dw_dma_is_enabled(const struct device *dev, uint32_t channel) { const struct dw_dma_dev_cfg *const dev_cfg = dev->config; - return dw_read(dev_cfg->base, DW_DMA_CHAN_EN) & DW_CHAN_MASK(channel); + return dw_read(dev_cfg->base, DW_DMA_CHAN_EN) & DW_CHAN(channel); } int dw_dma_start(const struct device *dev, uint32_t channel) From 0d9654670f564fc5fa7dd080f60dbbdfdbe196b2 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Sat, 11 Nov 2023 10:26:59 +0100 Subject: [PATCH 0291/1049] drivers: i3c: add dummy driver for vnd,i3c It is just used to be able to DEVICE_DT_GET() bus devices from tests/drivers/build_all in an upcoming commit. Signed-off-by: Armando Visconti --- drivers/i3c/CMakeLists.txt | 5 ++++ drivers/i3c/Kconfig | 1 + drivers/i3c/Kconfig.test | 11 +++++++++ drivers/i3c/i3c_test.c | 47 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 drivers/i3c/Kconfig.test create mode 100644 drivers/i3c/i3c_test.c diff --git a/drivers/i3c/CMakeLists.txt b/drivers/i3c/CMakeLists.txt index 2645dbeabb59d7c..71a7dc6eb27b00a 100644 --- a/drivers/i3c/CMakeLists.txt +++ b/drivers/i3c/CMakeLists.txt @@ -30,3 +30,8 @@ zephyr_library_sources_ifdef( CONFIG_I3C_CADENCE i3c_cdns.c ) + +zephyr_library_sources_ifdef( + CONFIG_I3C_TEST + i3c_test.c +) diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig index f4a343632abf4bb..2b524c2bf9d8ed9 100644 --- a/drivers/i3c/Kconfig +++ b/drivers/i3c/Kconfig @@ -100,5 +100,6 @@ comment "Device Drivers" rsource "Kconfig.nxp" rsource "Kconfig.cdns" +rsource "Kconfig.test" endif # I3C diff --git a/drivers/i3c/Kconfig.test b/drivers/i3c/Kconfig.test new file mode 100644 index 000000000000000..3b28d596980e5b5 --- /dev/null +++ b/drivers/i3c/Kconfig.test @@ -0,0 +1,11 @@ +# Copyright (c) 2021, Commonwealth Scientific and Industrial Research +# Organisation (CSIRO) ABN 41 687 119 230. +# Copyright (c) 2023 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 + +# Hidden option for turning on the dummy driver for vnd,i3c devices +# used in testing. +config I3C_TEST + def_bool DT_HAS_VND_I3C_ENABLED + depends on DT_HAS_VND_I3C_ENABLED diff --git a/drivers/i3c/i3c_test.c b/drivers/i3c/i3c_test.c new file mode 100644 index 000000000000000..165449747d859bc --- /dev/null +++ b/drivers/i3c/i3c_test.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This is not a real I3C driver. It is used to instantiate struct + * devices for the "vnd,i3c" devicetree compatible used in test code. + */ + +#define DT_DRV_COMPAT vnd_i3c + +#include +#include +#include + +static int vnd_i3c_configure(const struct device *dev, + enum i3c_config_type type, void *config) +{ + return -ENOTSUP; +} + +static int vnd_i3c_config_get(const struct device *dev, + enum i3c_config_type type, void *config) +{ + return -ENOTSUP; +} + +static int vnd_i3c_recover_bus(const struct device *dev) +{ + return -ENOTSUP; +} + +static const struct i3c_driver_api vnd_i3c_api = { + .configure = vnd_i3c_configure, + .config_get = vnd_i3c_config_get, + .recover_bus = vnd_i3c_recover_bus, +}; + +#define VND_I3C_INIT(n) \ + DEVICE_DT_INST_DEFINE(n, NULL, NULL, NULL, NULL, \ + POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &vnd_i3c_api); + +DT_INST_FOREACH_STATUS_OKAY(VND_I3C_INIT) From 0973531c94062e8bca78dfc8e1212a36e4fbc88a Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Sat, 11 Nov 2023 10:44:35 +0100 Subject: [PATCH 0292/1049] tests: drivers: build_all: sensor: add I3C test framework Add framework to test sensor drivers I3C conditional checkings. Signed-off-by: Armando Visconti --- tests/drivers/build_all/sensor/app.overlay | 11 +++++++++++ tests/drivers/build_all/sensor/i3c.dtsi | 18 ++++++++++++++++++ tests/drivers/build_all/sensor/prj.conf | 1 + .../build_all/sensor/src/generic_test.c | 1 + 4 files changed, 31 insertions(+) create mode 100644 tests/drivers/build_all/sensor/i3c.dtsi diff --git a/tests/drivers/build_all/sensor/app.overlay b/tests/drivers/build_all/sensor/app.overlay index 23b732e9db436a2..fb039a8ebace669 100644 --- a/tests/drivers/build_all/sensor/app.overlay +++ b/tests/drivers/build_all/sensor/app.overlay @@ -143,6 +143,17 @@ #include "w1.dtsi" }; + + test_i3c: i3c@f0cacc1a { + #address-cells = <3>; + #size-cells = <0>; + compatible = "vnd,i3c"; + reg = <0xf0cacc1a 0x1000>; + status = "okay"; + + #include "i3c.dtsi" + }; + }; }; diff --git a/tests/drivers/build_all/sensor/i3c.dtsi b/tests/drivers/build_all/sensor/i3c.dtsi new file mode 100644 index 000000000000000..005c21fdff2db93 --- /dev/null +++ b/tests/drivers/build_all/sensor/i3c.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Application overlay for i3c devices + */ + +/**************************************** + * PLEASE KEEP REG ADDRESSES SEQUENTIAL * + ***************************************/ + +test_i3c_lps22hh: lps22hh@100000803E0000001 { + compatible = "st,lps22hh"; + reg = <0x1 0x00000803 0xE0000001>; + assigned-address = <0x1>; + drdy-gpios = <&test_gpio 0 0>; +}; diff --git a/tests/drivers/build_all/sensor/prj.conf b/tests/drivers/build_all/sensor/prj.conf index b29c11a64bb25b1..67172951b7d5694 100644 --- a/tests/drivers/build_all/sensor/prj.conf +++ b/tests/drivers/build_all/sensor/prj.conf @@ -6,6 +6,7 @@ CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 CONFIG_ADC=y CONFIG_GPIO=y CONFIG_I2C=y +CONFIG_I3C=y CONFIG_SERIAL=y CONFIG_SPI=y CONFIG_W1=y diff --git a/tests/drivers/build_all/sensor/src/generic_test.c b/tests/drivers/build_all/sensor/src/generic_test.c index 42ac57e8f379f5c..9a1dc537535fc8f 100644 --- a/tests/drivers/build_all/sensor/src/generic_test.c +++ b/tests/drivers/build_all/sensor/src/generic_test.c @@ -282,6 +282,7 @@ static void run_generic_test(const struct device *dev) /* Iterate through each of the emulated buses and create a test for each device. */ DT_FOREACH_CHILD_STATUS_OKAY(DT_NODELABEL(test_i2c), DECLARE_ZTEST_PER_DEVICE) +DT_FOREACH_CHILD_STATUS_OKAY(DT_NODELABEL(test_i3c), DECLARE_ZTEST_PER_DEVICE) DT_FOREACH_CHILD_STATUS_OKAY(DT_NODELABEL(test_spi), DECLARE_ZTEST_PER_DEVICE) ZTEST_SUITE(generic, NULL, NULL, before, NULL, NULL); From f1f7e4712c38e0c4e13652fe45af000b6a2c37c1 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Mon, 28 Aug 2023 16:15:41 +0200 Subject: [PATCH 0293/1049] drivers/sensor: add support to LPS22DF pressure sensor The LPS22DF is an ultracompact, piezoresistive, absolute pressure sensor that functions as a digital output barometer. The LPS22DF provides lower power consumption, achieving lower pressure noise than its predecessor. This driver is based on stmemsc HAL i/f v2.3 https://www.st.com/en/datasheet/lps22df.pdf Signed-off-by: Armando Visconti --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/lps22df/CMakeLists.txt | 12 + drivers/sensor/lps22df/Kconfig | 59 +++ drivers/sensor/lps22df/lps22df.c | 338 ++++++++++++++++++ drivers/sensor/lps22df/lps22df.h | 99 +++++ drivers/sensor/lps22df/lps22df_trigger.c | 251 +++++++++++++ dts/bindings/sensor/st,lps22df-common.yaml | 88 +++++ dts/bindings/sensor/st,lps22df-i2c.yaml | 10 + dts/bindings/sensor/st,lps22df-i3c.yaml | 10 + dts/bindings/sensor/st,lps22df-spi.yaml | 10 + modules/Kconfig.st | 3 + tests/drivers/build_all/sensor/app.overlay | 3 +- tests/drivers/build_all/sensor/i2c.dtsi | 7 + tests/drivers/build_all/sensor/i3c.dtsi | 7 + .../sensor/sensors_trigger_global.conf | 1 + .../sensor/sensors_trigger_none.conf | 1 + .../build_all/sensor/sensors_trigger_own.conf | 1 + tests/drivers/build_all/sensor/spi.dtsi | 8 + 19 files changed, 909 insertions(+), 1 deletion(-) create mode 100644 drivers/sensor/lps22df/CMakeLists.txt create mode 100644 drivers/sensor/lps22df/Kconfig create mode 100644 drivers/sensor/lps22df/lps22df.c create mode 100644 drivers/sensor/lps22df/lps22df.h create mode 100644 drivers/sensor/lps22df/lps22df_trigger.c create mode 100644 dts/bindings/sensor/st,lps22df-common.yaml create mode 100644 dts/bindings/sensor/st,lps22df-i2c.yaml create mode 100644 dts/bindings/sensor/st,lps22df-i3c.yaml create mode 100644 dts/bindings/sensor/st,lps22df-spi.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 8ac3da6c937fda3..0bace9305b96b58 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -71,6 +71,7 @@ add_subdirectory_ifdef(CONFIG_LIS2MDL lis2mdl) add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl) add_subdirectory_ifdef(CONFIG_LM75 lm75) add_subdirectory_ifdef(CONFIG_LM77 lm77) +add_subdirectory_ifdef(CONFIG_LPS22DF lps22df) add_subdirectory_ifdef(CONFIG_LPS22HB lps22hb) add_subdirectory_ifdef(CONFIG_LPS22HH lps22hh) add_subdirectory_ifdef(CONFIG_LPS25HB lps25hb) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 000c4bb1a3571b5..e334617cf0b3196 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -144,6 +144,7 @@ source "drivers/sensor/lis2mdl/Kconfig" source "drivers/sensor/lis3mdl/Kconfig" source "drivers/sensor/lm75/Kconfig" source "drivers/sensor/lm77/Kconfig" +source "drivers/sensor/lps22df/Kconfig" source "drivers/sensor/lps22hb/Kconfig" source "drivers/sensor/lps22hh/Kconfig" source "drivers/sensor/lps25hb/Kconfig" diff --git a/drivers/sensor/lps22df/CMakeLists.txt b/drivers/sensor/lps22df/CMakeLists.txt new file mode 100644 index 000000000000000..bb5194cf9ba9320 --- /dev/null +++ b/drivers/sensor/lps22df/CMakeLists.txt @@ -0,0 +1,12 @@ +# ST Microelectronics LPS22DF pressure and temperature sensor +# +# Copyright (c) 2023 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources(lps22df.c) +zephyr_library_sources_ifdef(CONFIG_LPS22DF_TRIGGER lps22df_trigger.c) + +zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lps22df/Kconfig b/drivers/sensor/lps22df/Kconfig new file mode 100644 index 000000000000000..843c6e755c41641 --- /dev/null +++ b/drivers/sensor/lps22df/Kconfig @@ -0,0 +1,59 @@ +# ST Microelectronics LPS22DF pressure and temperature sensor + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LPS22DF + bool "LPS22DF pressure and temperature" + default y + depends on DT_HAS_ST_LPS22DF_ENABLED + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i2c) + select I3C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i3c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),spi) + select HAS_STMEMSC + select USE_STDC_LPS22DF + help + Enable driver for LPS22DF I2C-based pressure and temperature + sensor. + +if LPS22DF + +choice LPS22DF_TRIGGER_MODE + prompt "Trigger mode" + default LPS22DF_TRIGGER_GLOBAL_THREAD + help + Specify the type of triggering to be used by the driver. + +config LPS22DF_TRIGGER_NONE + bool "No trigger" + +config LPS22DF_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select LPS22DF_TRIGGER + +config LPS22DF_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select LPS22DF_TRIGGER + +endchoice # LPS22DF_TRIGGER_MODE + +config LPS22DF_TRIGGER + bool + +config LPS22DF_THREAD_PRIORITY + int "Thread priority" + depends on LPS22DF_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config LPS22DF_THREAD_STACK_SIZE + int "Thread stack size" + depends on LPS22DF_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +endif # LPS22DF diff --git a/drivers/sensor/lps22df/lps22df.c b/drivers/sensor/lps22df/lps22df.c new file mode 100644 index 000000000000000..a74ef75c2455795 --- /dev/null +++ b/drivers/sensor/lps22df/lps22df.c @@ -0,0 +1,338 @@ +/* ST Microelectronics LPS22DF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lps22df.pdf + */ + +#define DT_DRV_COMPAT st_lps22df + +#include +#include +#include +#include +#include +#include +#include + +#include "lps22df.h" + +#define LPS22DF_SWRESET_WAIT_TIME 50 + +LOG_MODULE_REGISTER(LPS22DF, CONFIG_SENSOR_LOG_LEVEL); + +static inline int lps22df_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lps22df_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_md_t md; + + md.odr = odr; + md.avg = cfg->avg; + md.lpf = cfg->lpf; + + return lps22df_mode_set(ctx, &md); +} + +static int lps22df_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + struct lps22df_data *data = dev->data; + const struct lps22df_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_data_t raw_data; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); + + if (lps22df_data_get(ctx, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + data->sample_press = raw_data.pressure.raw; + data->sample_temp = raw_data.heat.raw; + + return 0; +} + +static inline void lps22df_press_convert(struct sensor_value *val, + int32_t raw_val) +{ + int32_t press_tmp = raw_val >> 8; /* raw value is left aligned (24 msb) */ + + /* Pressure sensitivity is 4096 LSB/hPa */ + /* Also convert hPa into kPa */ + + val->val1 = press_tmp / 40960; + + /* For the decimal part use (3125 / 128) as a factor instead of + * (1000000 / 40960) to avoid int32 overflow + */ + val->val2 = (press_tmp % 40960) * 3125 / 128; +} + +static inline void lps22df_temp_convert(struct sensor_value *val, + int16_t raw_val) +{ + /* Temperature sensitivity is 100 LSB/deg C */ + val->val1 = raw_val / 100; + val->val2 = ((int32_t)raw_val % 100) * 10000; +} + +static int lps22df_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct lps22df_data *data = dev->data; + + if (chan == SENSOR_CHAN_PRESS) { + lps22df_press_convert(val, data->sample_press); + } else if (chan == SENSOR_CHAN_AMBIENT_TEMP) { + lps22df_temp_convert(val, data->sample_temp); + } else { + return -ENOTSUP; + } + + return 0; +} + +static const uint16_t lps22df_map[] = {0, 1, 4, 10, 25, 50, 75, 100, 200}; + +static int lps22df_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + for (odr = 0; odr < ARRAY_SIZE(lps22df_map); odr++) { + if (freq == lps22df_map[odr]) { + break; + } + } + + if (odr == ARRAY_SIZE(lps22df_map)) { + LOG_DBG("bad frequency"); + return -EINVAL; + } + + if (lps22df_set_odr_raw(dev, odr) < 0) { + LOG_DBG("failed to set sampling rate"); + return -EIO; + } + + return 0; +} + +static int lps22df_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_ALL) { + LOG_WRN("attr_set() not supported on this channel."); + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lps22df_odr_set(dev, val->val1); + default: + LOG_DBG("operation not supported."); + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api lps22df_driver_api = { + .attr_set = lps22df_attr_set, + .sample_fetch = lps22df_sample_fetch, + .channel_get = lps22df_channel_get, +#if CONFIG_LPS22DF_TRIGGER + .trigger_set = lps22df_trigger_set, +#endif +}; + +static int lps22df_init_chip(const struct device *dev) +{ + const struct lps22df_config * const cfg = dev->config; + __maybe_unused struct lps22df_data *data = dev->data; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_id_t id; + lps22df_stat_t status; + uint8_t tries = 10; + int ret; + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) + if (cfg->i3c.bus != NULL) { + /* + * Need to grab the pointer to the I3C device descriptor + * before we can talk to the sensor. + */ + data->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id); + if (data->i3c_dev == NULL) { + LOG_ERR("Cannot find I3C device descriptor"); + return -ENODEV; + } + } +#endif + + if (lps22df_id_get(ctx, &id) < 0) { + LOG_ERR("%s: Not able to read dev id", dev->name); + return -EIO; + } + + if (id.whoami != LPS22DF_ID) { + LOG_ERR("%s: Invalid chip ID 0x%02x", dev->name, id.whoami); + return -EIO; + } + + LOG_DBG("%s: chip id 0x%x", dev->name, id.whoami); + + /* Restore default configuration */ + if (lps22df_init_set(ctx, LPS22DF_RESET) < 0) { + LOG_ERR("%s: Not able to reset device", dev->name); + return -EIO; + } + + do { + if (!--tries) { + LOG_DBG("sw reset timed out"); + return -ETIMEDOUT; + } + k_usleep(LPS22DF_SWRESET_WAIT_TIME); + + if (lps22df_status_get(ctx, &status) < 0) { + return -EIO; + } + } while (status.sw_reset); + + /* Set bdu and if_inc recommended for driver usage */ + if (lps22df_init_set(ctx, LPS22DF_DRV_RDY) < 0) { + LOG_ERR("%s: Not able to set device to ready state", dev->name); + return -EIO; + } + + if (ON_I3C_BUS(cfg)) { + lps22df_bus_mode_t bus_mode; + + /* Select bus interface */ + bus_mode.filter = LPS22DF_AUTO; + bus_mode.interface = LPS22DF_SEL_BY_HW; + lps22df_bus_mode_set(ctx, &bus_mode); + + } + + /* set sensor default odr */ + LOG_DBG("%s: odr: %d", dev->name, cfg->odr); + ret = lps22df_set_odr_raw(dev, cfg->odr); + if (ret < 0) { + LOG_ERR("%s: Failed to set odr %d", dev->name, cfg->odr); + return ret; + } + + return 0; +} + +static int lps22df_init(const struct device *dev) +{ + if (lps22df_init_chip(dev) < 0) { + LOG_DBG("Failed to initialize chip"); + return -EIO; + } + +#ifdef CONFIG_LPS22DF_TRIGGER + if (lps22df_init_interrupt(dev) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } +#endif + + return 0; +} + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#ifdef CONFIG_LPS22DF_TRIGGER +#define LPS22DF_CFG_IRQ(inst) \ + .gpio_int = GPIO_DT_SPEC_INST_GET(inst, drdy_gpios), +#else +#define LPS22DF_CFG_IRQ(inst) +#endif /* CONFIG_LPS22DF_TRIGGER */ + +#define LPS22DF_CONFIG_COMMON(inst) \ + .odr = DT_INST_PROP(inst, odr), \ + .lpf = DT_INST_PROP(inst, lpf), \ + .avg = DT_INST_PROP(inst, avg), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, drdy_gpios), \ + (LPS22DF_CFG_IRQ(inst)), ()) + +#define LPS22DF_SPI_OPERATION (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | \ + SPI_MODE_CPOL | SPI_MODE_CPHA) \ + +#define LPS22DF_CONFIG_SPI(inst) \ + { \ + STMEMSC_CTX_SPI(&lps22df_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, \ + LPS22DF_SPI_OPERATION, \ + 0), \ + }, \ + LPS22DF_CONFIG_COMMON(inst) \ + } + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define LPS22DF_CONFIG_I2C(inst) \ + { \ + STMEMSC_CTX_I2C(&lps22df_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + LPS22DF_CONFIG_COMMON(inst) \ + } + +/* + * Instantiation macros used when a device is on an I#C bus. + */ + +#define LPS22DF_CONFIG_I3C(inst) \ + { \ + STMEMSC_CTX_I3C(&lps22df_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i3c = &lps22df_data_##inst.i3c_dev, \ + }, \ + .i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst), \ + LPS22DF_CONFIG_COMMON(inst) \ + } + +#define LPS22DF_CONFIG_I3C_OR_I2C(inst) \ + COND_CODE_0(DT_INST_PROP_BY_IDX(inst, reg, 1), \ + (LPS22DF_CONFIG_I2C(inst)), \ + (LPS22DF_CONFIG_I3C(inst))) + +/* + * Main instantiation macro. Use of COND_CODE_1() selects the right + * bus-specific macro at preprocessor time. + */ + +#define LPS22DF_DEFINE(inst) \ + static struct lps22df_data lps22df_data_##inst; \ + static const struct lps22df_config lps22df_config_##inst = \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (LPS22DF_CONFIG_SPI(inst)), \ + (COND_CODE_1(DT_INST_ON_BUS(inst, i3c), \ + (LPS22DF_CONFIG_I3C_OR_I2C(inst)), \ + (LPS22DF_CONFIG_I2C(inst))))); \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, lps22df_init, NULL, &lps22df_data_##inst, \ + &lps22df_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &lps22df_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(LPS22DF_DEFINE) diff --git a/drivers/sensor/lps22df/lps22df.h b/drivers/sensor/lps22df/lps22df.h new file mode 100644 index 000000000000000..044c08cbd93b708 --- /dev/null +++ b/drivers/sensor/lps22df/lps22df.h @@ -0,0 +1,99 @@ +/* ST Microelectronics LPS22DF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lps22df.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ +#define ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ + +#include +#include +#include "lps22df_reg.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) + #define ON_I3C_BUS(cfg) (cfg->i3c.bus != NULL) +#else + #define ON_I3C_BUS(cfg) (false) +#endif + +struct lps22df_config { + stmdev_ctx_t ctx; + union { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + const struct i2c_dt_spec i2c; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + const struct spi_dt_spec spi; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) + struct i3c_device_desc **i3c; +#endif + } stmemsc_cfg; + uint8_t odr; + uint8_t lpf; + uint8_t avg; + uint8_t drdy_pulsed; +#ifdef CONFIG_LPS22DF_TRIGGER + struct gpio_dt_spec gpio_int; +#endif + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) + struct { + const struct device *bus; + const struct i3c_device_id dev_id; + } i3c; +#endif +}; + +struct lps22df_data { + int32_t sample_press; + int16_t sample_temp; + +#ifdef CONFIG_LPS22DF_TRIGGER + struct gpio_callback gpio_cb; + + const struct sensor_trigger *data_ready_trigger; + sensor_trigger_handler_t handler_drdy; + const struct device *dev; + +#if defined(CONFIG_LPS22DF_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LPS22DF_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem intr_sem; +#elif defined(CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif + +#endif /* CONFIG_LPS22DF_TRIGGER */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) + struct i3c_device_desc *i3c_dev; +#endif +}; + +#ifdef CONFIG_LPS22DF_TRIGGER +int lps22df_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lps22df_init_interrupt(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ */ diff --git a/drivers/sensor/lps22df/lps22df_trigger.c b/drivers/sensor/lps22df/lps22df_trigger.c new file mode 100644 index 000000000000000..c5d6a91dba845db --- /dev/null +++ b/drivers/sensor/lps22df/lps22df_trigger.c @@ -0,0 +1,251 @@ +/* ST Microelectronics LPS22DF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lps22df.pdf + */ + +#define DT_DRV_COMPAT st_lps22df + +#include +#include +#include +#include + +#include "lps22df.h" + +LOG_MODULE_DECLARE(LPS22DF, CONFIG_SENSOR_LOG_LEVEL); + +/** + * lps22df_enable_int - enable selected int pin to generate interrupt + */ +static int lps22df_enable_int(const struct device *dev, int enable) +{ + const struct lps22df_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_pin_int_route_t int_route; + + /* set interrupt */ + lps22df_pin_int_route_get(ctx, &int_route); + int_route.drdy_pres = enable; + return lps22df_pin_int_route_set(ctx, &int_route); +} + +/** + * lps22df_trigger_set - link external trigger to event data ready + */ +int lps22df_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct lps22df_data *lps22df = dev->data; + const struct lps22df_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_data_t raw_data; + + if (trig->chan != SENSOR_CHAN_ALL) { + LOG_WRN("trigger set not supported on this channel."); + return -ENOTSUP; + } + + lps22df->handler_drdy = handler; + lps22df->data_ready_trigger = trig; + if (handler) { + /* dummy read: re-trigger interrupt */ + if (lps22df_data_get(ctx, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + return lps22df_enable_int(dev, 1); + } else { + return lps22df_enable_int(dev, 0); + } + + return -ENOTSUP; +} + +/** + * lps22df_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +static void lps22df_handle_interrupt(const struct device *dev) +{ + int ret; + struct lps22df_data *lps22df = dev->data; + const struct lps22df_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_all_sources_t status; + + if (lps22df_all_sources_get(ctx, &status) < 0) { + LOG_DBG("failed reading status reg"); + goto exit; + } + + if (status.drdy_pres == 0) { + goto exit; /* spurious interrupt */ + } + + if (lps22df->handler_drdy != NULL) { + lps22df->handler_drdy(dev, lps22df->data_ready_trigger); + } + + if (ON_I3C_BUS(cfg)) { + /* + * I3C IBI does not rely on GPIO. + * So no need to enable GPIO pin for interrupt trigger. + */ + return; + } + +exit: + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } +} + +static void lps22df_intr_callback(struct lps22df_data *lps22df) +{ +#if defined(CONFIG_LPS22DF_TRIGGER_OWN_THREAD) + k_sem_give(&lps22df->intr_sem); +#elif defined(CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD) + k_work_submit(&lps22df->work); +#endif /* CONFIG_LPS22DF_TRIGGER_OWN_THREAD */ +} + +static void lps22df_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct lps22df_data *lps22df = + CONTAINER_OF(cb, struct lps22df_data, gpio_cb); + + ARG_UNUSED(pins); + const struct lps22df_config *cfg = lps22df->dev->config; + int ret; + + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } + + lps22df_intr_callback(lps22df); +} + +#ifdef CONFIG_LPS22DF_TRIGGER_OWN_THREAD +static void lps22df_thread(struct lps22df_data *lps22df) +{ + while (1) { + k_sem_take(&lps22df->intr_sem, K_FOREVER); + lps22df_handle_interrupt(lps22df->dev); + } +} +#endif /* CONFIG_LPS22DF_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD +static void lps22df_work_cb(struct k_work *work) +{ + struct lps22df_data *lps22df = + CONTAINER_OF(work, struct lps22df_data, work); + + lps22df_handle_interrupt(lps22df->dev); +} +#endif /* CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) +static int lps22df_ibi_cb(struct i3c_device_desc *target, + struct i3c_ibi_payload *payload) +{ + const struct device *dev = target->dev; + struct lps22df_data *lps22df = dev->data; + + ARG_UNUSED(payload); + + lps22df_intr_callback(lps22df); + + return 0; +} +#endif + +int lps22df_init_interrupt(const struct device *dev) +{ + struct lps22df_data *lps22df = dev->data; + const struct lps22df_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_int_mode_t mode; + int ret; + + /* setup data ready gpio interrupt */ + if (!gpio_is_ready_dt(&cfg->gpio_int) && !ON_I3C_BUS(cfg)) { + if (cfg->gpio_int.port) { + LOG_ERR("%s: device %s is not ready", dev->name, + cfg->gpio_int.port->name); + return -ENODEV; + } + + LOG_DBG("%s: gpio_int not defined in DT", dev->name); + return 0; + } + + lps22df->dev = dev; + +#if defined(CONFIG_LPS22DF_TRIGGER_OWN_THREAD) + k_sem_init(&lps22df->intr_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&lps22df->thread, lps22df->thread_stack, + CONFIG_LPS22DF_THREAD_STACK_SIZE, + (k_thread_entry_t)lps22df_thread, lps22df, + NULL, NULL, K_PRIO_COOP(CONFIG_LPS22DF_THREAD_PRIORITY), + 0, K_NO_WAIT); +#elif defined(CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD) + lps22df->work.handler = lps22df_work_cb; +#endif /* CONFIG_LPS22DF_TRIGGER_OWN_THREAD */ + + if (!ON_I3C_BUS(cfg)) { + ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure gpio"); + return ret; + } + + LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name, + cfg->gpio_int.pin); + + gpio_init_callback(&lps22df->gpio_cb, + lps22df_gpio_callback, + BIT(cfg->gpio_int.pin)); + + ret = gpio_add_callback(cfg->gpio_int.port, &lps22df->gpio_cb); + if (ret < 0) { + LOG_ERR("Could not set gpio callback"); + return ret; + } + } + + /* enable drdy in pulsed/latched mode */ + LOG_DBG("drdy_pulsed is %d", (int)cfg->drdy_pulsed); + mode.drdy_latched = ~cfg->drdy_pulsed; + if (lps22df_interrupt_mode_set(ctx, &mode) < 0) { + return -EIO; + } + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) + if (cfg->i3c.bus != NULL) { + /* I3C IBI does not utilize GPIO interrupt. */ + lps22df->i3c_dev->ibi_cb = lps22df_ibi_cb; + + if (i3c_ibi_enable(lps22df->i3c_dev) != 0) { + LOG_DBG("Could not enable I3C IBI"); + return -EIO; + } + + return 0; + } +#endif + + return gpio_pin_interrupt_configure_dt(&cfg->gpio_int, + GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/dts/bindings/sensor/st,lps22df-common.yaml b/dts/bindings/sensor/st,lps22df-common.yaml new file mode 100644 index 000000000000000..7a1f21573b2ba86 --- /dev/null +++ b/dts/bindings/sensor/st,lps22df-common.yaml @@ -0,0 +1,88 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +include: sensor-device.yaml + +properties: + drdy-gpios: + type: phandle-array + description: | + DRDY pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + drdy-pulsed: + type: boolean + description: | + Selects the pulsed mode for data-ready interrupt when enabled, + and the latched mode when disabled. + + odr: + type: int + default: 0 + description: | + Specify the output data rate expressed in samples per second (Hz). + The default is the power-on reset value. + + 0 = Power-Down + 1 = 1Hz + 2 = 4Hz + 3 = 10Hz + 4 = 25Hz + 5 = 50Hz + 6 = 75Hz + 7 = 100Hz + 8 = 200Hz + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + + lpf: + type: int + default: 0 + description: | + Specify the low pass filter value to be applied to pressure data. + The default is the power-on reset value. + + 0 = Low Pass Filter disabled + 1 = Low Pass Filter set to ODR/4 + 3 = Low Pass Filter set to ODR/9 + enum: + - 0 + - 1 + - 3 + + avg: + type: int + default: 0 + description: | + Specify the average filter value (i.e. number of samples) to be applied + to pressure and temperature data. + The default is the power-on reset value. + + 0 = Average of 4 data samples + 1 = Average of 8 data samples + 2 = Average of 16 data samples + 3 = Average of 32 data samples + 4 = Average of 64 data samples + 5 = Average of 128 data samples + 6 = Average of 256 data samples + 7 = Average of 512 data samples + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 diff --git a/dts/bindings/sensor/st,lps22df-i2c.yaml b/dts/bindings/sensor/st,lps22df-i2c.yaml new file mode 100644 index 000000000000000..11074528cf34fa8 --- /dev/null +++ b/dts/bindings/sensor/st,lps22df-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS22DF pressure and temperature sensor connected to I2C + bus + +compatible: "st,lps22df" + +include: ["i2c-device.yaml", "st,lps22df-common.yaml"] diff --git a/dts/bindings/sensor/st,lps22df-i3c.yaml b/dts/bindings/sensor/st,lps22df-i3c.yaml new file mode 100644 index 000000000000000..6bba397e0bea363 --- /dev/null +++ b/dts/bindings/sensor/st,lps22df-i3c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS22DF pressure and temperature sensor connected to I3C + bus + +compatible: "st,lps22df" + +include: ["i3c-device.yaml", "st,lps22df-common.yaml"] diff --git a/dts/bindings/sensor/st,lps22df-spi.yaml b/dts/bindings/sensor/st,lps22df-spi.yaml new file mode 100644 index 000000000000000..219738d0e950f13 --- /dev/null +++ b/dts/bindings/sensor/st,lps22df-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS22DF pressure and temperature sensor connected to SPI + bus + +compatible: "st,lps22df" + +include: ["spi-device.yaml", "st,lps22df-common.yaml"] diff --git a/modules/Kconfig.st b/modules/Kconfig.st index 2db03e18f77c8a6..fd90aee0b171e44 100644 --- a/modules/Kconfig.st +++ b/modules/Kconfig.st @@ -115,6 +115,9 @@ config USE_STDC_LIS3DSH config USE_STDC_LIS3MDL bool +config USE_STDC_LPS22DF + bool + config USE_STDC_LPS22HB bool diff --git a/tests/drivers/build_all/sensor/app.overlay b/tests/drivers/build_all/sensor/app.overlay index fb039a8ebace669..9f7c604bf302a7f 100644 --- a/tests/drivers/build_all/sensor/app.overlay +++ b/tests/drivers/build_all/sensor/app.overlay @@ -121,7 +121,8 @@ <&test_gpio 0 0>, <&test_gpio 0 0>, <&test_gpio 0 0>, /* 0x25 */ - <&test_gpio 0 0>; /* 0x26 */ + <&test_gpio 0 0>, /* 0x26 */ + <&test_gpio 0 0>; /* 0x27 */ #include "spi.dtsi" }; diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index eda5bff0ff7401b..42beeab095e6317 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -800,3 +800,10 @@ test_i2c_tsl2561: tsl2561@78 { compatible = "ams,tsl2561"; reg = <0x78>; }; + +test_i2c_lps22df: lps22df@78 { + compatible = "st,lps22df"; + reg = <0x78>; + drdy-gpios = <&test_gpio 0 0>; + status = "okay"; +}; diff --git a/tests/drivers/build_all/sensor/i3c.dtsi b/tests/drivers/build_all/sensor/i3c.dtsi index 005c21fdff2db93..42adb3fb1759bed 100644 --- a/tests/drivers/build_all/sensor/i3c.dtsi +++ b/tests/drivers/build_all/sensor/i3c.dtsi @@ -16,3 +16,10 @@ test_i3c_lps22hh: lps22hh@100000803E0000001 { assigned-address = <0x1>; drdy-gpios = <&test_gpio 0 0>; }; + +test_i3c_lps22df: lps22df@200000803E0000002 { + compatible = "st,lps22df"; + reg = <0x2 0x00000803 0xE0000002>; + assigned-address = <0x2>; + drdy-gpios = <&test_gpio 0 0>; +}; diff --git a/tests/drivers/build_all/sensor/sensors_trigger_global.conf b/tests/drivers/build_all/sensor/sensors_trigger_global.conf index 74ba8f20239801d..c42b4fa951e1d3d 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -36,6 +36,7 @@ CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS3MDL_TRIGGER_GLOBAL_THREAD=y +CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD=y CONFIG_LPS22HH_TRIGGER_GLOBAL_THREAD=y CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y CONFIG_LSM6DSO_TRIGGER_GLOBAL_THREAD=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_none.conf b/tests/drivers/build_all/sensor/sensors_trigger_none.conf index 905907928f522cd..9c46cb3637e6e87 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -36,6 +36,7 @@ CONFIG_LIS2DS12_TRIGGER_NONE=y CONFIG_LIS2DW12_TRIGGER_NONE=y CONFIG_LIS2MDL_TRIGGER_NONE=y CONFIG_LIS3MDL_TRIGGER_NONE=y +CONFIG_LPS22DF_TRIGGER_NONE=y CONFIG_LPS22HH_TRIGGER_NONE=y CONFIG_LSM6DSL_TRIGGER_NONE=y CONFIG_LSM6DSO_TRIGGER_NONE=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_own.conf b/tests/drivers/build_all/sensor/sensors_trigger_own.conf index 92504b6c2f4d6e6..5ecacb03d9a85ae 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -34,6 +34,7 @@ CONFIG_LIS2DS12_TRIGGER_OWN_THREAD=y CONFIG_LIS2DW12_TRIGGER_OWN_THREAD=y CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y CONFIG_LIS3MDL_TRIGGER_OWN_THREAD=y +CONFIG_LPS22DF_TRIGGER_OWN_THREAD=y CONFIG_LPS22HH_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSL_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSO_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index d026e244f88aa2d..cd7bf1b66ec5da2 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -304,3 +304,11 @@ test_spi_adxl367: adxl367@26 { odr = <4>; int1-gpios = <&test_gpio 0 0>; }; + +test_spi_lps22df: lps22df@27 { + compatible = "st,lps22df"; + reg = <0x27>; + spi-max-frequency = <0>; + drdy-gpios = <&test_gpio 0 0>; + status = "okay"; +}; From 92704d7f263bbc9d884f17be1ff006e7ed568098 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Mon, 6 Nov 2023 16:38:33 +0100 Subject: [PATCH 0294/1049] boards: arm: sensortile_box_pro: extend with lps22df Extend sensortile_box_pro with lps22df. Signed-off-by: Armando Visconti --- boards/arm/sensortile_box_pro/doc/index.rst | 5 +++++ boards/arm/sensortile_box_pro/sensortile_box_pro.dts | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/boards/arm/sensortile_box_pro/doc/index.rst b/boards/arm/sensortile_box_pro/doc/index.rst index c5f8eed3a3795d4..bba5a4cb288be79 100644 --- a/boards/arm/sensortile_box_pro/doc/index.rst +++ b/boards/arm/sensortile_box_pro/doc/index.rst @@ -159,6 +159,8 @@ Motion and environmental sensors (`lsm6dsv16x datasheet`_) - **LIS2MDL** 3-axis magnetometer (`lis2mdl datasheet`_) + - **LPS22DF** Altimeter / pressure sensor + (`lps22df datasheet`_) - **LIS2DU12** 3-axis accelerometer (`lis2du12 datasheet`_) - **HTS221** Humidity sensor @@ -362,6 +364,9 @@ References .. _lis2mdl datasheet: https://www.st.com/en/mems-and-sensors/lis2mdl.html +.. _lps22df datasheet: + https://www.st.com/en/mems-and-sensors/lps22df.html + .. _lis2du12 datasheet: https://www.st.com/en/mems-and-sensors/lis2du12.html diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts index 8f5999d2aefc2f2..485ec6b6e7d0a43 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts @@ -215,6 +215,13 @@ status = "okay"; }; + lps22df@5d { + compatible = "st,lps22df"; + reg = <0x5d>; + drdy-gpios = <&gpioe 8 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; + lis2mdl@1e { compatible = "st,lis2mdl"; reg = <0x1e>; From 6dd2336a50849ead9241fec80d8b65b8e53445c4 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Mon, 6 Nov 2023 16:47:51 +0100 Subject: [PATCH 0295/1049] sample: board: sensortile_box_pro: extend with lps22df Extend sensor sample reading also lps22df data. Signed-off-by: Armando Visconti --- .../sensors-on-board/README.rst | 3 + .../sensors-on-board/prj.conf | 1 + .../sensors-on-board/src/main.c | 62 +++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/README.rst b/samples/boards/sensortile_box_pro/sensors-on-board/README.rst index 16d5deca3537977..f65294f2aa88174 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/README.rst +++ b/samples/boards/sensortile_box_pro/sensors-on-board/README.rst @@ -13,6 +13,7 @@ periodically reads and displays data on the console from the following sensors: - HTS221: ambient temperature and relative humidity +- LPS22DF: ambient temperature and atmospheric pressure - LSM6DSV16X: 6-Axis acceleration and angular velocity Requirements @@ -62,6 +63,8 @@ The sample code outputs sensors data on the SensorTile.box Pro console. HTS221: Temperature: 26.4 C HTS221: Relative Humidity: 60.5% + LPS22DF: Temperature: 28.4 C + LPS22DF: Pressure:99.694 kpa LSM6DSV16X: Accel (m.s-2): x: -0.158, y: 0.158, z: 9.811 LSM6DSV16X: GYro (dps): x: 0.003, y: 0.000, z: -0.005 1:: lsm6dsv16x acc trig 836 diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf b/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf index 82c6af865c93f5c..a7c57f2f7469acb 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf +++ b/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf @@ -8,6 +8,7 @@ CONFIG_GPIO=y CONFIG_SENSOR=y CONFIG_SENSOR_LOG_LEVEL_DBG=y CONFIG_HTS221_TRIGGER_NONE=y +CONFIG_LPS22DF_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD=y CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c b/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c index 8bb24ccc7d640eb..7aab1f36b13b588 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c +++ b/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c @@ -15,6 +15,17 @@ #include +#ifdef CONFIG_LPS22DF_TRIGGER +static int lps22df_trig_cnt; + +static void lps22df_trigger_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_PRESS); + lps22df_trig_cnt++; +} +#endif + #ifdef CONFIG_LSM6DSV16X_TRIGGER static int lsm6dsv16x_acc_trig_cnt; static int lsm6dsv16x_gyr_trig_cnt; @@ -53,6 +64,29 @@ static void lis2mdl_trigger_handler(const struct device *dev, } #endif +static void lps22df_config(const struct device *lps22df) +{ + struct sensor_value odr_attr; + + /* set LPS22DF sampling frequency to 50 Hz */ + odr_attr.val1 = 50; + odr_attr.val2 = 0; + + if (sensor_attr_set(lps22df, SENSOR_CHAN_ALL, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LPS22DF\n"); + return; + } + +#ifdef CONFIG_LPS22DF_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ALL; + sensor_trigger_set(lps22df, &trig, lps22df_trigger_handler); +#endif +} + static void lsm6dsv16x_config(const struct device *lsm6dsv16x) { struct sensor_value odr_attr, fs_attr; @@ -199,6 +233,7 @@ int main(void) printk("SensorTile.box Pro sensor test\n"); const struct device *const hts221 = DEVICE_DT_GET_ONE(st_hts221); + const struct device *const lps22df = DEVICE_DT_GET_ONE(st_lps22df); const struct device *const lsm6dsv16x = DEVICE_DT_GET_ONE(st_lsm6dsv16x); const struct device *const lis2mdl = DEVICE_DT_GET_ONE(st_lis2mdl); @@ -206,6 +241,10 @@ int main(void) printk("%s: device not ready.\n", hts221->name); return 0; } + if (!device_is_ready(lps22df)) { + printk("%s: device not ready.\n", lps22df->name); + return 0; + } if (!device_is_ready(lsm6dsv16x)) { printk("%s: device not ready.\n", lsm6dsv16x->name); return 0; @@ -216,10 +255,12 @@ int main(void) } lis2mdl_config(lis2mdl); + lps22df_config(lps22df); lsm6dsv16x_config(lsm6dsv16x); while (1) { struct sensor_value hts221_hum, hts221_temp; + struct sensor_value lps22df_press, lps22df_temp; struct sensor_value lsm6dsv16x_accel[3], lsm6dsv16x_gyro[3]; struct sensor_value lis2mdl_magn[3]; struct sensor_value lis2mdl_temp; @@ -237,6 +278,13 @@ int main(void) } #endif +#ifndef CONFIG_LPS22DF_TRIGGER + if (sensor_sample_fetch(lps22df) < 0) { + printf("LPS22DF Sensor sample update error\n"); + return 0; + } +#endif + #ifndef CONFIG_LIS2MDL_TRIGGER if (sensor_sample_fetch(lis2mdl) < 0) { printf("LIS2MDL Magn Sensor sample update error\n"); @@ -246,6 +294,8 @@ int main(void) sensor_channel_get(hts221, SENSOR_CHAN_HUMIDITY, &hts221_hum); sensor_channel_get(hts221, SENSOR_CHAN_AMBIENT_TEMP, &hts221_temp); + sensor_channel_get(lps22df, SENSOR_CHAN_AMBIENT_TEMP, &lps22df_temp); + sensor_channel_get(lps22df, SENSOR_CHAN_PRESS, &lps22df_press); sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, lsm6dsv16x_accel); sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, lsm6dsv16x_gyro); sensor_channel_get(lis2mdl, SENSOR_CHAN_MAGN_XYZ, lis2mdl_magn); @@ -266,6 +316,14 @@ int main(void) printf("HTS221: Relative Humidity: %.1f%%\n", sensor_value_to_double(&hts221_hum)); + /* temperature */ + printf("LPS22DF: Temperature: %.1f C\n", + sensor_value_to_double(&lps22df_temp)); + + /* pressure */ + printf("LPS22DF: Pressure: %.3f kpa\n", + sensor_value_to_double(&lps22df_press)); + printf("LSM6DSV16X: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", sensor_value_to_double(&lsm6dsv16x_accel[0]), sensor_value_to_double(&lsm6dsv16x_accel[1]), @@ -285,6 +343,10 @@ int main(void) printf("LIS2MDL: Temperature: %.1f C\n", sensor_value_to_double(&lis2mdl_temp)); +#ifdef CONFIG_LPS22DF_TRIGGER + printk("%d:: lps22df trig %d\n", cnt, lps22df_trig_cnt); +#endif + #ifdef CONFIG_LSM6DSV16X_TRIGGER printk("%d:: lsm6dsv16x acc trig %d\n", cnt, lsm6dsv16x_acc_trig_cnt); printk("%d:: lsm6dsv16x gyr trig %d\n", cnt, lsm6dsv16x_gyr_trig_cnt); From f9d0a4c5cf0ff90287cd902c81de882010700689 Mon Sep 17 00:00:00 2001 From: Lucas Denefle Date: Thu, 2 Nov 2023 16:23:02 +0000 Subject: [PATCH 0296/1049] drivers: modem: add Quectel EG25-G This commit introduces support for the modem EG25-G from Quectel. Signed-off-by: Lucas Denefle --- drivers/modem/Kconfig.cellular | 3 +- drivers/modem/modem_cellular.c | 73 +++++++++++++++++++++++++ dts/bindings/modem/quectel,eg25-g.yaml | 16 ++++++ tests/drivers/build_all/modem/uart.dtsi | 6 ++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/modem/quectel,eg25-g.yaml diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index 767879ccf0e0148..7817fb599e3bdba 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -13,7 +13,8 @@ config MODEM_CELLULAR select NET_L2_PPP_OPTION_MRU depends on (DT_HAS_QUECTEL_BG95_ENABLED || DT_HAS_ZEPHYR_GSM_PPP_ENABLED || \ DT_HAS_SIMCOM_SIM7080_ENABLED || DT_HAS_U_BLOX_SARA_R4_ENABLED || \ - DT_HAS_SWIR_HL7800_ENABLED || DT_HAS_TELIT_ME910G1_ENABLED) + DT_HAS_SWIR_HL7800_ENABLED || DT_HAS_TELIT_ME910G1_ENABLED || \ + DT_HAS_QUECTEL_EG25_G_ENABLED) help This driver uses the generic 3gpp AT commands, along with the standard protocols CMUX and PPP, to configure diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index 7564283417a92aa..c3b97f0b6186eee 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -1356,6 +1356,47 @@ MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_periodic_chat_script, modem_cellular_chat_callback_handler, 4); #endif +#if DT_HAS_COMPAT_STATUS_OKAY(quectel_eg25_g) +MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_init_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGSN", imei_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127,10,3,30,10,2", + 100)); + +MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_init_chat_script, quectel_eg25_g_init_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_dial_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT+CGACT=0,1", allow_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGDCONT=1,\"IP\"," + "\""CONFIG_MODEM_CELLULAR_APN"\"", + ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("ATD*99***1#", 0),); + +MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_dial_chat_script, quectel_eg25_g_dial_chat_script_cmds, + dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_periodic_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_periodic_chat_script, + quectel_eg25_g_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); +#endif + #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_gsm_ppp) MODEM_CHAT_SCRIPT_CMDS_DEFINE(zephyr_gsm_ppp_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), @@ -1625,6 +1666,34 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, &MODEM_CELLULAR_INST_NAME(data, inst), \ &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); +#define MODEM_CELLULAR_DEVICE_QUECTEL_EG25_G(inst) \ + MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ + \ + static struct modem_cellular_data MODEM_CELLULAR_INST_NAME(data, inst) = { \ + .chat_delimiter = {'\r'}, \ + .chat_filter = {'\n'}, \ + .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ + }; \ + \ + static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .power_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mdm_power_gpios, {}), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mdm_reset_gpios, {}), \ + .power_pulse_duration_ms = 1500, \ + .reset_pulse_duration_ms = 500, \ + .startup_time_ms = 15000, \ + .shutdown_time_ms = 5000, \ + .init_chat_script = &quectel_eg25_g_init_chat_script, \ + .dial_chat_script = &quectel_eg25_g_dial_chat_script, \ + .periodic_chat_script = &_CONCAT(DT_DRV_COMPAT, _periodic_chat_script), \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, modem_cellular_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ + &MODEM_CELLULAR_INST_NAME(data, inst), \ + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); + #define MODEM_CELLULAR_DEVICE_GSM_PPP(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ \ @@ -1769,6 +1838,10 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_BG95) #undef DT_DRV_COMPAT +#define DT_DRV_COMPAT quectel_eg25_g +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_EG25_G) +#undef DT_DRV_COMPAT + #define DT_DRV_COMPAT zephyr_gsm_ppp DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_GSM_PPP) #undef DT_DRV_COMPAT diff --git a/dts/bindings/modem/quectel,eg25-g.yaml b/dts/bindings/modem/quectel,eg25-g.yaml new file mode 100644 index 000000000000000..45284ddf174b4b1 --- /dev/null +++ b/dts/bindings/modem/quectel,eg25-g.yaml @@ -0,0 +1,16 @@ +description: Quectel EG25-G modem + +compatible: "quectel,eg25-g" + +include: uart-device.yaml + +properties: + mdm-reset-gpios: + type: phandle-array + required: true + + mdm-dtr-gpios: + type: phandle-array + + mdm-wdisable-gpios: + type: phandle-array diff --git a/tests/drivers/build_all/modem/uart.dtsi b/tests/drivers/build_all/modem/uart.dtsi index 985f60dba6915ad..3d649a2ff603216 100644 --- a/tests/drivers/build_all/modem/uart.dtsi +++ b/tests/drivers/build_all/modem/uart.dtsi @@ -47,6 +47,12 @@ test_quectel_bg9x: quectel_bg9x { mdm-reset-gpios = <&test_gpio 0 0>; }; +test_quectel_eg25_g: quectel_eg25_g { + compatible = "quectel,eg25-g"; + + mdm-reset-gpios = <&test_gpio 0 0>; +}; + test_gsm_ppp: gsm_ppp { compatible = "zephyr,gsm-ppp"; }; From 85888c673da009f0c4767b8ec11c4c2b4600d785 Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 10 Nov 2023 13:52:00 +0800 Subject: [PATCH 0297/1049] manifest: Bump up hal_nxp revision Bump up hal_nxp revision to contain the clock frequency array initialization code of i.MX 93 Signed-off-by: Chekhov Ma --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 62194f60c193e2a..639f5566de01a6d 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: d5e5358e56542b94bc65b6483396f50ed8f3172d + revision: 73620197038d7ba80fb1f9abd001828b9dd6a27e path: modules/hal/nxp groups: - hal From 4e99da8599616eff73de2bce9f7cae56838aa858 Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Fri, 10 Nov 2023 11:21:08 +0800 Subject: [PATCH 0298/1049] imx93: change ccm driver to "imx-ccm-rev2" i.MX93 share similiar register layout with i.MX RT11xx. Change ccm driver to align with i.MX RT11xx, and make it easier to enable other drivers. Signed-off-by: Chekhov Ma --- drivers/clock_control/clock_control_mcux_ccm_rev2.c | 9 ++++++--- dts/arm64/nxp/nxp_mimx93_a55.dtsi | 8 ++++---- soc/arm64/nxp_imx/mimx9/Kconfig.soc | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index 626402d73dff8df..9a88a36823a9a59 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -6,7 +6,6 @@ #define DT_DRV_COMPAT nxp_imx_ccm_rev2 #include -#include #include #include #include @@ -31,7 +30,7 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, clock_control_subsys_t sub_system, uint32_t *rate) { - uint32_t clock_name = (uint32_t) sub_system; + uint32_t clock_name = (size_t) sub_system; uint32_t clock_root, peripheral, instance; peripheral = (clock_name & IMX_CCM_PERIPHERAL_MASK); @@ -51,6 +50,7 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, #ifdef CONFIG_UART_MCUX_LPUART case IMX_CCM_LPUART1_CLK: + case IMX_CCM_LPUART2_CLK: clock_root = kCLOCK_Root_Lpuart1 + instance; break; #endif @@ -106,8 +106,11 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, default: return -EINVAL; } - +#ifdef CONFIG_SOC_MIMX93_A55 + *rate = CLOCK_GetIpFreq(clock_root); +#else *rate = CLOCK_GetRootClockFreq(clock_root); +#endif return 0; } diff --git a/dts/arm64/nxp/nxp_mimx93_a55.dtsi b/dts/arm64/nxp/nxp_mimx93_a55.dtsi index e064233e46fa05a..22a61e2dfca8488 100644 --- a/dts/arm64/nxp/nxp_mimx93_a55.dtsi +++ b/dts/arm64/nxp/nxp_mimx93_a55.dtsi @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include / { @@ -70,7 +70,7 @@ }; ccm: ccm@44450000 { - compatible = "nxp,imx-ccm"; + compatible = "nxp,imx-ccm-rev2"; reg = <0x44450000 DT_SIZE_K(64)>; #clock-cells = <3>; }; @@ -81,7 +81,7 @@ interrupts = ; interrupt-names = "irq_0"; interrupt-parent = <&gic>; - clocks = <&ccm IMX_CCM_LPUART_CLK 0x6c 24>; + clocks = <&ccm IMX_CCM_LPUART1_CLK 0x6c 24>; status = "disabled"; }; @@ -91,7 +91,7 @@ interrupts = ; interrupt-names = "irq_0"; interrupt-parent = <&gic>; - clocks = <&ccm IMX_CCM_LPUART_CLK 0x6c 24>; + clocks = <&ccm IMX_CCM_LPUART2_CLK 0x6c 24>; status = "disabled"; }; }; diff --git a/soc/arm64/nxp_imx/mimx9/Kconfig.soc b/soc/arm64/nxp_imx/mimx9/Kconfig.soc index 01ba98968744ea7..3f38d40131fd15c 100644 --- a/soc/arm64/nxp_imx/mimx9/Kconfig.soc +++ b/soc/arm64/nxp_imx/mimx9/Kconfig.soc @@ -11,7 +11,7 @@ config SOC_MIMX93_A55 select CPU_CORTEX_A55 select ARM_ARCH_TIMER if SYS_CLOCK_EXISTS select HAS_MCUX if CLOCK_CONTROL - select HAS_MCUX_CCM if CLOCK_CONTROL + select HAS_MCUX_CCM_REV2 if CLOCK_CONTROL select HAS_MCUX_IOMUXC if PINCTRL endchoice From 5078265213e1afb06f530ea5d301882350724282 Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Mon, 23 Oct 2023 15:40:41 +0800 Subject: [PATCH 0299/1049] Revert "drivers: mcux_ccm: add support for lpuart on imx93" This reverts commit d963900dbd56fc3663881cf54f64b81e6dcc30fb. Since i.MX 93 is supported by mcux_ccm_rev2, remove i.MX 93 support from mcux_ccm driver. Signed-off-by: Chekhov Ma --- .../clock_control/clock_control_mcux_ccm.c | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/drivers/clock_control/clock_control_mcux_ccm.c b/drivers/clock_control/clock_control_mcux_ccm.c index 77736caa1c92fca..ab90602d2a40099 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -43,18 +43,6 @@ static const clock_ip_name_t uart_clocks[] = { kCLOCK_Uart4, }; #endif -#if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX93_A55) -static const clock_root_t lpuart_clk_root[] = { - kCLOCK_Root_Lpuart1, - kCLOCK_Root_Lpuart2, - kCLOCK_Root_Lpuart3, - kCLOCK_Root_Lpuart4, - kCLOCK_Root_Lpuart5, - kCLOCK_Root_Lpuart6, - kCLOCK_Root_Lpuart7, - kCLOCK_Root_Lpuart8, -}; -#endif #ifdef CONFIG_UART_MCUX_LPUART @@ -203,28 +191,6 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, *rate = CLOCK_GetIpFreq(lpuart_clocks[instance]); break; -#elif defined(CONFIG_SOC_MIMX93_A55) - case IMX_CCM_LPUART1_CLK: - case IMX_CCM_LPUART2_CLK: - case IMX_CCM_LPUART3_CLK: - case IMX_CCM_LPUART4_CLK: - case IMX_CCM_LPUART5_CLK: - case IMX_CCM_LPUART6_CLK: - case IMX_CCM_LPUART7_CLK: - case IMX_CCM_LPUART8_CLK: - { - uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK; - clock_root_t clk_root = lpuart_clk_root[instance]; - uint32_t uart_mux = CLOCK_GetRootClockMux(clk_root); - uint32_t divider = CLOCK_GetRootClockDiv(clk_root); - - if (uart_mux == 0) - *rate = MHZ(24) / divider; - else - LOG_ERR("LPUART Clock is not supported\r\n"); - - } break; - #else case IMX_CCM_LPUART_CLK: if (CLOCK_GetMux(kCLOCK_UartMux) == 0) { From b654b6169944054e4a72be483c824c6d22ac7763 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 3 Oct 2023 13:00:45 +0300 Subject: [PATCH 0300/1049] drivers: sensor: adxl372: remove unused function After the merge of 9dda350 the `adxl327_reg_write_mask` function is no longer used. Signed-off-by: Antoniu Miclaus --- drivers/sensor/adxl372/adxl372.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/sensor/adxl372/adxl372.h b/drivers/sensor/adxl372/adxl372.h index c891413088239c9..13b4d93454b056e 100644 --- a/drivers/sensor/adxl372/adxl372.h +++ b/drivers/sensor/adxl372/adxl372.h @@ -365,9 +365,6 @@ int adxl372_i2c_init(const struct device *dev); int adxl372_get_status(const struct device *dev, uint8_t *status1, uint8_t *status2, uint16_t *fifo_entries); -int adxl372_reg_write_mask(const struct device *dev, - uint8_t reg_addr, uint32_t mask, uint8_t data); - int adxl372_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler); From 461cc8c136c0d8055255fe404edc8aeb7184963b Mon Sep 17 00:00:00 2001 From: Maxin John Date: Fri, 20 Oct 2023 18:16:52 +0300 Subject: [PATCH 0301/1049] samples: sensor: dht: add longan_nano overlay Add an overlay to use DHT11 temperature/humidity sensor in Longan Nano. Signed-off-by: Maxin John --- samples/sensor/dht/boards/longan_nano.overlay | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 samples/sensor/dht/boards/longan_nano.overlay diff --git a/samples/sensor/dht/boards/longan_nano.overlay b/samples/sensor/dht/boards/longan_nano.overlay new file mode 100644 index 000000000000000..a50cd9b94049dbc --- /dev/null +++ b/samples/sensor/dht/boards/longan_nano.overlay @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + dht22 { + compatible = "aosong,dht"; + status = "okay"; + dio-gpios = <&gpiob 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; +}; From 774bf6b50e09ca07f91159ab66034129d7de503c Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 25 Oct 2023 16:46:42 +0300 Subject: [PATCH 0302/1049] drivers: sensor: adxl367: update self test delay The wait times in the self test procedure, according to the datasheet are 4 / ODR (current set value). Update the self test procedure by using the delay corresponding to the current ODR value that is set, instead of default ODR. Signed-off-by: Antoniu Miclaus --- drivers/sensor/adxl367/adxl367.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/sensor/adxl367/adxl367.c b/drivers/sensor/adxl367/adxl367.c index 020ee476b2b72a1..f63b8f73a321077 100644 --- a/drivers/sensor/adxl367/adxl367.c +++ b/drivers/sensor/adxl367/adxl367.c @@ -277,9 +277,30 @@ int adxl367_self_test(const struct device *dev) { int ret; struct adxl367_data *data = dev->data; + const struct adxl367_dev_config *cfg = dev->config; int16_t x_axis_1, x_axis_2, dif, min, max; uint8_t read_val[2]; + uint32_t st_delay_ms; + + /* 4 / ODR value in ms */ + switch (cfg->odr) { + case ADXL367_ODR_12P5HZ: + st_delay_ms = 320; + case ADXL367_ODR_25HZ: + st_delay_ms = 160; + case ADXL367_ODR_50HZ: + st_delay_ms = 80; + case ADXL367_ODR_100HZ: + st_delay_ms = 40; + case ADXL367_ODR_200HZ: + st_delay_ms = 20; + case ADXL367_ODR_400HZ: + st_delay_ms = 10; + default: + return -EINVAL; + } + ret = adxl367_set_op_mode(dev, ADXL367_MEASURE); if (ret != 0) { return ret; @@ -291,8 +312,8 @@ int adxl367_self_test(const struct device *dev) return ret; } - /* 4 / default ODR = 40ms */ - k_sleep(K_MSEC(40)); + /* 4 / ODR */ + k_sleep(K_MSEC(st_delay_ms)); ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, read_val, 2); if (ret != 0) { @@ -313,8 +334,8 @@ int adxl367_self_test(const struct device *dev) return ret; } - /* 4 / default ODR = 40ms */ - k_sleep(K_MSEC(40)); + /* 4 / ODR */ + k_sleep(K_MSEC(st_delay_ms)); ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, read_val, 2); if (ret != 0) { From dcf882af03b84bd9e8319be652cf2824eaf2999c Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Thu, 26 Oct 2023 15:29:17 +0200 Subject: [PATCH 0303/1049] dts: bindings: Add gss vendor prefix Add vendor prefix for Gas Sensing Solutions Ltd. Signed-off-by: Jeppe Odgaard --- dts/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index e426bef99bd55b1..5515ea53ebe73ed 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -243,6 +243,7 @@ google Google, Inc. greeled GreeLed Electronic Ltd. grinn Grinn grmn Garmin Limited +gss Gas Sensing Solutions Ltd. gumstix Gumstix, Inc. hamamatsu Hamamatsu Photonics K.K. hannstar HannStar Display Corporation From 128f80db7dde84b4a60a5a5d749ad01c140e3093 Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Thu, 26 Oct 2023 15:50:09 +0200 Subject: [PATCH 0304/1049] dts: bindings: add explorir_m support Add bindings for the ExplorIR-M CO2 sensor. Signed-off-by: Jeppe Odgaard --- dts/bindings/sensor/gss,explorir-m.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 dts/bindings/sensor/gss,explorir-m.yaml diff --git a/dts/bindings/sensor/gss,explorir-m.yaml b/dts/bindings/sensor/gss,explorir-m.yaml new file mode 100644 index 000000000000000..62de081c1be159b --- /dev/null +++ b/dts/bindings/sensor/gss,explorir-m.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +description: Gas Sensing Solutions CO2 sensor + +compatible: "gss,explorir-m" + +include: [sensor-device.yaml, uart-device.yaml] From b0fdbce4df43f0b1ebccbd110c83ebd5d553e214 Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Fri, 27 Oct 2023 15:17:44 +0200 Subject: [PATCH 0305/1049] drivers: sensors: add explorir_m co2 sensor Add driver for Gas Sensing Solutions' ExplorIR-M CO2 sensor. Signed-off-by: Jeppe Odgaard --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/explorir_m/CMakeLists.txt | 5 + drivers/sensor/explorir_m/Kconfig | 13 + drivers/sensor/explorir_m/explorir_m.c | 387 +++++++++++++++++++++ include/zephyr/drivers/sensor/explorir_m.h | 25 ++ 6 files changed, 432 insertions(+) create mode 100644 drivers/sensor/explorir_m/CMakeLists.txt create mode 100644 drivers/sensor/explorir_m/Kconfig create mode 100644 drivers/sensor/explorir_m/explorir_m.c create mode 100644 include/zephyr/drivers/sensor/explorir_m.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 0bace9305b96b58..ff1cf9ec4eb449c 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -36,6 +36,7 @@ add_subdirectory_ifdef(CONFIG_DPS310 dps310) add_subdirectory_ifdef(CONFIG_DS18B20 ds18b20) add_subdirectory_ifdef(CONFIG_ENS210 ens210) add_subdirectory_ifdef(CONFIG_ESP32_TEMP esp32_temp) +add_subdirectory_ifdef(CONFIG_EXPLORIR_M explorir_m) add_subdirectory_ifdef(CONFIG_F75303 f75303) add_subdirectory_ifdef(CONFIG_FDC2X1X fdc2x1x) add_subdirectory_ifdef(CONFIG_FXAS21002 fxas21002) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index e334617cf0b3196..55ef3ffec513643 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -109,6 +109,7 @@ source "drivers/sensor/dps310/Kconfig" source "drivers/sensor/ds18b20/Kconfig" source "drivers/sensor/ens210/Kconfig" source "drivers/sensor/esp32_temp/Kconfig" +source "drivers/sensor/explorir_m/Kconfig" source "drivers/sensor/f75303/Kconfig" source "drivers/sensor/fdc2x1x/Kconfig" source "drivers/sensor/fxas21002/Kconfig" diff --git a/drivers/sensor/explorir_m/CMakeLists.txt b/drivers/sensor/explorir_m/CMakeLists.txt new file mode 100644 index 000000000000000..71125b505f38076 --- /dev/null +++ b/drivers/sensor/explorir_m/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(explorir_m.c) diff --git a/drivers/sensor/explorir_m/Kconfig b/drivers/sensor/explorir_m/Kconfig new file mode 100644 index 000000000000000..02806bf82a80e74 --- /dev/null +++ b/drivers/sensor/explorir_m/Kconfig @@ -0,0 +1,13 @@ +# ExplorIR-M CO2 sensor configuration options + +# Copyright (c) 2023, Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +config EXPLORIR_M + bool "ExplorIR-M CO2 Sensor" + default y + depends on DT_HAS_GSS_EXPLORIR_M_ENABLED + depends on UART_INTERRUPT_DRIVEN + select UART + help + Enable driver for ExplorIR-M CO2 Sensor. diff --git a/drivers/sensor/explorir_m/explorir_m.c b/drivers/sensor/explorir_m/explorir_m.c new file mode 100644 index 000000000000000..058c43faf2b4952 --- /dev/null +++ b/drivers/sensor/explorir_m/explorir_m.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2023, Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.gassensing.co.uk/wp-content/uploads/2023/05/ExplorIR-M-Data-Sheet-Rev-4.13_3.pdf + * + */ + +#define DT_DRV_COMPAT gss_explorir_m + +#include + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(explorir_m_sensor, CONFIG_SENSOR_LOG_LEVEL); + +#define EXPLORIR_M_BEGIN_CHAR ' ' + +#define EXPLORIR_M_SET_FILTER_CHAR 'A' +#define EXPLORIR_M_GET_FILTER_CHAR 'a' +#define EXPLORIR_M_MODE_CHAR 'K' +#define EXPLORIR_M_CO2_FILTERED_CHAR 'Z' +#define EXPLORIR_M_SCALING_CHAR '.' +#define EXPLORIR_M_NOT_RECOGNISED_CHAR '?' + +#define EXPLORIR_M_SEPARATOR_CHAR ' ' +#define EXPLORIR_M_PRE_END_CHAR '\r' +#define EXPLORIR_M_END_CHAR '\n' + +#define EXPLORIR_M_TYPE_INDEX 1 +#define EXPLORIR_M_VALUE_INDEX 3 + +#define EXPLORIR_M_BUFFER_LENGTH 16 + +#define EXPLORIR_M_MAX_RESPONSE_DELAY 200 /* Add margin to the specified 100 in datasheet */ +#define EXPLORIR_M_CO2_VALID_DELAY 1200 + +struct explorir_m_data { + struct k_mutex uart_mutex; + struct k_sem uart_rx_sem; + uint16_t filtered; + uint16_t scaling; + uint8_t read_index; + uint8_t read_buffer[EXPLORIR_M_BUFFER_LENGTH]; +}; + +struct explorir_m_cfg { + const struct device *uart_dev; + uart_irq_callback_user_data_t cb; +}; + +enum explorir_m_uart_set_usage { + EXPLORIR_M_SET_NONE, + EXPLORIR_M_SET_VAL_ONE, + EXPLORIR_M_SET_VAL_ONE_TWO, +}; + +enum EXPLORIR_M_MODE { + EXPLORIR_M_MODE_COMMAND, + EXPLORIR_M_MODE_STREAM, + EXPLORIR_M_MODE_POLL, +}; + +static void explorir_m_uart_flush(const struct device *uart_dev) +{ + uint8_t tmp; + + while (uart_fifo_read(uart_dev, &tmp, 1) > 0) { + continue; + } +} + +static void explorir_m_uart_flush_until_end(const struct device *uart_dev) +{ + uint8_t tmp; + uint32_t uptime; + + uptime = k_uptime_get_32(); + do { + uart_poll_in(uart_dev, &tmp); + } while (tmp != EXPLORIR_M_END_CHAR && + k_uptime_get_32() - uptime < EXPLORIR_M_MAX_RESPONSE_DELAY); +} + +static void explorir_m_buffer_reset(struct explorir_m_data *data) +{ + memset(data->read_buffer, 0, data->read_index); + data->read_index = 0; +} + +static int explorir_m_buffer_verify(const struct explorir_m_data *data, char type) +{ + char buffer_type = data->read_buffer[EXPLORIR_M_TYPE_INDEX]; + + if (data->read_buffer[0] == EXPLORIR_M_NOT_RECOGNISED_CHAR) { + LOG_WRN("Sensor did not recognise the command"); + return -EIO; + } + + if (buffer_type != type) { + LOG_WRN("Expected type %c but got %c", type, buffer_type); + return -EIO; + } + + if (data->read_buffer[0] != EXPLORIR_M_BEGIN_CHAR || + data->read_buffer[2] != EXPLORIR_M_SEPARATOR_CHAR || + data->read_buffer[data->read_index - 2] != EXPLORIR_M_PRE_END_CHAR) { + LOG_HEXDUMP_WRN(data->read_buffer, data->read_index, "Invalid buffer"); + return -EIO; + } + + return 0; +} + +static int explorir_m_buffer_process(struct explorir_m_data *data, char type, + struct sensor_value *val) +{ + if (explorir_m_buffer_verify(data, type) != 0) { + return -EIO; + } + + switch (type) { + case EXPLORIR_M_SET_FILTER_CHAR: + case EXPLORIR_M_MODE_CHAR: + break; + + case EXPLORIR_M_CO2_FILTERED_CHAR: + data->scaling = strtol(&data->read_buffer[EXPLORIR_M_VALUE_INDEX], NULL, 10); + break; + + case EXPLORIR_M_SCALING_CHAR: + data->filtered = strtol(&data->read_buffer[EXPLORIR_M_VALUE_INDEX], NULL, 10); + break; + + case EXPLORIR_M_GET_FILTER_CHAR: + val->val1 = strtol(&data->read_buffer[EXPLORIR_M_VALUE_INDEX], NULL, 10); + break; + + default: + LOG_ERR("Unknown type %c/0x%02x", type, type); + return -EIO; + } + + return 0; +} + +static void explorir_m_uart_isr(const struct device *uart_dev, void *user_data) +{ + const struct device *dev = user_data; + struct explorir_m_data *data = dev->data; + int rc, read_len; + + if (!device_is_ready(uart_dev)) { + LOG_DBG("UART device is not ready"); + return; + } + + if (!uart_irq_update(uart_dev)) { + LOG_DBG("Unable to process interrupts"); + return; + } + + if (!uart_irq_rx_ready(uart_dev)) { + LOG_DBG("No RX data"); + return; + } + + read_len = EXPLORIR_M_BUFFER_LENGTH - data->read_index; + rc = uart_fifo_read(uart_dev, &data->read_buffer[data->read_index], read_len); + + if (rc < 0 || rc == read_len) { + LOG_ERR("UART read failed: %d", rc < 0 ? rc : -ERANGE); + explorir_m_uart_flush(uart_dev); + LOG_HEXDUMP_WRN(data->read_buffer, data->read_index, "Discarding"); + explorir_m_buffer_reset(data); + } else { + data->read_index += rc; + + if (data->read_buffer[data->read_index - 1] != EXPLORIR_M_END_CHAR) { + return; + } + } + + k_sem_give(&data->uart_rx_sem); +} + +static void explorir_m_uart_terminate(const struct device *uart_dev) +{ + uart_poll_out(uart_dev, EXPLORIR_M_PRE_END_CHAR); + uart_poll_out(uart_dev, EXPLORIR_M_END_CHAR); +} + +static int explorir_m_await_receive(struct explorir_m_data *data) +{ + int rc = k_sem_take(&data->uart_rx_sem, K_MSEC(EXPLORIR_M_MAX_RESPONSE_DELAY)); + + /* Reset semaphore if sensor did not respond within maximum specified response time */ + if (rc == -EAGAIN) { + k_sem_reset(&data->uart_rx_sem); + } + + return rc; +} + +static int explorir_m_uart_transceive(const struct device *dev, char type, struct sensor_value *val, + enum explorir_m_uart_set_usage set) +{ + const struct explorir_m_cfg *cfg = dev->config; + struct explorir_m_data *data = dev->data; + char buf[EXPLORIR_M_BUFFER_LENGTH]; + int rc, len; + + if (val == NULL && set != EXPLORIR_M_SET_NONE) { + LOG_ERR("val is NULL but set is not NONE"); + return -EINVAL; + } + + k_mutex_lock(&data->uart_mutex, K_FOREVER); + + explorir_m_buffer_reset(data); + + uart_poll_out(cfg->uart_dev, type); + + if (set == EXPLORIR_M_SET_VAL_ONE) { + len = snprintf(buf, EXPLORIR_M_BUFFER_LENGTH, "%c%u", EXPLORIR_M_SEPARATOR_CHAR, + val->val1); + } else if (set == EXPLORIR_M_SET_VAL_ONE_TWO) { + len = snprintf(buf, EXPLORIR_M_BUFFER_LENGTH, "%c%u%c%u", EXPLORIR_M_SEPARATOR_CHAR, + val->val1, EXPLORIR_M_SEPARATOR_CHAR, val->val2); + } else { + len = 0; + } + + if (len == EXPLORIR_M_BUFFER_LENGTH) { + LOG_WRN("Set value truncated"); + } + for (int i = 0; i != len; i++) { + uart_poll_out(cfg->uart_dev, buf[i]); + } + + explorir_m_uart_terminate(cfg->uart_dev); + + rc = explorir_m_await_receive(data); + if (rc != 0) { + LOG_WRN("%c did not receive a response: %d", type, rc); + } + + if (rc == 0) { + rc = explorir_m_buffer_process(data, type, val); + } + + k_mutex_unlock(&data->uart_mutex); + + return rc; +} + +static int explorir_m_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_CO2) { + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_EXPLORIR_M_FILTER: + return explorir_m_uart_transceive(dev, EXPLORIR_M_GET_FILTER_CHAR, val, + EXPLORIR_M_SET_NONE); + default: + return -ENOTSUP; + } +} + +static int explorir_m_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_CO2) { + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_EXPLORIR_M_FILTER: + if (val->val1 < 0 || val->val1 > 255) { + return -ERANGE; + } + return explorir_m_uart_transceive(dev, EXPLORIR_M_SET_FILTER_CHAR, + (struct sensor_value *)val, + EXPLORIR_M_SET_VAL_ONE); + default: + return -ENOTSUP; + } +} + +static int explorir_m_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + if (chan != SENSOR_CHAN_CO2 && chan != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + return explorir_m_uart_transceive(dev, EXPLORIR_M_CO2_FILTERED_CHAR, NULL, + EXPLORIR_M_SET_NONE); +} + +static int explorir_m_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct explorir_m_data *data = dev->data; + + if (chan != SENSOR_CHAN_CO2) { + return -ENOTSUP; + } + + if (k_uptime_get() < EXPLORIR_M_CO2_VALID_DELAY) { + return -EAGAIN; + } + + val->val1 = data->filtered * data->scaling; + val->val2 = 0; + + return 0; +} + +static const struct sensor_driver_api explorir_m_api_funcs = { + .attr_set = explorir_m_attr_set, + .attr_get = explorir_m_attr_get, + .sample_fetch = explorir_m_sample_fetch, + .channel_get = explorir_m_channel_get, +}; + +static int explorir_m_init(const struct device *dev) +{ + const struct explorir_m_cfg *cfg = dev->config; + struct explorir_m_data *data = dev->data; + struct sensor_value val; + int rc; + + LOG_DBG("Initializing %s", dev->name); + + if (!device_is_ready(cfg->uart_dev)) { + return -ENODEV; + } + + k_mutex_init(&data->uart_mutex); + k_sem_init(&data->uart_rx_sem, 0, 1); + + uart_irq_rx_disable(cfg->uart_dev); + uart_irq_tx_disable(cfg->uart_dev); + + rc = uart_irq_callback_user_data_set(cfg->uart_dev, cfg->cb, (void *)dev); + if (rc != 0) { + LOG_ERR("UART IRQ setup failed: %d", rc); + return rc; + } + + /* Terminate garbled tx due to GPIO setup or crash during unfinished send */ + explorir_m_uart_terminate(cfg->uart_dev); + explorir_m_uart_flush_until_end(cfg->uart_dev); + + uart_irq_rx_enable(cfg->uart_dev); + + val.val1 = EXPLORIR_M_MODE_POLL; + explorir_m_uart_transceive(dev, EXPLORIR_M_MODE_CHAR, &val, EXPLORIR_M_SET_VAL_ONE); + explorir_m_uart_transceive(dev, EXPLORIR_M_SCALING_CHAR, NULL, EXPLORIR_M_SET_NONE); + + return rc; +} + +#define EXPLORIR_M_INIT(n) \ + \ + static struct explorir_m_data explorir_m_data_##n; \ + \ + static const struct explorir_m_cfg explorir_m_cfg_##n = { \ + .uart_dev = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .cb = explorir_m_uart_isr, \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, explorir_m_init, NULL, &explorir_m_data_##n, \ + &explorir_m_cfg_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &explorir_m_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(EXPLORIR_M_INIT) diff --git a/include/zephyr/drivers/sensor/explorir_m.h b/include/zephyr/drivers/sensor/explorir_m.h new file mode 100644 index 000000000000000..efef562447cead0 --- /dev/null +++ b/include/zephyr/drivers/sensor/explorir_m.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023, Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_EXPLORIR_M_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_EXPLORIR_M_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum sensor_attribute_explorir_m { + /* Sensor integrated low-pass filter. Values 16, 32, 64, and 128 is allowed */ + SENSOR_ATTR_EXPLORIR_M_FILTER = SENSOR_ATTR_PRIV_START, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_EXPLORIR_M_H_ */ From 171dbd0435a0fd50303523bb147896f473d412b3 Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Fri, 27 Oct 2023 15:23:46 +0200 Subject: [PATCH 0306/1049] samples: sensors: add generic co2 sensor polling Add polling sample for any CO2 sensor. Signed-off-by: Jeppe Odgaard --- samples/sensor/co2_polling/CMakeLists.txt | 7 ++++ samples/sensor/co2_polling/README.rst | 30 +++++++++++++++++ .../co2_polling/boards/nucleo_h563zi.conf | 1 + .../co2_polling/boards/nucleo_h563zi.overlay | 15 +++++++++ samples/sensor/co2_polling/prj.conf | 7 ++++ samples/sensor/co2_polling/sample.yaml | 8 +++++ samples/sensor/co2_polling/src/main.c | 33 +++++++++++++++++++ 7 files changed, 101 insertions(+) create mode 100644 samples/sensor/co2_polling/CMakeLists.txt create mode 100644 samples/sensor/co2_polling/README.rst create mode 100644 samples/sensor/co2_polling/boards/nucleo_h563zi.conf create mode 100644 samples/sensor/co2_polling/boards/nucleo_h563zi.overlay create mode 100644 samples/sensor/co2_polling/prj.conf create mode 100644 samples/sensor/co2_polling/sample.yaml create mode 100644 samples/sensor/co2_polling/src/main.c diff --git a/samples/sensor/co2_polling/CMakeLists.txt b/samples/sensor/co2_polling/CMakeLists.txt new file mode 100644 index 000000000000000..ae467b6d2aa9d98 --- /dev/null +++ b/samples/sensor/co2_polling/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(co2_polling) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/sensor/co2_polling/README.rst b/samples/sensor/co2_polling/README.rst new file mode 100644 index 000000000000000..c0436b363acccaf --- /dev/null +++ b/samples/sensor/co2_polling/README.rst @@ -0,0 +1,30 @@ +.. co2: + +Generic CO2 polling sample +########################## + +Overview +******** + +A sensor sample that demonstrates how to poll a CO2 sensor. + +Building and Running +******************** + +This sample reads the CO2 sensor and print the values continuously. + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/co2_polling + :board: + :goals: build flash + :compact: + +Sample Output +============= + +.. code-block:: console + + CO2 940 ppm + CO2 950 ppm + + diff --git a/samples/sensor/co2_polling/boards/nucleo_h563zi.conf b/samples/sensor/co2_polling/boards/nucleo_h563zi.conf new file mode 100644 index 000000000000000..86df0aff3e6242a --- /dev/null +++ b/samples/sensor/co2_polling/boards/nucleo_h563zi.conf @@ -0,0 +1 @@ +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/samples/sensor/co2_polling/boards/nucleo_h563zi.overlay b/samples/sensor/co2_polling/boards/nucleo_h563zi.overlay new file mode 100644 index 000000000000000..549e34926995da6 --- /dev/null +++ b/samples/sensor/co2_polling/boards/nucleo_h563zi.overlay @@ -0,0 +1,15 @@ +/ { + aliases { + co2 = &explorir_m; + }; +}; + +&lpuart1 { + status = "okay"; + current-speed = <9600>; + + explorir_m: explorir_m { + compatible = "gss,explorir-m"; + status = "okay"; + }; +}; diff --git a/samples/sensor/co2_polling/prj.conf b/samples/sensor/co2_polling/prj.conf new file mode 100644 index 000000000000000..fe480d2b794be33 --- /dev/null +++ b/samples/sensor/co2_polling/prj.conf @@ -0,0 +1,7 @@ +CONFIG_STDOUT_CONSOLE=y +CONFIG_LOG=y +CONFIG_SHELL=y +CONFIG_SENSOR_SHELL=y +CONFIG_SERIAL=y +CONFIG_SENSOR=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y diff --git a/samples/sensor/co2_polling/sample.yaml b/samples/sensor/co2_polling/sample.yaml new file mode 100644 index 000000000000000..13b4ffa6dfb4839 --- /dev/null +++ b/samples/sensor/co2_polling/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: CO2 sensor sample +tests: + sample.sensor.co2: + harness: sensor + tags: sensors + filter: dt_alias_exists("co2") + depends_on: serial uart_interrupt_driven diff --git a/samples/sensor/co2_polling/src/main.c b/samples/sensor/co2_polling/src/main.c new file mode 100644 index 000000000000000..4f1845274539b96 --- /dev/null +++ b/samples/sensor/co2_polling/src/main.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +LOG_MODULE_REGISTER(MAIN); + +int main(void) +{ + struct sensor_value value; + const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(co2)); + + if (!device_is_ready(dev)) { + LOG_ERR("%s is not ready", dev->name); + return 0; + } + + while (1) { + if (sensor_sample_fetch(dev) == 0 && + sensor_channel_get(dev, SENSOR_CHAN_CO2, &value) == 0) { + LOG_INF("CO2 %d ppm", value.val1); + } + + k_msleep(1000); + } + + return 0; +} From a1b16d3151c061af270744bc44e09e6b8ec2e7b6 Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Thu, 26 Oct 2023 15:59:37 +0200 Subject: [PATCH 0307/1049] tests: build_all: sensor: i2c: add explorir_m Add ExplorIR-M uart node in the build_all tests. Signed-off-by: Jeppe Odgaard --- tests/drivers/build_all/sensor/uart.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/drivers/build_all/sensor/uart.dtsi b/tests/drivers/build_all/sensor/uart.dtsi index 11b08dd99eb184c..05a2634f24a92dd 100644 --- a/tests/drivers/build_all/sensor/uart.dtsi +++ b/tests/drivers/build_all/sensor/uart.dtsi @@ -30,3 +30,7 @@ grow_r502a { test_uart_a01nyub: a01nyub { compatible = "dfrobot,a01nyub"; }; + +test_uart_explorir_m: explorir-m { + compatible = "gss,explorir-m"; +}; From a2a18e3fa4196e45edb006153da1959f854ec134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 7 Nov 2023 17:51:33 +0100 Subject: [PATCH 0308/1049] doc: pdf: Add Glossary of Terms to PDF output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the Glossary page to the PDF so that :term: roles are properly resolved. Signed-off-by: Benjamin Cabé --- doc/index-tex.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/index-tex.rst b/doc/index-tex.rst index 09ef9e9459e64ea..9c0527ae73a0efa 100644 --- a/doc/index-tex.rst +++ b/doc/index-tex.rst @@ -24,3 +24,4 @@ Zephyr Project Documentation project/index.rst security/index.rst safety/index.rst + glossary.rst From 434a40470c904cb40b8e1b128e5f1a180a993bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 9 Nov 2023 18:00:57 +0700 Subject: [PATCH 0309/1049] drivers: mbox: nxp_s32: use instance-based DT macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At present, many of the NXP S32 shim drivers do not make use of devicetree instance-based macros because the NXP S32 HAL relies on an index-based approach, requiring knowledge of the peripheral instance index during both compilation and runtime, and this index might not align with the devicetree instance index. The proposed solution in this patch eliminates this limitation by determining the peripheral instance index during compilation through macrobatics and defining the driver's ISR within the shim driver itself. Note that for some peripheral instances is needed to redefine the HAL macros of the peripheral base address, since the naming is not uniform for all instances. Signed-off-by: Manuel Argüelles --- drivers/mbox/mbox_nxp_s32_mru.c | 91 ++++++++++++--------------------- soc/arm/nxp_s32/s32ze/soc.h | 10 ++++ 2 files changed, 44 insertions(+), 57 deletions(-) diff --git a/drivers/mbox/mbox_nxp_s32_mru.c b/drivers/mbox/mbox_nxp_s32_mru.c index 287ba89eff8d4eb..8981e260d503162 100644 --- a/drivers/mbox/mbox_nxp_s32_mru.c +++ b/drivers/mbox/mbox_nxp_s32_mru.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_mru + #include #include #include @@ -19,22 +21,11 @@ LOG_MODULE_REGISTER(nxp_s32_mru); #define MRU_MBOX_SIZE 4 #define MRU_CHANNEL_OFFSET 0x1000 -#define MRU_NODE(n) DT_NODELABEL(mru##n) -#define MRU_BASE(n) ((RTU_MRU_Type *)DT_REG_ADDR(MRU_NODE(n))) -#define MRU_RX_CHANNELS(n) DT_PROP_OR(MRU_NODE(n), rx_channels, 0) -#define MRU_MBOX_ADDR(n, ch, mb) \ - (DT_REG_ADDR(MRU_NODE(n)) + ((ch + 1) * MRU_CHANNEL_OFFSET) + (MRU_MBOX_SIZE * mb)) - /* Utility macros to convert from GIC index to interrupt group index */ #define _MRU_IRQ_17 MRU_IP_INT_GROUP_0 #define _MRU_IRQ_18 MRU_IP_INT_GROUP_1 #define MRU_INT_GROUP(irq) _CONCAT(_MRU_IRQ_, irq) -#define _CONCAT7(...) DT_CAT7(__VA_ARGS__) -#define MRU_ISR_FUNC(n) \ - _CONCAT7(Mru_Ip_RTU, CONFIG_NXP_S32_RTU_INDEX, _MRU, n, _Int, \ - MRU_INT_GROUP(DT_IRQN(MRU_NODE(n))), _IRQHandler) - struct nxp_s32_mru_data { mbox_callback_t cb[MRU_MAX_CHANNELS]; void *user_data[MRU_MAX_CHANNELS]; @@ -44,6 +35,7 @@ struct nxp_s32_mru_config { RTU_MRU_Type *base; Mru_Ip_ConfigType hw_cfg; void (*config_irq)(void); + uint8_t irq_group; }; static inline bool is_rx_channel_valid(const struct device *dev, uint32_t ch) @@ -178,6 +170,13 @@ static int nxp_s32_mru_init(const struct device *dev) return 0; } +void nxp_s32_mru_isr(const struct device *dev) +{ + const struct nxp_s32_mru_config *config = dev->config; + + Mru_Ip_IrqHandler(config->hw_cfg.InstanceId, config->irq_group); +} + static const struct mbox_driver_api nxp_s32_mru_driver_api = { .send = nxp_s32_mru_send, .register_callback = nxp_s32_mru_register_callback, @@ -186,18 +185,26 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { .set_enabled = nxp_s32_mru_set_enabled, }; -#define MRU_ISR_FUNC_DECLARE(n) extern void MRU_ISR_FUNC(n)(void) +#define MRU_BASE(n) ((RTU_MRU_Type *)DT_INST_REG_ADDR(n)) +#define MRU_RX_CHANNELS(n) DT_INST_PROP_OR(n, rx_channels, 0) +#define MRU_MBOX_ADDR(n, ch, mb) \ + (DT_INST_REG_ADDR(n) + ((ch + 1) * MRU_CHANNEL_OFFSET) + (MRU_MBOX_SIZE * mb)) + +#define MRU_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_MRU_##i##_BASE) ? i : 0) + +#define MRU_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET RTU_MRU_INSTANCE_COUNT, MRU_HW_INSTANCE_CHECK, (|), n) #define MRU_INIT_IRQ_FUNC(n) \ - MRU_ISR_FUNC_DECLARE(n); \ static void nxp_s32_mru_##n##_init_irq(void) \ { \ - IRQ_CONNECT(DT_IRQN(MRU_NODE(n)), \ - DT_IRQ(MRU_NODE(n), priority), \ - MRU_ISR_FUNC(n), \ - NULL, \ - DT_IRQ(MRU_NODE(n), flags)); \ - irq_enable(DT_IRQN(MRU_NODE(n))); \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + nxp_s32_mru_isr, \ + DEVICE_DT_INST_GET(n), \ + DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ } #define MRU_CH_RX_CFG(i, n) \ @@ -208,7 +215,6 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { static uint32_t nxp_s32_mru_##n##_ch_##i##_buf[MRU_MAX_MBOX_PER_CHAN]; \ static const Mru_Ip_ReceiveChannelType nxp_s32_mru_##n##_ch_##i##_rx_cfg = { \ .ChannelId = i, \ - .InstanceId = n, \ .ChannelIndex = i, \ .NumRxMB = MRU_MAX_MBOX_PER_CHAN, \ .MBAddList = nxp_s32_mru_##n##_ch_##i##_rx_mbox_addr, \ @@ -224,7 +230,7 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { #define MRU_CH_RX_LINK_CFG(i, n) \ static const Mru_Ip_MBLinkReceiveChannelType \ nxp_s32_mru_##n##_ch_##i##_rx_link_cfg[MRU_MAX_MBOX_PER_CHAN][MRU_MAX_INT_GROUPS] = {\ - MRU_CH_RX_LINK_CFG_MBOX(0, n, i, MRU_INT_GROUP(DT_IRQN(MRU_NODE(n)))) \ + MRU_CH_RX_LINK_CFG_MBOX(0, n, i, MRU_INT_GROUP(DT_INST_IRQN(n))) \ } #define MRU_CH_CFG(i, n) \ @@ -232,7 +238,7 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { .ChCFG0Add = &MRU_BASE(n)->CHXCONFIG[i].CH_CFG0, \ .ChCFG0 = RTU_MRU_CH_CFG0_IE(0) | RTU_MRU_CH_CFG0_MBE0(0), \ .ChCFG1Add = &MRU_BASE(n)->CHXCONFIG[i].CH_CFG1, \ - .ChCFG1 = RTU_MRU_CH_CFG1_MBIC0(MRU_INT_GROUP(DT_IRQN(MRU_NODE(n)))), \ + .ChCFG1 = RTU_MRU_CH_CFG1_MBIC0(MRU_INT_GROUP(DT_INST_IRQN(n))), \ .ChMBSTATAdd = &MRU_BASE(n)->CHXCONFIG[i].CH_MBSTAT, \ .NumMailbox = MRU_MAX_MBOX_PER_CHAN, \ .MBLinkReceiveChCfg = nxp_s32_mru_##n##_ch_##i##_rx_link_cfg \ @@ -242,7 +248,7 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { #define MRU_CALLBACK_WRAPPER_FUNC(n) \ void nxp_s32_mru_##n##_cb(uint8_t channel, const uint32_t *buf, uint8_t mbox_count) \ { \ - const struct device *dev = DEVICE_DT_GET(MRU_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ struct nxp_s32_mru_data *data = dev->data; \ \ if (is_rx_channel_valid(dev, channel)) { \ @@ -271,7 +277,7 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { static struct nxp_s32_mru_config nxp_s32_mru_##n##_config = { \ .base = MRU_BASE(n), \ .hw_cfg = { \ - .InstanceId = n, \ + .InstanceId = MRU_HW_INSTANCE(n), \ .StateIndex = n, \ .NumChannel = MRU_RX_CHANNELS(n), \ .ChannelCfg = COND_CODE_0(MRU_RX_CHANNELS(n), \ @@ -281,43 +287,14 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { &MRU_BASE(n)->NOTIFY1 \ }, \ }, \ + .irq_group = MRU_INT_GROUP(DT_INST_IRQN(n)), \ .config_irq = COND_CODE_0(MRU_RX_CHANNELS(n), \ (NULL), (nxp_s32_mru_##n##_init_irq)), \ }; \ \ - DEVICE_DT_DEFINE(MRU_NODE(n), nxp_s32_mru_init, NULL, \ + DEVICE_DT_INST_DEFINE(n, nxp_s32_mru_init, NULL, \ &nxp_s32_mru_##n##_data, &nxp_s32_mru_##n##_config, \ POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \ - &nxp_s32_mru_driver_api) - -#if DT_NODE_HAS_STATUS(MRU_NODE(0), okay) -MRU_INSTANCE_DEFINE(0); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(1), okay) -MRU_INSTANCE_DEFINE(1); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(2), okay) -MRU_INSTANCE_DEFINE(2); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(3), okay) -MRU_INSTANCE_DEFINE(3); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(4), okay) -MRU_INSTANCE_DEFINE(4); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(5), okay) -MRU_INSTANCE_DEFINE(5); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(6), okay) -MRU_INSTANCE_DEFINE(6); -#endif + &nxp_s32_mru_driver_api); -#if DT_NODE_HAS_STATUS(MRU_NODE(7), okay) -MRU_INSTANCE_DEFINE(7); -#endif +DT_INST_FOREACH_STATUS_OKAY(MRU_INSTANCE_DEFINE) diff --git a/soc/arm/nxp_s32/s32ze/soc.h b/soc/arm/nxp_s32/s32ze/soc.h index 17289511f7dfe6d..1a3ea6311733855 100644 --- a/soc/arm/nxp_s32/s32ze/soc.h +++ b/soc/arm/nxp_s32/s32ze/soc.h @@ -51,4 +51,14 @@ /* NETC */ #define IP_NETC_EMDIO_0_BASE IP_NETC__EMDIO_BASE_BASE +/* MRU */ +#define IP_MRU_0_BASE IP_RTU0__MRU_0_BASE +#define IP_MRU_1_BASE IP_RTU0__MRU_1_BASE +#define IP_MRU_2_BASE IP_RTU0__MRU_2_BASE +#define IP_MRU_3_BASE IP_RTU0__MRU_3_BASE +#define IP_MRU_4_BASE IP_RTU1__MRU_0_BASE +#define IP_MRU_5_BASE IP_RTU1__MRU_1_BASE +#define IP_MRU_6_BASE IP_RTU1__MRU_2_BASE +#define IP_MRU_7_BASE IP_RTU1__MRU_3_BASE + #endif /* _NXP_S32_S32ZE_SOC_H_ */ From c9e6ac54d63875bfd463cf8f1eb3d3710de141a4 Mon Sep 17 00:00:00 2001 From: Charles Dias Date: Sat, 11 Nov 2023 11:05:09 -0300 Subject: [PATCH 0310/1049] samples: maxim_ds3231: increase variable size in min_alarm_handler Change the variable name from **us** to **ms** and increase its size to **uint16_t** within the min_alarm_handler function. This update allows the function to correctly handle the millisecond values in the range of 0 to 999. Signed-off-by: Charles Dias --- samples/drivers/counter/maxim_ds3231/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/drivers/counter/maxim_ds3231/src/main.c b/samples/drivers/counter/maxim_ds3231/src/main.c index 32c37c17188bc65..992283ef3439c5e 100644 --- a/samples/drivers/counter/maxim_ds3231/src/main.c +++ b/samples/drivers/counter/maxim_ds3231/src/main.c @@ -105,7 +105,7 @@ static void min_alarm_handler(const struct device *dev, (void)counter_get_value(dev, &time); uint32_t uptime = k_uptime_get_32(); - uint8_t us = uptime % 1000U; + uint16_t ms = uptime % 1000U; uptime /= 1000U; uint8_t se = uptime % 60U; @@ -143,7 +143,7 @@ static void min_alarm_handler(const struct device *dev, printk("%s: adj %d.%09lu, uptime %u:%02u:%02u.%03u, clk err %d ppm\n", format_time(time, -1), (uint32_t)(ts->tv_sec - time), ts->tv_nsec, - hr, mn, se, us, err_ppm); + hr, mn, se, ms, err_ppm); } struct maxim_ds3231_alarm sec_alarm; From 56dd8f90cd4d49c3bef04d3176fc83cb29e85752 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 31 Oct 2023 16:29:23 +0100 Subject: [PATCH 0311/1049] tests: drivers: i2c: i2c_target_api add stm32f3_disco Adds stm32f3_disco in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- tests/drivers/i2c/i2c_target_api/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index a61139862746943..fe3531dde651df6 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -14,6 +14,7 @@ tests: - nucleo_g474re - nucleo_f091rc - stm32f072b_disco + - stm32f3_disco - nucleo_g071rb - nucleo_f207zg - nucleo_f429zi From c19ba8ffe9e9d5becd12ae14f568bf9c4c543ef0 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 31 Oct 2023 16:31:48 +0100 Subject: [PATCH 0312/1049] tests: drivers: i2c: i2c_target_api add stm32f3_disco Adds necessary overlay stm32f3_disco in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- .../i2c_target_api/boards/stm32f3_disco.conf | 2 ++ .../boards/stm32f3_disco.overlay | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/stm32f3_disco.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/stm32f3_disco.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/stm32f3_disco.conf b/tests/drivers/i2c/i2c_target_api/boards/stm32f3_disco.conf new file mode 100644 index 000000000000000..34b2571d125164b --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/stm32f3_disco.conf @@ -0,0 +1,2 @@ +CONFIG_I2C_STM32_INTERRUPT=y +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/stm32f3_disco.overlay b/tests/drivers/i2c/i2c_target_api/boards/stm32f3_disco.overlay new file mode 100644 index 000000000000000..b23520b04acbcb4 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/stm32f3_disco.overlay @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* I2C bus pins are exposed on the ST P2 connector. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PB7 P2:21 PB6 P2:22 + * i2c2 PA10 P2:43 PA9 P2:44 + * + * Short Pin PB7 to PA10, and PB6 to PA9, for the test to pass. + */ + + + +&i2c1 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&i2c2 { + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; + +}; From 04e18f093fde6ed2671f52c3f373edf546259783 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Fri, 10 Nov 2023 13:19:07 +0000 Subject: [PATCH 0313/1049] drivers: regulator: Added startup and off/on delay to common driver A configurable delay during regulator switch on is currently only supported by the GPIO and fixed regulator drivers. This functionality has been moved to the common driver, so it can be easily added to any regulator driver. Signed-off-by: Andy Sinclair --- drivers/regulator/regulator_common.c | 22 ++++++++++++++----- drivers/regulator/regulator_fixed.c | 15 ------------- drivers/regulator/regulator_gpio.c | 11 ---------- .../regulator/nordic,npm1300-regulator.yaml | 2 ++ dts/bindings/regulator/regulator-fixed.yaml | 12 ++-------- dts/bindings/regulator/regulator-gpio.yaml | 5 +---- dts/bindings/regulator/regulator.yaml | 8 +++++++ include/zephyr/drivers/regulator.h | 6 +++++ 8 files changed, 36 insertions(+), 45 deletions(-) diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index adbacddac1205cc..7f33040d2d91ab8 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -3,8 +3,20 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include +static void regulator_delay(uint32_t delay_us) +{ + if (delay_us > 0U) { +#ifdef CONFIG_MULTITHREADING + k_sleep(K_USEC(delay_us)); +#else + k_busy_wait(delay_us); +#endif + } +} + void regulator_common_data_init(const struct device *dev) { struct regulator_common_data *data = dev->data; @@ -67,6 +79,7 @@ int regulator_common_init(const struct device *dev, bool is_enabled) return ret; } + regulator_delay(config->startup_delay_us); data->refcnt++; } @@ -94,12 +107,11 @@ int regulator_enable(const struct device *dev) (void)k_mutex_lock(&data->lock, K_FOREVER); #endif - data->refcnt++; - - if (data->refcnt == 1) { + if (data->refcnt == 0) { ret = api->enable(dev); - if (ret < 0) { - data->refcnt--; + if (ret == 0) { + data->refcnt++; + regulator_delay(config->off_on_delay_us); } } diff --git a/drivers/regulator/regulator_fixed.c b/drivers/regulator/regulator_fixed.c index 4526b6d2378e52c..c0b58273987a530 100644 --- a/drivers/regulator/regulator_fixed.c +++ b/drivers/regulator/regulator_fixed.c @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -18,8 +17,6 @@ LOG_MODULE_REGISTER(regulator_fixed, CONFIG_REGULATOR_LOG_LEVEL); struct regulator_fixed_config { struct regulator_common_config common; - uint32_t startup_delay_us; - uint32_t off_on_delay_us; struct gpio_dt_spec enable; }; @@ -41,14 +38,6 @@ static int regulator_fixed_enable(const struct device *dev) return ret; } - if (cfg->off_on_delay_us > 0U) { -#ifdef CONFIG_MULTITHREADING - k_sleep(K_USEC(cfg->off_on_delay_us)); -#else - k_busy_wait(cfg->off_on_delay_us); -#endif - } - return 0; } @@ -113,8 +102,6 @@ static int regulator_fixed_init(const struct device *dev) if (ret < 0) { return ret; } - - k_busy_wait(cfg->startup_delay_us); } else { ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); if (ret < 0) { @@ -134,8 +121,6 @@ static int regulator_fixed_init(const struct device *dev) \ static const struct regulator_fixed_config config##inst = { \ .common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(inst), \ - .startup_delay_us = DT_INST_PROP(inst, startup_delay_us), \ - .off_on_delay_us = DT_INST_PROP(inst, off_on_delay_us), \ .enable = GPIO_DT_SPEC_INST_GET_OR(inst, enable_gpios, {0}), \ }; \ \ diff --git a/drivers/regulator/regulator_gpio.c b/drivers/regulator/regulator_gpio.c index e752a9ad45750bd..49d373897b38eb3 100644 --- a/drivers/regulator/regulator_gpio.c +++ b/drivers/regulator/regulator_gpio.c @@ -7,7 +7,6 @@ #include -#include #include #include #include @@ -24,7 +23,6 @@ struct regulator_gpio_config { uint8_t states_cnt; const struct gpio_dt_spec enable; - int32_t startup_delay_us; }; struct regulator_gpio_data { @@ -73,14 +71,6 @@ static int regulator_gpio_enable(const struct device *dev) return ret; } - if (cfg->startup_delay_us > 0U) { -#ifdef CONFIG_MULTITHREADING - k_sleep(K_USEC(cfg->startup_delay_us)); -#else - k_busy_wait(cfg->startup_delay_us); -#endif - } - return 0; } @@ -233,7 +223,6 @@ static int regulator_gpio_init(const struct device *dev) .enable = GPIO_DT_SPEC_INST_GET_OR(inst, enable_gpios, {0}), \ .states = ((const int[])DT_INST_PROP(inst, states)), \ .states_cnt = DT_INST_PROP_LEN(inst, states) / 2, \ - .startup_delay_us = DT_INST_PROP_OR(inst, startup_delay_us, 0), \ }; \ DEVICE_DT_INST_DEFINE(inst, regulator_gpio_init, NULL, &data##inst, &config##inst, \ POST_KERNEL, CONFIG_REGULATOR_GPIO_INIT_PRIORITY, \ diff --git a/dts/bindings/regulator/nordic,npm1300-regulator.yaml b/dts/bindings/regulator/nordic,npm1300-regulator.yaml index cbd62671f15b918..c5364a49fe0dd70 100644 --- a/dts/bindings/regulator/nordic,npm1300-regulator.yaml +++ b/dts/bindings/regulator/nordic,npm1300-regulator.yaml @@ -60,6 +60,8 @@ child-binding: - regulator-initial-mode - regulator-min-microamp - regulator-max-microamp + - startup-delay-us + - off-on-delay-us properties: retention-microvolt: diff --git a/dts/bindings/regulator/regulator-fixed.yaml b/dts/bindings/regulator/regulator-fixed.yaml index 1033d333f08d17f..4f3236d8c6cb26f 100644 --- a/dts/bindings/regulator/regulator-fixed.yaml +++ b/dts/bindings/regulator/regulator-fixed.yaml @@ -13,6 +13,8 @@ include: - regulator-always-on - regulator-min-microvolt - regulator-max-microvolt + - startup-delay-us + - off-on-delay-us compatible: "regulator-fixed" @@ -29,13 +31,3 @@ properties: provide the GPIO polarity and open-drain status in the phandle selector. The Linux enable-active-high and gpio-open-drain properties are not valid for Zephyr devicetree files. - - startup-delay-us: - type: int - default: 0 - description: Startup time, in microseconds - - off-on-delay-us: - type: int - default: 0 - description: Off delay time, in microseconds diff --git a/dts/bindings/regulator/regulator-gpio.yaml b/dts/bindings/regulator/regulator-gpio.yaml index aa7aeb44eeeee6e..15c419a0043a8b1 100644 --- a/dts/bindings/regulator/regulator-gpio.yaml +++ b/dts/bindings/regulator/regulator-gpio.yaml @@ -34,6 +34,7 @@ include: - regulator-max-microvolt - regulator-always-on - regulator-boot-on + - startup-delay-us compatible: "regulator-gpio" @@ -70,7 +71,3 @@ properties: Example: enable-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>; - - startup-delay-us: - type: int - description: startup time in microseconds diff --git a/dts/bindings/regulator/regulator.yaml b/dts/bindings/regulator/regulator.yaml index 067133aa97e2672..167355d92245b2d 100644 --- a/dts/bindings/regulator/regulator.yaml +++ b/dts/bindings/regulator/regulator.yaml @@ -256,3 +256,11 @@ properties: description: | Maximum difference between current and target voltages that can be changed safely in a single step. + + startup-delay-us: + type: int + description: Startup time, in microseconds + + off-on-delay-us: + type: int + description: Off to on delay time, in microseconds diff --git a/include/zephyr/drivers/regulator.h b/include/zephyr/drivers/regulator.h index 77dd6d76b601c25..bad9de28239fd0e 100644 --- a/include/zephyr/drivers/regulator.h +++ b/include/zephyr/drivers/regulator.h @@ -140,6 +140,10 @@ struct regulator_common_config { int32_t min_ua; /** Maximum allowed current, in microamps. */ int32_t max_ua; + /** Startup delay, in microseconds. */ + uint32_t startup_delay_us; + /** Off to on delay, in microseconds. */ + uint32_t off_on_delay_us; /** Allowed modes */ const regulator_mode_t *allowed_modes; /** Number of allowed modes */ @@ -167,6 +171,8 @@ struct regulator_common_config { INT32_MIN), \ .max_ua = DT_PROP_OR(node_id, regulator_max_microamp, \ INT32_MAX), \ + .startup_delay_us = DT_PROP_OR(node_id, startup_delay_us, 0), \ + .off_on_delay_us = DT_PROP_OR(node_id, off_on_delay_us, 0), \ .allowed_modes = (const regulator_mode_t []) \ DT_PROP_OR(node_id, regulator_allowed_modes, {}), \ .allowed_modes_cnt = \ From 6de2900eec7ebb7d897c9d6dc388a5080d94b45d Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Mon, 30 Oct 2023 10:15:22 +0100 Subject: [PATCH 0314/1049] boards: arm: b_u585i_iot02a: add i2c Adds i2c on b_u585i_iot02a to use the i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml index 9faefebf0bcd874..27ba601cae56dbb 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml @@ -22,4 +22,5 @@ supported: - backup_sram - pwm - counter + - i2c vendor: st From 619d2fd887ca0c5492a3da2e3d352e59b4821fdc Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Mon, 30 Oct 2023 10:19:36 +0100 Subject: [PATCH 0315/1049] tests: drivers: i2c: i2c_target_api add b_u585i_iot02a Adds b_u585i_iot02a in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- tests/drivers/i2c/i2c_target_api/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index fe3531dde651df6..3254e3d74f2d235 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -10,6 +10,7 @@ common: tests: drivers.i2c.target_api.dual_role: platform_allow: + - b_u585i_iot02a - nucleo_f746zg - nucleo_g474re - nucleo_f091rc From c1a6cfdf9bd8c3aa1f5af589f5181ec5dfefe3af Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Mon, 30 Oct 2023 10:21:48 +0100 Subject: [PATCH 0316/1049] tests: drivers: i2c: i2c_target_api add b_u585i_iot02a Adds necessary overlay b_u585i_iot02a in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- .../i2c_target_api/boards/b_u585i_iot02a.conf | 2 ++ .../boards/b_u585i_iot02a.overlay | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.conf b/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.conf new file mode 100644 index 000000000000000..34b2571d125164b --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.conf @@ -0,0 +1,2 @@ +CONFIG_I2C_STM32_INTERRUPT=y +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.overlay b/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.overlay new file mode 100644 index 000000000000000..f07d43230e90906 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.overlay @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* I2C bus pins are exposed on the STMod+. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PB9 CN3:10 PB8 CN3:7 + * i2c2 PH5 CN2:10 PH4 CN2:7 + * + * Short Pin PB9 to PH5, and PB8 to PH4, for the test to pass. + */ + +&i2c1 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&i2c2 { + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; From aa0b8af577e390ce3b4ea6a8365b0cbabb16693e Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 27 Oct 2023 22:25:49 +0000 Subject: [PATCH 0317/1049] drivers: dma: mcux_mcux_lpc: support hardware triggering The LPC DMA IP offers hardware triggering via a series of SOC-specific signals, often including sources like GPIO pins or hardware timers. Support hardware triggers via the "dma_slot" field of the DMA configuration structure. Currently support is offered for setting the following: - Trigger polarity - Trigger level/edge mode - burst mode - burst length - peripheral request Signed-off-by: Daniel DeGrasse --- drivers/dma/dma_mcux_lpc.c | 26 ++++++++++- include/zephyr/drivers/dma/dma_mcux_lpc.h | 56 +++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 include/zephyr/drivers/dma/dma_mcux_lpc.h diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index eb44d4fb5fca174..cd45211e678ab5c 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -18,6 +18,7 @@ #include #include #include +#include #define DT_DRV_COMPAT nxp_lpc_dma @@ -554,7 +555,30 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, data->descriptors_queued = true; } - if (is_periph) { + if (config->dma_slot) { + uint32_t cfg_reg = 0; + + /* User supplied manual trigger configuration */ + if (config->dma_slot & LPC_DMA_PERIPH_REQ_EN) { + cfg_reg |= DMA_CHANNEL_CFG_PERIPHREQEN_MASK; + } + if (config->dma_slot & LPC_DMA_HWTRIG_EN) { + /* Setup hardware trigger */ + cfg_reg |= DMA_CHANNEL_CFG_HWTRIGEN_MASK; + if (config->dma_slot & LPC_DMA_TRIGTYPE_LEVEL) { + cfg_reg |= DMA_CHANNEL_CFG_TRIGTYPE_MASK; + } + if (config->dma_slot & LPC_DMA_TRIGPOL_HIGH_RISING) { + cfg_reg |= DMA_CHANNEL_CFG_TRIGPOL_MASK; + } + if (config->dma_slot & LPC_DMA_TRIGBURST) { + cfg_reg |= DMA_CHANNEL_CFG_TRIGBURST_MASK; + cfg_reg |= DMA_CHANNEL_CFG_BURSTPOWER( + LPC_DMA_GET_BURSTPOWER(config->dma_slot)); + } + } + p_handle->base->CHANNEL[p_handle->channel].CFG = cfg_reg; + } else if (is_periph) { DMA_EnableChannelPeriphRq(p_handle->base, p_handle->channel); } else { DMA_DisableChannelPeriphRq(p_handle->base, p_handle->channel); diff --git a/include/zephyr/drivers/dma/dma_mcux_lpc.h b/include/zephyr/drivers/dma/dma_mcux_lpc.h new file mode 100644 index 000000000000000..5bae1f8f39e920c --- /dev/null +++ b/include/zephyr/drivers/dma/dma_mcux_lpc.h @@ -0,0 +1,56 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_DMA_DMA_MCUX_LPC_H_ +#define ZEPHYR_INCLUDE_DRIVERS_DMA_DMA_MCUX_LPC_H_ + +/* + * LPC DMA engine channel hardware trigger attributes. + * These attributes can be set to the "dma_slot" field + * in a dma_config structure to configure a channel for + * hardware triggering. + */ + +/* Peripheral request enable. When set, the peripheral + * request line associated with this channel is used to pace DMA transfers. + */ +#define LPC_DMA_PERIPH_REQ_EN BIT(0) + +/* Hardware trigger enable. When set, the hardware trigger connected to this + * channel via INPUTMUX can be used to trigger a transfer + */ +#define LPC_DMA_HWTRIG_EN BIT(1) + +/* HW trigger polarity. When this bit is set, the trigger will be active + * high or rising edge triggered, based on TRIG_TYPE selection + */ +#define LPC_DMA_TRIGPOL_HIGH_RISING BIT(2) + +/* HW trigger type. When this bit is set, the trigger will be level triggered. + * When it is cleared, the hardware trigger will be edge triggered. + */ +#define LPC_DMA_TRIGTYPE_LEVEL BIT(3) + +/* HW trigger burst mode. When set, the hardware trigger will cause a burst + * transfer to occur, the length of which is determined by BURST_POWER. + * When cleared, a single transfer (of the width selected by XFERCFG register) + * will occur. + */ +#define LPC_DMA_TRIGBURST BIT(4) + +/* HW trigger burst power. Note that due to the size limit of the dma_slot + * field, the maximum transfer burst possible is 128. The hardware supports + * up to 1024 transfers in BURSTPOWER. The value set here will result in + * 2^BURSTPOWER transfers occurring. So for BURSTPOWER=3, 8 transfers would + * occur. + */ +#define LPC_DMA_BURSTPOWER(pwr) (((pwr) & 0x7) << 5) + + +/* Used by driver to extract burstpower setting */ +#define LPC_DMA_GET_BURSTPOWER(slot) (((slot) & 0xE0) >> 5) + +#endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_DMA_MCUX_LPC_H_ */ From 3548ffe053992e268008f817ddd57d8cdc863378 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Mon, 30 Oct 2023 16:12:35 +0100 Subject: [PATCH 0318/1049] tests: drivers: i2c: i2c_target_api add nucleo_wb55rg Adds nucleo_wb55rg in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- tests/drivers/i2c/i2c_target_api/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index 3254e3d74f2d235..d3c5a4084956bee 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -22,6 +22,7 @@ tests: - nucleo_wl55jc - nucleo_l073rz - nucleo_l152re + - nucleo_wb55rg - rpi_pico - efr32bg22_brd4184a - mr_canhubk3 From 32e1d06a3ccca4149616e824314c235519ed90c5 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Mon, 30 Oct 2023 16:15:18 +0100 Subject: [PATCH 0319/1049] tests: drivers: i2c: i2c_target_api add nucleo_wb55rg Adds necessary overlay nucleo_wb55rg in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- .../i2c_target_api/boards/nucleo_wb55rg.conf | 2 ++ .../boards/nucleo_wb55rg.overlay | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_wb55rg.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_wb55rg.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_wb55rg.conf b/tests/drivers/i2c/i2c_target_api/boards/nucleo_wb55rg.conf new file mode 100644 index 000000000000000..34b2571d125164b --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_wb55rg.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_wb55rg.overlay b/tests/drivers/i2c/i2c_target_api/boards/nucleo_wb55rg.overlay new file mode 100644 index 000000000000000..121265cad7c626c --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_wb55rg.overlay @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* I2C bus pins are exposed on the Arduino Shield Connectors and Morpho connectors. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PB9 CN5:9 PB8 CN5:10 + * i2c3 PA7 CN5:4 PB14 CN10:28 + * + * Short Pin PB9 to PA7, and PB8 to PB14, for the test to pass. + */ + +&i2c1 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&i2c3 { + pinctrl-0 = <&i2c3_scl_pa7 &i2c3_sda_pb14>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; From 4fe2605160fd535980924a7ea09080c5984fe896 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Sun, 9 Apr 2023 08:47:13 +1200 Subject: [PATCH 0320/1049] drivers: serial: Fix pinctrl usage in NS16550 driver pinctrl-0 property should not be directly referenced in this driver Signed-off-by: Grant Ramsay --- drivers/serial/uart_ns16550.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 5adf0eca6452073..a41cdca784341f0 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -1371,8 +1371,8 @@ static const struct uart_driver_api uart_ns16550_driver_api = { IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pcp), \ (.pcp = DT_INST_PROP_OR(n, pcp, 0),)) \ .reg_interval = (1 << DT_INST_PROP(n, reg_shift)), \ - IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ - (.pincfg = PINCTRL_DT_DEV_CONFIG_GET(DT_DRV_INST(n)),)) \ + IF_ENABLED(CONFIG_PINCTRL, \ + (.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),)) \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, resets), \ (.reset_spec = RESET_DT_SPEC_INST_GET(n),)) @@ -1390,8 +1390,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #define UART_NS16550_DEVICE_IO_MMIO_INIT(n) \ UART_NS16550_IRQ_FUNC_DECLARE(n); \ - IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ - (PINCTRL_DT_INST_DEFINE(n))); \ + IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(n))); \ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \ COND_CODE_1(DT_INST_PROP_OR(n, io_mapped, 0), \ (.port = DT_INST_REG_ADDR(n),), \ @@ -1413,8 +1412,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #define UART_NS16550_DEVICE_PCIE_INIT(n) \ UART_NS16550_PCIE_IRQ_FUNC_DECLARE(n); \ DEVICE_PCIE_INST_DECLARE(n); \ - IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ - (PINCTRL_DT_INST_DEFINE(n))); \ + IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(n))); \ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \ UART_NS16550_COMMON_DEV_CFG_INITIALIZER(n) \ DEV_CONFIG_PCIE_IRQ_FUNC_INIT(n) \ From 327f75ec3554603c54ed2c6484975dbf2f986f4c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 13:51:02 +0100 Subject: [PATCH 0321/1049] tests/bluetooth/tester: Enable in native_sim Enable this test in the native_sim target. Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/tester/boards/native_sim.conf | 3 +++ tests/bluetooth/tester/testcase.yaml | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 tests/bluetooth/tester/boards/native_sim.conf diff --git a/tests/bluetooth/tester/boards/native_sim.conf b/tests/bluetooth/tester/boards/native_sim.conf new file mode 100644 index 000000000000000..30abfdbc3d9f156 --- /dev/null +++ b/tests/bluetooth/tester/boards/native_sim.conf @@ -0,0 +1,3 @@ +CONFIG_UART_PIPE=n +CONFIG_SERIAL=y +CONFIG_UART_NATIVE_POSIX=y diff --git a/tests/bluetooth/tester/testcase.yaml b/tests/bluetooth/tester/testcase.yaml index dba67716af16ace..8c36291b30f7df1 100644 --- a/tests/bluetooth/tester/testcase.yaml +++ b/tests/bluetooth/tester/testcase.yaml @@ -4,6 +4,7 @@ tests: platform_allow: - qemu_x86 - native_posix + - native_sim - nrf52840dk_nrf52840 tags: bluetooth harness: bluetooth @@ -12,6 +13,7 @@ tests: platform_allow: - qemu_x86 - native_posix + - native_sim - nrf5340dk_nrf5340_cpuapp extra_args: OVERLAY_CONFIG="overlay-le-audio.conf" tags: bluetooth @@ -21,6 +23,7 @@ tests: platform_allow: - qemu_x86 - native_posix + - native_sim - nrf52840dk_nrf52840 extra_args: OVERLAY_CONFIG="overlay-mesh.conf" tags: bluetooth @@ -30,6 +33,7 @@ tests: platform_allow: - qemu_x86 - native_posix + - native_sim - nrf52840dk_nrf52840 extra_args: OVERLAY_CONFIG="overlay-mesh.conf;overlay-mesh-v1d1.conf" tags: bluetooth From e444f495406d34f29f4d37305f9d0266e73ff17a Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 13:56:26 +0100 Subject: [PATCH 0322/1049] samples/bluetooth/hap_ha: Enable in native_sim Enable this test in the native_sim target Signed-off-by: Alberto Escolar Piedras --- samples/bluetooth/hap_ha/boards/native_sim.conf | 7 +++++++ samples/bluetooth/hap_ha/sample.yaml | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 samples/bluetooth/hap_ha/boards/native_sim.conf diff --git a/samples/bluetooth/hap_ha/boards/native_sim.conf b/samples/bluetooth/hap_ha/boards/native_sim.conf new file mode 100644 index 000000000000000..abce1c1111e5db2 --- /dev/null +++ b/samples/bluetooth/hap_ha/boards/native_sim.conf @@ -0,0 +1,7 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/hap_ha/sample.yaml b/samples/bluetooth/hap_ha/sample.yaml index c9fcfda90ca22db..3b0fcd53a51cdb7 100644 --- a/samples/bluetooth/hap_ha/sample.yaml +++ b/samples/bluetooth/hap_ha/sample.yaml @@ -4,25 +4,33 @@ sample: tests: sample.bluetooth.hap_ha.monaural: harness: bluetooth - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: bluetooth build_only: true sample.bluetooth.hap_ha.monaural_no_presets: harness: bluetooth - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: bluetooth build_only: true extra_configs: - CONFIG_BT_HAS_PRESET_COUNT=0 sample.bluetooth.hap_ha.banded: harness: bluetooth - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: bluetooth extra_args: OVERLAY_CONFIG="banded.conf" build_only: true sample.bluetooth.hap_ha.binaural: harness: bluetooth - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: bluetooth extra_args: OVERLAY_CONFIG="binaural.conf" build_only: true From 49bccb58392ce2780e9d36d04f14edd883b91481 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 14:11:26 +0100 Subject: [PATCH 0323/1049] samples/bluetooth/tmap*: Enable in native_sim Let's enable these samples in the native_sim target. Signed-off-by: Alberto Escolar Piedras --- samples/bluetooth/tmap_bmr/boards/native_sim.conf | 10 ++++++++++ samples/bluetooth/tmap_bmr/sample.yaml | 5 ++++- samples/bluetooth/tmap_bms/boards/native_sim.conf | 10 ++++++++++ samples/bluetooth/tmap_bms/sample.yaml | 5 ++++- samples/bluetooth/tmap_central/boards/native_sim.conf | 10 ++++++++++ samples/bluetooth/tmap_central/sample.yaml | 5 ++++- .../bluetooth/tmap_peripheral/boards/native_sim.conf | 10 ++++++++++ samples/bluetooth/tmap_peripheral/sample.yaml | 10 ++++++++-- 8 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 samples/bluetooth/tmap_bmr/boards/native_sim.conf create mode 100644 samples/bluetooth/tmap_bms/boards/native_sim.conf create mode 100644 samples/bluetooth/tmap_central/boards/native_sim.conf create mode 100644 samples/bluetooth/tmap_peripheral/boards/native_sim.conf diff --git a/samples/bluetooth/tmap_bmr/boards/native_sim.conf b/samples/bluetooth/tmap_bmr/boards/native_sim.conf new file mode 100644 index 000000000000000..e06b29993819415 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/boards/native_sim.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_bmr/sample.yaml b/samples/bluetooth/tmap_bmr/sample.yaml index 2427ef9ca823274..aaaa52961492cf7 100644 --- a/samples/bluetooth/tmap_bmr/sample.yaml +++ b/samples/bluetooth/tmap_bmr/sample.yaml @@ -4,7 +4,10 @@ sample: tests: sample.bluetooth.tmap_bmr: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth integration_platforms: - qemu_cortex_m3 diff --git a/samples/bluetooth/tmap_bms/boards/native_sim.conf b/samples/bluetooth/tmap_bms/boards/native_sim.conf new file mode 100644 index 000000000000000..e06b29993819415 --- /dev/null +++ b/samples/bluetooth/tmap_bms/boards/native_sim.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_bms/sample.yaml b/samples/bluetooth/tmap_bms/sample.yaml index 83bdc86a9a2dd01..fc4410eac0eca98 100644 --- a/samples/bluetooth/tmap_bms/sample.yaml +++ b/samples/bluetooth/tmap_bms/sample.yaml @@ -4,7 +4,10 @@ sample: tests: sample.bluetooth.tmap_bms: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth integration_platforms: - qemu_cortex_m3 diff --git a/samples/bluetooth/tmap_central/boards/native_sim.conf b/samples/bluetooth/tmap_central/boards/native_sim.conf new file mode 100644 index 000000000000000..e06b29993819415 --- /dev/null +++ b/samples/bluetooth/tmap_central/boards/native_sim.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_central/sample.yaml b/samples/bluetooth/tmap_central/sample.yaml index 3d0e1e8a08b16aa..cf4dd36293843a6 100644 --- a/samples/bluetooth/tmap_central/sample.yaml +++ b/samples/bluetooth/tmap_central/sample.yaml @@ -4,7 +4,10 @@ sample: tests: sample.bluetooth.tmap_central: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth integration_platforms: - qemu_cortex_m3 diff --git a/samples/bluetooth/tmap_peripheral/boards/native_sim.conf b/samples/bluetooth/tmap_peripheral/boards/native_sim.conf new file mode 100644 index 000000000000000..e06b29993819415 --- /dev/null +++ b/samples/bluetooth/tmap_peripheral/boards/native_sim.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_peripheral/sample.yaml b/samples/bluetooth/tmap_peripheral/sample.yaml index 69f399c5b23866a..a27626359685c7f 100644 --- a/samples/bluetooth/tmap_peripheral/sample.yaml +++ b/samples/bluetooth/tmap_peripheral/sample.yaml @@ -4,13 +4,19 @@ sample: tests: sample.bluetooth.tmap_peripheral: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth integration_platforms: - qemu_cortex_m3 sample.bluetooth.tmap_peripheral.duo: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth extra_args: OVERLAY_CONFIG="duo.conf" extra_configs: From d427169845e6c2b46266965da0d8b732fdfb7576 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 10:48:15 +0100 Subject: [PATCH 0324/1049] docs: bluetooth: Replace reference to native_posix w native_sim Let's replace the references to native_posix with native_sim, Background: during this release native_sim is replacing native_posix as the main host test/development platform. Signed-off-by: Alberto Escolar Piedras --- .../bluetooth/autopts/autopts-linux.rst | 8 +++---- doc/connectivity/bluetooth/bluetooth-dev.rst | 16 ++++++------- .../bluetooth/bluetooth-tools.rst | 24 +++++++++---------- samples/bluetooth/bluetooth.rst | 4 ++-- samples/bluetooth/hci_uart/README.rst | 8 +++---- samples/bluetooth/hci_uart_async/README.rst | 8 +++---- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/doc/connectivity/bluetooth/autopts/autopts-linux.rst b/doc/connectivity/bluetooth/autopts/autopts-linux.rst index 6388673f0256b07..eac940e97378995 100644 --- a/doc/connectivity/bluetooth/autopts/autopts-linux.rst +++ b/doc/connectivity/bluetooth/autopts/autopts-linux.rst @@ -16,11 +16,11 @@ Supported methods to test zephyr bluetooth host: - Testing Zephyr Host Stack on QEMU -- Testing Zephyr Host Stack on native posix +- Testing Zephyr Host Stack on :ref:`native_sim ` - Testing Zephyr combined (controller + host) build on Real hardware (such as nRF52) -For running with QEMU or native posix, see :ref:`bluetooth_qemu_posix`. +For running with QEMU or :ref:`native_sim `, see :ref:`bluetooth_qemu_native`. Setup Linux =========================== @@ -293,14 +293,14 @@ Testing Zephyr Host Stack on QEMU: ~/zephyrproject/build/zephyr/zephyr.elf -i SERVER_IP -l LOCAL_IP -Testing Zephyr Host Stack on native posix: +Testing Zephyr Host Stack on :ref:`native_sim `: .. code-block:: # A Bluetooth controller needs to be mounted. # For running with HCI UART, please visit: https://docs.zephyrproject.org/latest/samples/bluetooth/hci_uart/README.html#bluetooth-hci-uart - west build -b native_posix zephyr/tests/bluetooth/tester/ -DEXTRA_CONF_FILE=overlay-native.conf + west build -b native_sim zephyr/tests/bluetooth/tester/ -DEXTRA_CONF_FILE=overlay-native.conf sudo python ./autoptsclient-zephyr.py "C:\Users\USER_NAME\Documents\Profile Tuning Suite\PTS_PROJECT\PTS_PROJECT.pqw6" \ ~/zephyrproject/build/zephyr/zephyr.exe -i SERVER_IP -l LOCAL_IP --hci 0 diff --git a/doc/connectivity/bluetooth/bluetooth-dev.rst b/doc/connectivity/bluetooth/bluetooth-dev.rst index dd3c2058c2cde93..49daefe43b90834 100644 --- a/doc/connectivity/bluetooth/bluetooth-dev.rst +++ b/doc/connectivity/bluetooth/bluetooth-dev.rst @@ -33,7 +33,7 @@ There are 4 possible hardware setups to use with Zephyr and Bluetooth: #. Embedded #. QEMU with an external Controller -#. Native POSIX with an external Controller +#. :ref:`native_sim ` with an external Controller #. Simulated nRF52 with BabbleSim Embedded @@ -90,7 +90,7 @@ This setup relies on a "dual-chip" :ref:`configuration ` which is comprised of the following devices: #. A :ref:`Host-only ` application running in the - :ref:`QEMU ` emulator or the ``native_posix`` native + :ref:`QEMU ` emulator or the :ref:`native_sim ` native port of Zephyr #. A Controller, which can be one of the following types: @@ -117,23 +117,23 @@ QEMU You can run the Zephyr Host on the :ref:`QEMU emulator` and have it interact with a physical external Bluetooth Controller. -Refer to :ref:`bluetooth_qemu_posix` for full instructions on how to build and +Refer to :ref:`bluetooth_qemu_native` for full instructions on how to build and run an application in this setup. -Native POSIX ------------- +native_sim +---------- .. note:: This is currently only available on GNU/Linux -The :ref:`Native POSIX ` target builds your Zephyr application +The :ref:`native_sim ` target builds your Zephyr application with the Zephyr kernel, and some minimal HW emulation as a native Linux executable. This executable is a normal Linux program, which can be debugged and instrumented like any other, and it communicates with a physical or virtual external Controller. -Refer to :ref:`bluetooth_qemu_posix` for full instructions on how to build and +Refer to :ref:`bluetooth_qemu_native` for full instructions on how to build and run an application with a physical controller. For the virtual controller refer to :ref:`bluetooth_virtual_posix`. @@ -152,7 +152,7 @@ This board, uses: * The POSIX arch to emulate the processor. * `Models of the nrf52 HW `_ -Just like with the ``native_posix`` target, the build result is a normal Linux +Just like with the :ref:`native_sim ` target, the build result is a normal Linux executable. You can find more information on how to run simulations with one or several devices in diff --git a/doc/connectivity/bluetooth/bluetooth-tools.rst b/doc/connectivity/bluetooth/bluetooth-tools.rst index 35453dd5f673ed6..daa8107e0f3a36d 100644 --- a/doc/connectivity/bluetooth/bluetooth-tools.rst +++ b/doc/connectivity/bluetooth/bluetooth-tools.rst @@ -74,13 +74,13 @@ Finally, reload and restart the daemon: sudo systemctl daemon-reload sudo systemctl restart bluetooth -.. _bluetooth_qemu_posix: +.. _bluetooth_qemu_native: -Running on QEMU and Native POSIX -******************************** +Running on QEMU or native_sim +***************************** It's possible to run Bluetooth applications using either the :ref:`QEMU -emulator` or :ref:`Native POSIX `. +emulator` or :ref:`native_sim `. In either case, a Bluetooth controller needs to be exported from the host OS (Linux) to the emulator. For this purpose you will need some tools described in the :ref:`bluetooth_bluez` section. @@ -94,14 +94,14 @@ The host OS's Bluetooth controller is connected in the following manner: with the help of the QEMU option :literal:`-serial unix:/tmp/bt-server-bredr`. This option gets passed to QEMU through :makevar:`QEMU_EXTRA_FLAGS` automatically whenever an application has enabled Bluetooth support. -* To a serial port in Native POSIX through the use of a command-line option - passed to the Native POSIX executable: ``--bt-dev=hci0`` +* To a serial port in :ref:`native_sim ` through the use of a command-line option + passed to the native_sim executable: ``--bt-dev=hci0`` On the host side, BlueZ allows you to export its Bluetooth controller -through a so-called user channel for QEMU and Native POSIX to use. +through a so-called user channel for QEMU and :ref:`native_sim ` to use. .. note:: - You only need to run ``btproxy`` when using QEMU. Native POSIX handles + You only need to run ``btproxy`` when using QEMU. native_sim handles the UNIX socket proxying automatically If you are using QEMU, in order to make the Controller available you will need @@ -142,12 +142,12 @@ building and running a sample: the :literal:`bt-server-bredr` UNIX socket, letting the application access the Bluetooth controller. -* To run a Bluetooth application in Native POSIX, first build it: +* To run a Bluetooth application in :ref:`native_sim `, first build it: .. zephyr-app-commands:: :zephyr-app: samples/bluetooth/ :host-os: unix - :board: native_posix + :board: native_sim :goals: build :compact: @@ -180,8 +180,8 @@ In order to see those logs, you can use the built-in ``btmon`` tool from BlueZ: .. _bluetooth_virtual_posix: -Running on a Virtual Controller and Native POSIX -************************************************* +Running on a Virtual Controller and native_sim +********************************************** An alternative to a Bluetooth physical controller is the use of a virtual controller. This controller can be connected over an HCI TCP server. diff --git a/samples/bluetooth/bluetooth.rst b/samples/bluetooth/bluetooth.rst index b96637d0c4e71f9..0b59b9626b4ea81 100644 --- a/samples/bluetooth/bluetooth.rst +++ b/samples/bluetooth/bluetooth.rst @@ -6,13 +6,13 @@ Bluetooth samples To build any of the Bluetooth samples, follow the same steps as building any other Zephyr application. Refer to :ref:`bluetooth-dev` for more information. -Many Bluetooth samples can be run on QEMU or Native POSIX with support for +Many Bluetooth samples can be run on QEMU or :ref:`native_sim ` with support for external Bluetooth Controllers. Refer to the :ref:`bluetooth-hw-setup` section for further details. Several of the bluetooth samples will build a Zephyr-based Controller that can then be used with any external Host (including Zephyr running natively or with -QEMU or Native POSIX), those are named accordingly with an "HCI" prefix in the +QEMU or ``native_sim``), those are named accordingly with an "HCI" prefix in the documentation and are prefixed with :literal:`hci_` in their folder names. .. note:: diff --git a/samples/bluetooth/hci_uart/README.rst b/samples/bluetooth/hci_uart/README.rst index 83004cd544f982d..0beb105035d82ae 100644 --- a/samples/bluetooth/hci_uart/README.rst +++ b/samples/bluetooth/hci_uart/README.rst @@ -55,10 +55,10 @@ For example, to build for the nRF52832 Development Kit: .. _bluetooth-hci-uart-qemu-posix: -Using the controller with QEMU and Native POSIX -=============================================== +Using the controller with QEMU or native_sim +============================================ -In order to use the HCI UART controller with QEMU or Native POSIX you will need +In order to use the HCI UART controller with QEMU or :ref:`native_sim ` you will need to attach it to the Linux Host first. To do so simply build the sample and connect the UART to the Linux machine, and then attach it with this command: @@ -84,7 +84,7 @@ If you are running :file:`btmon` you should see a brief log showing how the Linux kernel identifies the attached controller. Once the controller is attached follow the instructions in the -:ref:`bluetooth_qemu_posix` section to use QEMU with it. +:ref:`bluetooth_qemu_native` section to use QEMU with it. .. _bluetooth-hci-uart-bluez: diff --git a/samples/bluetooth/hci_uart_async/README.rst b/samples/bluetooth/hci_uart_async/README.rst index 75bf586868dc3c5..f5caf0f965d1e57 100644 --- a/samples/bluetooth/hci_uart_async/README.rst +++ b/samples/bluetooth/hci_uart_async/README.rst @@ -52,10 +52,10 @@ For example, to build for the nRF52832 Development Kit: .. _bluetooth-hci-uart-async-qemu-posix: -Using the controller with QEMU and Native POSIX -=============================================== +Using the controller with QEMU or native_sim +============================================ -In order to use the HCI UART controller with QEMU or Native POSIX you will need +In order to use the HCI UART controller with QEMU or :ref:`native_sim ` you will need to attach it to the Linux Host first. To do so simply build the sample and connect the UART to the Linux machine, and then attach it with this command: @@ -77,7 +77,7 @@ If you are running :file:`btmon` you should see a brief log showing how the Linux kernel identifies the attached controller. Once the controller is attached follow the instructions in the -:ref:`bluetooth_qemu_posix` section to use QEMU with it. +:ref:`bluetooth_qemu_native` section to use QEMU with it. .. _bluetooth-hci-uart-async-bluez: From fc4967e71fe3252d7ba196b11b44f30ace626df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 13 Nov 2023 16:09:22 +0100 Subject: [PATCH 0325/1049] samples: lz4: reduce malloc arena size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #63332 introduced a change to the LZ4 sample that set the malloc arena to an unnecessarily large size. After testing on native_posix, qemu_m3, and esp32s3_devkitm_appcpu, it would appear 24K is a much more reasonable (and sufficient) size. Signed-off-by: Benjamin Cabé --- samples/compression/lz4/prj.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/compression/lz4/prj.conf b/samples/compression/lz4/prj.conf index a3228945546aab1..d4f2049eb89b8f2 100644 --- a/samples/compression/lz4/prj.conf +++ b/samples/compression/lz4/prj.conf @@ -1,4 +1,4 @@ CONFIG_LZ4=y CONFIG_REQUIRES_FULL_LIBC=y CONFIG_HEAP_MEM_POOL_SIZE=16384 -CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=65536 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=24576 From e74676223ae85f608cbb97737d1a19070b85bd00 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Mon, 9 Oct 2023 11:24:11 +1000 Subject: [PATCH 0326/1049] bluetooth: host: gatt: statically init callback list Statically initialise the callback list so that subscriptions can be registered before the call to `bt_enable`. Signed-off-by: Jordan Yates --- doc/releases/migration-guide-3.6.rst | 4 ++++ include/zephyr/bluetooth/gatt.h | 3 ++- subsys/bluetooth/host/gatt.c | 4 +--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index aaad9dfea3f620a..77a0c1b76f758b0 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -72,6 +72,10 @@ Bluetooth Devicetree chosen is now ``zephyr,bt-hci-ipc``. The existing sample has also been renamed, from ``samples/bluetooth/hci_rpmsg`` to ``samples/bluetooth/hci_ipc``. +* The BT GATT callback list, appended to by :c:func:`bt_gatt_cb_register`, is no longer + cleared on :c:func:`bt_enable`. Callbacks can now be registered before the initial + call to :c:func:`bt_enable`, and should no longer be re-registered after a :c:func:`bt_disable` + :c:func:`bt_enable` cycle. LoRaWAN ======= diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index c50bfb25c3d4ea9..c53422648f0072e 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -370,7 +370,8 @@ struct bt_gatt_cpf { /** @brief Register GATT callbacks. * - * Register callbacks to monitor the state of GATT. + * Register callbacks to monitor the state of GATT. The callback struct + * must remain valid for the remainder of the program. * * @param cb Callback struct. */ diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 8266fe36daee1af..11c292f159eea5f 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -80,7 +80,7 @@ struct gatt_sub { * <=> (subscriptions[x].peer == BT_ADDR_LE_ANY). */ static struct gatt_sub subscriptions[SUB_MAX]; -static sys_slist_t callback_list; +static sys_slist_t callback_list = SYS_SLIST_STATIC_INIT(&callback_list); #if defined(CONFIG_BT_GATT_DYNAMIC_DB) static sys_slist_t db; @@ -1464,8 +1464,6 @@ void bt_gatt_init(void) bt_gatt_service_init(); - sys_slist_init(&callback_list); - #if defined(CONFIG_BT_GATT_CACHING) k_work_init_delayable(&db_hash.work, db_hash_process); From 165bd2a7808108d926d5ad8e09a01b4a752e9bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 16 Oct 2023 07:29:41 +0200 Subject: [PATCH 0327/1049] drivers: serial: Add uart_async_rx module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add module which can handle RX path of UART asynchronous RX API. Module can be utilized in cases where processing of received data is not performed directly in the event context but it is delayed. At least two use cases has been identified (shell async UART backend, asynchronous to interrupt driven adaptation layer). Signed-off-by: Krzysztof Chruściński --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 8 + drivers/serial/uart_async_rx.c | 134 +++++++++++++ include/zephyr/drivers/serial/uart_async_rx.h | 176 ++++++++++++++++++ 4 files changed, 319 insertions(+) create mode 100644 drivers/serial/uart_async_rx.c create mode 100644 include/zephyr/drivers/serial/uart_async_rx.h diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 62336a8980e2e91..be0cbfd394b1355 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -91,3 +91,4 @@ if(CONFIG_UART_NATIVE_TTY) endif() zephyr_library_sources_ifdef(CONFIG_SERIAL_TEST serial_test.c) +zephyr_library_sources_ifdef(CONFIG_UART_ASYNC_RX_HELPER uart_async_rx.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4a42a81aaddee30..22916527ca140fb 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -125,6 +125,14 @@ config UART_PIPE data (as contrary to console UART driver) and all aspects of received protocol data are handled by application provided callback. +config UART_ASYNC_RX_HELPER + bool "Helper for UART asynchronous reception" + help + Module implements handling of reception of variable length data using + Asynchronous UART API. It can be used in cases where received data processing + is delayed. Module implements zero-copy approach with multiple reception + buffers. + comment "Serial Drivers" source "drivers/serial/Kconfig.b91" diff --git a/drivers/serial/uart_async_rx.c b/drivers/serial/uart_async_rx.c new file mode 100644 index 000000000000000..68e17691c3efad6 --- /dev/null +++ b/drivers/serial/uart_async_rx.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static uint8_t inc(struct uart_async_rx *rx_data, uint8_t val) +{ + return (val + 1) & (rx_data->config->buf_cnt - 1); +} + +static struct uart_async_rx_buf *get_buf(struct uart_async_rx *rx_data, uint8_t idx) +{ + uint8_t *p = rx_data->config->buffer; + + p += idx * (rx_data->buf_len + sizeof(struct uart_async_rx_buf)); + + return (struct uart_async_rx_buf *)p; +} + +uint8_t *uart_async_rx_buf_req(struct uart_async_rx *rx_data) +{ + uint8_t *data = NULL; + + if (rx_data->free_buf_cnt != 0) { + struct uart_async_rx_buf *buf = get_buf(rx_data, rx_data->drv_buf_idx); + + data = buf->buffer; + rx_data->drv_buf_idx = inc(rx_data, rx_data->drv_buf_idx); + + atomic_dec(&rx_data->free_buf_cnt); + } + + return data; +} + +void uart_async_rx_on_rdy(struct uart_async_rx *rx_data, uint8_t *buffer, size_t length) +{ + /* Cannot use CONTAINER_OF because validation fails due to type mismatch: + * uint8_t * vs uint8_t []. + */ + struct uart_async_rx_buf *rx_buf = + (struct uart_async_rx_buf *)(buffer - offsetof(struct uart_async_rx_buf, buffer)); + + rx_buf->wr_idx += length; + __ASSERT_NO_MSG(rx_buf->wr_idx <= rx_data->buf_len); + + atomic_add(&rx_data->pending_bytes, length); +} + +static void buf_reset(struct uart_async_rx_buf *buf) +{ + buf->rd_idx = 0; + buf->wr_idx = 0; + buf->completed = 0; +} +static void usr_rx_buf_release(struct uart_async_rx *rx_data, struct uart_async_rx_buf *buf) +{ + buf_reset(buf); + rx_data->rd_buf_idx = inc(rx_data, rx_data->rd_buf_idx); + atomic_inc(&rx_data->free_buf_cnt); + __ASSERT_NO_MSG(rx_data->free_buf_cnt <= rx_data->config->buf_cnt); +} + +void uart_async_rx_on_buf_rel(struct uart_async_rx *rx_data, uint8_t *buffer) +{ + /* Cannot use CONTAINER_OF because validation fails due to type mismatch: + * uint8_t * vs uint8_t []. + */ + struct uart_async_rx_buf *rx_buf = + (struct uart_async_rx_buf *)(buffer - offsetof(struct uart_async_rx_buf, buffer)); + + rx_buf->completed = 1; + rx_data->wr_buf_idx = inc(rx_data, rx_data->wr_buf_idx); +} + +size_t uart_async_rx_data_claim(struct uart_async_rx *rx_data, uint8_t **data, size_t length) +{ + struct uart_async_rx_buf *buf; + int rem; + + if ((rx_data->pending_bytes == 0) || (length == 0)) { + return 0; + } + + do { + buf = get_buf(rx_data, rx_data->rd_buf_idx); + if ((buf->rd_idx == buf->wr_idx) && (buf->completed == 1)) { + usr_rx_buf_release(rx_data, buf); + } else { + break; + } + } while (1); + + *data = &buf->buffer[buf->rd_idx]; + rem = buf->wr_idx - buf->rd_idx; + + return MIN(length, rem); +} + +void uart_async_rx_data_consume(struct uart_async_rx *rx_data, size_t length) +{ + struct uart_async_rx_buf *buf = get_buf(rx_data, rx_data->rd_buf_idx); + + buf->rd_idx += length; + + atomic_sub(&rx_data->pending_bytes, length); + + __ASSERT_NO_MSG(buf->rd_idx <= buf->wr_idx); +} + +void uart_async_rx_reset(struct uart_async_rx *rx_data) +{ + rx_data->free_buf_cnt = rx_data->config->buf_cnt; + for (uint8_t i = 0; i < rx_data->config->buf_cnt; i++) { + buf_reset(get_buf(rx_data, i)); + } +} + +int uart_async_rx_init(struct uart_async_rx *rx_data, + const struct uart_async_rx_config *config) +{ + __ASSERT_NO_MSG(config->length / config->buf_cnt <= UINT8_MAX); + memset(rx_data, 0, sizeof(*rx_data)); + rx_data->config = config; + rx_data->buf_len = (config->length / config->buf_cnt) - UART_ASYNC_RX_BUF_OVERHEAD; + uart_async_rx_reset(rx_data); + + return 0; +} diff --git a/include/zephyr/drivers/serial/uart_async_rx.h b/include/zephyr/drivers/serial/uart_async_rx.h new file mode 100644 index 000000000000000..646a2befc946580 --- /dev/null +++ b/include/zephyr/drivers/serial/uart_async_rx.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Helper module for receiving using UART Asynchronous API. + */ + +#ifndef ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_ +#define ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* @brief RX buffer structure which holds the buffer and its state. */ +struct uart_async_rx_buf { + /* Write index which is incremented whenever new data is reported to be + * received to that buffer. + */ + uint8_t wr_idx; + + /* Read index which is incremented whenever data is consumed from the buffer. + * Read index cannot be higher than the write index. + */ + uint8_t rd_idx; + + /* Set to one if buffer is released by the driver. */ + uint8_t completed; + + /* Location which is passed to the UART driver. */ + uint8_t buffer[]; +}; + +/** @brief UART asynchronous RX helper structure. */ +struct uart_async_rx { + /* Pointer to the configuration structure. Structure must be persistent. */ + const struct uart_async_rx_config *config; + + /* Total amount of pending bytes. Bytes may be spread across multiple RX buffers. */ + atomic_t pending_bytes; + + /* Number of buffers which are free. */ + atomic_t free_buf_cnt; + + /* Single buffer size. */ + uint8_t buf_len; + + /* Index of the next buffer to be provided to the driver. */ + uint8_t drv_buf_idx; + + /* Current buffer to which data is written. */ + uint8_t wr_buf_idx; + + /* Current buffer from which data is being consumed. */ + uint8_t rd_buf_idx; +}; + +/** @brief UART asynchronous RX helper configuration structure. */ +struct uart_async_rx_config { + /* Pointer to the buffer. */ + uint8_t *buffer; + + /* Buffer length. */ + size_t length; + + /* Number of buffers into provided space shall be split. */ + uint8_t buf_cnt; +}; + +/** @brief Get RX buffer length. + * + * @param async_rx Pointer to the helper instance. + * + * @return Buffer length. + */ +static inline uint8_t uart_async_rx_get_buf_len(struct uart_async_rx *async_rx) +{ + return async_rx->buf_len; +} + +/** @brief Get amount of space dedicated for managing each buffer state. + * + * User buffer provided during the initialization is split into chunks and each + * chunk has overhead. This overhead can be used to calculate actual space used + * for UART data. + * + * @return Overhead space in bytes. + */ +#define UART_ASYNC_RX_BUF_OVERHEAD offsetof(struct uart_async_rx_buf, buffer) + +/** @brief Initialize the helper instance. + * + * @param async_rx Pointer to the helper instance. + * @param config Configuration. Must be persistent. + * + * @retval 0 on successful initialization. + */ +int uart_async_rx_init(struct uart_async_rx *async_rx, + const struct uart_async_rx_config *config); + +/** @brief Reset state of the helper instance. + * + * Helper can be reset after RX abort to discard all received data and bring + * the helper to its initial state. + * + * @param async_rx Pointer to the helper instance. + */ +void uart_async_rx_reset(struct uart_async_rx *async_rx); + +/** @brief Indicate received data. + * + * Function shall be called from @ref UART_RX_RDY context. + * + * @param async_rx Pointer to the helper instance. + * @param buffer Buffer received in the UART driver event. + * @param length Length received in the UART driver event. + */ +void uart_async_rx_on_rdy(struct uart_async_rx *async_rx, uint8_t *buffer, size_t length); + +/** @brief Get next RX buffer. + * + * Returned pointer shall be provided to @ref uart_rx_buf_rsp or @ref uart_rx_enable. + * If null is returned that indicates that there are no available buffers since all + * buffers are used by the driver or contain not consumed data. + * + * @param async_rx Pointer to the helper instance. + * + * @return Pointer to the next RX buffer or null if no buffer available. + */ +uint8_t *uart_async_rx_buf_req(struct uart_async_rx *async_rx); + +/** @brief Indicate that buffer is no longer used by the UART driver. + * + * Function shall be called on @ref UART_RX_BUF_RELEASED event. + * + * @param async_rx Pointer to the helper instance. + * @param buf Buffer pointer received in the UART driver event. + */ +void uart_async_rx_on_buf_rel(struct uart_async_rx *async_rx, uint8_t *buf); + +/** @brief Claim received data for processing. + * + * Helper module works in the zero copy mode. It provides a pointer to the buffer + * that was directly used by the UART driver. Since received data is spread across + * multiple buffers there is no possibility to read all data at once. It can only be + * consumed in chunks. After data is processed, @ref uart_async_rx_data_consume is + * used to indicate that data is consumed. + * + * @param async_rx Pointer to the helper instance. + * @param data Location where address to the buffer is written. Untouched if no data to claim. + * @param length Amount of requested data. + * + * @return Amount valid of data in the @p data buffer. 0 is returned when there is no data. + */ +size_t uart_async_rx_data_claim(struct uart_async_rx *async_rx, uint8_t **data, size_t length); + +/** @brief Consume claimed data. + * + * It pairs with @ref uart_async_rx_data_claim. + * + * @param async_rx Pointer to the helper instance. + * @param length Amount of data to consume. It must be less or equal than amount of claimed data. + */ +void uart_async_rx_data_consume(struct uart_async_rx *async_rx, size_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_ */ From 8ba4249ef72c468dc94697ed959471333576da34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 16 Oct 2023 07:31:22 +0200 Subject: [PATCH 0328/1049] tests: drivers: uart: Add test for uart_async_rx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test for helper module for handling asynchronous RX. Signed-off-by: Krzysztof Chruściński --- .../drivers/uart/uart_async_rx/CMakeLists.txt | 9 + tests/drivers/uart/uart_async_rx/prj.conf | 4 + tests/drivers/uart/uart_async_rx/src/main.c | 327 ++++++++++++++++++ .../drivers/uart/uart_async_rx/testcase.yaml | 15 + 4 files changed, 355 insertions(+) create mode 100644 tests/drivers/uart/uart_async_rx/CMakeLists.txt create mode 100644 tests/drivers/uart/uart_async_rx/prj.conf create mode 100644 tests/drivers/uart/uart_async_rx/src/main.c create mode 100644 tests/drivers/uart/uart_async_rx/testcase.yaml diff --git a/tests/drivers/uart/uart_async_rx/CMakeLists.txt b/tests/drivers/uart/uart_async_rx/CMakeLists.txt new file mode 100644 index 000000000000000..9cb2446f3c6d073 --- /dev/null +++ b/tests/drivers/uart/uart_async_rx/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(uart_async_rx) + +target_sources(app PRIVATE + src/main.c +) diff --git a/tests/drivers/uart/uart_async_rx/prj.conf b/tests/drivers/uart/uart_async_rx/prj.conf new file mode 100644 index 000000000000000..e10bf49c4d1ccdf --- /dev/null +++ b/tests/drivers/uart/uart_async_rx/prj.conf @@ -0,0 +1,4 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_ZTRESS=y +CONFIG_UART_ASYNC_RX_HELPER=y diff --git a/tests/drivers/uart/uart_async_rx/src/main.c b/tests/drivers/uart/uart_async_rx/src/main.c new file mode 100644 index 000000000000000..d95c6a690661c9b --- /dev/null +++ b/tests/drivers/uart/uart_async_rx/src/main.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(test); + +static void mem_fill(uint8_t *buf, uint8_t init, size_t len) +{ + for (size_t i = 0; i < len; i++) { + buf[i] = init + i; + } +} + +static bool mem_check(uint8_t *buf, uint8_t init, size_t len) +{ + for (size_t i = 0; i < len; i++) { + if (buf[i] != init + i) { + return false; + } + } + + return true; +} + +ZTEST(uart_async_rx, test_rx) +{ + int err; + uint8_t buf[40]; + static const int buf_cnt = 4; + size_t aloc_len; + size_t claim_len; + uint8_t *claim_buf; + uint8_t *aloc_buf; + struct uart_async_rx async_rx; + const struct uart_async_rx_config config = { + .buffer = buf, + .length = sizeof(buf), + .buf_cnt = buf_cnt + }; + + err = uart_async_rx_init(&async_rx, &config); + zassert_equal(err, 0); + + aloc_len = uart_async_rx_get_buf_len(&async_rx); + aloc_buf = uart_async_rx_buf_req(&async_rx); + + mem_fill(aloc_buf, 0, aloc_len - 2); + + /* No data to read. */ + claim_len = uart_async_rx_data_claim(&async_rx, &claim_buf, 1); + zassert_equal(claim_len, 0); + + /* Simulate partial write */ + uart_async_rx_on_rdy(&async_rx, aloc_buf, aloc_len - 4); + + /* There is at least 1 byte available */ + claim_len = uart_async_rx_data_claim(&async_rx, &claim_buf, 1); + zassert_equal(claim_len, 1); + zassert_equal(claim_buf, aloc_buf); + zassert_true(mem_check(claim_buf, 0, 1)); + + /* All received data is available */ + claim_len = uart_async_rx_data_claim(&async_rx, &claim_buf, 100); + zassert_equal(claim_len, aloc_len - 4); + zassert_equal(claim_buf, aloc_buf); + zassert_true(mem_check(claim_buf, 0, aloc_len - 4)); + + /* Simulate 2 bytes received to the same buffer. */ + uart_async_rx_on_rdy(&async_rx, aloc_buf, 2); + + /* Indicate and of the current buffer. */ + uart_async_rx_on_buf_rel(&async_rx, aloc_buf); + + /* Claim all data received so far */ + claim_len = uart_async_rx_data_claim(&async_rx, &claim_buf, 100); + zassert_equal(claim_len, aloc_len - 2); + zassert_equal(claim_buf, aloc_buf); + zassert_true(mem_check(claim_buf, 0, aloc_len - 2)); + + /* Consume first 2 bytes. */ + uart_async_rx_data_consume(&async_rx, 2); + + /* Now claim will return buffer taking into account that first 2 bytes are + * consumed. + */ + claim_len = uart_async_rx_data_claim(&async_rx, &claim_buf, 100); + zassert_equal(claim_len, aloc_len - 4); + zassert_equal(claim_buf, &aloc_buf[2]); + zassert_true(mem_check(claim_buf, 2, aloc_len - 4)); + + /* Consume rest of data. Get indication that it was end of the buffer. */ + uart_async_rx_data_consume(&async_rx, aloc_len - 4); +} + +ZTEST(uart_async_rx, test_rx_late_consume) +{ + int err; + uint8_t buf[40] __aligned(4); + static const int buf_cnt = 4; + size_t aloc_len; + size_t claim_len; + uint8_t *claim_buf; + uint8_t *aloc_buf; + struct uart_async_rx async_rx; + const struct uart_async_rx_config config = { + .buffer = buf, + .length = sizeof(buf), + .buf_cnt = buf_cnt + }; + + err = uart_async_rx_init(&async_rx, &config); + zassert_equal(err, 0); + + aloc_len = uart_async_rx_get_buf_len(&async_rx); + for (int i = 0; i < buf_cnt; i++) { + aloc_buf = uart_async_rx_buf_req(&async_rx); + + aloc_buf[0] = (uint8_t)i; + uart_async_rx_on_rdy(&async_rx, aloc_buf, 1); + uart_async_rx_on_buf_rel(&async_rx, aloc_buf); + } + + for (int i = 0; i < buf_cnt; i++) { + claim_len = uart_async_rx_data_claim(&async_rx, &claim_buf, 100); + zassert_equal(claim_len, 1); + zassert_equal(claim_buf[0], (uint8_t)i); + + uart_async_rx_data_consume(&async_rx, 1); + } + + claim_len = uart_async_rx_data_claim(&async_rx, &claim_buf, 100); + zassert_equal(claim_len, 0); +} + +struct test_async_rx { + struct uart_async_rx async_rx; + atomic_t pending_req; + atomic_t total_pending_req; + bool in_chunks; + uint8_t exp_consume; + uint32_t byte_cnt; + uint8_t curr_len; + uint8_t *curr_buf; + uint8_t *next_buf; + struct k_spinlock lock; +}; + +static bool producer_no_chunks(void *user_data, uint32_t cnt, bool last, int prio) +{ + struct test_async_rx *test_data = (struct test_async_rx *)user_data; + struct uart_async_rx *async_rx = &test_data->async_rx; + uint32_t r = sys_rand32_get(); + uint32_t len = MAX(1, MIN(uart_async_rx_get_buf_len(async_rx), r & 0x7)); + + if (test_data->curr_buf) { + + for (int i = 0; i < len; i++) { + test_data->curr_buf[i] = (uint8_t)test_data->byte_cnt; + test_data->byte_cnt++; + } + uart_async_rx_on_rdy(async_rx, test_data->curr_buf, len); + uart_async_rx_on_buf_rel(async_rx, test_data->curr_buf); + test_data->curr_buf = test_data->next_buf; + test_data->next_buf = NULL; + + uint8_t *buf = uart_async_rx_buf_req(async_rx); + + if (buf) { + if (test_data->curr_buf == NULL) { + test_data->curr_buf = buf; + } else { + test_data->next_buf = buf; + } + } else { + atomic_inc(&test_data->pending_req); + atomic_inc(&test_data->total_pending_req); + } + } + + return true; +} + +static bool consumer(void *user_data, uint32_t cnt, bool last, int prio) +{ + struct test_async_rx *test_data = (struct test_async_rx *)user_data; + struct uart_async_rx *async_rx = &test_data->async_rx; + uint32_t r = sys_rand32_get(); + uint32_t rpt = MAX(1, r & 0x7); + + r >>= 3; + + for (uint32_t i = 0; i < rpt; i++) { + size_t claim_len = MAX(1, r & 0x7); + size_t len; + uint8_t *buf; + + r >>= 3; + len = uart_async_rx_data_claim(async_rx, &buf, claim_len); + + if (len == 0) { + return true; + } + + for (int j = 0; j < len; j++) { + zassert_equal(buf[j], test_data->exp_consume, + "%02x (exp:%02x) len:%d, total:%d", + buf[j], test_data->exp_consume, len, test_data->byte_cnt); + test_data->exp_consume++; + } + + uart_async_rx_data_consume(async_rx, len); + + if (test_data->pending_req) { + buf = uart_async_rx_buf_req(async_rx); + if (buf) { + atomic_dec(&test_data->pending_req); + } + k_spinlock_key_t key = k_spin_lock(&test_data->lock); + + if (test_data->curr_buf == NULL) { + test_data->curr_buf = buf; + } else if (test_data->next_buf == NULL) { + test_data->next_buf = buf; + } else { + zassert_true(false); + } + k_spin_unlock(&test_data->lock, key); + } + } + + return true; +} + +static bool producer_in_chunks(void *user_data, uint32_t cnt, bool last, int prio) +{ + struct test_async_rx *test_data = (struct test_async_rx *)user_data; + struct uart_async_rx *async_rx = &test_data->async_rx; + uint32_t r = sys_rand32_get(); + uint32_t rem = uart_async_rx_get_buf_len(async_rx) - test_data->curr_len; + uint32_t len = MAX(1, MIN(uart_async_rx_get_buf_len(async_rx), r & 0x7)); + + len = MIN(rem, len); + + if (test_data->curr_buf) { + for (int i = 0; i < len; i++) { + test_data->curr_buf[test_data->curr_len + i] = (uint8_t)test_data->byte_cnt; + test_data->byte_cnt++; + } + uart_async_rx_on_rdy(async_rx, test_data->curr_buf, len); + test_data->curr_len += len; + + if ((test_data->curr_len == uart_async_rx_get_buf_len(async_rx)) || (r & BIT(31))) { + test_data->curr_len = 0; + uart_async_rx_on_buf_rel(async_rx, test_data->curr_buf); + + test_data->curr_buf = test_data->next_buf; + test_data->next_buf = NULL; + + uint8_t *buf = uart_async_rx_buf_req(async_rx); + + if (buf) { + if (test_data->curr_buf == NULL) { + test_data->curr_buf = buf; + } else { + test_data->next_buf = buf; + } + } else { + atomic_inc(&test_data->pending_req); + } + } + } + + return true; +} + +static void stress_test(bool in_chunks) +{ + int err; + uint8_t buf[40]; + static const int buf_cnt = 4; + int preempt = 1000; + int timeout = 5000; + struct test_async_rx test_data; + const struct uart_async_rx_config config = { + .buffer = buf, + .length = sizeof(buf), + .buf_cnt = buf_cnt + }; + + memset(&test_data, 0, sizeof(test_data)); + + err = uart_async_rx_init(&test_data.async_rx, &config); + zassert_equal(err, 0); + + test_data.in_chunks = in_chunks; + test_data.curr_buf = uart_async_rx_buf_req(&test_data.async_rx); + + ztress_set_timeout(K_MSEC(timeout)); + + ZTRESS_EXECUTE(ZTRESS_THREAD(in_chunks ? producer_in_chunks : producer_no_chunks, + &test_data, 0, 0, Z_TIMEOUT_TICKS(20)), + ZTRESS_THREAD(consumer, &test_data, 0, preempt, Z_TIMEOUT_TICKS(20))); + + TC_PRINT("total bytes: %d\n", test_data.byte_cnt); + ztress_set_timeout(K_NO_WAIT); +} + +ZTEST(uart_async_rx, test_rx_ztress_no_chunks) +{ + stress_test(false); +} + +ZTEST(uart_async_rx, test_rx_ztress_with_chunks) +{ + stress_test(true); +} + +ZTEST_SUITE(uart_async_rx, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/drivers/uart/uart_async_rx/testcase.yaml b/tests/drivers/uart/uart_async_rx/testcase.yaml new file mode 100644 index 000000000000000..64311dc1eb73b21 --- /dev/null +++ b/tests/drivers/uart/uart_async_rx/testcase.yaml @@ -0,0 +1,15 @@ +tests: + drivers.uart.async_rx: + filter: CONFIG_SERIAL + tags: drivers uart + integration_platforms: + - native_posix + drivers.uart.async_rx.ztress: + filter: CONFIG_SERIAL + tags: drivers uart + platform_allow: > + qemu_cortex_m3 qemu_x86 qemu_x86_64 qemu_riscv32 + integration_platforms: + - qemu_x86 + extra_configs: + - CONFIG_SYS_CLOCK_TICKS_PER_SEC=10000 From 5e4e944cc0c09066ac67fa485f0c18998a396acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 16 Oct 2023 07:49:32 +0200 Subject: [PATCH 0329/1049] shell: backends: uart: Rework and add support for async API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework UART backend to clearly use single instance approach as before it was a bit messy with some parts of implementation indicating multi-instance approach and some single instance. Backend has been around for years and multi-instance requirement never came. Added support for UART asynchronous API which is more efficient in terms of power consumption and performance. Asynchronous API support is using uart_async_rx helper module for handling data received asynchronously. Signed-off-by: Krzysztof Chruściński --- include/zephyr/shell/shell_uart.h | 70 +--- subsys/shell/backends/Kconfig.backends | 60 +++- subsys/shell/backends/shell_uart.c | 441 +++++++++++++++++++------ 3 files changed, 400 insertions(+), 171 deletions(-) diff --git a/include/zephyr/shell/shell_uart.h b/include/zephyr/shell/shell_uart.h index adf8a4044aa08dd..2b157aac6e78219 100644 --- a/include/zephyr/shell/shell_uart.h +++ b/include/zephyr/shell/shell_uart.h @@ -8,81 +8,15 @@ #define SHELL_UART_H__ #include -#include -#include -#include #ifdef __cplusplus extern "C" { #endif -extern const struct shell_transport_api shell_uart_transport_api; - -/** @brief Shell UART transport instance control block (RW data). */ -struct shell_uart_ctrl_blk { - const struct device *dev; - shell_transport_handler_t handler; - void *context; - atomic_t tx_busy; - bool blocking_tx; -#ifdef CONFIG_MCUMGR_TRANSPORT_SHELL - struct smp_shell_data smp; -#endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ -}; - -#ifdef CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN -#define Z_UART_SHELL_TX_RINGBUF_DECLARE(_name, _size) \ - RING_BUF_DECLARE(_name##_tx_ringbuf, _size) - -#define Z_UART_SHELL_RX_TIMER_DECLARE(_name) /* Empty */ -#define Z_UART_SHELL_TX_RINGBUF_PTR(_name) (&_name##_tx_ringbuf) - -#define Z_UART_SHELL_RX_TIMER_PTR(_name) NULL - -#define Z_UART_SHELL_DTR_TIMER_DECLARE(_name) static struct k_timer _name##_dtr_timer -#define Z_UART_SHELL_DTR_TIMER_PTR(_name) (&_name##_dtr_timer) - -#else /* CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN */ -#define Z_UART_SHELL_TX_RINGBUF_DECLARE(_name, _size) /* Empty */ -#define Z_UART_SHELL_RX_TIMER_DECLARE(_name) static struct k_timer _name##_timer -#define Z_UART_SHELL_TX_RINGBUF_PTR(_name) NULL -#define Z_UART_SHELL_RX_TIMER_PTR(_name) (&_name##_timer) -#define Z_UART_SHELL_DTR_TIMER_DECLARE(_name) /* Empty */ -#define Z_UART_SHELL_DTR_TIMER_PTR(_name) NULL -#endif /* CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN */ - -/** @brief Shell UART transport instance structure. */ -struct shell_uart { - struct shell_uart_ctrl_blk *ctrl_blk; - struct k_timer *timer; - struct k_timer *dtr_timer; - struct ring_buf *tx_ringbuf; - struct ring_buf *rx_ringbuf; -}; - -/** @brief Macro for creating shell UART transport instance. */ -#define SHELL_UART_DEFINE(_name, _tx_ringbuf_size, _rx_ringbuf_size) \ - static struct shell_uart_ctrl_blk _name##_ctrl_blk; \ - Z_UART_SHELL_RX_TIMER_DECLARE(_name); \ - Z_UART_SHELL_DTR_TIMER_DECLARE(_name); \ - Z_UART_SHELL_TX_RINGBUF_DECLARE(_name, _tx_ringbuf_size); \ - RING_BUF_DECLARE(_name##_rx_ringbuf, _rx_ringbuf_size); \ - static const struct shell_uart _name##_shell_uart = { \ - .ctrl_blk = &_name##_ctrl_blk, \ - .timer = Z_UART_SHELL_RX_TIMER_PTR(_name), \ - .dtr_timer = Z_UART_SHELL_DTR_TIMER_PTR(_name), \ - .tx_ringbuf = Z_UART_SHELL_TX_RINGBUF_PTR(_name), \ - .rx_ringbuf = &_name##_rx_ringbuf, \ - }; \ - struct shell_transport _name = { \ - .api = &shell_uart_transport_api, \ - .ctx = (struct shell_uart *)&_name##_shell_uart \ - } - /** - * @brief This function provides pointer to shell uart backend instance. + * @brief This function provides pointer to the shell UART backend instance. * - * Function returns pointer to the shell uart instance. This instance can be + * Function returns pointer to the shell UART instance. This instance can be * next used with shell_execute_cmd function in order to test commands behavior. * * @returns Pointer to the shell instance. diff --git a/subsys/shell/backends/Kconfig.backends b/subsys/shell/backends/Kconfig.backends index 1d30bee2305d533..7c81030cb20083c 100644 --- a/subsys/shell/backends/Kconfig.backends +++ b/subsys/shell/backends/Kconfig.backends @@ -42,23 +42,44 @@ config SHELL_PROMPT_UART Displayed prompt name for UART backend. If prompt is set, the shell will send two newlines during initialization. -# Internal config to enable UART interrupts if supported. config SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN bool "Interrupt driven" - default y + depends on SERIAL_SUPPORT_INTERRUPT + +choice SHELL_BACKEND_SERIAL_API + prompt "Mode" + default SHELL_BACKEND_SERIAL_API_ASYNC if SERIAL_SUPPORT_ASYNC + default SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN if SERIAL_SUPPORT_INTERRUPT + default SHELL_BACKEND_SERIAL_API_POLLING + +config SHELL_BACKEND_SERIAL_API_POLLING + prompt "Polling" + +config SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN + bool "Interrupt driven" depends on SERIAL_SUPPORT_INTERRUPT select UART_INTERRUPT_DRIVEN + +config SHELL_BACKEND_SERIAL_API_ASYNC + bool "Asynchronous" + depends on SERIAL_SUPPORT_ASYNC + select UART_ASYNC_RX_HELPER + select UART_ASYNC_API + +endchoice + config SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE int "Set TX ring buffer size" default 8 - depends on SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN + depends on SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN help If UART is utilizing DMA transfers then increasing ring buffer size increases transfers length and reduces number of interrupts. config SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE int "Set RX ring buffer size" + depends on SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN || SHELL_BACKEND_SERIAL_API_POLLING default 256 if MCUMGR_TRANSPORT_SHELL default 64 help @@ -68,16 +89,45 @@ config SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE escape sequences). However, if bulk data is transferred it may be required to increase it. +if SHELL_BACKEND_SERIAL_API_ASYNC + +config SHELL_BACKEND_SERIAL_ASYNC_RX_TIMEOUT + int "RX inactivity timeout (in microseconds)" + default 10000 + help + Inactivity timeout after which received data is reported. + +config SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT + int "Number of RX buffers" + default 4 + range 2 64 + help + Number of RX buffers. Some UART driver implementations changes buffers + on timeout so this number should be big enough to cover handling on + time incoming data. 4 should be enough for almost all the cases unless + CPU load is high and there is very high shell thread latency. + +config SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE + int "Size of the RX buffer" + default 16 + help + Size of a single RX buffer. Together with buffer count it defines the + space that can hold RX data. It may be decreased if shell input is + slow and may need to be increased if long messages are pasted directly + to the shell prompt. + +endif # SHELL_BACKEND_SERIAL_API_ASYNC + config SHELL_BACKEND_SERIAL_RX_POLL_PERIOD int "RX polling period (in milliseconds)" default 10 - depends on !SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN + depends on SHELL_BACKEND_SERIAL_API_POLLING help Determines how often UART is polled for RX byte. config SHELL_BACKEND_SERIAL_CHECK_DTR bool "Check DTR signal before TX" - depends on SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN + depends on SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN depends on UART_LINE_CTRL help Check DTR signal before TX. diff --git a/subsys/shell/backends/shell_uart.c b/subsys/shell/backends/shell_uart.c index ce52eb15d8c3156..f64438c0b5986ac 100644 --- a/subsys/shell/backends/shell_uart.c +++ b/subsys/shell/backends/shell_uart.c @@ -4,8 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include +#include #include #include +#include #include #include #include @@ -19,34 +23,122 @@ LOG_MODULE_REGISTER(shell_uart); #define RX_POLL_PERIOD K_NO_WAIT #endif +#ifndef CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE +#define CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE 0 +#endif + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE +#define CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE 0 +#endif + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT +#define CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT 0 +#endif + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE +#define CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE 0 +#endif + +#define ASYNC_RX_BUF_SIZE (CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT * \ + (CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE + \ + UART_ASYNC_RX_BUF_OVERHEAD)) + +struct shell_uart_common { + const struct device *dev; + shell_transport_handler_t handler; + void *context; + bool blocking_tx; +#ifdef CONFIG_MCUMGR_TRANSPORT_SHELL + struct smp_shell_data smp; +#endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ +}; + +struct shell_uart_int_driven { + struct shell_uart_common common; + struct ring_buf tx_ringbuf; + struct ring_buf rx_ringbuf; + struct k_timer dtr_timer; + atomic_t tx_busy; +}; + +struct shell_uart_async { + struct shell_uart_common common; + struct k_sem tx_sem; + struct uart_async_rx async_rx; + atomic_t pending_rx_req; +}; + +struct shell_uart_polling { + struct shell_uart_common common; + struct ring_buf rx_ringbuf; + struct k_timer rx_timer; +}; + +static uint8_t __noinit async_rx_data[ASYNC_RX_BUF_SIZE]; +static uint8_t __noinit rx_ringbuf_data[CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE]; +static uint8_t __noinit tx_ringbuf_data[CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE]; + +static struct shell_uart_int_driven shell_uart_i; +static struct shell_uart_async shell_uart_a; +static struct shell_uart_polling shell_uart_p; + #ifdef CONFIG_MCUMGR_TRANSPORT_SHELL NET_BUF_POOL_DEFINE(smp_shell_rx_pool, CONFIG_MCUMGR_TRANSPORT_SHELL_RX_BUF_COUNT, SMP_SHELL_RX_BUF_SIZE, 0, NULL); #endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ -SHELL_UART_DEFINE(shell_transport_uart, - CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE, - CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE); -SHELL_DEFINE(shell_uart, CONFIG_SHELL_PROMPT_UART, &shell_transport_uart, - CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_SIZE, - CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_TIMEOUT, - SHELL_FLAG_OLF_CRLF); +static void async_callback(const struct device *dev, struct uart_event *evt, void *user_data) +{ + struct shell_uart_async *sh_uart = (struct shell_uart_async *)user_data; + + switch (evt->type) { + case UART_TX_DONE: + k_sem_give(&sh_uart->tx_sem); + break; + case UART_RX_RDY: + uart_async_rx_on_rdy(&sh_uart->async_rx, evt->data.rx.buf, evt->data.rx.len); + sh_uart->common.handler(SHELL_TRANSPORT_EVT_RX_RDY, sh_uart->common.context); + break; + case UART_RX_BUF_REQUEST: + { + uint8_t *buf = uart_async_rx_buf_req(&sh_uart->async_rx); + size_t len = uart_async_rx_get_buf_len(&sh_uart->async_rx); + + if (buf) { + int err = uart_rx_buf_rsp(dev, buf, len); + + if (err < 0) { + uart_async_rx_on_buf_rel(&sh_uart->async_rx, buf); + } + } else { + atomic_inc(&sh_uart->pending_rx_req); + } -#ifdef CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN -static void uart_rx_handle(const struct device *dev, - const struct shell_uart *sh_uart) + break; + } + case UART_RX_BUF_RELEASED: + uart_async_rx_on_buf_rel(&sh_uart->async_rx, evt->data.rx_buf.buf); + break; + case UART_RX_DISABLED: + break; + default: + break; + }; +} + +static void uart_rx_handle(const struct device *dev, struct shell_uart_int_driven *sh_uart) { uint8_t *data; uint32_t len; uint32_t rd_len; bool new_data = false; #ifdef CONFIG_MCUMGR_TRANSPORT_SHELL - struct smp_shell_data *const smp = &sh_uart->ctrl_blk->smp; + struct smp_shell_data *const smp = &sh_uart->common.smp; #endif do { - len = ring_buf_put_claim(sh_uart->rx_ringbuf, &data, - sh_uart->rx_ringbuf->size); + len = ring_buf_put_claim(&sh_uart->rx_ringbuf, &data, + sh_uart->rx_ringbuf.size); if (len > 0) { rd_len = uart_fifo_read(dev, data, len); @@ -72,8 +164,7 @@ static void uart_rx_handle(const struct device *dev, } } #endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ - int err = ring_buf_put_finish(sh_uart->rx_ringbuf, - rd_len); + int err = ring_buf_put_finish(&sh_uart->rx_ringbuf, rd_len); (void)err; __ASSERT_NO_MSG(err == 0); } else { @@ -87,8 +178,7 @@ static void uart_rx_handle(const struct device *dev, /* If successful in getting byte from the fifo, try * feeding it to SMP as a part of mcumgr frame. */ - if ((rd_len != 0) && - (smp_shell_rx_bytes(smp, &dummy, 1) == 1)) { + if ((rd_len != 0) && (smp_shell_rx_bytes(smp, &dummy, 1) == 1)) { new_data = true; } #endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ @@ -96,8 +186,7 @@ static void uart_rx_handle(const struct device *dev, } while (rd_len && (rd_len == len)); if (new_data) { - sh_uart->ctrl_blk->handler(SHELL_TRANSPORT_EVT_RX_RDY, - sh_uart->ctrl_blk->context); + sh_uart->common.handler(SHELL_TRANSPORT_EVT_RX_RDY, sh_uart->common.context); } } @@ -123,19 +212,18 @@ static bool uart_dtr_check(const struct device *dev) static void dtr_timer_handler(struct k_timer *timer) { - const struct shell_uart *sh_uart = k_timer_user_data_get(timer); + struct shell_uart_int_driven *sh_uart = k_timer_user_data_get(timer); - if (!uart_dtr_check(sh_uart->ctrl_blk->dev)) { + if (!uart_dtr_check(sh_uart->common.dev)) { return; } /* DTR is active, stop timer and start TX */ k_timer_stop(timer); - uart_irq_tx_enable(sh_uart->ctrl_blk->dev); + uart_irq_tx_enable(sh_uart->common.dev); } -static void uart_tx_handle(const struct device *dev, - const struct shell_uart *sh_uart) +static void uart_tx_handle(const struct device *dev, struct shell_uart_int_driven *sh_uart) { uint32_t len; const uint8_t *data; @@ -143,31 +231,30 @@ static void uart_tx_handle(const struct device *dev, if (!uart_dtr_check(dev)) { /* Wait for DTR signal before sending anything to output. */ uart_irq_tx_disable(dev); - k_timer_start(sh_uart->dtr_timer, K_MSEC(100), K_MSEC(100)); + k_timer_start(&sh_uart->dtr_timer, K_MSEC(100), K_MSEC(100)); return; } - len = ring_buf_get_claim(sh_uart->tx_ringbuf, (uint8_t **)&data, - sh_uart->tx_ringbuf->size); + len = ring_buf_get_claim(&sh_uart->tx_ringbuf, (uint8_t **)&data, + sh_uart->tx_ringbuf.size); if (len) { int err; len = uart_fifo_fill(dev, data, len); - err = ring_buf_get_finish(sh_uart->tx_ringbuf, len); + err = ring_buf_get_finish(&sh_uart->tx_ringbuf, len); __ASSERT_NO_MSG(err == 0); ARG_UNUSED(err); } else { uart_irq_tx_disable(dev); - sh_uart->ctrl_blk->tx_busy = 0; + sh_uart->tx_busy = 0; } - sh_uart->ctrl_blk->handler(SHELL_TRANSPORT_EVT_TX_RDY, - sh_uart->ctrl_blk->context); + sh_uart->common.handler(SHELL_TRANSPORT_EVT_TX_RDY, sh_uart->common.context); } static void uart_callback(const struct device *dev, void *user_data) { - const struct shell_uart *sh_uart = (struct shell_uart *)user_data; + struct shell_uart_int_driven *sh_uart = (struct shell_uart_int_driven *)user_data; uart_irq_update(dev); @@ -179,80 +266,135 @@ static void uart_callback(const struct device *dev, void *user_data) uart_tx_handle(dev, sh_uart); } } -#endif /* CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN */ -static void uart_irq_init(const struct shell_uart *sh_uart) +static void irq_init(struct shell_uart_int_driven *sh_uart) { -#ifdef CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN - const struct device *dev = sh_uart->ctrl_blk->dev; + const struct device *dev = sh_uart->common.dev; - ring_buf_reset(sh_uart->tx_ringbuf); - ring_buf_reset(sh_uart->rx_ringbuf); - sh_uart->ctrl_blk->tx_busy = 0; + ring_buf_init(&sh_uart->rx_ringbuf, CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE, + rx_ringbuf_data); + ring_buf_init(&sh_uart->tx_ringbuf, CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE, + tx_ringbuf_data); + sh_uart->tx_busy = 0; uart_irq_callback_user_data_set(dev, uart_callback, (void *)sh_uart); uart_irq_rx_enable(dev); if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_CHECK_DTR)) { - k_timer_init(sh_uart->dtr_timer, dtr_timer_handler, NULL); - k_timer_user_data_set(sh_uart->dtr_timer, (void *)sh_uart); + k_timer_init(&sh_uart->dtr_timer, dtr_timer_handler, NULL); + k_timer_user_data_set(&sh_uart->dtr_timer, (void *)sh_uart); } -#endif } -static void timer_handler(struct k_timer *timer) +static int rx_enable(const struct device *dev, uint8_t *buf, size_t len) +{ + return uart_rx_enable(dev, buf, len, 10000); +} + +static void async_init(struct shell_uart_async *sh_uart) +{ + static const struct uart_async_rx_config async_rx_config = { + .buffer = async_rx_data, + .length = sizeof(async_rx_data), + .buf_cnt = CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT + }; + const struct device *dev = sh_uart->common.dev; + struct uart_async_rx *async_rx = &sh_uart->async_rx; + int err; + + k_sem_init(&sh_uart->tx_sem, 0, 1); + + err = uart_async_rx_init(async_rx, &async_rx_config); + (void)err; + __ASSERT_NO_MSG(err == 0); + + uint8_t *buf = uart_async_rx_buf_req(async_rx); + + err = uart_callback_set(dev, async_callback, (void *)sh_uart); + (void)err; + __ASSERT_NO_MSG(err == 0); + + err = rx_enable(dev, buf, uart_async_rx_get_buf_len(async_rx)); + (void)err; + __ASSERT_NO_MSG(err == 0); +} + +static void polling_rx_timeout_handler(struct k_timer *timer) { uint8_t c; - const struct shell_uart *sh_uart = k_timer_user_data_get(timer); + struct shell_uart_polling *sh_uart = k_timer_user_data_get(timer); - while (uart_poll_in(sh_uart->ctrl_blk->dev, &c) == 0) { - if (ring_buf_put(sh_uart->rx_ringbuf, &c, 1) == 0U) { + while (uart_poll_in(sh_uart->common.dev, &c) == 0) { + if (ring_buf_put(&sh_uart->rx_ringbuf, &c, 1) == 0U) { /* ring buffer full. */ LOG_WRN("RX ring buffer full."); } - sh_uart->ctrl_blk->handler(SHELL_TRANSPORT_EVT_RX_RDY, - sh_uart->ctrl_blk->context); + sh_uart->common.handler(SHELL_TRANSPORT_EVT_RX_RDY, sh_uart->common.context); } } +static void polling_init(struct shell_uart_polling *sh_uart) +{ + k_timer_init(&sh_uart->rx_timer, polling_rx_timeout_handler, NULL); + k_timer_user_data_set(&sh_uart->rx_timer, (void *)sh_uart); + k_timer_start(&sh_uart->rx_timer, RX_POLL_PERIOD, RX_POLL_PERIOD); + + ring_buf_init(&sh_uart->rx_ringbuf, CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE, + rx_ringbuf_data); +} + static int init(const struct shell_transport *transport, const void *config, shell_transport_handler_t evt_handler, void *context) { - const struct shell_uart *sh_uart = (struct shell_uart *)transport->ctx; + struct shell_uart_common *common = (struct shell_uart_common *)transport->ctx; - sh_uart->ctrl_blk->dev = (const struct device *)config; - sh_uart->ctrl_blk->handler = evt_handler; - sh_uart->ctrl_blk->context = context; + common->dev = (const struct device *)config; + common->handler = evt_handler; + common->context = context; #ifdef CONFIG_MCUMGR_TRANSPORT_SHELL - sh_uart->ctrl_blk->smp.buf_pool = &smp_shell_rx_pool; - k_fifo_init(&sh_uart->ctrl_blk->smp.buf_ready); + common->smp.buf_pool = &smp_shell_rx_pool; + k_fifo_init(&common->smp.buf_ready); #endif - if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN)) { - uart_irq_init(sh_uart); + if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_ASYNC)) { + async_init((struct shell_uart_async *)transport->ctx); + } else if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN)) { + irq_init((struct shell_uart_int_driven *)transport->ctx); } else { - k_timer_init(sh_uart->timer, timer_handler, NULL); - k_timer_user_data_set(sh_uart->timer, (void *)sh_uart); - k_timer_start(sh_uart->timer, RX_POLL_PERIOD, RX_POLL_PERIOD); + polling_init((struct shell_uart_polling *)transport->ctx); } return 0; } -static int uninit(const struct shell_transport *transport) +static void irq_uninit(struct shell_uart_int_driven *sh_uart) { - const struct shell_uart *sh_uart = (struct shell_uart *)transport->ctx; + const struct device *dev = sh_uart->common.dev; - if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN)) { - const struct device *dev = sh_uart->ctrl_blk->dev; + k_timer_stop(&sh_uart->dtr_timer); + uart_irq_tx_disable(dev); + uart_irq_rx_disable(dev); +} - k_timer_stop(sh_uart->dtr_timer); - uart_irq_tx_disable(dev); - uart_irq_rx_disable(dev); +static void async_uninit(struct shell_uart_async *sh_uart) +{ +} + +static void polling_uninit(struct shell_uart_polling *sh_uart) +{ + k_timer_stop(&sh_uart->rx_timer); +} + +static int uninit(const struct shell_transport *transport) +{ + if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_ASYNC)) { + async_uninit((struct shell_uart_async *)transport->ctx); + } else if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN)) { + irq_uninit((struct shell_uart_int_driven *)transport->ctx); } else { - k_timer_stop(sh_uart->timer); + polling_uninit((struct shell_uart_polling *)transport->ctx); } return 0; @@ -260,70 +402,161 @@ static int uninit(const struct shell_transport *transport) static int enable(const struct shell_transport *transport, bool blocking_tx) { - const struct shell_uart *sh_uart = (struct shell_uart *)transport->ctx; + struct shell_uart_common *sh_uart = (struct shell_uart_common *)transport->ctx; - sh_uart->ctrl_blk->blocking_tx = blocking_tx; + sh_uart->blocking_tx = blocking_tx; - if (blocking_tx) { -#ifdef CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN - uart_irq_tx_disable(sh_uart->ctrl_blk->dev); -#endif + if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN) && blocking_tx) { + uart_irq_tx_disable(sh_uart->dev); } return 0; } -static void irq_write(const struct shell_uart *sh_uart, const void *data, - size_t length, size_t *cnt) +static int polling_write(struct shell_uart_common *sh_uart, + const void *data, size_t length, size_t *cnt) { - *cnt = ring_buf_put(sh_uart->tx_ringbuf, data, length); + const uint8_t *data8 = (const uint8_t *)data; - if (atomic_set(&sh_uart->ctrl_blk->tx_busy, 1) == 0) { -#ifdef CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN - uart_irq_tx_enable(sh_uart->ctrl_blk->dev); -#endif + for (size_t i = 0; i < length; i++) { + uart_poll_out(sh_uart->dev, data8[i]); } + + *cnt = length; + + sh_uart->handler(SHELL_TRANSPORT_EVT_TX_RDY, sh_uart->context); + + return 0; +} + +static int irq_write(struct shell_uart_int_driven *sh_uart, + const void *data, size_t length, size_t *cnt) +{ + *cnt = ring_buf_put(&sh_uart->tx_ringbuf, data, length); + + if (atomic_set(&sh_uart->tx_busy, 1) == 0) { + uart_irq_tx_enable(sh_uart->common.dev); + } + + return 0; +} + +static int async_write(struct shell_uart_async *sh_uart, + const void *data, size_t length, size_t *cnt) +{ + int err; + + err = uart_tx(sh_uart->common.dev, data, length, SYS_FOREVER_US); + if (err < 0) { + *cnt = 0; + return err; + } + + err = k_sem_take(&sh_uart->tx_sem, K_FOREVER); + *cnt = length; + + sh_uart->common.handler(SHELL_TRANSPORT_EVT_TX_RDY, sh_uart->common.context); + + return err; } static int write(const struct shell_transport *transport, const void *data, size_t length, size_t *cnt) { - const struct shell_uart *sh_uart = (struct shell_uart *)transport->ctx; - const uint8_t *data8 = (const uint8_t *)data; + struct shell_uart_common *sh_uart = (struct shell_uart_common *)transport->ctx; - if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN) && - !sh_uart->ctrl_blk->blocking_tx) { - irq_write(sh_uart, data, length, cnt); + if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_POLLING) || sh_uart->blocking_tx) { + return polling_write(sh_uart, data, length, cnt); + } else if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN)) { + return irq_write((struct shell_uart_int_driven *)transport->ctx, data, length, cnt); } else { - for (size_t i = 0; i < length; i++) { - uart_poll_out(sh_uart->ctrl_blk->dev, data8[i]); - } + return async_write((struct shell_uart_async *)transport->ctx, data, length, cnt); + } +} - *cnt = length; +static int irq_read(struct shell_uart_int_driven *sh_uart, + void *data, size_t length, size_t *cnt) +{ + *cnt = ring_buf_get(&sh_uart->rx_ringbuf, data, length); - sh_uart->ctrl_blk->handler(SHELL_TRANSPORT_EVT_TX_RDY, - sh_uart->ctrl_blk->context); - } + return 0; +} + +static int polling_read(struct shell_uart_polling *sh_uart, + void *data, size_t length, size_t *cnt) +{ + *cnt = ring_buf_get(&sh_uart->rx_ringbuf, data, length); return 0; } -static int read(const struct shell_transport *transport, - void *data, size_t length, size_t *cnt) +static int async_read(struct shell_uart_async *sh_uart, + void *data, size_t length, size_t *cnt) { - struct shell_uart *sh_uart = (struct shell_uart *)transport->ctx; + uint8_t *buf; + size_t blen; + struct uart_async_rx *async_rx = &sh_uart->async_rx; + + blen = uart_async_rx_data_claim(async_rx, &buf, length); +#ifdef CONFIG_MCUMGR_TRANSPORT_SHELL + struct smp_shell_data *const smp = &sh_uart->common.smp; + size_t sh_cnt = 0; + + for (size_t i = 0; i < blen; i++) { + if (smp_shell_rx_bytes(smp, &buf[i], 1) == 0) { + data[sh_cnt++] = buf[i]; + } + } +#else + size_t sh_cnt = blen; - *cnt = ring_buf_get(sh_uart->rx_ringbuf, data, length); + memcpy(data, buf, blen); +#endif + uart_async_rx_data_consume(async_rx, sh_cnt); + *cnt = sh_cnt; + + if (sh_uart->pending_rx_req) { + uint8_t *buf = uart_async_rx_buf_req(async_rx); + + if (buf) { + int err; + size_t len = uart_async_rx_get_buf_len(async_rx); + + atomic_dec(&sh_uart->pending_rx_req); + err = uart_rx_buf_rsp(sh_uart->common.dev, buf, len); + /* If it is too late and RX is disabled then re-enable it. */ + if (err < 0) { + if (err == -EACCES) { + sh_uart->pending_rx_req = 0; + err = rx_enable(sh_uart->common.dev, buf, len); + } else { + return err; + } + } + } + } return 0; } +static int read(const struct shell_transport *transport, + void *data, size_t length, size_t *cnt) +{ + if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN)) { + return irq_read((struct shell_uart_int_driven *)transport->ctx, data, length, cnt); + } else if (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_ASYNC)) { + return async_read((struct shell_uart_async *)transport->ctx, data, length, cnt); + } else { + return polling_read((struct shell_uart_polling *)transport->ctx, data, length, cnt); + } +} + #ifdef CONFIG_MCUMGR_TRANSPORT_SHELL static void update(const struct shell_transport *transport) { - struct shell_uart *sh_uart = (struct shell_uart *)transport->ctx; + struct shell_uart_common *sh_uart = (struct shell_uart_common *)transport->ctx; - smp_shell_process(&sh_uart->ctrl_blk->smp); + smp_shell_process(&sh_uart->smp); } #endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ @@ -338,6 +571,18 @@ const struct shell_transport_api shell_uart_transport_api = { #endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ }; +struct shell_transport shell_transport_uart = { + .api = &shell_uart_transport_api, + .ctx = IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_POLLING) ? (void *)&shell_uart_p : + (IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL_API_ASYNC) ? (void *)&shell_uart_a : + (void *)&shell_uart_i) +}; + +SHELL_DEFINE(shell_uart, CONFIG_SHELL_PROMPT_UART, &shell_transport_uart, + CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_SIZE, + CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_TIMEOUT, + SHELL_FLAG_OLF_CRLF); + static int enable_shell_uart(void) { const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart)); From 8b98acb77b764d2909b25832e435b414f6c36d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 25 Oct 2023 18:39:59 +0200 Subject: [PATCH 0330/1049] boards: esp32: Add support for M5Stack AtomS3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces support for the ESP32S3 based M5Stack AtomS3. Signed-off-by: Benjamin Cabé --- boards/xtensa/m5stack_atoms3/Kconfig.board | 12 ++ .../xtensa/m5stack_atoms3/Kconfig.defconfig | 29 +++ boards/xtensa/m5stack_atoms3/board.cmake | 9 + .../doc/img/m5stack_atoms3.webp | Bin 0 -> 20380 bytes boards/xtensa/m5stack_atoms3/doc/index.rst | 136 +++++++++++++ .../m5stack_atoms3/grove_connectors.dtsi | 17 ++ .../m5stack_atoms3-pinctrl.dtsi | 54 +++++ .../xtensa/m5stack_atoms3/m5stack_atoms3.dts | 186 ++++++++++++++++++ .../xtensa/m5stack_atoms3/m5stack_atoms3.yaml | 21 ++ .../m5stack_atoms3/m5stack_atoms3_defconfig | 13 ++ 10 files changed, 477 insertions(+) create mode 100644 boards/xtensa/m5stack_atoms3/Kconfig.board create mode 100644 boards/xtensa/m5stack_atoms3/Kconfig.defconfig create mode 100644 boards/xtensa/m5stack_atoms3/board.cmake create mode 100644 boards/xtensa/m5stack_atoms3/doc/img/m5stack_atoms3.webp create mode 100644 boards/xtensa/m5stack_atoms3/doc/index.rst create mode 100644 boards/xtensa/m5stack_atoms3/grove_connectors.dtsi create mode 100644 boards/xtensa/m5stack_atoms3/m5stack_atoms3-pinctrl.dtsi create mode 100644 boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts create mode 100644 boards/xtensa/m5stack_atoms3/m5stack_atoms3.yaml create mode 100644 boards/xtensa/m5stack_atoms3/m5stack_atoms3_defconfig diff --git a/boards/xtensa/m5stack_atoms3/Kconfig.board b/boards/xtensa/m5stack_atoms3/Kconfig.board new file mode 100644 index 000000000000000..726e31773e223fa --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/Kconfig.board @@ -0,0 +1,12 @@ +# M5Stack AtomS3 board configuration + +# Copyright (c) 2023 Benjamin Cabé +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_M5STACK_ATOMS3 + bool "M5Stack AtomS3 Development Board" + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_FN8 +endchoice diff --git a/boards/xtensa/m5stack_atoms3/Kconfig.defconfig b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig new file mode 100644 index 000000000000000..b9bd2641458f886 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig @@ -0,0 +1,29 @@ +# M5Stack AtomS3 board configuration +# Copyright (c) 2023 Benjamin Cabé +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_M5STACK_ATOMS3 + +config BOARD + default "m5stack_atoms3" + depends on BOARD_M5STACK_ATOMS3 + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_SIZE + default 98304 if WIFI + default 65536 if BT + default 4096 + +config KERNEL_MEM_POOL + default y + +choice BT_HCI_BUS_TYPE + default BT_ESP32 if BT +endchoice + +config LV_COLOR_16_SWAP + default y if LVGL + +endif # BOARD_M5STACK_ATOMS3 diff --git a/boards/xtensa/m5stack_atoms3/board.cmake b/boards/xtensa/m5stack_atoms3/board.cmake new file mode 100644 index 000000000000000..2f04d1fe8861ea6 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/m5stack_atoms3/doc/img/m5stack_atoms3.webp b/boards/xtensa/m5stack_atoms3/doc/img/m5stack_atoms3.webp new file mode 100644 index 0000000000000000000000000000000000000000..b4b964069b4159da55ee04a2a0c113a2bb24be9d GIT binary patch literal 20380 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 Tk0jSdS{ni>0fYd=_3!-;A|r<= literal 0 HcmV?d00001 diff --git a/boards/xtensa/m5stack_atoms3/doc/index.rst b/boards/xtensa/m5stack_atoms3/doc/index.rst new file mode 100644 index 000000000000000..2dd229be436455c --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/doc/index.rst @@ -0,0 +1,136 @@ +.. _m5stack_atoms3: + +M5Stack AtomS3 +############## + +Overview +******** + +M5Stack AtomS3 is an ESP32-based development board from M5Stack. + +It features the following integrated components: + +- ESP32-S3FN8 chip (240MHz dual core, Wi-Fi/BLE 5.0) +- 512KB of SRAM +- 384KB of ROM +- 8MB of Flash +- LCD IPS TFT 0.85", 128x128 px screen (ST7789 compatible) +- 6-axis IMU MPU6886 +- Infrared emitter + + +.. figure:: img/m5stack_atoms3.webp + :align: center + :alt: M5Stack AtomS3 + + M5Stack AtomS3 + + +Supported Features +================== + +The Zephyr m5stack_atoms3 board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | reset and clock control | ++-----------+------------+-------------------------------------+ +| COUNTER | on-chip | rtc | ++-----------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ +| DAC | on-chip | dac | ++-----------+------------+-------------------------------------+ +| die-temp | on-chip | die temperature sensor | ++-----------+------------+-------------------------------------+ + + +Start Application Development +***************************** + +Before powering up your M5Stack AtomS3, please make sure that the board is in good +condition with no obvious signs of damage. + +System requirements +=================== + +Prerequisites +------------- + +Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command +below to retrieve those files. + +.. code-block:: shell + + west blobs fetch hal_espressif + +.. note:: + + It is recommended running the command above after :file:`west update`. + +Building & Flashing +------------------- + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: m5stack_atoms3 + :goals: build + +The usual ``flash`` target will work with the ``m5stack_atoms3`` board +configuration. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: m5stack_atoms3 + :goals: flash + +The baud rate of 921600bps is set by default. If experiencing issues when flashing, +try using different values by using ``--esp-baud-rate `` option during +``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). + +You can also open the serial monitor using the following command: + +.. code-block:: shell + + west espressif monitor + +After the board has automatically reset and booted, you should see the following +message in the monitor: + +.. code-block:: console + + ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** + Hello World! m5stack_atoms3 + +Debugging +--------- + +M5Stack AtomS3 debugging is not supported due to pinout limitations. + +Related Documents +***************** + +- `M5Stack AtomS3 schematic `_ +- `ESP32S3 Datasheet `_ diff --git a/boards/xtensa/m5stack_atoms3/grove_connectors.dtsi b/boards/xtensa/m5stack_atoms3/grove_connectors.dtsi new file mode 100644 index 000000000000000..798c40cf2961daa --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/grove_connectors.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + grove_header: grove_header { + compatible = "grove-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 1 0>, + <1 0 &gpio0 2 0>; + }; +}; + +grove_i2c1: &i2c1 {}; diff --git a/boards/xtensa/m5stack_atoms3/m5stack_atoms3-pinctrl.dtsi b/boards/xtensa/m5stack_atoms3/m5stack_atoms3-pinctrl.dtsi new file mode 100644 index 000000000000000..0f59b0bc6a82520 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3-pinctrl.dtsi @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * + * SPDX-License-Identifier: Apache-2.0 + */ + + #include + #include + #include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , + ; + }; + group2 { + pinmux = ; + output-low; + }; + + }; +}; diff --git a/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts new file mode 100644 index 000000000000000..abbff8bbbfdab46 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "m5stack_atoms3-pinctrl.dtsi" +#include "grove_connectors.dtsi" +#include + +/ { + model = "M5Stack AtomS3"; + compatible = "m5stack,atoms3"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &usb_serial; + zephyr,shell-uart = &usb_serial; + zephyr,flash = &flash0; + zephyr,display = &st7789v; + }; + + aliases { + sw0 = &user_button_0; + watchdog0 = &wdt0; + accel0 = &mpu6886; + }; + + gpio_keys { + compatible = "gpio-keys"; + + /* This is the button that's underneath the LCD display */ + user_button_0: button_0 { + label = "User button 0"; + gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; // G42 + zephyr,code = ; + }; + }; + + /* Regulators */ + lcd_backlight_en { + compatible = "regulator-fixed"; + regulator-name = "lcd_backlight_enable"; + enable-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; + +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&usb_serial { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; + + mpu6886: mpu6886@68 { + compatible = "invensense,mpu6050"; + reg = <0x68>; + status = "okay"; + }; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&trng0 { + status = "okay"; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; + + st7789v: st7789v@0 { + compatible = "sitronix,st7789v"; + reg = <0>; + spi-max-frequency = <27000000>; + cmd-data-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; /* G33 */ + reset-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; /* G34 */ + + width = <128>; + height = <128>; + x-offset = <2>; + y-offset = <1>; + + vcom = <0x28>; + gctrl = <0x35>; + vrhs = <0x10>; + vdvs = <0x20>; + mdac = <0x00>; + gamma = <0x01>; + colmod = <0x55>; + lcm = <0x0c>; + porch-param = [0c 0c 00 33 33]; + cmd2en-param = [5a 69 02 00]; + pwctrl1-param = [a4 a1]; + pvgam-param = [d0 00 02 07 0a 28 32 44 42 06 0e 12 14 17]; + nvgam-param = [d0 00 02 07 0a 28 31 54 47 0e 1c 17 1b 1e]; + ram-param = [00 E0]; + rgb-param = [40 02 14]; + }; + +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000F000>; + read-only; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/m5stack_atoms3/m5stack_atoms3.yaml b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.yaml new file mode 100644 index 000000000000000..ed34b2f551d7d6f --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.yaml @@ -0,0 +1,21 @@ +identifier: m5stack_atoms3 +name: M5Stack AtomS3 +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - spi + - watchdog + - regulator + - uart + - pinmux + - nvs + - display +testing: + ignore_tags: + - net + - bluetooth +vendor: m5stack diff --git a/boards/xtensa/m5stack_atoms3/m5stack_atoms3_defconfig b/boards/xtensa/m5stack_atoms3/m5stack_atoms3_defconfig new file mode 100644 index 000000000000000..1000271dbe584bd --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3_defconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_M5STACK_ATOMS3=y +CONFIG_SOC_SERIES_ESP32S3=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_GPIO=y +CONFIG_REGULATOR=y # for LCD backlight + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y From 1fbcccd2fc0325c13e8f133a717d09c921444e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 10 Nov 2023 10:14:17 +0100 Subject: [PATCH 0331/1049] boards: xtensa: Set M5Stack vendor for M5Stack boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit s/espressif/extensa/ for the couple M5Stack boards in-tree that had the wrong vendor set. Signed-off-by: Benjamin Cabé --- boards/xtensa/m5stack_core2/m5stack_core2.dts | 4 ++-- boards/xtensa/m5stack_core2/m5stack_core2.yaml | 2 +- boards/xtensa/m5stickc_plus/m5stickc_plus.dts | 4 ++-- boards/xtensa/m5stickc_plus/m5stickc_plus.yaml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/boards/xtensa/m5stack_core2/m5stack_core2.dts b/boards/xtensa/m5stack_core2/m5stack_core2.dts index 5fb6f0cc495d8d5..41ccb5be0746a06 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2.dts +++ b/boards/xtensa/m5stack_core2/m5stack_core2.dts @@ -13,8 +13,8 @@ #include / { - model = "esp32"; - compatible = "espressif,esp32"; + model = "M5Stack Core2"; + compatible = "m5stack,core2"; aliases { pwr-led = &pwr_led; diff --git a/boards/xtensa/m5stack_core2/m5stack_core2.yaml b/boards/xtensa/m5stack_core2/m5stack_core2.yaml index 35dd0c12b461e49..78b361e8834205f 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2.yaml +++ b/boards/xtensa/m5stack_core2/m5stack_core2.yaml @@ -17,4 +17,4 @@ testing: ignore_tags: - net - bluetooth -vendor: espressif +vendor: m5stack diff --git a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts index 0254d82003d0f72..8cdd4170ba5ebd0 100644 --- a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts +++ b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts @@ -10,8 +10,8 @@ #include / { - model = "esp32"; - compatible = "espressif,esp32"; + model = "M5StickC Plus"; + compatible = "m5stack,m5stickc-plus"; aliases { led0 = &red_led; diff --git a/boards/xtensa/m5stickc_plus/m5stickc_plus.yaml b/boards/xtensa/m5stickc_plus/m5stickc_plus.yaml index dbd09151be1df54..821770c2be4410d 100644 --- a/boards/xtensa/m5stickc_plus/m5stickc_plus.yaml +++ b/boards/xtensa/m5stickc_plus/m5stickc_plus.yaml @@ -16,4 +16,4 @@ testing: ignore_tags: - net - bluetooth -vendor: espressif +vendor: m5stack From 78714b193a56182998dd8c0a6c4415b16d79d819 Mon Sep 17 00:00:00 2001 From: Lars Knudsen Date: Tue, 31 Oct 2023 07:56:12 +0100 Subject: [PATCH 0332/1049] samples: Add USB Audio to broadcast audio source Adds support for using a connected host to broadcast audio via USB Audio. Offload LC3 encoding to separate thread. Signed-off-by: Lars Knudsen --- .../bluetooth/broadcast_audio_source/Kconfig | 9 + .../nrf5340_audio_dk_nrf5340_cpuapp.conf | 10 +- .../boards/nrf5340dk_nrf5340_cpuapp.conf | 3 - .../bluetooth/broadcast_audio_source/prj.conf | 2 - .../broadcast_audio_source/src/main.c | 353 ++++++++++++++---- 5 files changed, 297 insertions(+), 80 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_source/Kconfig b/samples/bluetooth/broadcast_audio_source/Kconfig index cc3e714ded74939..d88378d08488ac7 100644 --- a/samples/bluetooth/broadcast_audio_source/Kconfig +++ b/samples/bluetooth/broadcast_audio_source/Kconfig @@ -28,4 +28,13 @@ config ENABLE_LC3 select LIBLC3 select FPU +config USE_USB_AUDIO_INPUT + bool "Use USB Audio as input" + # By default, use the USB Audio path is disabled. + default n + depends on ENABLE_LC3 + select USB_DEVICE_STACK + select USB_DEVICE_AUDIO + select RING_BUFFER + source "Kconfig.zephyr" diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index 8d28a7031d23590..ff8004f0dc050e1 100644 --- a/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -1,4 +1,8 @@ -# The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence -# inctease stack size for that thread. -CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 CONFIG_MAIN_STACK_SIZE=4096 + +# Use USB Audio as input +CONFIG_USE_USB_AUDIO_INPUT=y +CONFIG_USB_DEVICE_PRODUCT="Zephyr Broadcast Source" + +# Two streams in one subgroup (stereo) +CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf5340dk_nrf5340_cpuapp.conf index 8d28a7031d23590..5df721fba267419 100644 --- a/samples/bluetooth/broadcast_audio_source/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -1,4 +1 @@ -# The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence -# inctease stack size for that thread. -CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 CONFIG_MAIN_STACK_SIZE=4096 diff --git a/samples/bluetooth/broadcast_audio_source/prj.conf b/samples/bluetooth/broadcast_audio_source/prj.conf index 2e0fcb778de6c3a..d74cbbe50ce46bd 100644 --- a/samples/bluetooth/broadcast_audio_source/prj.conf +++ b/samples/bluetooth/broadcast_audio_source/prj.conf @@ -13,5 +13,3 @@ CONFIG_BT_ISO_TX_BUF_COUNT=4 CONFIG_BT_ISO_TX_MTU=60 CONFIG_BT_DEVICE_NAME="Broadcast Audio Source" - -CONFIG_BT_TINYCRYPT_ECC=y diff --git a/samples/bluetooth/broadcast_audio_source/src/main.c b/samples/bluetooth/broadcast_audio_source/src/main.c index f9a2a5330b28982..8a129e3f3619301 100644 --- a/samples/bluetooth/broadcast_audio_source/src/main.c +++ b/samples/bluetooth/broadcast_audio_source/src/main.c @@ -35,19 +35,93 @@ BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, #if defined(CONFIG_BAP_BROADCAST_16_2_1) static struct bt_bap_lc3_preset preset_active = BT_BAP_LC3_BROADCAST_PRESET_16_2_1( - BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT, + BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + +#define BROADCAST_SAMPLE_RATE 16000 #elif defined(CONFIG_BAP_BROADCAST_24_2_1) static struct bt_bap_lc3_preset preset_active = BT_BAP_LC3_BROADCAST_PRESET_24_2_1( - BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT, + BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + +#define BROADCAST_SAMPLE_RATE 24000 + +#endif +#if defined(CONFIG_BAP_BROADCAST_16_2_1) +#define MAX_SAMPLE_RATE 16000 +#elif defined(CONFIG_BAP_BROADCAST_24_2_1) +#define MAX_SAMPLE_RATE 24000 #endif +#define MAX_FRAME_DURATION_US 10000 +#define MAX_NUM_SAMPLES ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC) + +#if defined(CONFIG_LIBLC3) +#include "lc3.h" + +#if defined(CONFIG_USB_DEVICE_AUDIO) +#include +#include +#include + +/* USB Audio Data is downsampled from 48kHz to match broadcast preset when receiving data */ +#define USB_SAMPLE_RATE 48000 +#define USB_DOWNSAMPLE_RATE BROADCAST_SAMPLE_RATE +#define USB_FRAME_DURATION_US 1000 +#define USB_NUM_SAMPLES ((USB_FRAME_DURATION_US * USB_DOWNSAMPLE_RATE) / USEC_PER_SEC) +#define USB_BYTES_PER_SAMPLE 2 +#define USB_CHANNELS 2 + +#define RING_BUF_USB_FRAMES 20 +#define AUDIO_RING_BUF_BYTES USB_NUM_SAMPLES * USB_BYTES_PER_SAMPLE * RING_BUF_USB_FRAMES +#else /* !defined(CONFIG_USB_DEVICE_AUDIO) */ + +#include + +#define AUDIO_VOLUME (INT16_MAX - 3000) /* codec does clipping above INT16_MAX - 3000 */ +#define AUDIO_TONE_FREQUENCY_HZ 400 + +/** + * Use the math lib to generate a sine-wave using 16 bit samples into a buffer. + * + * @param buf Destination buffer + * @param length_us Length of the buffer in microseconds + * @param frequency_hz frequency in Hz + * @param sample_rate_hz sample-rate in Hz. + */ +static void fill_audio_buf_sin(int16_t *buf, int length_us, int frequency_hz, int sample_rate_hz) +{ + const int sine_period_samples = sample_rate_hz / frequency_hz; + const unsigned int num_samples = (length_us * sample_rate_hz) / USEC_PER_SEC; + const float step = 2 * 3.1415f / sine_period_samples; + + for (unsigned int i = 0; i < num_samples; i++) { + const float sample = sin(i * step); + + buf[i] = (int16_t)(AUDIO_VOLUME * sample); + } +} +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ +#endif /* defined(CONFIG_LIBLC3) */ static struct broadcast_source_stream { struct bt_bap_stream stream; uint16_t seq_num; size_t sent_cnt; +#if defined(CONFIG_LIBLC3) + lc3_encoder_t lc3_encoder; +#if defined(CONFIG_BAP_BROADCAST_16_2_1) + lc3_encoder_mem_16k_t lc3_encoder_mem; +#elif defined(CONFIG_BAP_BROADCAST_24_2_1) + lc3_encoder_mem_48k_t lc3_encoder_mem; +#endif +#if defined(CONFIG_USB_DEVICE_AUDIO) + struct ring_buf audio_ring_buf; + uint8_t _ring_buffer_memory[AUDIO_RING_BUF_BYTES]; +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ +#endif /* defined(CONFIG_LIBLC3) */ } streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; static struct bt_bap_broadcast_source *broadcast_source; @@ -55,10 +129,8 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); -#define MAX_SAMPLE_RATE 16000 -#define MAX_FRAME_DURATION_US 10000 -#define MAX_NUM_SAMPLES ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC) -static int16_t mock_data[MAX_NUM_SAMPLES]; + +static int16_t send_pcm_data[MAX_NUM_SAMPLES]; static uint16_t seq_num; static bool stopping; @@ -68,17 +140,80 @@ static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams)); #define BROADCAST_SOURCE_LIFETIME 120U /* seconds */ #if defined(CONFIG_LIBLC3) - -#include "lc3.h" - -static lc3_encoder_t lc3_encoder; -static lc3_encoder_mem_16k_t lc3_encoder_mem; static int freq_hz; static int frame_duration_us; static int frames_per_sdu; static int octets_per_frame; -static void init_lc3(void) +static K_SEM_DEFINE(lc3_encoder_sem, 0U, ARRAY_SIZE(streams)); +#endif + +static void send_data(struct broadcast_source_stream *source_stream) +{ + struct bt_bap_stream *stream = &source_stream->stream; + struct net_buf *buf; + int ret; + + if (stopping) { + return; + } + + buf = net_buf_alloc(&tx_pool, K_FOREVER); + if (buf == NULL) { + printk("Could not allocate buffer when sending on %p\n", + stream); + return; + } + + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); +#if defined(CONFIG_LIBLC3) + uint8_t lc3_encoded_buffer[preset_active.qos.sdu]; + + if (source_stream->lc3_encoder == NULL) { + printk("LC3 encoder not setup, cannot encode data.\n"); + return; + } + +#if defined(CONFIG_USB_DEVICE_AUDIO) + uint32_t size = ring_buf_get(&source_stream->audio_ring_buf, + (uint8_t *)send_pcm_data, sizeof(send_pcm_data)); + + if (size < sizeof(send_pcm_data)) { + const size_t padding_size = sizeof(send_pcm_data) - size; + + printk("Not enough bytes ready, padding %d!\n", padding_size); + memset(&((uint8_t *)send_pcm_data)[size], 0, padding_size); + } +#endif + + ret = lc3_encode(source_stream->lc3_encoder, LC3_PCM_FORMAT_S16, + send_pcm_data, 1, octets_per_frame, lc3_encoded_buffer); + if (ret == -1) { + printk("LC3 encoder failed - wrong parameters?: %d", ret); + return; + } + + net_buf_add_mem(buf, lc3_encoded_buffer, preset_active.qos.sdu); +#else + net_buf_add_mem(buf, send_pcm_data, preset_active.qos.sdu); +#endif /* defined(CONFIG_LIBLC3) */ + + ret = bt_bap_stream_send(stream, buf, source_stream->seq_num++, BT_ISO_TIMESTAMP_NONE); + if (ret < 0) { + /* This will end broadcasting on this stream. */ + printk("Unable to broadcast data on %p: %d\n", stream, ret); + net_buf_unref(buf); + return; + } + + source_stream->sent_cnt++; + if ((source_stream->sent_cnt % 1000U) == 0U) { + printk("Stream %p: Sent %u total ISO packets\n", stream, source_stream->sent_cnt); + } +} + +#if defined(CONFIG_LIBLC3) +static void init_lc3_thread(void *arg1, void *arg2, void *arg3) { const struct bt_audio_codec_cfg *codec_cfg = &preset_active.codec_cfg; int ret; @@ -116,14 +251,95 @@ static void init_lc3(void) return; } +#if !defined(CONFIG_USB_DEVICE_AUDIO) + /* If USB is not used as a sound source, generate a sine wave */ + fill_audio_buf_sin(send_pcm_data, frame_duration_us, AUDIO_TONE_FREQUENCY_HZ, freq_hz); +#endif + /* Create the encoder instance. This shall complete before stream_started() is called. */ - lc3_encoder = lc3_setup_encoder(frame_duration_us, freq_hz, 0, /* No resampling */ - &lc3_encoder_mem); + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + printk("Initializing lc3 encoder for stream %zu\n", i); + streams[i].lc3_encoder = lc3_setup_encoder(frame_duration_us, freq_hz, + 0, &streams[i].lc3_encoder_mem); - if (lc3_encoder == NULL) { - printk("ERROR: Failed to setup LC3 encoder - wrong parameters?\n"); + if (streams[i].lc3_encoder == NULL) { + printk("ERROR: Failed to setup LC3 encoder - wrong parameters?\n"); + } + } + + while (true) { + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + k_sem_take(&lc3_encoder_sem, K_FOREVER); + } + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + send_data(&streams[i]); + } } } + +#define LC3_ENCODER_STACK_SIZE 4 * 4096 +#define LC3_ENCODER_PRIORITY 5 + +K_THREAD_DEFINE(encoder, LC3_ENCODER_STACK_SIZE, init_lc3_thread, + NULL, NULL, NULL, LC3_ENCODER_PRIORITY, 0, -1); + +#if defined(CONFIG_USB_DEVICE_AUDIO) +static void data_received(const struct device *dev, + struct net_buf *buffer, + size_t size) +{ + static int count; + int16_t *pcm; + int nsamples, ratio; + int16_t usb_pcm_data[USB_CHANNELS][USB_NUM_SAMPLES]; + + if (!buffer) { + return; + } + + if (!size) { + net_buf_unref(buffer); + return; + } + + pcm = (int16_t *)net_buf_pull_mem(buffer, size); + + /* 'size' is in bytes, containing 1ms, 48kHz, stereo, 2 bytes per sample. + * Take left channel and do a simple downsample to 16kHz/24Khz + * matching the broadcast preset. + */ + + ratio = USB_SAMPLE_RATE / USB_DOWNSAMPLE_RATE; + nsamples = size / (sizeof(int16_t) * USB_CHANNELS * ratio); + for (size_t i = 0, j = 0; i < nsamples; i++, j += USB_CHANNELS * ratio) { + usb_pcm_data[0][i] = pcm[j]; + usb_pcm_data[1][i] = pcm[j + 1]; + } + + for (size_t i = 0U; i < MIN(ARRAY_SIZE(streams), 2); i++) { + const uint32_t size_put = ring_buf_put(&(streams[i].audio_ring_buf), + (uint8_t *)(usb_pcm_data[i]), nsamples * USB_BYTES_PER_SAMPLE); + if (size_put < nsamples * USB_BYTES_PER_SAMPLE) { + printk("Not enough room for samples in %s buffer: %u < %u, total capacity: %u\n", + i == 0 ? "left" : "right", + size_put, + nsamples * USB_BYTES_PER_SAMPLE, + ring_buf_capacity_get(&(streams[i].audio_ring_buf))); + } + } + + count++; + if ((count % 1000) == 0) { + printk("USB Data received (count = %d)\n", count); + } + + net_buf_unref(buffer); +} + +static const struct usb_audio_ops ops = { + .data_received_cb = data_received +}; +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ #endif /* defined(CONFIG_LIBLC3) */ static void stream_started_cb(struct bt_bap_stream *stream) @@ -143,57 +359,15 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) static void stream_sent_cb(struct bt_bap_stream *stream) { - struct broadcast_source_stream *source_stream = - CONTAINER_OF(stream, struct broadcast_source_stream, stream); - struct net_buf *buf; - int ret; - - if (stopping) { - return; - } - - buf = net_buf_alloc(&tx_pool, K_FOREVER); - if (buf == NULL) { - printk("Could not allocate buffer when sending on %p\n", - stream); - return; - } - - net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); #if defined(CONFIG_LIBLC3) - int lc3_ret; - uint8_t lc3_encoder_buffer[preset_active.qos.sdu]; - - if (lc3_encoder == NULL) { - printk("LC3 encoder not setup, cannot encode data.\n"); - return; - } - - lc3_ret = lc3_encode(lc3_encoder, LC3_PCM_FORMAT_S16, mock_data, 1, octets_per_frame, - lc3_encoder_buffer); - - if (lc3_ret == -1) { - printk("LC3 encoder failed - wrong parameters?: %d", lc3_ret); - return; - } - - net_buf_add_mem(buf, lc3_encoder_buffer, preset_active.qos.sdu); + k_sem_give(&lc3_encoder_sem); #else - net_buf_add_mem(buf, mock_data, preset_active.qos.sdu); -#endif /* defined(CONFIG_LIBLC3) */ - - ret = bt_bap_stream_send(stream, buf, source_stream->seq_num++, BT_ISO_TIMESTAMP_NONE); - if (ret < 0) { - /* This will end broadcasting on this stream. */ - printk("Unable to broadcast data on %p: %d\n", stream, ret); - net_buf_unref(buf); - return; - } + /* If no LC3 encoder is used, just send mock data directly */ + struct broadcast_source_stream *source_stream = + CONTAINER_OF(stream, struct broadcast_source_stream, stream); - source_stream->sent_cnt++; - if ((source_stream->sent_cnt % 1000U) == 0U) { - printk("Stream %p: Sent %u total ISO packets\n", stream, source_stream->sent_cnt); - } + send_data(source_stream); +#endif } static struct bt_bap_stream_ops stream_ops = { @@ -210,10 +384,12 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source) subgroup_param[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT]; struct bt_bap_broadcast_source_param create_param; const size_t streams_per_subgroup = ARRAY_SIZE(stream_params) / ARRAY_SIZE(subgroup_param); + uint8_t left[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_BYTES_LIST_LE32(BT_AUDIO_LOCATION_FRONT_LEFT))}; + uint8_t right[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_BYTES_LIST_LE32(BT_AUDIO_LOCATION_FRONT_RIGHT))}; int err; - (void)memset(streams, 0, sizeof(streams)); - for (size_t i = 0U; i < ARRAY_SIZE(subgroup_param); i++) { subgroup_param[i].params_count = streams_per_subgroup; subgroup_param[i].params = stream_params + i * streams_per_subgroup; @@ -222,8 +398,8 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source) for (size_t j = 0U; j < ARRAY_SIZE(stream_params); j++) { stream_params[j].stream = &streams[j].stream; - stream_params[j].data = NULL; - stream_params[j].data_len = 0U; + stream_params[j].data = j == 0 ? left : right; + stream_params[j].data_len = j == 0 ? sizeof(left) : sizeof(right); bt_bap_stream_cb_register(stream_params[j].stream, &stream_ops); } @@ -258,13 +434,43 @@ int main(void) } printk("Bluetooth initialized\n"); - for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) { + for (size_t i = 0U; i < ARRAY_SIZE(send_pcm_data); i++) { /* Initialize mock data */ - mock_data[i] = i; + send_pcm_data[i] = i; } #if defined(CONFIG_LIBLC3) - init_lc3(); +#if defined(CONFIG_USB_DEVICE_AUDIO) + const struct device *hs_dev; + + hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0)); + + if (!device_is_ready(hs_dev)) { + printk("Device USB Headset is not ready\n"); + return 0; + } + + printk("Found USB Headset Device\n"); + + (void)memset(streams, 0, sizeof(streams)); + + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + ring_buf_init(&(streams[i].audio_ring_buf), + sizeof(streams[i]._ring_buffer_memory), + streams[i]._ring_buffer_memory); + printk("Initialized ring buf %zu: capacity: %u\n", i, + ring_buf_capacity_get(&(streams[i].audio_ring_buf))); + } + + usb_audio_register(hs_dev, &ops); + + err = usb_enable(NULL); + if (err) { + printk("Failed to enable USB"); + return 0; + } +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + k_thread_start(encoder); #endif /* defined(CONFIG_LIBLC3) */ while (true) { @@ -372,10 +578,13 @@ int main(void) } } +#if defined(CONFIG_LIBLC3) && defined(CONFIG_USB_DEVICE_AUDIO) + /* Never stop streaming when using USB Audio as input */ + k_sleep(K_FOREVER); +#endif /* defined(CONFIG_LIBLC3) && defined(CONFIG_USB_DEVICE_AUDIO) */ printk("Waiting %u seconds before stopped\n", BROADCAST_SOURCE_LIFETIME); k_sleep(K_SECONDS(BROADCAST_SOURCE_LIFETIME)); - printk("Stopping broadcast source\n"); stopping = true; err = bt_bap_broadcast_source_stop(broadcast_source); From f6d6742ca1d17c07309132d06d96c75405ccab07 Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Thu, 2 Nov 2023 11:52:07 +0100 Subject: [PATCH 0333/1049] bluetooth: id: make sharing RPA between adv sets optional Added a Kconfig option that makes the RPA sharing feature optional. By default, the Zephyr Bluetooth stack now uses the RPA rotation policy that was active before the introduction of the RPA sharing functionality in the following PR: https://github.com/zephyrproject-rtos/zephyr/pull/55449 The new Kconfig option configures the advertising sets linked with the same Bluetooth identity to use the same Resolvable Private Address in a given rotation period. After the RPA timeout, the new RPA is generated and shared between the advertising sets in the subsequent rotation period. When this option is disabled, the generated RPAs of the advertising sets differ from each other in a given rotation period. Signed-off-by: Kamil Piszczek --- subsys/bluetooth/host/Kconfig | 12 ++++ subsys/bluetooth/host/hci_core.h | 2 + subsys/bluetooth/host/id.c | 61 ++++++++++++++----- .../id/bt_id_set_adv_private_addr/src/main.c | 2 +- .../host/privacy/peripheral/src/tester.c | 17 +++++- 5 files changed, 76 insertions(+), 18 deletions(-) diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index f09d8a14d724b09..c5c73be39a2f033 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -469,6 +469,18 @@ config BT_RPA_TIMEOUT_DYNAMIC This option allows the user to override the default value of the Resolvable Private Address timeout using dedicated APIs. +config BT_RPA_SHARING + bool "Share the Resolvable Private Address between advertising sets" + depends on BT_PRIVACY && BT_EXT_ADV + help + This option configures the advertising sets linked with the same + Bluetooth identity to use the same Resolvable Private Address in + a given rotation period. After the RPA timeout, the new RPA is + generated and shared between the advertising sets in the subsequent + rotation period. When this option is disabled, the generated RPAs + of the advertising sets differ from each other in a given rotation + period. + config BT_SIGNING bool "Data signing support" help diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 65466cae7402a78..ce4fc5a9b63e923 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -381,8 +381,10 @@ struct bt_dev { /* Local Identity Resolving Key */ uint8_t irk[CONFIG_BT_ID_MAX][16]; +#if defined(CONFIG_BT_RPA_SHARING) /* Only 1 RPA per identity */ bt_addr_t rpa[CONFIG_BT_ID_MAX]; +#endif /* Work used for RPA rotation */ struct k_work_delayable rpa_update; diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index cf07418dd020140..6b5fcbd5d17df8f 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -207,13 +207,14 @@ static void adv_rpa_expired(struct bt_le_ext_adv *adv) if (atomic_test_bit(adv->flags, BT_ADV_RPA_VALID) && adv->cb && adv->cb->rpa_expired) { rpa_invalid = adv->cb->rpa_expired(adv); - if (rpa_invalid) { - bt_addr_copy(&bt_dev.rpa[adv->id], BT_ADDR_NONE); - } } #endif if (rpa_invalid) { atomic_clear_bit(adv->flags, BT_ADV_RPA_VALID); + +#if defined(CONFIG_BT_RPA_SHARING) + bt_addr_copy(&bt_dev.rpa[adv->id], BT_ADDR_NONE); +#endif } } @@ -321,8 +322,39 @@ int bt_id_set_private_addr(uint8_t id) return 0; } +#if defined(CONFIG_BT_RPA_SHARING) +static int adv_rpa_get(struct bt_le_ext_adv *adv, bt_addr_t *rpa) +{ + int err; + + if (bt_addr_eq(&bt_dev.rpa[adv->id], BT_ADDR_NONE)) { + err = bt_rpa_create(bt_dev.irk[adv->id], &bt_dev.rpa[adv->id]); + if (err) { + return err; + } + } + + bt_addr_copy(rpa, &bt_dev.rpa[adv->id]); + + return 0; +} +#else +static int adv_rpa_get(struct bt_le_ext_adv *adv, bt_addr_t *rpa) +{ + int err; + + err = bt_rpa_create(bt_dev.irk[adv->id], rpa); + if (err) { + return err; + } + + return 0; +} +#endif /* defined(CONFIG_BT_RPA_SHARING) */ + int bt_id_set_adv_private_addr(struct bt_le_ext_adv *adv) { + bt_addr_t rpa; int err; CHECKIF(adv == NULL) { @@ -373,16 +405,12 @@ int bt_id_set_adv_private_addr(struct bt_le_ext_adv *adv) return 0; } - if (bt_addr_eq(&bt_dev.rpa[adv->id], BT_ADDR_NONE)) { - err = bt_rpa_create(bt_dev.irk[adv->id], &bt_dev.rpa[adv->id]); - if (err) { - return err; - } - } - - err = bt_id_set_adv_random_addr(adv, &bt_dev.rpa[adv->id]); + err = adv_rpa_get(adv, &rpa); if (!err) { - atomic_set_bit(adv->flags, BT_ADV_RPA_VALID); + err = bt_id_set_adv_random_addr(adv, &rpa); + if (!err) { + atomic_set_bit(adv->flags, BT_ADV_RPA_VALID); + } } if (!atomic_test_bit(adv->flags, BT_ADV_LIMITED)) { @@ -394,7 +422,7 @@ int bt_id_set_adv_private_addr(struct bt_le_ext_adv *adv) } if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { - LOG_INF("RPA: %s", bt_addr_str(&bt_dev.rpa[adv->id])); + LOG_INF("RPA: %s", bt_addr_str(&rpa)); } return 0; @@ -1230,7 +1258,10 @@ static int id_create(uint8_t id, bt_addr_le_t *addr, uint8_t *irk) memcpy(irk, &bt_dev.irk[id], 16); } } + +#if defined(CONFIG_BT_RPA_SHARING) bt_addr_copy(&bt_dev.rpa[id], BT_ADDR_NONE); +#endif } #endif /* Only store if stack was already initialized. Before initialization @@ -2064,10 +2095,12 @@ int bt_id_init(void) int err; #if defined(CONFIG_BT_PRIVACY) + k_work_init_delayable(&bt_dev.rpa_update, rpa_timeout); +#if defined(CONFIG_BT_RPA_SHARING) for (uint8_t id = 0U; id < ARRAY_SIZE(bt_dev.rpa); id++) { bt_addr_copy(&bt_dev.rpa[id], BT_ADDR_NONE); } - k_work_init_delayable(&bt_dev.rpa_update, rpa_timeout); +#endif #endif if (!IS_ENABLED(CONFIG_BT_SETTINGS) && !bt_dev.id_count) { diff --git a/tests/bluetooth/host/id/bt_id_set_adv_private_addr/src/main.c b/tests/bluetooth/host/id/bt_id_set_adv_private_addr/src/main.c index b8c4974c03ff3cf..73f51ad4bf2e9f7 100644 --- a/tests/bluetooth/host/id/bt_id_set_adv_private_addr/src/main.c +++ b/tests/bluetooth/host/id/bt_id_set_adv_private_addr/src/main.c @@ -24,7 +24,7 @@ static void fff_reset_rule_before(const struct ztest_unit_test *test, void *fixt { memset(&bt_dev, 0x00, sizeof(struct bt_dev)); bt_addr_le_copy(&bt_dev.random_addr, &bt_addr_le_none); -#if defined(CONFIG_BT_PRIVACY) +#if defined(CONFIG_BT_RPA_SHARING) bt_addr_copy(&bt_dev.rpa[BT_ID_DEFAULT], BT_ADDR_NONE); #endif diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c b/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c index deaa001ddbe5070..db363cd6ea032e4 100644 --- a/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c +++ b/tests/bsim/bluetooth/host/privacy/peripheral/src/tester.c @@ -41,9 +41,20 @@ static void validate_rpa_addr_generated_for_adv_sets(void) return; } } - /* First two adv sets have same address as they use same ID and third adv set use diff ID */ - if (!bt_addr_le_eq(&adv_set_data[0].old_addr, &adv_set_data[1].old_addr)) { - FAIL("RPA not same for adv sets with same id\n"); + if (bt_addr_le_eq(&adv_set_data[0].old_addr, &adv_set_data[1].old_addr)) { + /* With RPA sharing mode disabled, the first two adv sets should have + * a different address even though they use the same Bluetooth ID. + */ + if (!IS_ENABLED(CONFIG_BT_RPA_SHARING)) { + FAIL("RPA same for adv sets with same id and RPA sharing disabled\n"); + } + } else { + /* In the RPA sharing mode, the first two adv sets should have + * the same address as they use the same Bluetooth ID. + */ + if (IS_ENABLED(CONFIG_BT_RPA_SHARING)) { + FAIL("RPA not same for adv sets with same id and RPA sharing enabled\n"); + } } if (bt_addr_le_eq(&adv_set_data[0].old_addr, &adv_set_data[3].old_addr)) { FAIL("RPA same for adv sets with different id's\n"); From ae05c5ea30ef4a2447c038e99e8ce230ef57efff Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Mon, 13 Nov 2023 09:33:09 +0100 Subject: [PATCH 0334/1049] tests: bsim: bluetooth: host: privacy: peripheral: test rpa sharing mode Added a new configuration to the BabbleSim Bluetooth Peripheral Privacy test to cover the code path for the RPA sharing mode. Signed-off-by: Kamil Piszczek --- tests/bsim/bluetooth/host/compile.sh | 1 + .../privacy/peripheral/prj_rpa_sharing.conf | 26 +++++++++++ .../privacy/peripheral/test_scripts/_env.sh | 3 ++ .../test_scripts/run_test_rpa_sharing.sh | 46 +++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 tests/bsim/bluetooth/host/privacy/peripheral/prj_rpa_sharing.conf create mode 100755 tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test_rpa_sharing.sh diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 9840083305c2739..ff42fd27adf99cf 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -71,6 +71,7 @@ app=tests/bsim/bluetooth/host/misc/disconnect/tester compile app=tests/bsim/bluetooth/host/privacy/central compile app=tests/bsim/bluetooth/host/privacy/peripheral compile +app=tests/bsim/bluetooth/host/privacy/peripheral conf_file=prj_rpa_sharing.conf compile app=tests/bsim/bluetooth/host/privacy/device compile app=tests/bsim/bluetooth/host/privacy/legacy compile diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/prj_rpa_sharing.conf b/tests/bsim/bluetooth/host/privacy/peripheral/prj_rpa_sharing.conf new file mode 100644 index 000000000000000..bebce9933ca4146 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/peripheral/prj_rpa_sharing.conf @@ -0,0 +1,26 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_SMP=y +CONFIG_ASSERT=y + +CONFIG_BT_EXT_ADV=y +CONFIG_BT_PRIVACY=y +CONFIG_BT_RPA_TIMEOUT=10 +CONFIG_BT_EXT_ADV_MAX_ADV_SET=3 +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=3 +CONFIG_BT_ID_MAX=3 + +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y +CONFIG_BT_SETTINGS=y + +# Increased stack due to settings API usage +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +# Enable the RPA sharing mode +CONFIG_BT_RPA_SHARING=y diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/_env.sh b/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/_env.sh index 13cf18ceec41e9d..3c86078a7a679f0 100755 --- a/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/_env.sh +++ b/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/_env.sh @@ -9,3 +9,6 @@ bsim_bin="${BSIM_OUT_PATH}/bin" BOARD="${BOARD:-nrf52_bsim}" central_exe="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_privacy_peripheral_prj_conf" peripheral_exe="${central_exe}" +central_exe_rpa_sharing="\ +${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_privacy_peripheral_prj_rpa_sharing_conf" +peripheral_exe_rpa_sharing="${central_exe_rpa_sharing}" diff --git a/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test_rpa_sharing.sh b/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test_rpa_sharing.sh new file mode 100755 index 000000000000000..2b0d5e4c4b7915b --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/peripheral/test_scripts/run_test_rpa_sharing.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +source "${bash_source_dir}/_env.sh" +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +verbosity_level=2 +simulation_id="$(basename "$(realpath "$bash_source_dir/..")")" +simulation_id="${simulation_id}_rpa_sharing" +EXECUTE_TIMEOUT=30 + +cd ${BSIM_OUT_PATH}/bin + +Execute "$central_exe_rpa_sharing" \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -RealEncryption=1 \ + -flash="${simulation_id}.central.log.bin" + + +Execute "$peripheral_exe_rpa_sharing" \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1 \ + -flash="${simulation_id}.peripheral.log.bin" + + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=70e6 $@ + +wait_for_background_jobs + +Execute "$central_exe_rpa_sharing" \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -RealEncryption=1 \ + -flash="${simulation_id}.central.log.bin" -flash_rm + + +Execute "$peripheral_exe_rpa_sharing" \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1 \ + -flash="${simulation_id}.peripheral.log.bin" -flash_rm + + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=70e6 $@ + +wait_for_background_jobs From 4cc12cb112c40a86769223b44ab7b92a9c877dc7 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 8 Nov 2023 16:14:51 -0600 Subject: [PATCH 0335/1049] include: mipi_dsi: add MIPI DSI detach API Add MIPI DSI detach API. This API allows the DSI controller to detach from the DSI device, and power down the DSI PHY. The primary goal of this API is to provide power savings for DSI devices when the display they are driving is not active. Signed-off-by: Daniel DeGrasse --- include/zephyr/drivers/mipi_dsi.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/zephyr/drivers/mipi_dsi.h b/include/zephyr/drivers/mipi_dsi.h index d26854fc1a6f906..e6ac1e0a787bc63 100644 --- a/include/zephyr/drivers/mipi_dsi.h +++ b/include/zephyr/drivers/mipi_dsi.h @@ -18,6 +18,7 @@ * @ingroup io_interfaces * @{ */ +#include #include #include #include @@ -247,6 +248,8 @@ __subsystem struct mipi_dsi_driver_api { const struct mipi_dsi_device *mdev); ssize_t (*transfer)(const struct device *dev, uint8_t channel, struct mipi_dsi_msg *msg); + int (*detach)(const struct device *dev, uint8_t channel, + const struct mipi_dsi_device *mdev); }; /** @@ -342,6 +345,29 @@ ssize_t mipi_dsi_dcs_read(const struct device *dev, uint8_t channel, ssize_t mipi_dsi_dcs_write(const struct device *dev, uint8_t channel, uint8_t cmd, const void *buf, size_t len); + +/** + * @brief Detach a device from the MIPI-DSI bus + * + * @param dev MIPI-DSI host device. + * @param channel Device channel (VID). + * @param mdev MIPI-DSI device description. + * + * @return 0 on success, negative on error + */ +static inline int mipi_dsi_detach(const struct device *dev, + uint8_t channel, + const struct mipi_dsi_device *mdev) +{ + const struct mipi_dsi_driver_api *api = (const struct mipi_dsi_driver_api *)dev->api; + + if (api->detach == NULL) { + return -ENOSYS; + } + + return api->detach(dev, channel, mdev); +} + #ifdef __cplusplus } #endif From 5854821b65ea8ba893e7e255a0d1e32684f3ef4f Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 8 Nov 2023 16:17:14 -0600 Subject: [PATCH 0336/1049] drivers: mipi_dsi: add support for mipi_dsi_detach to dsi_mcux_2l Add support for mipi_dsi_detach API to dsi_mcux_2l driver, and update RT5xx SOC interface to enable halting clocks for the MIPI DPHY. Signed-off-by: Daniel DeGrasse --- drivers/mipi_dsi/dsi_mcux_2l.c | 23 +++++++++++++++++++++-- soc/arm/nxp_imx/rt5xx/soc.c | 11 +++++++++++ soc/arm/nxp_imx/rt5xx/soc.h | 2 ++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/mipi_dsi/dsi_mcux_2l.c b/drivers/mipi_dsi/dsi_mcux_2l.c index de73d10e8acda95..62ab1400a22b669 100644 --- a/drivers/mipi_dsi/dsi_mcux_2l.c +++ b/drivers/mipi_dsi/dsi_mcux_2l.c @@ -227,6 +227,8 @@ static int dsi_mcux_attach(const struct device *dev, dsi_config.autoInsertEoTp = config->auto_insert_eotp; dsi_config.enableNonContinuousHsClk = config->noncontinuous_hs_clk; + imxrt_pre_init_display_interface(); + /* Init the DSI module. */ DSI_Init(config->base, &dsi_config); @@ -344,6 +346,24 @@ static int dsi_mcux_attach(const struct device *dev, return 0; } +static int dsi_mcux_detach(const struct device *dev, uint8_t channel, + const struct mipi_dsi_device *mdev) +{ + const struct mcux_mipi_dsi_config *config = dev->config; + + /* Enable DPHY auto power down */ + DSI_DeinitDphy(config->base); + /* Fully power off DPHY */ + config->base->PD_DPHY = 0x1; + /* Deinit MIPI */ + DSI_Deinit(config->base); + /* Call IMX RT clock function to gate clocks and power at SOC level */ + imxrt_deinit_display_interface(); + return 0; +} + + + static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, struct mipi_dsi_msg *msg) { @@ -434,6 +454,7 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, static struct mipi_dsi_driver_api dsi_mcux_api = { .attach = dsi_mcux_attach, + .detach = dsi_mcux_detach, .transfer = dsi_mcux_transfer, }; @@ -449,8 +470,6 @@ static int mcux_mipi_dsi_init(const struct device *dev) k_sem_init(&data->transfer_sem, 0, 1); - imxrt_pre_init_display_interface(); - if (!device_is_ready(config->bit_clk_dev) || !device_is_ready(config->esc_clk_dev) || !device_is_ready(config->pixel_clk_dev)) { diff --git a/soc/arm/nxp_imx/rt5xx/soc.c b/soc/arm/nxp_imx/rt5xx/soc.c index f6af227b17cbb05..d834d3e55bc05e9 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.c +++ b/soc/arm/nxp_imx/rt5xx/soc.c @@ -473,6 +473,17 @@ void __weak imxrt_post_init_display_interface(void) /* Deassert MIPI DPHY reset. */ RESET_ClearPeripheralReset(kMIPI_DSI_PHY_RST_SHIFT_RSTn); } + +void __weak imxrt_deinit_display_interface(void) +{ + /* Assert MIPI DPHY and DSI reset */ + RESET_SetPeripheralReset(kMIPI_DSI_PHY_RST_SHIFT_RSTn); + RESET_SetPeripheralReset(kMIPI_DSI_CTRL_RST_SHIFT_RSTn); + /* Remove clock from DPHY */ + CLOCK_AttachClk(kNONE_to_MIPI_DPHY_CLK); +} + + #endif /** diff --git a/soc/arm/nxp_imx/rt5xx/soc.h b/soc/arm/nxp_imx/rt5xx/soc.h index c2ebff0369d8ce6..eefef70ff8203d9 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.h +++ b/soc/arm/nxp_imx/rt5xx/soc.h @@ -80,6 +80,8 @@ void imxrt_pre_init_display_interface(void); void imxrt_post_init_display_interface(void); + +void imxrt_deinit_display_interface(void); #endif #endif From 5997f3d00d31f312bb50aa68b6e57d20b637a748 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 8 Nov 2023 16:18:46 -0600 Subject: [PATCH 0337/1049] drivers: display: rm67162: add device level power management Add device level power management to rm67162 display. Device level power management for this controller calls the MIPI DSI detach API, in order to power down the MIPI DPHY when the display is not active. Signed-off-by: Daniel DeGrasse --- drivers/display/display_rm67162.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/display/display_rm67162.c b/drivers/display/display_rm67162.c index edf9d6eb55df9e9..5516e57789de23d 100644 --- a/drivers/display/display_rm67162.c +++ b/drivers/display/display_rm67162.c @@ -13,6 +13,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(rm67162, CONFIG_DISPLAY_LOG_LEVEL); @@ -568,6 +569,31 @@ static int rm67162_set_orientation(const struct device *dev, return -ENOTSUP; } +#ifdef CONFIG_PM_DEVICE + +static int rm67162_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + struct mipi_dsi_device mdev = {0}; + + mdev.data_lanes = config->num_of_lanes; + mdev.pixfmt = data->pixel_format; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + /* Detach from the MIPI DSI controller */ + return mipi_dsi_detach(config->mipi_dsi, config->channel, &mdev); + case PM_DEVICE_ACTION_RESUME: + return mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); + default: + return -ENOTSUP; + } +} + +#endif /* CONFIG_PM_DEVICE */ + static const struct display_driver_api rm67162_api = { .blanking_on = rm67162_blanking_on, .blanking_off = rm67162_blanking_off, @@ -593,9 +619,10 @@ static const struct display_driver_api rm67162_api = { static struct rm67162_data rm67162_data_##id = { \ .pixel_format = DT_INST_PROP(id, pixel_format), \ }; \ + PM_DEVICE_DT_INST_DEFINE(id, rm67162_pm_action); \ DEVICE_DT_INST_DEFINE(id, \ &rm67162_init, \ - NULL, \ + PM_DEVICE_DT_INST_GET(id), \ &rm67162_data_##id, \ &rm67162_config_##id, \ POST_KERNEL, \ From d6d3f9f16a400ab01c0617a30114f9af1ec7bb10 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 8 Nov 2023 16:24:04 -0600 Subject: [PATCH 0338/1049] boards: shields: add support for low power on G1120B0MIPI using RT595 Add support for low power mode on the G1120B0MIPI using the RT595. This configuration is tested via a testcase in samples/drivers/display, which should validate that the display can be driven by the RT595 when CONFIG_PM and CONFIG_PM_DEVICE are set. Signed-off-by: Daniel DeGrasse --- .../g1120b0mipi/boards/mimxrt595_evk_cm33.overlay | 15 +++++++++++++++ samples/drivers/display/sample.yaml | 11 +++++++++++ 2 files changed, 26 insertions(+) create mode 100644 boards/shields/g1120b0mipi/boards/mimxrt595_evk_cm33.overlay diff --git a/boards/shields/g1120b0mipi/boards/mimxrt595_evk_cm33.overlay b/boards/shields/g1120b0mipi/boards/mimxrt595_evk_cm33.overlay new file mode 100644 index 000000000000000..7503627d99d3b95 --- /dev/null +++ b/boards/shields/g1120b0mipi/boards/mimxrt595_evk_cm33.overlay @@ -0,0 +1,15 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Change deep sleep config for suspend mode to keep SMARTDMA ram powered, + * so the SMARTDMA will continue functioning after deep sleep + */ +&suspend { + deep-sleep-config = <0xC800>, + <0x80030004>, + <0xFFFFFFFF>, + <0>; +}; diff --git a/samples/drivers/display/sample.yaml b/samples/drivers/display/sample.yaml index f2cc9d0a89d489d..00725caedb5c4db 100644 --- a/samples/drivers/display/sample.yaml +++ b/samples/drivers/display/sample.yaml @@ -131,3 +131,14 @@ tests: harness: console harness_config: fixture: fixture_display + sample.display.g1120b0mipi: + platform_allow: mimxrt595_evk_cm33 + tags: display + harness: console + extra_args: SHIELD=g1120b0mipi + extra_configs: + - CONFIG_PM=y + - CONFIG_PM_DEVICE=y + - CONFIG_IDLE_STACK_SIZE=400 + harness_config: + fixture: fixture_display From 07b5f51cdcba07b8b135f3714a1e05161710efab Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 9 Nov 2023 15:17:55 +0200 Subject: [PATCH 0339/1049] boards: up_squared_pro_7000: Add new board definition Add board definition for UP Squared Pro 7000. The board is powered by Intel Alder Lake N (N-series Intel Platform). Signed-off-by: Andrei Emeltchenko --- boards/x86/intel_adl/Kconfig.board | 6 ++++++ boards/x86/intel_adl/Kconfig.defconfig | 5 +++-- boards/x86/intel_adl/up_squared_pro_7000.dts | 21 +++++++++++++++++++ boards/x86/intel_adl/up_squared_pro_7000.yaml | 17 +++++++++++++++ .../intel_adl/up_squared_pro_7000_defconfig | 15 +++++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 boards/x86/intel_adl/up_squared_pro_7000.dts create mode 100644 boards/x86/intel_adl/up_squared_pro_7000.yaml create mode 100644 boards/x86/intel_adl/up_squared_pro_7000_defconfig diff --git a/boards/x86/intel_adl/Kconfig.board b/boards/x86/intel_adl/Kconfig.board index 997b5a30504e590..591da3261f27f4d 100644 --- a/boards/x86/intel_adl/Kconfig.board +++ b/boards/x86/intel_adl/Kconfig.board @@ -12,3 +12,9 @@ config BOARD_INTEL_ADL_RVP depends on SOC_ALDER_LAKE select X86_64 select HAS_COVERAGE_SUPPORT + +config BOARD_UP_SQUARED_PRO_7000 + bool "UP SQUARED PRO 7000 board" + depends on SOC_ALDER_LAKE + select X86_64 + select HAS_COVERAGE_SUPPORT diff --git a/boards/x86/intel_adl/Kconfig.defconfig b/boards/x86/intel_adl/Kconfig.defconfig index 247b8f7a0cb7ab1..cc9e3882ec45d6e 100644 --- a/boards/x86/intel_adl/Kconfig.defconfig +++ b/boards/x86/intel_adl/Kconfig.defconfig @@ -1,11 +1,12 @@ # Copyright (c) 2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -if BOARD_INTEL_ADL_CRB || BOARD_INTEL_ADL_RVP +if BOARD_INTEL_ADL_CRB || BOARD_INTEL_ADL_RVP || BOARD_UP_SQUARED_PRO_7000 config BOARD default "intel_adl_crb" if BOARD_INTEL_ADL_CRB default "intel_adl_rvp" if BOARD_INTEL_ADL_RVP + default "up_squared_pro_7000" if BOARD_UP_SQUARED_PRO_7000 config BUILD_OUTPUT_STRIPPED default y @@ -45,4 +46,4 @@ config SHELL_STACK_SIZE endif # SHELL endif # ACPI -endif # BOARD_INTEL_ADL_CRB || BOARD_INTEL_ADL_RVP +endif # BOARD_INTEL_ADL_CRB || BOARD_INTEL_ADL_RVP || BOARD_UP_SQUARED_PRO_7000 diff --git a/boards/x86/intel_adl/up_squared_pro_7000.dts b/boards/x86/intel_adl/up_squared_pro_7000.dts new file mode 100644 index 000000000000000..06d6f8e23307579 --- /dev/null +++ b/boards/x86/intel_adl/up_squared_pro_7000.dts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "intel_adl.dts" + +/ { + model = "UP Squared Pro 7000 board"; + compatible = "aaeon,up_squared_pro_7000"; + + chosen { + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + }; +}; + +&uart1 { + status = "okay"; +}; diff --git a/boards/x86/intel_adl/up_squared_pro_7000.yaml b/boards/x86/intel_adl/up_squared_pro_7000.yaml new file mode 100644 index 000000000000000..e16731123090978 --- /dev/null +++ b/boards/x86/intel_adl/up_squared_pro_7000.yaml @@ -0,0 +1,17 @@ +identifier: up_squared_pro_7000 +name: UP SQUARED PRO 7000 board +type: mcu +arch: x86 +toolchain: + - zephyr +ram: 2048 +supported: + - acpi + - smp + - watchdog +testing: + timeout_multiplier: 4 + ignore_tags: + - net + - bluetooth +vendor: UP diff --git a/boards/x86/intel_adl/up_squared_pro_7000_defconfig b/boards/x86/intel_adl/up_squared_pro_7000_defconfig new file mode 100644 index 000000000000000..211ce9f24e1d987 --- /dev/null +++ b/boards/x86/intel_adl/up_squared_pro_7000_defconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_ALDER_LAKE=y +CONFIG_BOARD_UP_SQUARED_PRO_7000=y +CONFIG_PIC_DISABLE=y +CONFIG_LOAPIC=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_NS16550=y +CONFIG_UART_CONSOLE=y +CONFIG_X2APIC=y +CONFIG_SMP=y +CONFIG_BUILD_OUTPUT_EFI=y +CONFIG_BUILD_NO_GAP_FILL=y +CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y From c99fe31f8333a9e2003e6bbd607a98ed9d482e79 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 9 Nov 2023 16:00:19 +0200 Subject: [PATCH 0340/1049] boards: up_squared_pro_7000: Add board documentation Add documentation for UP Squared Pro 7000 board. Signed-off-by: Andrei Emeltchenko --- .../x86/intel_adl/doc/up_squared_pro_7000.rst | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 boards/x86/intel_adl/doc/up_squared_pro_7000.rst diff --git a/boards/x86/intel_adl/doc/up_squared_pro_7000.rst b/boards/x86/intel_adl/doc/up_squared_pro_7000.rst new file mode 100644 index 000000000000000..8f322080d96ede7 --- /dev/null +++ b/boards/x86/intel_adl/doc/up_squared_pro_7000.rst @@ -0,0 +1,67 @@ +:orphan: + +.. _up_squared_pro_7000_board: + +UP SQUARED PRO 7000 board +######################### + +Overview +******** + +UP Squared Pro 7000 is the 3rd generation of palm-sized developer board of +UP Boards series. UP Squared Pro 7000 is powered by Intel Alder Lake N +(Intel N-series Platform). + +For more information about Intel N-series Platform please refer to +:ref:`intel_adl_n`. + +This board configuration enables kernel support for the UP Squared Pro 7000 boards. + +Hardware +******** + +General information about the board can be found at the `UP_SQUARED_PRO_7000`_ website. + +Connections and IOs +=================== + +Refer to the `UP_SQUARED_PRO_7000`_ website for more information. + +Programming and Debugging +************************* +Use the following procedures for booting an image for an UP SQUARED PRO 7000 board. + +.. contents:: + :depth: 1 + :local: + :backlinks: top + +Build Zephyr application +======================== + +#. Build a Zephyr application; for instance, to build the ``hello_world`` + application for UP SQUARED PRO 7000 board: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: up_squared_pro_7000 + :goals: build + + .. note:: + + A Zephyr EFI image file named :file:`zephyr.efi` is automatically + created in the build directory after the application is built. + +Booting the UP Squared Pro 7000 Board using UEFI +================================================ + +.. include:: ../../common/efi_boot.rst + :start-after: start_include_here + +Booting the UP Squared Pro 7000 Board over network +================================================== + +.. include:: ../../common/net_boot.rst + :start-after: start_include_here + +.. _UP_SQUARED_PRO_7000: https://up-board.org/up-squared-pro-7000/ From 0dab1e848233be8593d922070e1fd58ae8769df0 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 9 Nov 2023 17:31:04 +0200 Subject: [PATCH 0341/1049] doc: x86: Modify x86 TOC include Modify toctree glob to exclude common directory which keeps rst helpers. This allows to include several boards documentation from the common board directory. Signed-off-by: Andrei Emeltchenko --- boards/x86/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/x86/index.rst b/boards/x86/index.rst index d51c2551c4fb2d4..f7321566591af12 100644 --- a/boards/x86/index.rst +++ b/boards/x86/index.rst @@ -7,4 +7,4 @@ x86 Boards :maxdepth: 1 :glob: - **/index + [!common]*/**/* From 25ac2fa064187835946e8ba39a739bf5e82f3ec0 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 10 Nov 2023 12:13:47 +0200 Subject: [PATCH 0342/1049] dts: vendor-prefixes: Add AAEON Add AAEON Technology Inc prefix. Signed-off-by: Andrei Emeltchenko --- dts/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index 5515ea53ebe73ed..29a7b78aa70c9f0 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -10,6 +10,7 @@ # # +aaeon AAEON Technology Inc. abb ABB abilis Abilis Systems abracon Abracon Corporation From 81923652981b3362031e85d848a57c0d532f806e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 10 Nov 2023 12:39:29 +0200 Subject: [PATCH 0343/1049] boards: up_squared: Correct vendor Correct vendor name for up_squared board, the same as for UP 7000 board. Signed-off-by: Andrei Emeltchenko --- boards/x86/up_squared/up_squared.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/x86/up_squared/up_squared.dts b/boards/x86/up_squared/up_squared.dts index 22303e0ef1684a4..e4977160db62bed 100644 --- a/boards/x86/up_squared/up_squared.dts +++ b/boards/x86/up_squared/up_squared.dts @@ -14,7 +14,7 @@ / { model = "up_squared"; - compatible = "up_board,up_squared"; + compatible = "aaeon,up_squared"; aliases { i2c-0 = &i2c0; From a3ff8d5b90bd3bb0a6c7f3786f0852ed855b9344 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Sat, 11 Nov 2023 15:21:27 +0200 Subject: [PATCH 0344/1049] tests: samples: Add up_squared_pro_7000 overlay Add up_squared_pro_7000 overlay for watchdog test and sample. Signed-off-by: Andrei Emeltchenko --- .../drivers/watchdog/boards/up_squared_pro_7000.overlay | 9 +++++++++ .../wdt_basic_api/boards/up_squared_pro_7000.overlay | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 samples/drivers/watchdog/boards/up_squared_pro_7000.overlay create mode 100644 tests/drivers/watchdog/wdt_basic_api/boards/up_squared_pro_7000.overlay diff --git a/samples/drivers/watchdog/boards/up_squared_pro_7000.overlay b/samples/drivers/watchdog/boards/up_squared_pro_7000.overlay new file mode 100644 index 000000000000000..660b55c05121d45 --- /dev/null +++ b/samples/drivers/watchdog/boards/up_squared_pro_7000.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&tco_wdt { + status = "okay"; +}; diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/up_squared_pro_7000.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/up_squared_pro_7000.overlay new file mode 100644 index 000000000000000..660b55c05121d45 --- /dev/null +++ b/tests/drivers/watchdog/wdt_basic_api/boards/up_squared_pro_7000.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&tco_wdt { + status = "okay"; +}; From 8ebbd0227d76c430bc897ecf89ec687e6098b1df Mon Sep 17 00:00:00 2001 From: Jilay Pandya Date: Fri, 10 Nov 2023 16:15:47 +0100 Subject: [PATCH 0345/1049] sensors: tests: adi: increase coverage This commit adds tests for various configurations of adltc2990 Signed-off-by: Jilay Pandya --- .../adltc2990/boards/native_posix.overlay | 40 +++++- tests/drivers/sensor/adltc2990/src/main.c | 130 ++++++++++++++++++ 2 files changed, 168 insertions(+), 2 deletions(-) diff --git a/tests/drivers/sensor/adltc2990/boards/native_posix.overlay b/tests/drivers/sensor/adltc2990/boards/native_posix.overlay index 9497214ad449086..a3f7ae3ed7b5e00 100644 --- a/tests/drivers/sensor/adltc2990/boards/native_posix.overlay +++ b/tests/drivers/sensor/adltc2990/boards/native_posix.overlay @@ -4,9 +4,21 @@ */ &i2c0 { - adltc2990_1_3: adltc2990_1_3@c { + adltc2990_0_0: adltc2990_0_0@1 { compatible = "adi,adltc2990"; - reg = <0xc>; + reg = <0x1>; + measurement-mode = <0 0>; + pins-v1-v2-current-resistor = <0>; + pins-v3-v4-current-resistor = <0>; + pin-v1-voltage-divider-resistors = <500 1000>; + pin-v2-voltage-divider-resistors = <110000 100000>; + pin-v3-voltage-divider-resistors = <7000 1000>; + pin-v4-voltage-divider-resistors = <500 1000>; + }; + + adltc2990_1_3: adltc2990_1_3@b { + compatible = "adi,adltc2990"; + reg = <0xb>; temperature-format = <0>; acquistion-format = <1>; measurement-mode = <1 3>; @@ -18,6 +30,18 @@ pin-v4-voltage-divider-resistors = <0 1>; }; + adltc2990_4_3: adltc2990_4_3@c { + compatible = "adi,adltc2990"; + reg = <0xc>; + measurement-mode = <4 3>; + pins-v1-v2-current-resistor = <1000000>; + pins-v3-v4-current-resistor = <0>; + pin-v1-voltage-divider-resistors = <0 1>; + pin-v2-voltage-divider-resistors = <0 1>; + pin-v3-voltage-divider-resistors = <0 1>; + pin-v4-voltage-divider-resistors = <0 1>; + }; + adltc2990_5_3: adltc2990_5_3@d { compatible = "adi,adltc2990"; reg = <0xd>; @@ -59,4 +83,16 @@ pin-v3-voltage-divider-resistors = <7000 1000>; pin-v4-voltage-divider-resistors = <500 1000>; }; + + adltc2990_incorrect: adltc2990_incorrect@0 { + compatible = "adi,adltc2990"; + reg = <0x0>; + measurement-mode = <8 4>; + pins-v1-v2-current-resistor = <0>; + pins-v3-v4-current-resistor = <0>; + pin-v1-voltage-divider-resistors = <500 1000>; + pin-v2-voltage-divider-resistors = <110000 100000>; + pin-v3-voltage-divider-resistors = <7000 1000>; + pin-v4-voltage-divider-resistors = <500 1000>; + }; }; diff --git a/tests/drivers/sensor/adltc2990/src/main.c b/tests/drivers/sensor/adltc2990/src/main.c index 2f55ed38489e8f0..fabeb8ab0dc2aff 100644 --- a/tests/drivers/sensor/adltc2990/src/main.c +++ b/tests/drivers/sensor/adltc2990/src/main.c @@ -49,6 +49,84 @@ "expected %f, got %f", expected_temperature, \ sensor_val[index].val1 + (float)sensor_val[index].val2 / 1000000); +/*** TEST-SUITE: ADLTC2990 Measurement Mode 0 0***/ + +struct adltc2990_0_0_fixture { + const struct device *dev; + const struct emul *target; +}; + +static void *adltc2990_0_0_setup(void) +{ + static struct adltc2990_0_0_fixture fixture = { + .dev = DEVICE_DT_GET(DT_NODELABEL(adltc2990_0_0)), + .target = EMUL_DT_GET(DT_NODELABEL(adltc2990_0_0)), + }; + + zassert_not_null(fixture.dev); + zassert_not_null(fixture.target); + return &fixture; +} + +static void adltc2990_0_0_before(void *f) +{ + struct adltc2990_0_0_fixture *fixture = f; + + adltc2990_emul_reset(fixture->target); +} + +ZTEST_SUITE(adltc2990_0_0, NULL, adltc2990_0_0_setup, adltc2990_0_0_before, NULL, NULL); + +ZTEST_F(adltc2990_0_0, test_measure_mode_internal_temperature_only) +{ + struct sensor_value value[1]; + + zassert_equal(-ENOTSUP, sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_MAGN_X)); + zassert_equal(-ENOTSUP, sensor_channel_get(fixture->dev, SENSOR_CHAN_MAGN_Z, value)); + zassert_equal(-EINVAL, sensor_channel_get(fixture->dev, SENSOR_CHAN_CURRENT, value)); + zassert_equal(-EINVAL, sensor_channel_get(fixture->dev, SENSOR_CHAN_AMBIENT_TEMP, value)); +} + +/*** TEST-SUITE: ADLTC2990 Measurement Mode 4 3***/ + +struct adltc2990_4_3_fixture { + const struct device *dev; + const struct emul *target; +}; + +static void *adltc2990_4_3_setup(void) +{ + static struct adltc2990_4_3_fixture fixture = { + .dev = DEVICE_DT_GET(DT_NODELABEL(adltc2990_4_3)), + .target = EMUL_DT_GET(DT_NODELABEL(adltc2990_4_3)), + }; + + zassert_not_null(fixture.dev); + zassert_not_null(fixture.target); + return &fixture; +} + +static void adltc2990_4_3_before(void *f) +{ + struct adltc2990_4_3_fixture *fixture = f; + + adltc2990_emul_reset(fixture->target); +} + +ZTEST_SUITE(adltc2990_4_3, NULL, adltc2990_4_3_setup, adltc2990_4_3_before, NULL, NULL); + +ZTEST_F(adltc2990_4_3, test_available_channels) +{ + struct sensor_value value[3]; + + zassert_equal(0, sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_VOLTAGE)); + zassert_equal(0, sensor_channel_get(fixture->dev, SENSOR_CHAN_VOLTAGE, value)); + zassert_equal(0, sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_AMBIENT_TEMP)); + zassert_equal(0, sensor_channel_get(fixture->dev, SENSOR_CHAN_AMBIENT_TEMP, value)); + zassert_equal(0, sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_CURRENT)); + zassert_equal(0, sensor_channel_get(fixture->dev, SENSOR_CHAN_CURRENT, value)); +} + /*** TEST-SUITE: ADLTC2990 Measurement Mode 1 3***/ struct adltc2990_1_3_fixture { @@ -98,6 +176,7 @@ ZTEST_F(adltc2990_1_3, test_die_temperature) CHECK_TEMPERATURE(temp_value, 0, -40.00, SENSOR_CHAN_DIE_TEMP); } + ZTEST_F(adltc2990_1_3, test_ambient_temperature) { /* 0b00000001 0b10010001 +25.0625 */ @@ -300,6 +379,17 @@ ZTEST_F(adltc2990_7_3, test_available_channels) zassert_equal(-EINVAL, sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_CURRENT)); } +ZTEST_F(adltc2990_7_3, test_is_device_busy) +{ + uint8_t is_busy = BIT(0); + + adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_STATUS, &is_busy); + zassert_equal(-EBUSY, sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_ALL)); + is_busy = 0; + adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_STATUS, &is_busy); + zassert_equal(0, sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_ALL)); +} + ZTEST_F(adltc2990_7_3, test_die_temperature) { /* The following values are taken from datasheet and should translate to 398.1250K */ @@ -309,6 +399,11 @@ ZTEST_F(adltc2990_7_3, test_die_temperature) adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_INTERNAL_TEMP_MSB, &msb); adltc2990_emul_set_reg(fixture->target, ADLTC2990_REG_INTERNAL_TEMP_LSB, &lsb); + struct sensor_value *die_temp_value_null = (struct sensor_value *)NULL; + + zassert_equal(-EINVAL, + sensor_channel_get(fixture->dev, SENSOR_CHAN_ALL, die_temp_value_null)); + struct sensor_value die_temp_value[1]; CHECK_TEMPERATURE(die_temp_value, 0, 398.1250, SENSOR_CHAN_DIE_TEMP); @@ -372,3 +467,38 @@ ZTEST_F(adltc2990_7_3, test_V1_V2_V3_V4_VCC) zassert_equal(6, voltage_values[4].val1); } + +/*** TEST-SUITE: ADLTC2990 Measurement Mode Incorrect***/ +struct adltc2990_incorrect_fixture { + const struct device *dev; + const struct emul *target; +}; + +static void *adltc2990_incorrect_setup(void) +{ + static struct adltc2990_incorrect_fixture fixture = { + .dev = DEVICE_DT_GET(DT_NODELABEL(adltc2990_incorrect)), + .target = EMUL_DT_GET(DT_NODELABEL(adltc2990_incorrect)), + }; + + zassert_not_null(fixture.dev); + zassert_not_null(fixture.target); + return &fixture; +} + +static void adltc2990_incorrect_before(void *f) +{ + struct adltc2990_incorrect_fixture *fixture = f; + + adltc2990_emul_reset(fixture->target); +} + +ZTEST_SUITE(adltc2990_incorrect, NULL, adltc2990_incorrect_setup, adltc2990_incorrect_before, NULL, + NULL); + +ZTEST_F(adltc2990_incorrect, test_current_cannot_be_measured) +{ + struct sensor_value current[1]; + + zassert_equal(-EINVAL, sensor_channel_get(fixture->dev, SENSOR_CHAN_CURRENT, current)); +} From aa25fe06a5b73efb78dda530a57efadbccd6696b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 11 Nov 2023 19:47:24 +0000 Subject: [PATCH 0346/1049] ci: compliance: undef list few configs used in optional modules The Kconfig check fails when running the script locally for undefined symbols if the checkout does not include optional modules (the default behavior). Add these symbol to the Kconfig undef list. Signed-off-by: Fabio Baltieri --- scripts/ci/check_compliance.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index cbbd0da9b667ff2..8779fddda6686b7 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -643,6 +643,8 @@ def check_no_undef_outside_kconfig(self, kconf): "BTTESTER_LOG_LEVEL", # Used in tests/bluetooth/tester "BTTESTER_LOG_LEVEL_DBG", # Used in tests/bluetooth/tester "CDC_ACM_PORT_NAME_", + "CHRE", # Optional module + "CHRE_LOG_LEVEL_DBG", # Optional module "CLOCK_STM32_SYSCLK_SRC_", "CMU", "COMPILER_RT_RTLIB", @@ -689,6 +691,7 @@ def check_no_undef_outside_kconfig(self, kconf): "PEDO_THS_MIN", "REG1", "REG2", + "RIMAGE_SIGNING_SCHEMA", # Optional module "SAMPLE_MODULE_LOG_LEVEL", # Used as an example in samples/subsys/logging "SAMPLE_MODULE_LOG_LEVEL_DBG", # Used in tests/subsys/logging/log_api "LOG_BACKEND_MOCK_OUTPUT_DEFAULT", #Referenced in tests/subsys/logging/log_syst From 09521832be405b5732494ad8be9417923d7d6150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sun, 12 Nov 2023 14:35:54 +0700 Subject: [PATCH 0347/1049] drivers: pinctrl: kinetis: use clock control API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the direct use of the HAL API to configure clocks and use Zephyr's clock control API instead. Currently the PORT peripherals of the Kinetis family are either clocked by PCC in the case of KE1xF devices, or by SIM for the rest of the devices. PCC clock driver converts internally the subsys clock name into the clock gate address. SIM clock driver expects this conversion to be done by the caller. Signed-off-by: Manuel Argüelles --- drivers/pinctrl/pinctrl_kinetis.c | 35 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/pinctrl/pinctrl_kinetis.c b/drivers/pinctrl/pinctrl_kinetis.c index 5fdb07a8cedf99e..45ac0ebe3cfd464 100644 --- a/drivers/pinctrl/pinctrl_kinetis.c +++ b/drivers/pinctrl/pinctrl_kinetis.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 NXP + * Copyright (c) 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,9 +7,13 @@ #define DT_DRV_COMPAT nxp_kinetis_pinmux +#include #include +#include #include +LOG_MODULE_REGISTER(pinctrl_kinetis, CONFIG_PINCTRL_LOG_LEVEL); + /* Port register addresses. */ static PORT_Type *ports[] = { (PORT_Type *)DT_REG_ADDR(DT_NODELABEL(porta)), @@ -28,7 +32,8 @@ static PORT_Type *ports[] = { #define PINCFG(mux) ((mux) & Z_PINCTRL_KINETIS_PCR_MASK) struct pinctrl_mcux_config { - clock_ip_name_t clock_ip_name; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; }; int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, @@ -51,24 +56,36 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, static int pinctrl_mcux_init(const struct device *dev) { const struct pinctrl_mcux_config *config = dev->config; + int err; + + if (!device_is_ready(config->clock_dev)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } - CLOCK_EnableClock(config->clock_ip_name); + err = clock_control_on(config->clock_dev, config->clock_subsys); + if (err) { + LOG_ERR("failed to enable clock (err %d)", err); + return -EINVAL; + } return 0; } -#if DT_NODE_HAS_STATUS(DT_INST(0, nxp_kinetis_ke1xf_sim), okay) -#define INST_DT_CLOCK_IP_NAME(n) \ - DT_REG_ADDR(DT_INST_PHANDLE(n, clocks)) + DT_INST_CLOCKS_CELL(n, name) -#else -#define INST_DT_CLOCK_IP_NAME(n) \ +#if DT_NODE_HAS_STATUS(DT_INST(0, nxp_kinetis_sim), okay) +#define PINCTRL_MCUX_DT_INST_CLOCK_SUBSYS(n) \ CLK_GATE_DEFINE(DT_INST_CLOCKS_CELL(n, offset), \ DT_INST_CLOCKS_CELL(n, bits)) +#else +#define PINCTRL_MCUX_DT_INST_CLOCK_SUBSYS(n) \ + DT_INST_CLOCKS_CELL(n, name) #endif #define PINCTRL_MCUX_INIT(n) \ static const struct pinctrl_mcux_config pinctrl_mcux_##n##_config = {\ - .clock_ip_name = INST_DT_CLOCK_IP_NAME(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t) \ + PINCTRL_MCUX_DT_INST_CLOCK_SUBSYS(n), \ }; \ \ DEVICE_DT_INST_DEFINE(n, \ From 9e29c70a1f0e70ed020265f4d965b8cd89649f00 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Mon, 13 Nov 2023 12:00:47 +0900 Subject: [PATCH 0348/1049] arch: riscv: fix hangup in boot if hart0 is not boot hart This patch changes the section of riscv_cpu_wake_flag variable to noinit from bss to fix hangup of RISC-V multicore boot if hart0 is not boot hart (CONFIG_RV_BOOT_HART != 0). Current boot sequence initializes a riscv_cpu_wake_flag to -1 but this variable is unintentionally changed to 0 by boot hart. This is because the variable is placed in bss section so this patch changes the section of the variable to noinit. Signed-off-by: Katsuhiro Suzuki --- arch/riscv/core/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index a5499d4e16b6d95..6154450e58d2a6a 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -16,7 +16,7 @@ volatile struct { void *arg; } riscv_cpu_init[CONFIG_MP_MAX_NUM_CPUS]; -volatile uintptr_t riscv_cpu_wake_flag; +volatile uintptr_t __noinit riscv_cpu_wake_flag; volatile uintptr_t riscv_cpu_boot_flag; volatile void *riscv_cpu_sp; From d9a30c1f0a60f540d7362e377f9c0eea431b07c2 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Mon, 13 Nov 2023 15:30:26 -0600 Subject: [PATCH 0349/1049] docs: Remove out of date examples The examples in the RTIO docs were nice but continuously became out of date without being updated. This is unfortunately the downside of doc-only samples like this. Some real, buildable, samples right be better but will take a little time to write up. In the meantime drop the examples in the docs to avoid confusion. Signed-off-by: Tom Burdick --- doc/services/rtio/index.rst | 208 ------------------------------------ 1 file changed, 208 deletions(-) diff --git a/doc/services/rtio/index.rst b/doc/services/rtio/index.rst index b82972d7f687b6f..88c5f29a0754d1c 100644 --- a/doc/services/rtio/index.rst +++ b/doc/services/rtio/index.rst @@ -212,214 +212,6 @@ There is a small cost to each RTIO context and iodev. This cost could be weighed against using a thread for each concurrent I/O operation or custom queues and threads per peripheral. RTIO is much lower cost than that. -Examples -******** - -Examples speak loudly about the intended uses and goals of an API. So several key -examples are presented below. Some are entirely plausible today without a -big leap. Others (the sensor example) would require additional work in other -APIs outside of RTIO as a sub system and are theoretical. - -Chained Blocking Requests -========================= - -A common scenario is needing to write the register address to then read from. -This can be accomplished by chaining a write into a read operation. - -The transaction on i2c is implicit for each operation chain. - -.. code-block:: C - - RTIO_I2C_IODEV(i2c_dev, I2C_DT_SPEC_INST(n)); - RTIO_DEFINE(ez_io, 4, 4); - static uint16_t reg_addr; - static uint8_t buf[32]; - - int do_some_io(void) - { - struct rtio_sqe *write_sqe = rtio_spsc_acquire(ez_io.sq); - struct rtio_sqe *read_sqe = rtio_spsc_acquire(ez_io.sq); - - rtio_sqe_prep_write(write_sqe, i2c_dev, RTIO_PRIO_LOW, ®_addr, 2); - write_sqe->flags = RTIO_SQE_CHAINED; /* the next item in the queue will wait on this one */ - - rtio_sqe_prep_read(read_sqe, i2c_dev, RTIO_PRIO_LOW, buf, 32); - - rtio_submit(rtio_inplace_executor, &ez_io, 2); - - struct rtio_cqe *read_cqe = rtio_spsc_consume(ez_io.cq); - struct rtio_cqe *write_cqe = rtio_spsc_consume(ez_io.cq); - - if(read_cqe->result < 0) { - LOG_ERR("read failed!"); - } - - if(write_cqe->result < 0) { - LOG_ERR("write failed!"); - } - - rtio_spsc_release(ez_io.cq); - rtio_spsc_release(ez_io.cq); - } - -Non blocking device to device -============================= - -Imagine wishing to read from one device on an I2C bus and then write the same -buffer to a device on a SPI bus without blocking the thread or setting up -callbacks or other IPC notification mechanisms. - -Perhaps an I2C temperature sensor and a SPI lowrawan module. The following is a -simplified version of that potential operation chain. - -.. code-block:: C - - RTIO_I2C_IODEV(i2c_dev, I2C_DT_SPEC_INST(n)); - RTIO_SPI_IODEV(spi_dev, SPI_DT_SPEC_INST(m)); - - RTIO_DEFINE(ez_io, 4, 4); - static uint8_t buf[32]; - - int do_some_io(void) - { - uint32_t read, write; - struct rtio_sqe *read_sqe = rtio_spsc_acquire(ez_io.sq); - rtio_sqe_prep_read(read_sqe, i2c_dev, RTIO_PRIO_LOW, buf, 32); - read_sqe->flags = RTIO_SQE_CHAINED; /* the next item in the queue will wait on this one */ - - /* Safe to do as the chained operation *ensures* that if one fails all subsequent ops fail */ - struct rtio_sqe *write_sqe = rtio_spsc_acquire(ez_io.sq); - rtio_sqe_prep_write(write_sqe, spi_dev, RTIO_PRIO_LOW, buf, 32); - - /* call will return immediately without blocking if possible */ - rtio_submit(rtio_inplace_executor, &ez_io, 0); - - /* These calls might return NULL if the operations have not yet completed! */ - for (int i = 0; i < 2; i++) { - struct rtio_cqe *cqe = rtio_spsc_consume(ez_io.cq); - while(cqe == NULL) { - cqe = rtio_spsc_consume(ez_io.cq); - k_yield(); - } - if(cqe->userdata == &read && cqe->result < 0) { - LOG_ERR("read from i2c failed!"); - } - if(cqe->userdata == &write && cqe->result < 0) { - LOG_ERR("write to spi failed!"); - } - /* Must release the completion queue event after consume */ - rtio_spsc_release(ez_io.cq); - } - } - -Nested iodevs for Devices on Buses (Sensors), Theoretical -========================================================= - -Consider a device like a sensor or audio codec sitting on a bus. - -Its useful to consider that the sensor driver can use RTIO to do I/O on the SPI -bus, while also being an RTIO device itself. The sensor iodev can set aside a -small portion of the buffer in front or in back to store some metadata describing -the format of the data. This metadata could then be used in creating a sensor -readings iterator which lazily lets you map over each reading, doing -calculations such as FIR/IIR filtering, or perhaps translating the readings into -other numerical formats with useful measurement units such as SI. RTIO is a -common movement API and allows for such uses while not deciding the mechanism. - -This same sort of setup could be done for other data streams such as audio or -video. - -.. code-block:: C - - /* Note that the sensor device itself can use RTIO to get data over I2C/SPI - * potentially with DMA, but we don't need to worry about that here - * All we need to know is the device tree node_id and that it can be an iodev - */ - RTIO_SENSOR_IODEV(sensor_dev, DEVICE_DT_GET(DT_NODE(super6axis)); - - RTIO_DEFINE(ez_io, 4, 4); - - - /* The sensor driver decides the minimum buffer size for us, we decide how - * many bufs. This could be a typical multiple of a fifo packet the sensor - * produces, ICM42688 for example produces a FIFO packet of 20 bytes in - * 20bit mode at 32KHz so perhaps we'd like to get 4 buffers of 4ms of data - * each in this setup to process on. and its already been defined here for us. - */ - #include - static uint8_t bufs[4][ICM42688_RTIO_BUF_SIZE]; - - int do_some_sensors(void) { - /* Obtain a dmac executor from the DMA device */ - struct device *dma = DEVICE_DT_GET(DT_NODE(dma0)); - const struct rtio_executor *rtio_dma_exec = - dma_rtio_executor(dma); - - /* - * Set the executor for our queue context - */ - rtio_set_executor(ez_io, rtio_dma_exec); - - /* Mostly we want to feed the sensor driver enough buffers to fill while - * we wait and process! Small enough to process quickly with low latency, - * big enough to not spend all the time setting transfers up. - * - * It's assumed here that the sensor has been configured already - * and each FIFO watermark interrupt that occurs it attempts - * to pull from the queue, fill the buffer with a small metadata - * offset using its own rtio request to the SPI bus using DMA. - */ - for(int i = 0; i < 4; i++) { - struct rtio_sqe *read_sqe = rtio_spsc_acquire(ez_io.sq); - - rtio_sqe_prep_read(read_sqe, sensor_dev, RTIO_PRIO_HIGH, bufs[i], ICM42688_RTIO_BUF_SIZE); - } - struct device *sensor = DEVICE_DT_GET(DT_NODE(super6axis)); - struct sensor_reader reader; - struct sensor_channels channels[4] = { - SENSOR_TIMESTAMP_CHANNEL, - SENSOR_CHANNEL(int32_t, SENSOR_ACC_X, 0, SENSOR_RAW), - SENSOR_CHANNEL(int32_t SENSOR_ACC_Y, 0, SENSOR_RAW), - SENSOR_CHANNEL(int32_t, SENSOR_ACC_Z, 0, SENSOR_RAW), - }; - while (true) { - /* call will wait for one completion event */ - rtio_submit(ez_io, 1); - struct rtio_cqe *cqe = rtio_spsc_consume(ez_io.cq); - if(cqe->result < 0) { - LOG_ERR("read failed!"); - goto next; - } - - /* Bytes read into the buffer */ - int32_t bytes_read = cqe->result; - - /* Retrieve soon to be reusable buffer pointer from completion */ - uint8_t *buf = cqe->userdata; - - - /* Get an iterator (reader) that obtains sensor readings in integer - * form, 16 bit signed values in the native sensor reading format - */ - res = sensor_reader(sensor, buf, cqe->result, &reader, channels, - sizeof(channels)); - __ASSERT(res == 0); - while(sensor_reader_next(&reader)) { - printf("time(raw): %d, acc (x,y,z): (%d, %d, %d)\n", - channels[0].value.u32, channels[1].value.i32, - channels[2].value.i32, channels[3].value.i32); - } - - next: - /* Release completion queue event */ - rtio_spsc_release(ez_io.cq); - - /* resubmit a read request with the newly freed buffer to the sensor */ - struct rtio_sqe *read_sqe = rtio_spsc_acquire(ez_io.sq); - rtio_sqe_prep_read(read_sqe, sensor_dev, RTIO_PRIO_HIGH, buf, ICM20649_RTIO_BUF_SIZE); - } - } - API Reference ************* From 09c69731cd0e5f68c5b3352dfeb5fc9ad6fd8bc7 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 7 Nov 2023 12:41:04 +0100 Subject: [PATCH 0350/1049] Bluetooth: Controller: Reduce RTN for requested Max Transport Latency Add implementation to reduce CIG's CIS retransmissions so as to meet the Host requested Maximum Transport Latency. Signed-off-by: Vinayak Kariappa Chettimada --- .../controller/ll_sw/ull_central_iso.c | 28 +++++++++++++++++-- .../audio/test_scripts/cap_unicast_ac_11_i.sh | 2 +- .../test_scripts/cap_unicast_ac_11_ii.sh | 2 +- .../audio/test_scripts/cap_unicast_ac_5.sh | 2 +- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index 474b8d0dbe9e7f1..b0eac97a80c58cc 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -147,7 +147,6 @@ uint8_t ll_cis_parameters_set(uint8_t cis_id, } /* TODO: - * - Drop retransmissions to stay within Max_Transmission_Latency instead of asserting * - Calculate ISO_Interval to allow SDU_Interval < ISO_Interval */ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) @@ -311,6 +310,8 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) } num_cis = cig->lll.num_cis; + +ll_cig_parameters_commit_retry: handle_iter = UINT16_MAX; /* 1) Acquire CIS instances and initialize instance data. @@ -520,8 +521,29 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) if (!cig->central.test) { /* Make sure specified Max_Transport_Latency is not exceeded */ - LL_ASSERT(c_latency <= cig->c_latency); - LL_ASSERT(p_latency <= cig->p_latency); + if ((c_latency > cig->c_latency) || (p_latency > cig->p_latency)) { + /* Check if we can reduce RTN to meet requested latency */ + if (!cis->central.c_rtn && !cis->central.p_rtn) { + /* Actual latency exceeds the Max. Transport Latency */ + err = BT_HCI_ERR_INVALID_PARAM; + + /* Release allocated resources and exit */ + goto ll_cig_parameters_commit_cleanup; + } + + /* Reduce the RTN to meet host requested latency. + * NOTE: Both central and peripheral retransmission is reduced for + * simplicity. + */ + if (cis->central.c_rtn) { + cis->central.c_rtn--; + } + if (cis->central.p_rtn) { + cis->central.p_rtn--; + } + + goto ll_cig_parameters_commit_retry; + } } c_max_latency = MAX(c_max_latency, c_latency); diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_i.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_i.sh index 1fac51ec6c2464c..0356cd0b5947285 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_i.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_i.sh @@ -46,5 +46,5 @@ Execute_AC_11_I 48_1_1 48_1_1 Execute_AC_11_I 48_2_1 48_2_1 Execute_AC_11_I 48_3_1 48_3_1 Execute_AC_11_I 48_4_1 48_4_1 -# Execute_AC_11_I 48_5_1 48_5_1 # ASSERTION FAIL [c_latency <= cig->c_latency] +Execute_AC_11_I 48_5_1 48_5_1 Execute_AC_11_I 48_6_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_ii.sh index 1908be1110b2891..c83bdc8c4be7918 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_ii.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_ii.sh @@ -50,5 +50,5 @@ Execute_AC_11_II 48_1_1 48_1_1 Execute_AC_11_II 48_2_1 48_2_1 Execute_AC_11_II 48_3_1 48_3_1 Execute_AC_11_II 48_4_1 48_4_1 -# Execute_AC_11_II 48_5_1 48_5_1 # Controller assert: ASSERTION FAIL [c_latency <= cig->c_latency] +Execute_AC_11_II 48_5_1 48_5_1 Execute_AC_11_II 48_6_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_5.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_5.sh index 33b186a7fc305c8..5eb9f6f5e30df39 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_5.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_5.sh @@ -46,4 +46,4 @@ Execute_AC_5 48_2_1 48_2_1 Execute_AC_5 48_3_1 48_3_1 Execute_AC_5 48_4_1 48_4_1 Execute_AC_5 48_5_1 48_5_1 -# Execute_AC_5 48_6_1 48_6_1 # ASSERTION FAIL [c_latency <= cig->c_latency] +Execute_AC_5 48_6_1 48_6_1 From dd27dff492e12c83431e1a20ff843ad0754c1127 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 27 Aug 2023 13:56:31 -0400 Subject: [PATCH 0351/1049] tests: lib: c_lib: separate libc tests into smaller suites C library testing is mainly there to support what is necessary to support Zephyr. We do test a variety of libcs currently, which is where YAML comes in handy. However, the main libc testsuite can be overkill for testing some things, and might not be suitable for testing optional features. Create a 'common' subdirectory for common libc tests. Signed-off-by: Christopher Friedt --- tests/lib/c_lib/{ => common}/CMakeLists.txt | 2 +- tests/lib/c_lib/{ => common}/README.txt | 0 tests/lib/c_lib/{ => common}/prj.conf | 0 tests/lib/c_lib/{ => common}/src/main.c | 68 +++++++++---------- tests/lib/c_lib/{ => common}/src/test_qsort.c | 4 +- tests/lib/c_lib/{ => common}/src/test_sqrt.c | 4 +- tests/lib/c_lib/common/testcase.yaml | 45 ++++++++++++ tests/lib/c_lib/strerror/CMakeLists.txt | 8 +++ tests/lib/c_lib/{ => strerror}/Kconfig | 0 tests/lib/c_lib/strerror/prj.conf | 2 + .../test_strerror.c => strerror/src/main.c} | 6 +- tests/lib/c_lib/{ => strerror}/testcase.yaml | 46 ++++++------- 12 files changed, 121 insertions(+), 64 deletions(-) rename tests/lib/c_lib/{ => common}/CMakeLists.txt (90%) rename tests/lib/c_lib/{ => common}/README.txt (100%) rename tests/lib/c_lib/{ => common}/prj.conf (100%) rename tests/lib/c_lib/{ => common}/src/main.c (96%) rename tests/lib/c_lib/{ => common}/src/test_qsort.c (98%) rename tests/lib/c_lib/{ => common}/src/test_sqrt.c (99%) create mode 100644 tests/lib/c_lib/common/testcase.yaml create mode 100644 tests/lib/c_lib/strerror/CMakeLists.txt rename tests/lib/c_lib/{ => strerror}/Kconfig (100%) create mode 100644 tests/lib/c_lib/strerror/prj.conf rename tests/lib/c_lib/{src/test_strerror.c => strerror/src/main.c} (95%) rename tests/lib/c_lib/{ => strerror}/testcase.yaml (74%) diff --git a/tests/lib/c_lib/CMakeLists.txt b/tests/lib/c_lib/common/CMakeLists.txt similarity index 90% rename from tests/lib/c_lib/CMakeLists.txt rename to tests/lib/c_lib/common/CMakeLists.txt index 2d5c65a0329a3c2..1731374ae7cd009 100644 --- a/tests/lib/c_lib/CMakeLists.txt +++ b/tests/lib/c_lib/common/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(c_lib) +project(libc_common) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) diff --git a/tests/lib/c_lib/README.txt b/tests/lib/c_lib/common/README.txt similarity index 100% rename from tests/lib/c_lib/README.txt rename to tests/lib/c_lib/common/README.txt diff --git a/tests/lib/c_lib/prj.conf b/tests/lib/c_lib/common/prj.conf similarity index 100% rename from tests/lib/c_lib/prj.conf rename to tests/lib/c_lib/common/prj.conf diff --git a/tests/lib/c_lib/src/main.c b/tests/lib/c_lib/common/src/main.c similarity index 96% rename from tests/lib/c_lib/src/main.c rename to tests/lib/c_lib/common/src/main.c index 2347dfebce18239..986dba55f8e917a 100644 --- a/tests/lib/c_lib/src/main.c +++ b/tests/lib/c_lib/common/src/main.c @@ -55,7 +55,7 @@ #pragma GCC diagnostic ignored "-Wstringop-truncation" #endif -ZTEST_SUITE(test_c_lib, NULL, NULL, NULL, NULL, NULL); +ZTEST_SUITE(libc_common, NULL, NULL, NULL, NULL, NULL); /* * variables used during limits library testing; must be marked as "volatile" @@ -74,7 +74,7 @@ volatile long long_one = 1L; * */ -ZTEST(test_c_lib, test_limits) +ZTEST(libc_common, test_limits) { zassert_true((long_max + long_one == LONG_MIN)); @@ -85,7 +85,7 @@ static ssize_t foobar(void) return -1; } -ZTEST(test_c_lib, test_ssize_t) +ZTEST(libc_common, test_ssize_t) { zassert_true(foobar() < 0); } @@ -95,7 +95,7 @@ ZTEST(test_c_lib, test_ssize_t) * @brief Test boolean types and values library * */ -ZTEST(test_c_lib, test_stdbool) +ZTEST(libc_common, test_stdbool) { zassert_true((true == 1), "true value"); @@ -115,7 +115,7 @@ volatile size_t size_of_long_variable = sizeof(long_variable); * @brief Test standard type definitions library * */ -ZTEST(test_c_lib, test_stddef) +ZTEST(libc_common, test_stddef) { #ifdef CONFIG_64BIT zassert_true((size_of_long_variable == 8), "sizeof"); @@ -137,7 +137,7 @@ volatile uint32_t unsigned_int = 0xffffff00; * @brief Test integer types library * */ -ZTEST(test_c_lib, test_stdint) +ZTEST(libc_common, test_stdint) { zassert_true((unsigned_int + unsigned_byte + 1u == 0U)); @@ -162,7 +162,7 @@ ZTEST(test_c_lib, test_stdint) * @brief Test time_t to make sure it is at least 64 bits * */ -ZTEST(test_c_lib, test_time_t) +ZTEST(libc_common, test_time_t) { #ifdef CONFIG_EXTERNAL_LIBC ztest_test_skip(); @@ -184,7 +184,7 @@ char buffer[BUFSIZE]; * @brief Test string memset * */ -ZTEST(test_c_lib, test_memset) +ZTEST(libc_common, test_memset) { int i, ret; const char set = 'a'; @@ -206,7 +206,7 @@ ZTEST(test_c_lib, test_memset) * @see strlen(), strnlen(). * */ -ZTEST(test_c_lib, test_strlen) +ZTEST(libc_common, test_strlen) { (void)memset(buffer, '\0', BUFSIZE); (void)memset(buffer, 'b', 5); /* 5 is BUFSIZE / 2 */ @@ -223,7 +223,7 @@ ZTEST(test_c_lib, test_strlen) * @see strcmp(), strncasecmp(). * */ -ZTEST(test_c_lib, test_strcmp) +ZTEST(libc_common, test_strcmp) { strcpy(buffer, "eeeee"); char test = 0; @@ -244,7 +244,7 @@ ZTEST(test_c_lib, test_strcmp) * * @see strncmp(). */ -ZTEST(test_c_lib, test_strncmp) +ZTEST(libc_common, test_strncmp) { static const char pattern[] = "eeeeeeeeeeee"; @@ -271,7 +271,7 @@ ZTEST(test_c_lib, test_strncmp) * * @see strcpy(). */ -ZTEST(test_c_lib, test_strcpy) +ZTEST(libc_common, test_strcpy) { (void)memset(buffer, '\0', BUFSIZE); strcpy(buffer, "10 chars!\0"); @@ -285,7 +285,7 @@ ZTEST(test_c_lib, test_strcpy) * * @see strncpy(). */ -ZTEST(test_c_lib, test_strncpy) +ZTEST(libc_common, test_strncpy) { int ret; @@ -304,7 +304,7 @@ ZTEST(test_c_lib, test_strncpy) * * @see strchr(). */ -ZTEST(test_c_lib, test_strchr) +ZTEST(libc_common, test_strchr) { char *rs = NULL; int ret; @@ -328,7 +328,7 @@ ZTEST(test_c_lib, test_strchr) * * @see strspn(),strcspn(). */ -ZTEST(test_c_lib, test_strxspn) +ZTEST(libc_common, test_strxspn) { const char *empty = ""; const char *cset = "abc"; @@ -352,7 +352,7 @@ ZTEST(test_c_lib, test_strxspn) * * @see memcmp() */ -ZTEST(test_c_lib, test_memcmp) +ZTEST(libc_common, test_memcmp) { int ret; unsigned char m1[] = "a\0$def"; @@ -383,7 +383,7 @@ int cmp_func(const void *a, const void *b) return (*(int *)a - *(int *)b); } -ZTEST(test_c_lib, test_bsearch) +ZTEST(libc_common, test_bsearch) { void *result = NULL; int arr[5] = { 2, 5, 20, 50, 60 }; @@ -404,7 +404,7 @@ ZTEST(test_c_lib, test_bsearch) * * @see abs() */ -ZTEST(test_c_lib, test_abs) +ZTEST(libc_common, test_abs) { int val = -5, value = 5; @@ -418,7 +418,7 @@ ZTEST(test_c_lib, test_abs) * * @see atoi() */ -ZTEST(test_c_lib, test_atoi) +ZTEST(libc_common, test_atoi) { zassert_equal(atoi("123"), 123, "atoi error"); zassert_equal(atoi("2c5"), 2, "atoi error"); @@ -442,7 +442,7 @@ ZTEST(test_c_lib, test_atoi) * isprint(), isspace(), isupper(), isxdigit(). * */ -ZTEST(test_c_lib, test_checktype) +ZTEST(libc_common, test_checktype) { static const char exp_alnum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; @@ -537,7 +537,7 @@ ZTEST(test_c_lib, test_checktype) * * @see memchr(). */ -ZTEST(test_c_lib, test_memchr) +ZTEST(libc_common, test_memchr) { static const char str[] = "testfunction"; @@ -556,7 +556,7 @@ ZTEST(test_c_lib, test_memchr) * * @see memcpy(). */ -ZTEST(test_c_lib, test_memcpy) +ZTEST(libc_common, test_memcpy) { /* make sure the buffer is word aligned */ uintptr_t mem_dest[4] = {0}; @@ -606,7 +606,7 @@ ZTEST(test_c_lib, test_memcpy) * * @see memmove(). */ -ZTEST(test_c_lib, test_memmove) +ZTEST(libc_common, test_memmove) { char move_buffer[6] = "12123"; char move_new[6] = {0}; @@ -632,7 +632,7 @@ ZTEST(test_c_lib, test_memmove) * @see strcat(), strcspn(), strncat(). * */ -ZTEST(test_c_lib, test_str_operate) +ZTEST(libc_common, test_str_operate) { char str1[10] = "aabbcc", ncat[10] = "ddee"; char *str2 = "b"; @@ -684,7 +684,7 @@ ZTEST(test_c_lib, test_str_operate) * @see strtol(). * */ -ZTEST(test_c_lib, test_strtol) +ZTEST(libc_common, test_strtol) { static const char buf1[] = "+10379aegi"; static const char buf2[] = " -10379aegi"; @@ -773,7 +773,7 @@ ZTEST(test_c_lib, test_strtol) * @see strtoul(). * */ -ZTEST(test_c_lib, test_strtoul) +ZTEST(libc_common, test_strtoul) { static const char buf1[] = "+10379aegi"; static const char buf2[] = " -10379aegi"; @@ -1012,7 +1012,7 @@ void test_strtoull(void) * @brief test convert function * */ -ZTEST(test_c_lib, test_tolower_toupper) +ZTEST(libc_common, test_tolower_toupper) { static const char test[] = "Az09Za{#!"; static const char toup[] = "AZ09ZA{#!"; @@ -1056,7 +1056,7 @@ void test_strtok_r_do(char *str, char *sep, int tlen, } } -ZTEST(test_c_lib, test_strtok_r) +ZTEST(libc_common, test_strtok_r) { static const char * const tc01[] = { "1", "2", "3", "4", "5" }; @@ -1077,7 +1077,7 @@ ZTEST(test_c_lib, test_strtok_r) * * @see gmtime(),gmtime_r(). */ -ZTEST(test_c_lib, test_time) +ZTEST(libc_common, test_time) { time_t tests1 = 0; time_t tests2 = -5; @@ -1099,7 +1099,7 @@ ZTEST(test_c_lib, test_time) * @brief Test rand function * */ -ZTEST(test_c_lib, test_rand) +ZTEST(libc_common, test_rand) { #ifdef CONFIG_MINIMAL_LIBC int a; @@ -1117,7 +1117,7 @@ ZTEST(test_c_lib, test_rand) * @brief Test srand function * */ -ZTEST(test_c_lib, test_srand) +ZTEST(libc_common, test_srand) { #ifdef CONFIG_MINIMAL_LIBC int a; @@ -1151,7 +1151,7 @@ ZTEST(test_c_lib, test_srand) * @brief Test rand function for reproducibility * */ -ZTEST(test_c_lib, test_rand_reproducibility) +ZTEST(libc_common, test_rand_reproducibility) { #ifdef CONFIG_MINIMAL_LIBC int a; @@ -1218,7 +1218,7 @@ ZTEST(test_c_lib, test_rand_reproducibility) * * @see abort(). */ -ZTEST(test_c_lib, test_abort) +ZTEST(libc_common, test_abort) { #ifdef CONFIG_EXTERNAL_LIBC ztest_test_skip(); @@ -1247,7 +1247,7 @@ static struct k_thread tdata; #endif -ZTEST(test_c_lib, test_exit) +ZTEST(libc_common, test_exit) { #ifdef CONFIG_EXTERNAL_LIBC ztest_test_skip(); diff --git a/tests/lib/c_lib/src/test_qsort.c b/tests/lib/c_lib/common/src/test_qsort.c similarity index 98% rename from tests/lib/c_lib/src/test_qsort.c rename to tests/lib/c_lib/common/src/test_qsort.c index 9cfddc396c9c9f2..37db119803f69ab 100644 --- a/tests/lib/c_lib/src/test_qsort.c +++ b/tests/lib/c_lib/common/src/test_qsort.c @@ -22,7 +22,7 @@ static int compare_ints(const void *a, const void *b) * @brief Test qsort function * */ -ZTEST(test_c_lib, test_qsort) +ZTEST(libc_common, test_qsort) { { int actual_int[] = { 1, 3, 2 }; @@ -138,7 +138,7 @@ static int compare_ints_with_boolp_arg(const void *a, const void *b, void *argp) return (aa > bb) - (aa < bb); } -ZTEST(test_c_lib, test_qsort_r) +ZTEST(libc_common, test_qsort_r) { bool arg = false; diff --git a/tests/lib/c_lib/src/test_sqrt.c b/tests/lib/c_lib/common/src/test_sqrt.c similarity index 99% rename from tests/lib/c_lib/src/test_sqrt.c rename to tests/lib/c_lib/common/src/test_sqrt.c index 99af27717af3b58..59edad9c1935ad9 100644 --- a/tests/lib/c_lib/src/test_sqrt.c +++ b/tests/lib/c_lib/common/src/test_sqrt.c @@ -94,7 +94,7 @@ static int isnanf(float x) #define MAX_FLOAT_ERROR_PERCENT (3.5e-5) #define MAX_DOUBLE_ERROR_PERCENT (4.5e-14) -ZTEST(test_c_lib, test_sqrtf) +ZTEST(libc_common, test_sqrtf) { int i; float exponent, resf, square, root_squared; @@ -164,7 +164,7 @@ int32_t *p_root_squared = (int32_t *)&root_squared; TC_PRINT("test_sqrtf max error %d counts\n", max_error); } -ZTEST(test_c_lib, test_sqrt) +ZTEST(libc_common, test_sqrt) { int i; double resd, error, square, root_squared, exponent; diff --git a/tests/lib/c_lib/common/testcase.yaml b/tests/lib/c_lib/common/testcase.yaml new file mode 100644 index 000000000000000..28a7d54194c52fa --- /dev/null +++ b/tests/lib/c_lib/common/testcase.yaml @@ -0,0 +1,45 @@ +common: + tags: + - clib + ignore_faults: true + integration_platforms: + - mps2_an385 +tests: + libraries.libc.common: {} + libraries.libc.common.minimal: + filter: CONFIG_MINIMAL_LIBC_SUPPORTED + tags: minimal_libc + extra_configs: + - CONFIG_MINIMAL_LIBC=y + - CONFIG_MINIMAL_LIBC_NON_REENTRANT_FUNCTIONS=y + - CONFIG_MINIMAL_LIBC_RAND=y + libraries.libc.common.newlib: + filter: CONFIG_NEWLIB_LIBC_SUPPORTED + min_ram: 32 + tags: newlib + extra_configs: + - CONFIG_NEWLIB_LIBC=y + libraries.libc.common.newlib_nano: + filter: CONFIG_NEWLIB_LIBC_SUPPORTED and CONFIG_HAS_NEWLIB_LIBC_NANO + tags: newlib + extra_configs: + - CONFIG_NEWLIB_LIBC=y + - CONFIG_NEWLIB_LIBC_NANO=y + libraries.libc.common.picolibc: + filter: CONFIG_PICOLIBC_SUPPORTED + tags: picolibc + extra_configs: + - CONFIG_PICOLIBC=y + libraries.libc.common.picolibc.module: + filter: CONFIG_ZEPHYR_PICOLIBC_MODULE + tags: picolibc + extra_configs: + - CONFIG_PICOLIBC=y + - CONFIG_PICOLIBC_USE_MODULE=y + libraries.libc.common.picolibc.notls: + filter: CONFIG_ZEPHYR_PICOLIBC_MODULE + tags: picolibc + extra_configs: + - CONFIG_PICOLIBC=y + - CONFIG_PICOLIBC_USE_MODULE=y + - CONFIG_THREAD_LOCAL_STORAGE=n diff --git a/tests/lib/c_lib/strerror/CMakeLists.txt b/tests/lib/c_lib/strerror/CMakeLists.txt new file mode 100644 index 000000000000000..350d76aa6d71018 --- /dev/null +++ b/tests/lib/c_lib/strerror/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(c_lib_strerror) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/lib/c_lib/Kconfig b/tests/lib/c_lib/strerror/Kconfig similarity index 100% rename from tests/lib/c_lib/Kconfig rename to tests/lib/c_lib/strerror/Kconfig diff --git a/tests/lib/c_lib/strerror/prj.conf b/tests/lib/c_lib/strerror/prj.conf new file mode 100644 index 000000000000000..e39776e7067ab86 --- /dev/null +++ b/tests/lib/c_lib/strerror/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_TEST_USERSPACE=y diff --git a/tests/lib/c_lib/src/test_strerror.c b/tests/lib/c_lib/strerror/src/main.c similarity index 95% rename from tests/lib/c_lib/src/test_strerror.c rename to tests/lib/c_lib/strerror/src/main.c index 9b7dde334d840c5..8bfd06bbff549c0 100644 --- a/tests/lib/c_lib/src/test_strerror.c +++ b/tests/lib/c_lib/strerror/src/main.c @@ -13,7 +13,7 @@ #include -ZTEST(test_c_lib, test_strerror) +ZTEST(libc_strerror, test_strerror) { const char *expected; const char *actual; @@ -55,7 +55,7 @@ ZTEST(test_c_lib, test_strerror) } } -ZTEST(test_c_lib, test_strerror_r) +ZTEST(libc_strerror, test_strerror_r) { const char *expected; char actual[] = {'1', 'n', 'v', 'a', '1', '1', 'd', ' ', 'a', @@ -96,3 +96,5 @@ ZTEST(test_c_lib, test_strerror_r) /* do not change errno on failure */ zassert_equal(0, errno, ""); } + +ZTEST_SUITE(libc_strerror, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/lib/c_lib/testcase.yaml b/tests/lib/c_lib/strerror/testcase.yaml similarity index 74% rename from tests/lib/c_lib/testcase.yaml rename to tests/lib/c_lib/strerror/testcase.yaml index eb42925958a1514..2475c3e31ecd412 100644 --- a/tests/lib/c_lib/testcase.yaml +++ b/tests/lib/c_lib/strerror/testcase.yaml @@ -2,50 +2,50 @@ common: tags: - clib integration_platforms: - - mps2_an385 + - qemu_x86 tests: - libraries.libc: - ignore_faults: true - libraries.libc.picolibc: - filter: CONFIG_PICOLIBC_SUPPORTED - tags: picolibc - ignore_faults: true + libraries.libc.strerror.minimal.strerror_table: + filter: CONFIG_MINIMAL_LIBC_SUPPORTED + tags: minimal_libc extra_configs: - - CONFIG_PICOLIBC=y - libraries.libc.newlib: + - CONFIG_MINIMAL_LIBC=y + - CONFIG_MINIMAL_LIBC_STRING_ERROR_TABLE=y + - CONFIG_MINIMAL_LIBC_NON_REENTRANT_FUNCTIONS=y + libraries.libc.strerror.minimal.no_strerror_table: + filter: CONFIG_MINIMAL_LIBC_SUPPORTED + tags: minimal_libc + extra_configs: + - CONFIG_MINIMAL_LIBC=y + - CONFIG_MINIMAL_LIBC_STRING_ERROR_TABLE=n + - CONFIG_MINIMAL_LIBC_NON_REENTRANT_FUNCTIONS=y + libraries.libc.strerror.newlib: filter: CONFIG_NEWLIB_LIBC_SUPPORTED min_ram: 32 tags: newlib ignore_faults: true extra_configs: - CONFIG_NEWLIB_LIBC=y - libraries.libc.newlib_nano: + libraries.libc.strerror.newlib_nano: filter: CONFIG_NEWLIB_LIBC_SUPPORTED and CONFIG_HAS_NEWLIB_LIBC_NANO tags: newlib ignore_faults: true extra_configs: - CONFIG_NEWLIB_LIBC=y - CONFIG_NEWLIB_LIBC_NANO=y - libraries.libc.minimal.strerror_table: - filter: CONFIG_MINIMAL_LIBC_SUPPORTED - tags: minimal_libc - extra_configs: - - CONFIG_MINIMAL_LIBC=y - - CONFIG_MINIMAL_LIBC_STRING_ERROR_TABLE=y - libraries.libc.minimal.no_strerror_table: - filter: CONFIG_MINIMAL_LIBC_SUPPORTED - tags: minimal_libc + libraries.libc.strerror.picolibc: + filter: CONFIG_PICOLIBC_SUPPORTED + tags: picolibc + ignore_faults: true extra_configs: - - CONFIG_MINIMAL_LIBC=y - - CONFIG_MINIMAL_LIBC_STRING_ERROR_TABLE=n - libraries.libc.picolibc.module: + - CONFIG_PICOLIBC=y + libraries.libc.strerror.picolibc.module: filter: CONFIG_ZEPHYR_PICOLIBC_MODULE tags: picolibc ignore_faults: true extra_configs: - CONFIG_PICOLIBC=y - CONFIG_PICOLIBC_USE_MODULE=y - libraries.libc.picolibc.notls: + libraries.libc.strerror.picolibc.notls: filter: CONFIG_ZEPHYR_PICOLIBC_MODULE tags: picolibc ignore_faults: true From 97668b8b09c310eea4f383c48a78e55e6cec8163 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 24 Jul 2023 20:51:00 -0400 Subject: [PATCH 0352/1049] libc: common: add support for iso c11 threads This change capitalizes on newly added support for dynamic thread stacks and the existing pthread support to provide an implementation of the ISO C11 `` API. Signed-off-by: Christopher Friedt --- include/zephyr/posix/sys/stat.h | 2 +- lib/libc/common/CMakeLists.txt | 3 + lib/libc/common/Kconfig | 10 +++ lib/libc/common/include/machine/_threads.h | 20 +++++ lib/libc/common/include/threads.h | 47 ++++++++++++ lib/libc/common/source/thrd/thrd.c | 85 ++++++++++++++++++++++ 6 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 lib/libc/common/include/machine/_threads.h create mode 100644 lib/libc/common/include/threads.h create mode 100644 lib/libc/common/source/thrd/thrd.c diff --git a/include/zephyr/posix/sys/stat.h b/include/zephyr/posix/sys/stat.h index 01251c65ace08d1..2d19df29700a623 100644 --- a/include/zephyr/posix/sys/stat.h +++ b/include/zephyr/posix/sys/stat.h @@ -114,7 +114,7 @@ struct stat { #define st_mtime st_mtim.tv_sec #define st_ctime st_ctim.tv_sec #if defined(__linux) && defined(__x86_64__) - __uint64_t __glibc_reserved[3]; + uint64_t __glibc_reserved[3]; #endif #else #if defined(__rtems__) diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index 048977511869b82..c65b6a1aa12cb83 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -1,11 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_system_include_directories(include) + zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ABORT source/stdlib/abort.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c) +zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD source/thrd/thrd.c) # Prevent compiler from optimizing calloc into an infinite recursive call zephyr_library_compile_options($) diff --git a/lib/libc/common/Kconfig b/lib/libc/common/Kconfig index 56ac8f7b22b3193..dc22d0c2108d5f1 100644 --- a/lib/libc/common/Kconfig +++ b/lib/libc/common/Kconfig @@ -67,3 +67,13 @@ config COMMON_LIBC_STRNLEN bool help common implementation of strnlen(). + +config COMMON_LIBC_THRD + bool "C11 API support" + depends on DYNAMIC_THREAD + # Note: the POSIX_API dependency is only necessary until common elements + # of C11 threads and POSIX API can be abstracted out to a common library. + depends on POSIX_API + default y + help + Common implementation of C11 API. diff --git a/lib/libc/common/include/machine/_threads.h b/lib/libc/common/include/machine/_threads.h new file mode 100644 index 000000000000000..2c61ac0d81a919f --- /dev/null +++ b/lib/libc/common/include/machine/_threads.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_COMMON_INCLUDE_MACHINE__THREADS_H_ +#define ZEPHYR_LIB_LIBC_COMMON_INCLUDE_MACHINE__THREADS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int thrd_t; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_COMMON_INCLUDE_MACHINE__THREADS_H_ */ diff --git a/lib/libc/common/include/threads.h b/lib/libc/common/include/threads.h new file mode 100644 index 000000000000000..f045a23830c10f7 --- /dev/null +++ b/lib/libc/common/include/threads.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_COMMON_INCLUDE_THREADS_H_ +#define ZEPHYR_LIB_LIBC_COMMON_INCLUDE_THREADS_H_ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*thrd_start_t)(void *arg); + +enum { + thrd_success, +#define thrd_success thrd_success + thrd_nomem, +#define thrd_nomem thrd_nomem + thrd_timedout, +#define thrd_timedout thrd_timedout + thrd_busy, +#define thrd_busy thrd_busy + thrd_error, +#define thrd_error thrd_error +}; + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec *duration, struct timespec *remaining); +void thrd_yield(void); +_Noreturn void thrd_exit(int res); +int thrd_detach(thrd_t thr); +int thrd_join(thrd_t thr, int *res); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_COMMON_INCLUDE_THREADS_H_ */ diff --git a/lib/libc/common/source/thrd/thrd.c b/lib/libc/common/source/thrd/thrd.c new file mode 100644 index 000000000000000..d811fe31ce6b7fc --- /dev/null +++ b/lib/libc/common/source/thrd/thrd.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include + +struct thrd_trampoline_arg { + thrd_start_t func; + void *arg; +}; + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + typedef void *(*pthread_func_t)(void *arg); + + pthread_func_t pfunc = (pthread_func_t)func; + + switch (pthread_create(thr, NULL, pfunc, arg)) { + case 0: + return thrd_success; + case EAGAIN: + return thrd_nomem; + default: + return thrd_error; + } +} + +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return pthread_equal(lhs, rhs); +} + +thrd_t thrd_current(void) +{ + return pthread_self(); +} + +int thrd_sleep(const struct timespec *duration, struct timespec *remaining) +{ + return nanosleep(duration, remaining); +} + +void thrd_yield(void) +{ + (void)sched_yield(); +} + +FUNC_NORETURN void thrd_exit(int res) +{ + pthread_exit(INT_TO_POINTER(res)); + + CODE_UNREACHABLE; +} + +int thrd_detach(thrd_t thr) +{ + switch (pthread_detach(thr)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} + +int thrd_join(thrd_t thr, int *res) +{ + void *ret; + + switch (pthread_join(thr, &ret)) { + case 0: + if (res != NULL) { + *res = POINTER_TO_INT(ret); + } + return thrd_success; + default: + return thrd_error; + } +} From ded97fd5b31f1d135543598a89e00ea1c6ae7f89 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 24 Jul 2023 20:52:20 -0400 Subject: [PATCH 0353/1049] tests: libc: add tests for iso c11 threads Add tests to verify functionality of the C11 `` API. Signed-off-by: Christopher Friedt --- tests/lib/c_lib/thrd/CMakeLists.txt | 9 ++ tests/lib/c_lib/thrd/prj.conf | 9 ++ tests/lib/c_lib/thrd/src/thrd.c | 167 ++++++++++++++++++++++++++++ tests/lib/c_lib/thrd/src/thrd.h | 31 ++++++ tests/lib/c_lib/thrd/testcase.yaml | 52 +++++++++ 5 files changed, 268 insertions(+) create mode 100644 tests/lib/c_lib/thrd/CMakeLists.txt create mode 100644 tests/lib/c_lib/thrd/prj.conf create mode 100644 tests/lib/c_lib/thrd/src/thrd.c create mode 100644 tests/lib/c_lib/thrd/src/thrd.h create mode 100644 tests/lib/c_lib/thrd/testcase.yaml diff --git a/tests/lib/c_lib/thrd/CMakeLists.txt b/tests/lib/c_lib/thrd/CMakeLists.txt new file mode 100644 index 000000000000000..795545f0cb9e9b9 --- /dev/null +++ b/tests/lib/c_lib/thrd/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(c11_threads) + +FILE(GLOB app_sources src/*.c) + +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/lib/c_lib/thrd/prj.conf b/tests/lib/c_lib/thrd/prj.conf new file mode 100644 index 000000000000000..dfa2820de7c4643 --- /dev/null +++ b/tests/lib/c_lib/thrd/prj.conf @@ -0,0 +1,9 @@ +CONFIG_ZTEST=y +CONFIG_TEST_USERSPACE=y +CONFIG_ZTEST_FATAL_HOOK=y + +CONFIG_POSIX_API=y +CONFIG_THREAD_STACK_INFO=y +CONFIG_DYNAMIC_THREAD=y +CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 +CONFIG_COMMON_LIBC_THRD=y diff --git a/tests/lib/c_lib/thrd/src/thrd.c b/tests/lib/c_lib/thrd/src/thrd.c new file mode 100644 index 000000000000000..55cd1841c131fc0 --- /dev/null +++ b/tests/lib/c_lib/thrd/src/thrd.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "thrd.h" + +#include +#include + +#include +#include + +ZTEST(libc_thrd, test_thrd_sleep) +{ + int64_t end; + int64_t start; + struct timespec duration = {0}; + struct timespec remaining; + const uint16_t delay_ms[] = {0, 100, 200, 400}; + + zassert_not_equal(0, thrd_sleep(NULL, NULL)); + zassert_ok(thrd_sleep(&duration, NULL)); + zassert_ok(thrd_sleep(&duration, &duration)); + + for (int i = 0; i < ARRAY_SIZE(delay_ms); ++i) { + duration = (struct timespec){.tv_nsec = delay_ms[i] * NSEC_PER_MSEC}; + remaining = (struct timespec){.tv_sec = 4242, .tv_nsec = 4242}; + + printk("sleeping %d ms\n", delay_ms[i]); + start = k_uptime_get(); + zassert_ok(thrd_sleep(&duration, &remaining)); + end = k_uptime_get(); + zassert_equal(remaining.tv_sec, 0); + zassert_equal(remaining.tv_nsec, 0); + zassert_true(end - start >= delay_ms[i]); + } +} + +static int thrd_create_join_fn(void *arg) +{ + uintptr_t *x = (uintptr_t *)arg; + + if (x != NULL) { + *x = BIOS_FOOD; + } + + return FORTY_TWO; +} + +ZTEST(libc_thrd, test_thrd_create_join) +{ + thrd_t thr; + int res = 0; + uintptr_t x = 0; + thrd_start_t fun = thrd_create_join_fn; + + if (false) { + /* pthread_create() is not hardened for degenerate cases like this */ + zassert_equal(thrd_error, thrd_create(NULL, NULL, NULL)); + zassert_equal(thrd_error, thrd_create(NULL, NULL, &x)); + zassert_equal(thrd_error, thrd_create(NULL, fun, NULL)); + zassert_equal(thrd_error, thrd_create(NULL, fun, &x)); + zassert_equal(thrd_error, thrd_create(&thr, NULL, NULL)); + zassert_equal(thrd_error, thrd_create(&thr, NULL, &x)); + } + + zassert_equal(thrd_success, thrd_create(&thr, fun, NULL)); + zassert_equal(thrd_success, thrd_join(thr, NULL)); + + zassert_equal(thrd_success, thrd_create(&thr, fun, &x)); + zassert_equal(thrd_success, thrd_join(thr, &res)); + zassert_equal(BIOS_FOOD, x, "expected: %d actual: %d", BIOS_FOOD, x); + zassert_equal(FORTY_TWO, res); +} + +static int thrd_exit_fn(void *arg) +{ + uintptr_t *x = (uintptr_t *)arg; + + *x = BIOS_FOOD; + + thrd_exit(SEVENTY_THREE); + + return FORTY_TWO; + + CODE_UNREACHABLE; +} + +ZTEST(libc_thrd, test_thrd_exit) +{ + thrd_t thr; + int res = 0; + uintptr_t x = 0; + + zassert_equal(thrd_success, thrd_create(&thr, thrd_exit_fn, &x)); + zassert_equal(thrd_success, thrd_join(thr, &res)); + zassert_equal(BIOS_FOOD, x); + zassert_equal(SEVENTY_THREE, res); +} + +ZTEST(libc_thrd, test_thrd_yield) +{ + thrd_yield(); +} + +static thrd_t child; +static thrd_t parent; + +static int thrd_current_equal_fn(void *arg) +{ + ARG_UNUSED(arg); + + zassert_equal(thrd_current(), child); + zassert_not_equal(child, parent); + + zassert_true(thrd_equal(thrd_current(), child)); + zassert_false(thrd_equal(child, parent)); + + return 0; +} + +ZTEST(libc_thrd, test_thrd_current_equal) +{ + parent = thrd_current(); + + zassert_equal(thrd_success, thrd_create(&child, thrd_current_equal_fn, NULL)); + zassert_equal(thrd_success, thrd_join(child, NULL)); +} + +static bool detached_thread_is_probably_done; + +static int thrd_detach_fn(void *arg) +{ + ARG_UNUSED(arg); + + detached_thread_is_probably_done = true; + return SEVENTY_THREE; +} + +ZTEST(libc_thrd, test_thrd_detach) +{ + thrd_t thr; + + zassert_equal(thrd_success, thrd_create(&thr, thrd_detach_fn, NULL)); + zassert_equal(thrd_success, thrd_detach(thr)); + zassert_equal(thrd_error, thrd_join(thr, NULL)); + + do { + k_msleep(100); + } while (!detached_thread_is_probably_done); + + zassert_equal(thrd_error, thrd_join(thr, NULL)); +} + +ZTEST(libc_thrd, test_thrd_reuse) +{ + thrd_t thr; + + for (int i = 0; i < FORTY_TWO; ++i) { + zassert_equal(thrd_success, thrd_create(&thr, thrd_create_join_fn, NULL)); + zassert_equal(thrd_success, thrd_join(thr, NULL)); + } +} + +ZTEST_SUITE(libc_thrd, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/lib/c_lib/thrd/src/thrd.h b/tests/lib/c_lib/thrd/src/thrd.h new file mode 100644 index 000000000000000..02861b2ac6ea9f4 --- /dev/null +++ b/tests/lib/c_lib/thrd/src/thrd.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TESTS_LIB_CLIB_SRC_TEST_THRD_H_ +#define TESTS_LIB_CLIB_SRC_TEST_THRD_H_ + +#include + +#include +#include + +/* arbitrary magic numbers used for testing */ +#define BIOS_FOOD 0xb105f00d +#define FORTY_TWO 42 +#define SEVENTY_THREE 73 +#define DONT_CARE 0x370ca2e5 + +static inline void timespec_add_ms(struct timespec *ts, uint32_t ms) +{ + bool oflow; + + ts->tv_nsec += ms * NSEC_PER_MSEC; + oflow = ts->tv_nsec >= NSEC_PER_SEC; + ts->tv_sec += oflow; + ts->tv_nsec -= oflow * NSEC_PER_SEC; +} + +#endif diff --git a/tests/lib/c_lib/thrd/testcase.yaml b/tests/lib/c_lib/thrd/testcase.yaml new file mode 100644 index 000000000000000..ecba688407f7317 --- /dev/null +++ b/tests/lib/c_lib/thrd/testcase.yaml @@ -0,0 +1,52 @@ +common: + tags: + - clib c11 threads + filter: not CONFIG_NATIVE_APPLICATION + integration_platforms: + - qemu_x86 + platform_exclude: + - native_posix + - native_posix_64 +tests: + libraries.libc.c11_threads.minimal: + tags: minimal_libc + filter: CONFIG_MINIMAL_LIBC_SUPPORTED + extra_configs: + - CONFIG_MINIMAL_LIBC=y + - CONFIG_MINIMAL_LIBC_NON_REENTRANT_FUNCTIONS=y + - CONFIG_MINIMAL_LIBC_RAND=y + libraries.libc.c11_threads.picolibc: + filter: CONFIG_PICOLIBC_SUPPORTED + tags: picolibc + extra_configs: + - CONFIG_PICOLIBC=y + libraries.libc.c11_threads.picolibc.module: + filter: CONFIG_ZEPHYR_PICOLIBC_MODULE + tags: picolibc + extra_configs: + - CONFIG_PICOLIBC=y + - CONFIG_PICOLIBC_USE_MODULE=y + - CONFIG_THREAD_LOCAL_STORAGE=y + libraries.libc.c11_threads.picolibc.notls: + filter: CONFIG_ZEPHYR_PICOLIBC_MODULE + tags: picolibc + extra_configs: + - CONFIG_PICOLIBC=y + - CONFIG_PICOLIBC_USE_MODULE=y + - CONFIG_THREAD_LOCAL_STORAGE=n + libraries.libc.c11_threads.newlib: + filter: CONFIG_NEWLIB_LIBC_SUPPORTED + arch_exclude: + - posix + min_ram: 32 + tags: newlib + extra_configs: + - CONFIG_NEWLIB_LIBC=y + libraries.libc.c11_threads.newlib_nano: + filter: CONFIG_NEWLIB_LIBC_SUPPORTED and CONFIG_HAS_NEWLIB_LIBC_NANO + arch_exclude: + - posix + tags: newlib + extra_configs: + - CONFIG_NEWLIB_LIBC=y + - CONFIG_NEWLIB_LIBC_NANO=y From 576ae7f677919bd1236f5e1b2f428122838cefa7 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 2 Aug 2023 10:38:45 -0400 Subject: [PATCH 0354/1049] lib: libc: common: add C11 mutex implementation Add support for C11 mutexes to go with C11 threads. Signed-off-by: Christopher Friedt --- lib/libc/common/CMakeLists.txt | 5 +- lib/libc/common/include/machine/_threads.h | 1 + lib/libc/common/include/threads.h | 16 ++++ lib/libc/common/source/thrd/mtx.c | 99 ++++++++++++++++++++++ 4 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 lib/libc/common/source/thrd/mtx.c diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index c65b6a1aa12cb83..2a78574715c7056 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -8,7 +8,10 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ABORT source/stdlib/abort.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c) -zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD source/thrd/thrd.c) +zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD + source/thrd/mtx.c + source/thrd/thrd.c + ) # Prevent compiler from optimizing calloc into an infinite recursive call zephyr_library_compile_options($) diff --git a/lib/libc/common/include/machine/_threads.h b/lib/libc/common/include/machine/_threads.h index 2c61ac0d81a919f..e0360410a47b579 100644 --- a/lib/libc/common/include/machine/_threads.h +++ b/lib/libc/common/include/machine/_threads.h @@ -11,6 +11,7 @@ extern "C" { #endif +typedef int mtx_t; typedef int thrd_t; #ifdef __cplusplus diff --git a/lib/libc/common/include/threads.h b/lib/libc/common/include/threads.h index f045a23830c10f7..13e57cc9a8d17a8 100644 --- a/lib/libc/common/include/threads.h +++ b/lib/libc/common/include/threads.h @@ -40,6 +40,22 @@ _Noreturn void thrd_exit(int res); int thrd_detach(thrd_t thr); int thrd_join(thrd_t thr, int *res); +enum { + mtx_plain, +#define mtx_plain mtx_plain + mtx_timed, +#define mtx_timed mtx_timed + mtx_recursive, +#define mtx_recursive mtx_recursive +}; + +int mtx_init(mtx_t *mutex, int type); +void mtx_destroy(mtx_t *mutex); +int mtx_lock(mtx_t *mutex); +int mtx_timedlock(mtx_t *ZRESTRICT mutex, const struct timespec *ZRESTRICT time_point); +int mtx_trylock(mtx_t *mutex); +int mtx_unlock(mtx_t *mutex); + #ifdef __cplusplus } #endif diff --git a/lib/libc/common/source/thrd/mtx.c b/lib/libc/common/source/thrd/mtx.c new file mode 100644 index 000000000000000..9746ea64fe6901e --- /dev/null +++ b/lib/libc/common/source/thrd/mtx.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +int mtx_init(mtx_t *mutex, int type) +{ + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_t *attrp = NULL; + + switch (type) { + case mtx_plain: + case mtx_timed: + break; + case mtx_plain | mtx_recursive: + case mtx_timed | mtx_recursive: + attrp = &attr; + ret = pthread_mutexattr_init(attrp); + __ASSERT_NO_MSG(ret == 0); + + ret = pthread_mutexattr_settype(attrp, PTHREAD_MUTEX_RECURSIVE); + __ASSERT_NO_MSG(ret == 0); + break; + default: + return thrd_error; + } + + switch (pthread_mutex_init(mutex, attrp)) { + case 0: + ret = thrd_success; + break; + default: + ret = thrd_error; + break; + } + + if (attrp != NULL) { + (void)pthread_mutexattr_destroy(attrp); + } + + return ret; +} + +void mtx_destroy(mtx_t *mutex) +{ + (void)pthread_mutex_destroy(mutex); +} + +int mtx_lock(mtx_t *mutex) +{ + switch (pthread_mutex_lock(mutex)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} + +int mtx_timedlock(mtx_t *restrict mutex, const struct timespec *restrict time_point) +{ + switch (pthread_mutex_timedlock(mutex, time_point)) { + case 0: + return thrd_success; + case ETIMEDOUT: + return thrd_timedout; + default: + return thrd_error; + } +} + +int mtx_trylock(mtx_t *mutex) +{ + switch (pthread_mutex_trylock(mutex)) { + case 0: + return thrd_success; + case EBUSY: + return thrd_busy; + default: + return thrd_error; + } +} + +int mtx_unlock(mtx_t *mutex) +{ + switch (pthread_mutex_unlock(mutex)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} From 0c2da383d33933a6557646ec8827311de7441b30 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 2 Aug 2023 10:40:41 -0400 Subject: [PATCH 0355/1049] tests: lib: c_lib: add tests for C11 mutexes Add tests to cover C11 mutexes Signed-off-by: Christopher Friedt --- tests/lib/c_lib/thrd/src/mtx.c | 177 +++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 tests/lib/c_lib/thrd/src/mtx.c diff --git a/tests/lib/c_lib/thrd/src/mtx.c b/tests/lib/c_lib/thrd/src/mtx.c new file mode 100644 index 000000000000000..433ea0e64e4c301 --- /dev/null +++ b/tests/lib/c_lib/thrd/src/mtx.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "thrd.h" + +#include +#include + +#include +#include + +static const int valid_mtx_types[] = { + mtx_plain, + mtx_timed, + mtx_plain | mtx_recursive, + mtx_timed | mtx_recursive, +}; + +ZTEST(libc_mtx, test_mtx_init) +{ + mtx_t mutex; + + zassert_not_equal(thrd_success, mtx_init(NULL, FORTY_TWO)); + zassert_not_equal(thrd_success, mtx_init(&mutex, FORTY_TWO)); + + if (false) { + /* pthread_mutexattr_init() is not hardened against this */ + zassert_not_equal(thrd_success, mtx_init(NULL, mtx_plain)); + zassert_not_equal(thrd_success, mtx_init((mtx_t *)BIOS_FOOD, FORTY_TWO)); + } + + for (size_t i = 0; i < ARRAY_SIZE(valid_mtx_types); ++i) { + int type = valid_mtx_types[i]; + + zassert_equal(thrd_success, mtx_init(&mutex, type)); + mtx_destroy(&mutex); + } +} + +ZTEST(libc_mtx, test_mtx_destroy) +{ + mtx_t mutex; + + if (false) { + /* degenerate cases */ + /* pthread_mutex_destroy() is not hardened against these */ + mtx_destroy(NULL); + mtx_destroy((mtx_t *)BIOS_FOOD); + } + + zassert_equal(thrd_success, mtx_init(&mutex, mtx_plain)); + mtx_destroy(&mutex); +} + +ZTEST(libc_mtx, test_mtx_lock) +{ + mtx_t mutex; + + if (false) { + /* pthread_mutex_lock() is not hardened against this */ + zassert_not_equal(thrd_success, mtx_lock(NULL)); + zassert_not_equal(thrd_success, mtx_lock((mtx_t *)BIOS_FOOD)); + } + + /* test plain mutex */ + for (size_t i = 0; i < ARRAY_SIZE(valid_mtx_types); ++i) { + int type = valid_mtx_types[i]; + + zassert_equal(thrd_success, mtx_init(&mutex, type)); + zassert_equal(thrd_success, mtx_lock(&mutex)); + if ((type & mtx_recursive) == 0) { + if (false) { + /* pthread_mutex_lock() is not hardened against this */ + zassert_not_equal(thrd_success, mtx_lock((&mutex))); + } + } else { + zassert_equal(thrd_success, mtx_lock(&mutex)); + zassert_equal(thrd_success, mtx_unlock(&mutex)); + } + zassert_equal(thrd_success, mtx_unlock(&mutex)); + mtx_destroy(&mutex); + } +} + +#define TIMEDLOCK_TIMEOUT_MS 200 +#define TIMEDLOCK_TIMEOUT_DELAY_MS 100 + +BUILD_ASSERT(TIMEDLOCK_TIMEOUT_DELAY_MS >= 100, "TIMEDLOCK_TIMEOUT_DELAY_MS too small"); +BUILD_ASSERT(TIMEDLOCK_TIMEOUT_MS >= 2 * TIMEDLOCK_TIMEOUT_DELAY_MS, + "TIMEDLOCK_TIMEOUT_MS too small"); + +static int mtx_timedlock_fn(void *arg) +{ + struct timespec time_point; + mtx_t *mutex = (mtx_t *)arg; + + zassume_ok(clock_gettime(CLOCK_MONOTONIC, &time_point)); + timespec_add_ms(&time_point, TIMEDLOCK_TIMEOUT_MS); + + return mtx_timedlock(mutex, &time_point); +} + +ZTEST(libc_mtx, test_mtx_timedlock) +{ + int ret; + thrd_t th; + mtx_t mutex; + + /* + * mtx_timed here is technically unnecessary, because all pthreads can + * be used for timed locks, but that is sort of peeking into the + * implementation + */ + zassert_equal(thrd_success, mtx_init(&mutex, mtx_timed)); + + printk("Expecting timedlock with timeout of %d ms to fail\n", TIMEDLOCK_TIMEOUT_MS); + zassert_equal(thrd_success, mtx_lock(&mutex)); + zassert_equal(thrd_success, thrd_create(&th, mtx_timedlock_fn, &mutex)); + zassert_equal(thrd_success, thrd_join(th, &ret)); + /* ensure timeout occurs */ + zassert_equal(thrd_timedout, ret); + + printk("Expecting timedlock with timeout of %d ms to succeed after 100ms\n", + TIMEDLOCK_TIMEOUT_MS); + zassert_equal(thrd_success, thrd_create(&th, mtx_timedlock_fn, &mutex)); + /* unlock before timeout expires */ + k_msleep(TIMEDLOCK_TIMEOUT_DELAY_MS); + zassert_equal(thrd_success, mtx_unlock(&mutex)); + zassert_equal(thrd_success, thrd_join(th, &ret)); + /* ensure lock is successful, in spite of delay */ + zassert_equal(thrd_success, ret); + + mtx_destroy(&mutex); +} + +static int mtx_trylock_fn(void *arg) +{ + mtx_t *mutex = (mtx_t *)arg; + + return mtx_trylock(mutex); +} + +ZTEST(libc_mtx, test_mtx_trylock) +{ + int ret; + thrd_t th; + mtx_t mutex; + + zassert_equal(thrd_success, mtx_init(&mutex, mtx_plain)); + + /* ensure trylock fails when lock is held */ + zassert_equal(thrd_success, mtx_lock(&mutex)); + zassert_equal(thrd_success, thrd_create(&th, mtx_trylock_fn, &mutex)); + zassert_equal(thrd_success, thrd_join(th, &ret)); + /* ensure lock fails */ + zassert_equal(thrd_busy, ret); + + mtx_destroy(&mutex); +} + +ZTEST(libc_mtx, test_mtx_unlock) +{ + mtx_t mutex = (mtx_t)BIOS_FOOD; + + /* degenerate case */ + zassert_not_equal(thrd_success, mtx_unlock(&mutex)); + + zassert_equal(thrd_success, mtx_init(&mutex, mtx_plain)); + zassert_equal(thrd_success, mtx_lock(&mutex)); + zassert_equal(thrd_success, mtx_unlock(&mutex)); + mtx_destroy(&mutex); +} + +ZTEST_SUITE(libc_mtx, NULL, NULL, NULL, NULL, NULL); From 7e539e2706a7cc33d79bc2b528795f1b6c407843 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 3 Aug 2023 21:45:50 -0400 Subject: [PATCH 0356/1049] libc: common: support for C11 condition variables Add C11 condition variable support to go with C11 threads and mutexes. Signed-off-by: Christopher Friedt --- lib/libc/common/CMakeLists.txt | 1 + lib/libc/common/include/machine/_threads.h | 1 + lib/libc/common/include/threads.h | 7 +++ lib/libc/common/source/thrd/cnd.c | 71 ++++++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 lib/libc/common/source/thrd/cnd.c diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index 2a78574715c7056..a52d8dc8d423361 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -9,6 +9,7 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD + source/thrd/cnd.c source/thrd/mtx.c source/thrd/thrd.c ) diff --git a/lib/libc/common/include/machine/_threads.h b/lib/libc/common/include/machine/_threads.h index e0360410a47b579..0b82b876505719a 100644 --- a/lib/libc/common/include/machine/_threads.h +++ b/lib/libc/common/include/machine/_threads.h @@ -11,6 +11,7 @@ extern "C" { #endif +typedef int cnd_t; typedef int mtx_t; typedef int thrd_t; diff --git a/lib/libc/common/include/threads.h b/lib/libc/common/include/threads.h index 13e57cc9a8d17a8..f4a52f74b13e1a2 100644 --- a/lib/libc/common/include/threads.h +++ b/lib/libc/common/include/threads.h @@ -56,6 +56,13 @@ int mtx_timedlock(mtx_t *ZRESTRICT mutex, const struct timespec *ZRESTRICT time_ int mtx_trylock(mtx_t *mutex); int mtx_unlock(mtx_t *mutex); +int cnd_init(cnd_t *cond); +int cnd_wait(cnd_t *cond, mtx_t *mtx); +int cnd_timedwait(cnd_t *ZRESTRICT cond, mtx_t *ZRESTRICT mtx, const struct timespec *ZRESTRICT ts); +int cnd_signal(cnd_t *cond); +int cnd_broadcast(cnd_t *cond); +void cnd_destroy(cnd_t *cond); + #ifdef __cplusplus } #endif diff --git a/lib/libc/common/source/thrd/cnd.c b/lib/libc/common/source/thrd/cnd.c new file mode 100644 index 000000000000000..aea6f5cb78a4209 --- /dev/null +++ b/lib/libc/common/source/thrd/cnd.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +int cnd_broadcast(cnd_t *cond) +{ + switch (pthread_cond_broadcast(cond)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} + +void cnd_destroy(cnd_t *cond) +{ + (void)pthread_cond_destroy(cond); +} + +int cnd_init(cnd_t *cond) +{ + switch (pthread_cond_init(cond, NULL)) { + case 0: + return thrd_success; + case ENOMEM: + return thrd_nomem; + default: + return thrd_error; + } +} + +int cnd_signal(cnd_t *cond) +{ + switch (pthread_cond_signal(cond)) { + case 0: + return thrd_success; + case ENOMEM: + return thrd_nomem; + default: + return thrd_error; + } +} + +int cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, const struct timespec *restrict ts) +{ + switch (pthread_cond_timedwait(cond, mtx, ts)) { + case 0: + return thrd_success; + case ETIMEDOUT: + return thrd_timedout; + default: + return thrd_error; + } +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + switch (pthread_cond_wait(cond, mtx)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} From 70b03111ebaef374c9699418ef2883340de9cee3 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 3 Aug 2023 21:46:46 -0400 Subject: [PATCH 0357/1049] tests: lib: c_lib: tests for C11 condition variables Add tests for C11 condition variables. Signed-off-by: Christopher Friedt --- tests/lib/c_lib/thrd/src/cnd.c | 172 +++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 tests/lib/c_lib/thrd/src/cnd.c diff --git a/tests/lib/c_lib/thrd/src/cnd.c b/tests/lib/c_lib/thrd/src/cnd.c new file mode 100644 index 000000000000000..aaf00f9cb7b97aa --- /dev/null +++ b/tests/lib/c_lib/thrd/src/cnd.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "thrd.h" + +#include +#include + +#include + +#define WAIT_TIME_MS 100 + +static struct libc_cnd_fixture { + /* shared between threads in tests */ + cnd_t cond; + mtx_t mutex; + + /* de-duplicate local variables in test cases */ + int res1; + int res2; + thrd_t thrd1; + thrd_t thrd2; + bool do_timedwait; + bool is_broadcast; + struct timespec time_point; +} _libc_cnd_fixture; + +ZTEST_F(libc_cnd, test_cnd_init_destroy) +{ + /* degenerate cases */ + if (false) { + /* pthread_cond_init() pthread_cond_destroy() are not hardened against these */ + zassert_equal(thrd_error, cnd_init(NULL)); + zassert_equal(thrd_error, cnd_init((cnd_t *)BIOS_FOOD)); + cnd_destroy(NULL); + cnd_destroy((cnd_t *)BIOS_FOOD); + } + + /* happy path tested in before() / after() */ +} + +ZTEST_F(libc_cnd, test_cnd_errors) +{ + /* degenerate test cases */ + if (false) { + /* pthread_cond_*() are not hardened against these */ + zassert_equal(thrd_error, cnd_signal(NULL)); + zassert_equal(thrd_error, cnd_broadcast(NULL)); + zassert_equal(thrd_error, cnd_wait(NULL, NULL)); + zassert_equal(thrd_error, cnd_wait(NULL, &fixture->mutex)); + zassert_equal(thrd_error, cnd_wait(&fixture->cond, NULL)); + zassert_equal(thrd_error, cnd_timedwait(NULL, NULL, NULL)); + zassert_equal(thrd_error, cnd_timedwait(NULL, NULL, &fixture->time_point)); + zassert_equal(thrd_error, cnd_timedwait(NULL, &fixture->mutex, NULL)); + zassert_equal(thrd_error, + cnd_timedwait(NULL, &fixture->mutex, &fixture->time_point)); + zassert_equal(thrd_error, cnd_timedwait(&fixture->cond, NULL, NULL)); + zassert_equal(thrd_error, + cnd_timedwait(&fixture->cond, NULL, &fixture->time_point)); + zassert_equal(thrd_error, cnd_timedwait(&fixture->cond, &fixture->mutex, NULL)); + } +} + +static int test_cnd_thread_fn(void *arg) +{ + int res = thrd_success; + struct timespec time_point; + struct libc_cnd_fixture *const fixture = arg; + + if (fixture->do_timedwait) { + zassume_ok(clock_gettime(CLOCK_MONOTONIC, &time_point)); + timespec_add_ms(&time_point, WAIT_TIME_MS); + res = cnd_timedwait(&fixture->cond, &fixture->mutex, &time_point); + } else { + res = cnd_wait(&fixture->cond, &fixture->mutex); + } + + if (fixture->is_broadcast) { + /* re-signal so that the next thread wakes up too */ + zassert_equal(thrd_success, cnd_signal(&fixture->cond)); + } + + (void)mtx_unlock(&fixture->mutex); + + return res; +} + +static void tst_cnd_common(struct libc_cnd_fixture *fixture, size_t wait_ms, bool th2, int exp1, + int exp2) +{ + zassert_equal(thrd_success, mtx_lock(&fixture->mutex)); + + zassert_equal(thrd_success, thrd_create(&fixture->thrd1, test_cnd_thread_fn, fixture)); + if (th2) { + zassert_equal(thrd_success, + thrd_create(&fixture->thrd2, test_cnd_thread_fn, fixture)); + } + + k_msleep(wait_ms); + + if (fixture->is_broadcast) { + zassert_equal(thrd_success, cnd_broadcast(&fixture->cond)); + } else { + zassert_equal(thrd_success, cnd_signal(&fixture->cond)); + } + + zassert_equal(thrd_success, mtx_unlock(&fixture->mutex)); + + zassert_equal(thrd_success, thrd_join(fixture->thrd1, &fixture->res1)); + if (th2) { + zassert_equal(thrd_success, thrd_join(fixture->thrd2, &fixture->res2)); + } + + zassert_equal(exp1, fixture->res1); + if (th2) { + zassert_equal(exp2, fixture->res2); + } +} + +ZTEST_F(libc_cnd, test_cnd_signal_wait) +{ + tst_cnd_common(fixture, WAIT_TIME_MS / 2, false, thrd_success, DONT_CARE); +} + +ZTEST_F(libc_cnd, test_cnd_signal_timedwait) +{ + fixture->do_timedwait = true; + tst_cnd_common(fixture, WAIT_TIME_MS / 2, false, thrd_success, DONT_CARE); +} + +ZTEST_F(libc_cnd, test_cnd_timedwait_timeout) +{ + fixture->do_timedwait = true; + tst_cnd_common(fixture, WAIT_TIME_MS * 2, false, thrd_timedout, DONT_CARE); +} + +ZTEST_F(libc_cnd, test_cnd_broadcast_wait) +{ + fixture->is_broadcast = true; + tst_cnd_common(fixture, WAIT_TIME_MS, true, thrd_success, thrd_success); +} + +static void *setup(void) +{ + return &_libc_cnd_fixture; +} + +static void before(void *arg) +{ + struct libc_cnd_fixture *const fixture = arg; + + *fixture = (struct libc_cnd_fixture){ + .res1 = FORTY_TWO, + .res2 = SEVENTY_THREE, + }; + + zassert_equal(thrd_success, mtx_init(&fixture->mutex, mtx_plain)); + zassert_equal(thrd_success, cnd_init(&fixture->cond)); +} + +static void after(void *arg) +{ + struct libc_cnd_fixture *const fixture = arg; + + cnd_destroy(&fixture->cond); + mtx_destroy(&fixture->mutex); +} + +ZTEST_SUITE(libc_cnd, NULL, setup, before, after, NULL); From b9db7df628a6a81a436e0afb1a699cb73aa4cf5b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 25 Aug 2023 07:30:54 -0400 Subject: [PATCH 0358/1049] libc: common: support for C11 thread-specific storage Add C11 thread-specific storage (tss) support to go with C11 threads and mutexes. Signed-off-by: Christopher Friedt --- lib/libc/common/CMakeLists.txt | 1 + lib/libc/common/include/machine/_threads.h | 1 + lib/libc/common/include/threads.h | 11 +++++ lib/libc/common/source/thrd/tss.c | 47 ++++++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 lib/libc/common/source/thrd/tss.c diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index a52d8dc8d423361..a99ec825a005092 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -12,6 +12,7 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD source/thrd/cnd.c source/thrd/mtx.c source/thrd/thrd.c + source/thrd/tss.c ) # Prevent compiler from optimizing calloc into an infinite recursive call diff --git a/lib/libc/common/include/machine/_threads.h b/lib/libc/common/include/machine/_threads.h index 0b82b876505719a..2742384599cdcf4 100644 --- a/lib/libc/common/include/machine/_threads.h +++ b/lib/libc/common/include/machine/_threads.h @@ -14,6 +14,7 @@ extern "C" { typedef int cnd_t; typedef int mtx_t; typedef int thrd_t; +typedef int tss_t; #ifdef __cplusplus } diff --git a/lib/libc/common/include/threads.h b/lib/libc/common/include/threads.h index f4a52f74b13e1a2..c7d231444446b7e 100644 --- a/lib/libc/common/include/threads.h +++ b/lib/libc/common/include/threads.h @@ -63,6 +63,17 @@ int cnd_signal(cnd_t *cond); int cnd_broadcast(cnd_t *cond); void cnd_destroy(cnd_t *cond); +#ifndef thread_local +#define thread_local _Thread_local +#endif + +typedef void (*tss_dtor_t)(void *val); + +int tss_create(tss_t *key, tss_dtor_t destructor); +void *tss_get(tss_t key); +int tss_set(tss_t key, void *val); +void tss_delete(tss_t key); + #ifdef __cplusplus } #endif diff --git a/lib/libc/common/source/thrd/tss.c b/lib/libc/common/source/thrd/tss.c new file mode 100644 index 000000000000000..4b110d17170d686 --- /dev/null +++ b/lib/libc/common/source/thrd/tss.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +int tss_create(tss_t *key, tss_dtor_t destructor) +{ + switch (pthread_key_create(key, destructor)) { + case 0: + return thrd_success; + case EAGAIN: + return thrd_busy; + case ENOMEM: + return thrd_nomem; + default: + return thrd_error; + } +} + +void *tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +int tss_set(tss_t key, void *val) +{ + switch (pthread_setspecific(key, val)) { + case 0: + return thrd_success; + case ENOMEM: + return thrd_nomem; + default: + return thrd_error; + } +} + +void tss_delete(tss_t key) +{ + (void)pthread_key_delete(key); +} From 44a431bbba3de1aedf3ee7f18a9c6b3b4b114d9c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 25 Aug 2023 07:32:59 -0400 Subject: [PATCH 0359/1049] tests: lib: c_lib: tests for C11 thread-specific storage Add tests for C11 thread-specific storage. Signed-off-by: Christopher Friedt --- tests/lib/c_lib/thrd/src/tss.c | 97 ++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 tests/lib/c_lib/thrd/src/tss.c diff --git a/tests/lib/c_lib/thrd/src/tss.c b/tests/lib/c_lib/thrd/src/tss.c new file mode 100644 index 000000000000000..d68a6489dc57e55 --- /dev/null +++ b/tests/lib/c_lib/thrd/src/tss.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "thrd.h" + +#include +#include + +#include + +static tss_t key; +static int32_t destroyed_values[2]; +static const int32_t forty_two = FORTY_TWO; +static const int32_t seventy_three = SEVENTY_THREE; + +static void destroy_fn(void *arg) +{ + int32_t val = *(int32_t *)arg; + + switch (val) { + case FORTY_TWO: + destroyed_values[0] = FORTY_TWO; + break; + case SEVENTY_THREE: + destroyed_values[1] = SEVENTY_THREE; + break; + default: + zassert_true(val == FORTY_TWO || val == SEVENTY_THREE, "unexpected val %d", val); + } +} + +ZTEST(libc_tss, test_tss_create_delete) +{ + /* degenerate test cases */ + if (false) { + /* pthread_key_create() has not been hardened against this */ + zassert_equal(thrd_error, tss_create(NULL, NULL)); + zassert_equal(thrd_error, tss_create(NULL, destroy_fn)); + } + tss_delete(BIOS_FOOD); + + /* happy path tested in before() / after() */ +} + +static int thread_fn(void *arg) +{ + int32_t val = *(int32_t *)arg; + + zassert_equal(tss_get(key), NULL); + tss_set(key, arg); + zassert_equal(tss_get(key), arg); + + return val; +} + +/* test out separate threads doing tss_get() / tss_set() */ +ZTEST(libc_tss, test_tss_get_set) +{ + thrd_t thread1; + thrd_t thread2; + int res1 = BIOS_FOOD; + int res2 = BIOS_FOOD; + + /* degenerate test cases */ + zassert_is_null(tss_get(BIOS_FOOD)); + zassert_not_equal(thrd_success, tss_set(FORTY_TWO, (void *)BIOS_FOOD)); + zassert_is_null(tss_get(FORTY_TWO)); + + zassert_equal(thrd_success, thrd_create(&thread1, thread_fn, (void *)&forty_two)); + zassert_equal(thrd_success, thrd_create(&thread2, thread_fn, (void *)&seventy_three)); + + zassert_equal(thrd_success, thrd_join(thread1, &res1)); + zassert_equal(thrd_success, thrd_join(thread2, &res2)); + zassert_equal(FORTY_TWO, res1); + zassert_equal(SEVENTY_THREE, res2); + + zassert_equal(destroyed_values[0], FORTY_TWO); + zassert_equal(destroyed_values[1], SEVENTY_THREE); +} + +static void before(void *arg) +{ + destroyed_values[0] = 0; + destroyed_values[1] = 0; + + zassert_equal(thrd_success, tss_create(&key, destroy_fn)); +} + +static void after(void *arg) +{ + tss_delete(key); +} + +ZTEST_SUITE(libc_tss, NULL, NULL, before, after, NULL); From 4c58c6b4c4f02bbaf97e49f94397cd91f5587093 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 25 Aug 2023 08:02:46 -0400 Subject: [PATCH 0360/1049] libc: common: support for C11 call_once() Add C11 call_once() support to go with C11 threads and mutexes. Signed-off-by: Christopher Friedt --- lib/libc/common/CMakeLists.txt | 1 + lib/libc/common/include/machine/_threads.h | 9 +++++++++ lib/libc/common/include/threads.h | 2 ++ lib/libc/common/source/thrd/once.c | 16 ++++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 lib/libc/common/source/thrd/once.c diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index a99ec825a005092..4b101d8b84bdc97 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD source/thrd/cnd.c source/thrd/mtx.c + source/thrd/once.c source/thrd/thrd.c source/thrd/tss.c ) diff --git a/lib/libc/common/include/machine/_threads.h b/lib/libc/common/include/machine/_threads.h index 2742384599cdcf4..578536ca5c69425 100644 --- a/lib/libc/common/include/machine/_threads.h +++ b/lib/libc/common/include/machine/_threads.h @@ -11,10 +11,19 @@ extern "C" { #endif +#define ONCE_FLAG_INIT \ + { \ + 1, 0 \ + } + typedef int cnd_t; typedef int mtx_t; typedef int thrd_t; typedef int tss_t; +typedef struct { + int is_initialized; + int init_executed; +} once_flag; #ifdef __cplusplus } diff --git a/lib/libc/common/include/threads.h b/lib/libc/common/include/threads.h index c7d231444446b7e..b2a8c738389569c 100644 --- a/lib/libc/common/include/threads.h +++ b/lib/libc/common/include/threads.h @@ -74,6 +74,8 @@ void *tss_get(tss_t key); int tss_set(tss_t key, void *val); void tss_delete(tss_t key); +void call_once(once_flag *flag, void (*func)(void)); + #ifdef __cplusplus } #endif diff --git a/lib/libc/common/source/thrd/once.c b/lib/libc/common/source/thrd/once.c new file mode 100644 index 000000000000000..7cfd9983df8958a --- /dev/null +++ b/lib/libc/common/source/thrd/once.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +void call_once(once_flag *flag, void (*func)(void)) +{ + (void)pthread_once((pthread_once_t *)flag, func); +} From 2fc19aa033c43aab45e11d0c802ebce68d3953f7 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 25 Aug 2023 08:03:33 -0400 Subject: [PATCH 0361/1049] tests: lib: c_lib: tests for C11 call_once() Add tests for C11 call_once(). Signed-off-by: Christopher Friedt --- tests/lib/c_lib/thrd/src/once.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/lib/c_lib/thrd/src/once.c diff --git a/tests/lib/c_lib/thrd/src/once.c b/tests/lib/c_lib/thrd/src/once.c new file mode 100644 index 000000000000000..e239206d9b41ab7 --- /dev/null +++ b/tests/lib/c_lib/thrd/src/once.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "thrd.h" + +#include +#include + +#include + +static size_t number_of_calls; +static once_flag flag = ONCE_FLAG_INIT; + +static void once_func(void) +{ + number_of_calls++; +} + +ZTEST(libc_once, test_call_once) +{ + zassert_equal(number_of_calls, 0); + + call_once(&flag, once_func); + call_once(&flag, once_func); + call_once(&flag, once_func); + + zassert_equal(number_of_calls, 1); +} + +ZTEST_SUITE(libc_once, NULL, NULL, NULL, NULL, NULL); From 8366c1adb48c8f03f4c78adefbe9ad3ad49fb0d4 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 12:55:36 +0100 Subject: [PATCH 0362/1049] doc/hardware: Replace references to native_posix w native_sim Replace the references to native_posix with native_sim. Background: during this release native_sim is replacing native_posix as the main host test/development platform. Signed-off-by: Alberto Escolar Piedras --- doc/hardware/emulator/index.rst | 18 +++++++++--------- doc/hardware/peripherals/rtc.rst | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/hardware/emulator/index.rst b/doc/hardware/emulator/index.rst index 23ed94a192aecef..686f2b603424b6a 100644 --- a/doc/hardware/emulator/index.rst +++ b/doc/hardware/emulator/index.rst @@ -32,7 +32,7 @@ This is the ultimate application we want to run. :alt: Emulator architecture showing tests, emulators and drivers Below that are peripheral drivers, such as the AT24 EEPROM driver. We can test -peripheral drivers using an emulation driver connected via a native_posix I2C +peripheral drivers using an emulation driver connected via a native_sim I2C controller/emulator which passes I2C traffic from the AT24 driver to the AT24 simulator. @@ -41,12 +41,12 @@ tests. These require some sort of device attached to the bus, but with this, we can validate much of the driver functionality. Putting the two together, we can test the application and peripheral code -entirely on native_posix. Since we know that the I2C driver on the real hardware +entirely on native_sim. Since we know that the I2C driver on the real hardware works, we should expect the application and peripheral drivers to work on the real hardware also. Using the above framework we can test an entire application (e.g. Embedded -Controller) on native_posix using emulators for all non-chip drivers: +Controller) on native_sim using emulators for all non-chip drivers: .. figure:: img/app.png :align: center @@ -68,7 +68,7 @@ With this approach we can: All of this can work in the emulated environment or on real hardware. * Write a complex application that ties together all of these pieces and runs on - native_posix. We can develop on a host, use source-level debugging, etc. + native_sim. We can develop on a host, use source-level debugging, etc. * Transfer the application to any board which provides the required features (e.g. I2C, enough GPIOs), by adding Kconfig and devicetree fragments. @@ -110,9 +110,9 @@ device-class. The real code is shown in green, while the emulator code is shown in yellow. -The ``bus_api`` connects the BC1.2 emulators to the ``native_posix`` I2C +The ``bus_api`` connects the BC1.2 emulators to the ``native_sim`` I2C controller. The real BC1.2 drivers are unchanged and operate exactly as if there -was a physical I2C controller present in the system. The ``native_posix`` I2C +was a physical I2C controller present in the system. The ``native_sim`` I2C controller uses the ``bus_api`` to initiate register reads and writes to the emulator. @@ -164,14 +164,14 @@ Here are some examples present in Zephyr: .. zephyr-app-commands:: :app: tests/drivers/sensor/accel/ - :board: native_posix + :board: native_sim :goals: build #. Simple test of the EEPROM emulator: .. zephyr-app-commands:: :app: tests/drivers/eeprom - :board: native_posix + :board: native_sim :goals: build #. The same test has a second EEPROM which is an Atmel AT24 EEPROM driver @@ -179,7 +179,7 @@ Here are some examples present in Zephyr: .. zephyr-app-commands:: :app: tests/drivers/eeprom - :board: native_posix + :board: native_sim :goals: build API Reference diff --git a/doc/hardware/peripherals/rtc.rst b/doc/hardware/peripherals/rtc.rst index c279c7c79131335..d2552d078ee7851 100644 --- a/doc/hardware/peripherals/rtc.rst +++ b/doc/hardware/peripherals/rtc.rst @@ -84,9 +84,9 @@ and clock calibration, these must be enabled by selecting :kconfig:option:`CONFIG_RTC_ALARM`, :kconfig:option:`CONFIG_RTC_UPDATE` and :kconfig:option:`CONFIG_RTC_CALIBRATION`. -The following examples build the test suite for the ``native_posix`` +The following examples build the test suite for the ``native_sim`` board. To build the test suite for a different board, replace the -``native_posix`` board with your board. +``native_sim`` board with your board. To build the test application with the default configuration, testing only the mandatory features, the following command can be used for @@ -95,7 +95,7 @@ reference: .. zephyr-app-commands:: :tool: west :host-os: unix - :board: native_posix + :board: native_sim :zephyr-app: tests/drivers/rtc/rtc_api :goals: build @@ -106,7 +106,7 @@ following command can be used for reference: .. zephyr-app-commands:: :tool: west :host-os: unix - :board: native_posix + :board: native_sim :zephyr-app: tests/drivers/rtc/rtc_api :goals: menuconfig @@ -115,7 +115,7 @@ Then build the test application using the following command: .. zephyr-app-commands:: :tool: west :host-os: unix - :board: native_posix + :board: native_sim :zephyr-app: tests/drivers/rtc/rtc_api :maybe-skip-config: :goals: build From 8d4d5184c6ca3fec7fbf3cf89ef168443d93e8b9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 15:24:54 +0100 Subject: [PATCH 0363/1049] tests/drivers/accel: Switch from native_posix to native_sim Switch the overlays and default test platform to native_sim from native_posix. Signed-off-by: Alberto Escolar Piedras --- .../sensor/accel/boards/{native_posix.conf => native_sim.conf} | 0 .../accel/boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/sensor/accel/testcase.yaml | 3 ++- 3 files changed, 2 insertions(+), 1 deletion(-) rename tests/drivers/sensor/accel/boards/{native_posix.conf => native_sim.conf} (100%) rename tests/drivers/sensor/accel/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/sensor/accel/boards/native_posix.conf b/tests/drivers/sensor/accel/boards/native_sim.conf similarity index 100% rename from tests/drivers/sensor/accel/boards/native_posix.conf rename to tests/drivers/sensor/accel/boards/native_sim.conf diff --git a/tests/drivers/sensor/accel/boards/native_posix.overlay b/tests/drivers/sensor/accel/boards/native_sim.overlay similarity index 100% rename from tests/drivers/sensor/accel/boards/native_posix.overlay rename to tests/drivers/sensor/accel/boards/native_sim.overlay diff --git a/tests/drivers/sensor/accel/testcase.yaml b/tests/drivers/sensor/accel/testcase.yaml index becbd1a03f4539d..fd18df000da588c 100644 --- a/tests/drivers/sensor/accel/testcase.yaml +++ b/tests/drivers/sensor/accel/testcase.yaml @@ -4,4 +4,5 @@ tests: - drivers - sensor - subsys - platform_allow: native_posix + platform_allow: + - native_sim From 74d22a4b35cc9528deb7f8d9aa17b94fe3787014 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 16:50:20 +0100 Subject: [PATCH 0364/1049] tests/drivers/eeprom: Several fixes and improvements * Fix app path in documentation * Move the at24 emulator overlays to be general instead of native_posix specific * Switch default test platform from native_posix to native_sim * From build only test, exclude platforms which are used in the build and run test. Signed-off-by: Alberto Escolar Piedras --- doc/hardware/emulator/index.rst | 7 +++--- .../native_posix.conf => at2x_emul.conf} | 0 ...native_posix.overlay => at2x_emul.overlay} | 0 tests/drivers/eeprom/api/testcase.yaml | 22 +++++++++++++++++++ tests/drivers/eeprom/shell/testcase.yaml | 4 ++-- 5 files changed, 28 insertions(+), 5 deletions(-) rename tests/drivers/eeprom/api/{boards/native_posix.conf => at2x_emul.conf} (100%) rename tests/drivers/eeprom/api/{boards/native_posix.overlay => at2x_emul.overlay} (100%) diff --git a/doc/hardware/emulator/index.rst b/doc/hardware/emulator/index.rst index 686f2b603424b6a..4373480a3e01531 100644 --- a/doc/hardware/emulator/index.rst +++ b/doc/hardware/emulator/index.rst @@ -170,17 +170,18 @@ Here are some examples present in Zephyr: #. Simple test of the EEPROM emulator: .. zephyr-app-commands:: - :app: tests/drivers/eeprom + :app: tests/drivers/eeprom/api :board: native_sim :goals: build -#. The same test has a second EEPROM which is an Atmel AT24 EEPROM driver +#. The same test can be built with a second EEPROM which is an Atmel AT24 EEPROM driver connected via I2C an emulator: .. zephyr-app-commands:: - :app: tests/drivers/eeprom + :app: tests/drivers/eeprom/api :board: native_sim :goals: build + :gen-args: -DDTC_OVERLAY_FILE=at2x_emul.overlay -DOVERLAY_CONFIG=at2x_emul.conf API Reference ************* diff --git a/tests/drivers/eeprom/api/boards/native_posix.conf b/tests/drivers/eeprom/api/at2x_emul.conf similarity index 100% rename from tests/drivers/eeprom/api/boards/native_posix.conf rename to tests/drivers/eeprom/api/at2x_emul.conf diff --git a/tests/drivers/eeprom/api/boards/native_posix.overlay b/tests/drivers/eeprom/api/at2x_emul.overlay similarity index 100% rename from tests/drivers/eeprom/api/boards/native_posix.overlay rename to tests/drivers/eeprom/api/at2x_emul.overlay diff --git a/tests/drivers/eeprom/api/testcase.yaml b/tests/drivers/eeprom/api/testcase.yaml index 5735d63da65253c..8bc76b3e9e66d8e 100644 --- a/tests/drivers/eeprom/api/testcase.yaml +++ b/tests/drivers/eeprom/api/testcase.yaml @@ -9,9 +9,31 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - nucleo_l152re - nucleo_l073rz + integration_platforms: + - qemu_x86 + drivers.eeprom.api.w_at2x_emul: + # Tests overwrite EEPROM content, only run on select boards + extra_args: + - DTC_OVERLAY_FILE=at2x_emul.overlay + - OVERLAY_CONFIG=at2x_emul.conf + platform_allow: + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - native_sim drivers.eeprom.api.build: # Build-only test for boards with EEPROMs build_only: true + platform_exclude: + - native_sim + - native_sim_64 + - qemu_x86 + - nucleo_l152re + - nucleo_l073rz diff --git a/tests/drivers/eeprom/shell/testcase.yaml b/tests/drivers/eeprom/shell/testcase.yaml index e9bdafceda562f3..fd78ec2c70fd906 100644 --- a/tests/drivers/eeprom/shell/testcase.yaml +++ b/tests/drivers/eeprom/shell/testcase.yaml @@ -1,8 +1,8 @@ tests: drivers.eeprom.shell: integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: - drivers - eeprom From 15cbe0f890a26b9c4d98a528293f9cf32588c2b9 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 14 Nov 2023 10:37:15 +0100 Subject: [PATCH 0365/1049] tests: Remove use of CONFIG_ZTEST_NEW_API The test was enabling CONFIG_ZTEST_NEW_API which was recently removed. Signed-off-by: Emil Gydesen --- tests/drivers/uart/uart_async_rx/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/drivers/uart/uart_async_rx/prj.conf b/tests/drivers/uart/uart_async_rx/prj.conf index e10bf49c4d1ccdf..eb88c509ea7e9f4 100644 --- a/tests/drivers/uart/uart_async_rx/prj.conf +++ b/tests/drivers/uart/uart_async_rx/prj.conf @@ -1,4 +1,3 @@ CONFIG_ZTEST=y -CONFIG_ZTEST_NEW_API=y CONFIG_ZTRESS=y CONFIG_UART_ASYNC_RX_HELPER=y From 21505c2c283f4c8e1ceaec90ecdd0b37968cf08d Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Mon, 21 Aug 2023 16:06:09 +0100 Subject: [PATCH 0366/1049] winc1500: WIFI_DISCONNECT request doesn't raise DISCONNECT_RESULT event Internal flag (w1500_data.connecting) was not being set to false after connection. Interface raises NET_EVENT_WIFI_CONNECT_RESULT event with error status instead of NET_EVENT_WIFI_DISCONNECT_RESULT when disconnection is manually requested (NET_REQUEST_WIFI_DISCONNECT). Signed-off-by: Diogo Correia --- drivers/wifi/winc1500/wifi_winc1500.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/wifi/winc1500/wifi_winc1500.c b/drivers/wifi/winc1500/wifi_winc1500.c index 0a93ef0fa27ad60..95d97fcfeaaba3d 100644 --- a/drivers/wifi/winc1500/wifi_winc1500.c +++ b/drivers/wifi/winc1500/wifi_winc1500.c @@ -639,6 +639,7 @@ static void handle_wifi_con_state_changed(void *pvMsg) LOG_DBG("Connected (%u)", pstrWifiState->u8ErrCode); w1500_data.connected = true; + w1500_data.connecting = false; wifi_mgmt_raise_connect_result_event(w1500_data.iface, 0); break; From 16bd8a82a688bbc5c77ef84e8f17e0c7ef1f9149 Mon Sep 17 00:00:00 2001 From: Georges Oates_Larsen Date: Tue, 26 Sep 2023 16:31:18 -0700 Subject: [PATCH 0367/1049] net: tls_credentials: credential_digest Adds an internal credential_digest for generating a string digest of credentials. Such digests would allow users of a prospective TLS credentials shell to verify the contents of a given credential without directly accessing those contents. Offloading the digest process to the underlying backend allows backends for which private portions are not directly accessible to be eventually supported. Signed-off-by: Georges Oates_Larsen --- subsys/net/lib/tls_credentials/CMakeLists.txt | 3 + .../net/lib/tls_credentials/tls_credentials.c | 6 ++ .../tls_credentials_digest_raw.c | 92 +++++++++++++++++++ .../tls_credentials_digest_raw.h | 20 ++++ .../tls_credentials/tls_credentials_trusted.c | 6 ++ subsys/net/lib/tls_credentials/tls_internal.h | 15 ++- 6 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 subsys/net/lib/tls_credentials/tls_credentials_digest_raw.c create mode 100644 subsys/net/lib/tls_credentials/tls_credentials_digest_raw.h diff --git a/subsys/net/lib/tls_credentials/CMakeLists.txt b/subsys/net/lib/tls_credentials/CMakeLists.txt index 8df3593b994de8d..dc08debc5faddb8 100644 --- a/subsys/net/lib/tls_credentials/CMakeLists.txt +++ b/subsys/net/lib/tls_credentials/CMakeLists.txt @@ -1,9 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(.) + zephyr_sources_ifdef(CONFIG_TLS_CREDENTIALS_BACKEND_VOLATILE tls_credentials.c + tls_credentials_digest_raw.c ) zephyr_sources_ifdef(CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE tls_credentials_trusted.c + tls_credentials_digest_raw.c ) diff --git a/subsys/net/lib/tls_credentials/tls_credentials.c b/subsys/net/lib/tls_credentials/tls_credentials.c index 133d29671604922..b15397ed697db28 100644 --- a/subsys/net/lib/tls_credentials/tls_credentials.c +++ b/subsys/net/lib/tls_credentials/tls_credentials.c @@ -9,6 +9,7 @@ #include #include "tls_internal.h" +#include "tls_credentials_digest_raw.h" /* Global pool of credentials shared among TLS contexts. */ static struct tls_credential credentials[CONFIG_TLS_MAX_CREDENTIALS_NUMBER]; @@ -74,6 +75,11 @@ struct tls_credential *credential_next_get(sec_tag_t tag, return NULL; } +int credential_digest(struct tls_credential *credential, void *dest, size_t *len) +{ + return credential_digest_raw(credential, dest, len); +} + void credentials_lock(void) { k_mutex_lock(&credential_lock, K_FOREVER); diff --git a/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.c b/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.c new file mode 100644 index 000000000000000..2013c5d52fb7878 --- /dev/null +++ b/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +/* This file provides an (internal-use-only) credential digest function that backends storing + * raw credentials can use. + */ + +#include + +#include +#include +#include "tls_internal.h" +#include "tls_credentials_digest_raw.h" + +/* Grab mbedTLS headers if they are available so that we can check whether SHA256 is supported */ + +#if defined(CONFIG_MBEDTLS) +#if !defined(CONFIG_MBEDTLS_CFG_FILE) +#include "mbedtls/config.h" +#else +#include CONFIG_MBEDTLS_CFG_FILE +#endif /* CONFIG_MBEDTLS_CFG_FILE */ +#endif /* CONFIG_MBEDTLS */ + +#if defined(CONFIG_TINYCRYPT_SHA256) && defined(CONFIG_BASE64) + +#include +#include + +int credential_digest_raw(struct tls_credential *credential, void *dest, size_t *len) +{ + int err = 0; + size_t written = 0; + struct tc_sha256_state_struct sha_state; + uint8_t digest_buf[TC_SHA256_DIGEST_SIZE]; + + /* Compute digest. */ + (void)tc_sha256_init(&sha_state); + (void)tc_sha256_update(&sha_state, credential->buf, credential->len); + (void)tc_sha256_final(digest_buf, &sha_state); + + /* Attempt to encode digest to destination. + * Will return -ENOMEM if there is not enough space in the destination buffer. + */ + err = base64_encode(dest, *len, &written, digest_buf, sizeof(digest_buf)); + *len = err ? 0 : written; + + /* Clean up. */ + memset(&sha_state, 0, sizeof(sha_state)); + memset(digest_buf, 0, sizeof(digest_buf)); + return err; +} + +#elif defined(MBEDTLS_SHA256_C) && defined(CONFIG_BASE64) + +#include +#include + +int credential_digest_raw(struct tls_credential *credential, void *dest, size_t *len) +{ + int err = 0; + size_t written = 0; + uint8_t digest_buf[32]; + + /* Compute digest. The '0' indicates to mbedtls to use SHA256 instead of 224. */ + mbedtls_sha256(credential->buf, credential->len, digest_buf, 0); + + /* Attempt to encode digest to destination. + * Will return -ENOMEM if there is not enough space in the destination buffer. + */ + err = base64_encode(dest, *len, &written, digest_buf, sizeof(digest_buf)); + *len = err ? 0 : written; + + /* Clean up. */ + memset(digest_buf, 0, sizeof(digest_buf)); + + return err; +} + +#else + +int credential_digest_raw(struct tls_credential *credential, void *dest, size_t *len) +{ + *len = 0; + return -ENOTSUP; +} + +#endif diff --git a/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.h b/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.h new file mode 100644 index 000000000000000..8b39a9cba985966 --- /dev/null +++ b/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Internal helper function for generating digests for raw credentials. + */ + +#ifndef __TLS_DIGEST_RAW_H +#define __TLS_DIGEST_RAW_H + +#include +#include "tls_internal.h" + +/* Common version of credential_digest that raw credentials backends can use. */ +int credential_digest_raw(struct tls_credential *credential, void *dest, size_t *len); + +#endif /* __TLS_DIGEST_RAW_H */ diff --git a/subsys/net/lib/tls_credentials/tls_credentials_trusted.c b/subsys/net/lib/tls_credentials/tls_credentials_trusted.c index ef105715b07cd97..99f53ebddb4b42a 100644 --- a/subsys/net/lib/tls_credentials/tls_credentials_trusted.c +++ b/subsys/net/lib/tls_credentials/tls_credentials_trusted.c @@ -12,6 +12,7 @@ #include #include "tls_internal.h" +#include "tls_credentials_digest_raw.h" LOG_MODULE_REGISTER(tls_credentials_trusted, CONFIG_TLS_CREDENTIALS_LOG_LEVEL); @@ -262,6 +263,11 @@ struct tls_credential *credential_next_get(sec_tag_t tag, return NULL; } +int credential_digest(struct tls_credential *credential, void *dest, size_t *len) +{ + return credential_digest_raw(credential, dest, len); +} + void credentials_lock(void) { k_mutex_lock(&credential_lock, K_FOREVER); diff --git a/subsys/net/lib/tls_credentials/tls_internal.h b/subsys/net/lib/tls_credentials/tls_internal.h index b825b6890d8466c..e92584d0c858119 100644 --- a/subsys/net/lib/tls_credentials/tls_internal.h +++ b/subsys/net/lib/tls_credentials/tls_internal.h @@ -42,7 +42,6 @@ void credentials_unlock(void); struct tls_credential *credential_get(sec_tag_t tag, enum tls_credential_type type); - /* Function for iterating over credentials by tag. * * Note, that to assure thread safety, credential access should be locked with @@ -51,4 +50,18 @@ struct tls_credential *credential_get(sec_tag_t tag, struct tls_credential *credential_next_get(sec_tag_t tag, struct tls_credential *iter); +/* Writes a (NULL-terminated, printable) string digest of the contents of the provided credential + * to the provided destination buffer. + * + * Digest format/type is up to the tls_credentials backend in use. + * + * len pointer should be set to the amount of space available in the destination buffer prior to + * calling, and will be set to the amount written to the destination buffer after calling + * (excluding the NULL terminator). + * + * Note, that to assure thread safety, credential access should be locked with + * credentials_lock before calling this function. + */ +int credential_digest(struct tls_credential *credential, void *dest, size_t *len); + #endif /* __TLS_INTERNAL_H */ From f5d12102a04a17ea4726f40c3018a631e4315148 Mon Sep 17 00:00:00 2001 From: Georges Oates_Larsen Date: Tue, 26 Sep 2023 17:18:49 -0700 Subject: [PATCH 0368/1049] net: tls_credentials: sectag iterators Add (internal) support for sectag iterating. Also officially marks negative sectag values as reserved for internal use. This will allow a prospective TLS credentials shell to iterate over all available credentials. Signed-off-by: Georges Oates_Larsen --- include/zephyr/net/tls_credentials.h | 2 ++ .../net/lib/tls_credentials/tls_credentials.c | 26 ++++++++++++++ .../tls_credentials/tls_credentials_trusted.c | 35 +++++++++++++++++++ subsys/net/lib/tls_credentials/tls_internal.h | 14 ++++++++ 4 files changed, 77 insertions(+) diff --git a/include/zephyr/net/tls_credentials.h b/include/zephyr/net/tls_credentials.h index 8436774ec65e6a0..77e2a2308527a1c 100644 --- a/include/zephyr/net/tls_credentials.h +++ b/include/zephyr/net/tls_credentials.h @@ -66,6 +66,8 @@ enum tls_credential_type { * - TLS_CREDENTIAL_PSK with TLS_CREDENTIAL_PSK_ID. * Such pairs of credentials must be assigned the same secure tag to be * correctly handled in the system. + * + * @note Negative values are reserved for internal use. */ typedef int sec_tag_t; diff --git a/subsys/net/lib/tls_credentials/tls_credentials.c b/subsys/net/lib/tls_credentials/tls_credentials.c index b15397ed697db28..94f4d9c5cd5a90a 100644 --- a/subsys/net/lib/tls_credentials/tls_credentials.c +++ b/subsys/net/lib/tls_credentials/tls_credentials.c @@ -75,6 +75,32 @@ struct tls_credential *credential_next_get(sec_tag_t tag, return NULL; } +sec_tag_t credential_next_tag_get(sec_tag_t iter) +{ + int i; + sec_tag_t lowest = TLS_SEC_TAG_NONE; + + /* Scan all slots and find lowest sectag greater than iter */ + for (i = 0; i < ARRAY_SIZE(credentials); i++) { + /* Skip empty slots. */ + if (credentials[i].type == TLS_CREDENTIAL_NONE) { + continue; + } + + /* Skip any slots containing sectags not greater than iter */ + if (credentials[i].tag <= iter && iter != TLS_SEC_TAG_NONE) { + continue; + } + + /* Find the lowest of such slots */ + if (lowest == TLS_SEC_TAG_NONE || credentials[i].tag < lowest) { + lowest = credentials[i].tag; + } + } + + return lowest; +} + int credential_digest(struct tls_credential *credential, void *dest, size_t *len) { return credential_digest_raw(credential, dest, len); diff --git a/subsys/net/lib/tls_credentials/tls_credentials_trusted.c b/subsys/net/lib/tls_credentials/tls_credentials_trusted.c index 99f53ebddb4b42a..0b77e52f558817c 100644 --- a/subsys/net/lib/tls_credentials/tls_credentials_trusted.c +++ b/subsys/net/lib/tls_credentials/tls_credentials_trusted.c @@ -263,6 +263,41 @@ struct tls_credential *credential_next_get(sec_tag_t tag, return NULL; } +sec_tag_t credential_next_tag_get(sec_tag_t iter) +{ + unsigned int slot; + psa_storage_uid_t uid; + sec_tag_t lowest_candidate = TLS_SEC_TAG_NONE; + sec_tag_t candidate; + + /* Scan all slots and find lowest sectag greater than iter */ + for (slot = 0; slot < CRED_MAX_SLOTS; slot++) { + uid = credentials_toc[slot]; + + /* Skip empty slots. */ + if (uid == 0) { + continue; + } + if (tls_credential_uid_to_type(uid) == TLS_CREDENTIAL_NONE) { + continue; + } + + candidate = tls_credential_uid_to_tag(uid); + + /* Skip any slots containing sectags not greater than iter */ + if (candidate <= iter && iter != TLS_SEC_TAG_NONE) { + continue; + } + + /* Find the lowest of such slots */ + if (lowest_candidate == TLS_SEC_TAG_NONE || candidate < lowest_candidate) { + lowest_candidate = candidate; + } + } + + return lowest_candidate; +} + int credential_digest(struct tls_credential *credential, void *dest, size_t *len) { return credential_digest_raw(credential, dest, len); diff --git a/subsys/net/lib/tls_credentials/tls_internal.h b/subsys/net/lib/tls_credentials/tls_internal.h index e92584d0c858119..e7cfc0a1c0b8f2a 100644 --- a/subsys/net/lib/tls_credentials/tls_internal.h +++ b/subsys/net/lib/tls_credentials/tls_internal.h @@ -28,6 +28,11 @@ struct tls_credential { size_t len; }; +/* + * Special sec_tag value indicating none or invalid sec_tag. For internal use only for now. + */ +#define TLS_SEC_TAG_NONE -1 + /* Lock TLS credential access. */ void credentials_lock(void); @@ -50,6 +55,15 @@ struct tls_credential *credential_get(sec_tag_t tag, struct tls_credential *credential_next_get(sec_tag_t tag, struct tls_credential *iter); +/* Function for iterating over occupied sec tags. + * + * Returns the next occupied sec tag after the one provided, or TLS_SEC_TAG_NONE if there are no + * more. + * + * Provide TLS_SEC_TAG_NONE to start from the first available sec tag. + */ +sec_tag_t credential_next_tag_get(sec_tag_t iter); + /* Writes a (NULL-terminated, printable) string digest of the contents of the provided credential * to the provided destination buffer. * From 9f093ab7317a3290e4c6dce56f47845112a2620b Mon Sep 17 00:00:00 2001 From: Georges Oates_Larsen Date: Tue, 26 Sep 2023 16:09:30 -0700 Subject: [PATCH 0369/1049] net: tls_credetials: Add TLS Credentials shell Adds a shell interface for TLS Credentials, allowing management of credentials via the Zephyr shell Signed-off-by: Georges Oates_Larsen --- doc/connectivity/networking/api/sockets.rst | 2 + .../networking/api/system_mgmt.rst | 1 + .../networking/api/tls_credentials_shell.rst | 259 ++++++ subsys/net/lib/tls_credentials/CMakeLists.txt | 3 + subsys/net/lib/tls_credentials/Kconfig | 2 + subsys/net/lib/tls_credentials/Kconfig.shell | 35 + .../tls_credentials/tls_credentials_shell.c | 811 ++++++++++++++++++ 7 files changed, 1113 insertions(+) create mode 100644 doc/connectivity/networking/api/tls_credentials_shell.rst create mode 100644 subsys/net/lib/tls_credentials/Kconfig.shell create mode 100644 subsys/net/lib/tls_credentials/tls_credentials_shell.c diff --git a/doc/connectivity/networking/api/sockets.rst b/doc/connectivity/networking/api/sockets.rst index 3f632e3bea93e3a..720bebeb820061e 100644 --- a/doc/connectivity/networking/api/sockets.rst +++ b/doc/connectivity/networking/api/sockets.rst @@ -73,6 +73,8 @@ To enable secure sockets, set the :kconfig:option:`CONFIG_NET_SOCKETS_SOCKOPT_TL option. To enable DTLS support, use :kconfig:option:`CONFIG_NET_SOCKETS_ENABLE_DTLS` option. +.. _sockets_tls_credentials_subsys: + TLS credentials subsystem ========================= diff --git a/doc/connectivity/networking/api/system_mgmt.rst b/doc/connectivity/networking/api/system_mgmt.rst index 59aab16d3b72dfc..a09ed2b2787f279 100644 --- a/doc/connectivity/networking/api/system_mgmt.rst +++ b/doc/connectivity/networking/api/system_mgmt.rst @@ -18,3 +18,4 @@ Network System Management traffic-class.rst net_pkt_filter.rst net_shell.rst + tls_credentials_shell.rst diff --git a/doc/connectivity/networking/api/tls_credentials_shell.rst b/doc/connectivity/networking/api/tls_credentials_shell.rst new file mode 100644 index 000000000000000..69749a8f972b1f5 --- /dev/null +++ b/doc/connectivity/networking/api/tls_credentials_shell.rst @@ -0,0 +1,259 @@ +.. _tls_credentials_shell: + +TLS Credentials Shell +##################### + +The TLS Credentials shell provides a command-line interface for managing installed TLS credentials. + +Commands +******** + +.. _tls_credentials_shell_buf_cred: + +Buffer Credential (``buf``) +=========================== + +Buffer data incrementaly into the credential buffer so that it can be added using the :ref:`tls_credentials_shell_add_cred` command. + +Alternatively, clear the credential buffer. + +Usage +----- + +To append ```` to the credential buffer, use: + +.. code-block:: shell + + cred buf + +Use this as many times as needed to load the full credential into the credential buffer, then use the :ref:`tls_credentials_shell_add_cred` command to store it. + +To clear the credential buffer, use: + +.. code-block:: shell + + cred buf clear + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "Text data to be appended to credential buffer. It can be either text, or base64-encoded binary. See :ref:`tls_credentials_shell_add_cred` and :ref:`tls_credentials_shell_data_formats` for details." + +.. _tls_credentials_shell_add_cred: + +Add Credential (``add``) +========================= + +Add a TLS credential to the TLS Credential store. + +Credential contents can be provided in-line with the call to ``cred add``, or will otherwise be sourced from the credential buffer. + +Usage +----- + +To add a TLS credential using the data from the credential buffer, use: + +.. code-block:: shell + + cred add + +To add a TLS credential using data provided with the same command, use: + +.. code-block:: shell + + cred add + + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "The sectag to use for the new credential. Can be any non-negative integer." + "````", "The type of credential to add. See :ref:`tls_credentials_shell_cred_types` for valid values." + "````", "Reserved. Must always be ``DEFAULT`` (case-insensitive)." + "````", "Specifies the storage format of the provided credential. See :ref:`tls_credentials_shell_data_formats` for valid values." + "````", "If provided, this argument will be used as the credential data, instead of any data in the credential buffer. Can be either text, or base64-encoded binary." + +.. _tls_credentials_shell_del_cred: + +Delete Credential (``del``) +=========================== + +Delete a specified credential from the credential store. + +Usage +----- + +To delete a credential matching a specified sectag and credential type (if it exists), use: + +.. code-block:: shell + + cred del + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "The sectag of the credential to delete. Can be any non-negative integer." + "````", "The type of credential to delete. See :ref:`tls_credentials_shell_cred_types` for valid values." + +.. _tls_credentials_shell_get_cred: + +Get Credential Contents (``get``) +================================= + +Retrieve and print the contents of a specified credential. + +Usage +----- + +To retrieve and print a credential matching a specified sectag and credential type (if it exists), use: + +.. code-block:: shell + + cred get + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "The sectag of the credential to get. Can be any non-negative integer." + "````", "The type of credential to get. See :ref:`tls_credentials_shell_cred_types` for valid values." + "````", "Specifies the retrieval format for the provided credential. See :ref:`tls_credentials_shell_data_formats` for valid values." + +.. _tls_credentials_shell_list_cred: + +List Credentials (``list``) +=========================== + +List TLS credentials in the credential store. + +Usage +----- + +To list all available credentials, use: + +.. code-block:: shell + + cred list + +To list all credentials with a specified sectag, use: + +.. code-block:: shell + + cred list + +To list all credentials with a specified credential type, use: + +.. code-block:: shell + + cred list any + +To list all credentials with a specified credential type and sectag, use: + +.. code-block:: shell + + cred list + + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "Optional. If provided, only list credentials with this sectag. Pass ``any`` or omit to allow any sectag. Otherwise, can be any non-negative integer." + "````", "Optional. If provided, only list credentials with this credential type. Pass ``any`` or omit to allow any credential type. Otherwise, see :ref:`tls_credentials_shell_cred_types` for valid values." + + +Output +------ + +The command outputs all matching credentials in the following (CSV-compliant) format: + +.. code-block:: shell + + ,,, + +Where: + +.. csv-table:: + :header: "Symbol", "Value" + :widths: 15 85 + + "````", "The sectag of the listed credential. A non-negative integer." + "````", "Credential type short-code (see :ref:`tls_credentials_shell_cred_types` for details) of the listed credential." + "````", "A string digest representing the credential contents. The exact nature of this digest may vary depending on credentials storage backend, but currently for all backends this is a base64 encoded SHA256 hash of the raw credential contents (so different storage formats for essentially identical credentials will have different digests)." + "````", "Status code indicating success or failure with generating a digest of the listed credential. 0 if successful, negative error code specific to the storage backend otherwise. Lines for which status is not zero will be printed with error formatting." + +After the list is printed, a final summary of the found credentials will be printed in the form: + +.. code-block:: shell + + credentials found. + +Where `` is the number of credentials found, and is zero if none are found. + +.. _tls_credentials_shell_cred_types: + +Credential Types +**************** + +The following keywords (case-insensitive) may be used to specify a credential type: + +.. csv-table:: + :header: "Keyword(s)", "Meaning" + :widths: 15 85 + + "``CA_CERT``, ``CA``", "A trusted CA certificate." + "``SERVER_CERT``, ``SELF_CERT``, ``CLIENT_CERT``, ``CLIENT``, ``SELF``, ``SERV``", "Self or server certificate." + "``PRIVATE_KEY``, ``PK``", "A private key." + "``PRE_SHARED_KEY``, ``PSK``", "A pre-shared key." + "``PRE_SHARED_KEY_ID``, ``PSK_ID``", "ID for pre-shared key." + +.. _tls_credentials_shell_data_formats: + +Storage/Retrieval Formats +************************* + +The :ref:`tls_credentials ` module treats stored credentials as arbitrary binary buffers. + +For convenience, the TLS credentials shell offers four formats for providing and later retrieving these buffers using the shell. + +These formats and their (case-insensitive) keywords are as follows: + +.. csv-table:: + :header: "Keyword", "Meaning", "Behavior during storage (``cred add``)", "Behavior during retrieval (``cred get``)" + :widths: 3, 32, 34, 34 + + "``BIN``", "Credential is handled by shell as base64 and stored without NULL termination.", "Data entered into shell will be decoded from base64 into raw binary before storage. No terminator will be appended.", "Stored data will be encoded into base64 before being printed." + "``BINT``", "Credential is handled by shell as base64 and stored with NULL termination.", "Data entered into shell will be decoded from base64 into raw binary and a NULL terminator will be appended before storage.", "NULL terminator will be truncated from stored data before said data is encoded into base64 and then printed." + "``STR``", "Credential is handled by shell as literal string and stored without NULL termination.", "Text data entered into shell will be passed into storage as-written, without a NULL terminator.", "Stored data will be printed as text. Non-printable characters will be printed as ``?``" + "``STRT``", "Credential is handled by shell as literal string and stored with NULL-termination.", "Text data entered into shell will be passed into storage as-written, with a NULL terminator.", "NULL terminator will be truncated from stored data before said data is printed as text. Non-printable characters will be printed as ``?``" + +The ``BIN`` format can be used to install credentials of any type, since base64 can be used to encode any concievable binary buffer. +The remaining three formats are provided for convenience in special use-cases. + +For example: + +- To install printable pre-shared-keys, use ``STR`` to enter the PSK without first encoding it. + This ensures it is stored without a NULL terminator. +- To install DER-formatted X.509 certificates (or other raw-binary credentials, such as non-printable PSKs) base64-encode the binary and use the ``BIN`` format. +- To install PEM-formatted X.509 certificates or certificate chains, base64 encode the full PEM string (including new-lines and ``----BEGIN X ----`` / ``----END X----`` markers), and then use the ``BINT`` format to make sure the stored string is NULL-terminated. + This is required because Zephyr does not support multi-line strings in the shell. + Otherwise, the ``STRT`` format could be used for this purpose without base64 encoding. + It is possible to use ``BIN`` instead if you manually encode a NULL terminator into the base64. diff --git a/subsys/net/lib/tls_credentials/CMakeLists.txt b/subsys/net/lib/tls_credentials/CMakeLists.txt index dc08debc5faddb8..8acb4a5f4f104b3 100644 --- a/subsys/net/lib/tls_credentials/CMakeLists.txt +++ b/subsys/net/lib/tls_credentials/CMakeLists.txt @@ -10,3 +10,6 @@ zephyr_sources_ifdef(CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE tls_credentials_trusted.c tls_credentials_digest_raw.c ) +zephyr_sources_ifdef(CONFIG_TLS_CREDENTIALS_SHELL + tls_credentials_shell.c +) diff --git a/subsys/net/lib/tls_credentials/Kconfig b/subsys/net/lib/tls_credentials/Kconfig index 94ecc8287c6a62e..58ec0949d474f8c 100644 --- a/subsys/net/lib/tls_credentials/Kconfig +++ b/subsys/net/lib/tls_credentials/Kconfig @@ -54,4 +54,6 @@ config TLS_CREDENTIAL_FILENAMES This option is currently only available for secure socket offload devices. +source "subsys/net/lib/tls_credentials/Kconfig.shell" + endif # TLS_CREDENTIALS diff --git a/subsys/net/lib/tls_credentials/Kconfig.shell b/subsys/net/lib/tls_credentials/Kconfig.shell new file mode 100644 index 000000000000000..3e20f6e77174040 --- /dev/null +++ b/subsys/net/lib/tls_credentials/Kconfig.shell @@ -0,0 +1,35 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menuconfig TLS_CREDENTIALS_SHELL + bool "TLS credentials management shell" + depends on TLS_CREDENTIALS + depends on SHELL + depends on BASE64 + help + Enable shell commands to manage TLS credentials. + +if TLS_CREDENTIALS_SHELL + +config TLS_CREDENTIALS_SHELL_CRED_BUF_SIZE + int "Size of buffer used for storing and retrieving credentials, measured in bytes." + default 1024 + help + The amount of preallocated buffer (in bytes) used for storing and retrieving credentials. + +config TLS_CREDENTIALS_SHELL_CRED_OUTPUT_WIDTH + int "Credential output line width (characters)" + default 32 + help + This setting specifies how long (in characters) contiguous lines of base64 credential + output should be. Must be a multiple of 4. Applies only to ??? mode. + +config TLS_CREDENTIALS_SHELL_DIGEST_BUF_SIZE + int "Buffer for generating credentials digests" + default 48 + help + The amount of preallocated buffer (in bytes) for temporarily storing credential digests. + + Also used to print error messages if digest generation fails. + +endif # TLS_CREDENTIALS_SHELL diff --git a/subsys/net/lib/tls_credentials/tls_credentials_shell.c b/subsys/net/lib/tls_credentials/tls_credentials_shell.c new file mode 100644 index 000000000000000..1b06520466bda2f --- /dev/null +++ b/subsys/net/lib/tls_credentials/tls_credentials_shell.c @@ -0,0 +1,811 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(tls_credentials_shell, CONFIG_TLS_CREDENTIALS_LOG_LEVEL); + +#include +#include +#include +#include +#include "tls_internal.h" +#include +#include +#include + +enum cred_storage_fmt { + /* Credential is stored as a string and will be passed between the shell and storage + * unmodified. + */ + CRED_STORAGE_FMT_STRING, + + /* Credential is stored as raw binary, and is parsed from base64 before storage and encoded + * back into base64 when retrieved via the shell. + */ + CRED_STORAGE_FMT_BINARY, +}; + +struct cred_type_string { + char *name; + enum tls_credential_type type; +}; + +/* The first entry in each credential type group will be used for human-readable shell + * output. The last will be used for compact shell output. The rest are accepted synonyms. + */ +static const struct cred_type_string type_strings[] = { + {"CA_CERT", TLS_CREDENTIAL_CA_CERTIFICATE}, + {"CA", TLS_CREDENTIAL_CA_CERTIFICATE}, + + {"SERVER_CERT", TLS_CREDENTIAL_SERVER_CERTIFICATE}, + {"CLIENT_CERT", TLS_CREDENTIAL_SERVER_CERTIFICATE}, + {"SELF_CERT", TLS_CREDENTIAL_SERVER_CERTIFICATE}, + {"SELF", TLS_CREDENTIAL_SERVER_CERTIFICATE}, + {"CLIENT", TLS_CREDENTIAL_SERVER_CERTIFICATE}, + {"SERV", TLS_CREDENTIAL_SERVER_CERTIFICATE}, + + {"PRIVATE_KEY", TLS_CREDENTIAL_PRIVATE_KEY}, + {"PK", TLS_CREDENTIAL_PRIVATE_KEY}, + + {"PRE_SHARED_KEY", TLS_CREDENTIAL_PSK}, + {"PSK", TLS_CREDENTIAL_PSK}, + + {"PRE_SHARED_KEY_ID", TLS_CREDENTIAL_PSK_ID}, + {"PSK_ID", TLS_CREDENTIAL_PSK_ID} +}; + +#define ANY_KEYWORD "any" + +/* This is so that we can output base64 in chunks of this length if necessary */ +BUILD_ASSERT( + (CONFIG_TLS_CREDENTIALS_SHELL_CRED_OUTPUT_WIDTH % 4) == 0, + "CONFIG_TLS_CREDENTIALS_SHELL_CRED_OUTPUT_WIDTH must be a multiple of 4." +); + +/* Output buffers used for printing credentials and digests. + * One extra byte included for NULL termination. + */ +static char cred_out_buf[CONFIG_TLS_CREDENTIALS_SHELL_CRED_OUTPUT_WIDTH + 1]; +static char cred_digest_buf[CONFIG_TLS_CREDENTIALS_SHELL_DIGEST_BUF_SIZE + 1]; + +/* Internal buffer used for storing and retrieving credentials. + * +1 byte for potential NULL termination. + */ +static char cred_buf[CONFIG_TLS_CREDENTIALS_SHELL_CRED_BUF_SIZE + 1]; +static size_t cred_written; + +/* Some backends (namely, the volatile backend) store a reference rather than a copy of passed-in + * credentials. For these backends, we need to copy incoming credentials onto the heap before + * attempting to store them. + * + * Since the backend in use is determined at build time by KConfig, so is this behavior. + * If multi/dynamic-backend support is ever added, this will need to be updated. + */ +#define COPY_CREDENTIALS_TO_HEAP CONFIG_TLS_CREDENTIALS_BACKEND_VOLATILE + +/* Used to track credentials that have been copied permanently to the heap, in case they are + * ever deleted and need to be freed. + */ +static void *cred_refs[CONFIG_TLS_MAX_CREDENTIALS_NUMBER]; + +/* Find an empty slot in the cred_refs array, or return -1 if none exists. + * Pass NULL to find an unused slot. + */ +static int find_ref_slot(const void *const cred) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cred_refs); i++) { + if (cred_refs[i] == cred) { + return i; + } + } + + return -1; +} + +/* Helpers */ + +/* Filter out non-printable characters from a passed-in string of known length */ +static int filter_nonprint(char *buf, size_t len, char inval) +{ + int i; + int ret = 0; + + for (i = 0; i < len; i++) { + if (!isprint((int)buf[i])) { + buf[i] = inval; + ret = -EINVAL; + } + } + + return ret; +} + +/* Verify that a provided string consists only of the characters 0-9*/ +static bool check_numeric(char *str) +{ + int i; + int len = strlen(str); + + for (i = 0; i < len; i++) { + if (!isdigit((int)str[i])) { + return false; + } + } + + return true; +} + +/* Clear the credential write buffer, returns true if anything was actually cleared. */ +static bool cred_buf_clear(void) +{ + bool cleared = cred_written != 0; + + (void)memset(cred_buf, 0, sizeof(cred_buf)); + cred_written = 0; + + return cleared; +} + +/* Parse a (possibly incomplete) chunk into the credential buffer */ +static int cred_buf_write(char *chunk) +{ + char *writehead = cred_buf + cred_written; + size_t chunk_len = strlen(chunk); + + /* Verify that there is room for the incoming chunk */ + if ((writehead + chunk_len) >= (cred_buf + sizeof(cred_buf) - 1)) { + return -ENOMEM; + } + + /* Append chunk to the credential buffer. + * Deliberately do not copy NULL terminator. + */ + memcpy(writehead, chunk, chunk_len); + cred_written += chunk_len; + + return chunk_len; +} + +/* Get the human-readable name of a TLS credential type */ +static const char *cred_type_name(enum tls_credential_type type) +{ + /* Scan over predefined type strings, and return the name + * of the first one of matching type. + */ + for (int i = 0; i < ARRAY_SIZE(type_strings); i++) { + if (type_strings[i].type == type) { + return type_strings[i].name; + } + } + + /* No matches found, it's invalid. */ + return "INVALID"; +} + +/* Get the compact name of a TLS credential type*/ +static const char *cred_type_name_compact(enum tls_credential_type type) +{ + /* Scan over predefined type strings, and return the name + * of the last one of matching type. + */ + for (int i = ARRAY_SIZE(type_strings) - 1; i >= 0; i--) { + if (type_strings[i].type == type) { + return type_strings[i].name; + } + } + + /* No matches found, it's invalid. */ + return "INV"; +} + +/* Shell interface routines */ + +/* Attempt to parse a command line argument into a sectag. + * TLS_SEC_TAG_NONE is returned if ANY_KEYWORD is provided. + */ +static int shell_parse_cred_sectag(const struct shell *sh, char *arg, sec_tag_t *out, + bool allow_any) +{ + unsigned long sectag_value; + int err = 0; + + /* Check for "ANY" special keyword if desired. */ + if (allow_any && strcasecmp(arg, ANY_KEYWORD) == 0) { + *out = TLS_SEC_TAG_NONE; + return 0; + } + + /* Otherwise, verify that the sectag is purely numeric */ + if (!check_numeric(arg)) { + err = -EINVAL; + goto error; + } + + /* Use strtoul because it has nicer validation features than atoi */ + sectag_value = shell_strtoul(arg, 10, &err); + + if (!err) { + *out = (sec_tag_t)sectag_value; + return 0; + } + +error: + shell_fprintf(sh, SHELL_ERROR, "%s is not a valid sectag.\n", arg); + return err; +} + +/* Attempt to parse a command line argument into a credential type. + * TLS_CREDENTIAL_NONE is returned if ANY_KEYWORD is provided. + */ +static int shell_parse_cred_type(const struct shell *sh, char *arg, enum tls_credential_type *out, + bool allow_any) +{ + /* Check for "ANY" special keyword if desired. */ + if (allow_any && strcasecmp(arg, ANY_KEYWORD) == 0) { + *out = TLS_CREDENTIAL_NONE; + return 0; + } + + /* Otherwise, scan over predefined type strings, and return the corresponding + * credential type if one is found + */ + for (int i = 0; i < ARRAY_SIZE(type_strings); i++) { + if (strcasecmp(arg, type_strings[i].name) == 0) { + *out = type_strings[i].type; + return 0; + } + } + + /* No matches found, it's invalid. */ + shell_fprintf(sh, SHELL_ERROR, "%s is not a valid credential type.\n", arg); + + return -EINVAL; +} + +/* Parse a backend specifier argument + * Right now, only a single backend is supported, so this is serving simply as a reserved argument. + * As such, the only valid input is "default" + */ +static int shell_parse_cred_backend(const struct shell *sh, char *arg) +{ + if (strcasecmp(arg, "default") == 0) { + return 0; + } + + shell_fprintf(sh, SHELL_ERROR, "%s is not a valid backend.\n", arg); + + return -EINVAL; +} + +/* Parse an input type specifier */ +static int shell_parse_cred_storage_format(const struct shell *sh, char *arg, + enum cred_storage_fmt *out, bool *terminated) +{ + if (strcasecmp(arg, "bin") == 0) { + *out = CRED_STORAGE_FMT_BINARY; + *terminated = false; + return 0; + } + + if (strcasecmp(arg, "bint") == 0) { + *out = CRED_STORAGE_FMT_BINARY; + *terminated = true; + return 0; + } + + if (strcasecmp(arg, "str") == 0) { + *out = CRED_STORAGE_FMT_STRING; + *terminated = false; + return 0; + } + + if (strcasecmp(arg, "strt") == 0) { + *out = CRED_STORAGE_FMT_STRING; + *terminated = true; + return 0; + } + + shell_fprintf(sh, SHELL_ERROR, "%s is not a valid storage format.\n", arg); + + return -EINVAL; +} + +/* Clear credential buffer, with shell feedback */ +static void shell_clear_cred_buf(const struct shell *sh) +{ + /* We will only print a message if some data was actually wiped. */ + if (cred_buf_clear()) { + shell_fprintf(sh, SHELL_NORMAL, "Credential buffer cleared.\n"); + } +} + +/* Write data into the credential buffer, with shell feedback. */ +static int shell_write_cred_buf(const struct shell *sh, char *chunk) +{ + int res = cred_buf_write(chunk); + + /* Report results. */ + + if (res == -ENOMEM) { + shell_fprintf(sh, SHELL_ERROR, "Not enough room in credential buffer for " + "provided data. Increase " + "CONFIG_TLS_CREDENTIALS_SHELL_CRED_BUF_SIZE.\n"); + shell_clear_cred_buf(sh); + return -ENOMEM; + } + + shell_fprintf(sh, SHELL_NORMAL, "Stored %d bytes.\n", res); + + return 0; +} + +/* Adds a credential to the credential store */ +static int tls_cred_cmd_add(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + sec_tag_t sectag; + enum cred_storage_fmt format; + bool terminated; + enum tls_credential_type type; + void *cred_copy = NULL; + void *cred_chosen = NULL; + bool keep_copy = false; + int ref_slot = -1; + + /* Lock credentials so that we can interact with them directly. + * Mainly this is required by credential_get. + */ + + credentials_lock(); + + err = shell_parse_cred_sectag(sh, argv[1], §ag, false); + if (err) { + goto cleanup; + } + + err = shell_parse_cred_type(sh, argv[2], &type, false); + if (err) { + goto cleanup; + } + + err = shell_parse_cred_backend(sh, argv[3]); + if (err) { + goto cleanup; + } + + err = shell_parse_cred_storage_format(sh, argv[4], &format, &terminated); + if (err) { + goto cleanup; + } + + if (argc == 6) { + /* Credential was passed, clear credential buffer and then use the passed-in + * credential. + */ + shell_clear_cred_buf(sh); + err = shell_write_cred_buf(sh, argv[5]); + if (err) { + goto cleanup; + } + } + + /* Make sure the credential buffer isn't empty. */ + if (cred_written == 0) { + shell_fprintf(sh, SHELL_ERROR, "Please provide a credential to add.\n"); + err = -ENOENT; + goto cleanup; + } + + /* Check whether a credential of this type and sectag already exists. */ + if (credential_get(sectag, type)) { + shell_fprintf(sh, SHELL_ERROR, "TLS credential with sectag %d and type %s " + "already exists.\n", sectag, cred_type_name(type)); + err = -EEXIST; + goto cleanup; + } + + /* If binary format was specified, decode from base64. */ + if (format == CRED_STORAGE_FMT_BINARY) { + /* base64_decode can handle in-place operation. + * Pass &cred_written as olen so that it is updated to match the size of the base64 + * encoding. + * + * We use sizeof(cred_buf) - 1 since we want to keep room fors a NULL terminator. + * Though, technically, this is not actually needed since the output of + * base64_decode is always shorter than its input. + */ + err = base64_decode(cred_buf, sizeof(cred_buf) - 1, &cred_written, + cred_buf, cred_written); + if (err) { + shell_fprintf(sh, SHELL_ERROR, "Could not decode input from base64, " + "error: %d\n", err); + err = -EINVAL; + goto cleanup; + } + } + + /* If NULL termination was requested, append one. + * We are always guaranteed to have room in the buffer for this. + */ + if (terminated) { + cred_buf[cred_written] = 0; + cred_written += 1; + } + + /* Default to using cred_buf directly. */ + cred_chosen = cred_buf; + + /* If the currently active TLS Credentials backend stores credentials by reference, + * copy the incoming credentials off to the heap, and then use this copy instead. + */ + if (IS_ENABLED(COPY_CREDENTIALS_TO_HEAP)) { + /* Before copying the credential to heap, make sure we are able to store a + * reference to it so that it can be freed if the credential is ever deleted. + */ + + ref_slot = find_ref_slot(NULL); + + if (ref_slot < 0) { + shell_fprintf(sh, SHELL_ERROR, "No reference slot available, cannot copy " + "credential to heap. Credential will not be " + "stored\n"); + err = -ENOMEM; + goto cleanup; + } + + cred_copy = k_malloc(cred_written); + if (!cred_copy) { + shell_fprintf(sh, SHELL_ERROR, "Not enough heap for TLS credential of " + "size %d.\n", cred_written); + err = -ENOMEM; + goto cleanup; + } + + memset(cred_copy, 0, cred_written); + memcpy(cred_copy, cred_buf, cred_written); + + shell_fprintf(sh, SHELL_WARNING, "Credential has been copied to heap. Memory will " + "be leaked if this credential is deleted without " + "using the shell.\n"); + + cred_chosen = cred_copy; + } + + /* Finally, store the credential in whatever credentials backend is active. */ + err = tls_credential_add(sectag, type, cred_chosen, cred_written); + if (err) { + shell_fprintf(sh, SHELL_ERROR, "Failed to add TLS credential with sectag %d and " + "type %s. Error: %d\n.", sectag, + cred_type_name(type), err); + goto cleanup; + } + + /* Do not free the copied key during cleanup, since it was successfully written. */ + keep_copy = true; + + shell_fprintf(sh, SHELL_NORMAL, "Added TLS credential of type %s, sectag %d, and length %d " + "bytes.\n", cred_type_name(type), sectag, cred_written); + +cleanup: + /* Unlock credentials since we are done interacting with internal state. */ + credentials_unlock(); + + /* We are also done with the credentials buffer, so clear it for good measure. */ + shell_clear_cred_buf(sh); + + /* If we copied the credential, make sure it is eventually freed. */ + if (cred_copy) { + if (keep_copy) { + /* If the credential was successfully stored, keep a reference to it in case + * it is ever deleted and needs to be freed. + */ + cred_refs[ref_slot] = cred_copy; + } else { + /* Otherwise, clear and free it immediately */ + memset(cred_copy, 0, cred_written); + (void)k_free(cred_copy); + } + } + + return err; +} + +/* Buffers credential data into the credential buffer. */ +static int tls_cred_cmd_buf(const struct shell *sh, size_t argc, char *argv[]) +{ + /* If the "clear" keyword is provided, clear the buffer rather than write to it. */ + if (strcmp(argv[1], "clear") == 0) { + shell_clear_cred_buf(sh); + return 0; + } + + /* Otherwise, assume provided arg is base64 and attempt to write it into the credential + * buffer. + */ + return shell_write_cred_buf(sh, argv[1]); +} + +/* Deletes a credential from the credential store */ +static int tls_cred_cmd_del(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + sec_tag_t sectag; + enum tls_credential_type type; + struct tls_credential *cred = NULL; + int ref_slot = -1; + + /* Lock credentials so that we can safely use internal access functions. */ + credentials_lock(); + + err = shell_parse_cred_sectag(sh, argv[1], §ag, false); + if (err) { + goto cleanup; + } + + err = shell_parse_cred_type(sh, argv[2], &type, false); + if (err) { + goto cleanup; + } + + /* Check whether a credential of this type and sectag actually exists. */ + cred = credential_get(sectag, type); + if (!cred) { + shell_fprintf(sh, SHELL_ERROR, "There is no TLS credential with sectag %d and " + "type %s.\n", sectag, cred_type_name(type)); + err = -ENOENT; + goto cleanup; + } + + ref_slot = find_ref_slot(cred->buf); + if (ref_slot >= 0) { + /* This was a credential we copied to heap. Clear and free it. */ + memset((void *)cred_buf, 0, cred->len); + k_free((void *)cred_buf); + cred->buf = NULL; + + /* Clear the reference slot so it can be used again. */ + cred_refs[ref_slot] = NULL; + + shell_fprintf(sh, SHELL_NORMAL, "Stored credential freed.\n"); + } + + /* Attempt to delete. */ + err = tls_credential_delete(sectag, type); + if (err) { + shell_fprintf(sh, SHELL_ERROR, "Deleting TLS credential with sectag %d and " + "type %s failed with error: %d.\n", sectag, + cred_type_name(type), err); + goto cleanup; + } + + shell_fprintf(sh, SHELL_NORMAL, "Deleted TLS credential with sectag %d and type %s.\n", + sectag, cred_type_name(type)); + +cleanup: + /* Unlock credentials since we are done interacting with internal state. */ + credentials_unlock(); + + return err; +} + +/* Retrieves credential data from credential store. */ +static int tls_cred_cmd_get(const struct shell *sh, size_t argc, char *argv[]) +{ + int i; + int remaining; + int written; + int err = 0; + size_t cred_len; + sec_tag_t sectag; + enum tls_credential_type type; + enum cred_storage_fmt format; + bool terminated; + + size_t line_length; + + /* Lock credentials so that we can safely use internal access functions. */ + credentials_lock(); + + err = shell_parse_cred_sectag(sh, argv[1], §ag, false); + if (err) { + goto cleanup; + } + + err = shell_parse_cred_type(sh, argv[2], &type, false); + if (err) { + goto cleanup; + } + + err = shell_parse_cred_storage_format(sh, argv[3], &format, &terminated); + if (err) { + goto cleanup; + } + + line_length = CONFIG_TLS_CREDENTIALS_SHELL_CRED_OUTPUT_WIDTH; + + /* If the credential is stored as binary, adjust line length so that the output + * base64 has width CONFIG_TLS_CREDENTIALS_SHELL_CRED_OUTPUT_WIDTH + */ + if (format == CRED_STORAGE_FMT_BINARY) { + line_length = CONFIG_TLS_CREDENTIALS_SHELL_CRED_OUTPUT_WIDTH / 4 * 3; + } + + /* Check whether a credential of this type and sectag actually exists. */ + if (!credential_get(sectag, type)) { + shell_fprintf(sh, SHELL_ERROR, "There is no TLS credential with sectag %d and " + "type %s.\n", sectag, cred_type_name(type)); + err = -ENOENT; + goto cleanup; + } + + /* Clear the credential buffer before use. */ + shell_clear_cred_buf(sh); + + /* Load the credential into the credential buffer */ + cred_len = sizeof(cred_buf); + err = tls_credential_get(sectag, type, cred_buf, &cred_len); + if (err == -EFBIG) { + shell_fprintf(sh, SHELL_ERROR, "Not enough room in the credential buffer to " + "retrieve credential with sectag %d and type %s. " + "Increase TLS_CREDENTIALS_SHELL_MAX_CRED_LEN.\n", + sectag, cred_type_name(type)); + err = -ENOMEM; + goto cleanup; + } else if (err) { + shell_fprintf(sh, SHELL_ERROR, "Could not retrieve TLS credential with sectag %d " + "and type %s due to error: %d.\n", sectag, + cred_type_name(type), err); + goto cleanup; + } + + /* Update the credential buffer writehead. + * Keeping this accurate ensures that a "Buffer Cleared" message is eventually printed. + */ + cred_written = cred_len; + + /* If the stored credential is NULL-terminated, do not include NULL termination in output */ + if (terminated) { + if (cred_buf[cred_written - 1] != 0) { + shell_fprintf(sh, SHELL_ERROR, "The stored credential isn't " + "NULL-terminated, but a NULL-terminated " + "format was specified.\n"); + + err = -EINVAL; + goto cleanup; + } + cred_written -= 1; + } + + /* Print the credential out in lines. */ + for (i = 0; i < cred_written; i += line_length) { + /* Print either a full line, or however much credential data is left. */ + remaining = MIN(line_length, cred_written - i); + + /* Read out a line of data. */ + memset(cred_out_buf, 0, sizeof(cred_out_buf)); + if (format == CRED_STORAGE_FMT_BINARY) { + (void)base64_encode(cred_out_buf, sizeof(cred_out_buf), + &written, &cred_buf[i], remaining); + } else if (format == CRED_STORAGE_FMT_STRING) { + memcpy(cred_out_buf, &cred_buf[i], remaining); + if (filter_nonprint(cred_out_buf, remaining, '?')) { + err = -EBADF; + } + } + + /* Print the line. */ + shell_fprintf(sh, SHELL_NORMAL, "%s\n", cred_out_buf); + } + + if (err) { + shell_fprintf(sh, SHELL_WARNING, "Non-printable characters were included in the " + "output and filtered. Have you selected the " + "correct storage format?\n"); + } + +cleanup: + /* Unlock credentials since we are done interacting with internal state. */ + credentials_unlock(); + + /* Clear buffers when done. */ + memset(cred_out_buf, 0, sizeof(cred_out_buf)); + shell_clear_cred_buf(sh); + + return err; +} + +/* Lists credentials in credential store. */ +static int tls_cred_cmd_list(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + size_t digest_size; + sec_tag_t sectag = TLS_SEC_TAG_NONE; + struct tls_credential *cred; + int count = 0; + + sec_tag_t sectag_filter = TLS_SEC_TAG_NONE; + enum tls_credential_type type_filter = TLS_CREDENTIAL_NONE; + + /* Lock credentials so that we can safely use internal access functions. */ + credentials_lock(); + + /* Sectag filter was provided, parse it. */ + if (argc >= 2) { + err = shell_parse_cred_sectag(sh, argv[1], §ag_filter, true); + if (err) { + goto cleanup; + } + } + + /* Credential type filter was provided, parse it. */ + if (argc >= 3) { + err = shell_parse_cred_type(sh, argv[2], &type_filter, true); + if (err) { + goto cleanup; + } + } + + /* Scan through all occupied sectags */ + while ((sectag = credential_next_tag_get(sectag)) != TLS_SEC_TAG_NONE) { + /* Filter by sectag if requested. */ + if (sectag_filter != TLS_SEC_TAG_NONE && sectag != sectag_filter) { + continue; + } + + cred = NULL; + /* Scan through all credentials within each sectag */ + while ((cred = credential_next_get(sectag, cred)) != NULL) { + /* Filter by credential type if requested. */ + if (type_filter != TLS_CREDENTIAL_NONE && cred->type != type_filter) { + continue; + } + count++; + + /* Generate a digest of the credential */ + memset(cred_digest_buf, 0, sizeof(cred_digest_buf)); + strcpy(cred_digest_buf, "N/A"); + digest_size = sizeof(cred_digest_buf); + err = credential_digest(cred, cred_digest_buf, &digest_size); + + /* Print digest and sectag/type info */ + shell_fprintf(sh, err ? SHELL_ERROR : SHELL_NORMAL, "%d,%s,%s,%d\n", + sectag, cred_type_name_compact(cred->type), + err ? "ERROR" : cred_digest_buf, err); + + err = 0; + } + }; + + shell_fprintf(sh, SHELL_NORMAL, "%d credentials found.\n", count); + +cleanup: + /* Unlock credentials since we are done interacting with internal state. */ + credentials_unlock(); + + /* Clear digest buffer afterwards for good measure. */ + memset(cred_digest_buf, 0, sizeof(cred_digest_buf)); + + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(tls_cred_cmds, + SHELL_CMD_ARG(buf, NULL, "Buffer in credential data so it can be added.", + tls_cred_cmd_buf, 2, 0), + SHELL_CMD_ARG(add, NULL, "Add a TLS credential.", + tls_cred_cmd_add, 5, 1), + SHELL_CMD_ARG(del, NULL, "Delete a TLS credential.", + tls_cred_cmd_del, 3, 0), + SHELL_CMD_ARG(get, NULL, "Retrieve the contents of a TLS credential", + tls_cred_cmd_get, 4, 0), + SHELL_CMD_ARG(list, NULL, "List stored TLS credentials, optionally filtering by type " + "or sectag.", + tls_cred_cmd_list, 1, 2), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_REGISTER(cred, &tls_cred_cmds, "TLS Credentials Commands", NULL); From d1e91686f3263b4cc8d07fa4e0363a33c15dd475 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 17:00:17 +0100 Subject: [PATCH 0370/1049] twister: Replace native_posix with native_sim * Replace native_posix references with native_sim in arguments help messages * For the seed parameter, correct platform check to accept native_sim * Use native_sim in twister tests Signed-off-by: Alberto Escolar Piedras --- scripts/pylib/twister/twisterlib/environment.py | 10 +++++----- scripts/pylib/twister/twisterlib/handlers.py | 2 +- scripts/pylib/twister/twisterlib/runner.py | 2 +- scripts/tests/twister/test_runner.py | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index f84749d547c4a5a..86965f1f9cfbadc 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -220,7 +220,7 @@ def add_parse_arguments(parser = None): "--enable-valgrind", action="store_true", help="""Run binary through valgrind and check for several memory access errors. Valgrind needs to be installed on the host. This option only - works with host binaries such as those generated for the native_posix + works with host binaries such as those generated for the native_sim configuration and is mutual exclusive with --enable-asan. """) @@ -228,7 +228,7 @@ def add_parse_arguments(parser = None): "--enable-asan", action="store_true", help="""Enable address sanitizer to check for several memory access errors. Libasan needs to be installed on the host. This option only - works with host binaries such as those generated for the native_posix + works with host binaries such as those generated for the native_sim configuration and is mutual exclusive with --enable-valgrind. """) @@ -349,7 +349,7 @@ def add_parse_arguments(parser = None): "--enable-lsan", action="store_true", help="""Enable leak sanitizer to check for heap memory leaks. Libasan needs to be installed on the host. This option only - works with host binaries such as those generated for the native_posix + works with host binaries such as those generated for the native_sim configuration and when --enable-asan is given. """) @@ -358,7 +358,7 @@ def add_parse_arguments(parser = None): help="""Enable undefined behavior sanitizer to check for undefined behaviour during program execution. It uses an optional runtime library to provide better error diagnostics. This option only works with host - binaries such as those generated for the native_posix configuration. + binaries such as those generated for the native_sim configuration. """) parser.add_argument("--enable-size-report", action="store_true", @@ -586,7 +586,7 @@ def add_parse_arguments(parser = None): parser.add_argument( "--seed", type=int, - help="Seed for native posix pseudo-random number generator") + help="Seed for native_sim pseudo-random number generator") parser.add_argument( "--short-build-path", diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index 2ffeb4bfc195202..a39e68741aa2959 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -246,7 +246,7 @@ def _create_command(self, robot_test): "--track-origins=yes", ] + command - # Only valid for native_posix + # Only valid for native_sim if self.seed is not None: command.append(f"--seed={self.seed}") if self.extra_test_args is not None: diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index 94c24a837d8dc52..2e9c31bb715fe3d 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -1059,7 +1059,7 @@ def run(self): if instance.handler.type_str == "device": instance.handler.duts = self.duts - if(self.options.seed is not None and instance.platform.name.startswith("native_posix")): + if(self.options.seed is not None and instance.platform.name.startswith("native_")): self.parse_generated() if('CONFIG_FAKE_ENTROPY_NATIVE_POSIX' in self.defconfig and self.defconfig['CONFIG_FAKE_ENTROPY_NATIVE_POSIX'] == 'y'): diff --git a/scripts/tests/twister/test_runner.py b/scripts/tests/twister/test_runner.py index 50732bf42287e42..f0c2cbb50cf1355 100644 --- a/scripts/tests/twister/test_runner.py +++ b/scripts/tests/twister/test_runner.py @@ -2100,7 +2100,7 @@ def test_projectbuilder_build(mocked_jobserver): True, 'device', 234, - 'native_posix', + 'native_sim', 'posix', {'CONFIG_FAKE_ENTROPY_NATIVE_POSIX': 'y'}, 'pytest', @@ -2115,7 +2115,7 @@ def test_projectbuilder_build(mocked_jobserver): True, 'not device', None, - 'native_posix', + 'native_sim', 'not posix', {'CONFIG_FAKE_ENTROPY_NATIVE_POSIX': 'y'}, 'not pytest', @@ -2130,7 +2130,7 @@ def test_projectbuilder_build(mocked_jobserver): False, 'device', 234, - 'native_posix', + 'native_sim', 'posix', {'CONFIG_FAKE_ENTROPY_NATIVE_POSIX': 'y'}, 'pytest', From 373f2d21c121e523a5a062312c0401a87b7bb16d Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 12:29:28 +0100 Subject: [PATCH 0371/1049] doc/develop/test: Replace references to native_posix w native_sim Replace the references to native_posix with native_sim. Signed-off-by: Alberto Escolar Piedras --- doc/develop/test/bsim.rst | 2 +- doc/develop/test/coverage.rst | 4 ++-- doc/develop/test/twister.rst | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/develop/test/bsim.rst b/doc/develop/test/bsim.rst index be06fad434fa281..d52bbc6fcfd124f 100644 --- a/doc/develop/test/bsim.rst +++ b/doc/develop/test/bsim.rst @@ -32,7 +32,7 @@ Tests without radio activity: bsim tests with twister The :ref:`bsim boards` can be used without radio activity, and in that case, it is not necessary to connect them to a phyisical layer simulation. Thanks to this, this target boards can -be used just like :ref:`native_posix` with :ref:`twister `, +be used just like :ref:`native_sim` with :ref:`twister `, to run all standard Zephyr twister tests, but with models of a real SOC HW, and their drivers. Tests with radio activity diff --git a/doc/develop/test/coverage.rst b/doc/develop/test/coverage.rst index f911c74287cf90c..84eadad1a218a90 100644 --- a/doc/develop/test/coverage.rst +++ b/doc/develop/test/coverage.rst @@ -109,7 +109,7 @@ You may postprocess these with your preferred tools. For example: :zephyr-app: samples/hello_world :gen-args: -DCONFIG_COVERAGE=y :host-os: unix - :board: native_posix + :board: native_sim :goals: build :compact: @@ -140,7 +140,7 @@ For example, you may invoke:: or:: - $ twister --coverage -p native_posix -T tests/bluetooth + $ twister --coverage -p native_sim -T tests/bluetooth which will produce ``twister-out/coverage/index.html`` with the report. diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index 14cffac9e5054f6..b4cc35f3cb320cb 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -19,7 +19,7 @@ tests for different boards and different configurations to help keep the complete code tree buildable. When using (at least) one ``-v`` option, twister's console output -shows for every test how the test is run (qemu, native_posix, etc.) or +shows for every test how the test is run (qemu, native_sim, etc.) or whether the binary was just built. There are a few reasons why twister only builds a test and doesn't run it: @@ -1118,7 +1118,7 @@ An example of entries in a quarantine yaml: - kernel.common.nano64 platforms: - .*_cortex_.* - - native_posix + - native_sim To exclude a platform, use the following syntax: @@ -1272,7 +1272,7 @@ Running in Tests in Random Order ******************************** Enable ZTEST framework's :kconfig:option:`CONFIG_ZTEST_SHUFFLE` config option to run your tests in random order. This can be beneficial for identifying -dependencies between test cases. For native_posix platforms, you can provide +dependencies between test cases. For native_sim platforms, you can provide the seed to the random number generator by providing ``-seed=value`` as an argument to twister. See :ref:`Shuffling Test Sequence ` for more details. From fd281f5ea26969e6b4d504598f714377bf2c6e3f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 11:20:23 +0100 Subject: [PATCH 0372/1049] samples native_tty docs: Replace references to native_posix w native_sim Let's replace the references to native_posix with native_sim Signed-off-by: Alberto Escolar Piedras --- samples/drivers/uart/native_tty/README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/drivers/uart/native_tty/README.rst b/samples/drivers/uart/native_tty/README.rst index 8571ad1c538d66c..6b6e2a3175ed73f 100644 --- a/samples/drivers/uart/native_tty/README.rst +++ b/samples/drivers/uart/native_tty/README.rst @@ -15,7 +15,7 @@ The source code for this sample application can be found at: :zephyr_file:`samples/drivers/uart/native-tty`. You can learn more about the Native TTY UART driver in the -:ref:`TTY UART ` section of the Native posix board +:ref:`TTY UART ` section of the native_sim board documentation. Requirements @@ -34,12 +34,12 @@ Requirements Building and Running ******************** -This application can be built and executed on Native Posix as follows: +This application can be built and executed on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/drivers/uart/native_tty :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: From 277746185841c08bf900a02077512133f062012a Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 11:24:37 +0100 Subject: [PATCH 0373/1049] samples kernel: Replace references to native_posix w native_sim Let's replace the references to native_posix with native_sim in the documentation, and enable this tests by default in native_sim. Signed-off-by: Alberto Escolar Piedras --- samples/kernel/condition_variables/condvar/README.rst | 6 +++--- samples/kernel/condition_variables/condvar/sample.yaml | 2 +- samples/kernel/condition_variables/simple/README.rst | 6 +++--- samples/kernel/condition_variables/simple/sample.yaml | 2 +- samples/kernel/metairq_dispatch/README.rst | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/samples/kernel/condition_variables/condvar/README.rst b/samples/kernel/condition_variables/condvar/README.rst index 51f4cf0beb23d13..bd84d54854a7c5c 100644 --- a/samples/kernel/condition_variables/condvar/README.rst +++ b/samples/kernel/condition_variables/condvar/README.rst @@ -20,16 +20,16 @@ the console. Building and Running ******************** -This application can be built and executed on Native Posix as follows: +This application can be built and executed on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/kernel/condition_variables/condvar :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: -To build for another board, change "native_posix" above to that board's name. +To build for another board, change ``native_sim`` above to that board's name. Sample Output ============= diff --git a/samples/kernel/condition_variables/condvar/sample.yaml b/samples/kernel/condition_variables/condvar/sample.yaml index a6e1515c67b05c9..d2a68fbdce4977c 100644 --- a/samples/kernel/condition_variables/condvar/sample.yaml +++ b/samples/kernel/condition_variables/condvar/sample.yaml @@ -1,7 +1,7 @@ tests: sample.kernel.cond_var: integration_platforms: - - native_posix + - native_sim tags: - kernel - condition_variables diff --git a/samples/kernel/condition_variables/simple/README.rst b/samples/kernel/condition_variables/simple/README.rst index 42199d31c5bda34..2977b72cc9739b5 100644 --- a/samples/kernel/condition_variables/simple/README.rst +++ b/samples/kernel/condition_variables/simple/README.rst @@ -19,16 +19,16 @@ the console. Building and Running ******************** -This application can be built and executed on Native Posix as follows: +This application can be built and executed on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/kernel/condition_variables/simple :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: -To build for another board, change "native_posix" above to that board's name. +To build for another board, change ``native_sim`` above to that board's name. Sample Output ============= diff --git a/samples/kernel/condition_variables/simple/sample.yaml b/samples/kernel/condition_variables/simple/sample.yaml index 556fc8e9f03ec72..0b260a8a7e30cc9 100644 --- a/samples/kernel/condition_variables/simple/sample.yaml +++ b/samples/kernel/condition_variables/simple/sample.yaml @@ -1,7 +1,7 @@ tests: sample.kernel.cond_var.simple: integration_platforms: - - native_posix + - native_sim tags: - kernel - condition_variables diff --git a/samples/kernel/metairq_dispatch/README.rst b/samples/kernel/metairq_dispatch/README.rst index ef7e96afa17e691..1e9fda7927c03e0 100644 --- a/samples/kernel/metairq_dispatch/README.rst +++ b/samples/kernel/metairq_dispatch/README.rst @@ -60,7 +60,7 @@ kHz). Note that because the test is fundamentally measuring thread preemption behavior, it does not run without modification on -native_posix platforms. In that emulation environment, threads will +native_sim platforms. In that emulation environment, threads will not be preempted except at specific instrumentation points (e.g. in k_busy_wait()) where they will voluntarily release the CPU. From bf02cbc51f170d0236a4c74c11969ca7ca82c82f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 11:34:44 +0100 Subject: [PATCH 0374/1049] samples display: Switch from native_posix to native_sim In the docs replace the references to native_posix with native_sim Enable native_sim in the tests, and replace native_posix as integration platform. Signed-off-by: Alberto Escolar Piedras --- samples/drivers/display/README.rst | 4 ++-- samples/drivers/display/sample.yaml | 8 ++++++-- samples/subsys/display/lvgl/README.rst | 10 +++++----- samples/subsys/display/lvgl/sample.yaml | 2 +- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/samples/drivers/display/README.rst b/samples/drivers/display/README.rst index 02ec21f3eda1029..872a0b5f5d22243 100644 --- a/samples/drivers/display/README.rst +++ b/samples/drivers/display/README.rst @@ -30,12 +30,12 @@ Below is an example on how to build for a :ref:`nrf52840dk_nrf52840` board with :shield: adafruit_2_8_tft_touch_v2 :compact: -For testing purpose without the need of any hardware, the :ref:`native_posix` +For testing purpose without the need of any hardware, the :ref:`native_sim ` board is also supported and can be built as follows; .. zephyr-app-commands:: :zephyr-app: samples/drivers/display - :board: native_posix + :board: native_sim :goals: build :compact: diff --git a/samples/drivers/display/sample.yaml b/samples/drivers/display/sample.yaml index 00725caedb5c4db..ba93efd5c2e4651 100644 --- a/samples/drivers/display/sample.yaml +++ b/samples/drivers/display/sample.yaml @@ -103,10 +103,14 @@ tests: fixture: fixture_display sample.display.sdl: build_only: true - platform_allow: native_posix_64 + platform_allow: + - native_posix_64 + - native_sim_64 tags: display sample.display.dummy: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim extra_args: DTC_OVERLAY_FILE="dummy_dc.overlay" extra_configs: - CONFIG_DUMMY_DISPLAY=y diff --git a/samples/subsys/display/lvgl/README.rst b/samples/subsys/display/lvgl/README.rst index e7312a2791b7647..84bb5fdb40ba9e6 100644 --- a/samples/subsys/display/lvgl/README.rst +++ b/samples/subsys/display/lvgl/README.rst @@ -27,9 +27,9 @@ or a board with an integrated display: - :ref:`esp_wrover_kit` -or a simulated display environment in a native Posix application: +or a simulated display environment in a :ref:`native_sim ` application: -- :ref:`native_posix` +- :ref:`native_sim` - `SDL2`_ or @@ -53,15 +53,15 @@ Example building for :ref:`nrf52840dk_nrf52840`: :shield: adafruit_2_8_tft_touch_v2 :goals: build flash -Example building for :ref:`native_posix`: +Example building for :ref:`native_sim `: .. zephyr-app-commands:: :zephyr-app: samples/subsys/display/lvgl - :board: native_posix + :board: native_sim :goals: build run Alternatively, if building from a 64-bit host machine, the previous target -board argument may also be replaced by ``native_posix_64``. +board argument may also be replaced by ``native_sim_64``. References ********** diff --git a/samples/subsys/display/lvgl/sample.yaml b/samples/subsys/display/lvgl/sample.yaml index d53bc36aaa771fc..c57ab87122bdf1d 100644 --- a/samples/subsys/display/lvgl/sample.yaml +++ b/samples/subsys/display/lvgl/sample.yaml @@ -19,7 +19,7 @@ tests: modules: - lvgl integration_platforms: - - native_posix_64 + - native_sim_64 sample.display.lvgl.rk055hdmipi4m: # This sample is intended to test the RT1170 and RT595, which require # a display shield to work with LVGL From d800634515b7fc889f1145f4fa2b96e25095949e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 11:36:34 +0100 Subject: [PATCH 0375/1049] samples sensing: Switch from native_posix to native_sim In the docs replace the references to native_posix with native_sim. And switch the overlays and default test platform to native_sim from native_posix. Signed-off-by: Alberto Escolar Piedras --- samples/subsys/sensing/simple/README.rst | 8 ++++---- .../simple/boards/{native_posix.conf => native_sim.conf} | 0 .../boards/{native_posix.overlay => native_sim.overlay} | 0 samples/subsys/sensing/simple/sample.yaml | 5 +++-- 4 files changed, 7 insertions(+), 6 deletions(-) rename samples/subsys/sensing/simple/boards/{native_posix.conf => native_sim.conf} (100%) rename samples/subsys/sensing/simple/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/samples/subsys/sensing/simple/README.rst b/samples/subsys/sensing/simple/README.rst index b24d48685855ded..f8ff0857b315ba0 100644 --- a/samples/subsys/sensing/simple/README.rst +++ b/samples/subsys/sensing/simple/README.rst @@ -26,14 +26,14 @@ The program runs in the following sequence: Building and Running ******************** -This application can be built and executed on native_posix as follows: +This application can be built and executed on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/subsys/sensing/simple :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: -To build for another board, change "native_posix" above to that board's name. -At the current stage, it only support native posix +To build for another board, change "native_sim" above to that board's name. +At the current stage, it only support native sim. diff --git a/samples/subsys/sensing/simple/boards/native_posix.conf b/samples/subsys/sensing/simple/boards/native_sim.conf similarity index 100% rename from samples/subsys/sensing/simple/boards/native_posix.conf rename to samples/subsys/sensing/simple/boards/native_sim.conf diff --git a/samples/subsys/sensing/simple/boards/native_posix.overlay b/samples/subsys/sensing/simple/boards/native_sim.overlay similarity index 100% rename from samples/subsys/sensing/simple/boards/native_posix.overlay rename to samples/subsys/sensing/simple/boards/native_sim.overlay diff --git a/samples/subsys/sensing/simple/sample.yaml b/samples/subsys/sensing/simple/sample.yaml index b930aff274be83b..e8b33b417d96b4b 100644 --- a/samples/subsys/sensing/simple/sample.yaml +++ b/samples/subsys/sensing/simple/sample.yaml @@ -4,7 +4,7 @@ sample: common: tags: sensing integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: multi_line @@ -12,5 +12,6 @@ common: - "sensing subsystem run successfully" tests: sample.subsys.sensing.simple: - platform_allow: native_posix + platform_allow: + - native_sim tags: sensing From 388f82f6b38ec5c418a683187f969682cfa259b5 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 13:00:25 +0100 Subject: [PATCH 0376/1049] samples/basic: Switch from native_posix to native_sim In the docs replace the references to native_posix with native_sim. And switch the default test platform to native_sim from native_posix. Signed-off-by: Alberto Escolar Piedras --- samples/basic/hash_map/README.rst | 6 +++--- samples/basic/sys_heap/README.rst | 8 ++++---- samples/basic/sys_heap/sample.yaml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/basic/hash_map/README.rst b/samples/basic/hash_map/README.rst index 403ef297923352d..0c5d91a3dae77ce 100644 --- a/samples/basic/hash_map/README.rst +++ b/samples/basic/hash_map/README.rst @@ -16,16 +16,16 @@ This is a simple example that repeatedly: Building ******** -This application can be built on native_posix as follows: +This application can be built on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/basic/hash_map :host-os: unix - :board: native_posix + :board: native_sim :goals: build :compact: -To build for another board, change "native_posix" above to that board's name. +To build for another board, change "native_sim" above to that board's name. Additionally, it is possible to use one of the other Hashmap implementations by specifying diff --git a/samples/basic/sys_heap/README.rst b/samples/basic/sys_heap/README.rst index 2b124400cde7e70..74eb2b9e3320e03 100644 --- a/samples/basic/sys_heap/README.rst +++ b/samples/basic/sys_heap/README.rst @@ -10,18 +10,18 @@ A simple sample that can be used with any :ref:`supported board ` and prints system heap usage to the console. Building -******************** +******** -This application can be built on native_posix as follows: +This application can be built on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/basic/sys_heap :host-os: unix - :board: native_posix + :board: native_sim :goals: build :compact: -To build for another board, change "native_posix" above to that board's name. +To build for another board, change "native_sim" above to that board's name. Running ******* diff --git a/samples/basic/sys_heap/sample.yaml b/samples/basic/sys_heap/sample.yaml index 9e9f45c90ca71b0..d6179247991d490 100644 --- a/samples/basic/sys_heap/sample.yaml +++ b/samples/basic/sys_heap/sample.yaml @@ -3,7 +3,7 @@ sample: name: Basic system heap sample common: integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: multi_line From 374ecf706d570c205df8bcf9460422960fa6b9fd Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 13:02:22 +0100 Subject: [PATCH 0377/1049] samples drivers eeprom: Switch from native_posix to native_sim In the docs replace the references to native_posix with native_sim. Enable this test in natives_sim. And switch the default test platform to native_sim from native_posix. Signed-off-by: Alberto Escolar Piedras --- samples/drivers/eeprom/README.rst | 4 ++-- samples/drivers/eeprom/sample.yaml | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/samples/drivers/eeprom/README.rst b/samples/drivers/eeprom/README.rst index 25007274a05a503..079a3ebb469b8c5 100644 --- a/samples/drivers/eeprom/README.rst +++ b/samples/drivers/eeprom/README.rst @@ -15,12 +15,12 @@ Building and Running In case the target board has defined an EEPROM with alias ``eeprom-0`` the sample can be built without further ado. This applies for example to the -:ref:`native_posix` board: +:ref:`native_sim` board: .. zephyr-app-commands:: :zephyr-app: samples/drivers/eeprom :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: diff --git a/samples/drivers/eeprom/sample.yaml b/samples/drivers/eeprom/sample.yaml index b971faf9ba53df3..c9dfa7dd071a160 100644 --- a/samples/drivers/eeprom/sample.yaml +++ b/samples/drivers/eeprom/sample.yaml @@ -8,8 +8,10 @@ tests: - gd32f450i_eval - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix_64 + - native_sim_64 harness: console harness_config: type: one_line From 32000aafa1048c0198276916a1a466cb7a111f88 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 13:04:45 +0100 Subject: [PATCH 0378/1049] samples/modules/lvgl: Switch from native_posix to native_sim In the docs replace the references to native_posix with native_sim. And switch the default test platform to native_sim from native_posix. Signed-off-by: Alberto Escolar Piedras --- samples/modules/lvgl/accelerometer_chart/README.rst | 2 +- samples/modules/lvgl/accelerometer_chart/sample.yaml | 2 +- samples/modules/lvgl/demos/README.rst | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/modules/lvgl/accelerometer_chart/README.rst b/samples/modules/lvgl/accelerometer_chart/README.rst index 95d7287c89e88a9..69f90b4f4de610b 100644 --- a/samples/modules/lvgl/accelerometer_chart/README.rst +++ b/samples/modules/lvgl/accelerometer_chart/README.rst @@ -45,7 +45,7 @@ custom value of 20 Hz): .. zephyr-app-commands:: :zephyr-app: samples/modules/lvgl/accelerometer_chart :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_SAMPLE_ACCEL_SAMPLING_RATE=20 :goals: run :compact: diff --git a/samples/modules/lvgl/accelerometer_chart/sample.yaml b/samples/modules/lvgl/accelerometer_chart/sample.yaml index cca7fe07ffe6889..943a242d00cf5b2 100644 --- a/samples/modules/lvgl/accelerometer_chart/sample.yaml +++ b/samples/modules/lvgl/accelerometer_chart/sample.yaml @@ -15,4 +15,4 @@ tests: modules: - lvgl integration_platforms: - - native_posix_64 + - native_sim_64 diff --git a/samples/modules/lvgl/demos/README.rst b/samples/modules/lvgl/demos/README.rst index 1e12b8d77f8b717..cbc97616808a080 100644 --- a/samples/modules/lvgl/demos/README.rst +++ b/samples/modules/lvgl/demos/README.rst @@ -31,7 +31,7 @@ These demos can be built as follows: .. zephyr-app-commands:: :zephyr-app: samples/modules/lvgl/demos :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_LV_Z_DEMO_MUSIC=y :goals: run :compact: @@ -39,7 +39,7 @@ These demos can be built as follows: .. zephyr-app-commands:: :zephyr-app: samples/modules/lvgl/demos :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_LV_Z_DEMO_BENCHMARK=y :goals: run :compact: @@ -47,7 +47,7 @@ These demos can be built as follows: .. zephyr-app-commands:: :zephyr-app: samples/modules/lvgl/demos :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_LV_Z_DEMO_STRESS=y :goals: run :compact: @@ -55,7 +55,7 @@ These demos can be built as follows: .. zephyr-app-commands:: :zephyr-app: samples/modules/lvgl/demos :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_LV_Z_DEMO_WIDGETS=y :goals: run :compact: From 6e2deeebbc2e376cddb796acfb76b1fa18c8987e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 13:05:22 +0100 Subject: [PATCH 0379/1049] samples/modules/chre: Switch from native_posix to native_sim In the docs replace the references to native_posix with native_sim. And switch the default test platform to native_sim from native_posix. Signed-off-by: Alberto Escolar Piedras --- samples/modules/chre/README.rst | 2 +- samples/modules/chre/sample.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/modules/chre/README.rst b/samples/modules/chre/README.rst index 54b9244d3dcad46..22a43a58432e9d6 100644 --- a/samples/modules/chre/README.rst +++ b/samples/modules/chre/README.rst @@ -31,7 +31,7 @@ To build the sample use the following west command: .. zephyr-app-commands:: :zephyr-app: samples/modules/chre - :board: native_posix + :board: native_sim :goals: build Once built and run, the sample application should: diff --git a/samples/modules/chre/sample.yaml b/samples/modules/chre/sample.yaml index 65f64e9453dc4f6..9442decc83df545 100644 --- a/samples/modules/chre/sample.yaml +++ b/samples/modules/chre/sample.yaml @@ -24,5 +24,5 @@ tests: - "EchoApp::nanoappEnd\\(\\)" - "I: Exiting EventLoop.*" integration_platforms: - - native_posix + - native_sim filter: CONFIG_FULL_LIBC_SUPPORTED From b4d0791d1ab727e376924a97acb5f647431fa406 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 12:58:13 +0100 Subject: [PATCH 0380/1049] services/tracing doc & samples: Replace native_posix w native_sim In the docs replace the references to native_posix with native_sim. In the sample, add overlays for native_sim, and add native_sim to filter and as default integration platform. Signed-off-by: Alberto Escolar Piedras --- doc/services/tracing/index.rst | 12 ++++++------ samples/subsys/tracing/README.rst | 7 +++---- samples/subsys/tracing/boards/native_sim.conf | 5 +++++ ...tive_posix_ctf.conf => prj_native_ctf.conf} | 0 samples/subsys/tracing/sample.yaml | 18 +++++++++++++----- 5 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 samples/subsys/tracing/boards/native_sim.conf rename samples/subsys/tracing/{prj_native_posix_ctf.conf => prj_native_ctf.conf} (100%) diff --git a/doc/services/tracing/index.rst b/doc/services/tracing/index.rst index 74212d2f5a17fa7..eb32d385b31c151 100644 --- a/doc/services/tracing/index.rst +++ b/doc/services/tracing/index.rst @@ -181,7 +181,7 @@ The following backends are currently supported: * UART * USB -* File (Using native posix port) +* File (Using the native port with POSIX architecture based targets) * RTT (With SystemView) * RAM (buffer to be retrieved by a debugger) @@ -191,14 +191,14 @@ Using Tracing The sample :zephyr_file:`samples/subsys/tracing` demonstrates tracing with different formats and backends. -To get started, the simplest way is to use the CTF format with the ``native_posix`` +To get started, the simplest way is to use the CTF format with the :ref:`native_sim ` port, build the sample as follows: .. zephyr-app-commands:: :tool: all :app: samples/subsys/tracing - :board: native_posix - :gen-args: -DCONF_FILE=prj_native_posix_ctf.conf + :board: native_sim + :gen-args: -DCONF_FILE=prj_native_ctf.conf :goals: build You can then run the resulting binary with the option ``-trace-file`` to generate @@ -343,14 +343,14 @@ Locking may not be needed if multiple independent channels are available. ``emit(a,thread_id); emit(b,thread_id); emit(c,thread_id);`` - The system has atomic write but one shared channel - E.g. ``native_posix`` or board with DMA. May or may not need locking. + E.g. ``native_sim`` or board with DMA. May or may not need locking. ``emit(a ## b ## c); /* Concat to buffer */`` ``lock(); emit(a); emit(b); emit(c); release(); /* No extra mem */`` - The system has atomic write and many channels - E.g. native_posix or board with multi-channel DMA. Lock-free. + E.g. native_sim or board with multi-channel DMA. Lock-free. ``emit(a ## b ## c, thread_id);`` diff --git a/samples/subsys/tracing/README.rst b/samples/subsys/tracing/README.rst index 5214e35ce48af00..299ab0a751d61cd 100644 --- a/samples/subsys/tracing/README.rst +++ b/samples/subsys/tracing/README.rst @@ -83,8 +83,7 @@ Build a POSIX-tracing image with: .. zephyr-app-commands:: :zephyr-app: samples/subsys/tracing - :board: native_posix - :conf: "prj_native_posix.conf" + :board: native_sim :goals: build :compact: @@ -92,8 +91,8 @@ or: .. zephyr-app-commands:: :zephyr-app: samples/subsys/tracing - :board: native_posix - :conf: "prj_native_posix_ctf.conf" + :board: native_sim + :conf: "prj_native_ctf.conf" :goals: build :compact: diff --git a/samples/subsys/tracing/boards/native_sim.conf b/samples/subsys/tracing/boards/native_sim.conf new file mode 100644 index 000000000000000..2a60b33a7677fff --- /dev/null +++ b/samples/subsys/tracing/boards/native_sim.conf @@ -0,0 +1,5 @@ +CONFIG_TRACING=y +CONFIG_TRACING_TEST=y +CONFIG_TRACING_SYNC=y +CONFIG_TRACING_BACKEND_POSIX=y +CONFIG_TRACING_PACKET_MAX_SIZE=64 diff --git a/samples/subsys/tracing/prj_native_posix_ctf.conf b/samples/subsys/tracing/prj_native_ctf.conf similarity index 100% rename from samples/subsys/tracing/prj_native_posix_ctf.conf rename to samples/subsys/tracing/prj_native_ctf.conf diff --git a/samples/subsys/tracing/sample.yaml b/samples/subsys/tracing/sample.yaml index dda98638a58816b..23db8876ceebc56 100644 --- a/samples/subsys/tracing/sample.yaml +++ b/samples/subsys/tracing/sample.yaml @@ -60,11 +60,19 @@ tests: platform_allow: sam_e70_xplained depends_on: usb_device extra_args: CONF_FILE="prj_usb_ctf.conf" - sample.tracing.transport.native_posix: - platform_allow: native_posix - sample.tracing.transport.native_posix.ctf: - platform_allow: native_posix - extra_args: CONF_FILE="prj_native_posix_ctf.conf" + sample.tracing.transport.native: + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim + sample.tracing.transport.native.ctf: + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim + extra_args: CONF_FILE="prj_native_ctf.conf" sample.tracing.percepio: platform_allow: frdm_k64f extra_args: CONF_FILE="prj_percepio.conf" From 90aee7d65cffba0d0f681e46093c318e70481aee Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Sun, 1 Oct 2023 19:57:20 +0800 Subject: [PATCH 0381/1049] imx93: update iomuxc refs to match new pinctrl.dtsi Update iomuxc references to match the changes of `mimx9352cvuxk-pinctrl.dtsi` in hal/nxp. Signed-off-by: Chekhov Ma --- boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi | 4 ++-- west.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi index 50186a49b0ad08c..947fbb502a04d7e 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi +++ b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi @@ -9,8 +9,8 @@ &pinctrl { uart2_default: uart2_default { group0 { - pinmux = <&iomuxc_uart2_rxd_uart_rx_uart2_rx>, - <&iomuxc_uart2_txd_uart_tx_uart2_tx>; + pinmux = <&iomuxc1_uart2_rxd_lpuart_rx_lpuart2_rx>, + <&iomuxc1_uart2_txd_lpuart_tx_lpuart2_tx>; bias-pull-up; slew-rate = "slightly_fast"; drive-strength = "x5"; diff --git a/west.yml b/west.yml index 639f5566de01a6d..f7b40860645430c 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 73620197038d7ba80fb1f9abd001828b9dd6a27e + revision: 78d1912dbc2b5f6e114d7fd19a31053716a3b01d path: modules/hal/nxp groups: - hal From 2c13e53081774db4bd5a2772be5a605af07a9a97 Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Mon, 25 Sep 2023 10:28:15 +0800 Subject: [PATCH 0382/1049] imx93: add lpuart1 imx93: add dts node and mmu region for lpuart1 Signed-off-by: Chekhov Ma --- boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi | 10 ++++++++++ boards/arm64/mimx93_evk/mimx93_evk_a55.dts | 8 ++++++++ soc/arm64/nxp_imx/mimx9/mmu_regions.c | 5 +++++ 3 files changed, 23 insertions(+) diff --git a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi index 947fbb502a04d7e..83070adf93fde9b 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi +++ b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi @@ -7,6 +7,16 @@ #include &pinctrl { + uart1_default: uart1_default { + group0 { + pinmux = <&iomuxc1_uart1_rxd_lpuart_rx_lpuart1_rx>, + <&iomuxc1_uart1_txd_lpuart_tx_lpuart1_tx>; + bias-pull-up; + slew-rate = "slightly_fast"; + drive-strength = "x5"; + }; + }; + uart2_default: uart2_default { group0 { pinmux = <&iomuxc1_uart2_rxd_lpuart_rx_lpuart2_rx>, diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts index 4ace06656712fbf..375bb2f7a0ef15a 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts @@ -30,6 +30,14 @@ }; }; +&lpuart1 { + status = "disabled"; + current-speed = <115200>; + /* clocks = <&ccm IMX_CCM_UART4_CLK 0x6c 24>; */ + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + &lpuart2 { status = "okay"; current-speed = <115200>; diff --git a/soc/arm64/nxp_imx/mimx9/mmu_regions.c b/soc/arm64/nxp_imx/mimx9/mmu_regions.c index fb53c54e7f38f77..6dd767c2c9cf8e7 100644 --- a/soc/arm64/nxp_imx/mimx9/mmu_regions.c +++ b/soc/arm64/nxp_imx/mimx9/mmu_regions.c @@ -30,6 +30,11 @@ static const struct arm_mmu_region mmu_regions[] = { DT_REG_SIZE(DT_NODELABEL(ana_pll)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), + MMU_REGION_FLAT_ENTRY("UART1", + DT_REG_ADDR(DT_NODELABEL(lpuart1)), + DT_REG_SIZE(DT_NODELABEL(lpuart1)), + MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), + MMU_REGION_FLAT_ENTRY("UART2", DT_REG_ADDR(DT_NODELABEL(lpuart2)), DT_REG_SIZE(DT_NODELABEL(lpuart2)), From 2b6c861f0c6ec686cfec4a000bfe01c8febd67fe Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Tue, 25 Apr 2023 17:19:55 +0800 Subject: [PATCH 0383/1049] imx93: increase mmu region count to 64 The default mmu region count is not enough when more drivers are added. Signed-off-by: Chekhov Ma --- boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig b/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig index 2bcf6198a10e1b8..53cb74f825c781e 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig @@ -7,6 +7,9 @@ CONFIG_AARCH64_IMAGE_HEADER=y CONFIG_ARMV8_A_NS=y +# MMU Options +CONFIG_MAX_XLAT_TABLES=64 + # Cache Options CONFIG_CACHE_MANAGEMENT=y CONFIG_DCACHE_LINE_SIZE_DETECT=y From c05b81bd9cad4d42334cc0807e12d6f175c900d7 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 09:30:53 +0100 Subject: [PATCH 0384/1049] docs: native_sim/posix: Swap documentation from native_posix to native_sim During this release native_sim is replacing native_posix as the main host test/development platform. Therefore, instead of basing the native_sim documentation in native_posix's one, let's do it the other way around. This commit mostly moves documentation from the native_posix page into the native_sim one, changing the board and renaming labels. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_posix/doc/index.rst | 510 ++-------------------- boards/posix/native_sim/doc/index.rst | 530 +++++++++++++++++++++-- boards/posix/nrf_bsim/doc/nrf52_bsim.rst | 4 +- 3 files changed, 536 insertions(+), 508 deletions(-) diff --git a/boards/posix/native_posix/doc/index.rst b/boards/posix/native_posix/doc/index.rst index 92827acbacfe59a..e096e8c54839f05 100644 --- a/boards/posix/native_posix/doc/index.rst +++ b/boards/posix/native_posix/doc/index.rst @@ -11,14 +11,28 @@ Native POSIX execution (native_posix) Overview ******** -This is a :ref:`POSIX architecture` based board. -With it, a Zephyr application can be compiled together with -the Zephyr kernel, creating a normal Linux executable. +``native_posix`` is the predecessor of :ref:`native_sim`. +Just like with :ref:`native_sim` you can build your Zephyr application +with the Zephyr kernel, creating a normal Linux executable with your host tooling, +and can debug and instrument it like any other Linux program. + +But unlike with :ref:`native_sim` you are limited to only using the host C library. +:ref:`native_sim` supports all ``native_posix`` use cases. + +.. note:: + + | If you are a new user, you are encouraged to use :ref:`native_sim` directly. + | If you have been using native_posix you are recommended to start using + :ref:`native_sim` instead. + | If needed, :ref:`native_sim` includes a compatibility mode + :kconfig:option:`CONFIG_NATIVE_SIM_NATIVE_POSIX_COMPAT`, + which will set its configuration to mimic a native_posix's like configuration. This board does not intend to simulate any particular HW, but it provides a few peripherals such as an Ethernet driver, display, UART, etc., to enable developing and testing application code which would require them. -See `Peripherals`_ for more information. +This board supports the same :ref:`peripherals` +:ref:`and backends as native_sim`. .. _native_posix_deps: @@ -36,15 +50,16 @@ Important limitations This board inherits :ref:`the limitations of its architecture` +Moreover, being limited to build only with the host C library, it is not possible to build +applications with the :ref:`Zephyr POSIX OS abstraction`, as there would be symbol +collisions between the host OS and this abstraction layer. + .. _native_posix_how_to_use: How to use it ************* -Compiling -========= - -Specify the native_posix board target to build a native POSIX application: +To build, simply specify the ``native_posix`` board as target: .. zephyr-app-commands:: :zephyr-app: samples/hello_world @@ -53,92 +68,20 @@ Specify the native_posix board target to build a native POSIX application: :goals: build :compact: -Running -======= - -The result of the compilation is an executable (zephyr.exe) placed in the -zephyr/ subdirectory of the build folder. -Run the zephyr.exe executable as you would any other Linux console application. - -.. code-block:: console - - $ ./build/zephyr/zephyr.exe - # Press Ctrl+C to exit - -This executable accepts several command line options depending on the -compilation configuration. -You can run it with the ``--help`` command line switch to get a list of -available options:: - - $ ./build/zephyr/zephyr.exe --help - -Note that the Zephyr kernel does not actually exit once the application is -finished. It simply goes into the idle loop forever. -Therefore you must stop the application manually (Ctrl+C in Linux). - -Application tests using the ``ztest`` framework will exit after all -tests have completed. - -If you want your application to gracefully finish when it reaches some point, -you may add a conditionally compiled (:kconfig:option:`CONFIG_ARCH_POSIX`) call to -``posix_exit(int status)`` at that point. - -.. _native_posix_debug: - -Debugging -========= - -Since the Zephyr executable is a native application, it can be debugged and -instrumented as any other native program. The program is compiled with debug -information, so it can be run directly in, for example, ``gdb`` or instrumented -with ``valgrind``. - -Because the execution of your Zephyr application is normally deterministic -(there are no asynchronous or random components), you can execute the -code multiple times and get the exact same result. Instrumenting the -code does not affect its execution. - -To ease debugging you may want to compile your code without optimizations -(e.g., -O0) by setting :kconfig:option:`CONFIG_NO_OPTIMIZATIONS`. - -.. _native_posix_asan: - -Address Sanitizer (ASan) -======================== - -You can also build Zephyr with the `Address Sanitizer`_. To do this, set -:kconfig:option:`CONFIG_ASAN`, for example, in the application project file, or in the -``west build`` or ``cmake`` command line invocation. - -Note that you will need the ASan library installed in your system. -In Debian/Ubuntu this is ``libasan1``. - -.. _Address Sanitizer: - https://github.com/google/sanitizers/wiki/AddressSanitizer - -Undefined Behavior Sanitizer (UBSan) -==================================== - -You can also build Zephyr with the `Undefined Behavior Sanitizer`_. To do this, set -:kconfig:option:`CONFIG_UBSAN`, for example, in the application project file, or in the -``west build`` or ``cmake`` command line invocation. - -.. _Undefined Behavior Sanitizer: - https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html - -Coverage reports -================ - -See -:ref:`coverage reports using the POSIX architecture`. +Now you have a Linux executable, ``./build/zephyr/zephyr.exe``, you can use just like any +other Linux program. +You can run, debug, build it with sanitizers or with coverage just like with +:ref:`native_sim`. +Please check :ref:`native_sim's how to` for more info. .. _native_posix32_64: 32 and 64bit versions ********************* -native_posix comes with two targets: A 32 bit and 64 bit version. +Just like :ref:`native_sim`, ``native_posix comes`` with two targets: +A 32 bit and 64 bit version. The 32 bit version, ``native_posix``, is the default target, which will compile your code for the ILP32 ABI (i386 in a x86 or x86_64 system) where pointers and longs are 32 bits. @@ -151,396 +94,3 @@ one with a 32bit userspace. The 64 bit version, ``native_posix_64``, compiles your code targeting the LP64 ABI (x86-64 in x86 systems), where pointers and longs are 64 bits. You can use this target if you cannot compile or run 32 bit binaries. - -If you are using another 32 bit POSIX arch target you may also override its ABI -target and pointer bit width by setting :kconfig:option:`CONFIG_64BIT`. - - -Rationale for this port and comparison with other options -********************************************************* - -The native_posix board shares the overall -:ref:`intent of the POSIX architecture`, -while being a HW agnostic test platform which in some cases utilizes the host -OS peripherals. -It does not intend to model any particular HW, and as such can only be used -to develop and test application code which is far decoupled from the HW. - -For developing and testing SW which requires specific HW, while retaining the -benefits of the POSIX architecture other solutions like the -:ref:`bsim boards` -should be considered. - -Check the :ref:`POSIX architecture comparison ` -with other development and test options for more insights. - -.. _native_posix_architecture: - -Architecture -************ - -This board is based on the POSIX architecture port of Zephyr and shares -:ref:`its basic architecture` regarding threading -and CPU/HW scheduling. - -This board does not try to emulate any particular embedded CPU or SOC. -The code is compiled natively for the host system (typically x86). - -About time in native_posix -========================== - -Normally simulated time runs fully decoupled from the real host time -and as fast as the host compute power would allow. -This is desirable when running in a debugger or testing in batch, but not if -interacting with external interfaces based on the real host time. - -The Zephyr kernel is only aware of the simulated time as provided by the -HW models. Therefore any normal Zephyr thread will also know only about -simulated time. - -The only link between the simulated time and the real/host time, if any, -is created by the clock and timer model. - -This model can be configured to slow down the execution of native_posix to -real time. -You can do this with the ``--rt`` and ``--no-rt`` options from the command line. -The default behavior is set with -:kconfig:option:`CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME`. -Note that all this model does is wait before raising the -next system tick interrupt until the corresponding real/host time. -If, for some reason, native_posix runs slower than real time, all this -model can do is "catch up" as soon as possible by not delaying the -following ticks. -So if the host load is too high, or you are running in a debugger, you will -see simulated time lagging behind the real host time. -This solution ensures that normal runs are still deterministic while -providing an illusion of real timeness to the observer. - -When locked to real time, simulated time can also be set to run faster or -slower than real time. -This can be controlled with the ``--rt-ratio=`` and ``-rt-drift=`` -command line options. Note that both of these options control the same -underlying mechanism, and that ``drift`` is by definition equal to -``ratio - 1``. -It is also possible to adjust this clock speed on the fly with -:c:func:`native_rtc_adjust_clock()`. - -In this way if, for example, ``--rt-ratio=2`` is given, the simulated time -will advance at twice the real time speed. -Similarly if ``--rt-drift=-100e-6`` is given, the simulated time will progress -100ppm slower than real time. -Note that these 2 options have no meaning when running in non real-time -mode. - -How simulated time and real time relate to each other ------------------------------------------------------ - -Simulated time (``st``) can be calculated from real time (``rt``) as - -``st = (rt - last_rt) * ratio + last_st`` - -And vice-versa: - -``rt = (st - last_st) / ratio + last_rt`` - -Where ``last_rt`` and ``last_st`` are respectively the real time and the -simulated time when the last clock ratio adjustment took place. - -All times are kept in microseconds. - -.. _native_posix_peripherals: - -Peripherals -*********** - -The following peripherals are currently provided with this board: - -**Interrupt controller**: - A simple yet generic interrupt controller is provided. It can nest interrupts - and provides interrupt priorities. Interrupts can be individually masked or - unmasked. SW interrupts are also supported. - -**Clock, timer and system tick model** - This model provides the system tick timer. By default - :kconfig:option:`CONFIG_SYS_CLOCK_TICKS_PER_SEC` configures it to tick every 10ms. - - This peripheral driver also provides the needed functionality for this - architecture-specific :c:func:`k_busy_wait`. - - Please refer to the section `About time in native_posix`_ for more - information. - -**UART/Serial** - Two optional native UART drivers are available: - - **PTTY driver (UART_NATIVE_POSIX)** - With this driver, one or two Zephyr UART devices can be created. These - can be connected to the Linux process stdin/stdout or a newly created - pseudo-tty. For more information refer to the section `PTTY UART`_. - - **TTY driver (UART_NATIVE_TTY)** - An UART driver for interacting with host-attached serial port devices - (eg. USB to UART dongles). For more information refer to the section - `TTY UART`_. - -**Real time clock** - The real time clock model provides a model of a constantly powered clock. - By default this is initialized to the host time at boot. - - This RTC can also be set to start from time 0 with the ``--rtc-reset`` command - line option. - - It is possible to offset the RTC clock value at boot with the - ``--rtc-offset=`` option, - or to adjust it dynamically with the function :c:func:`native_rtc_offset`. - - After start, this RTC advances with the simulated time, and is therefore - affected by the simulated time speed ratio. - See `About time in native_posix`_ for more information. - - The time can be queried with the functions :c:func:`native_rtc_gettime_us` - and :c:func:`native_rtc_gettime`. Both accept as parameter the clock source: - - - ``RTC_CLOCK_BOOT``: It counts the simulated time passed since boot. - It is not subject to offset adjustments - - ``RTC_CLOCK_REALTIME``: RTC persistent time. It is affected by - offset adjustments. - - ``RTC_CLOCK_PSEUDOHOSTREALTIME``: A version of the real host time, - as if the host was also affected by the clock speed ratio and offset - adjustments performed to the simulated clock and this RTC. Normally - this value will be a couple of hundredths of microseconds ahead of the - simulated time, depending on the host execution speed. - This clock source should be used with care, as depending on the actual - execution speed of native_posix and the host load, - it may return a value considerably ahead of the simulated time. - -**Entropy device**: - An entropy device based on the host :c:func:`random` API. - This device will generate the same sequence of random numbers if initialized - with the same random seed. - You can change this random seed value by using the command line option: - ``--seed=`` where the value specified is a 32-bit integer - such as 97229 (decimal), 0x17BCD (hex), or 0275715 (octal). - -**Ethernet driver**: - A simple TAP based ethernet driver is provided. The driver expects that the - **zeth** network interface already exists in the host system. The **zeth** - network interface can be created by the ``net-setup.sh`` script found in - the `net-tools`_ zephyr project repository. User can communicate with the - Zephyr instance via the **zeth** network interface. Multiple TAP based - network interfaces can be created if needed. The IP address configuration - can be specified for each network interface instance. - - Note that this device can only be used with Linux hosts. - -.. _net-tools: - https://github.com/zephyrproject-rtos/net-tools - - -**Bluetooth controller**: - It's possible to use the host's Bluetooth adapter as a Bluetooth - controller for Zephyr. To do this the HCI device needs to be passed as - a command line option to ``zephyr.exe``. For example, to use ``hci0``, - use ``sudo zephyr.exe --bt-dev=hci0``. Using the device requires root - privileges (or the CAP_NET_ADMIN POSIX capability, to be exact) so - ``zephyr.exe`` needs to be run through ``sudo``. The chosen HCI device - must be powered down and support Bluetooth Low Energy (i.e. support the - Bluetooth specification version 4.0 or greater). - - Another possibility is to use a HCI TCP server which acts as a - :ref:`virtual Bluetooth controller` over TCP. - To connect to a HCI TCP server its IP address and port number must - be specified. For example, to connect to a HCI TCP server with IP - address 127.0.0.0 and port number 1020 use ``zephyr.exe --bt-dev=127.0.0.1:1020``. - This alternative option is mainly aimed for testing Bluetooth connectivity over - a virtual Bluetooth controller that does not depend on the Linux Bluetooth - stack and its HCI interface. - -**USB controller**: - It's possible to use the Virtual USB controller working over USB/IP - protocol. More information can be found in - :ref:`Testing USB over USP/IP in native_posix `. - -**Display driver**: - A display driver is provided that creates a window on the host machine to - render display content. - - This driver requires a 32-bit version of the `SDL2`_ library on the host - machine and ``pkg-config`` settings to correctly pickup the SDL2 install path - and compiler flags. - - On a Ubuntu 18.04 host system, for example, install the ``pkg-config`` and - ``libsdl2-dev:i386`` packages, and configure the pkg-config search path with - these commands:: - - $ sudo apt-get install pkg-config libsdl2-dev:i386 - $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig - -.. _SDL2: - https://www.libsdl.org/download-2.0.php - -**Flash driver**: - A flash driver is provided that accesses all flash data through a binary file - on the host file system. The behavior of the flash device can be configured - through the native POSIX board devicetree or Kconfig settings under - :kconfig:option:`CONFIG_FLASH_SIMULATOR`. - - By default the binary data is located in the file *flash.bin* in the current - working directory. The location of this file can be changed through the - command line parameter *--flash*. The flash data will be stored in raw format - and the file will be truncated to match the size specified in the devicetree - configuration. In case the file does not exists the driver will take care of - creating the file, else the existing file is used. - - The flash content can be accessed from the host system, as explained in the - `Host based flash access`_ section. - -PTTY UART -********* - -This driver can be configured with :kconfig:option:`CONFIG_UART_NATIVE_POSIX` -to instantiate up to two UARTs. By default only one UART is enabled. -With :kconfig:option:`CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE` -you can enable the second one. - -For the first UART, it can link it to a new -pseudoterminal (i.e. ``/dev/pts``), or map the UART input and -output to the executable's ``stdin`` and ``stdout``. -This is chosen by selecting either -:kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` or -:kconfig:option:`CONFIG_NATIVE_UART_0_ON_STDINOUT` -For interactive use with the :ref:`shell_api`, choose the first (OWN_PTY) option. -The second (STDINOUT) option can be used with the shell for automated -testing, such as when piping other processes' output to control it. -This is because the shell subsystem expects access to a raw terminal, -which (by default) a normal Linux terminal is not. - -When :kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` is chosen, the name of the -newly created UART pseudo-terminal will be displayed in the console. -If you want to interact with it manually, you should attach a terminal emulator -to it. This can be done, for example with the command:: - - $ xterm -e screen /dev/ & - -where ``/dev/`` should be replaced with the actual TTY device. - -You may also chose to automatically attach a terminal emulator to the first UART -by passing the command line option ``-attach_uart`` to the executable. -The command used for attaching to the new shell can be set with the command line -option ``-attach_uart_cmd=<"cmd">``. Where the default command is given by -:kconfig:option:`CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD`. -Note that the default command assumes both ``xterm`` and ``screen`` are -installed in the system. - -This driver only supports poll mode. Interrupt and async mode are not supported. -Neither runtime configuration or line control are supported. - -.. _native_tty_uart: - -TTY UART -******** - -With this driver an application can use the polling UART API (``uart_poll_out``, -``uart_poll_in``) to write and read characters to and from a connected serial -port device. - -This driver is automatically enabled when a devicetree contains a node -with ``"zephyr,native-tty-uart"`` compatible property and ``okay`` status, such -as one below:: - - uart { - status = "okay"; - compatible = "zephyr,native-tty-uart"; - serial-port = "/dev/ttyUSB0"; - current-speed = <115200>; - }; - -Interaction with serial ports can be configured in several different ways: - -* The default serial port and baud rate can be set via the device tree - properties ``serial-port`` and ``current-speed`` respectively. The - ``serial-port`` property is optional. -* Serial port and baud rate can also be set via command line options ``X_port`` - and ``X_baud`` respectively, where ``X`` is a name of a node. Command line - options override values from the devicetree. -* The rest of the configuration options such as number of data and stop bits, - parity, as well as baud rate can be set at runtime with ``uart_configure``. - -Multiple instances of such uart drivers are supported. - -The :zephyr:code-sample:`uart-native-tty` sample app provides a working example of the -driver. - -This driver only supports poll mode. Interrupt and async mode are not supported. -It has runtime configuration support, but no line control support. - -Subsystems backends -******************* - -Apart from its own peripherals, the native_posix board also has some dedicated -backends for some of Zephyr's subsystems. These backends are designed to ease -development by integrating more seamlessly with the host operating system: - -**Console backend**: - A console backend which by default is configured to - redirect any :c:func:`printk` write to the native host application's - ``stdout``. - - This driver is selected by default if the `PTTY UART`_ is not compiled in. - Otherwise :kconfig:option:`CONFIG_UART_CONSOLE` will be set to select the UART as - console backend. - -**Logger backend**: - A backend which prints all logger output to the process ``stdout``. - It supports timestamping, which can be enabled with - :kconfig:option:`CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP`; and colored output which can - be enabled with :kconfig:option:`CONFIG_LOG_BACKEND_SHOW_COLOR` and controlled - with the command line options ``--color``, ``--no-color`` and - ``--force-color``. - - In native_posix, by default, the logger is configured with - :kconfig:option:`CONFIG_LOG_MODE_IMMEDIATE`. - - This backend can be selected with :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX` - and is enabled by default unless the native_posix UART is compiled in. - In this later case, by default, the logger is set to output to the - `PTTY UART`_. - -**Tracing**: - A backend/"bottom" for Zephyr's CTF tracing subsystem which writes the tracing - data to a file in the host filesystem. - More information can be found in :ref:`Common Tracing Format ` - -Host based flash access -*********************** - -If a flash device is present, the file system partitions on the flash -device can be exposed through the host file system by enabling -:kconfig:option:`CONFIG_FUSE_FS_ACCESS`. This option enables a FUSE -(File system in User space) layer that maps the Zephyr file system calls to -the required UNIX file system calls, and provides access to the flash file -system partitions with normal operating system commands such as ``cd``, -``ls`` and ``mkdir``. - -By default the partitions are exposed through the directory *flash* in the -current working directory. This directory can be changed via the command line -option *--flash-mount*. As this directory operates as a mount point for FUSE -you have to ensure that it exists before starting the native POSIX board. - -On exit, the native POSIX board application will take care of unmounting the -directory. In the unfortunate case that the native POSIX board application -crashes, you can cleanup the stale mount point by using the program -``fusermount``:: - - $ fusermount -u flash - -Note that this feature requires a 32-bit version of the FUSE library, with a -minimal version of 2.6, on the host system and ``pkg-config`` settings to -correctly pickup the FUSE install path and compiler flags. - -On a Ubuntu 18.04 host system, for example, install the ``pkg-config`` and -``libfuse-dev:i386`` packages, and configure the pkg-config search path with -these commands:: - - $ sudo apt-get install pkg-config libfuse-dev:i386 - $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index bd332c1e081cbd8..00c8fa682ba3a47 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -3,18 +3,33 @@ Native simulator - native_sim ############################# +.. contents:: + :depth: 1 + :backlinks: entry + :local: + Overview ******** -The native_sim board is an evolution of :ref:`native_posix`. -Just like with :ref:`native_posix` you can build your Zephyr application -with the Zephyr kernel, creating a normal Linux executable with your host tooling, -and can debug and instrument it like any other Linux program. +The ``native_sim`` board is a :ref:`POSIX architecture` based board. +With it, a Zephyr application can be compiled together with +the Zephyr kernel, and libraries, creating a normal Linux executable. -native_sim is based on the +``native_sim`` is based on the `native simulator `_ and the :ref:`POSIX architecture`. +This board does not intend to simulate any particular HW, but it provides +a few peripherals such as an Ethernet driver, display, UART, etc., to enable +developing and testing application code which would require them. +See `Peripherals`_ for more information. + +.. note:: + + | ``native_sim`` is an evolution of the older :ref:`native_posix`. + | Some components, code, options names, and documentation will still use the old native_posix + names. But all components which worked with native_posix will work with native_sim. + Host system dependencies ************************ @@ -26,13 +41,18 @@ Please check the Important limitations ********************* -Native_sim is based on the :ref:`POSIX architecture`, and therefore +``native_sim`` is based on the :ref:`POSIX architecture`, and therefore :ref:`its limitations ` and considerations apply to it. +.. _native_sim_how_to_use: + How to use it ************* -To build, simply specify the native_sim board as target: +Compiling +========= + +To build, simply specify the ``native_sim`` board as target: .. zephyr-app-commands:: :zephyr-app: samples/hello_world @@ -41,17 +61,94 @@ To build, simply specify the native_sim board as target: :goals: build :compact: -Now you have a Linux executable, ``./build/zephyr/zephyr.exe``, you can use just like any -other Linux program. +Running +======= + +The result of the compilation is an executable (``zephyr.exe``) placed in the +``zephyr/`` subdirectory of the ``build`` folder. +Run the ``zephyr.exe`` executable as you would any other Linux console application. + +.. code-block:: console + + $ ./build/zephyr/zephyr.exe + # Press Ctrl+C to exit + +This executable accepts several command line options depending on the +compilation configuration. +You can run it with the ``--help`` command line switch to get a list of +available options:: + + $ ./build/zephyr/zephyr.exe --help + +Note that the Zephyr kernel does not actually exit once the application is +finished. It simply goes into the idle loop forever. +Therefore you must stop the application manually (Ctrl+C in Linux). + +Application tests using the :ref:`ztest framework` will exit after all +tests have completed. + +If you want your application to gracefully finish when it reaches some point, +you may add a conditionally compiled (:kconfig:option:`CONFIG_ARCH_POSIX`) call to +``nsi_exit(int status)`` at that point. + +.. _native_sim_debug: + +Debugging +========= + +Since the Zephyr executable is a native application, it can be debugged and +instrumented as any other native program. The program is compiled with debug +information, so it can be run directly in, for example, ``gdb`` or instrumented +with ``valgrind``. + +Because the execution of your Zephyr application is normally deterministic +(there are no asynchronous or random components), you can execute the +code multiple times and get the exact same result. Instrumenting the +code does not affect its execution. + +To ease debugging you may want to compile your code without optimizations +(e.g., ``-O0``) by setting :kconfig:option:`CONFIG_NO_OPTIMIZATIONS`. + +For ease of debugging consider using an IDE as GUI for your debugger. + +.. _native_sim_asan: + +Address Sanitizer (ASan) +======================== + +You can also build Zephyr with the `Address Sanitizer`_. To do this, set +:kconfig:option:`CONFIG_ASAN`, for example, in the application project file, or in the +``west build`` or ``cmake`` command line invocation. + +Note that you will need the ASan library installed in your system. +In Debian/Ubuntu this is ``libasan1``. + +.. _Address Sanitizer: + https://github.com/google/sanitizers/wiki/AddressSanitizer + +Undefined Behavior Sanitizer (UBSan) +==================================== + +You can also build Zephyr with the `Undefined Behavior Sanitizer`_. To do this, set +:kconfig:option:`CONFIG_UBSAN`, for example, in the application project file, or in the +``west build`` or ``cmake`` command line invocation. + +.. _Undefined Behavior Sanitizer: + https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html + +Coverage reports +================ + +See +:ref:`coverage reports using the POSIX architecture`. -You can run, debug, build it with sanitizers or with coverage just like with -:ref:`native_posix `. -Please check :ref:`native_posix's how to` for more info. + +.. _native_sim32_64: 32 and 64bit versions ********************* -Just like native_posix, native_sim comes with two targets: A 32 bit and 64 bit version. +native_sim comes with two targets: A 32 bit and 64 bit version. The 32 bit version, ``native_sim``, is the default target, which will compile your code for the ILP32 ABI (i386 in a x86 or x86_64 system) where pointers and longs are 32 bits. @@ -70,38 +167,419 @@ You can use this target if you cannot compile or run 32 bit binaries. C library choice **************** -Unlike native_posix, native_sim may be compiled with a choice of C libraries. +native_sim may be compiled with a choice of C libraries. By default it will be compiled with the host C library (:kconfig:option:`CONFIG_EXTERNAL_LIBC`), but you can also select to build it with :kconfig:option:`CONFIG_MINIMAL_LIBC` or with :kconfig:option:`CONFIG_PICOLIBC`. +If you select some feature which are not compatible with the host C library, +:ref:`Picolibc ` will be selected by default instead. -When building with either :ref:`MINIMAL` or :ref:`PICO` libC +When building with either :ref:`minimal ` or :ref:`Picolibc` you will build your code in a more similar way as when building for the embedded target, you will be able to test your code interacting with that C library, and there will be no conflicts with the :ref:`POSIX OS abstraction` shim, but, accessing the host for test purposes from your embedded code will be more difficult, and you will have a limited choice of -:ref:`drivers and backends to chose from`. +:ref:`drivers and backends to chose from`. + +Rationale for this port and comparison with other options +********************************************************* + +The native_sim board shares the overall +:ref:`intent of the POSIX architecture`, +while being a HW agnostic test platform which in some cases utilizes the host +OS peripherals. +It does not intend to model any particular HW, and as such can only be used +to develop and test application code which is far decoupled from the HW. + +For developing and testing SW which requires specific HW, while retaining the +benefits of the POSIX architecture other solutions like the +:ref:`bsim boards` +should be considered. + +Check the :ref:`POSIX architecture comparison ` +with other development and test options for more insights. + +.. _native_sim_architecture: Architecture ************ -:ref:`native_posix's architecture description` as well as the -:ref:`POSIX architecture description` are directly -applicable to native_sim. +This board is based on the POSIX architecture port of Zephyr and shares +:ref:`its basic architecture` regarding threading +and CPU/HW scheduling. -If you are interested on the inner workigns of the native simulator itself, you can check +If you are interested on the inner workings of the native simulator itself, you can check `its documentation `_. +This board does not try to emulate any particular embedded CPU or SOC. +The code is compiled natively for the host system (typically x86). + +About time in native_sim +======================== + +Normally simulated time runs fully decoupled from the real host time +and as fast as the host compute power would allow. +This is desirable when running in a debugger or testing in batch, but not if +interacting with external interfaces based on the real host time. + +The Zephyr kernel is only aware of the simulated time as provided by the +HW models. Therefore any normal Zephyr thread will also know only about +simulated time. + +The only link between the simulated time and the real/host time, if any, +is created by the clock and timer model. + +This model can be configured to slow down the execution of native_sim to +real time. +You can do this with the ``--rt`` and ``--no-rt`` options from the command line. +The default behavior is set with +:kconfig:option:`CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME`. +Note that all this model does is wait before raising the +next system tick interrupt until the corresponding real/host time. +If, for some reason, native_sim runs slower than real time, all this +model can do is "catch up" as soon as possible by not delaying the +following ticks. +So if the host load is too high, or you are running in a debugger, you will +see simulated time lagging behind the real host time. +This solution ensures that normal runs are still deterministic while +providing an illusion of real timeness to the observer. + +When locked to real time, simulated time can also be set to run faster or +slower than real time. +This can be controlled with the ``--rt-ratio=`` and ``-rt-drift=`` +command line options. Note that both of these options control the same +underlying mechanism, and that ``drift`` is by definition equal to +``ratio - 1``. +It is also possible to adjust this clock speed on the fly with +:c:func:`native_rtc_adjust_clock()`. + +In this way if, for example, ``--rt-ratio=2`` is given, the simulated time +will advance at twice the real time speed. +Similarly if ``--rt-drift=-100e-6`` is given, the simulated time will progress +100ppm slower than real time. +Note that these 2 options have no meaning when running in non real-time +mode. + +How simulated time and real time relate to each other +----------------------------------------------------- + +Simulated time (``st``) can be calculated from real time (``rt``) as + +``st = (rt - last_rt) * ratio + last_st`` + +And vice-versa: + +``rt = (st - last_st) / ratio + last_rt`` + +Where ``last_rt`` and ``last_st`` are respectively the real time and the +simulated time when the last clock ratio adjustment took place. + +All times are kept in microseconds. + .. _native_sim_peripherals: -Peripherals, subsystems backends and host based flash access -************************************************************ +Peripherals +*********** + +The following peripherals are currently provided with this board: + +**Interrupt controller**: + A simple yet generic interrupt controller is provided. It can nest interrupts + and provides interrupt priorities. Interrupts can be individually masked or + unmasked. SW interrupts are also supported. + +**Clock, timer and system tick model** + This model provides the system tick timer. By default + :kconfig:option:`CONFIG_SYS_CLOCK_TICKS_PER_SEC` configures it to tick every 10ms. + + Please refer to the section `About time in native_sim`_ for more + information. + +**UART/Serial** + Two optional native UART drivers are available: + + **PTTY driver (UART_NATIVE_POSIX)** + With this driver, one or two Zephyr UART devices can be created. These + can be connected to the Linux process stdin/stdout or a newly created + pseudo-tty. For more information refer to the section `PTTY UART`_. + + **TTY driver (UART_NATIVE_TTY)** + An UART driver for interacting with host-attached serial port devices + (eg. USB to UART dongles). For more information refer to the section + `TTY UART`_. + +**Real time clock** + The real time clock model provides a model of a constantly powered clock. + By default this is initialized to the host time at boot. + + This RTC can also be set to start from time 0 with the ``--rtc-reset`` command + line option. + + It is possible to offset the RTC clock value at boot with the + ``--rtc-offset=`` option, + or to adjust it dynamically with the function :c:func:`native_rtc_offset`. + + After start, this RTC advances with the simulated time, and is therefore + affected by the simulated time speed ratio. + See `About time in native_sim`_ for more information. + + The time can be queried with the functions :c:func:`native_rtc_gettime_us` + and :c:func:`native_rtc_gettime`. Both accept as parameter the clock source: + + - ``RTC_CLOCK_BOOT``: It counts the simulated time passed since boot. + It is not subject to offset adjustments + - ``RTC_CLOCK_REALTIME``: RTC persistent time. It is affected by + offset adjustments. + - ``RTC_CLOCK_PSEUDOHOSTREALTIME``: A version of the real host time, + as if the host was also affected by the clock speed ratio and offset + adjustments performed to the simulated clock and this RTC. Normally + this value will be a couple of hundredths of microseconds ahead of the + simulated time, depending on the host execution speed. + This clock source should be used with care, as depending on the actual + execution speed of native_sim and the host load, + it may return a value considerably ahead of the simulated time. + +**Entropy device**: + An entropy device based on the host :c:func:`random` API. + This device will generate the same sequence of random numbers if initialized + with the same random seed. + You can change this random seed value by using the command line option: + ``--seed=`` where the value specified is a 32-bit integer + such as 97229 (decimal), 0x17BCD (hex), or 0275715 (octal). + +**Ethernet driver**: + A simple TAP based ethernet driver is provided. The driver expects that the + **zeth** network interface already exists in the host system. The **zeth** + network interface can be created by the ``net-setup.sh`` script found in + the `net-tools`_ zephyr project repository. User can communicate with the + Zephyr instance via the **zeth** network interface. Multiple TAP based + network interfaces can be created if needed. The IP address configuration + can be specified for each network interface instance. + + Note that this device can only be used with Linux hosts. + +.. _net-tools: + https://github.com/zephyrproject-rtos/net-tools + + +**Bluetooth controller**: + It's possible to use the host's Bluetooth adapter as a Bluetooth + controller for Zephyr. To do this the HCI device needs to be passed as + a command line option to ``zephyr.exe``. For example, to use ``hci0``, + use ``sudo zephyr.exe --bt-dev=hci0``. Using the device requires root + privileges (or the CAP_NET_ADMIN POSIX capability, to be exact) so + ``zephyr.exe`` needs to be run through ``sudo``. The chosen HCI device + must be powered down and support Bluetooth Low Energy (i.e. support the + Bluetooth specification version 4.0 or greater). + + Another possibility is to use a HCI TCP server which acts as a + :ref:`virtual Bluetooth controller` over TCP. + To connect to a HCI TCP server its IP address and port number must + be specified. For example, to connect to a HCI TCP server with IP + address 127.0.0.0 and port number 1020 use ``zephyr.exe --bt-dev=127.0.0.1:1020``. + This alternative option is mainly aimed for testing Bluetooth connectivity over + a virtual Bluetooth controller that does not depend on the Linux Bluetooth + stack and its HCI interface. + +**USB controller**: + It's possible to use the Virtual USB controller working over USB/IP + protocol. More information can be found in + :ref:`Testing USB over USP/IP in native_posix `. + +**Display driver**: + A display driver is provided that creates a window on the host machine to + render display content. + + This driver requires a 32-bit version of the `SDL2`_ library on the host + machine and ``pkg-config`` settings to correctly pickup the SDL2 install path + and compiler flags. + + On a Ubuntu 22.04 host system, for example, install the ``pkg-config`` and + ``libsdl2-dev:i386`` packages, and configure the pkg-config search path with + these commands:: + + $ sudo apt-get install pkg-config libsdl2-dev:i386 + $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig + +.. _SDL2: + https://www.libsdl.org/download-2.0.php + +**Flash driver**: + A flash driver is provided that accesses all flash data through a binary file + on the host file system. The behavior of the flash device can be configured + through the native_sim board devicetree or Kconfig settings under + :kconfig:option:`CONFIG_FLASH_SIMULATOR`. + + By default the binary data is located in the file *flash.bin* in the current + working directory. The location of this file can be changed through the + command line parameter *--flash*. The flash data will be stored in raw format + and the file will be truncated to match the size specified in the devicetree + configuration. In case the file does not exists the driver will take care of + creating the file, else the existing file is used. + + The flash content can be accessed from the host system, as explained in the + `Host based flash access`_ section. + +PTTY UART +********* + +This driver can be configured with :kconfig:option:`CONFIG_UART_NATIVE_POSIX` +to instantiate up to two UARTs. By default only one UART is enabled. +With :kconfig:option:`CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE` +you can enable the second one. + +For the first UART, it can link it to a new +pseudoterminal (i.e. ``/dev/pts``), or map the UART input and +output to the executable's ``stdin`` and ``stdout``. +This is chosen by selecting either +:kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` or +:kconfig:option:`CONFIG_NATIVE_UART_0_ON_STDINOUT` +For interactive use with the :ref:`shell_api`, choose the first (OWN_PTY) option. +The second (STDINOUT) option can be used with the shell for automated +testing, such as when piping other processes' output to control it. +This is because the shell subsystem expects access to a raw terminal, +which (by default) a normal Linux terminal is not. + +When :kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` is chosen, the name of the +newly created UART pseudo-terminal will be displayed in the console. +If you want to interact with it manually, you should attach a terminal emulator +to it. This can be done, for example with the command:: + + $ xterm -e screen /dev/ & + +where ``/dev/`` should be replaced with the actual TTY device. + +You may also chose to automatically attach a terminal emulator to the first UART +by passing the command line option ``-attach_uart`` to the executable. +The command used for attaching to the new shell can be set with the command line +option ``-attach_uart_cmd=<"cmd">``. Where the default command is given by +:kconfig:option:`CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD`. +Note that the default command assumes both ``xterm`` and ``screen`` are +installed in the system. + +This driver only supports poll mode. Interrupt and async mode are not supported. +Neither runtime configuration or line control are supported. + +.. _native_tty_uart: + +TTY UART +******** + +With this driver an application can use the polling UART API (``uart_poll_out``, +``uart_poll_in``) to write and read characters to and from a connected serial +port device. + +This driver is automatically enabled when a devicetree contains a node +with ``"zephyr,native-tty-uart"`` compatible property and ``okay`` status, such +as one below:: + + uart { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + serial-port = "/dev/ttyUSB0"; + current-speed = <115200>; + }; + +Interaction with serial ports can be configured in several different ways: + +* The default serial port and baud rate can be set via the device tree + properties ``serial-port`` and ``current-speed`` respectively. The + ``serial-port`` property is optional. +* Serial port and baud rate can also be set via command line options ``X_port`` + and ``X_baud`` respectively, where ``X`` is a name of a node. Command line + options override values from the devicetree. +* The rest of the configuration options such as number of data and stop bits, + parity, as well as baud rate can be set at runtime with ``uart_configure``. + +Multiple instances of such uart drivers are supported. + +The :zephyr:code-sample:`uart-native-tty` sample app provides a working example of the +driver. + +This driver only supports poll mode. Interrupt and async mode are not supported. +It has runtime configuration support, but no line control support. + +.. _native_sim_backends: + +Subsystems backends +******************* + +Apart from its own peripherals, the native_sim board also has some dedicated +backends for some of Zephyr's subsystems. These backends are designed to ease +development by integrating more seamlessly with the host operating system: + +**Console backend**: + A console backend which by default is configured to + redirect any :c:func:`printk` write to the native host application's + ``stdout``. + + This driver is selected by default if the `PTTY UART`_ is not compiled in. + Otherwise :kconfig:option:`CONFIG_UART_CONSOLE` will be set to select the UART as + console backend. + +**Logger backend**: + A backend which prints all logger output to the process ``stdout``. + It supports timestamping, which can be enabled with + :kconfig:option:`CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP`; and colored output which can + be enabled with :kconfig:option:`CONFIG_LOG_BACKEND_SHOW_COLOR` and controlled + with the command line options ``--color``, ``--no-color`` and + ``--force-color``. + + In native_sim, by default, the logger is configured with + :kconfig:option:`CONFIG_LOG_MODE_IMMEDIATE`. + + This backend can be selected with :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX` + and is enabled by default unless the PTTY UART is compiled in. + In this later case, by default, the logger is set to output to the + `PTTY UART`_. + +**Tracing**: + A backend/"bottom" for Zephyr's CTF tracing subsystem which writes the tracing + data to a file in the host filesystem. + More information can be found in :ref:`Common Tracing Format ` + +Host based flash access +*********************** + +If a flash device is present, the file system partitions on the flash +device can be exposed through the host file system by enabling +:kconfig:option:`CONFIG_FUSE_FS_ACCESS`. This option enables a FUSE +(File system in User space) layer that maps the Zephyr file system calls to +the required UNIX file system calls, and provides access to the flash file +system partitions with normal operating system commands such as ``cd``, +``ls`` and ``mkdir``. + +By default the partitions are exposed through the directory *flash* in the +current working directory. This directory can be changed via the command line +option *--flash-mount*. As this directory operates as a mount point for FUSE +you have to ensure that it exists before starting the native_sim board. + +On exit, the native_sim board application will take care of unmounting the +directory. In the unfortunate case that the native_sim board application +crashes, you can cleanup the stale mount point by using the program +``fusermount``:: + + $ fusermount -u flash + +Note that this feature requires a 32-bit version of the FUSE library, with a +minimal version of 2.6, on the host system and ``pkg-config`` settings to +correctly pickup the FUSE install path and compiler flags. + +On a Ubuntu 22.04 host system, for example, install the ``pkg-config`` and +``libfuse-dev:i386`` packages, and configure the pkg-config search path with +these commands:: + + $ sudo apt-get install pkg-config libfuse-dev:i386 + $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig + +.. _native_sim_peripherals_c_compat: + +Peripherals and backends C library compatibility +************************************************ -Today, native_sim supports the exact same -:ref:`peripherals and backends as native_posix`, -with the only caveat that some of these are, so far, only available when compiling with the -host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`). +Today, some native_sim peripherals and backends are, so far, only available when compiling with the +host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`): .. csv-table:: Drivers/backends vs libC choice :header: Driver class, driver name, driver kconfig, libC choices diff --git a/boards/posix/nrf_bsim/doc/nrf52_bsim.rst b/boards/posix/nrf_bsim/doc/nrf52_bsim.rst index f8b7cad6628491b..da1212e33679301 100644 --- a/boards/posix/nrf_bsim/doc/nrf52_bsim.rst +++ b/boards/posix/nrf_bsim/doc/nrf52_bsim.rst @@ -182,7 +182,7 @@ Check the :ref:`native simulator C library choice section`, the resulting +Just like with :ref:`native_sim`, the resulting executables are Linux native applications. Therefore they can be debugged or instrumented with the same tools as any other native application, like for example ``gdb`` or ``valgrind``. @@ -191,7 +191,7 @@ The same :ref:`code coverage analysis means from the POSIX arch` are inherited in this board. Similarly, the -:ref:`address and undefined behavior sanitizers can be used as in native_posix`. +:ref:`address and undefined behavior sanitizers can be used as in native_sim`. Note that BabbleSim will run fine if one or several of its components are From c3d863f864d1398a5a6295816aa6d45021087735 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 10:26:46 +0100 Subject: [PATCH 0385/1049] docs: boards posix: Replace reference to native_posix w native_sim Let's replace the references to native_posix with native_sim, Background: during this release native_sim is replacing native_posix as the main host test/development platform. Signed-off-by: Alberto Escolar Piedras --- boards/posix/doc/arch_soc.rst | 8 ++++---- boards/posix/doc/bsim_boards_design.rst | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/boards/posix/doc/arch_soc.rst b/boards/posix/doc/arch_soc.rst index cac21706293c9d4..ff1f947e4834e26 100644 --- a/boards/posix/doc/arch_soc.rst +++ b/boards/posix/doc/arch_soc.rst @@ -65,9 +65,9 @@ This port is designed and tested to run in Linux. The 32 bit version of this port does not directly work in Windows Subsystem for Linux (WSL) because WSL does not support native 32-bit binaries. - You may want to consider WSL2, or, if using native_posix, - you can also just use the native_posix_64 - target: Check :ref:`32 and 64bit versions`. + You may want to consider WSL2, or, if using :ref:`native_sim `, + you can also just use the ``native_sim_64`` + target: Check :ref:`32 and 64bit versions`. Otherwise `with some tinkering `_ it should be possible to make it work. @@ -391,7 +391,7 @@ Busy waits ========== Busy waits work thanks to provided board functionality. -This does not need to be the same for all boards, but both native_posix and the +This does not need to be the same for all boards, but both native_sim and the nrf52_bsim board work similarly thru the combination of a board specific `arch_busy_wait()` and a special fake HW timer (provided by the board). diff --git a/boards/posix/doc/bsim_boards_design.rst b/boards/posix/doc/bsim_boards_design.rst index f69a27a57619aec..bb510f583513948 100644 --- a/boards/posix/doc/bsim_boards_design.rst +++ b/boards/posix/doc/bsim_boards_design.rst @@ -52,7 +52,7 @@ These tests are run in workstation, that is, without using real embedded HW. The intention being to be able to run tests much faster than real time, without the need for real HW, and in a deterministic/reproducible fashion. -Unlike native_posix, bsim boards do not interact directly with any host +Unlike :ref:`native_sim `, bsim boards do not interact directly with any host peripherals, and their execution is independent of the host load, or timing. .. _bsim_boards_tests: @@ -95,13 +95,13 @@ to these boards. an special driver that handles the EDTT communication (its RPC transport) and an embedded application that handles the RPC calls themselves, while the python test scripts provide the test logic. - - Using Zephyr's native_posix board: It also allows integration testing of + - Using Zephyr's :ref:`native_sim ` board: It also allows integration testing of the embedded code, but without any specific HW. In that way, many embedded components which are dependent on the HW would not be suited for testing in that platform. Just like the bsim boards, this Zephyr target board can be used with or without Zephyr's ztest system and twister. - The native_posix board shares the :ref:`POSIX architecture` - with the bsim boards. + The :ref:`native_sim ` board shares the :ref:`POSIX architecture`, + and native simulator runner with the bsim boards. - Zephyr's ztest infrastructure and Zephyr's twister: Based on dedicated embedded test applications build with the code under test. From 85b54358a135eabdd875fb6f84b85705822c09fc Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 11:11:44 +0100 Subject: [PATCH 0386/1049] docs: Introduction: Replace references to native_posix w native_sim Let's replace the references to native_posix with native_sim, in the introduction and beyond the getting started guide. Background: during this release native_sim is replacing native_posix as the main host test/development platform. Signed-off-by: Alberto Escolar Piedras --- doc/develop/beyond-GSG.rst | 20 ++++++++++---------- doc/introduction/index.rst | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/develop/beyond-GSG.rst b/doc/develop/beyond-GSG.rst index 41269c1263446de..1b9aab82644919b 100644 --- a/doc/develop/beyond-GSG.rst +++ b/doc/develop/beyond-GSG.rst @@ -177,7 +177,8 @@ Build and Run an Application You can build, flash, and run Zephyr applications on real hardware using a supported host system. Depending on your operating system, -you can also run it in emulation with QEMU, or as a native POSIX application. +you can also run it in emulation with QEMU, or as a native application with +:ref:`native_sim `. Additional information about building applications can be found in the :ref:`build_an_application` section. @@ -291,22 +292,21 @@ To exit QEMU, type :kbd:`Ctrl-a`, then :kbd:`x`. Use ``qemu_cortex_m3`` to target an emulated Arm Cortex-M3 sample. -.. _gs_posix: +.. _gs_native: -Run a Sample Application natively (POSIX OS) -============================================ +Run a Sample Application natively (Linux) +========================================= -You can compile some samples to run as host processes -on a POSIX OS. This is currently only tested on Linux hosts. See -:ref:`native_posix` for more information. On 64-bit host operating systems, you -need to install a 32-bit C library; see :ref:`native_posix_deps` for details. +You can compile some samples to run as host programs +on Linux. See :ref:`native_sim` for more information. On 64-bit host operating systems, you +need to install a 32-bit C library, or build targeting :ref:`native_sim_64 `. -First, build Hello World for ``native_posix``. +First, build Hello World for ``native_sim``. .. zephyr-app-commands:: :zephyr-app: samples/hello_world :host-os: unix - :board: native_posix + :board: native_sim :goals: build Next, run the application. diff --git a/doc/introduction/index.rst b/doc/introduction/index.rst index 5444694dd21cae6..85968ca456a1032 100644 --- a/doc/introduction/index.rst +++ b/doc/introduction/index.rst @@ -144,8 +144,8 @@ Zephyr offers a large and ever growing number of features including: **Native Linux, macOS, and Windows Development** A command-line CMake build environment runs on popular developer OS - systems. A native POSIX port lets you build and run Zephyr as a native - application on Linux and other OSes, aiding development and testing. + systems. A native port (:ref:`native_sim `) lets you build and run Zephyr as a native + application on Linux, aiding development and testing. **Virtual File System Interface with ext2, FatFs, and LittleFS Support** ext2, LittleFS and FatFS support; FCB (Flash Circular Buffer) for memory constrained @@ -170,9 +170,9 @@ Zephyr offers a large and ever growing number of features including: NVS allows storage of binary blobs, strings, integers, longs, and any combination of these. -**Native POSIX port** - Supports running Zephyr as a Linux application with support for various - subsystems and networking. +**Native port** + :ref:`Native sim ` allows running Zephyr as a Linux application with support + for various subsystems and networking. .. include:: ../../README.rst From 86db69956487275aa078e8a0f1dd5e37f80bdd3b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 14 Nov 2023 12:50:04 +0100 Subject: [PATCH 0387/1049] docs: native_sim: Polish documentation Polish the native_sim documentation a bit. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_posix/doc/index.rst | 2 +- boards/posix/native_sim/doc/index.rst | 87 +++++++++++++++---------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/boards/posix/native_posix/doc/index.rst b/boards/posix/native_posix/doc/index.rst index e096e8c54839f05..61e6c1643278310 100644 --- a/boards/posix/native_posix/doc/index.rst +++ b/boards/posix/native_posix/doc/index.rst @@ -80,7 +80,7 @@ Please check :ref:`native_sim's how to` for more info. 32 and 64bit versions ********************* -Just like :ref:`native_sim`, ``native_posix comes`` with two targets: +Just like :ref:`native_sim`, ``native_posix`` comes with two targets: A 32 bit and 64 bit version. The 32 bit version, ``native_posix``, is the default target, which will compile your code for the ILP32 ABI (i386 in a x86 or x86_64 system) where pointers diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 00c8fa682ba3a47..94eb8d43580503a 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -76,7 +76,9 @@ Run the ``zephyr.exe`` executable as you would any other Linux console applicati This executable accepts several command line options depending on the compilation configuration. You can run it with the ``--help`` command line switch to get a list of -available options:: +available options. + +.. code-block:: console $ ./build/zephyr/zephyr.exe --help @@ -146,7 +148,7 @@ See .. _native_sim32_64: 32 and 64bit versions -********************* +===================== native_sim comes with two targets: A 32 bit and 64 bit version. The 32 bit version, ``native_sim``, is the default target, which will compile @@ -235,6 +237,7 @@ real time. You can do this with the ``--rt`` and ``--no-rt`` options from the command line. The default behavior is set with :kconfig:option:`CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME`. + Note that all this model does is wait before raising the next system tick interrupt until the corresponding real/host time. If, for some reason, native_sim runs slower than real time, all this @@ -266,11 +269,13 @@ How simulated time and real time relate to each other Simulated time (``st``) can be calculated from real time (``rt``) as -``st = (rt - last_rt) * ratio + last_st`` +.. math:: + st = (rt - last\_rt) \times ratio + last\_st And vice-versa: -``rt = (st - last_st) / ratio + last_rt`` +.. math:: + rt = (st - last\_st) / ratio + last\_rt Where ``last_rt`` and ``last_st`` are respectively the real time and the simulated time when the last clock ratio adjustment took place. @@ -284,7 +289,7 @@ Peripherals The following peripherals are currently provided with this board: -**Interrupt controller**: +**Interrupt controller** A simple yet generic interrupt controller is provided. It can nest interrupts and provides interrupt priorities. Interrupts can be individually masked or unmasked. SW interrupts are also supported. @@ -340,15 +345,15 @@ The following peripherals are currently provided with this board: execution speed of native_sim and the host load, it may return a value considerably ahead of the simulated time. -**Entropy device**: +**Entropy device** An entropy device based on the host :c:func:`random` API. This device will generate the same sequence of random numbers if initialized with the same random seed. You can change this random seed value by using the command line option: - ``--seed=`` where the value specified is a 32-bit integer + :samp:`--seed={}` where the value specified is a 32-bit integer such as 97229 (decimal), 0x17BCD (hex), or 0275715 (octal). -**Ethernet driver**: +**Ethernet driver** A simple TAP based ethernet driver is provided. The driver expects that the **zeth** network interface already exists in the host system. The **zeth** network interface can be created by the ``net-setup.sh`` script found in @@ -363,7 +368,7 @@ The following peripherals are currently provided with this board: https://github.com/zephyrproject-rtos/net-tools -**Bluetooth controller**: +**Bluetooth controller** It's possible to use the host's Bluetooth adapter as a Bluetooth controller for Zephyr. To do this the HCI device needs to be passed as a command line option to ``zephyr.exe``. For example, to use ``hci0``, @@ -382,12 +387,12 @@ The following peripherals are currently provided with this board: a virtual Bluetooth controller that does not depend on the Linux Bluetooth stack and its HCI interface. -**USB controller**: +**USB controller** It's possible to use the Virtual USB controller working over USB/IP protocol. More information can be found in :ref:`Testing USB over USP/IP in native_posix `. -**Display driver**: +**Display driver** A display driver is provided that creates a window on the host machine to render display content. @@ -397,23 +402,25 @@ The following peripherals are currently provided with this board: On a Ubuntu 22.04 host system, for example, install the ``pkg-config`` and ``libsdl2-dev:i386`` packages, and configure the pkg-config search path with - these commands:: + these commands: - $ sudo apt-get install pkg-config libsdl2-dev:i386 - $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig + .. code-block:: console + + $ sudo apt-get install pkg-config libsdl2-dev:i386 + $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig .. _SDL2: https://www.libsdl.org/download-2.0.php -**Flash driver**: +**Flash driver** A flash driver is provided that accesses all flash data through a binary file on the host file system. The behavior of the flash device can be configured through the native_sim board devicetree or Kconfig settings under :kconfig:option:`CONFIG_FLASH_SIMULATOR`. - By default the binary data is located in the file *flash.bin* in the current + By default the binary data is located in the file :file:`flash.bin` in the current working directory. The location of this file can be changed through the - command line parameter *--flash*. The flash data will be stored in raw format + command line parameter ``--flash``. The flash data will be stored in raw format and the file will be truncated to match the size specified in the devicetree configuration. In case the file does not exists the driver will take care of creating the file, else the existing file is used. @@ -422,7 +429,7 @@ The following peripherals are currently provided with this board: `Host based flash access`_ section. PTTY UART -********* +========= This driver can be configured with :kconfig:option:`CONFIG_UART_NATIVE_POSIX` to instantiate up to two UARTs. By default only one UART is enabled. @@ -430,7 +437,7 @@ With :kconfig:option:`CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE` you can enable the second one. For the first UART, it can link it to a new -pseudoterminal (i.e. ``/dev/pts``), or map the UART input and +pseudoterminal (i.e. :file:`/dev/pts{}`), or map the UART input and output to the executable's ``stdin`` and ``stdout``. This is chosen by selecting either :kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` or @@ -444,11 +451,13 @@ which (by default) a normal Linux terminal is not. When :kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` is chosen, the name of the newly created UART pseudo-terminal will be displayed in the console. If you want to interact with it manually, you should attach a terminal emulator -to it. This can be done, for example with the command:: +to it. This can be done, for example with the command: + +.. code-block:: console $ xterm -e screen /dev/ & -where ``/dev/`` should be replaced with the actual TTY device. +where :file:`/dev/tty{}` should be replaced with the actual TTY device. You may also chose to automatically attach a terminal emulator to the first UART by passing the command line option ``-attach_uart`` to the executable. @@ -464,7 +473,7 @@ Neither runtime configuration or line control are supported. .. _native_tty_uart: TTY UART -******** +======== With this driver an application can use the polling UART API (``uart_poll_out``, ``uart_poll_in``) to write and read characters to and from a connected serial @@ -472,14 +481,16 @@ port device. This driver is automatically enabled when a devicetree contains a node with ``"zephyr,native-tty-uart"`` compatible property and ``okay`` status, such -as one below:: +as one below. - uart { - status = "okay"; - compatible = "zephyr,native-tty-uart"; - serial-port = "/dev/ttyUSB0"; - current-speed = <115200>; - }; +.. code-block:: dts + + uart { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + serial-port = "/dev/ttyUSB0"; + current-speed = <115200>; + }; Interaction with serial ports can be configured in several different ways: @@ -550,17 +561,19 @@ the required UNIX file system calls, and provides access to the flash file system partitions with normal operating system commands such as ``cd``, ``ls`` and ``mkdir``. -By default the partitions are exposed through the directory *flash* in the +By default the partitions are exposed through the directory :file:`flash/` in the current working directory. This directory can be changed via the command line -option *--flash-mount*. As this directory operates as a mount point for FUSE +option ``--flash-mount``. As this directory operates as a mount point for FUSE you have to ensure that it exists before starting the native_sim board. On exit, the native_sim board application will take care of unmounting the directory. In the unfortunate case that the native_sim board application crashes, you can cleanup the stale mount point by using the program -``fusermount``:: +``fusermount``: - $ fusermount -u flash +.. code-block:: console + + $ fusermount -u flash Note that this feature requires a 32-bit version of the FUSE library, with a minimal version of 2.6, on the host system and ``pkg-config`` settings to @@ -568,10 +581,12 @@ correctly pickup the FUSE install path and compiler flags. On a Ubuntu 22.04 host system, for example, install the ``pkg-config`` and ``libfuse-dev:i386`` packages, and configure the pkg-config search path with -these commands:: +these commands: + +.. code-block:: console - $ sudo apt-get install pkg-config libfuse-dev:i386 - $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig + $ sudo apt-get install pkg-config libfuse-dev:i386 + $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig .. _native_sim_peripherals_c_compat: From 8b6f447ef8e946a582e313b1fb3a32ede206bcd7 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Thu, 12 Oct 2023 17:06:04 +0200 Subject: [PATCH 0388/1049] twister: harness: Fix Console unordered pattern matching for ztest Fix the Twister Console harness unordered pattern matching to treat the ztest as failed when not all of the expected patterns were found in the console output, but the ztest application itself reports 'PROJECT EXECUTION SUCCESSFUL'. Unify debug logging on pattern match for ordered and unordered patterns. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/harness.py | 26 +++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index ef24ef577204d13..312ac943cef695f 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -174,13 +174,16 @@ def configure(self, instance): def handle(self, line): if self.type == "one_line": if self.pattern.search(line): - logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED({self.next_pattern}):'{self.pattern.pattern}'") + logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED:" + f"'{self.pattern.pattern}'") self.next_pattern += 1 self.state = "passed" elif self.type == "multi_line" and self.ordered: if (self.next_pattern < len(self.patterns) and self.patterns[self.next_pattern].search(line)): - logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED({self.next_pattern}):'{self.patterns[self.next_pattern].pattern}'") + logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED(" + f"{self.next_pattern + 1}/{self.patterns_expected}):" + f"'{self.patterns[self.next_pattern].pattern}'") self.next_pattern += 1 if self.next_pattern >= len(self.patterns): self.state = "passed" @@ -189,6 +192,9 @@ def handle(self, line): r = self.regex[i] if pattern.search(line) and not r in self.matches: self.matches[r] = line + logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED(" + f"{len(self.matches)}/{self.patterns_expected}):" + f"'{pattern.pattern}'") if len(self.matches) == len(self.regex): self.state = "passed" else: @@ -218,16 +224,22 @@ def handle(self, line): self.recording.append(csv) self.process_test(line) - # Reset the resulting test state to 'failed' for 'one_line' and - # ordered 'multi_line' patterns when not all of these patterns were + # Reset the resulting test state to 'failed' when not all of the patterns were # found in the output, but just ztest's 'PROJECT EXECUTION SUCCESSFUL'. # It might happen because of the pattern sequence diverged from the # test code, the test platform has console issues, or even some other # test image was executed. - # TODO: Introduce explicit match policy type either to reject - # unexpected console output, or to allow missing patterns. + # TODO: Introduce explicit match policy type to reject + # unexpected console output, allow missing patterns, deny duplicates. if self.state == "passed" and self.ordered and self.next_pattern < self.patterns_expected: - logger.error(f"HARNESS:{self.__class__.__name__}: failed with only {self.next_pattern} matched patterns from expected {self.patterns_expected}") + logger.error(f"HARNESS:{self.__class__.__name__}: failed with" + f" {self.next_pattern} of {self.patterns_expected}" + f" expected ordered patterns.") + self.state = "failed" + if self.state == "passed" and not self.ordered and len(self.matches) < self.patterns_expected: + logger.error(f"HARNESS:{self.__class__.__name__}: failed with" + f" {len(self.matches)} of {self.patterns_expected}" + f" expected unordered patterns.") self.state = "failed" tc = self.instance.get_case_or_create(self.id) From 00d260af96844eb60ef271f00f3493b32d7497c8 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Fri, 13 Oct 2023 20:42:59 +0200 Subject: [PATCH 0389/1049] twister: harness: Check Console harness configuration If Console Harness 'harness_config' properties have no 'regex' patterns or no correct 'type' set, then ConfigurationError exception is raised, handled, and the test instance error is accounted in the summary results. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/harness.py | 18 ++++++++++++++++++ scripts/pylib/twister/twisterlib/runner.py | 11 +++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index 312ac943cef695f..cb3460a88497b28 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -13,6 +13,7 @@ import threading import time +from twisterlib.error import ConfigurationError from twisterlib.environment import ZEPHYR_BASE, PYTEST_PLUGIN_INSTALLED from twisterlib.handlers import Handler, terminate_process, SUPPORTED_SIMS_IN_PYTEST from twisterlib.testinstance import TestInstance @@ -162,6 +163,14 @@ class Console(Harness): def configure(self, instance): super(Console, self).configure(instance) + if self.regex is None or len(self.regex) == 0: + self.state = "failed" + tc = self.instance.set_case_status_by_name( + self.id, + "failed", + f"HARNESS:{self.__class__.__name__}:no regex patterns configured." + ) + raise ConfigurationError(self.instance.name, tc.reason) if self.type == "one_line": self.pattern = re.compile(self.regex[0]) self.patterns_expected = 1 @@ -170,6 +179,15 @@ def configure(self, instance): for r in self.regex: self.patterns.append(re.compile(r)) self.patterns_expected = len(self.patterns) + else: + self.state = "failed" + tc = self.instance.set_case_status_by_name( + self.id, + "failed", + f"HARNESS:{self.__class__.__name__}:incorrect type={self.type}" + ) + raise ConfigurationError(self.instance.name, tc.reason) + # def handle(self, line): if self.type == "one_line": diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index 2e9c31bb715fe3d..3471f6bf702d3d9 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -25,7 +25,7 @@ from domains import Domains from twisterlib.cmakecache import CMakeCache from twisterlib.environment import canonical_zephyr_base -from twisterlib.error import BuildError +from twisterlib.error import BuildError, ConfigurationError import elftools from elftools.elf.elffile import ELFFile @@ -1069,7 +1069,14 @@ def run(self): instance.handler.extra_test_args = self.options.extra_test_args harness = HarnessImporter.get_harness(instance.testsuite.harness.capitalize()) - harness.configure(instance) + try: + harness.configure(instance) + except ConfigurationError as error: + instance.status = "error" + instance.reason = str(error) + logger.error(instance.reason) + return + # if isinstance(harness, Pytest): harness.pytest_run(instance.handler.get_test_timeout()) else: From 7d0d3f83cbc53c8e791afb4141fd62931fed7683 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Fri, 13 Oct 2023 20:54:47 +0200 Subject: [PATCH 0390/1049] twister: harness: Fix TestCase id at Console for Ztest Implement a workaround for Console harness to compose TestCase identifier correctly when a Ztest suite with a single testcase uses this harness type. Normally, a Ztest suite should use the Ztest Twister harness. Without this workaround each Ztest TestCase result on Console is duplicated (and written into twister.json) with its 'identifier' attribute set to TestSuite id only, no TestCase suffix added; the resulting entry with the full TestCase id is also stored, but its values are empty with defaults. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/harness.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index cb3460a88497b28..052def7162a812b 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -161,12 +161,25 @@ def run_robot_test(self, command, handler): class Console(Harness): + def get_testcase_name(self): + ''' + Get current TestCase name. + + Console Harness id has only TestSuite id without TestCase name suffix. + Only the first TestCase name might be taken if available when a Ztest with + a single test case is configured to use this harness type for simplified + output parsing instead of the Ztest harness as Ztest suite should do. + ''' + if self.instance and len(self.instance.testcases) == 1: + return self.instance.testcases[0].name + return self.id + def configure(self, instance): super(Console, self).configure(instance) if self.regex is None or len(self.regex) == 0: self.state = "failed" tc = self.instance.set_case_status_by_name( - self.id, + self.get_testcase_name(), "failed", f"HARNESS:{self.__class__.__name__}:no regex patterns configured." ) @@ -182,7 +195,7 @@ def configure(self, instance): else: self.state = "failed" tc = self.instance.set_case_status_by_name( - self.id, + self.get_testcase_name(), "failed", f"HARNESS:{self.__class__.__name__}:incorrect type={self.type}" ) @@ -260,7 +273,7 @@ def handle(self, line): f" expected unordered patterns.") self.state = "failed" - tc = self.instance.get_case_or_create(self.id) + tc = self.instance.get_case_or_create(self.get_testcase_name()) if self.state == "passed": tc.status = "passed" else: From d6a3fd7cf00656a3e8b62f4e6968736820a00cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 14 Nov 2023 12:36:08 +0100 Subject: [PATCH 0391/1049] shell: uart: Add missing casting of the data pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixing compilation failure due to treating void pointer as uint8_t array. Added missing casting. Signed-off-by: Krzysztof Chruściński --- subsys/shell/backends/shell_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/shell/backends/shell_uart.c b/subsys/shell/backends/shell_uart.c index f64438c0b5986ac..b06cc4a09b8e242 100644 --- a/subsys/shell/backends/shell_uart.c +++ b/subsys/shell/backends/shell_uart.c @@ -504,7 +504,7 @@ static int async_read(struct shell_uart_async *sh_uart, for (size_t i = 0; i < blen; i++) { if (smp_shell_rx_bytes(smp, &buf[i], 1) == 0) { - data[sh_cnt++] = buf[i]; + ((uint8_t *)data)[sh_cnt++] = buf[i]; } } #else From 6d2e3b59a5d1ae0d6ca6e94ee95dc68459b5fea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 14 Nov 2023 12:39:28 +0100 Subject: [PATCH 0392/1049] mgmt: mcumgr: smp_shell: Change the way shell uart device is fetched MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SMP shell was looking into internal shell uart structures to get uart device. This structures are now internal to the shell and cannot be used. Using device tree chosen instead. Signed-off-by: Krzysztof Chruściński --- subsys/mgmt/mcumgr/transport/src/smp_shell.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/subsys/mgmt/mcumgr/transport/src/smp_shell.c b/subsys/mgmt/mcumgr/transport/src/smp_shell.c index c30874070bac02b..fc04bcd75c42ea4 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_shell.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_shell.c @@ -213,13 +213,11 @@ static uint16_t smp_shell_get_mtu(const struct net_buf *nb) static int smp_shell_tx_raw(const void *data, int len) { - const struct shell *const sh = shell_backend_uart_get_ptr(); - const struct shell_uart *const su = sh->iface->ctx; - const struct shell_uart_ctrl_blk *const scb = su->ctrl_blk; + static const struct device *const sh_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart)); const uint8_t *out = data; while ((out != NULL) && (len != 0)) { - uart_poll_out(scb->dev, *out); + uart_poll_out(sh_dev, *out); ++out; --len; } From e6e6515972d56b30c71f2379838724fc39d77ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 14 Nov 2023 13:10:37 +0100 Subject: [PATCH 0393/1049] shell: uart: Rework Kconfig dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When UART asynchronous API support was added to shell it was set up to be the default one and was turning on asynchronous API if it was supported. However, it may lead to complation failures if device requires additional setup for asynchronous UART (e.g DMA in device tree). Becuase of that, it is reverted back to use interrupt driven API and use asynchronous API if it is already enabled in the application. Signed-off-by: Krzysztof Chruściński --- subsys/shell/backends/Kconfig.backends | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/shell/backends/Kconfig.backends b/subsys/shell/backends/Kconfig.backends index 7c81030cb20083c..e4e826b031681d9 100644 --- a/subsys/shell/backends/Kconfig.backends +++ b/subsys/shell/backends/Kconfig.backends @@ -44,12 +44,13 @@ config SHELL_PROMPT_UART config SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN bool "Interrupt driven" + default y depends on SERIAL_SUPPORT_INTERRUPT choice SHELL_BACKEND_SERIAL_API prompt "Mode" - default SHELL_BACKEND_SERIAL_API_ASYNC if SERIAL_SUPPORT_ASYNC - default SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN if SERIAL_SUPPORT_INTERRUPT + default SHELL_BACKEND_SERIAL_API_ASYNC if UART_ASYNC_API + default SHELL_BACKEND_SERIAL_API_INTERRUPT_DRIVEN if SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN default SHELL_BACKEND_SERIAL_API_POLLING config SHELL_BACKEND_SERIAL_API_POLLING @@ -65,7 +66,6 @@ config SHELL_BACKEND_SERIAL_API_ASYNC bool "Asynchronous" depends on SERIAL_SUPPORT_ASYNC select UART_ASYNC_RX_HELPER - select UART_ASYNC_API endchoice From 2171f8b7a1770f5818fce0083175c8360004672c Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 14 Nov 2023 14:34:45 +0000 Subject: [PATCH 0394/1049] ci: compliance: only run sorted check on text files The sorted check code crashes on binary files. Add a check on file type and only process text ones. Signed-off-by: Fabio Baltieri --- scripts/ci/check_compliance.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 8779fddda6686b7..0a2da6bc9cab0a3 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -1177,6 +1177,11 @@ class KeepSorted(ComplianceTest): MARKER = "zephyr-keep-sorted" def check_file(self, file, fp): + mime_type = magic.from_file(file, mime=True) + + if not mime_type.startswith("text/"): + return + lines = [] in_block = False From a0b746ed74f373192dc524333b8a496f7d3dae99 Mon Sep 17 00:00:00 2001 From: Thien Nguyen Date: Mon, 2 Oct 2023 15:10:08 +0200 Subject: [PATCH 0395/1049] doc: drivers: deprecate driver init levels Remove deprecated driver initialization levels in the docs. Signed-off-by: Thien Nguyen --- doc/kernel/drivers/index.rst | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/doc/kernel/drivers/index.rst b/doc/kernel/drivers/index.rst index 3d3c1715b9fb05b..51b31de006f72c8 100644 --- a/doc/kernel/drivers/index.rst +++ b/doc/kernel/drivers/index.rst @@ -343,13 +343,6 @@ allow the user to specify at what time during the boot sequence the init function will be executed. Any driver will specify one of four initialization levels: -``EARLY`` - Used very early in the boot process, right after entering the C domain - (``z_cstart()``). This can be used in architectures and SoCs that extend - or implement architecture code and use drivers or system services that - have to be initialized before the Kernel calls any architecture specific - initialization code. - ``PRE_KERNEL_1`` Used for devices that have no dependencies, such as those that rely solely on hardware present in the processor/SOC. These devices cannot @@ -368,12 +361,6 @@ initialization levels: Used for devices that require kernel services during configuration. Init functions at this level run in context of the kernel main task. -``APPLICATION`` - Used for application components (i.e. non-kernel components) that need - automatic configuration. These devices can use all services provided by - the kernel during configuration. Init functions at this level run on - the kernel main task. - Within each initialization level you may specify a priority level, relative to other devices in the same initialization level. The priority level is specified as an integer value in the range 0 to 99; lower values indicate earlier From 1b4a647950da1422e7add603ee65a5b319b0a09b Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 14 Nov 2023 11:12:06 +0800 Subject: [PATCH 0396/1049] logging: backend: uart: append index conditionally for compatibility Updated the `LBU_DEFINE` so that the index is appended only when given to improve backward compatibility. When it is depending on the `zephyr,console` node, the backend is defined as `log_backend_uart`. When it is depending on the new `zephyr,log-uart` node, the backend is defined as `log_backend_uart0`, `log_backend_uart1`, and so on. Updated the names of the internal variables to follow the same naming convention. Signed-off-by: Yong Cong Sin --- subsys/logging/backends/log_backend_uart.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/subsys/logging/backends/log_backend_uart.c b/subsys/logging/backends/log_backend_uart.c index 7c58ea1774e444b..fbfdcc365a6bfb4 100644 --- a/subsys/logging/backends/log_backend_uart.c +++ b/subsys/logging/backends/log_backend_uart.c @@ -227,28 +227,28 @@ const struct log_backend_api log_backend_uart_api = { .format_set = format_set, }; -#define LBU_DEFINE(node_id, idx) \ - static uint8_t lbu_buffer_##idx[CONFIG_LOG_BACKEND_UART_BUFFER_SIZE]; \ - LOG_OUTPUT_DEFINE(lbu_output_##idx, char_out, lbu_buffer_##idx, \ +#define LBU_DEFINE(node_id, ...) \ + static uint8_t lbu_buffer##__VA_ARGS__[CONFIG_LOG_BACKEND_UART_BUFFER_SIZE]; \ + LOG_OUTPUT_DEFINE(lbu_output##__VA_ARGS__, char_out, lbu_buffer##__VA_ARGS__, \ CONFIG_LOG_BACKEND_UART_BUFFER_SIZE); \ \ - static struct lbu_data lbu_data_##idx = { \ + static struct lbu_data lbu_data##__VA_ARGS__ = { \ .log_format_current = CONFIG_LOG_BACKEND_UART_OUTPUT_DEFAULT, \ }; \ \ - static const struct lbu_cb_ctx lbu_cb_ctx_##idx = { \ - .output = &lbu_output_##idx, \ + static const struct lbu_cb_ctx lbu_cb_ctx##__VA_ARGS__ = { \ + .output = &lbu_output##__VA_ARGS__, \ .device = DEVICE_DT_GET(node_id), \ - .data = &lbu_data_##idx, \ + .data = &lbu_data##__VA_ARGS__, \ }; \ \ - LOG_BACKEND_DEFINE(log_backend_uart##idx, log_backend_uart_api, \ + LOG_BACKEND_DEFINE(log_backend_uart##__VA_ARGS__, log_backend_uart_api, \ IS_ENABLED(CONFIG_LOG_BACKEND_UART_AUTOSTART), \ - (void *)&lbu_cb_ctx_##idx); + (void *)&lbu_cb_ctx##__VA_ARGS__); #if DT_HAS_CHOSEN(zephyr_log_uart) #define LBU_PHA_FN(node_id, prop, idx) LBU_DEFINE(DT_PHANDLE_BY_IDX(node_id, prop, idx), idx) DT_FOREACH_PROP_ELEM_SEP(DT_CHOSEN(zephyr_log_uart), uarts, LBU_PHA_FN, ()); #else -LBU_DEFINE(DT_CHOSEN(zephyr_console), 0); +LBU_DEFINE(DT_CHOSEN(zephyr_console)); #endif From f5a27bcfe3ea37c391f349c8500f2c05f2d57a54 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 14 Nov 2023 13:18:22 +0800 Subject: [PATCH 0397/1049] tests: logging: uart: increase test coverage The test should work on any boards with UART console, so increase the test coverage by adding `CONFIG_UART_CONSOLE` filter and using `qemu_x86` as `integration_platforms` instead of `platform_allow`. Signed-off-by: Yong Cong Sin --- tests/subsys/logging/log_backend_uart/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/subsys/logging/log_backend_uart/testcase.yaml b/tests/subsys/logging/log_backend_uart/testcase.yaml index 70eb49920f15f70..05a4626ba628569 100644 --- a/tests/subsys/logging/log_backend_uart/testcase.yaml +++ b/tests/subsys/logging/log_backend_uart/testcase.yaml @@ -6,7 +6,9 @@ common: - logging - backend - uart - platform_allow: qemu_x86 + filter: CONFIG_UART_CONSOLE + integration_platforms: + - qemu_x86 tests: logging.backend.uart.single: extra_args: DTC_OVERLAY_FILE="./single.overlay" From 2049aa8d16a891cbb2684d28599a0639734e4307 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 14 Nov 2023 14:21:35 +0800 Subject: [PATCH 0398/1049] logging: backend: uart: variable shouldn't have the same name as struct Rename the `device` variable in the `struct lbu_cb_ctx` to `uart_dev`, as it is a convention in Zephyr to not have the struct variable name after the struct. Signed-off-by: Yong Cong Sin --- subsys/logging/backends/log_backend_uart.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/logging/backends/log_backend_uart.c b/subsys/logging/backends/log_backend_uart.c index fbfdcc365a6bfb4..869ba869e750fac 100644 --- a/subsys/logging/backends/log_backend_uart.c +++ b/subsys/logging/backends/log_backend_uart.c @@ -28,7 +28,7 @@ struct lbu_data { struct lbu_cb_ctx { const struct log_output *output; - const struct device *device; + const struct device *uart_dev; struct lbu_data *data; }; @@ -78,7 +78,7 @@ static int char_out(uint8_t *data, size_t length, void *ctx) int err; const struct lbu_cb_ctx *cb_ctx = ctx; struct lbu_data *lb_data = cb_ctx->data; - const struct device *uart_dev = cb_ctx->device; + const struct device *uart_dev = cb_ctx->uart_dev; if (pm_device_runtime_is_enabled(uart_dev) && !k_is_in_isr()) { if (pm_device_runtime_get(uart_dev) < 0) { @@ -142,7 +142,7 @@ static int format_set(const struct log_backend *const backend, uint32_t log_type static void log_backend_uart_init(struct log_backend const *const backend) { const struct lbu_cb_ctx *ctx = backend->cb->ctx; - const struct device *uart_dev = ctx->device; + const struct device *uart_dev = ctx->uart_dev; struct lbu_data *data = ctx->data; __ASSERT_NO_MSG(device_is_ready(uart_dev)); @@ -180,7 +180,7 @@ static void panic(struct log_backend const *const backend) { const struct lbu_cb_ctx *ctx = backend->cb->ctx; struct lbu_data *data = ctx->data; - const struct device *uart_dev = ctx->device; + const struct device *uart_dev = ctx->uart_dev; /* Ensure that the UART device is in active mode */ #if defined(CONFIG_PM_DEVICE_RUNTIME) @@ -238,7 +238,7 @@ const struct log_backend_api log_backend_uart_api = { \ static const struct lbu_cb_ctx lbu_cb_ctx##__VA_ARGS__ = { \ .output = &lbu_output##__VA_ARGS__, \ - .device = DEVICE_DT_GET(node_id), \ + .uart_dev = DEVICE_DT_GET(node_id), \ .data = &lbu_data##__VA_ARGS__, \ }; \ \ From aa71ed4a1f556c03c4b1f5a8ffd1c8b0685881d1 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 14 Nov 2023 14:36:50 +0800 Subject: [PATCH 0399/1049] logging: backend: uart: compile the `uart_dev` pointer conditionally Compile the `uart_dev` pointer only when necessary (when `zephyr,log-uart` is used), this saves 4 bytes in 32-bit systems and 8 bytes in 64-bit systems. Signed-off-by: Yong Cong Sin --- subsys/logging/backends/log_backend_uart.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/subsys/logging/backends/log_backend_uart.c b/subsys/logging/backends/log_backend_uart.c index 869ba869e750fac..46fa12b92e1d060 100644 --- a/subsys/logging/backends/log_backend_uart.c +++ b/subsys/logging/backends/log_backend_uart.c @@ -28,10 +28,16 @@ struct lbu_data { struct lbu_cb_ctx { const struct log_output *output; +#if DT_HAS_CHOSEN(zephyr_log_uart) const struct device *uart_dev; +#endif struct lbu_data *data; }; +#define LBU_UART_DEV(ctx) \ + COND_CODE_1(DT_HAS_CHOSEN(zephyr_log_uart), (ctx->uart_dev), \ + (DEVICE_DT_GET(DT_CHOSEN(zephyr_console)))) + /* Fixed size to avoid auto-added trailing '\0'. * Used if CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX. */ @@ -78,7 +84,7 @@ static int char_out(uint8_t *data, size_t length, void *ctx) int err; const struct lbu_cb_ctx *cb_ctx = ctx; struct lbu_data *lb_data = cb_ctx->data; - const struct device *uart_dev = cb_ctx->uart_dev; + const struct device *uart_dev = LBU_UART_DEV(cb_ctx); if (pm_device_runtime_is_enabled(uart_dev) && !k_is_in_isr()) { if (pm_device_runtime_get(uart_dev) < 0) { @@ -142,7 +148,7 @@ static int format_set(const struct log_backend *const backend, uint32_t log_type static void log_backend_uart_init(struct log_backend const *const backend) { const struct lbu_cb_ctx *ctx = backend->cb->ctx; - const struct device *uart_dev = ctx->uart_dev; + const struct device *uart_dev = LBU_UART_DEV(ctx); struct lbu_data *data = ctx->data; __ASSERT_NO_MSG(device_is_ready(uart_dev)); @@ -180,7 +186,7 @@ static void panic(struct log_backend const *const backend) { const struct lbu_cb_ctx *ctx = backend->cb->ctx; struct lbu_data *data = ctx->data; - const struct device *uart_dev = ctx->uart_dev; + const struct device *uart_dev = LBU_UART_DEV(ctx); /* Ensure that the UART device is in active mode */ #if defined(CONFIG_PM_DEVICE_RUNTIME) @@ -238,7 +244,8 @@ const struct log_backend_api log_backend_uart_api = { \ static const struct lbu_cb_ctx lbu_cb_ctx##__VA_ARGS__ = { \ .output = &lbu_output##__VA_ARGS__, \ - .uart_dev = DEVICE_DT_GET(node_id), \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), (), \ + (.uart_dev = DEVICE_DT_GET(node_id),)) \ .data = &lbu_data##__VA_ARGS__, \ }; \ \ From 56f73bde0fb086fae38cfb5afb2f2500a340b39b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 14 Nov 2023 22:01:15 +0000 Subject: [PATCH 0400/1049] ci: testplan: fix mcumgr path fix path for mcumgr in tags.yaml, we were skipping tests due to wrong path. Signed-off-by: Anas Nashif --- scripts/ci/tags.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/tags.yaml b/scripts/ci/tags.yaml index b9152b10d680dc8..f66745fb208fdf2 100644 --- a/scripts/ci/tags.yaml +++ b/scripts/ci/tags.yaml @@ -72,7 +72,7 @@ cmsis_dsp: mcumgr: files: - - subsys/mcumgr/ + - subsys/mgmt/mcumgr/ - tests/subsys/mgmt/mcumgr/ - samples/subsys/mgmt/mcumgr/ - include/zephyr/mgmt/mcumgr/ From 1200fce75c6396fe6138659e802f92d43365259c Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Mon, 13 Nov 2023 14:28:07 -0800 Subject: [PATCH 0401/1049] drivers: i2s: mcux_flexcomm: Change LOG_INF to LOG_DBG in init Reduce log verboseness during init. Signed-off-by: Mike J. Chen --- drivers/i2s/i2s_mcux_flexcomm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2s/i2s_mcux_flexcomm.c b/drivers/i2s/i2s_mcux_flexcomm.c index d1dda99a5f2f4a4..4155bd24b62b8c8 100644 --- a/drivers/i2s/i2s_mcux_flexcomm.c +++ b/drivers/i2s/i2s_mcux_flexcomm.c @@ -901,7 +901,7 @@ static int i2s_mcux_init(const struct device *dev) data->tx.state = I2S_STATE_NOT_READY; data->rx.state = I2S_STATE_NOT_READY; - LOG_INF("Device %s inited", dev->name); + LOG_DBG("Device %s inited", dev->name); return 0; } From 5fee1b17d5deef03bd1064215280da69603a91ef Mon Sep 17 00:00:00 2001 From: MD Peace Date: Wed, 15 Nov 2023 11:52:09 +1100 Subject: [PATCH 0402/1049] drivers: gnss: Fix typo in __ASSERT statement str is being checking the __ASSERT where nano should be being checked Signed-off-by: MD Peace --- drivers/gnss/gnss_parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gnss/gnss_parse.c b/drivers/gnss/gnss_parse.c index 5cde6a630a90adc..29808dd74f22af5 100644 --- a/drivers/gnss/gnss_parse.c +++ b/drivers/gnss/gnss_parse.c @@ -26,7 +26,7 @@ int gnss_parse_dec_to_nano(const char *str, int64_t *nano) int64_t increment; __ASSERT(str != NULL, "str argument must be provided"); - __ASSERT(str != NULL, "nano argument must be provided"); + __ASSERT(nano != NULL, "nano argument must be provided"); /* Find decimal */ while (str[pos] != '\0') { From 5c6402e76b5b775700b4ff6d75198e1a51a68623 Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Tue, 14 Nov 2023 15:11:27 +0100 Subject: [PATCH 0403/1049] drivers: ieee802154: add `IEEE802154_RX_ON_WHEN_IDLE` capability Introduce `IEEE802154_RX_ON_WHEN_IDLE` capability. Signed-off-by: Eduardo Montoya --- include/zephyr/net/ieee802154_radio.h | 37 ++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 71519dfe839fab4..59608fac391ba70 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -515,13 +515,16 @@ enum ieee802154_hw_caps { /** TX security supported (key management, encryption and authentication) */ IEEE802154_HW_TX_SEC = BIT(11), + /** RxOnWhenIdle handling supported */ + IEEE802154_RX_ON_WHEN_IDLE = BIT(12), + /* Note: Update also IEEE802154_HW_CAPS_BITS_COMMON_COUNT when changing * the ieee802154_hw_caps type. */ }; /** @brief Number of bits used by ieee802154_hw_caps type. */ -#define IEEE802154_HW_CAPS_BITS_COMMON_COUNT (12) +#define IEEE802154_HW_CAPS_BITS_COMMON_COUNT (13) /** @brief This and higher values are specific to the protocol- or driver-specific extensions. */ #define IEEE802154_HW_CAPS_BITS_PRIV_START IEEE802154_HW_CAPS_BITS_COMMON_COUNT @@ -1057,6 +1060,35 @@ enum ieee802154_config_type { */ IEEE802154_CONFIG_ENH_ACK_HEADER_IE, + /** + * Enable/disable RxOnWhenIdle MAC PIB attribute (Table 8-94). + * + * Since there is no clear guidance in IEEE 802.15.4 specification about the definition of + * an "idle period", this implementation expects that drivers use the RxOnWhenIdle attribute + * to determine next radio state (false --> off, true --> receive) in the following + * scenarios: + * - Finalization of a regular frame reception task, provided that: + * - The frame is received without errors and passes the filtering and it's not an + * spurious ACK. + * - ACK is not requested or transmission of ACK is not possible due to internal + * conditions. + * - Finalization of a frame transmission or transmission of an ACK frame, when ACK is not + * requested in the transmitted frame. + * - Finalization of the reception operation of a requested ACK due to: + * - ACK timeout expiration. + * - Reception of an invalid ACK or not an ACK frame. + * - Reception of the proper ACK, unless the transmitted frame was a Data Request Command + * and the frame pending bit on the received ACK is set to true. In this case the radio + * platform implementation SHOULD keep the receiver on until a determined timeout which + * triggers an idle period start. + * - Finalization of a stand alone CCA task. + * - Finalization of a CCA operation with busy result during CSMA/CA procedure. + * - Finalization of an Energy Detection task. + * - Finalization of a scheduled radio reception window + * (see @ref IEEE802154_CONFIG_RX_SLOT). + */ + IEEE802154_CONFIG_RX_ON_WHEN_IDLE, + /** Number of types defined in ieee802154_config_type. */ IEEE802154_CONFIG_COMMON_COUNT, @@ -1103,6 +1135,9 @@ struct ieee802154_config { /** see @ref IEEE802154_CONFIG_PROMISCUOUS */ bool promiscuous; + /** see @ref IEEE802154_CONFIG_RX_ON_WHEN_IDLE */ + bool rx_on_when_idle; + /** see @ref IEEE802154_CONFIG_EVENT_HANDLER */ ieee802154_event_cb_t event_handler; From b406024148e8619188c72a77cf3d523794af19b2 Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Tue, 14 Nov 2023 14:57:02 +0100 Subject: [PATCH 0404/1049] net: openthread: implement `otPlatRadioSetRxOnWhenIdle` OpenThread upmerge to commit `193e77e`. Implement `otPlatRadioSetRxOnWhenIdle` radio platform API. Signed-off-by: Eduardo Montoya --- modules/openthread/platform/radio.c | 17 +++++++++++++++++ west.yml | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 391ffba395dc56c..9c5de3c9d69f71c 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -890,9 +890,26 @@ otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) caps |= OT_RADIO_CAPS_RECEIVE_TIMING; } + if (radio_caps & IEEE802154_RX_ON_WHEN_IDLE) { + caps |= OT_RADIO_CAPS_RX_ON_WHEN_IDLE; + } + return caps; } +void otPlatRadioSetRxOnWhenIdle(otInstance *aInstance, bool aRxOnWhenIdle) +{ + struct ieee802154_config config = { + .rx_on_when_idle = aRxOnWhenIdle + }; + + ARG_UNUSED(aInstance); + + LOG_DBG("RxOnWhenIdle=%d", aRxOnWhenIdle ? 1 : 0); + + radio_api->configure(radio_dev, IEEE802154_CONFIG_RX_ON_WHEN_IDLE, &config); +} + bool otPlatRadioGetPromiscuous(otInstance *aInstance) { ARG_UNUSED(aInstance); diff --git a/west.yml b/west.yml index f7b40860645430c..3c50603e8c8248f 100644 --- a/west.yml +++ b/west.yml @@ -301,7 +301,7 @@ manifest: revision: 214f9fc1539f8e5937c0474cb6ee29b6dcb2d4b8 path: modules/lib/open-amp - name: openthread - revision: 6edb06e4e0472411200ce2a084a783eaf3faffe3 + revision: 193e77e40ec2387d458eaebd1e03902d86f484a5 path: modules/lib/openthread - name: percepio path: modules/debug/percepio From 909c087521ce435a30ea74811f5c43211ce39334 Mon Sep 17 00:00:00 2001 From: Patryk Lipinski Date: Mon, 13 Nov 2023 15:13:27 +0100 Subject: [PATCH 0405/1049] fs: Changes in the macro statements Changes in the macro statements that allows to build with -Wudef flag enebaled, without errors. Signed-off-by: Patryk Lipinski --- include/zephyr/fs/fs_interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/fs/fs_interface.h b/include/zephyr/fs/fs_interface.h index 2692ea168a7cd8e..5db637635b954c6 100644 --- a/include/zephyr/fs/fs_interface.h +++ b/include/zephyr/fs/fs_interface.h @@ -13,7 +13,7 @@ extern "C" { #endif -#if (CONFIG_FILE_SYSTEM_MAX_FILE_NAME - 0) > 0 +#if defined(CONFIG_FILE_SYSTEM_MAX_FILE_NAME) && (CONFIG_FILE_SYSTEM_MAX_FILE_NAME - 0) > 0 #define MAX_FILE_NAME CONFIG_FILE_SYSTEM_MAX_FILE_NAME #else /* CONFIG_FILE_SYSTEM_MAX_FILE_NAME */ From 4a522114329b5b0356e0e4b8f7bdf2e86a0c67e0 Mon Sep 17 00:00:00 2001 From: Patryk Lipinski Date: Mon, 13 Nov 2023 15:15:49 +0100 Subject: [PATCH 0406/1049] logging: Changes in the macro statements Changes in the macro statements that allows to build with -Wudef flag enebaled, without errors. Signed-off-by: Patryk Lipinski --- include/zephyr/logging/log_msg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/logging/log_msg.h b/include/zephyr/logging/log_msg.h index c04b00cdd9858ae..c35a69d85ccec1a 100644 --- a/include/zephyr/logging/log_msg.h +++ b/include/zephyr/logging/log_msg.h @@ -79,7 +79,7 @@ struct log_msg_hdr { const void *source; log_timestamp_t timestamp; #endif -#if CONFIG_LOG_THREAD_ID_PREFIX +#if defined(CONFIG_LOG_THREAD_ID_PREFIX) void *tid; #endif }; @@ -807,7 +807,7 @@ static inline log_timestamp_t log_msg_get_timestamp(struct log_msg *msg) */ static inline void *log_msg_get_tid(struct log_msg *msg) { -#if CONFIG_LOG_THREAD_ID_PREFIX +#if defined(CONFIG_LOG_THREAD_ID_PREFIX) return msg->hdr.tid; #else ARG_UNUSED(msg); From 14827aad6526985d02dc17737cbff8dd710da3ac Mon Sep 17 00:00:00 2001 From: Patryk Lipinski Date: Mon, 13 Nov 2023 15:16:26 +0100 Subject: [PATCH 0407/1049] modules: hal_nordic: nrfx_glue: Changes in the macro statements Changes in the macro statements that allows to build with -Wudef flag enebaled, without errors. Signed-off-by: Patryk Lipinski --- modules/hal_nordic/nrfx/nrfx_glue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hal_nordic/nrfx/nrfx_glue.h b/modules/hal_nordic/nrfx/nrfx_glue.h index 786004c05c3154c..2257ea879a3d7fd 100644 --- a/modules/hal_nordic/nrfx/nrfx_glue.h +++ b/modules/hal_nordic/nrfx/nrfx_glue.h @@ -357,7 +357,7 @@ void nrfx_busy_wait(uint32_t usec_to_wait); #define NRFX_PPI_GROUPS_USED_BY_MPSL 0 #endif -#if NRF_802154_VERIFY_PERIPHS_ALLOC_AGAINST_MPSL +#if defined(NRF_802154_VERIFY_PERIPHS_ALLOC_AGAINST_MPSL) BUILD_ASSERT( (NRFX_PPI_CHANNELS_USED_BY_802154_DRV & NRFX_PPI_CHANNELS_USED_BY_MPSL) == 0, "PPI channels used by the IEEE802.15.4 radio driver overlap with those " From 2deea4eeeec18eb880682f3d0c50d0e5a8e111fc Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 25 Oct 2023 04:54:52 +0100 Subject: [PATCH 0408/1049] twister: Fix failure on MacOS On MacOS, ps utils raises a `NoSuchProcess` error rather than a `ProcessLookupError` when a pid no longer exists. Signed-off-by: Wilfried Chauveau --- .../src/twister_harness/device/utils.py | 2 +- scripts/pylib/twister/twisterlib/handlers.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/utils.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/utils.py index 5b89d1ad7a851e5..60ee2537bb8d549 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/utils.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/utils.py @@ -44,7 +44,7 @@ def terminate_process(proc: subprocess.Popen) -> None: for child in psutil.Process(proc.pid).children(recursive=True): try: os.kill(child.pid, signal.SIGTERM) - except ProcessLookupError: + except (ProcessLookupError, psutil.NoSuchProcess): pass proc.terminate() # sleep for a while before attempting to kill diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index a39e68741aa2959..3c6498a6ea43541 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -56,7 +56,7 @@ def terminate_process(proc): for child in psutil.Process(proc.pid).children(recursive=True): try: os.kill(child.pid, signal.SIGTERM) - except ProcessLookupError: + except (ProcessLookupError, psutil.NoSuchProcess): pass proc.terminate() # sleep for a while before attempting to kill @@ -182,7 +182,7 @@ def try_kill_process_by_pid(self): self.pid_fn = None # clear so we don't try to kill the binary twice try: os.kill(pid, signal.SIGKILL) - except ProcessLookupError: + except (ProcessLookupError, psutil.NoSuchProcess): pass def _output_reader(self, proc): @@ -805,7 +805,7 @@ def _thread_close_files(fifo_in, fifo_out, pid, out_fp, in_fp, log_out_fp): try: if pid: os.kill(pid, signal.SIGTERM) - except ProcessLookupError: + except (ProcessLookupError, psutil.NoSuchProcess): # Oh well, as long as it's dead! User probably sent Ctrl-C pass @@ -864,6 +864,8 @@ def _thread(handler, timeout, outdir, logfile, fifo_fn, pid_fn, results, if cpu_time < timeout and not out_state: timeout_time = time.time() + (timeout - cpu_time) continue + except psutil.NoSuchProcess: + pass except ProcessLookupError: out_state = "failed" break From 321c5e865665eb7c843db5cdb111b9b5ff0d9e07 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 23 Mar 2023 08:53:27 +0100 Subject: [PATCH 0409/1049] drivers: entropy: stm32: Move irq_lock at init Perform clock check inside irq_lock in order to exit cleanly if failing. Signed-off-by: Erwan Gouriou --- drivers/entropy/entropy_stm32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c index 3dd8f82e8a5bb6f..0abedb1940c1506 100644 --- a/drivers/entropy/entropy_stm32.c +++ b/drivers/entropy/entropy_stm32.c @@ -235,6 +235,8 @@ static int random_byte_get(void) unsigned int key; RNG_TypeDef *rng = entropy_stm32_rng_data.rng; + key = irq_lock(); + if (IS_ENABLED(CONFIG_ENTROPY_STM32_CLK_CHECK) && !k_is_pre_kernel()) { /* CECS bit signals that a clock configuration issue is detected, * which may lead to generation of non truly random data. @@ -244,8 +246,6 @@ static int random_byte_get(void) "\tSee ref man and update target clock configuration."); } - key = irq_lock(); - if (LL_RNG_IsActiveFlag_SEIS(rng) && (recover_seed_error(rng) < 0)) { retval = -EIO; goto out; From 8ed4876bed99314ee20a46394532b5b2675cfa37 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Thu, 9 Nov 2023 10:34:46 +0000 Subject: [PATCH 0410/1049] tests: kernel: also move the test_isr_dynamic to new ztest API `test_isr_dynamic` for `CONFIG_GEN_SW_ISR_TABLE=n` was somehow overlooked in commit b7f1e9872495ee29d223cd7b5c2f8fb5eceab2cd. I'm disabling the irq at the end of the test. The babblesim for the `nrf5340bsim_*` target walked into a timeout otherwise. Signed-off-by: Greter Raffael --- tests/kernel/interrupt/src/dynamic_isr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/kernel/interrupt/src/dynamic_isr.c b/tests/kernel/interrupt/src/dynamic_isr.c index 35f42220fb8f893..d697fda32e8fc6c 100644 --- a/tests/kernel/interrupt/src/dynamic_isr.c +++ b/tests/kernel/interrupt/src/dynamic_isr.c @@ -73,7 +73,7 @@ ZTEST(interrupt_feature, test_isr_dynamic) #define TEST_IRQ_DYN_LINE 5 #endif -void test_isr_dynamic(void) +ZTEST(interrupt_feature, test_isr_dynamic) { int vector_num; @@ -118,5 +118,6 @@ extern const void *x86_irq_args[]; "interrupt triggered but handler has not run(%d)", handler_has_run); + irq_disable(TEST_IRQ_DYN_LINE); } #endif /* CONFIG_GEN_SW_ISR_TABLE */ From 7029c79ef250b28ed1710e6cb7ae6a33daae8933 Mon Sep 17 00:00:00 2001 From: Paszkiet Kamil Date: Thu, 9 Nov 2023 13:41:55 +0100 Subject: [PATCH 0411/1049] scripts: tests: twister_blackbox: Add test test_hardwaremap.py add tests to hardwaremap tests: - generate_hardware_map (different ways) Signed-off-by: Paszkiet Kamil --- .../twister_blackbox/test_hardwaremap.py | 301 ++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 scripts/tests/twister_blackbox/test_hardwaremap.py diff --git a/scripts/tests/twister_blackbox/test_hardwaremap.py b/scripts/tests/twister_blackbox/test_hardwaremap.py new file mode 100644 index 000000000000000..c5dbd990377bfab --- /dev/null +++ b/scripts/tests/twister_blackbox/test_hardwaremap.py @@ -0,0 +1,301 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Blackbox tests for twister's command line functions +""" +import logging +import importlib +import mock +import os +import pytest +import sys + +from conftest import ZEPHYR_BASE, testsuite_filename_mock +from twisterlib.testplan import TestPlan + +sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister/twisterlib")) + +@mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) +class TestHardwaremap: + TESTDATA_1 = [ + ( + [ + 'ARM', + 'SEGGER', + 'MBED' + ], + [ + 'DAPLink CMSIS-DAP', + 'MBED CMSIS-DAP' + ], + [1234, 'abcd'], + 'pyocd' + ), + ( + [ + 'STMicroelectronics', + 'Atmel Corp.' + ], + [ + 'J-Link', + 'J-Link OB' + ], + [1234, 'abcd'], + 'jlink' + ), + ( + [ + 'Silicon Labs', + 'NXP Semiconductors', + 'Microchip Technology Inc.' + ], + [ + 'STM32 STLink', + '^XDS110.*', + 'STLINK-V3' + ], + [1234, 'abcd'], + 'openocd' + ), + ( + [ + 'FTDI', + 'Digilent', + 'Microsoft' + ], + [ + 'TTL232R-3V3', + 'MCP2200 USB Serial Port Emulator' + ], + [1234, 'abcd'], + 'dediprog' + ) + ] + TESTDATA_2 = [ + ( + 'FTDI', + 'DAPLink CMSIS-DAP', + 1234, + 'pyocd' + ) + ] + TESTDATA_3 = [ + ( + 'Texas Instruments', + 'DAPLink CMSIS-DAP', + 'abcd', 'las' + ), + ( + 'Texas Instruments', + 'DAPLink CMSIS-DAP', + 'abcd', 'dse0' + ) + ] + + @classmethod + def setup_class(cls): + apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') + cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) + cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) + cls.twister_module = importlib.util.module_from_spec(cls.spec) + + @classmethod + def teardown_class(cls): + pass + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + ('manufacturer', 'product', 'serial', 'runner'), + TESTDATA_1, + ) + def test_generate(self, capfd, manufacturer, product, serial, runner): + file_name = "test-map.yaml" + path = os.path.join(ZEPHYR_BASE, file_name) + args = ['--generate-hardware-map', file_name] + + if os.path.exists(path): + os.remove(path) + + def mocked_comports(): + return [ + mock.Mock(device='/dev/ttyUSB23', + manufacturer=id_man, + product=id_pro, + serial_number=id_serial + ) + ] + + for id_man in manufacturer: + for id_pro in product: + for id_serial in serial: + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + mock.patch('serial.tools.list_ports.comports', + side_effect=mocked_comports), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert os.path.exists(path) + + expected_data = '- connected: true\n' \ + f' id: {id_serial}\n' \ + ' platform: unknown\n' \ + f' product: {id_pro}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB23\n' + + load_data = open(path).read() + assert load_data == expected_data + + if os.path.exists(path): + os.remove(path) + + assert str(sys_exit.value) == '0' + loggers = [logging.getLogger()] + \ + list(logging.Logger.manager.loggerDict.values()) + \ + [logging.getLogger(name) for \ + name in logging.root.manager.loggerDict] + for logger in loggers: + handlers = getattr(logger, 'handlers', []) + for handler in handlers: + logger.removeHandler(handler) + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + ('manufacturer', 'product', 'serial', 'runner'), + TESTDATA_2, + ) + def test_few_generate(self, capfd, manufacturer, product, serial, runner): + file_name = "test-map.yaml" + path = os.path.join(ZEPHYR_BASE, file_name) + args = ['--generate-hardware-map', file_name] + + if os.path.exists(path): + os.remove(path) + + def mocked_comports(): + return [ + mock.Mock(device='/dev/ttyUSB23', + manufacturer=manufacturer, + product=product, + serial_number=serial + ), + mock.Mock(device='/dev/ttyUSB24', + manufacturer=manufacturer, + product=product, + serial_number=serial + 1 + ), + mock.Mock(device='/dev/ttyUSB24', + manufacturer=manufacturer, + product=product, + serial_number=serial + 2 + ), + mock.Mock(device='/dev/ttyUSB25', + manufacturer=manufacturer, + product=product, + serial_number=serial + 3 + ) + ] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + mock.patch('serial.tools.list_ports.comports', + side_effect=mocked_comports), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert os.path.exists(path) + + expected_data = '- connected: true\n' \ + f' id: {serial}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB23\n' \ + '- connected: true\n' \ + f' id: {serial + 1}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB24\n' \ + '- connected: true\n' \ + f' id: {serial + 2}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB24\n' \ + '- connected: true\n' \ + f' id: {serial + 3}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB25\n' + + load_data = open(path).read() + assert load_data == expected_data + + if os.path.exists(path): + os.remove(path) + + assert str(sys_exit.value) == '0' + + @pytest.mark.usefixtures("clear_log") + @pytest.mark.parametrize( + ('manufacturer', 'product', 'serial', 'location'), + TESTDATA_3, + ) + def test_texas_exeption(self, capfd, manufacturer, product, serial, location): + file_name = "test-map.yaml" + path = os.path.join(ZEPHYR_BASE, file_name) + args = ['--generate-hardware-map', file_name] + + if os.path.exists(path): + os.remove(path) + + def mocked_comports(): + return [ + mock.Mock(device='/dev/ttyUSB23', + manufacturer=manufacturer, + product=product, + serial_number=serial, + location=location + ) + ] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + mock.patch('serial.tools.list_ports.comports', + side_effect=mocked_comports), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert os.path.exists(path) + + expected_data = '- connected: true\n' \ + f' id: {serial}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + ' runner: pyocd\n' \ + ' serial: /dev/ttyUSB23\n' + expected_data2 = '[]\n' + + load_data = open(path).read() + if location.endswith('0'): + assert load_data == expected_data + else: + assert load_data == expected_data2 + if os.path.exists(path): + os.remove(path) + + assert str(sys_exit.value) == '0' From 1f4dacad08e859ea5ad82dc3f7d99ea753019b05 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Fri, 10 Nov 2023 10:48:28 +0800 Subject: [PATCH 0412/1049] Bluetooth: Mesh: Remove relay sets config for adv Separate queue should also used for lagecy adv, due to when local queue has adv buf, k_poll will process local queue. Signed-off-by: Lingao Meng --- subsys/bluetooth/mesh/adv.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/subsys/bluetooth/mesh/adv.c b/subsys/bluetooth/mesh/adv.c index b24523aacf3a219..548e7f3fe1512c6 100644 --- a/subsys/bluetooth/mesh/adv.c +++ b/subsys/bluetooth/mesh/adv.c @@ -157,7 +157,6 @@ struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, tag, xmit, timeout); } -#if CONFIG_BT_MESH_RELAY_ADV_SETS || CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE static struct net_buf *process_events(struct k_poll_event *ev, int count) { for (; count; ev++, count--) { @@ -186,12 +185,15 @@ struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout) K_POLL_MODE_NOTIFY_ONLY, &bt_mesh_adv_queue, 0), -#if defined(CONFIG_BT_MESH_ADV_EXT_RELAY_USING_MAIN_ADV_SET) +#if defined(CONFIG_BT_MESH_RELAY) && \ + (defined(CONFIG_BT_MESH_ADV_LEGACY) || \ + defined(CONFIG_BT_MESH_ADV_EXT_RELAY_USING_MAIN_ADV_SET) || \ + !(CONFIG_BT_MESH_RELAY_ADV_SETS)) K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE, K_POLL_MODE_NOTIFY_ONLY, &bt_mesh_relay_queue, 0), -#endif /* CONFIG_BT_MESH_ADV_EXT_RELAY_USING_MAIN_ADV_SET */ +#endif }; err = k_poll(events, ARRAY_SIZE(events), timeout); @@ -209,27 +211,13 @@ struct net_buf *bt_mesh_adv_buf_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_time return net_buf_get(&bt_mesh_friend_queue, timeout); } -#if CONFIG_BT_MESH_RELAY_ADV_SETS - if (!(tags & BT_MESH_ADV_TAG_BIT_LOCAL)) { + if (IS_ENABLED(CONFIG_BT_MESH_RELAY) && + !(tags & BT_MESH_ADV_TAG_BIT_LOCAL)) { return net_buf_get(&bt_mesh_relay_queue, timeout); } -#endif return bt_mesh_adv_buf_get(timeout); } -#else /* !(CONFIG_BT_MESH_RELAY_ADV_SETS || CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) */ -struct net_buf *bt_mesh_adv_buf_get(k_timeout_t timeout) -{ - return net_buf_get(&bt_mesh_adv_queue, timeout); -} - -struct net_buf *bt_mesh_adv_buf_get_by_tag(enum bt_mesh_adv_tag_bit tags, k_timeout_t timeout) -{ - ARG_UNUSED(tags); - - return bt_mesh_adv_buf_get(timeout); -} -#endif /* CONFIG_BT_MESH_RELAY_ADV_SETS || CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE */ void bt_mesh_adv_buf_get_cancel(void) { @@ -237,9 +225,9 @@ void bt_mesh_adv_buf_get_cancel(void) k_fifo_cancel_wait(&bt_mesh_adv_queue); -#if CONFIG_BT_MESH_RELAY_ADV_SETS - k_fifo_cancel_wait(&bt_mesh_relay_queue); -#endif /* CONFIG_BT_MESH_RELAY_ADV_SETS */ + if (IS_ENABLED(CONFIG_BT_MESH_RELAY)) { + k_fifo_cancel_wait(&bt_mesh_relay_queue); + } if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)) { k_fifo_cancel_wait(&bt_mesh_friend_queue); @@ -267,15 +255,14 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, return; } -#if CONFIG_BT_MESH_RELAY_ADV_SETS - if (BT_MESH_ADV(buf)->tag == BT_MESH_ADV_TAG_RELAY || + if ((IS_ENABLED(CONFIG_BT_MESH_RELAY) && + BT_MESH_ADV(buf)->tag == BT_MESH_ADV_TAG_RELAY) || (IS_ENABLED(CONFIG_BT_MESH_PB_ADV_USE_RELAY_SETS) && BT_MESH_ADV(buf)->tag == BT_MESH_ADV_TAG_PROV)) { net_buf_put(&bt_mesh_relay_queue, net_buf_ref(buf)); bt_mesh_adv_buf_relay_ready(); return; } -#endif net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf)); bt_mesh_adv_buf_local_ready(); From e1d4451976b925ae0daacacce44e782daae98d64 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Fri, 10 Nov 2023 14:36:57 +0800 Subject: [PATCH 0413/1049] bsim: bluetooth: mesh: Increase Net Transmit Count value on the node This is to increase probability of reception of responses (Config Status messages) from the node when the provisioner sends a Set message and the node response with a Status message at the same time so that the message collide. Signed-off-by: Lingao Meng --- tests/bsim/bluetooth/mesh/src/test_provision.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 5425874652425e5..24e1f627382a8a7 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -1572,6 +1572,9 @@ static void comp_data_get(uint16_t server_addr, uint8_t page, struct net_buf_sim { uint8_t page_rsp; + /* Let complete advertising of the transaction to prevent collisions. */ + k_sleep(K_SECONDS(3)); + net_buf_simple_reset(comp); ASSERT_OK(bt_mesh_cfg_cli_comp_data_get(0, server_addr, page, &page_rsp, comp)); ASSERT_EQUAL(page, page_rsp); From 4c33323c056f47119630acd39370c1bff4681663 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 10 Nov 2023 12:34:33 +0100 Subject: [PATCH 0414/1049] drivers: can: shell: add support for setting raw timing values Add support for setting raw timing values. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_shell.c | 105 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/drivers/can/can_shell.c b/drivers/can/can_shell.c index 4faf11aae4e347c..46dac3fb06ab73b 100644 --- a/drivers/can/can_shell.c +++ b/drivers/can/can_shell.c @@ -519,6 +519,102 @@ static int cmd_can_dbitrate_set(const struct shell *sh, size_t argc, char **argv return 0; } +static int can_shell_parse_timing(const struct shell *sh, size_t argc, char **argv, + struct can_timing *timing) +{ + char *endptr; + + timing->sjw = (uint32_t)strtoul(argv[2], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse sjw"); + return -EINVAL; + } + + timing->prop_seg = (uint32_t)strtoul(argv[3], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse prop_seg"); + return -EINVAL; + } + + timing->phase_seg1 = (uint32_t)strtoul(argv[4], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse phase_seg1"); + return -EINVAL; + } + + timing->phase_seg2 = (uint32_t)strtoul(argv[5], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse phase_seg2"); + return -EINVAL; + } + + timing->prescaler = (uint32_t)strtoul(argv[6], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse prescaler"); + return -EINVAL; + } + + return 0; +} + +static int cmd_can_timing_set(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev = device_get_binding(argv[1]); + struct can_timing timing = { 0 }; + int err; + + if (!device_is_ready(dev)) { + shell_error(sh, "device %s not ready", argv[1]); + return -ENODEV; + } + + err = can_shell_parse_timing(sh, argc, argv, &timing); + if (err < 0) { + return err; + } + + shell_print(sh, "setting timing to sjw %u, prop_seg %u, phase_seg1 %u, phase_seg2 %u, " + "prescaler %u", timing.sjw, timing.prop_seg, timing.phase_seg1, + timing.phase_seg2, timing.prescaler); + + err = can_set_timing(dev, &timing); + if (err != 0) { + shell_error(sh, "failed to set timing (err %d)", err); + return err; + } + + return 0; +} + +static int cmd_can_dtiming_set(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev = device_get_binding(argv[1]); + struct can_timing timing = { 0 }; + int err; + + if (!device_is_ready(dev)) { + shell_error(sh, "device %s not ready", argv[1]); + return -ENODEV; + } + + err = can_shell_parse_timing(sh, argc, argv, &timing); + if (err < 0) { + return err; + } + + shell_print(sh, "setting data phase timing to sjw %u, prop_seg %u, phase_seg1 %u, " + "phase_seg2 %u, prescaler %u", timing.sjw, timing.prop_seg, timing.phase_seg1, + timing.phase_seg2, timing.prescaler); + + err = can_set_timing_data(dev, &timing); + if (err != 0) { + shell_error(sh, "failed to set data phase timing (err %d)", err); + return err; + } + + return 0; +} + static int cmd_can_mode_set(const struct shell *sh, size_t argc, char **argv) { const struct device *dev = device_get_binding(argv[1]); @@ -942,6 +1038,15 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_can_cmds, "Set CAN controller data phase bitrate (sample point and SJW optional)\n" "Usage: can dbitrate [sample point] [sjw]", cmd_can_dbitrate_set, 3, 2), + SHELL_CMD_ARG(timing, &dsub_can_device_name, + "Set CAN controller timing\n" + "Usage: can timing ", + cmd_can_timing_set, 7, 0), + SHELL_COND_CMD_ARG(CONFIG_CAN_FD_MODE, + dtiming, &dsub_can_device_name, + "Set CAN controller data phase timing\n" + "Usage: can dtiming ", + cmd_can_dtiming_set, 7, 0), SHELL_CMD_ARG(mode, &dsub_can_device_name_mode, "Set CAN controller mode\n" "Usage: can mode [mode] [mode] [...]", From c56bfb9d06a909429070eace0286a6394e2b0ae6 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 10 Nov 2023 12:35:49 +0100 Subject: [PATCH 0415/1049] tests: drivers: can: shell: add tests for setting raw timing Add CAN shell tests for the "timing" and "dtiming" subcommands. Signed-off-by: Henrik Brix Andersen --- tests/drivers/can/shell/src/main.c | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tests/drivers/can/shell/src/main.c b/tests/drivers/can/shell/src/main.c index 8b7ec053c5a4b90..61bd80ec72f7510 100644 --- a/tests/drivers/can/shell/src/main.c +++ b/tests/drivers/can/shell/src/main.c @@ -206,6 +206,75 @@ ZTEST(can_shell, test_can_dbitrate_sample_point) can_shell_test_dbitrate("can dbitrate " FAKE_CAN_NAME " 1000000 875", 1000000, 875); } +ZTEST(can_shell, test_can_timing) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + struct can_timing expected = { + .sjw = 1U, + .prop_seg = 2U, + .phase_seg1 = 3U, + .phase_seg2 = 4U, + .prescaler = 5U, + }; + int err; + + fake_can_set_timing_fake.custom_fake = can_shell_test_capture_timing; + + err = shell_execute_cmd(sh, "can timing " FAKE_CAN_NAME " 1 2 3 4 5"); + zassert_ok(err, "failed to execute shell command (err %d)", err); + zassert_equal(fake_can_set_timing_fake.call_count, 1, "set_timing function not called"); + zassert_equal(fake_can_set_timing_fake.arg0_val, fake_can_dev, "wrong device pointer"); + assert_can_timing_equal(&expected, &timing_capture); +} + +ZTEST(can_shell, test_can_timing_missing_value) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + int err; + + Z_TEST_SKIP_IFNDEF(CONFIG_CAN_FD_MODE); + + err = shell_execute_cmd(sh, "can timing " FAKE_CAN_NAME); + zassert_not_equal(err, 0, " executed shell command without timing"); + zassert_equal(fake_can_set_timing_fake.call_count, 0, + "set_timing function called"); +} + +ZTEST(can_shell, test_can_dtiming) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + struct can_timing expected = { + .sjw = 1U, + .prop_seg = 2U, + .phase_seg1 = 3U, + .phase_seg2 = 4U, + .prescaler = 5U, + }; + int err; + + fake_can_set_timing_data_fake.custom_fake = can_shell_test_capture_timing; + + err = shell_execute_cmd(sh, "can dtiming " FAKE_CAN_NAME " 1 2 3 4 5"); + zassert_ok(err, "failed to execute shell command (err %d)", err); + zassert_equal(fake_can_set_timing_data_fake.call_count, 1, + "set_timing_data function not called"); + zassert_equal(fake_can_set_timing_data_fake.arg0_val, fake_can_dev, "wrong device pointer"); + assert_can_timing_equal(&expected, &timing_capture); +} + +ZTEST(can_shell, test_can_dtiming_missing_value) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + int err; + + Z_TEST_SKIP_IFNDEF(CONFIG_CAN_FD_MODE); + + err = shell_execute_cmd(sh, "can dtiming " FAKE_CAN_NAME); + zassert_not_equal(err, 0, " executed shell command without dtiming"); + zassert_equal(fake_can_set_timing_data_fake.call_count, 0, + "set_timing_data function called"); +} + ZTEST(can_shell, test_can_mode_missing_value) { const struct shell *sh = shell_backend_dummy_get_ptr(); From 63ceeb3bba7c113a4f3cb6b4cfdef4c4d42bdc5b Mon Sep 17 00:00:00 2001 From: Charles Dias Date: Sat, 11 Nov 2023 14:38:54 -0300 Subject: [PATCH 0416/1049] soc: arm: st_stm32: add support for stm32h7b0xx and stm32h7b0xxQ Add Kconfig SoC configurations. Signed-off-by: Charles Dias --- .../stm32h7/Kconfig.defconfig.stm32h7b0xx | 15 +++++++++++++++ soc/arm/st_stm32/stm32h7/Kconfig.soc | 10 ++++++++++ 2 files changed, 25 insertions(+) create mode 100644 soc/arm/st_stm32/stm32h7/Kconfig.defconfig.stm32h7b0xx diff --git a/soc/arm/st_stm32/stm32h7/Kconfig.defconfig.stm32h7b0xx b/soc/arm/st_stm32/stm32h7/Kconfig.defconfig.stm32h7b0xx new file mode 100644 index 000000000000000..105021350149c89 --- /dev/null +++ b/soc/arm/st_stm32/stm32h7/Kconfig.defconfig.stm32h7b0xx @@ -0,0 +1,15 @@ +# ST STM32H7B0XX MCU configuration options + +# Copyright (c) 2023 Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32H7B0XX || SOC_STM32H7B0XXQ + +config SOC + default "stm32h7b0xxQ" if SOC_STM32H7B0XXQ + default "stm32h7b0xx" if SOC_STM32H7B0XX + +config NUM_IRQS + default 155 + +endif # SOC_STM32H7B0XX || SOC_STM32H7B0XXQ diff --git a/soc/arm/st_stm32/stm32h7/Kconfig.soc b/soc/arm/st_stm32/stm32h7/Kconfig.soc index 46f101f0e1420d2..7856c52652ac0c4 100644 --- a/soc/arm/st_stm32/stm32h7/Kconfig.soc +++ b/soc/arm/st_stm32/stm32h7/Kconfig.soc @@ -73,6 +73,16 @@ config SOC_STM32H7A3XXQ select CPU_CORTEX_M7 select CPU_HAS_FPU_DOUBLE_PRECISION +config SOC_STM32H7B0XX + bool "STM32H7B0XX" + select CPU_CORTEX_M7 + select CPU_HAS_FPU_DOUBLE_PRECISION + +config SOC_STM32H7B0XXQ + bool "STM32H7B0XXQ" + select CPU_CORTEX_M7 + select CPU_HAS_FPU_DOUBLE_PRECISION + config SOC_STM32H7B3XX bool "STM32H7B3XX" select CPU_CORTEX_M7 From de51fca769bb7e99a9b00fb8b8af954180d291af Mon Sep 17 00:00:00 2001 From: Charles Dias Date: Sun, 12 Nov 2023 12:32:04 -0300 Subject: [PATCH 0417/1049] drivers: clock_control: define clock freq for STM32H7B0 Define max SYSCLK and AHB clock frequencies as 280 MHz, max APB frequency as 140 MHz, and enable semaphore clock. Signed-off-by: Charles Dias --- drivers/clock_control/clock_stm32_ll_h7.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index c95d8ab1294fe88..dc9127d277d00d6 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -107,6 +107,7 @@ #define AHB_FREQ_MAX 275000000UL #define APBx_FREQ_MAX 137500000UL #elif defined(CONFIG_SOC_STM32H7A3XX) || defined(CONFIG_SOC_STM32H7A3XXQ) ||\ + defined(CONFIG_SOC_STM32H7B0XX) || defined(CONFIG_SOC_STM32H7B0XXQ) ||\ defined(CONFIG_SOC_STM32H7B3XX) || defined(CONFIG_SOC_STM32H7B3XXQ) #define SYSCLK_FREQ_MAX 280000000UL #define AHB_FREQ_MAX 280000000UL @@ -829,6 +830,7 @@ int stm32_clock_control_init(const struct device *dev) /* HW semaphore Clock enable */ #if defined(CONFIG_SOC_STM32H7A3XX) || defined(CONFIG_SOC_STM32H7A3XXQ) || \ + defined(CONFIG_SOC_STM32H7B0XX) || defined(CONFIG_SOC_STM32H7B0XXQ) || \ defined(CONFIG_SOC_STM32H7B3XX) || defined(CONFIG_SOC_STM32H7B3XXQ) LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_HSEM); #else From d15f5bbcc72bbec26be448477d7c6fe647c66531 Mon Sep 17 00:00:00 2001 From: Charles Dias Date: Sun, 12 Nov 2023 12:33:57 -0300 Subject: [PATCH 0418/1049] dts: arm: st: h7: add support for stm32h7b0 Add device tree support for STM32H7B0 line. Signed-off-by: Charles Dias --- dts/arm/st/h7/stm32h7b0.dtsi | 27 +++++++++++++++++++++++++++ dts/arm/st/h7/stm32h7b0Xb.dtsi | 17 +++++++++++++++++ dts/arm/st/h7/stm32h7b3.dtsi | 14 ++------------ 3 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 dts/arm/st/h7/stm32h7b0.dtsi create mode 100644 dts/arm/st/h7/stm32h7b0Xb.dtsi diff --git a/dts/arm/st/h7/stm32h7b0.dtsi b/dts/arm/st/h7/stm32h7b0.dtsi new file mode 100644 index 000000000000000..043c3fee302f092 --- /dev/null +++ b/dts/arm/st/h7/stm32h7b0.dtsi @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Charles Dias + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* + * STM32H7B0 line contains the same peripherals as STM32H7A3, + * with addition of CRYPTO/HASH and OTFDEC peripherals. + */ +/ { + soc { + compatible = "st,stm32h7b0", "st,stm32h7", "simple-bus"; + + cryp: cryp@48021000 { + compatible = "st,stm32-cryp"; + reg = <0x48021000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000010>; + interrupts = <79 0>; + interrupt-names = "cryp"; + status = "disabled"; + }; + }; +}; diff --git a/dts/arm/st/h7/stm32h7b0Xb.dtsi b/dts/arm/st/h7/stm32h7b0Xb.dtsi new file mode 100644 index 000000000000000..884e22edc8e928a --- /dev/null +++ b/dts/arm/st/h7/stm32h7b0Xb.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Charles Dias + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +/ { + soc { + flash-controller@52002000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(128)>; + }; + }; + }; +}; diff --git a/dts/arm/st/h7/stm32h7b3.dtsi b/dts/arm/st/h7/stm32h7b3.dtsi index a104f58a192bd56..f8b583b9d751ee4 100644 --- a/dts/arm/st/h7/stm32h7b3.dtsi +++ b/dts/arm/st/h7/stm32h7b3.dtsi @@ -5,23 +5,13 @@ */ #include -#include +#include /* - * STM32H7B3 line contains the same peripherals as STM32H7A3, - * with addition of CRYPTO/HASH and OTFDEC peripherals + * STM32H7B3 line contains the same peripherals as STM32H7B0. */ / { soc { compatible = "st,stm32h7b3", "st,stm32h7", "simple-bus"; - - cryp: cryp@48021000 { - compatible = "st,stm32-cryp"; - reg = <0x48021000 0x400>; - clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000010>; - interrupts = <79 0>; - interrupt-names = "cryp"; - status = "disabled"; - }; }; }; From 1f0320441b7c888f788e1cb7ba15ebf1feaa7fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:40:14 +0100 Subject: [PATCH 0419/1049] drivers: bluetooth: hci: cyw43xxx: Add dependency to UART runtime config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration for CYW43XXX. Signed-off-by: Krzysztof Chruściński --- drivers/bluetooth/hci/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 835b90edd545986..0f792b58b0821b3 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -141,6 +141,7 @@ menuconfig BT_AIROC bool "AIROC BT connectivity" default y select BT_HCI_SETUP + select UART_USE_RUNTIME_CONFIGURE depends on GPIO depends on DT_HAS_INFINEON_CYW43XXX_BT_HCI_ENABLED depends on BT_H4 From c674eafe7501c1610c15b67826a16d7a1ce9e803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:40:59 +0100 Subject: [PATCH 0420/1049] drivers: i2c: sc18im704: Add dependency to UART runtime config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration for sc18im704. Signed-off-by: Krzysztof Chruściński --- drivers/i2c/Kconfig.sc18im704 | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/Kconfig.sc18im704 b/drivers/i2c/Kconfig.sc18im704 index 15cdbd43d4d5c90..f38c0e67d23472e 100644 --- a/drivers/i2c/Kconfig.sc18im704 +++ b/drivers/i2c/Kconfig.sc18im704 @@ -5,6 +5,7 @@ config I2C_SC18IM704 bool "NXP SC18IM704 I2C controller driver" default y depends on DT_HAS_NXP_SC18IM704_I2C_ENABLED + select UART_USE_RUNTIME_CONFIGURE help Enables NXP SC18IM704 I2C controller driver From 3bb4cd813aea44f678156cf4ccedb1aad023bb8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:41:43 +0100 Subject: [PATCH 0421/1049] drivers: sensor: a01nyub: Add dependency to UART runtime configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration for A01NYUB. Signed-off-by: Krzysztof Chruściński --- drivers/sensor/a01nyub/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/sensor/a01nyub/Kconfig b/drivers/sensor/a01nyub/Kconfig index ff40a6f0682e715..5f137e0358a17e0 100644 --- a/drivers/sensor/a01nyub/Kconfig +++ b/drivers/sensor/a01nyub/Kconfig @@ -6,5 +6,6 @@ config A01NYUB default y depends on DT_HAS_DFROBOT_A01NYUB_ENABLED depends on UART_INTERRUPT_DRIVEN + select UART_USE_RUNTIME_CONFIGURE help Enable driver for the DFRobot A01NYUB distance sensor. From a47c7dd79330ed18525a5294ad03a787c75c6f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:42:40 +0100 Subject: [PATCH 0422/1049] drivers: w1: Add dependency to UART runtime configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration for 1-wire serial driver. Signed-off-by: Krzysztof Chruściński --- drivers/w1/Kconfig.zephyr_serial | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/w1/Kconfig.zephyr_serial b/drivers/w1/Kconfig.zephyr_serial index 9555fb43a92750f..10eb274ee1e1451 100644 --- a/drivers/w1/Kconfig.zephyr_serial +++ b/drivers/w1/Kconfig.zephyr_serial @@ -8,6 +8,7 @@ config W1_ZEPHYR_SERIAL select SERIAL default y depends on DT_HAS_ZEPHYR_W1_SERIAL_ENABLED + select UART_USE_RUNTIME_CONFIGURE help This option enables the Zephyr serial 1-Wire master driver. From 0f79f3a4c00d2864a8c5f9491a03e7a8a9eeb350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:44:08 +0100 Subject: [PATCH 0423/1049] drivers: wifi: esp_at: Add dependency to UART runtime configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration for ESP AT driver. Signed-off-by: Krzysztof Chruściński --- drivers/wifi/esp_at/Kconfig.esp_at | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/wifi/esp_at/Kconfig.esp_at b/drivers/wifi/esp_at/Kconfig.esp_at index afe02931ee6ae85..9b7e38045d95f18 100644 --- a/drivers/wifi/esp_at/Kconfig.esp_at +++ b/drivers/wifi/esp_at/Kconfig.esp_at @@ -11,6 +11,7 @@ menuconfig WIFI_ESP_AT select MODEM_IFACE_UART select NET_L2_WIFI_MGMT select WIFI_OFFLOAD + imply UART_USE_RUNTIME_CONFIGURE help Enable Espressif AT Command offloaded WiFi driver. It is supported on any serial capable platform and communicates with Espressif chips From 6022a413d644a1682aa5a61c705de0b8fe342a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:45:18 +0100 Subject: [PATCH 0424/1049] samples: drivers: uart: native_tty: Add dependency to UART runtime conf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration in the sample. Signed-off-by: Krzysztof Chruściński --- samples/drivers/uart/native_tty/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/drivers/uart/native_tty/prj.conf b/samples/drivers/uart/native_tty/prj.conf index ef2861c789f8d14..7958f8c58bf29a6 100644 --- a/samples/drivers/uart/native_tty/prj.conf +++ b/samples/drivers/uart/native_tty/prj.conf @@ -1 +1,2 @@ CONFIG_SERIAL=y +CONFIG_UART_USE_RUNTIME_CONFIGURE=y From 7778b7d46d526aebed515d3c409dde361b6d6fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:46:51 +0100 Subject: [PATCH 0425/1049] debug: gdbstub: Add dependency to UART runtime configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration for GDBSTUB. Signed-off-by: Krzysztof Chruściński --- subsys/debug/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/debug/Kconfig b/subsys/debug/Kconfig index f9468ff5e0c3054..54d83f18ff60b62 100644 --- a/subsys/debug/Kconfig +++ b/subsys/debug/Kconfig @@ -397,6 +397,7 @@ endmenu config GDBSTUB bool "GDB remote serial protocol support [EXPERIMENTAL]" depends on ARCH_HAS_GDBSTUB + select UART_USE_RUNTIME_CONFIGURE select EXPERIMENTAL help This option enable support the target using GDB, or any other From b0323820119fb30e2e5a35cabae62bb7ab01fa59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:47:24 +0100 Subject: [PATCH 0426/1049] modbus: Add dependency to UART runtime configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration for modbus serial. Signed-off-by: Krzysztof Chruściński --- subsys/modbus/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/modbus/Kconfig b/subsys/modbus/Kconfig index 614afdd83416c9d..38c7d761c076eb3 100644 --- a/subsys/modbus/Kconfig +++ b/subsys/modbus/Kconfig @@ -44,6 +44,7 @@ config MODBUS_SERIAL default y depends on SERIAL && SERIAL_HAS_DRIVER depends on DT_HAS_ZEPHYR_MODBUS_SERIAL_ENABLED + select UART_USE_RUNTIME_CONFIGURE help Enable Modbus over serial line support. From 1ec05c4431988c6dcaa895fb84912c3a8ed288e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 11:20:40 +0100 Subject: [PATCH 0427/1049] tests: drivers: Add dependency to UART runtime configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration in UART tests. Signed-off-by: Krzysztof Chruściński --- tests/drivers/uart/uart_async_api/prj.conf | 1 + tests/drivers/uart/uart_basic_api/prj.conf | 1 + tests/drivers/uart/uart_basic_api/prj_poll.conf | 1 + tests/drivers/uart/uart_basic_api/prj_shell.conf | 1 + 4 files changed, 4 insertions(+) diff --git a/tests/drivers/uart/uart_async_api/prj.conf b/tests/drivers/uart/uart_async_api/prj.conf index ef0d6054812db6f..39c50952d48da7c 100644 --- a/tests/drivers/uart/uart_async_api/prj.conf +++ b/tests/drivers/uart/uart_async_api/prj.conf @@ -1,4 +1,5 @@ CONFIG_SERIAL=y CONFIG_UART_ASYNC_API=y +CONFIG_UART_USE_RUNTIME_CONFIGURE=y CONFIG_ZTEST=y CONFIG_TEST_USERSPACE=y diff --git a/tests/drivers/uart/uart_basic_api/prj.conf b/tests/drivers/uart/uart_basic_api/prj.conf index d12c995df094117..4234fa733981d82 100644 --- a/tests/drivers/uart/uart_basic_api/prj.conf +++ b/tests/drivers/uart/uart_basic_api/prj.conf @@ -1,4 +1,5 @@ CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_USE_RUNTIME_CONFIGURE=y CONFIG_ZTEST=y CONFIG_NATIVE_UART_0_ON_STDINOUT=y diff --git a/tests/drivers/uart/uart_basic_api/prj_poll.conf b/tests/drivers/uart/uart_basic_api/prj_poll.conf index 772072f1c4d348a..7b1c92736652d12 100644 --- a/tests/drivers/uart/uart_basic_api/prj_poll.conf +++ b/tests/drivers/uart/uart_basic_api/prj_poll.conf @@ -1,3 +1,4 @@ CONFIG_SERIAL=y +CONFIG_UART_USE_RUNTIME_CONFIGURE=y CONFIG_ZTEST=y CONFIG_NATIVE_UART_0_ON_STDINOUT=y diff --git a/tests/drivers/uart/uart_basic_api/prj_shell.conf b/tests/drivers/uart/uart_basic_api/prj_shell.conf index 6ecbf8931a4950d..f4ce1d0334cf032 100644 --- a/tests/drivers/uart/uart_basic_api/prj_shell.conf +++ b/tests/drivers/uart/uart_basic_api/prj_shell.conf @@ -1,5 +1,6 @@ CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_USE_RUNTIME_CONFIGURE=y CONFIG_ZTEST=y CONFIG_SHELL_CMD_BUFF_SIZE=90 CONFIG_SHELL=y From d31424e040c49c750e089182378aa52b5d14445f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Mon, 13 Nov 2023 09:51:14 +0100 Subject: [PATCH 0428/1049] mgmt: osdp: Add dependency to UART runtime configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Force enabling of the UART runtime configuration for OSDP. Signed-off-by: Krzysztof Chruściński --- subsys/mgmt/osdp/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/mgmt/osdp/Kconfig b/subsys/mgmt/osdp/Kconfig index 2d19d7960433ccd..c04abbc6df6c24a 100644 --- a/subsys/mgmt/osdp/Kconfig +++ b/subsys/mgmt/osdp/Kconfig @@ -9,6 +9,7 @@ menuconfig OSDP select RING_BUFFER imply SERIAL_SUPPORT_INTERRUPT imply UART_INTERRUPT_DRIVEN + imply UART_USE_RUNTIME_CONFIGURE select CRC help Add support for Open Supervised Device Protocol (OSDP) From b5f4d8374a6c5e9535515dbf2379188637502046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Mon, 13 Nov 2023 12:45:56 +0100 Subject: [PATCH 0429/1049] net: buf: Preserve buffer pointer in destroy callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The use case is to have a netbuf pool that is used exclusively with net_buf_alloc_with_data() where the destroy callback takes care of freeing the actual data buffer pointed to by __buf. Signed-off-by: Tomasz Moń --- include/zephyr/net/buf.h | 7 +++++++ subsys/net/buf.c | 16 ---------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/include/zephyr/net/buf.h b/include/zephyr/net/buf.h index 91d0f601183638f..f7378fc39620ec3 100644 --- a/include/zephyr/net/buf.h +++ b/include/zephyr/net/buf.h @@ -1358,6 +1358,13 @@ static inline void net_buf_destroy(struct net_buf *buf) { struct net_buf_pool *pool = net_buf_pool_get(buf->pool_id); + if (buf->__buf) { + if (!(buf->flags & NET_BUF_EXTERNAL_DATA)) { + pool->alloc->cb->unref(buf, buf->__buf); + } + buf->__buf = NULL; + } + k_lifo_put(&pool->free, buf); } diff --git a/subsys/net/buf.c b/subsys/net/buf.c index da8c75f32f26693..09f937da59dfb02 100644 --- a/subsys/net/buf.c +++ b/subsys/net/buf.c @@ -221,17 +221,6 @@ static uint8_t *data_ref(struct net_buf *buf, uint8_t *data) return pool->alloc->cb->ref(buf, data); } -static void data_unref(struct net_buf *buf, uint8_t *data) -{ - struct net_buf_pool *pool = net_buf_pool_get(buf->pool_id); - - if (buf->flags & NET_BUF_EXTERNAL_DATA) { - return; - } - - pool->alloc->cb->unref(buf, data); -} - #if defined(CONFIG_NET_BUF_LOG) struct net_buf *net_buf_alloc_len_debug(struct net_buf_pool *pool, size_t size, k_timeout_t timeout, const char *func, @@ -484,11 +473,6 @@ void net_buf_unref(struct net_buf *buf) return; } - if (buf->__buf) { - data_unref(buf, buf->__buf); - buf->__buf = NULL; - } - buf->data = NULL; buf->frags = NULL; From 341e571cfb9c4d1826ffde0e448870eca84c46e3 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 13 Nov 2023 13:02:07 +0100 Subject: [PATCH 0430/1049] tests: audio: mocks: Add k_work_schedule mock implementation This adds k_work_schedule mock implementation that will be used in bluetooth audio unit tests. Signed-off-by: Mariusz Skamra --- .../audio/mocks/include/mock_kernel.h | 1 - tests/bluetooth/audio/mocks/src/kernel.c | 37 +++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/tests/bluetooth/audio/mocks/include/mock_kernel.h b/tests/bluetooth/audio/mocks/include/mock_kernel.h index 8da6a064cda9fc6..360ff79f4165daa 100644 --- a/tests/bluetooth/audio/mocks/include/mock_kernel.h +++ b/tests/bluetooth/audio/mocks/include/mock_kernel.h @@ -15,7 +15,6 @@ void mock_kernel_init(void); void mock_kernel_cleanup(void); DECLARE_FAKE_VALUE_FUNC(k_ticks_t, z_timeout_remaining, const struct _timeout *); -DECLARE_FAKE_VALUE_FUNC(int, k_work_schedule, struct k_work_delayable *, k_timeout_t); DECLARE_FAKE_VALUE_FUNC(bool, k_work_cancel_delayable_sync, struct k_work_delayable *, struct k_work_sync *); DECLARE_FAKE_VALUE_FUNC(int, k_sem_take, struct k_sem *, k_timeout_t); diff --git a/tests/bluetooth/audio/mocks/src/kernel.c b/tests/bluetooth/audio/mocks/src/kernel.c index 03dc2cf582d3990..5cd8bbbd85293dc 100644 --- a/tests/bluetooth/audio/mocks/src/kernel.c +++ b/tests/bluetooth/audio/mocks/src/kernel.c @@ -6,6 +6,7 @@ */ #include +#include #include #include "mock_kernel.h" @@ -13,14 +14,12 @@ /* List of fakes used by this unit tester */ #define FFF_FAKES_LIST(FAKE) \ FAKE(z_timeout_remaining) \ - FAKE(k_work_schedule) \ FAKE(k_work_cancel_delayable_sync) \ /* List of k_work items to be worked. */ static sys_slist_t work_pending; DEFINE_FAKE_VALUE_FUNC(k_ticks_t, z_timeout_remaining, const struct _timeout *); -DEFINE_FAKE_VALUE_FUNC(int, k_work_schedule, struct k_work_delayable *, k_timeout_t); DEFINE_FAKE_VALUE_FUNC(bool, k_work_cancel_delayable_sync, struct k_work_delayable *, struct k_work_sync *); DEFINE_FAKE_VALUE_FUNC(int, k_sem_take, struct k_sem *, k_timeout_t); @@ -32,19 +31,49 @@ void k_work_init_delayable(struct k_work_delayable *dwork, k_work_handler_t hand } int k_work_reschedule(struct k_work_delayable *dwork, k_timeout_t delay) +{ + bool on_list = false; + struct k_work *work; + + dwork->timeout.dticks = delay.ticks; + + /* Determine whether the work item is queued already. */ + SYS_SLIST_FOR_EACH_CONTAINER(&work_pending, work, node) { + on_list = work == &dwork->work; + if (on_list) { + break; + } + } + + if (dwork->timeout.dticks == 0) { + dwork->work.handler(&dwork->work); + if (on_list) { + (void)sys_slist_remove(&work_pending, NULL, &dwork->work.node); + } + } else if (!on_list) { + sys_slist_append(&work_pending, &dwork->work.node); + } + + return 0; +} + +int k_work_schedule(struct k_work_delayable *dwork, k_timeout_t delay) { struct k_work *work; /* Determine whether the work item is queued already. */ SYS_SLIST_FOR_EACH_CONTAINER(&work_pending, work, node) { if (work == &dwork->work) { - dwork->timeout.dticks = delay.ticks; return 0; } } dwork->timeout.dticks = delay.ticks; - sys_slist_append(&work_pending, &dwork->work.node); + if (dwork->timeout.dticks == 0) { + dwork->work.handler(&dwork->work); + } else { + sys_slist_append(&work_pending, &dwork->work.node); + } return 0; } From ba6142050493eb5f6b0f1233cf4a313eb4d162b5 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 13 Nov 2023 10:44:15 +0100 Subject: [PATCH 0431/1049] Bluetooth: audio: ascs: Retry ASE state notifications on error This adds retry logic for ASE state notifications if failed due to insufficient number of buffers to send ATT PDU. The state transition is retried after connection interval delay. Fixes: #64574 Signed-off-by: Mariusz Skamra --- .../bluetooth/unicast_audio_server/prj.conf | 4 - subsys/bluetooth/audio/ascs.c | 236 +++++++++++------- 2 files changed, 143 insertions(+), 97 deletions(-) diff --git a/samples/bluetooth/unicast_audio_server/prj.conf b/samples/bluetooth/unicast_audio_server/prj.conf index 6fd0c50158574f1..3aec74ddbcc65d0 100644 --- a/samples/bluetooth/unicast_audio_server/prj.conf +++ b/samples/bluetooth/unicast_audio_server/prj.conf @@ -14,7 +14,3 @@ CONFIG_BT_ATT_PREPARE_COUNT=1 CONFIG_BT_EXT_ADV=y CONFIG_BT_DEVICE_NAME="Unicast Audio Server" - -# Due to https://github.com/zephyrproject-rtos/zephyr/issues/64574 we need to increase the number -# of L2CAP buffers -CONFIG_BT_L2CAP_TX_BUF_COUNT=4 diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 94cff37f6b71ab8..116071d4c0f661c 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -61,7 +61,7 @@ static struct bt_ascs_ase { struct bt_bap_ep ep; const struct bt_gatt_attr *attr; struct k_work_delayable disconnect_work; - struct k_work state_transition_work; + struct k_work_delayable state_transition_work; enum bt_bap_ep_state state_pending; bool unexpected_iso_link_loss; } ase_pool[CONFIG_BT_ASCS_MAX_ACTIVE_ASES]; @@ -124,56 +124,51 @@ static void ase_free(struct bt_ascs_ase *ase) bt_conn_unref(ase->conn); ase->conn = NULL; - (void)k_work_cancel(&ase->state_transition_work); + (void)k_work_cancel_delayable(&ase->disconnect_work); + (void)k_work_cancel_delayable(&ase->state_transition_work); } -static void ase_status_changed(struct bt_ascs_ase *ase, uint8_t state) +static int ase_state_notify(struct bt_ascs_ase *ase) { + const uint8_t att_ntf_header_size = 3; /* opcode (1) + handle (2) */ struct bt_conn *conn = ase->conn; + struct bt_conn_info conn_info; + uint16_t max_ntf_size; + uint16_t ntf_size; + int err; - LOG_DBG("ase %p id 0x%02x %s -> %s", ase, ase->ep.status.id, - bt_bap_ep_state_str(ascs_ep_get_state(&ase->ep)), bt_bap_ep_state_str(state)); - - ase->ep.status.state = state; + __ASSERT_NO_MSG(conn != NULL); - if (conn != NULL) { - struct bt_conn_info conn_info; - int err; + err = bt_conn_get_info(conn, &conn_info); + __ASSERT_NO_MSG(err == 0); - err = bt_conn_get_info(conn, &conn_info); - if (err != 0) { - LOG_ERR("Failed to get conn %p info: %d", (void *)conn, err); + if (conn_info.state != BT_CONN_STATE_CONNECTED || + !bt_gatt_is_subscribed(conn, ase->attr, BT_GATT_CCC_NOTIFY)) { + return 0; + } - return; - } + err = k_sem_take(&ase_buf_sem, ASE_BUF_SEM_TIMEOUT); + if (err != 0) { + LOG_WRN("Failed to take ase_buf_sem: %d", err); - if (conn_info.state == BT_CONN_STATE_CONNECTED && - bt_gatt_is_subscribed(conn, ase->attr, BT_GATT_CCC_NOTIFY)) { - const uint8_t att_ntf_header_size = 3; /* opcode (1) + handle (2) */ - const uint16_t max_ntf_size = bt_gatt_get_mtu(conn) - att_ntf_header_size; - uint16_t ntf_size; + return err; + } - err = k_sem_take(&ase_buf_sem, ASE_BUF_SEM_TIMEOUT); - if (err != 0) { - LOG_DBG("Failed to take ase_buf_sem: %d", err); + ascs_ep_get_status(&ase->ep, &ase_buf); - return; - } + max_ntf_size = bt_gatt_get_mtu(conn) - att_ntf_header_size; - ascs_ep_get_status(&ase->ep, &ase_buf); + ntf_size = MIN(max_ntf_size, ase_buf.len); + if (ntf_size < ase_buf.len) { + LOG_DBG("Sending truncated notification (%u / %u)", + ntf_size, ase_buf.len); + } - ntf_size = MIN(max_ntf_size, ase_buf.len); - if (ntf_size < ase_buf.len) { - LOG_DBG("Sending truncated notification (%u / %u)", - ntf_size, ase_buf.len); - } + err = bt_gatt_notify(conn, ase->attr, ase_buf.data, ntf_size); - err = bt_gatt_notify(conn, ase->attr, ase_buf.data, ntf_size); - __ASSERT_NO_MSG(err == 0); + k_sem_give(&ase_buf_sem); - k_sem_give(&ase_buf_sem); - } - } + return err; } static void ascs_disconnect_stream_work_handler(struct k_work *work) @@ -243,7 +238,7 @@ static int ascs_disconnect_stream(struct bt_bap_stream *stream) K_MSEC(CONFIG_BT_ASCS_ISO_DISCONNECT_DELAY)); } -static void ase_set_state_idle(struct bt_ascs_ase *ase) +static void ase_enter_state_idle(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; @@ -252,8 +247,6 @@ static void ase_set_state_idle(struct bt_ascs_ase *ase) ase->ep.receiver_ready = false; - ase_status_changed(ase, BT_BAP_EP_STATE_IDLE); - if (stream->conn != NULL) { bt_conn_unref(stream->conn); stream->conn = NULL; @@ -267,7 +260,7 @@ static void ase_set_state_idle(struct bt_ascs_ase *ase) ase_free(ase); } -static void ase_set_state_codec_configured(struct bt_ascs_ase *ase) +static void ase_enter_state_codec_configured(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; @@ -276,15 +269,13 @@ static void ase_set_state_codec_configured(struct bt_ascs_ase *ase) ase->ep.receiver_ready = false; - ase_status_changed(ase, BT_BAP_EP_STATE_CODEC_CONFIGURED); - ops = stream->ops; if (ops != NULL && ops->configured != NULL) { ops->configured(stream, &ase->ep.qos_pref); } } -static void ase_set_state_qos_configured(struct bt_ascs_ase *ase) +static void ase_enter_state_qos_configured(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; @@ -293,29 +284,22 @@ static void ase_set_state_qos_configured(struct bt_ascs_ase *ase) ase->ep.receiver_ready = false; - ase_status_changed(ase, BT_BAP_EP_STATE_QOS_CONFIGURED); - ops = stream->ops; if (ops != NULL && ops->qos_set != NULL) { ops->qos_set(stream); } } -static void ase_set_state_enabling(struct bt_ascs_ase *ase) +static void ase_enter_state_enabling(struct bt_ascs_ase *ase) { - const bool state_changed = ascs_ep_get_state(&ase->ep) != BT_BAP_EP_STATE_ENABLING; struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; __ASSERT_NO_MSG(stream != NULL); - ase_status_changed(ase, BT_BAP_EP_STATE_ENABLING); - ops = stream->ops; - if (state_changed && ops != NULL && ops->enabled != NULL) { + if (ops != NULL && ops->enabled != NULL) { ops->enabled(stream); - } else if (!state_changed && ops != NULL && ops->metadata_updated != NULL) { - ops->metadata_updated(stream); } /* SINK ASEs can autonomously go into the streaming state if the CIS is connected */ @@ -325,34 +309,61 @@ static void ase_set_state_enabling(struct bt_ascs_ase *ase) } } -static void ase_set_state_streaming(struct bt_ascs_ase *ase) +static void ase_enter_state_streaming(struct bt_ascs_ase *ase) { - const bool state_changed = ascs_ep_get_state(&ase->ep) != BT_BAP_EP_STATE_STREAMING; struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; __ASSERT_NO_MSG(stream != NULL); - ase_status_changed(ase, BT_BAP_EP_STATE_STREAMING); - ops = stream->ops; - if (state_changed && ops != NULL && ops->started != NULL) { + if (ops != NULL && ops->started != NULL) { ops->started(stream); - } else if (!state_changed && ops != NULL && ops->metadata_updated != NULL) { + } +} + +static void ase_metadata_updated(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; + + __ASSERT_NO_MSG(stream != NULL); + + ops = stream->ops; + if (ops != NULL && ops->metadata_updated != NULL) { ops->metadata_updated(stream); } } -static void ase_set_state_disabling(struct bt_ascs_ase *ase) +static void ase_exit_state_streaming(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; + uint8_t reason = ase->ep.reason; __ASSERT_NO_MSG(stream != NULL); - ase->ep.receiver_ready = false; + if (reason == BT_HCI_ERR_SUCCESS) { + /* Default to BT_HCI_ERR_UNSPECIFIED if no other reason is set */ + reason = BT_HCI_ERR_UNSPECIFIED; + } + + ops = stream->ops; + if (ops != NULL && ops->stopped != NULL) { + ops->stopped(stream, reason); + } else { + LOG_WRN("No callback for stopped set"); + } +} - ase_status_changed(ase, BT_BAP_EP_STATE_DISABLING); +static void ase_enter_state_disabling(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; + + __ASSERT_NO_MSG(stream != NULL); + + ase->ep.receiver_ready = false; ops = stream->ops; if (ops != NULL && ops->disabled != NULL) { @@ -360,7 +371,7 @@ static void ase_set_state_disabling(struct bt_ascs_ase *ase) } } -static void ase_set_state_releasing(struct bt_ascs_ase *ase) +static void ase_enter_state_releasing(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; @@ -368,8 +379,6 @@ static void ase_set_state_releasing(struct bt_ascs_ase *ase) ase->ep.receiver_ready = false; - ase_status_changed(ase, BT_BAP_EP_STATE_RELEASING); - /* Either the client or the server may disconnect the CISes when entering the releasing * state. */ @@ -387,52 +396,88 @@ static void ase_set_state_releasing(struct bt_ascs_ase *ase) static void state_transition_work_handler(struct k_work *work) { - struct bt_ascs_ase *ase = CONTAINER_OF(work, struct bt_ascs_ase, state_transition_work); + struct k_work_delayable *d_work = k_work_delayable_from_work(work); + struct bt_ascs_ase *ase = CONTAINER_OF(d_work, struct bt_ascs_ase, state_transition_work); const enum bt_bap_ep_state old_state = ascs_ep_get_state(&ase->ep); const enum bt_bap_ep_state new_state = ase->state_pending; - struct bt_bap_stream *stream = ase->ep.stream; - struct bt_bap_ep *ep = &ase->ep; + int err; - __ASSERT_NO_MSG(stream != NULL); + ase->ep.status.state = new_state; + + /* Notify ASE state */ + if (ase->conn != NULL) { + err = ase_state_notify(ase); + if (err == -ENOMEM) { + struct bt_conn_info info; + uint32_t retry_delay_ms; - /* We left the streaming state, let the upper layers know that the stream is stopped */ - if (old_state != new_state && old_state == BT_BAP_EP_STATE_STREAMING) { - struct bt_bap_stream_ops *ops = stream->ops; - uint8_t reason = ep->reason; + /* Revert back to old state */ + ase->ep.status.state = old_state; + + err = bt_conn_get_info(ase->conn, &info); + __ASSERT_NO_MSG(err == 0); + + retry_delay_ms = BT_CONN_INTERVAL_TO_MS(info.le.interval); + + /* Reschedule the state transition */ + err = k_work_reschedule(d_work, K_MSEC(retry_delay_ms)); + if (err >= 0) { + LOG_WRN("Out of buffers for ase state notification. " + "Will retry in %dms", retry_delay_ms); + return; + } + } - if (reason == BT_HCI_ERR_SUCCESS) { - /* Default to BT_HCI_ERR_UNSPECIFIED if no other reason is set */ - reason = BT_HCI_ERR_UNSPECIFIED; + if (err < 0) { + LOG_ERR("Failed to notify ASE state (err %d)", err); } + } - if (ops != NULL && ops->stopped != NULL) { - ops->stopped(stream, reason); - } else { - LOG_WRN("No callback for stopped set"); + LOG_DBG("ase %p id 0x%02x %s -> %s", ase, ase->ep.status.id, + bt_bap_ep_state_str(old_state), bt_bap_ep_state_str(new_state)); + + if (old_state == new_state) { + switch (new_state) { + case BT_BAP_EP_STATE_ENABLING: + case BT_BAP_EP_STATE_STREAMING: + ase_metadata_updated(ase); + return; + default: + break; } } + /* Actions needed for exiting the old state */ + switch (old_state) { + case BT_BAP_EP_STATE_STREAMING: + ase_exit_state_streaming(ase); + break; + default: + break; + } + + /* Actions needed for entering the new state */ switch (new_state) { case BT_BAP_EP_STATE_IDLE: - ase_set_state_idle(ase); + ase_enter_state_idle(ase); break; case BT_BAP_EP_STATE_CODEC_CONFIGURED: - ase_set_state_codec_configured(ase); + ase_enter_state_codec_configured(ase); break; case BT_BAP_EP_STATE_QOS_CONFIGURED: - ase_set_state_qos_configured(ase); + ase_enter_state_qos_configured(ase); break; case BT_BAP_EP_STATE_ENABLING: - ase_set_state_enabling(ase); + ase_enter_state_enabling(ase); break; case BT_BAP_EP_STATE_STREAMING: - ase_set_state_streaming(ase); + ase_enter_state_streaming(ase); break; case BT_BAP_EP_STATE_DISABLING: - ase_set_state_disabling(ase); + ase_enter_state_disabling(ase); break; case BT_BAP_EP_STATE_RELEASING: - ase_set_state_releasing(ase); + ase_enter_state_releasing(ase); break; default: __ASSERT_PRINT("Invalid state %d", new_state); @@ -533,9 +578,9 @@ int ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state) ase->state_pending = state; - err = k_work_submit(&ase->state_transition_work); + err = k_work_schedule(&ase->state_transition_work, K_NO_WAIT); if (err < 0) { - LOG_ERR("Failed to submit state transition work err %d", err); + LOG_ERR("Failed to schedule state transition work err %d", err); return err; } @@ -1020,6 +1065,12 @@ static int ase_release(struct bt_ascs_ase *ase, uint8_t reason, struct bt_bap_as int bt_ascs_release_ase(struct bt_bap_ep *ep) { struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + const enum bt_bap_ep_state state = ascs_ep_get_state(&ase->ep); + + if (state == BT_BAP_EP_STATE_IDLE) { + ase_free(ase); + return 0; + } return ase_release(ase, BT_HCI_ERR_LOCALHOST_TERM_CONN, BT_BAP_ASCS_RSP_NULL); } @@ -1103,12 +1154,12 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) * should expect there to be only a single reference to the bt_conn pointer * from the stack. * We trigger the work handler directly rather than e.g. calling - * ase_set_state_idle to trigger "regular" state change behavior (such) as + * ase_enter_state_idle to trigger "regular" state change behavior (such) as * calling stream->stopped when leaving the streaming state. */ ase->ep.reason = reason; ase->state_pending = BT_BAP_EP_STATE_IDLE; - state_transition_work_handler(&ase->state_transition_work); + state_transition_work_handler(&ase->state_transition_work.work); /* At this point, `ase` object have been free'd */ } } @@ -1205,9 +1256,8 @@ static void ase_init(struct bt_ascs_ase *ase, struct bt_conn *conn, uint8_t id) __ASSERT(ase->attr, "ASE characteristic not found\n"); - k_work_init_delayable(&ase->disconnect_work, - ascs_disconnect_stream_work_handler); - k_work_init(&ase->state_transition_work, state_transition_work_handler); + k_work_init_delayable(&ase->disconnect_work, ascs_disconnect_stream_work_handler); + k_work_init_delayable(&ase->state_transition_work, state_transition_work_handler); } static struct bt_ascs_ase *ase_new(struct bt_conn *conn, uint8_t id) From 71494dd98fff653125e5002a35d7ef98e3f9a666 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 13 Nov 2023 14:26:42 +0100 Subject: [PATCH 0432/1049] tests: bluetooth: ascs: Add test for ASE notificaion retry This adds test for ASE state notification retry. The test verifies whether the state transition is repeated if failed due to notification error. Signed-off-by: Mariusz Skamra --- tests/bluetooth/audio/ascs/src/main.c | 81 ++++++++++++++++++++ tests/bluetooth/audio/ascs/src/test_common.c | 1 + tests/bluetooth/audio/mocks/src/gatt.c | 44 ++++++++++- 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index 126c82d63bb04ed..2937bd6d9165773 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -648,3 +648,84 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries) bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } + +static struct bt_bap_stream *stream_allocated; +static const struct bt_audio_codec_qos_pref qos_pref = + BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 40000, 40000, 40000, 40000); + +static int unicast_server_cb_config_custom_fake(struct bt_conn *conn, const struct bt_bap_ep *ep, + enum bt_audio_dir dir, + const struct bt_audio_codec_cfg *codec_cfg, + struct bt_bap_stream **stream, + struct bt_audio_codec_qos_pref *const pref, + struct bt_bap_ascs_rsp *rsp) +{ + *stream = stream_allocated; + *pref = qos_pref; + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); + + bt_bap_stream_cb_register(*stream, &mock_bap_stream_ops); + + return 0; +} + +ZTEST_F(ascs_test_suite, test_ase_state_notification_retry) +{ + struct bt_bap_stream *stream = &fixture->stream; + struct bt_conn *conn = &fixture->conn; + const struct bt_gatt_attr *ase, *cp; + struct bt_conn_info info; + uint8_t ase_id; + int err; + + if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK)) { + ase = fixture->ase_snk.attr; + ase_id = fixture->ase_snk.id; + } else { + ase = fixture->ase_src.attr; + ase_id = fixture->ase_src.id; + } + + zexpect_not_null(ase); + zassert_not_equal(ase_id, 0x00); + + cp = test_ase_control_point_get(); + zexpect_not_null(cp); + + bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + + stream_allocated = stream; + mock_bap_unicast_server_cb_config_fake.custom_fake = unicast_server_cb_config_custom_fake; + + /* Mock out of buffers case */ + mock_bt_gatt_notify_cb_fake.return_val = -ENOMEM; + + const uint8_t buf[] = { + 0x01, /* Opcode = Config Codec */ + 0x01, /* Number_of_ASEs */ + ase_id, /* ASE_ID[0] */ + 0x01, /* Target_Latency[0] = Target low latency */ + 0x02, /* Target_PHY[0] = LE 2M PHY */ + 0x06, /* Codec_ID[0].Coding_Format = LC3 */ + 0x00, 0x00, /* Codec_ID[0].Company_ID */ + 0x00, 0x00, /* Codec_ID[0].Vendor_Specific_Codec_ID */ + 0x00, /* Codec_Specific_Configuration_Length[0] */ + }; + + cp->write(conn, cp, (void *)buf, sizeof(buf), 0, 0); + + /* Verification */ + expect_bt_bap_stream_ops_configured_not_called(); + + mock_bt_gatt_notify_cb_fake.return_val = 0; + + err = bt_conn_get_info(conn, &info); + zassert_equal(err, 0); + + /* Wait for ASE state notification retry */ + k_sleep(K_MSEC(BT_CONN_INTERVAL_TO_MS(info.le.interval))); + + expect_bt_bap_stream_ops_configured_called_once(stream, EMPTY); + + bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); +} diff --git a/tests/bluetooth/audio/ascs/src/test_common.c b/tests/bluetooth/audio/ascs/src/test_common.c index 941cbc98f02d5fd..17f5bf71e2b7952 100644 --- a/tests/bluetooth/audio/ascs/src/test_common.c +++ b/tests/bluetooth/audio/ascs/src/test_common.c @@ -68,6 +68,7 @@ void test_conn_init(struct bt_conn *conn) conn->info.security.level = BT_SECURITY_L2; conn->info.security.enc_key_size = BT_ENC_KEY_SIZE_MAX; conn->info.security.flags = BT_SECURITY_FLAG_OOB | BT_SECURITY_FLAG_SC; + conn->info.le.interval = BT_GAP_INIT_CONN_INT_MIN; } const struct bt_gatt_attr *test_ase_control_point_get(void) diff --git a/tests/bluetooth/audio/mocks/src/gatt.c b/tests/bluetooth/audio/mocks/src/gatt.c index d020306b04dcce8..29ab2ee2b0d5bbe 100644 --- a/tests/bluetooth/audio/mocks/src/gatt.c +++ b/tests/bluetooth/audio/mocks/src/gatt.c @@ -60,12 +60,38 @@ void mock_bt_gatt_init(void) mock_bt_gatt_is_subscribed_fake.return_val = true; } -static void notify_params_deep_copy_destroy(void) +static void notify_params_deep_copy_destroy(struct bt_gatt_notify_params *params) { struct bt_gatt_notify_params *copy; for (unsigned int i = 0; i < mock_bt_gatt_notify_cb_fake.call_count; i++) { copy = mock_bt_gatt_notify_cb_fake.arg1_history[i]; + if (copy != params) { + continue; + } + + /* Free UUID deep copy */ + if (copy->uuid) { + free((void *)copy->uuid); + } + + free(copy); + + mock_bt_gatt_notify_cb_fake.arg1_history[i] = NULL; + + break; + } +} + +static void notify_params_deep_copy_destroy_all(void) +{ + struct bt_gatt_notify_params *copy; + + for (unsigned int i = 0; i < mock_bt_gatt_notify_cb_fake.call_count; i++) { + copy = mock_bt_gatt_notify_cb_fake.arg1_history[i]; + if (copy == NULL) { + continue; + } /* Free UUID deep copy */ if (copy->uuid) { @@ -78,7 +104,7 @@ static void notify_params_deep_copy_destroy(void) void mock_bt_gatt_cleanup(void) { - notify_params_deep_copy_destroy(); + notify_params_deep_copy_destroy_all(); } static struct bt_uuid *uuid_deep_copy(const struct bt_uuid *uuid) @@ -126,6 +152,9 @@ static struct bt_gatt_notify_params *notify_params_deep_copy(struct bt_gatt_noti int bt_gatt_notify_cb(struct bt_conn *conn, struct bt_gatt_notify_params *params) { + struct bt_gatt_notify_params *copy; + int err; + zassert_not_null(params, "'%s()' was called with incorrect '%s' value", __func__, "params"); /* Either params->uuid, params->attr, or both has to be provided */ @@ -133,12 +162,19 @@ int bt_gatt_notify_cb(struct bt_conn *conn, struct bt_gatt_notify_params *params "'%s()' was called with incorrect '%s' value", __func__, "params->uuid or params->attr"); - return mock_bt_gatt_notify_cb(conn, notify_params_deep_copy(params)); + copy = notify_params_deep_copy(params); + + err = mock_bt_gatt_notify_cb(conn, copy); + if (err != 0) { + notify_params_deep_copy_destroy(copy); + } + + return err; } void bt_gatt_notify_cb_reset(void) { - notify_params_deep_copy_destroy(); + notify_params_deep_copy_destroy_all(); RESET_FAKE(mock_bt_gatt_notify_cb); } From 51ce9c583cd4b4314ed3a35d0c31d1349e3fdb1c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 13 Nov 2023 16:37:18 +0100 Subject: [PATCH 0433/1049] samples/net/lwm2m_client: Move from native_posix to native_sim * In the sample doc, replace native_posix references with native_sim * Provide an overlay for native_sim * Enable native_sim in the test yaml Signed-off-by: Alberto Escolar Piedras --- samples/net/lwm2m_client/README.rst | 2 +- samples/net/lwm2m_client/boards/native_sim.conf | 5 +++++ samples/net/lwm2m_client/sample.yaml | 10 ++++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 samples/net/lwm2m_client/boards/native_sim.conf diff --git a/samples/net/lwm2m_client/README.rst b/samples/net/lwm2m_client/README.rst index 4e231ba005112ca..50e22c30887061f 100644 --- a/samples/net/lwm2m_client/README.rst +++ b/samples/net/lwm2m_client/README.rst @@ -68,7 +68,7 @@ Build the lwm2m-client sample application like this: :compact: The easiest way to setup this sample application is to build and run it -as native POSIX application or as a QEMU target using the default configuration :file:`prj.conf`. +as a native_sim application or as a QEMU target using the default configuration :file:`prj.conf`. This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_posix`. Download and run the latest build of the Leshan Demo Server: diff --git a/samples/net/lwm2m_client/boards/native_sim.conf b/samples/net/lwm2m_client/boards/native_sim.conf new file mode 100644 index 000000000000000..3e21f837f7c2efe --- /dev/null +++ b/samples/net/lwm2m_client/boards/native_sim.conf @@ -0,0 +1,5 @@ +CONFIG_DNS_RESOLVER=y +CONFIG_DNS_SERVER_IP_ADDRESSES=y +CONFIG_DNS_SERVER1="192.0.2.2" +CONFIG_LWM2M_DNS_SUPPORT=y +CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" diff --git a/samples/net/lwm2m_client/sample.yaml b/samples/net/lwm2m_client/sample.yaml index 8faf0e613e5f17b..9c0cada2c1fa09f 100644 --- a/samples/net/lwm2m_client/sample.yaml +++ b/samples/net/lwm2m_client/sample.yaml @@ -10,6 +10,7 @@ tests: - frdm_k64f - pinnacle_100_dvk - mg100 + - native_sim integration_platforms: - qemu_x86 tags: @@ -18,7 +19,9 @@ tests: sample.net.lwm2m_client.all_objects: harness: net depends_on: netif - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim integration_platforms: - qemu_x86 tags: @@ -43,6 +46,7 @@ tests: - frdm_k64f - pinnacle_100_dvk - mg100 + - native_sim integration_platforms: - qemu_x86 tags: @@ -63,7 +67,9 @@ tests: harness: net depends_on: netif extra_args: OVERLAY_CONFIG=overlay-queue.conf - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim integration_platforms: - qemu_x86 tags: From f4a63aa7aea71b4365c75cf2357daaec0516e1a6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 13 Nov 2023 16:39:56 +0100 Subject: [PATCH 0434/1049] samples/net/tftp_client: Move from native_posix to native_sim * In the sample doc, replace native_posix references with native_sim * Provide an overlay for native_sim * Enable native_sim in the test yaml Signed-off-by: Alberto Escolar Piedras --- samples/net/tftp_client/README.rst | 8 ++++---- samples/net/tftp_client/boards/native_sim.conf | 3 +++ samples/net/tftp_client/sample.yaml | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 samples/net/tftp_client/boards/native_sim.conf diff --git a/samples/net/tftp_client/README.rst b/samples/net/tftp_client/README.rst index 40da21adcf6f939..aaf8444a8040a7b 100644 --- a/samples/net/tftp_client/README.rst +++ b/samples/net/tftp_client/README.rst @@ -41,15 +41,15 @@ Build the tftp-client sample application like this: :compact: The easiest way to setup this sample application is to build and run it -as native POSIX application or as a QEMU target using the default configuration :file:`prj.conf`. +as a native_sim application or as a QEMU target using the default configuration :file:`prj.conf`. This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_posix`. -Build the tftp-client sample application for native_posix like this: +Build the tftp-client sample application for :ref:`native_sim ` like this: .. zephyr-app-commands:: :zephyr-app: samples/net/tftp_client :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: @@ -70,7 +70,7 @@ configurations in ``prj.conf``:: Sample output ================================== -Sample run on native_posix platform with TFTP server on host machine +Sample run on native_sim platform with TFTP server on host machine Launch net-setup.sh in net-tools .. code-block:: console diff --git a/samples/net/tftp_client/boards/native_sim.conf b/samples/net/tftp_client/boards/native_sim.conf new file mode 100644 index 000000000000000..1e9e27b074ea10a --- /dev/null +++ b/samples/net/tftp_client/boards/native_sim.conf @@ -0,0 +1,3 @@ +CONFIG_DNS_RESOLVER=y +CONFIG_DNS_SERVER_IP_ADDRESSES=y +CONFIG_DNS_SERVER1="192.0.2.2" diff --git a/samples/net/tftp_client/sample.yaml b/samples/net/tftp_client/sample.yaml index baabc4790b4cb4f..3ccedecafe997eb 100644 --- a/samples/net/tftp_client/sample.yaml +++ b/samples/net/tftp_client/sample.yaml @@ -7,8 +7,9 @@ tests: depends_on: netif platform_allow: - native_posix + - native_sim integration_platforms: - - native_posix + - native_sim tags: - net - tftp From e44c43cc2c240885f68d9ff61ec41a23f07946e3 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 11:54:11 +0100 Subject: [PATCH 0435/1049] docs: Networking with native_posix: Rename Rename Networking with native_posix to Networking with native_sim replace all links to this page accordingly and replace its references to native_posix with native_sim. Background: during this release native_sim is replacing native_posix as the main host test/development platform. Signed-off-by: Alberto Escolar Piedras --- ...e_posix_setup.rst => native_sim_setup.rst} | 24 +++++++++---------- .../networking/networking_with_host.rst | 4 ++-- samples/net/gptp/README.rst | 4 ++-- samples/net/lwm2m_client/README.rst | 4 ++-- samples/net/tftp_client/README.rst | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) rename doc/connectivity/networking/{native_posix_setup.rst => native_sim_setup.rst} (73%) diff --git a/doc/connectivity/networking/native_posix_setup.rst b/doc/connectivity/networking/native_sim_setup.rst similarity index 73% rename from doc/connectivity/networking/native_posix_setup.rst rename to doc/connectivity/networking/native_sim_setup.rst index cc94c9f790bc367..166ff707c899e88 100644 --- a/doc/connectivity/networking/native_posix_setup.rst +++ b/doc/connectivity/networking/native_sim_setup.rst @@ -1,18 +1,18 @@ -.. _networking_with_native_posix: +.. _networking_with_native_sim: -Networking with native_posix board -################################## +Networking with native_sim board +################################ .. contents:: :local: :depth: 2 This page describes how to set up a virtual network between a (Linux) host -and a Zephyr application running in a native_posix board. +and a Zephyr application running in a :ref:`native_sim ` board. In this example, the :zephyr:code-sample:`sockets-echo-server` sample application from -the Zephyr source distribution is run in native_posix board. The Zephyr -native_posix board instance is connected to a Linux host using a tuntap device +the Zephyr source distribution is run in native_sim board. The Zephyr +native_sim board instance is connected to a Linux host using a tuntap device which is modeled in Linux as an Ethernet network interface. Prerequisites @@ -35,13 +35,13 @@ For the steps below, you will need three terminal windows: directory (``cd net-tools``) * Terminal #2 is your usual Zephyr development terminal, with the Zephyr environment initialized. -* Terminal #3 is the console to the running Zephyr native_posix +* Terminal #3 is the console to the running Zephyr native_sim instance (optional). Step 1 - Create Ethernet interface ================================== -Before starting native_posix with network emulation, a network interface +Before starting native_sim with network emulation, a network interface should be created. In terminal #1, type: @@ -58,8 +58,8 @@ by running ``net-setup.sh`` like this: ./net-setup.sh --help -Step 2 - Start app in native_posix board -======================================== +Step 2 - Start app in native_sim board +====================================== Build and start the ``echo_server`` sample application. @@ -68,7 +68,7 @@ In terminal #2, type: .. zephyr-app-commands:: :zephyr-app: samples/net/sockets/echo_server :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: @@ -78,7 +78,7 @@ Step 3 - Connect to console (optional) The console window should be launched automatically when the Zephyr instance is started but if it does not show up, you can manually connect to the console. -The native_posix board will print a string like this when it starts: +The native_sim board will print a string like this when it starts: .. code-block:: console diff --git a/doc/connectivity/networking/networking_with_host.rst b/doc/connectivity/networking/networking_with_host.rst index 063e065730aaa7a..07288b2cb2b5266 100644 --- a/doc/connectivity/networking/networking_with_host.rst +++ b/doc/connectivity/networking/networking_with_host.rst @@ -7,7 +7,7 @@ Networking with the host system :maxdepth: 1 :hidden: - native_posix_setup.rst + native_sim_setup.rst qemu_eth_setup.rst qemu_setup.rst usbnet_setup.rst @@ -60,7 +60,7 @@ possible: can attach host debugger directly to the running Zephyr instance. This requires that there is an adaptation driver in Zephyr for interfacing with the host system. An Ethernet driver exists in Zephyr for this purpose. - See :ref:`networking_with_native_posix` for details. + See :ref:`networking_with_native_sim` for details. * USB device networking. diff --git a/samples/net/gptp/README.rst b/samples/net/gptp/README.rst index a2c8696d95a3c21..08dd668c795c296 100644 --- a/samples/net/gptp/README.rst +++ b/samples/net/gptp/README.rst @@ -19,13 +19,13 @@ Requirements ************ For generic host connectivity, that can be used for debugging purposes, see -:ref:`networking_with_native_posix` for details. +:ref:`networking_with_native_sim` for details. Building and Running ******************** A good way to run this sample is to run this gPTP application inside -native_posix board as described in :ref:`networking_with_native_posix` or with +native_posix board as described in :ref:`networking_with_native_sim` or with embedded device like NXP FRDM-K64F, Nucleo-H743-ZI, Nucleo-H745ZI-Q, Nucleo-F767ZI or Atmel SAM-E70 Xplained. Note that gPTP is only supported for boards that have an Ethernet port and which has support for collecting diff --git a/samples/net/lwm2m_client/README.rst b/samples/net/lwm2m_client/README.rst index 50e22c30887061f..2225f789c0c8151 100644 --- a/samples/net/lwm2m_client/README.rst +++ b/samples/net/lwm2m_client/README.rst @@ -25,7 +25,7 @@ The source code for this sample application can be found at: Requirements ************ -- :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` or :ref:`networking_with_native_posix` +- :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` or :ref:`networking_with_native_sim` - Linux machine - Leshan Demo Server (https://eclipse.org/leshan/) @@ -69,7 +69,7 @@ Build the lwm2m-client sample application like this: The easiest way to setup this sample application is to build and run it as a native_sim application or as a QEMU target using the default configuration :file:`prj.conf`. -This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_posix`. +This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_sim`. Download and run the latest build of the Leshan Demo Server: diff --git a/samples/net/tftp_client/README.rst b/samples/net/tftp_client/README.rst index aaf8444a8040a7b..a6c684da5b0a5d5 100644 --- a/samples/net/tftp_client/README.rst +++ b/samples/net/tftp_client/README.rst @@ -19,7 +19,7 @@ The source code for this sample application can be found at: Requirements ************ -- :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` or :ref:`networking_with_native_posix` +- :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` or :ref:`networking_with_native_sim` - Linux machine Building and Running @@ -42,7 +42,7 @@ Build the tftp-client sample application like this: The easiest way to setup this sample application is to build and run it as a native_sim application or as a QEMU target using the default configuration :file:`prj.conf`. -This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_posix`. +This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_sim`. Build the tftp-client sample application for :ref:`native_sim ` like this: From d0f554dd6a5f2dc8bc8e19943595557710591943 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 12:07:22 +0100 Subject: [PATCH 0436/1049] docs: networing: Replace references to native_posix w native_sim Let's replace the references to native_posix with native_sim. Background: during this release native_sim is replacing native_posix as the main host test/development platform. Signed-off-by: Alberto Escolar Piedras --- doc/connectivity/networking/api/gptp.rst | 2 +- doc/connectivity/networking/network_monitoring.rst | 6 +++--- .../networking/networking_with_host.rst | 4 ++-- .../networking_with_multiple_instances.rst | 14 +++++++------- samples/net/sockets/coap_client/README.rst | 2 +- samples/net/sockets/net_mgmt/README.rst | 4 ++-- samples/net/stats/README.rst | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/doc/connectivity/networking/api/gptp.rst b/doc/connectivity/networking/api/gptp.rst index 12dedeaab0b4eec..58788ee003d63b4 100644 --- a/doc/connectivity/networking/api/gptp.rst +++ b/doc/connectivity/networking/api/gptp.rst @@ -40,7 +40,7 @@ Boards supported: - :ref:`nucleo_h745zi_q_board` - :ref:`nucleo_f767zi_board` - :ref:`sam_e70_xplained` -- :ref:`native_posix` (only usable for simple testing, limited capabilities +- :ref:`native_sim` (only usable for simple testing, limited capabilities due to lack of hardware clock) - :ref:`qemu_x86` (emulated, limited capabilities due to lack of hardware clock) diff --git a/doc/connectivity/networking/network_monitoring.rst b/doc/connectivity/networking/network_monitoring.rst index b0a20b287d08397..a5f2dcfee7140a6 100644 --- a/doc/connectivity/networking/network_monitoring.rst +++ b/doc/connectivity/networking/network_monitoring.rst @@ -104,7 +104,7 @@ need to terminate the network connection like this. Zephyr Configuration ******************** -In this example, we use ``native_posix`` board. You can also use any other board +In this example, we use the ``native_sim`` board. You can also use any other board that supports networking. In terminal #3, type: @@ -112,7 +112,7 @@ In terminal #3, type: .. zephyr-app-commands:: :zephyr-app: samples/net/capture :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD=\""gnome-terminal -- screen %s"\" :goals: build :compact: @@ -189,7 +189,7 @@ Then we need to enable the network packet monitoring like this: net capture enable 2 The ``2`` tells the network interface which traffic we want to capture. In -this example, the ``2`` is the ``native_posix`` board Ethernet interface. +this example, the ``2`` is the ``native_sim`` board Ethernet interface. Note that we send the network traffic to the same interface that we are monitoring in this example. The monitoring system avoids to capture already captured network traffic as that would lead to recursion. diff --git a/doc/connectivity/networking/networking_with_host.rst b/doc/connectivity/networking/networking_with_host.rst index 07288b2cb2b5266..995e7dc0f801a4b 100644 --- a/doc/connectivity/networking/networking_with_host.rst +++ b/doc/connectivity/networking/networking_with_host.rst @@ -53,7 +53,7 @@ possible: the host on which the model is running. See :ref:`networking_with_armfvp` for details. -* native_posix board. +* native_sim board. * The Zephyr instance can be executed as a user space process in the host system. This is the most convenient way to debug the Zephyr system as one @@ -70,7 +70,7 @@ possible: * Connecting multiple Zephyr instances together. - * If you have multiple Zephyr instances, either QEMU or native_posix ones, + * If you have multiple Zephyr instances, either QEMU or native_sim ones, and want to create a connection between them, see :ref:`networking_with_multiple_instances` for details. diff --git a/doc/connectivity/networking/networking_with_multiple_instances.rst b/doc/connectivity/networking/networking_with_multiple_instances.rst index c83f7e04ed6554e..6489db455514652 100644 --- a/doc/connectivity/networking/networking_with_multiple_instances.rst +++ b/doc/connectivity/networking/networking_with_multiple_instances.rst @@ -9,7 +9,7 @@ Networking with multiple Zephyr instances This page describes how to set up a virtual network between multiple Zephyr instances. The Zephyr instances could be running inside QEMU -or could be native_posix board processes. The Linux host can be used +or could be native_sim board processes. The Linux host can be used to route network traffic between these systems. Prerequisites @@ -34,10 +34,10 @@ For the steps below, you will need five terminal windows: with the Zephyr environment initialized. As there are multiple ways to setup the Zephyr network, the example below uses -``qemu_x86`` board with ``e1000`` Ethernet controller and native_posix board +``qemu_x86`` board with ``e1000`` Ethernet controller and native_sim board to simplify the setup instructions. You can use other QEMU boards and drivers if needed, see :ref:`networking_with_eth_qemu` for details. You can also use -two or more native_posix board Zephyr instances and connect them together. +two or more native_sim board Zephyr instances and connect them together. Step 1 - Create configuration files @@ -141,11 +141,11 @@ In terminal #4, if you are using QEMU, type this: -DCONFIG_ETH_QEMU_IFACE_NAME=\"zeth.1\" \ -DCONFIG_ETH_QEMU_EXTRA_ARGS=\"mac=00:00:5e:00:53:01\" -or if you want to use native_posix board, type this: +or if you want to use native_sim board, type this: .. code-block:: console - west build -d build/server -b native_posix -t run \ + west build -d build/server -b native_sim -t run \ samples/net/sockets/echo_server -- \ -DCONFIG_NET_CONFIG_MY_IPV4_ADDR=\"198.51.100.1\" \ -DCONFIG_NET_CONFIG_PEER_IPV4_ADDR=\"203.0.113.1\" \ @@ -172,11 +172,11 @@ In terminal #5, if you are using QEMU, type this: -DCONFIG_ETH_QEMU_IFACE_NAME=\"zeth.2\" \ -DCONFIG_ETH_QEMU_EXTRA_ARGS=\"mac=00:00:5e:00:53:02\" -or if you want to use native_posix board, type this: +or if you want to use native_sim board, type this: .. code-block:: console - west build -d build/client -b native_posix -t run \ + west build -d build/client -b native_sim -t run \ samples/net/sockets/echo_client -- \ -DCONFIG_NET_CONFIG_MY_IPV4_ADDR=\"203.0.113.1\" \ -DCONFIG_NET_CONFIG_PEER_IPV4_ADDR=\"198.51.100.1\" \ diff --git a/samples/net/sockets/coap_client/README.rst b/samples/net/sockets/coap_client/README.rst index a26d632772bfed1..ffcd81978cc317b 100644 --- a/samples/net/sockets/coap_client/README.rst +++ b/samples/net/sockets/coap_client/README.rst @@ -29,7 +29,7 @@ be obtained by using a tool such as tcpdump or wireshark. See the `net-tools`_ project for more details. -This sample can be built and executed on QEMU or native_posix board as described +This sample can be built and executed on QEMU or native_sim board as described in :ref:`networking_with_host`. Sample output diff --git a/samples/net/sockets/net_mgmt/README.rst b/samples/net/sockets/net_mgmt/README.rst index 92d6d8524c79277..c59b8170e31749c 100644 --- a/samples/net/sockets/net_mgmt/README.rst +++ b/samples/net/sockets/net_mgmt/README.rst @@ -34,12 +34,12 @@ Build net-mgmt socket sample application like this: :goals: build :compact: -Example building for the native_posix board: +Example building for the native_sim board: .. zephyr-app-commands:: :zephyr-app: samples/net/sockets/net_mgmt :host-os: unix - :board: native_posix + :board: native_sim :conf: prj.conf :goals: run :compact: diff --git a/samples/net/stats/README.rst b/samples/net/stats/README.rst index 84204d46131e63e..b8a2016c83f3b50 100644 --- a/samples/net/stats/README.rst +++ b/samples/net/stats/README.rst @@ -21,7 +21,7 @@ Requirements Building and Running ******************** -A good way to run this sample application is with QEMU or native_posix board +A good way to run this sample application is with QEMU or native_sim board as described in :ref:`networking_with_host`. Follow these steps to build the network statistics sample application: From 01ae8079e5c3400738679b6fe6f541244c56f85e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 13 Nov 2023 16:53:57 +0100 Subject: [PATCH 0437/1049] samples/net/gptp: Move from native_posix to native_sim * In the sample doc and shell script, replace native_posix references with native_sim * Provide overlays for native_sim(_64) * Enable native_sim in the test yaml Signed-off-by: Alberto Escolar Piedras --- samples/net/gptp/README.rst | 16 ++++++++-------- samples/net/gptp/boards/native_sim.conf | 8 ++++++++ samples/net/gptp/boards/native_sim_64.conf | 8 ++++++++ samples/net/gptp/docker-test.sh | 2 +- samples/net/gptp/sample.yaml | 2 ++ 5 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 samples/net/gptp/boards/native_sim.conf create mode 100644 samples/net/gptp/boards/native_sim_64.conf diff --git a/samples/net/gptp/README.rst b/samples/net/gptp/README.rst index 08dd668c795c296..f0c1b39e9581dd9 100644 --- a/samples/net/gptp/README.rst +++ b/samples/net/gptp/README.rst @@ -25,7 +25,7 @@ Building and Running ******************** A good way to run this sample is to run this gPTP application inside -native_posix board as described in :ref:`networking_with_native_sim` or with +native_sim board as described in :ref:`networking_with_native_sim` or with embedded device like NXP FRDM-K64F, Nucleo-H743-ZI, Nucleo-H745ZI-Q, Nucleo-F767ZI or Atmel SAM-E70 Xplained. Note that gPTP is only supported for boards that have an Ethernet port and which has support for collecting @@ -51,7 +51,7 @@ Setting up Linux Host If you need VLAN support in your network, then the :zephyr_file:`samples/net/vlan/vlan-setup-linux.sh` provides a script that can be executed on the Linux host. It creates two VLANs on the Linux host and creates -routes to Zephyr. If you are using native_posix board, then +routes to Zephyr. If you are using native_sim board, then the ``net-setup.sh`` will create VLAN setup automatically with this command: .. code-block:: console @@ -61,9 +61,9 @@ the ``net-setup.sh`` will create VLAN setup automatically with this command: The OpenAVNU repository at https://github.com/AVnu contains gPTP daemon that can be run in Linux host and which can act as a grandmaster for the IEEE 801.1AS network. Note that OpenAVNU will not work with -native_posix board as that board only supports software timestamping and +native_sim board as that board only supports software timestamping and OpenAVNU only supports hardware timestamping. See instructions at the end -of this chapter how to run linuxptp daemon with native_posix board. +of this chapter how to run linuxptp daemon with native_sim board. Get OpenAvnu/gPTP project sources @@ -126,7 +126,7 @@ By default gPTP in Zephyr will not print any gPTP debug messages to console. One can enable debug prints by setting :kconfig:option:`CONFIG_NET_GPTP_LOG_LEVEL_DBG` in the config file. -For native_posix board, use ``linuxptp`` project as that supports +For native_sim board, use ``linuxptp`` project as that supports software timestamping. Get linuxptp project sources @@ -150,7 +150,7 @@ Multiport Setup If you set :kconfig:option:`CONFIG_NET_GPTP_NUM_PORTS` larger than 1, then gPTP sample will create multiple TSN ports. This configuration is currently only supported -in native_posix board. +in native_sim board. You need to enable the ports in the net-tools. If the number of ports is set to 2, then give following commands to create the network interfaces in host @@ -163,7 +163,7 @@ side: After that you can start ptp4l daemon for both interfaces. Please use two terminals when starting ptp4l daemon. Note that you must use ptp4l as OpenAVNU -does not work with software clock available in native_posix. +does not work with software clock available in native_sim. .. code-block:: console @@ -175,7 +175,7 @@ Compile Zephyr application. .. zephyr-app-commands:: :zephyr-app: samples/net/gptp - :board: native_posix + :board: native_sim :goals: build :compact: diff --git a/samples/net/gptp/boards/native_sim.conf b/samples/net/gptp/boards/native_sim.conf new file mode 100644 index 000000000000000..c514520186c2bbe --- /dev/null +++ b/samples/net/gptp/boards/native_sim.conf @@ -0,0 +1,8 @@ +# Settings for native_posix ethernet driver +CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK=y + +#CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=y +CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:2a" + +# Assume 1 ms accuracy for native_posix simulated clock +CONFIG_NET_GPTP_CLOCK_ACCURACY_1MS=y diff --git a/samples/net/gptp/boards/native_sim_64.conf b/samples/net/gptp/boards/native_sim_64.conf new file mode 100644 index 000000000000000..c514520186c2bbe --- /dev/null +++ b/samples/net/gptp/boards/native_sim_64.conf @@ -0,0 +1,8 @@ +# Settings for native_posix ethernet driver +CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK=y + +#CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=y +CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:2a" + +# Assume 1 ms accuracy for native_posix simulated clock +CONFIG_NET_GPTP_CLOCK_ACCURACY_1MS=y diff --git a/samples/net/gptp/docker-test.sh b/samples/net/gptp/docker-test.sh index 03ab0f48aa7d447..bc791584c0b58d6 100644 --- a/samples/net/gptp/docker-test.sh +++ b/samples/net/gptp/docker-test.sh @@ -14,7 +14,7 @@ start_docker \ "/usr/local/sbin/ptp4l -2 -f /etc/gptp.cfg -m -q -l 6 -S -i eth0" \ || return $? -# For native_posix gPTP run, the delay threshold needs to be huge +# For native_sim gPTP run, the delay threshold needs to be huge start_zephyr "$overlay" "-DCONFIG_NET_SAMPLE_RUN_DURATION=10" \ "-DCONFIG_NET_GPTP_NEIGHBOR_PROP_DELAY_THR=12000000" diff --git a/samples/net/gptp/sample.yaml b/samples/net/gptp/sample.yaml index 0184353569eacfe..a668d6325a5188b 100644 --- a/samples/net/gptp/sample.yaml +++ b/samples/net/gptp/sample.yaml @@ -13,6 +13,8 @@ tests: - sam_e70_xplained - native_posix - native_posix_64 + - native_sim + - native_sim_64 - nucleo_f767zi - nucleo_h743zi - nucleo_h745zi_q_m7 From 2cadcb3df4c924d13f009d2b01178303dc807b81 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 13 Nov 2023 17:01:54 +0100 Subject: [PATCH 0438/1049] samples/net/mqtt_sn_publisher: Move from native_posix to native_sim * In the sample doc, replace native_posix references with native_sim * Provide overlays for native_sim * Enable native_sim in the test yaml Signed-off-by: Alberto Escolar Piedras --- samples/net/mqtt_sn_publisher/README.rst | 2 +- samples/net/mqtt_sn_publisher/boards/native_sim.conf | 1 + samples/net/mqtt_sn_publisher/boards/native_sim_64.conf | 1 + samples/net/mqtt_sn_publisher/sample.yaml | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 samples/net/mqtt_sn_publisher/boards/native_sim.conf create mode 100644 samples/net/mqtt_sn_publisher/boards/native_sim_64.conf diff --git a/samples/net/mqtt_sn_publisher/README.rst b/samples/net/mqtt_sn_publisher/README.rst index 425160e8892375b..48b8dab5dec307c 100644 --- a/samples/net/mqtt_sn_publisher/README.rst +++ b/samples/net/mqtt_sn_publisher/README.rst @@ -67,7 +67,7 @@ Then, locate your zephyr directory and type: .. zephyr-app-commands:: :zephyr-app: samples/net/mqtt_sn_publisher - :board: native_posix_64 + :board: native_sim_64 :goals: run :compact: diff --git a/samples/net/mqtt_sn_publisher/boards/native_sim.conf b/samples/net/mqtt_sn_publisher/boards/native_sim.conf new file mode 100644 index 000000000000000..0843e94acbdbdea --- /dev/null +++ b/samples/net/mqtt_sn_publisher/boards/native_sim.conf @@ -0,0 +1 @@ +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/net/mqtt_sn_publisher/boards/native_sim_64.conf b/samples/net/mqtt_sn_publisher/boards/native_sim_64.conf new file mode 100644 index 000000000000000..0843e94acbdbdea --- /dev/null +++ b/samples/net/mqtt_sn_publisher/boards/native_sim_64.conf @@ -0,0 +1 @@ +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/net/mqtt_sn_publisher/sample.yaml b/samples/net/mqtt_sn_publisher/sample.yaml index 5d37a430ba120f6..ca11e3e96f30f94 100644 --- a/samples/net/mqtt_sn_publisher/sample.yaml +++ b/samples/net/mqtt_sn_publisher/sample.yaml @@ -13,5 +13,6 @@ tests: - qemu_x86 - pinnacle_100_dvk - mg100 + - native_sim_64 integration_platforms: - qemu_x86 From 3e4b3939090963f7f78b82a511429b69a8963989 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 13 Nov 2023 17:08:18 +0100 Subject: [PATCH 0439/1049] samples coap_server: Move from native_posix to native_sim * In the sample doc, replace native_posix references with native_sim * Provide overlays for native_sim * Enable native_sim in the sample yaml * Remove native_posix from the sample yaml platform_allow as it was filtered out by the host libC Signed-off-by: Alberto Escolar Piedras --- samples/net/sockets/coap_server/README.rst | 2 +- samples/net/sockets/coap_server/boards/native_sim.conf | 4 ++++ samples/net/sockets/coap_server/boards/native_sim_64.conf | 4 ++++ samples/net/sockets/coap_server/sample.yaml | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 samples/net/sockets/coap_server/boards/native_sim.conf create mode 100644 samples/net/sockets/coap_server/boards/native_sim_64.conf diff --git a/samples/net/sockets/coap_server/README.rst b/samples/net/sockets/coap_server/README.rst index 89490ad399b736a..a2962b941bedbaa 100644 --- a/samples/net/sockets/coap_server/README.rst +++ b/samples/net/sockets/coap_server/README.rst @@ -44,7 +44,7 @@ or wireshark. See the `net-tools`_ project for more details -This sample can be built and executed on QEMU or native_posix board as +This sample can be built and executed on QEMU or native_sim board as described in :ref:`networking_with_host`. Use this command on the host to run the `libcoap`_ implementation of diff --git a/samples/net/sockets/coap_server/boards/native_sim.conf b/samples/net/sockets/coap_server/boards/native_sim.conf new file mode 100644 index 000000000000000..ac091ebe5db39e9 --- /dev/null +++ b/samples/net/sockets/coap_server/boards/native_sim.conf @@ -0,0 +1,4 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y +CONFIG_NATIVE_UART_0_ON_STDINOUT=y +CONFIG_PICOLIBC=y diff --git a/samples/net/sockets/coap_server/boards/native_sim_64.conf b/samples/net/sockets/coap_server/boards/native_sim_64.conf new file mode 100644 index 000000000000000..ac091ebe5db39e9 --- /dev/null +++ b/samples/net/sockets/coap_server/boards/native_sim_64.conf @@ -0,0 +1,4 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y +CONFIG_NATIVE_UART_0_ON_STDINOUT=y +CONFIG_PICOLIBC=y diff --git a/samples/net/sockets/coap_server/sample.yaml b/samples/net/sockets/coap_server/sample.yaml index 3c0cfe475db8139..2fcf9b6328714cb 100644 --- a/samples/net/sockets/coap_server/sample.yaml +++ b/samples/net/sockets/coap_server/sample.yaml @@ -10,5 +10,5 @@ tests: - net - socket platform_allow: - - native_posix + - native_sim - qemu_x86 From 1d6cfc0543e2755967827e5a09191563096f6fd1 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 13 Nov 2023 17:18:37 +0100 Subject: [PATCH 0440/1049] samples coap_server: Move from native_posix to native_sim * In the sample doc, replace native_posix references with native_sim * Enable native_sim in the sample yaml, and switch integration_platform Signed-off-by: Alberto Escolar Piedras --- samples/net/sockets/packet/README.rst | 2 +- samples/net/sockets/packet/sample.yaml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/samples/net/sockets/packet/README.rst b/samples/net/sockets/packet/README.rst index ea096be0a23f9ca..b9429215061588e 100644 --- a/samples/net/sockets/packet/README.rst +++ b/samples/net/sockets/packet/README.rst @@ -23,7 +23,7 @@ sent and received packets. See the `net-tools`_ project for more details. -This sample can be built and executed on QEMU or native_posix board as +This sample can be built and executed on QEMU or native_sim board as described in :ref:`networking_with_host`. .. _`net-tools`: https://github.com/zephyrproject-rtos/net-tools diff --git a/samples/net/sockets/packet/sample.yaml b/samples/net/sockets/packet/sample.yaml index 66deae9f335374e..d02c03c7d681c7c 100644 --- a/samples/net/sockets/packet/sample.yaml +++ b/samples/net/sockets/packet/sample.yaml @@ -7,8 +7,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - net - sockets From eae281bb338f7c6da201c114f58ce31df3b19ce5 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 13 Nov 2023 17:23:38 +0100 Subject: [PATCH 0441/1049] samples sntp_client: Move from native_posix to native_sim * In the sample doc, replace native_posix references with native_sim * Enable native_sim in the sample yaml Signed-off-by: Alberto Escolar Piedras --- samples/net/sockets/sntp_client/README.rst | 2 +- samples/net/sockets/sntp_client/sample.yaml | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/samples/net/sockets/sntp_client/README.rst b/samples/net/sockets/sntp_client/README.rst index 1e061c36a707a9b..f9a1aacd4b8ffc0 100644 --- a/samples/net/sockets/sntp_client/README.rst +++ b/samples/net/sockets/sntp_client/README.rst @@ -24,7 +24,7 @@ printed. See the `net-tools`_ project for more details. -This sample can be built and executed on QEMU or native_posix board as +This sample can be built and executed on QEMU or native_sim board as described in :ref:`networking_with_qemu`. .. _`net-tools`: https://github.com/zephyrproject-rtos/net-tools diff --git a/samples/net/sockets/sntp_client/sample.yaml b/samples/net/sockets/sntp_client/sample.yaml index 3a87d5995e24933..65d4f2f3b2cc629 100644 --- a/samples/net/sockets/sntp_client/sample.yaml +++ b/samples/net/sockets/sntp_client/sample.yaml @@ -6,13 +6,19 @@ common: tags: net tests: sample.net.sockets.sntp_client: - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim sample.net.sockets.sntp_client.posix_names: - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim extra_configs: - CONFIG_NET_SOCKETS_POSIX_NAMES=y sample.net.sockets.sntp_client.posix: - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim extra_configs: - CONFIG_NET_SOCKETS_POSIX_NAMES=n - CONFIG_POSIX_API=y From b32e57391b32e7d76e0548d56634ab57098ba7a8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 13 Nov 2023 17:24:55 +0100 Subject: [PATCH 0442/1049] samples/net: Move from native_posix to native_sim For several samples that today have native_sim enabled, enable them also for native_sim. And set native_sim as default integration_platform instead of native_posix. Signed-off-by: Alberto Escolar Piedras --- samples/net/ipv4_autoconf/sample.yaml | 4 +++- samples/net/lldp/sample.yaml | 4 +++- samples/net/sockets/txtime/sample.yaml | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/samples/net/ipv4_autoconf/sample.yaml b/samples/net/ipv4_autoconf/sample.yaml index bb1f529ef4b380d..07260fee0add16c 100644 --- a/samples/net/ipv4_autoconf/sample.yaml +++ b/samples/net/ipv4_autoconf/sample.yaml @@ -7,8 +7,10 @@ common: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim sample: description: Test IPv4 autoconf functionality name: IPv4 autoconf sample app diff --git a/samples/net/lldp/sample.yaml b/samples/net/lldp/sample.yaml index 78b61768ee674be..4daf567dca29723 100644 --- a/samples/net/lldp/sample.yaml +++ b/samples/net/lldp/sample.yaml @@ -11,6 +11,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim depends_on: netif diff --git a/samples/net/sockets/txtime/sample.yaml b/samples/net/sockets/txtime/sample.yaml index 98488b70e942687..189f6901bfc76ef 100644 --- a/samples/net/sockets/txtime/sample.yaml +++ b/samples/net/sockets/txtime/sample.yaml @@ -5,10 +5,12 @@ common: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_x86_64 integration_platforms: - - native_posix + - native_sim sample: description: Socket SO_TXTIME sample name: txtime-socket From b4ce96d161d45310a1a553ab31aa7c72a8ef787e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 13 Nov 2023 15:32:09 +0000 Subject: [PATCH 0443/1049] soc: arm: nordic_nrf: Imply XIP instead of select This allows XIP to be disabled for applications that execute in RAM, which do not need XIP support from flash Signed-off-by: Jamie McCrae --- soc/arm/nordic_nrf/nrf51/Kconfig.series | 2 +- soc/arm/nordic_nrf/nrf52/Kconfig.series | 2 +- soc/arm/nordic_nrf/nrf53/Kconfig.series | 2 +- soc/arm/nordic_nrf/nrf91/Kconfig.series | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/soc/arm/nordic_nrf/nrf51/Kconfig.series b/soc/arm/nordic_nrf/nrf51/Kconfig.series index e7028b021909758..c484d44fc30fc9c 100644 --- a/soc/arm/nordic_nrf/nrf51/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf51/Kconfig.series @@ -9,7 +9,7 @@ config SOC_SERIES_NRF51X select ARM select CPU_CORTEX_M0 select SOC_FAMILY_NRF - select XIP + imply XIP select HAS_NRFX select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select HAS_POWEROFF diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.series b/soc/arm/nordic_nrf/nrf52/Kconfig.series index f11bd5cd59f5ab1..d47089cd5953d9e 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.series @@ -10,7 +10,7 @@ config SOC_SERIES_NRF52X select CPU_CORTEX_M4 select CPU_HAS_ARM_MPU select SOC_FAMILY_NRF - select XIP + imply XIP select HAS_NRFX select HAS_NORDIC_DRIVERS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.series b/soc/arm/nordic_nrf/nrf53/Kconfig.series index 8ab81ad310bda5b..28d1c10fc1e2f7a 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.series @@ -11,7 +11,7 @@ config SOC_SERIES_NRF53X select CPU_CORTEX_M_HAS_DWT select CPU_HAS_ARM_MPU select SOC_FAMILY_NRF - select XIP + imply XIP select HAS_NRFX select HAS_NORDIC_DRIVERS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.series b/soc/arm/nordic_nrf/nrf91/Kconfig.series index fd8f5b04d7ad3dc..c30132c7bac040b 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.series @@ -13,7 +13,7 @@ config SOC_SERIES_NRF91X select CPU_HAS_FPU select ARMV8_M_DSP select SOC_FAMILY_NRF - select XIP + imply XIP select HAS_NRFX select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select HAS_POWEROFF From a36d4beafa210fa597b6a504a756c4c2b2d1a103 Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Mon, 13 Nov 2023 14:26:05 -0800 Subject: [PATCH 0444/1049] drivers: dma: mcux_lpc: support channel priority Set DMA channel priority in dma_mcux_lpc_configure(). Signed-off-by: Mike J. Chen --- drivers/dma/dma_mcux_lpc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index cd45211e678ab5c..ef0a164d4af5c56 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -583,6 +583,7 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, } else { DMA_DisableChannelPeriphRq(p_handle->base, p_handle->channel); } + DMA_SetChannelPriority(p_handle->base, p_handle->channel, config->channel_priority); data->busy = false; if (config->dma_callback) { From e8c5ca50ccb44335ab55ae8330b0613c5be287e6 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Tue, 14 Nov 2023 18:03:17 -0300 Subject: [PATCH 0445/1049] zbus: make ZBUS_CHANNEL_DECLARE compatible with C++ The current implementation of ZBUS_CHAN_DECLARE is not compatible with C++. It fixes the bug by adding the extern keyword at the channel definition which will work for both C and C++. Signed-off-by: Rodrigo Peixoto --- include/zephyr/zbus/zbus.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/zephyr/zbus/zbus.h b/include/zephyr/zbus/zbus.h index 7e5557ef84e2091..8b2aa05175b38ff 100644 --- a/include/zephyr/zbus/zbus.h +++ b/include/zephyr/zbus/zbus.h @@ -304,6 +304,7 @@ struct zbus_channel_observation { static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \ .observers_start_idx = -1, .observers_end_idx = -1}; \ static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \ + IF_ENABLED(CONFIG_CPP, (extern)) \ const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \ ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \ .message = &_CONCAT(_zbus_message_, _name), \ From f2f81361d8b33a03da8a180e8012888f50e6950f Mon Sep 17 00:00:00 2001 From: Xudong Zheng <7pkvm5aw@slicealias.com> Date: Tue, 14 Nov 2023 21:47:43 -0500 Subject: [PATCH 0446/1049] doc: extensions: kconfig: allow paste event to trigger search The "keyup" event is not triggered when pasting with mouse (right click, paste) or when pasting on a phone/tablet. Signed-off-by: Xudong Zheng <7pkvm5aw@slicealias.com> --- doc/_extensions/zephyr/kconfig/static/kconfig.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_extensions/zephyr/kconfig/static/kconfig.mjs b/doc/_extensions/zephyr/kconfig/static/kconfig.mjs index ae27532ab6a8ef1..6c94845a1079e31 100644 --- a/doc/_extensions/zephyr/kconfig/static/kconfig.mjs +++ b/doc/_extensions/zephyr/kconfig/static/kconfig.mjs @@ -491,7 +491,7 @@ function setupKconfigSearch() { doSearchFromURL(); /* install event listeners */ - input.addEventListener('keyup', () => { + input.addEventListener('input', () => { searchOffset = 0; doSearch(); }); From 2e97e5daa8851387abab4bb284bce77bbe2daf47 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 14 Nov 2023 16:24:00 +0100 Subject: [PATCH 0447/1049] doc: mpsc: Add missed 'end' Adds missed 'end' in the 'Internals' chapter. Signed-off-by: Andrej Butok --- doc/kernel/data_structures/mpsc_pbuf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/kernel/data_structures/mpsc_pbuf.rst b/doc/kernel/data_structures/mpsc_pbuf.rst index 4ecef5b62e476fe..73780d6a42671ac 100644 --- a/doc/kernel/data_structures/mpsc_pbuf.rst +++ b/doc/kernel/data_structures/mpsc_pbuf.rst @@ -54,7 +54,7 @@ Header state: +-------+------+----------------------+ Packet buffer space contains free space, valid user packets and internal skip -packets. Internal skip packets indicates padding, e.g. at the of the buffer. +packets. Internal skip packets indicates padding, e.g. at the end of the buffer. Allocation ^^^^^^^^^^ From 15e92d5e5cf32d98311daf61b0c2014fe95dff57 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 13 Nov 2023 11:40:47 +0000 Subject: [PATCH 0448/1049] input: kbd: make row and col size optional add extra macro Change the row-count and col-count to be optional in the generic binding, add a second pair of macro to allow the implementation to specify the numbers from a different property. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.h | 70 +++++++++++++++++------ dts/bindings/input/kbd-matrix-common.yaml | 2 - dts/bindings/input/nuvoton,npcx-kbd.yaml | 6 ++ 3 files changed, 59 insertions(+), 19 deletions(-) diff --git a/drivers/input/input_kbd_matrix.h b/drivers/input/input_kbd_matrix.h index ec286ab5520294d..400505562bd3e7e 100644 --- a/drivers/input/input_kbd_matrix.h +++ b/drivers/input/input_kbd_matrix.h @@ -56,23 +56,36 @@ struct input_kbd_matrix_common_config { _CONCAT(__input_kbd_matrix_, \ _CONCAT(name, DEVICE_DT_NAME_GET(node_id))) +/** + * @brief Defines the common keyboard matrix support data from devicetree, + * specify row and col count. + */ +#define INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL(node_id, _row_size, _col_size) \ + BUILD_ASSERT(IN_RANGE(_row_size, 1, 8), "invalid row-size"); \ + BUILD_ASSERT(IN_RANGE(_col_size, 1, UINT8_MAX), "invalid col-size"); \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state)[_col_size]; \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state)[_col_size]; \ + static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx)[_row_size * _col_size]; + /** * @brief Defines the common keyboard matrix support data from devicetree. */ #define INPUT_KBD_MATRIX_DT_DEFINE(node_id) \ - BUILD_ASSERT(IN_RANGE(DT_PROP(node_id, row_size), 1, 8), "invalid row-size"); \ - BUILD_ASSERT(IN_RANGE(DT_PROP(node_id, col_size), 1, UINT8_MAX), "invalid col-size"); \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ - node_id, stable_state)[DT_PROP(node_id, col_size)]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ - node_id, unstable_state)[DT_PROP(node_id, col_size)]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ - node_id, previous_state)[DT_PROP(node_id, col_size)]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ - node_id, new_state)[DT_PROP(node_id, col_size)]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \ - node_id, scan_cycle_idx)[DT_PROP(node_id, row_size) * \ - DT_PROP(node_id, col_size)]; + INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL( \ + node_id, DT_PROP(node_id, row_size), DT_PROP(node_id, col_size)) + +/** + * @brief Defines the common keyboard matrix support data from devicetree + * instance, specify row and col count. + * + * @param inst Instance. + * @param row_size The matrix row count. + * @param col_size The matrix column count. + */ +#define INPUT_KBD_MATRIX_DT_INST_DEFINE_ROW_COL(inst, row_size, col_size) \ + INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL(DT_DRV_INST(inst), row_size, col_size) /** * @brief Defines the common keyboard matrix support data from devicetree instance. @@ -83,15 +96,17 @@ struct input_kbd_matrix_common_config { INPUT_KBD_MATRIX_DT_DEFINE(DT_DRV_INST(inst)) /** - * @brief Initialize common keyboard matrix config from devicetree. + * @brief Initialize common keyboard matrix config from devicetree, specify row and col count. * * @param api Pointer to a :c:struct:`input_kbd_matrix_api` structure. + * @param row_size The matrix row count. + * @param col_size The matrix column count. */ -#define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(node_id, _api) \ +#define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL(node_id, _api, _row_size, _col_size) \ { \ .api = _api, \ - .row_size = DT_PROP(node_id, row_size), \ - .col_size = DT_PROP(node_id, col_size), \ + .row_size = _row_size, \ + .col_size = _col_size, \ .poll_period_us = DT_PROP(node_id, poll_period_ms) * USEC_PER_MSEC, \ .poll_timeout_ms = DT_PROP(node_id, poll_timeout_ms), \ .debounce_down_ms = DT_PROP(node_id, debounce_down_ms), \ @@ -106,6 +121,27 @@ struct input_kbd_matrix_common_config { .scan_cycle_idx = INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx), \ } +/** + * @brief Initialize common keyboard matrix config from devicetree. + * + * @param api Pointer to a :c:struct:`input_kbd_matrix_api` structure. + */ +#define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(node_id, _api) \ + INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL( \ + node_id, _api, DT_PROP(node_id, row_size), DT_PROP(node_id, col_size)) + +/** + * @brief Initialize common keyboard matrix config from devicetree instance, + * specify row and col count. + * + * @param inst Instance. + * @param api Pointer to a :c:struct:`input_kbd_matrix_api` structure. + * @param row_size The matrix row count. + * @param col_size The matrix column count. + */ +#define INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT_ROW_COL(inst, api, row_size, col_size) \ + INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL(DT_DRV_INST(inst), api, row_size, col_size) + /** * @brief Initialize common keyboard matrix config from devicetree instance. * diff --git a/dts/bindings/input/kbd-matrix-common.yaml b/dts/bindings/input/kbd-matrix-common.yaml index 53efd29dc9f97d2..e399bd4431fde20 100644 --- a/dts/bindings/input/kbd-matrix-common.yaml +++ b/dts/bindings/input/kbd-matrix-common.yaml @@ -8,13 +8,11 @@ include: base.yaml properties: row-size: type: int - required: true description: | The number of rows in the keyboard matrix. col-size: type: int - required: true description: | The number of column in the keyboard matrix. diff --git a/dts/bindings/input/nuvoton,npcx-kbd.yaml b/dts/bindings/input/nuvoton,npcx-kbd.yaml index 7ba9956cb6b2443..b7c30c5388f08f4 100644 --- a/dts/bindings/input/nuvoton,npcx-kbd.yaml +++ b/dts/bindings/input/nuvoton,npcx-kbd.yaml @@ -29,3 +29,9 @@ properties: For example the WUI mapping on 8 KSI pads would be wui-maps = <&wui_io30 &wui_io31 &wui_io27 &wui_io26 &wui_io25 &wui_io24 &wui_io23 &wui_io22>; + + row-size: + required: true + + col-size: + required: true From 0c00b6e0ab6de34045e04b11a62881a75b7242d6 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 13 Nov 2023 14:16:57 +0000 Subject: [PATCH 0449/1049] input: kbd_matrix: make the api field a pointer The API field of input_kbd_matrix_common_config should have been a pointer from the start, clang-16 caught this with a compiler warning. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 4 ++-- drivers/input/input_kbd_matrix.h | 2 +- drivers/input/input_npcx_kbd.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index d6da7764f739e58..b642e59b800df18 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -74,7 +74,7 @@ static bool input_kbd_matrix_ghosting(const struct device *dev) static bool input_kbd_matrix_scan(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; - const struct input_kbd_matrix_api *api = &cfg->api; + const struct input_kbd_matrix_api *api = cfg->api; int row; uint8_t key_event = 0U; @@ -264,7 +264,7 @@ static void input_kbd_matrix_polling_thread(void *arg1, void *unused2, void *unu { const struct device *dev = arg1; const struct input_kbd_matrix_common_config *cfg = dev->config; - const struct input_kbd_matrix_api *api = &cfg->api; + const struct input_kbd_matrix_api *api = cfg->api; struct input_kbd_matrix_common_data *data = dev->data; ARG_UNUSED(unused2); diff --git a/drivers/input/input_kbd_matrix.h b/drivers/input/input_kbd_matrix.h index 400505562bd3e7e..93aabdd84c83d3f 100644 --- a/drivers/input/input_kbd_matrix.h +++ b/drivers/input/input_kbd_matrix.h @@ -34,7 +34,7 @@ struct input_kbd_matrix_api { * This structure **must** be placed first in the driver's config structure. */ struct input_kbd_matrix_common_config { - struct input_kbd_matrix_api api; + const struct input_kbd_matrix_api *api; uint8_t row_size; uint8_t col_size; uint32_t poll_period_us; diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index 65ef7747875b724..8cb408d621abc54 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -211,7 +211,7 @@ static const struct input_kbd_matrix_api npcx_kbd_api = { }; static const struct input_npcx_kbd_config npcx_kbd_cfg = { - .common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(0, npcx_kbd_api), + .common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(0, &npcx_kbd_api), .base = (struct kbs_reg *)DT_INST_REG_ADDR(0), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), .clk_cfg = NPCX_DT_CLK_CFG_ITEM(0), From 297c41031bb9cec893a9d02257016a699ea2f4de Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 13 Nov 2023 17:23:22 +0000 Subject: [PATCH 0450/1049] doc: input: add a input_kbd_matrix group, fix few missing doc entries Add a input_kbd_matrix doxygen group and add this to the other Input APIs page, add few missing argument documentation entries. Signed-off-by: Fabio Baltieri --- doc/services/input/index.rst | 5 +++ drivers/input/input_kbd_matrix.h | 52 +++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/doc/services/input/index.rst b/doc/services/input/index.rst index 03851d795c0db00..b18c57beb3057df 100644 --- a/doc/services/input/index.rst +++ b/doc/services/input/index.rst @@ -87,3 +87,8 @@ Input Event Definitions *********************** .. doxygengroup:: input_events + +Keyboard Matrix API Reference +***************************** + +.. doxygengroup:: input_kbd_matrix diff --git a/drivers/input/input_kbd_matrix.h b/drivers/input/input_kbd_matrix.h index 93aabdd84c83d3f..06f298890282522 100644 --- a/drivers/input/input_kbd_matrix.h +++ b/drivers/input/input_kbd_matrix.h @@ -4,6 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @brief Keyboard Matrix API + * @defgroup input_kbd_matrix Keyboard Matrix API + * @ingroup io_interfaces + * @{ + */ + #include #include #include @@ -23,8 +30,33 @@ * @brief Keyboard matrix internal APIs. */ struct input_kbd_matrix_api { + /** + * @brief Request to drive a specific column. + * + * Request to drive a specific matrix column, or none, or all. + * + * @param dev Pointer to the keyboard matrix device. + * @param col The column to drive, or + * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE or + * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL. + */ void (*drive_column)(const struct device *dev, int col); + /** + * @brief Read the matrix row. + * + * @param dev Pointer to the keyboard matrix device. + */ int (*read_row)(const struct device *dev); + /** + * @brief Request to put the matrix in detection mode. + * + * Request to put the driver in detection mode, this is called after a + * request to drive all the column and typically involves reenabling + * interrupts row pin changes. + * + * @param dev Pointer to the keyboard matrix device. + * @param enable Whether detection mode has to be enabled or disabled. + */ void (*set_detect_mode)(const struct device *dev, bool enabled); }; @@ -98,9 +130,10 @@ struct input_kbd_matrix_common_config { /** * @brief Initialize common keyboard matrix config from devicetree, specify row and col count. * - * @param api Pointer to a :c:struct:`input_kbd_matrix_api` structure. - * @param row_size The matrix row count. - * @param col_size The matrix column count. + * @param node_id The devicetree node identifier. + * @param _api Pointer to a @ref input_kbd_matrix_api structure. + * @param _row_size The matrix row count. + * @param _col_size The matrix column count. */ #define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL(node_id, _api, _row_size, _col_size) \ { \ @@ -124,18 +157,19 @@ struct input_kbd_matrix_common_config { /** * @brief Initialize common keyboard matrix config from devicetree. * - * @param api Pointer to a :c:struct:`input_kbd_matrix_api` structure. + * @param node_id The devicetree node identifier. + * @param api Pointer to a @ref input_kbd_matrix_api structure. */ -#define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(node_id, _api) \ +#define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(node_id, api) \ INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL( \ - node_id, _api, DT_PROP(node_id, row_size), DT_PROP(node_id, col_size)) + node_id, api, DT_PROP(node_id, row_size), DT_PROP(node_id, col_size)) /** * @brief Initialize common keyboard matrix config from devicetree instance, * specify row and col count. * * @param inst Instance. - * @param api Pointer to a :c:struct:`input_kbd_matrix_api` structure. + * @param api Pointer to a @ref input_kbd_matrix_api structure. * @param row_size The matrix row count. * @param col_size The matrix column count. */ @@ -146,7 +180,7 @@ struct input_kbd_matrix_common_config { * @brief Initialize common keyboard matrix config from devicetree instance. * * @param inst Instance. - * @param api Pointer to a :c:struct:`input_kbd_matrix_api` structure. + * @param api Pointer to a @ref input_kbd_matrix_api structure. */ #define INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(inst, api) \ INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(DT_DRV_INST(inst), api) @@ -202,3 +236,5 @@ void input_kbd_matrix_poll_start(const struct device *dev); * @retval -errno Negative errno in case of failure. */ int input_kbd_matrix_common_init(const struct device *dev); + +/** @} */ From be5cb7af7cab7c23e59648b95c00b1fa54ed588e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 13 Nov 2023 18:18:29 +0000 Subject: [PATCH 0451/1049] input: kbd_matrix: move the header to the project wide include directory Move the input_kbd_matrix.h header out of drivers/ and into include/, this allows external drivers to use it and doxygen to pick it up. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 3 +-- drivers/input/input_npcx_kbd.c | 2 +- {drivers => include/zephyr}/input/input_kbd_matrix.h | 5 +++++ 3 files changed, 7 insertions(+), 3 deletions(-) rename {drivers => include/zephyr}/input/input_kbd_matrix.h (98%) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index b642e59b800df18..f4c49d29d51c782 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -15,8 +16,6 @@ #define LOG_LEVEL CONFIG_INPUT_LOG_LEVEL LOG_MODULE_REGISTER(input_kbd_matrix); -#include "input_kbd_matrix.h" - #define INPUT_KBD_MATRIX_ROW_MASK UINT8_MAX void input_kbd_matrix_poll_start(const struct device *dev) diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index 8cb408d621abc54..1de14726a6d2a0f 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -8,10 +8,10 @@ #define DT_DRV_COMPAT nuvoton_npcx_kbd #include "soc_miwu.h" -#include "input_kbd_matrix.h" #include #include +#include #include #include #include diff --git a/drivers/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h similarity index 98% rename from drivers/input/input_kbd_matrix.h rename to include/zephyr/input/input_kbd_matrix.h index 06f298890282522..0566f14d2cdc2bb 100644 --- a/drivers/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#ifndef ZEPHYR_INCLUDE_INPUT_KBD_MATRIX_H_ +#define ZEPHYR_INCLUDE_INPUT_KBD_MATRIX_H_ + /** * @brief Keyboard Matrix API * @defgroup input_kbd_matrix Keyboard Matrix API @@ -238,3 +241,5 @@ void input_kbd_matrix_poll_start(const struct device *dev); int input_kbd_matrix_common_init(const struct device *dev); /** @} */ + +#endif /* ZEPHYR_INCLUDE_INPUT_KBD_MATRIX_H_ */ From 256bc860cfd387e3b5cc7700bf81fbf55d507183 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 6 Nov 2023 23:31:44 +0000 Subject: [PATCH 0452/1049] input: add a gpio based keyboard matrix driver Add a GPIO based keyboard matrix driver using the generic keyboard matrix code. Signed-off-by: Fabio Baltieri --- drivers/input/CMakeLists.txt | 1 + drivers/input/Kconfig | 1 + drivers/input/Kconfig.gpio_kbd_matrix | 10 ++ drivers/input/input_gpio_kbd_matrix.c | 198 ++++++++++++++++++++++ dts/bindings/input/gpio-kbd-matrix.yaml | 43 +++++ tests/drivers/build_all/input/app.overlay | 9 + 6 files changed, 262 insertions(+) create mode 100644 drivers/input/Kconfig.gpio_kbd_matrix create mode 100644 drivers/input/input_gpio_kbd_matrix.c create mode 100644 dts/bindings/input/gpio-kbd-matrix.yaml diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 96f85ba0e72ef27..d63dc2ae79748e7 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -7,6 +7,7 @@ zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_INPUT_CAP1203 input_cap1203.c) zephyr_library_sources_ifdef(CONFIG_INPUT_CST816S input_cst816s.c) zephyr_library_sources_ifdef(CONFIG_INPUT_FT5336 input_ft5336.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KBD_MATRIX input_gpio_kbd_matrix.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_QDEC input_gpio_qdec.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GT911 input_gt911.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 2a0f8ac8526d9dd..afab00d425976c1 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -9,6 +9,7 @@ menu "Input drivers" source "drivers/input/Kconfig.cap1203" source "drivers/input/Kconfig.cst816s" source "drivers/input/Kconfig.ft5336" +source "drivers/input/Kconfig.gpio_kbd_matrix" source "drivers/input/Kconfig.gpio_keys" source "drivers/input/Kconfig.gpio_qdec" source "drivers/input/Kconfig.gt911" diff --git a/drivers/input/Kconfig.gpio_kbd_matrix b/drivers/input/Kconfig.gpio_kbd_matrix new file mode 100644 index 000000000000000..1ded27c12588157 --- /dev/null +++ b/drivers/input/Kconfig.gpio_kbd_matrix @@ -0,0 +1,10 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_GPIO_KBD_MATRIX + bool "GPIO based keyboard matrix input driver" + default y + depends on DT_HAS_GPIO_KBD_MATRIX_ENABLED + select INPUT_KBD_MATRIX + help + GPIO keyboard matrix input driver. diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c new file mode 100644 index 000000000000000..9d532bfd0af0db2 --- /dev/null +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -0,0 +1,198 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gpio_kbd_matrix + +#include +#include + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(input_gpio_kbd_matrix, CONFIG_INPUT_LOG_LEVEL); + +struct gpio_kbd_matrix_config { + struct input_kbd_matrix_common_config common; + const struct gpio_dt_spec *row_gpio; + const struct gpio_dt_spec *col_gpio; + struct gpio_callback *gpio_cb; + gpio_callback_handler_t handler; +}; + +struct gpio_kbd_matrix_data { + struct input_kbd_matrix_common_data common; + uint32_t last_col_state; +}; + +INPUT_KBD_STRUCT_CHECK(struct gpio_kbd_matrix_config, + struct gpio_kbd_matrix_data); + +static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) +{ + const struct gpio_kbd_matrix_config *cfg = dev->config; + const struct input_kbd_matrix_common_config *common = &cfg->common; + struct gpio_kbd_matrix_data *data = dev->data; + int state; + + if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) { + state = 0; + } else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) { + state = BIT_MASK(common->col_size); + } else { + state = BIT(col); + } + + for (int i = 0; i < common->col_size; i++) { + const struct gpio_dt_spec *gpio = &cfg->col_gpio[i]; + + if ((data->last_col_state ^ state) & BIT(i)) { + if (state & BIT(i)) { + gpio_pin_configure_dt(gpio, GPIO_OUTPUT_ACTIVE); + } else { + gpio_pin_configure_dt(gpio, GPIO_INPUT); + } + } + } + + data->last_col_state = state; +} + +static int gpio_kbd_matrix_read_row(const struct device *dev) +{ + const struct gpio_kbd_matrix_config *cfg = dev->config; + const struct input_kbd_matrix_common_config *common = &cfg->common; + int val = 0; + + for (int i = 0; i < common->row_size; i++) { + const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; + + if (gpio_pin_get_dt(gpio)) { + val |= BIT(i); + } + } + + return val; +} + +static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabled) +{ + const struct gpio_kbd_matrix_config *cfg = dev->config; + const struct input_kbd_matrix_common_config *common = &cfg->common; + unsigned int flags = enabled ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; + int ret; + + for (int i = 0; i < common->row_size; i++) { + const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; + + ret = gpio_pin_interrupt_configure_dt(gpio, flags); + if (ret != 0) { + LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret); + return; + } + } +} + +static int gpio_kbd_matrix_init(const struct device *dev) +{ + const struct gpio_kbd_matrix_config *cfg = dev->config; + const struct input_kbd_matrix_common_config *common = &cfg->common; + int ret; + int i; + + for (i = 0; i < common->col_size; i++) { + const struct gpio_dt_spec *gpio = &cfg->col_gpio[i]; + + if (!gpio_is_ready_dt(gpio)) { + LOG_ERR("%s is not ready", gpio->port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return ret; + } + } + + for (i = 0; i < common->row_size; i++) { + const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; + struct gpio_callback *gpio_cb = &cfg->gpio_cb[i]; + + if (!gpio_is_ready_dt(gpio)) { + LOG_ERR("%s is not ready", gpio->port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return ret; + } + + gpio_init_callback(gpio_cb, cfg->handler, BIT(gpio->pin)); + + ret = gpio_add_callback_dt(gpio, gpio_cb); + if (ret < 0) { + LOG_ERR("Could not set gpio callback"); + return ret; + } + } + + gpio_kbd_matrix_set_detect_mode(dev, true); + + return input_kbd_matrix_common_init(dev); +} + +static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { + .drive_column = gpio_kbd_matrix_drive_column, + .read_row = gpio_kbd_matrix_read_row, + .set_detect_mode = gpio_kbd_matrix_set_detect_mode, +}; + +#define INPUT_GPIO_KBD_MATRIX_INIT(n) \ + BUILD_ASSERT(DT_INST_PROP_LEN(n, col_gpios) <= 32, "invalid col-size"); \ + \ + INPUT_KBD_MATRIX_DT_INST_DEFINE_ROW_COL( \ + n, DT_INST_PROP_LEN(n, row_gpios), DT_INST_PROP_LEN(n, col_gpios)); \ + \ + static void gpio_kbd_matrix_cb_##n(const struct device *gpio_dev, \ + struct gpio_callback *cb, uint32_t pins) \ + { \ + input_kbd_matrix_poll_start(DEVICE_DT_INST_GET(n)); \ + } \ + \ + static const struct gpio_dt_spec gpio_kbd_matrix_row_gpio_##n[DT_INST_PROP_LEN( \ + n, row_gpios)] = { \ + DT_INST_FOREACH_PROP_ELEM_SEP(n, row_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) \ + }; \ + static const struct gpio_dt_spec gpio_kbd_matrix_col_gpio_##n[DT_INST_PROP_LEN( \ + n, col_gpios)] = { \ + DT_INST_FOREACH_PROP_ELEM_SEP(n, col_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) \ + }; \ + static struct gpio_callback gpio_kbd_matrix_gpio_cb_##n[DT_INST_PROP_LEN(n, row_gpios)];\ + \ + static const struct gpio_kbd_matrix_config gpio_kbd_matrix_cfg_##n = { \ + .common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT_ROW_COL( \ + n, &gpio_kbd_matrix_api, \ + DT_INST_PROP_LEN(n, row_gpios), DT_INST_PROP_LEN(n, col_gpios)), \ + .row_gpio = gpio_kbd_matrix_row_gpio_##n, \ + .col_gpio = gpio_kbd_matrix_col_gpio_##n, \ + .gpio_cb = gpio_kbd_matrix_gpio_cb_##n, \ + .handler = gpio_kbd_matrix_cb_##n, \ + }; \ + \ + static struct gpio_kbd_matrix_data gpio_kbd_matrix_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_kbd_matrix_init, NULL, \ + &gpio_kbd_matrix_data_##n, &gpio_kbd_matrix_cfg_##n, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(INPUT_GPIO_KBD_MATRIX_INIT) diff --git a/dts/bindings/input/gpio-kbd-matrix.yaml b/dts/bindings/input/gpio-kbd-matrix.yaml new file mode 100644 index 000000000000000..ef08ebaa44e67a1 --- /dev/null +++ b/dts/bindings/input/gpio-kbd-matrix.yaml @@ -0,0 +1,43 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO based keyboard matrix input device + + Implement an input device for a GPIO based keyboard matrix. + + Example configuration: + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>, + <&gpio0 3 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>; + no-ghostkey-check; + }; + +compatible: "gpio-kbd-matrix" + +include: + - name: kbd-matrix-common.yaml + property-blocklist: + - row-size + - col-size + +properties: + row-gpios: + type: phandle-array + required: true + description: | + GPIO for the keyboard matrix rows, up to 8 different GPIOs. All row GPIO + pins must have interrupt support. + + col-gpios: + type: phandle-array + required: true + description: | + GPIO for the keyboard matrix columns, supports up to 32 different GPIOs. + The pins will be driven according to the GPIO_ACTIVE_HIGH or + GPIO_ACTIVE_LOW flags when selected, high impedance when not selected. diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 71f1d9a212a99a6..f065aadd5f36c57 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -26,6 +26,15 @@ }; }; + kbd-matrix { + compatible = "gpio-kbd-matrix"; + row-gpios = <&test_gpio 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&test_gpio 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&test_gpio 2 GPIO_ACTIVE_LOW>, + <&test_gpio 3 GPIO_ACTIVE_LOW>, + <&test_gpio 4 GPIO_ACTIVE_LOW>; + }; + qdec-gpio { compatible = "gpio-qdec"; gpios = <&test_gpio 0 0>, <&test_gpio 1 0>; From b1c83c0335d7e16538e24e2ffe60d1fc8eef053e Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Fri, 4 Aug 2023 17:46:37 +0200 Subject: [PATCH 0453/1049] soc: Add support for RZ/T2M This adds a new SoC: SOC_RENESAS_RZT2M and a new board: rzt2m_startek_kit Signed-off-by: Wojciech Sipak Co-authored-by: Roman Dobrodii --- boards/arm/rzt2m_starterkit/Kconfig.board | 6 ++ boards/arm/rzt2m_starterkit/Kconfig.defconfig | 9 ++ boards/arm/rzt2m_starterkit/board.cmake | 11 ++ boards/arm/rzt2m_starterkit/doc/index.rst | 95 ++++++++++++++++++ .../rzt2m_starterkit/doc/rzt2m_starterkit.png | Bin 0 -> 96455 bytes .../rzt2m_starterkit/rzt2m_starter_kit.dts | 17 ++++ .../rzt2m_starterkit/rzt2m_starter_kit.yaml | 15 +++ .../rzt2m_starter_kit_defconfig | 5 + dts/arm/renesas/rzt2m.dtsi | 92 +++++++++++++++++ soc/arm/renesas_rzt2m/CMakeLists.txt | 6 ++ soc/arm/renesas_rzt2m/Kconfig | 15 +++ soc/arm/renesas_rzt2m/Kconfig.defconfig | 24 +++++ soc/arm/renesas_rzt2m/Kconfig.soc | 12 +++ soc/arm/renesas_rzt2m/linker.ld | 7 ++ soc/arm/renesas_rzt2m/soc.c | 76 ++++++++++++++ soc/arm/renesas_rzt2m/soc.h | 41 ++++++++ 16 files changed, 431 insertions(+) create mode 100644 boards/arm/rzt2m_starterkit/Kconfig.board create mode 100644 boards/arm/rzt2m_starterkit/Kconfig.defconfig create mode 100644 boards/arm/rzt2m_starterkit/board.cmake create mode 100644 boards/arm/rzt2m_starterkit/doc/index.rst create mode 100644 boards/arm/rzt2m_starterkit/doc/rzt2m_starterkit.png create mode 100644 boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts create mode 100644 boards/arm/rzt2m_starterkit/rzt2m_starter_kit.yaml create mode 100644 boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig create mode 100644 dts/arm/renesas/rzt2m.dtsi create mode 100644 soc/arm/renesas_rzt2m/CMakeLists.txt create mode 100644 soc/arm/renesas_rzt2m/Kconfig create mode 100644 soc/arm/renesas_rzt2m/Kconfig.defconfig create mode 100644 soc/arm/renesas_rzt2m/Kconfig.soc create mode 100644 soc/arm/renesas_rzt2m/linker.ld create mode 100644 soc/arm/renesas_rzt2m/soc.c create mode 100644 soc/arm/renesas_rzt2m/soc.h diff --git a/boards/arm/rzt2m_starterkit/Kconfig.board b/boards/arm/rzt2m_starterkit/Kconfig.board new file mode 100644 index 000000000000000..9fddcf006a4f14d --- /dev/null +++ b/boards/arm/rzt2m_starterkit/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RZT2M_STARTER_KIT + bool "RZ/T2M Starter Kit Board" + depends on SOC_RENESAS_RZT2M diff --git a/boards/arm/rzt2m_starterkit/Kconfig.defconfig b/boards/arm/rzt2m_starterkit/Kconfig.defconfig new file mode 100644 index 000000000000000..9699b23963c96f5 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_RZT2M_STARTER_KIT + +config BOARD + default "rzt2m_starter_kit" + +endif diff --git a/boards/arm/rzt2m_starterkit/board.cmake b/boards/arm/rzt2m_starterkit/board.cmake new file mode 100644 index 000000000000000..dd92d0e905a7924 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/board.cmake @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_set_debugger_ifnset(jlink) +board_set_flasher_ifnset(jlink) + +board_runner_args(jlink "--device=R9A07G075M2") +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/rzt2m_starterkit/doc/index.rst b/boards/arm/rzt2m_starterkit/doc/index.rst new file mode 100644 index 000000000000000..e965585f6cba023 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/doc/index.rst @@ -0,0 +1,95 @@ +.. _rzt2m_starterkit: + +Renesas Starter Kit+ for RZ/T2M +=============================== + +Overview +******** + +The Renesas Starter Kit+ for RZ/T2M is an evaluation and development kit for the RZ/T2M MPU. +The board is powered through a 5V input via a DC Power Jack or USB Type-C Connector. + +.. figure:: rzt2m_starterkit.png + :width: 800px + :align: center + :alt: Starter Kit+ for RZ/T2M + + Starter Kit+ for RZ/T2M (Credit: Renesas) + +Hardware +******** + +The board utilizes the SoC of part no. R9A07G075M24GBG, with 2MB of RAM. + +It has several on-board memory components: +* SDRAM (256MBit), +* NOR Flash (256MBit), +* Octa Flash (512MBit), +* HyperRAM (512Mbit), +* QSPI Serial Flash (512Mbit), +* I2C EEPROM (32Kbit). + +The communication interfaces include: +* Debug interfaces (J-Link, MIPI-10, MIPI-20), +* Ethernet, +* CAN, +* USB, +* RS485, +* UART, +* I2C, +* SPI. + +Supported Features +================== + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| PINCTRL | on-chip | pinctrl | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ + +Other hardware features are not currently supported by the port. + +Connections and IOs +=================== + +By default, the board is configured for use with: +* UART0 connected to the USB serial port (pins K18, K19), +* UART3 connected to the PMOD Header (J25, pins H16, G20), +* LEDs defined as `led0`, `led1`, `led2` and `led3`, + +The Zephyr console uses UART0. + +Programming and Debugging +************************* + +Debugging +========= + +Connect to the board using the J-Link On-board USB connector. +Use `west` to start the debug server: + +.. code-block:: console + + west debugserver + +Connect GDB to the server and load an application: + +.. code-block:: + + target remote :2331 + file build/zephyr/zephyr.elf + load + +References +********** + +.. _RZT2M Product page: https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rzt2m-high-performance-multi-function-mpu-realizing-high-speed-processing-and-high-precision-control diff --git a/boards/arm/rzt2m_starterkit/doc/rzt2m_starterkit.png b/boards/arm/rzt2m_starterkit/doc/rzt2m_starterkit.png new file mode 100644 index 0000000000000000000000000000000000000000..960df4fdbb58c5328a40628bccf53048a47b0a98 GIT binary patch literal 96455 zcmb5V1ymf}(k|RMAq01KcXtWy?hxEza1BmEg2ND8g9LZC7&1t3w*+?^+_{tYeCM9; z{_FqlT6fQy>6%@;YD-T){p_lq=lSPV083e3NgjZMg98*{FW`9{zD`L-##~cdLtaT$ z4yFJA_yQMeS1&{<0B{9)dul7ZrZO}#rb5{P&;SYm9iRnJEUmrVr8PBGf&Z~w%>pn_ z05HY=*Vq5p?Ehc!%Es2q8UWy^U}`CAcTaDaYyp!6{Jh=&${8>j&)UJ#1}0a*WHwLO z0Acd{-+HTm$%lVs`+sD3mT1it=7tB8sqFuoZ1vw{YX?tPSQ|cA8#)_T5X?Wk z;lE^?zjDxD+114dHnxAt-x;FYg7kD?M>^P>3{U`+05w1ppaQG_AHWfC0lWcr*bxM) z@dC7A`q%%1J;^`znlLLXn3W@74YQC1+yGa=@*jKP?>T_AftCNPt(P4y&p%ag=&u0) z>G$*VIXwWNqyWHU()08E=jZ3gLI6Nm27vFN|Jb_~0D#aXtUl>Kb#(avfcXvpT6+Ie zXO#{Btsek@Xu;jm)AFBw5MZD1c6I=8Rtf;Gi~s<4901Tv{u(eVh z0f5Xb0AR3(`8NF@=8Xz7_}}aHe{J($>-W3_$N(rv$jHb@D6kJyRFoGlanN6)p}i!; z!hVHAN=QaVLP$bPPR&9`PRT??OhV5?&&0;g$;C-d%O}LgA;`kP$??|-94ad6OSG2+ z=;#C-6eJWJ|Ig+5JAjP}Zv}6G0EZ30W5Xd}!#(%HCIi4B{k^{aQ{WH~k&xk0P+?jl zEC3!30RavX3Go#w3JL-|3LHEFfQXHRL(PqhE3Jh`!(-{;6`ov=f=|oK$NyUUbHk5` zQvw|;PjJf5Njd>tJ@3Xf8S9A1PlZrIdRZF=LH&1(az#xr*Q9U&Ji`B{WB9*4qrjA$ zuo1#KMudllb@#U!Y?ScW2(Vreae1U^wD2sEcxhjI;D;m2Xn*E=UIfq)VD7LHumMTn zs@>*#{M7`Gl4PU;FwmeP_t}VeyXYCPZsIzBy9@UvE8LirccSh}m{+UL#p};F>5D%J znFZ`9p(h2ns*O_@_wldc=)VwsU|C&t*+}U28WFrh`oVcCTp6Hnk@!au;op)J`m#e- zZWoUFFtOouqo)YQS3Z=(FNB%{h-v3+b#+6E6}ns!LSm16Xj6pWuE*z%>rNgol3asw z>8fd~9C!|;5dKWQyP_1sye16&C1}p#IM3eG*7;;vW;4Di0jK}XXg?&62|u>` z8Q^+E4v)Hi=)YqEem?^lf8+qtKj)a^4hT{C&PZ;$d0{ut0J#HE;Opb1 z;T}h&IG%XZNA`^h_jmZPc}sp1W+Ik1CXEz;5njrjBm9@$2OXTdZ*F)aHr<2W5wa0fucdK!ttfg z7gv}GkU@Xyz@7ItmX#5dC$j2+Xp zDdN7PJy#ReQRNtrMRLnc-Fw$E^qdeZm|YQDHO+vNr&8X|6{}$5m7A_yH`qCa*>JPN zi%O@?ns%7qUJa}hpR3xY&ro$?;(fd-OAUvR^mR1I!vqaw7e3uk$yb9ec(UKME6d?PK5gGi^Oxc?E)adS@D|IrSPH zXhfn)eG}+h*KAXSAjJLhyjx?lbS3x9tyg+VRc6tK3c)u|g`S1Kc^6f8m?gjI$Vzc8-47#R{Yu!i?Kx0j+Jt(xv zW5_iSR*pV~k>loaqg|3998(3p`eSS=6fbXaC5ipf3zvGtf!dQKA?-NOi%=dBqxf3^^`L>I7rHZg>W)TAvO>_L)&UUn|)< z&|08_1K@v%+`hU#!LVfTe+i80w z21nSxb_Ouydht1e2){-MEMigGen(jtqu5B~Hson3c5ux&61loNv!c{$k3pRt>1SHmO#?&&^1i?Vlg)!ZgN`7d~B&X9^yC@tMxAr9sKZ+JQ)7q6G_% zhyu?M)|%yMbdaso!yZ2AT||AD!fx3h3w?s8r-c1J-6c>|Iz>)A{*DA+E~YQxQF48uH?A$==Bs&x}3y7 zlHiZR7qAnPey#t=RAgE;;$)yL?LG0s($1PP7xbby*=BPFWVSbMVrtCRu&{(8?tumW z?!7SoVd}2F`Jw(Zu#&ii>+U8V#>99f(DVDZ+Qd2fC z4KlfFeRaQ^sGCpc=}j(YOe0WPS>zh5e5sKh(sMO4Oq-7WgI=h^cJ#xNnX_7^>Ktc) zTjyMY-SQt^3OOUPcuyfa$K$u^DP_`S3({|$?muVxF+*>HLOrUvo#f|-wGf(G+1(1A zc&Vu;f4?sFCojeOaz&s{e0~;XhgL+FgVx7r(uhd4BOmc4l31|i01V?*!%GA zm8A317h~1P_B;Zq>^gFxo`uq>_gx{!ysIG{Kc+Nj$M`wKNqEg&i8!W;dfvLx)ekg` zfQavxkHs1yr0u9yF>!Y`%!u7B)0y+i=SRF$!}+>}Pi&ma7rBzj@O8Q_Zl*izOLRm6 z7>V6SN`CZfTtMcG7w3yBUG+&FZNdvZ^_Eh9K*#dGrgBlV3t#u05Y+lyp?a3^+e}8H`nR_tl4hG2Ruf5PPxx+HN5#NASh!y zLZA4U^W$Jsc!`GBCJkj~4rNx6uYRJ{J)&2UlcCk0J=vXS08RgEW|TUn>NK(|{S9VK zvjnQu8LL`YE7KZ&umx`xk@Z%(4^0amDic6U6UOS|BG>h}{auJwxInR?Ao+a94aSlf z#5{4RbLeow0*m4(Yb7b1bF)XX+Ia|LT)b_Xbuu|X%xWr z&wl~Gj&b5378xnUoBh(m^@UX1usx+55UKZI=5=QGS>mNf044KcYX0l5t)4HJL`?e? zcVD1>4^p9i27a<;UJVD6{O+$aZwSeBC_p`oT`VIPSIptQUGlgcF^PW|KM9nGf!2hl zFDSco(>R(t(1~I+C4&rph^oT5N+I-)M+(vnB`azIOo#^N3okR@W#g@RfJ69Rq!ekE zRUmV5OO1)#3no4T4yD7@w);UUQ2)kWpR|*;x^Ij;W5^5s`vc0G_XB7eU9$v+S1~rh z0)w^mo5?u$3Ril<_QeyE-eY1Z7mjN&LbTYu;kp6(#A?GSlh!}ToC<}tOb9f!L+eyL zvOm)13Ji4JP?9tdlc_G;IoO&MMr{*D=#XBXN?3ImZWbqUPOqjBPl=l!>WIY`XyDef zk`E&d?xL074cr@$@%moBf?%;-&v9^R5I%u~N+wYQj-pcLtd; zF_%N*u4(agV5=$W3{#;9EiNtNA0Cb}T$t=j6UMq{vSs;>C6CH)?5aFC%G~$G`goOV zWe^o1YGcies8c^cb^gM}!gGQ$f z3`bg@KSZfm-Z!k?m(j56%NtO;f0aViIk<`@%~IXmbxT`D^}r&Sa`=r=x7nR7xOf(1 zldy6rJVR7*3|@<<6<0bXdy3(=xu>NlF+iFvTKqlXNWL9S(9~E=6sLr$A6EnSePdwt z;gwQXR;}jFG(5nMb7TF%z z+jWN^*1>itantKx6&uNp6*|5(g)p?-6*+1J6#npXKX00>6dr_YD|m6`JLm{Xk~gfl zV4u6$4ih^#{7D4)g6~>I-hNwAwQK~tA5(Z$zE+#IcYmP3yj3zXUdg0~-N~K8VoP+^ z@XXIU~W>reqK6{^FnDv7vv;_otixp#o!0s2*B z7HOO0+QMi}^GmZjUan(7h0@hKyBZW1*9H6+w(KpN5CQvea0n=P27RECyX+qQ_0>x4 zx7Kv>P5m?4)lC~Rk|;`Q82WX8RX>|j(-`fRyOYK*n>OF~xbARWHuL*=03FH#Di1mD zDlPwwdz>Imm8&e?TfeezYQP((!QXoZ^-n=KmseU*05YJp(b470r!bUYrK{ zoCq{Lukp? z-=k(9=3(DRO?1WImbKeSav?s%dQb}5VY z$x)!}Fqrd(-hA3V6YWlEZ;N`(!=-?n4`a=j_3ZQ~$9Ynym%!%z?lWK+dRZ8(SjB{; zi6Dq`&CT~-34ziK__?UXXZf8r$I}6kzaoUA{gziVAH9_@`7HG#w}@!LZ%8?AEoCl&Nt;FNues71>BHAvw11@YU?<3GTX$=8jz!tec7Ie zZ+&q)rLV5OpO79g<9D<;{ZhpV#u5|WIg!m@nCsfb5{@wb;6a62j>}Q~EUy|w>&@*C(K{?bu)!`Y46wEunG{7x86Ortr zUz)G0Iy&|d=Jwl)zZ`w)-tf7Z3oTV?t^c`CdW>DMt((Ou%4gEmMt1altiS!+0KMX_ z_p6rO@i~sGqO!Qz29zZ>K#8Rtu)okhG$=Ti9N_=sP_wL9llIvj#-#k7IL z1NL*}&>0@lNK933L7NXJA(S}5RpP972eBQNn23g)XkxR{NwFAn7|@f3NbjN&d#%6o zIj}0O7}T*g2xJTmWmO453j>$|ouo)qTv`+g3K<9=pIlFfyla(J+D{W1KN~RHad<8v zV=D1V?)+K5g84_8qvm#1mu*}nbQTc2t7xINKNT4zM>pozRHGLRH?%88zuI_u=w$O= zeg+=-%JBOLvhwQLA5)AQ6bZe!Fqv)Q8bPj=2|SK1CK8{U<@h{4o+%BUmrZB~X6|=` z50?!H7X_;Ehd?b3v9e0b;$CqR;mYcVhZ+Pz>}fm2l1+bb&EOle4BRY=Dgs-vCLJ#Rjn+_4Ec(YRc-POEp~<~ z2A-tB9$KuA0(XOj1W76*P0DYC;WvrqXxBzeFi;YEQ%kY=9Iid8yDanHDn^(Uy&UC| z_w*Rc*wpn*-C8us(x`uJ-LjZ$GyjuWTJ!Vk+}|=^UdiCxV*PxQpK22Ez6+mvo78F1 zrDU@_e~Ij6{L0yLA&HCX4AU5>I_!(P1ATC|^=j=-3_1Eho6cA}CPj9T6*M=s=PB3f z+PpZ-pb>U-vFBT6t)U=#eYU-9>pD^Z6TkY&ipbf4} zD(wqWfKcGKep#jev6~(mG5n}wocTuZj90|e?`0WtsxHG?9HoERLSXNDHh(iOl_s1N z5}@Ts;ForNKI|S-&t=i(k}^=h)Lnp?_cS!8Y3!S=l>m$cc##yfuPRWQa%M^}4p`@8 z?bx63FMOEdqepR$jHf`QGvt+YaDtNWPv_CeuWZ%0KZ1#%*ofvSS|7P%rW!(T z)HSeDXy9Ot4Vdl_-^93C`LFH}B#+ta%PAp#N1;&oqagb5!LGI5@EDJ+04ya8EkN;6_ddu^;eTqwY_col9HfDYE^*rqv$^j&kA`W7ifxc}T|vw?hChh0c{Hz~2m zvHpceEeJkEIb&u~poKm@wLRnuKjUt#WVT~tcdS3FXxjsY>67JMxwRiF^>i(?lRwnz zJf7j;iR!6h&I=`a`;uIYE2H(d z18g8jbrSF$hDFMW^fNYdsRPZ2-SO3z4|OYYziECN0*X6S{z1<2LSJ^Hn4Ihi$vM^A z-$&3@6H^n3)sFrSv+Ux{rwps?bdJ=p#h=UK$Y)6R5Xg6HP#kMHvj9-X=r)KXA^&vX`MA{uvQM(_y97cbiI$VmR_*UHi@S-eUeG_%7j#@=Avve0#4&;m8N# z-HSlMEyHA+7v;mGCQ19W4#iV^d;IV}C>`{5*Irt*1biohi%iigqEQ1+HO_IqMamB* z*vky_0C&kZ*o&i5w?Uo(TG?sl1;3K3;}hkUsL7Y4`dF(3w!&5z@`_^9mdtY6g2Pqs zx^XP-=?;*6c=l#f{ujWF!p%b{mbnGNN7#Jy)-1IIvK?9b||yBgNk9 z=FY!L2@fBS+swzFtkjUWPiO1s#wj`a`lS;+%crE+lWT!3GDcmKH{q-4YmOeb9?9sp`)t)r7awQR75D-s{`>Jn9}0_Cr?_ z2&v$cfi=d|hpDQfRT%0A`eb`M$F?kEaPqr%8HB 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�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 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include + +/ { + model = "RZT/2M Starter Kit"; + compatible = "renesas,rzt2m_starter_kit"; + + chosen { + zephyr,sram = &cpu0_atcm; + }; +}; diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.yaml b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.yaml new file mode 100644 index 000000000000000..5d091d0fddb3b74 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +identifier: rzt2m_starter_kit +name: Renesas RZ/T2M Starter Kit+ +type: mcu +arch: arm +ram: 2048 +toolchain: + - zephyr +supported: + - counter + - uart + - gpio +vendor: renesas diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig new file mode 100644 index 000000000000000..09e5e1d50a5fe6f --- /dev/null +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_RENESAS_RZT2M=y +CONFIG_BOARD_RZT2M_STARTER_KIT=y diff --git a/dts/arm/renesas/rzt2m.dtsi b/dts/arm/renesas/rzt2m.dtsi new file mode 100644 index 000000000000000..44e045014a95c48 --- /dev/null +++ b/dts/arm/renesas/rzt2m.dtsi @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "renesas,rzt2m-dev"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-r52"; + reg = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-r52"; + reg = <1>; + }; + }; + + arch_timer: timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + interrupt-parent = <&gic>; + }; + + soc { + compatible = "renesas,rzt2m-soc"; + + interrupt-parent = <&gic>; + + gic: interrupt-controller@94000000 { + compatible = "arm,gic-v3", "arm,gic"; + reg = <0x94000000 0x10000>, + <0x94100000 0x80000>; + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + }; + + cpu0_atcm: memory@0 { + compatible = "mmio-sram"; + reg = <0x00000000 DT_SIZE_K(512)>; + }; + + cpu0_btcm: memory@100000 { + compatible = "mmio-sram"; + reg = <0x00100000 DT_SIZE_K(64)>; + }; + + sram0: memory@10000000 { + compatible = "mmio-sram"; + reg = <0x10000000 DT_SIZE_M(2)>; + }; + + gsc: gsc@c0060000 { + /* Global System Counter */ + compatible = "syscon"; + reg = <0xc0060000 0x30>; + reg-io-width = <4>; + }; + + prcrn: prcrn@80281a10 { + /* Non-safety area */ + compatible = "syscon"; + reg = <0x80281a10 0x10>; + reg-io-width = <4>; + }; + + prcrs: prcrs@81281a00 { + /* Safety area */ + compatible = "syscon"; + reg = <0x81281a00 0x10>; + reg-io-width = <4>; + }; + }; +}; diff --git a/soc/arm/renesas_rzt2m/CMakeLists.txt b/soc/arm/renesas_rzt2m/CMakeLists.txt new file mode 100644 index 000000000000000..05fd66ec83cd403 --- /dev/null +++ b/soc/arm/renesas_rzt2m/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + soc.c + ) diff --git a/soc/arm/renesas_rzt2m/Kconfig b/soc/arm/renesas_rzt2m/Kconfig new file mode 100644 index 000000000000000..fc2f6e81c4eca4b --- /dev/null +++ b/soc/arm/renesas_rzt2m/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config SOC_RENESAS_RZT2M + bool + +if SOC_RENESAS_RZT2M + +config SOC_PART_NUMBER_R9A07G075 + bool + +config SOC_PART_NUMBER + default SOC_PART_NUMBER_R9A07G075 + +endif # SOC_RENESAS_RZT2M diff --git a/soc/arm/renesas_rzt2m/Kconfig.defconfig b/soc/arm/renesas_rzt2m/Kconfig.defconfig new file mode 100644 index 000000000000000..72f828d4351179c --- /dev/null +++ b/soc/arm/renesas_rzt2m/Kconfig.defconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +if SOC_RENESAS_RZT2M + +config SOC + default "renesas_rzt2m" + +config NUM_IRQS + default 994 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 20000000 + +config FPU + default y + +config FLASH_SIZE + default 0 + +config FLASH_BASE_ADDRESS + default 0 + +endif # SOC_RENESAS_RZT2M diff --git a/soc/arm/renesas_rzt2m/Kconfig.soc b/soc/arm/renesas_rzt2m/Kconfig.soc new file mode 100644 index 000000000000000..0275833b7925ece --- /dev/null +++ b/soc/arm/renesas_rzt2m/Kconfig.soc @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config SOC_RENESAS_RZT2M + bool "Renesas RZ/T2M MCU" + select ARM + select CPU_CORTEX_R52 + select CPU_HAS_ARM_MPU + select GIC_V3 + select GIC_SINGLE_SECURITY_STATE + select ARM_ARCH_TIMER + select SYSCON diff --git a/soc/arm/renesas_rzt2m/linker.ld b/soc/arm/renesas_rzt2m/linker.ld new file mode 100644 index 000000000000000..3a016555ba95bcb --- /dev/null +++ b/soc/arm/renesas_rzt2m/linker.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/arm/renesas_rzt2m/soc.c b/soc/arm/renesas_rzt2m/soc.c new file mode 100644 index 000000000000000..5a85409022934ce --- /dev/null +++ b/soc/arm/renesas_rzt2m/soc.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "soc.h" +#include + +static const struct device *const prcrn_dev = DEVICE_DT_GET(DT_NODELABEL(prcrn)); +static const struct device *const prcrs_dev = DEVICE_DT_GET(DT_NODELABEL(prcrs)); + +void rzt2m_unlock_prcrn(uint32_t mask) +{ + uint32_t prcrn; + + syscon_read_reg(prcrn_dev, 0, &prcrn); + prcrn |= PRC_KEY_CODE | mask; + + syscon_write_reg(prcrn_dev, 0, prcrn); +} + +void rzt2m_lock_prcrn(uint32_t mask) +{ + uint32_t prcrn; + + syscon_read_reg(prcrn_dev, 0, &prcrn); + prcrn &= ~mask; + prcrn |= PRC_KEY_CODE; + + syscon_write_reg(prcrn_dev, 0, prcrn); +} + +void rzt2m_unlock_prcrs(uint32_t mask) +{ + uint32_t prcrs; + + syscon_read_reg(prcrs_dev, 0, &prcrs); + prcrs |= PRC_KEY_CODE | mask; + + syscon_write_reg(prcrs_dev, 0, prcrs); +} + +void rzt2m_lock_prcrs(uint32_t mask) +{ + uint32_t prcrs; + + syscon_read_reg(prcrs_dev, 0, &prcrs); + prcrs &= ~mask; + prcrs |= PRC_KEY_CODE; + + syscon_write_reg(prcrs_dev, 0, prcrs); +} + +void rzt2m_enable_counters(void) +{ + const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(gsc)); + + syscon_write_reg(dev, 0, CNTCR_EN); +} + +static int rzt2m_init(void) +{ + /* Unlock the Protect Registers + * so that device drivers can access configuration registers of peripherals. + */ + /* After the device drivers are done, lock the Protect Registers. */ + + rzt2m_enable_counters(); + return 0; +} + +SYS_INIT(rzt2m_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/renesas_rzt2m/soc.h b/soc/arm/renesas_rzt2m/soc.h new file mode 100644 index 000000000000000..02bd03b69a1ad30 --- /dev/null +++ b/soc/arm/renesas_rzt2m/soc.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +/* Do not let CMSIS to handle GIC and Timer */ +#include +#define __GIC_PRESENT 0 +#define __TIM_PRESENT 0 + +/* Global system counter */ +#define CNTCR_EN BIT(0) +#define CNTCR_HDBG BIT(1) + +/* Safety area protect register */ +#define PRCRS_CLK BIT(0) +#define PRCRS_LPC_RESET BIT(1) +#define PRCRS_GPIO BIT(2) +#define PRCRS_SYS_CTRL BIT(3) + +/* Non-safety area protect register */ +#define PRCRN_PRC0 BIT(0) +#define PRCRN_PRC1 BIT(1) +#define PRCRN_PRC2 BIT(2) + +/* PRC Key Code - this value is required to allow any write operation + * to the PRCRS / PRCRN registers. + * See section 10.2 of the RZ/T2M User's Manual: Hardware. + */ +#define PRC_KEY_CODE 0xa500 + +void rzt2m_unlock_prcrn(uint32_t mask); +void rzt2m_lock_prcrn(uint32_t mask); +void rzt2m_unlock_prcrs(uint32_t mask); +void rzt2m_lock_prcrs(uint32_t mask); + +#endif /* _SOC__H_ */ From 4e35d0e3545c37473c6f11ff43282c9648483dc2 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Thu, 10 Aug 2023 14:49:35 +0200 Subject: [PATCH 0454/1049] drivers: serial: add RZT2M uart driver This adds a UART driver for the Renesas RZ/T2M Serial Communication Interface. The driver implements: * Polling API, * Interrupt-driven API. Signed-off-by: Wojciech Sipak --- .../rzt2m_starterkit/rzt2m_starter_kit.dts | 10 + .../rzt2m_starter_kit_defconfig | 5 + drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 2 + drivers/serial/Kconfig.rzt2m | 11 + drivers/serial/uart_rzt2m.c | 435 ++++++++++++++++++ drivers/serial/uart_rzt2m.h | 124 +++++ dts/arm/renesas/rzt2m.dtsi | 25 + dts/bindings/serial/renesas,rzt2m-uart.yaml | 26 ++ 9 files changed, 639 insertions(+) create mode 100644 drivers/serial/Kconfig.rzt2m create mode 100644 drivers/serial/uart_rzt2m.c create mode 100644 drivers/serial/uart_rzt2m.h create mode 100644 dts/bindings/serial/renesas,rzt2m-uart.yaml diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts index 06b47819a1d14a3..a9cb6bcf65a84cd 100644 --- a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts @@ -13,5 +13,15 @@ chosen { zephyr,sram = &cpu0_atcm; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; }; }; + +&uart0 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig index 09e5e1d50a5fe6f..8b994e00082f146 100644 --- a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig @@ -3,3 +3,8 @@ CONFIG_SOC_RENESAS_RZT2M=y CONFIG_BOARD_RZT2M_STARTER_KIT=y + +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index be0cbfd394b1355..bfc3860386428b7 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -67,6 +67,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_SEDI uart_sedi.c) zephyr_library_sources_ifdef(CONFIG_UART_BCM2711_MU uart_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_UART_INTEL_LW uart_intel_lw.c) zephyr_library_sources_ifdef(CONFIG_UART_RA uart_ra.c) +zephyr_library_sources_ifdef(CONFIG_UART_RZT2M uart_rzt2m.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 22916527ca140fb..5eb183c9a3e2352 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -255,4 +255,6 @@ source "drivers/serial/Kconfig.intel_lw" source "drivers/serial/Kconfig.ra" +source "drivers/serial/Kconfig.rzt2m" + endif # SERIAL diff --git a/drivers/serial/Kconfig.rzt2m b/drivers/serial/Kconfig.rzt2m new file mode 100644 index 000000000000000..bda26d628ad12da --- /dev/null +++ b/drivers/serial/Kconfig.rzt2m @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config UART_RZT2M + bool "Renesas RZ/T2M UART Driver" + default y + depends on DT_HAS_RENESAS_RZT2M_UART_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + help + Enable Renesas RZ/T2M UART Driver. diff --git a/drivers/serial/uart_rzt2m.c b/drivers/serial/uart_rzt2m.c new file mode 100644 index 000000000000000..afd012d5a8bf01c --- /dev/null +++ b/drivers/serial/uart_rzt2m.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "uart_rzt2m.h" +#include "zephyr/spinlock.h" +#include "zephyr/sys/printk.h" +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT renesas_rzt2m_uart + +LOG_MODULE_REGISTER(uart_renesas_rzt2m, CONFIG_UART_LOG_LEVEL); + +struct rzt2m_device_config { + mm_reg_t base; + uart_irq_config_func_t irq_config_func; +}; + +struct rzt2m_device_data { + struct uart_config uart_cfg; + struct k_spinlock lock; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t callback; + void *callback_data; +#endif +}; + +static int rzt2m_poll_in(const struct device *dev, unsigned char *c) +{ + if (!dev || !dev->config || !dev->data) { + return -ENODEV; + } + + const struct rzt2m_device_config *config = dev->config; + struct rzt2m_device_data *data = dev->data; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (FRSR_R(*FRSR(config->base)) == 0) { + k_spin_unlock(&data->lock, key); + return -1; + } + *c = *RDR(config->base) & RDR_MASK_RDAT; + *CFCLR(config->base) |= CFCLR_MASK_RDRFC; + + if (FRSR_R(*FRSR(config->base)) == 0) { + *FFCLR(config->base) |= FFCLR_MASK_DRC; + } + + k_spin_unlock(&data->lock, key); + return 0; +} + +static void rzt2m_poll_out(const struct device *dev, unsigned char c) +{ + if (!dev || !dev->config || !dev->data) { + return; + } + + const struct rzt2m_device_config *config = dev->config; + struct rzt2m_device_data *data = dev->data; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + int fifo_count = FTSR_T(*FTSR(config->base)); + + while (fifo_count == MAX_FIFO_DEPTH) { + fifo_count = FTSR_T(*FTSR(config->base)); + } + + *TDR(config->base) = c; + + /* Clear `Transmit data empty flag`. */ + *CFCLR(config->base) |= CFCLR_MASK_TDREC; + + k_spin_unlock(&data->lock, key); +} + +static int rzt2m_err_check(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + uint32_t status = *CSR(config->base); + uint32_t retval = 0; + + if (status & CSR_MASK_ORER) { + retval |= UART_ERROR_OVERRUN; + } + if (status & CSR_MASK_FER) { + retval |= UART_ERROR_FRAMING; + } + if (status & CSR_MASK_PER) { + retval |= UART_ERROR_PARITY; + } + + return retval; +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static int uart_rzt2m_irq_tx_ready(const struct device *dev); + +static int rzt2m_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size) +{ + struct rzt2m_device_data *data = dev->data; + const struct rzt2m_device_config *config = dev->config; + int num_tx = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + while ((size - num_tx > 0) && uart_rzt2m_irq_tx_ready(dev)) { + *TDR(config->base) = (uint8_t)tx_data[num_tx++]; + } + + k_spin_unlock(&data->lock, key); + return num_tx; +} + +static int rzt2m_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + struct rzt2m_device_data *data = dev->data; + const struct rzt2m_device_config *config = dev->config; + int num_rx = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + while (num_rx < size && (FRSR_R(*FRSR(config->base)))) { + rx_data[num_rx++] = *RDR(config->base); + } + *CFCLR(config->base) = CFCLR_MASK_RDRFC; + *FFCLR(config->base) = FFCLR_MASK_DRC; + k_spin_unlock(&data->lock, key); + return num_rx; +} + +static void uart_rzt2m_irq_rx_enable(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + *CCR0(config->base) |= CCR0_MASK_RIE | CCR0_MASK_RE; +} + +static void uart_rzt2m_irq_rx_disable(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + *CCR0(config->base) &= ~CCR0_MASK_RIE; +} + +static void uart_rzt2m_irq_tx_enable(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + /* These bits must be set simultaneously. */ + *CCR0(config->base) |= CCR0_MASK_TE | CCR0_MASK_TIE | CCR0_MASK_TEIE; +} + +static void uart_rzt2m_irq_tx_disable(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + *CCR0(config->base) &= ~(CCR0_MASK_TIE | CCR0_MASK_TEIE); +} + +static int uart_rzt2m_irq_tx_ready(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + if (FTSR_T(*FTSR(config->base)) == MAX_FIFO_DEPTH || + ((*CCR0(config->base) & CCR0_MASK_TIE) == 0)) { + return 0; + } + + return 1; +} + +static int uart_rzt2m_irq_rx_ready(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + if (FRSR_R(*FRSR(config->base))) { + return 1; + } + + return 0; +} + +static int uart_rzt2m_irq_is_pending(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + if ((*CSR(config->base) & (CSR_MASK_RDRF)) || (*FRSR(config->base) & FRSR_MASK_DR)) { + return 1; + } + return 0; +} + +static void uart_rzt2m_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, + void *cb_data) +{ + struct rzt2m_device_data *data = dev->data; + + data->callback = cb; + data->callback_data = cb_data; +} + +static int uart_rzt2m_irq_update(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + *CFCLR(config->base) = CFCLR_MASK_RDRFC; + *FFCLR(config->base) = FFCLR_MASK_DRC; + return 1; +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static const struct uart_driver_api rzt2m_uart_api = { + .poll_in = rzt2m_poll_in, + .poll_out = rzt2m_poll_out, + .err_check = rzt2m_err_check, +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = rzt2m_fifo_fill, + .fifo_read = rzt2m_fifo_read, + .irq_rx_enable = uart_rzt2m_irq_rx_enable, + .irq_rx_disable = uart_rzt2m_irq_rx_disable, + .irq_tx_enable = uart_rzt2m_irq_tx_enable, + .irq_tx_disable = uart_rzt2m_irq_tx_disable, + .irq_tx_ready = uart_rzt2m_irq_tx_ready, + .irq_rx_ready = uart_rzt2m_irq_rx_ready, + .irq_is_pending = uart_rzt2m_irq_is_pending, + .irq_callback_set = uart_rzt2m_irq_callback_set, + .irq_update = uart_rzt2m_irq_update, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +static int rzt2m_module_start(const struct device *dev) +{ + if (!dev || !dev->config || !dev->data) { + return -ENODEV; + } + + const struct rzt2m_device_config *config = dev->config; + struct rzt2m_device_data *data = dev->data; + int interface_id = BASE_TO_IFACE_ID(config->base); + unsigned int irqkey = irq_lock(); + volatile uint32_t dummy; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (interface_id < 5) { + /* Dummy-read at least one time as stated in 8.3.1 of the User's Manual: Hardware */ + *MSTPCRA &= ~(MSTPCRA_MASK_SCIx(interface_id)); + dummy = *MSTPCRA; + } else { + LOG_ERR("SCI modules in the secure domain on RZT2M are not supported."); + return -ENOTSUP; + } + + /* Dummy-read at least five times as stated in 8.3.1 of the User's Manual: Hardware */ + dummy = *RDR(config->base); + dummy = *RDR(config->base); + dummy = *RDR(config->base); + dummy = *RDR(config->base); + dummy = *RDR(config->base); + + k_spin_unlock(&data->lock, key); + irq_unlock(irqkey); + return 0; +} + +static int rzt2m_uart_init(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + struct rzt2m_device_data *data = dev->data; + uint32_t baud_setting = 0; + uint32_t baud_settings[] = {CCR2_BAUD_SETTING_9600, CCR2_BAUD_SETTING_115200}; + + rzt2m_unlock_prcrs(PRCRS_GPIO); + rzt2m_unlock_prcrn(PRCRN_PRC1 | PRCRN_PRC2); + + /* The module needs to be started + * to allow any operation on the registers of Serial Communications Interface. + */ + int ret = rzt2m_module_start(dev); + + if (ret) { + return ret; + } + + /* Disable transmitter, receiver, interrupts. */ + *CCR0(config->base) = CCR0_DEFAULT_VALUE; + while (*CCR0(config->base) & (CCR0_MASK_RE | CCR0_MASK_TE)) { + } + + *CCR1(config->base) = CCR1_DEFAULT_VALUE; + *CCR2(config->base) = CCR2_DEFAULT_VALUE; + *CCR3(config->base) = CCR3_DEFAULT_VALUE; + *CCR4(config->base) = CCR4_DEFAULT_VALUE; + + *CFCLR(config->base) = CFCLR_ALL_FLAG_CLEAR; + *FFCLR(config->base) = FFCLR_MASK_DRC; + + /* Use FIFO mode. */ + *CCR3(config->base) |= (CCR3_MASK_FM); + + switch (data->uart_cfg.stop_bits) { + case UART_CFG_STOP_BITS_1: + /* Default value, already set. */ + break; + case UART_CFG_STOP_BITS_2: + *CCR3(config->base) |= CCR3_MASK_STP; + break; + default: + LOG_ERR("Selected bit stop length is not supported: %u.", data->uart_cfg.stop_bits); + return -ENOTSUP; + } + + switch (data->uart_cfg.data_bits) { + case UART_CFG_DATA_BITS_7: + *CCR3(config->base) |= CCR3_CHR_7BIT; + break; + case UART_CFG_DATA_BITS_8: + *CCR3(config->base) |= CCR3_CHR_8BIT; + break; + default: + LOG_ERR("Selected number of data bits is not supported: %u.", + data->uart_cfg.data_bits); + return -ENOTSUP; + } + + if (data->uart_cfg.baudrate > ARRAY_SIZE(baud_settings)) { + LOG_ERR("Selected baudrate variant is not supported: %u.", data->uart_cfg.baudrate); + return -ENOTSUP; + } + baud_setting = baud_settings[data->uart_cfg.baudrate]; + + *CCR2(config->base) &= ~(CCR2_MASK_BAUD_SETTING); + *CCR2(config->base) |= (baud_setting & CCR2_MASK_BAUD_SETTING); + + *CCR1(config->base) |= (CCR1_MASK_NFEN | CCR1_MASK_SPB2DT | CCR1_MASK_SPB2IO); + + switch (data->uart_cfg.parity) { + case UART_CFG_PARITY_NONE: + /* Default value, already set. */ + break; + case UART_CFG_PARITY_EVEN: + *CCR1(config->base) |= CCR1_MASK_PE; + break; + case UART_CFG_PARITY_ODD: + *CCR1(config->base) |= (CCR1_MASK_PE | CCR1_MASK_PM); + break; + default: + LOG_ERR("Unsupported parity: %u", data->uart_cfg.parity); + } + + /* Specify trigger thresholds and clear FIFOs. */ + *FCR(config->base) = FCR_MASK_TFRST | FCR_MASK_RFRST | FCR_TTRG_15 | FCR_RTRG_15; + + /* Enable the clock. */ + *CCR3(config->base) &= ~CCR3_MASK_CKE; + *CCR3(config->base) |= CCR3_CKE_ENABLE; + + /* Clear status flags. */ + *CFCLR(config->base) = CFCLR_ALL_FLAG_CLEAR; + *FFCLR(config->base) = FFCLR_MASK_DRC; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + config->irq_config_func(dev); +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + + /* Start trasmitter and receiver. */ + *CCR0(config->base) |= (CCR0_MASK_TE | CCR0_MASK_RE); + while (!(*CCR0(config->base) & CCR0_MASK_RE)) { + } + while (!(*CCR0(config->base) & CCR0_MASK_TE)) { + } + + rzt2m_lock_prcrs(PRCRS_GPIO); + rzt2m_lock_prcrn(PRCRN_PRC1 | PRCRN_PRC2); + + return 0; +} + +static void uart_rzt2m_isr(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + struct rzt2m_device_data *data = dev->data; + + if (data->callback) { + data->callback(dev, data->callback_data); + } +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + + *CFCLR(config->base) = CFCLR_MASK_RDRFC; + *FFCLR(config->base) = FFCLR_MASK_DRC; +} + +#define UART_RZT2M_IRQ_CONNECT(n, irq_name) \ + do { \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, irq_name, irq), \ + DT_INST_IRQ_BY_NAME(n, irq_name, priority), uart_rzt2m_isr, \ + DEVICE_DT_INST_GET(n), DT_INST_IRQ_BY_NAME(n, irq_name, flags)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, irq_name, irq)); \ + } while (false) + +#define UART_RZT2M_CONFIG_FUNC(n) \ + static void uart##n##_rzt2m_irq_config(const struct device *port) \ + { \ + UART_RZT2M_IRQ_CONNECT(n, rx_err); \ + UART_RZT2M_IRQ_CONNECT(n, rx); \ + UART_RZT2M_IRQ_CONNECT(n, tx); \ + UART_RZT2M_IRQ_CONNECT(n, tx_end); \ + } + +#define UART_RZT2M_INIT(n) \ + static struct rzt2m_device_data rzt2m_uart_##n##data = { \ + .uart_cfg = \ + { \ + .baudrate = DT_INST_ENUM_IDX(n, current_speed), \ + .parity = DT_INST_ENUM_IDX_OR(n, parity, UART_CFG_PARITY_NONE), \ + .stop_bits = \ + DT_INST_ENUM_IDX_OR(n, stop_bits, UART_CFG_STOP_BITS_1), \ + .data_bits = \ + DT_INST_ENUM_IDX_OR(n, data_bits, UART_CFG_DATA_BITS_8), \ + }, \ + }; \ + UART_RZT2M_CONFIG_FUNC(n); \ + static const struct rzt2m_device_config rzt2m_uart_##n##_config = { \ + .base = DT_INST_REG_ADDR(n), .irq_config_func = uart##n##_rzt2m_irq_config}; \ + DEVICE_DT_INST_DEFINE(n, &rzt2m_uart_init, NULL, &rzt2m_uart_##n##data, \ + &rzt2m_uart_##n##_config, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ + &rzt2m_uart_api); + +DT_INST_FOREACH_STATUS_OKAY(UART_RZT2M_INIT) diff --git a/drivers/serial/uart_rzt2m.h b/drivers/serial/uart_rzt2m.h new file mode 100644 index 000000000000000..829064857b059b8 --- /dev/null +++ b/drivers/serial/uart_rzt2m.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SERIAL_UART_RZT2M_H_ +#define ZEPHYR_DRIVERS_SERIAL_UART_RZT2M_H_ + +#include + +#define MAX_FIFO_DEPTH 16 + +#define RDR(base) ((volatile uint32_t *)(base)) +#define TDR(base) ((volatile uint32_t *)(base + 0x04)) +#define CCR0(base) ((volatile uint32_t *)(base + 0x08)) +#define CCR1(base) ((volatile uint32_t *)(base + 0x0c)) +#define CCR2(base) ((volatile uint32_t *)(base + 0x10)) +#define CCR3(base) ((volatile uint32_t *)(base + 0x14)) +#define CCR4(base) ((volatile uint32_t *)(base + 0x18)) +#define FCR(base) ((volatile uint32_t *)(base + 0x24)) +#define CSR(base) ((volatile uint32_t *)(base + 0x48)) +#define FRSR(base) ((volatile uint32_t *)(base + 0x50)) +#define FTSR(base) ((volatile uint32_t *)(base + 0x54)) +#define CFCLR(base) ((volatile uint32_t *)(base + 0x68)) +#define FFCLR(base) ((volatile uint32_t *)(base + 0x70)) + +#define CCR0_DEFAULT_VALUE 0x0 +#define CCR1_DEFAULT_VALUE 0x00000010 +#define CCR2_DEFAULT_VALUE 0xff00ff04 +#define CCR3_DEFAULT_VALUE 0x00001203 +#define CCR4_DEFAULT_VALUE 0x0 + +#define RDR_MASK_RDAT GENMASK(8, 0) + +#define CCR0_MASK_RE BIT(0) +#define CCR0_MASK_TE BIT(4) +#define CCR0_MASK_DCME BIT(9) +#define CCR0_MASK_IDSEL BIT(10) +#define CCR0_MASK_RIE BIT(16) +#define CCR0_MASK_TIE BIT(20) +#define CCR0_MASK_TEIE BIT(21) +#define CCR0_MASK_SSE BIT(24) + +#define CCR1_MASK_CTSE BIT(0) +#define CCR1_MASK_SPB2DT BIT(4) +#define CCR1_MASK_SPB2IO BIT(5) +#define CCR1_MASK_PE BIT(8) +#define CCR1_MASK_PM BIT(9) +#define CCR1_MASK_NFEN BIT(28) + +#define CCR2_MASK_BGDM BIT(4) +#define CCR2_MASK_ABCS BIT(5) +#define CCR2_MASK_ABCSE BIT(6) +#define CCR2_MASK_BRR GENMASK(15, 8) +#define CCR2_MASK_BRME BIT(16) +#define CCR2_MASK_CKS GENMASK(21, 20) +#define CCR2_MASK_MDDR GENMASK(31, 24) +#define CCR2_MASK_BAUD_SETTING \ + (CCR2_MASK_BRME | CCR2_MASK_ABCSE | CCR2_MASK_ABCS | CCR2_MASK_BGDM | CCR2_MASK_CKS | \ + CCR2_MASK_BRR | CCR2_MASK_MDDR) + +#define CCR3_MASK_STP BIT(14) +#define CCR3_MASK_MP BIT(19) +#define CCR3_MASK_FM BIT(20) +#define CCR3_MASK_CKE (BIT(24) | BIT(25)) +#define CCR3_CKE_ENABLE BIT(24) +#define CCR3_CHR_7BIT (BIT(8) | BIT(9)) +#define CCR3_CHR_8BIT BIT(9) + +#define CCR4_MASK_ASEN BIT(16) +#define CCR4_MASK_ATEN BIT(17) + +#define FCR_MASK_TFRST BIT(15) +#define FCR_MASK_RFRST BIT(23) +#define FCR_MASK_TTRG GENMASK(12, 8) +#define FCR_MASK_RTRG GENMASK(20, 16) +#define FCR_TTRG_15 (15 << 8) +#define FCR_RTRG_15 (15 << 16) + +#define CSR_MASK_ORER BIT(24) +#define CSR_MASK_PER BIT(27) +#define CSR_MASK_FER BIT(28) +#define CSR_MASK_TDRE BIT(29) +#define CSR_MASK_TEND BIT(30) +#define CSR_MASK_RDRF BIT(31) + +#define FRSR_MASK_DR BIT(0) +#define FRSR_R(val) ((val >> 7) & 0x3f) + +#define FTSR_T(val) (val & 0x3f) + +#define CFCLR_MASK_ERSC BIT(4) +#define CFCLR_MASK_DCMFC BIT(16) +#define CFCLR_MASK_DPERC BIT(17) +#define CFCLR_MASK_DFERC BIT(18) +#define CFCLR_MASK_ORERC BIT(24) +#define CFCLR_MASK_MFFC BIT(26) +#define CFCLR_MASK_PERC BIT(27) +#define CFCLR_MASK_FERC BIT(28) +#define CFCLR_MASK_TDREC BIT(29) +#define CFCLR_MASK_RDRFC BIT(31) +#define CFCLR_ALL_FLAG_CLEAR \ + (CFCLR_MASK_ERSC | CFCLR_MASK_DCMFC | CFCLR_MASK_DPERC | CFCLR_MASK_DFERC | \ + CFCLR_MASK_ORERC | CFCLR_MASK_MFFC | CFCLR_MASK_PERC | CFCLR_MASK_FERC | \ + CFCLR_MASK_TDREC | CFCLR_MASK_RDRFC) + +#define FFCLR_MASK_DRC BIT(0) + +#define MSTPCRA (volatile uint32_t *)(0x80280000 + 0x300) +#define MSTPCRA_MASK_SCIx(x) BIT(x + 8) +#define BASE_TO_IFACE_ID(base) ((base & 0x1000000) ? 5 : ((base & 0xff00) >> 10) - 4) + +#define CCR2_MDDR_128 BIT(31) +#define CCR2_CKS_0 0 +#define CCR2_BRME_0 0 +#define CCR2_BRR_243 (0xf3 << 8) +#define CCR2_BRR_39 (0x27 << 8) +#define CCR2_BGDM_1 BIT(4) + +#define CCR2_BAUD_SETTING_9600 (CCR2_MDDR_128 | CCR2_BRR_243) +#define CCR2_BAUD_SETTING_115200 (CCR2_MDDR_128 | CCR2_BRR_39 | CCR2_BGDM_1) + +#endif /* ZEPHYR_DRIVERS_SERIAL_UART_RZT2M_H_ */ diff --git a/dts/arm/renesas/rzt2m.dtsi b/dts/arm/renesas/rzt2m.dtsi index 44e045014a95c48..7ac60cdf99cbaf7 100644 --- a/dts/arm/renesas/rzt2m.dtsi +++ b/dts/arm/renesas/rzt2m.dtsi @@ -88,5 +88,30 @@ reg = <0x81281a00 0x10>; reg-io-width = <4>; }; + + uart0: serial@80001000 { + compatible = "renesas,rzt2m-uart"; + reg = <0x80001000 0x1000>; + current-speed = <115200>; + interrupts = , + , + , + ; + interrupt-names = "rx_err", "rx", "tx", "tx_end"; + status = "disabled"; + }; + + uart3: serial@80001c00 { + compatible = "renesas,rzt2m-uart"; + reg = <0x80001c00 0x1000>; + current-speed = <115200>; + interrupts = , + , + , + ; + interrupt-names = "rx_err", "rx", "tx", "tx_end"; + status = "disabled"; + }; + }; }; diff --git a/dts/bindings/serial/renesas,rzt2m-uart.yaml b/dts/bindings/serial/renesas,rzt2m-uart.yaml new file mode 100644 index 000000000000000..967972ac7c83645 --- /dev/null +++ b/dts/bindings/serial/renesas,rzt2m-uart.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RZ/T2M UART + +compatible: "renesas,rzt2m-uart" + +include: + - name: uart-controller.yaml + - name: pinctrl-device.yaml + +properties: + reg: + required: true + + current-speed: + required: true + description: | + Initial baud rate setting for UART. Only a fixed set of baud + rates is currently supported. + enum: + - 9600 + - 115200 + + interrupts: + required: true From 9e44f59e9a27f44d0ac9dd428536914e00b82ad4 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Wed, 4 Oct 2023 15:38:30 +0200 Subject: [PATCH 0455/1049] drivers: pinctrl: add RZT2M driver This adds a new driver for Renesas RZ/T2M. The driver allows configuration of pin direction, pull up/down resistors, drive strength and slew rate, and selection of function for a pin. Signed-off-by: Wojciech Sipak --- .../rzt2m_starterkit/rzt2m_starter_kit.dts | 27 ++++++ drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.rzt2m | 9 ++ drivers/pinctrl/pinctrl_rzt2m.c | 63 +++++++++++++ drivers/serial/Kconfig.rzt2m | 1 + drivers/serial/uart_rzt2m.c | 13 ++- dts/arm/renesas/rzt2m.dtsi | 5 + .../pinctrl/renesas,rzt2m-pinctrl.yaml | 93 +++++++++++++++++++ .../pinctrl/renesas-rzt2m-pinctrl.h | 18 ++++ soc/arm/renesas_rzt2m/pinctrl_soc.h | 57 ++++++++++++ 11 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 drivers/pinctrl/Kconfig.rzt2m create mode 100644 drivers/pinctrl/pinctrl_rzt2m.c create mode 100644 dts/bindings/pinctrl/renesas,rzt2m-pinctrl.yaml create mode 100644 include/zephyr/dt-bindings/pinctrl/renesas-rzt2m-pinctrl.h create mode 100644 soc/arm/renesas_rzt2m/pinctrl_soc.h diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts index a9cb6bcf65a84cd..ddada360b99e6c1 100644 --- a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts @@ -5,6 +5,7 @@ */ /dts-v1/; +#include #include / { @@ -18,10 +19,36 @@ }; }; + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + uart3_default: uart3_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; +}; + &uart0 { status = "okay"; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; }; &uart3 { status = "okay"; + pinctrl-0 = <&uart3_default>; + pinctrl-names = "default"; }; diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index ba49a637689d981..9455b6e7c78cfa2 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -37,3 +37,4 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_NUMAKER pinctrl_numaker.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_QUICKLOGIC_EOS_S3 pinctrl_eos_s3.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_RA pinctrl_ra.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCU pinctrl_imx_scu.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_RZT2M pinctrl_rzt2m.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index b7dc6c2fa693048..8a165725e4d5853 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -65,5 +65,6 @@ source "drivers/pinctrl/Kconfig.ti_cc32xx" source "drivers/pinctrl/Kconfig.numaker" source "drivers/pinctrl/Kconfig.eos_s3" source "drivers/pinctrl/Kconfig.ra" +source "drivers/pinctrl/Kconfig.rzt2m" endif # PINCTRL diff --git a/drivers/pinctrl/Kconfig.rzt2m b/drivers/pinctrl/Kconfig.rzt2m new file mode 100644 index 000000000000000..236afdcf55ec3bf --- /dev/null +++ b/drivers/pinctrl/Kconfig.rzt2m @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_RZT2M + bool "Renesas RZ/T2M pin controller driver" + default y + depends on DT_HAS_RENESAS_RZT2M_PINCTRL_ENABLED + help + Renesas RZ/T2M pinctrl driver diff --git a/drivers/pinctrl/pinctrl_rzt2m.c b/drivers/pinctrl/pinctrl_rzt2m.c new file mode 100644 index 000000000000000..0dff44619031c42 --- /dev/null +++ b/drivers/pinctrl/pinctrl_rzt2m.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_rzt2m_pinctrl + +#include +#include +#include + +#define PORT_NSR DT_INST_REG_ADDR_BY_NAME(0, port_nsr) +#define PTADR DT_INST_REG_ADDR_BY_NAME(0, ptadr) + +/* Port m mode control register */ +#define PMC(port) (PORT_NSR + 0x400 + port) +/* Port m function control register */ +#define PFC(port) (PORT_NSR + 0x600 + (0x4 * port)) +/* IO Buffer m function switching register */ +#define DRCTL(port, pin) (PORT_NSR + 0xa00 + (0x8 * port) + pin) +/* Port m region select register */ +#define RSELP(port) (PTADR + port) + +#define DRCTL_DRIVE_STRENGTH(val) (val & 0x3) +#define DRCTL_PULL_UP_DOWN(val) ((val & 0x3) << 2) +#define DRCTL_SCHMITT(val) ((val & 0x1) << 4) +#define DRCTL_SLEW_RATE(val) ((val & 0x1) << 5) +#define DRCTL_CONFIG(drive, pull, schmitt, slew) \ + (DRCTL_DRIVE_STRENGTH(drive) | DRCTL_PULL_UP_DOWN(pull) | DRCTL_SCHMITT(schmitt) | \ + DRCTL_SLEW_RATE(slew)) +#define PFC_FUNC_MASK(pin) (0xf << (pin * 4)) + +static void pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) +{ + uint8_t rselp = sys_read8(RSELP(pin->port)); + uint32_t pfc = sys_read32(PFC(pin->port)) & ~(PFC_FUNC_MASK(pin->pin)); + uint8_t pmc = sys_read8(PMC(pin->port)); + + /* Set proper bit in the RSELP register to use as non-safety domain. */ + sys_write8(rselp | BIT(pin->pin), RSELP(pin->port)); + sys_write8(DRCTL_CONFIG( + pin->drive_strength, (pin->pull_up == 1 ? 1U : (pin->pull_down == 1 ? 2U : 0)), + pin->schmitt_enable, pin->slew_rate), + DRCTL(pin->port, pin->pin)); + + /* Select function for the pin. */ + sys_write32(pfc | pin->func << (pin->pin * 4), PFC(pin->port)); + + /* Set proper bit in the PMC register to use the pin as a peripheral IO. */ + sys_write8(pmc | BIT(pin->pin), PMC(pin->port)); +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (uint8_t i = 0U; i < pin_cnt; i++) { + pinctrl_configure_pin(pins++); + } + + return 0; +} diff --git a/drivers/serial/Kconfig.rzt2m b/drivers/serial/Kconfig.rzt2m index bda26d628ad12da..2561499a5b5fd6c 100644 --- a/drivers/serial/Kconfig.rzt2m +++ b/drivers/serial/Kconfig.rzt2m @@ -7,5 +7,6 @@ config UART_RZT2M depends on DT_HAS_RENESAS_RZT2M_UART_ENABLED select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT + select PINCTRL help Enable Renesas RZ/T2M UART Driver. diff --git a/drivers/serial/uart_rzt2m.c b/drivers/serial/uart_rzt2m.c index afd012d5a8bf01c..e4ebe251f2105c9 100644 --- a/drivers/serial/uart_rzt2m.c +++ b/drivers/serial/uart_rzt2m.c @@ -8,6 +8,7 @@ #include "zephyr/spinlock.h" #include "zephyr/sys/printk.h" #include +#include #include #include #include @@ -20,6 +21,7 @@ LOG_MODULE_REGISTER(uart_renesas_rzt2m, CONFIG_UART_LOG_LEVEL); struct rzt2m_device_config { mm_reg_t base; + const struct pinctrl_dev_config *pin_config; uart_irq_config_func_t irq_config_func; }; @@ -297,6 +299,12 @@ static int rzt2m_uart_init(const struct device *dev) *CCR3(config->base) = CCR3_DEFAULT_VALUE; *CCR4(config->base) = CCR4_DEFAULT_VALUE; + /* Configure pinmuxes */ + ret = pinctrl_apply_state(config->pin_config, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + *CFCLR(config->base) = CFCLR_ALL_FLAG_CLEAR; *FFCLR(config->base) = FFCLR_MASK_DRC; @@ -414,6 +422,7 @@ static void uart_rzt2m_isr(const struct device *dev) } #define UART_RZT2M_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ static struct rzt2m_device_data rzt2m_uart_##n##data = { \ .uart_cfg = \ { \ @@ -427,7 +436,9 @@ static void uart_rzt2m_isr(const struct device *dev) }; \ UART_RZT2M_CONFIG_FUNC(n); \ static const struct rzt2m_device_config rzt2m_uart_##n##_config = { \ - .base = DT_INST_REG_ADDR(n), .irq_config_func = uart##n##_rzt2m_irq_config}; \ + .base = DT_INST_REG_ADDR(n), \ + .irq_config_func = uart##n##_rzt2m_irq_config, \ + .pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(n)}; \ DEVICE_DT_INST_DEFINE(n, &rzt2m_uart_init, NULL, &rzt2m_uart_##n##data, \ &rzt2m_uart_##n##_config, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ &rzt2m_uart_api); diff --git a/dts/arm/renesas/rzt2m.dtsi b/dts/arm/renesas/rzt2m.dtsi index 7ac60cdf99cbaf7..dada6ea55c781fc 100644 --- a/dts/arm/renesas/rzt2m.dtsi +++ b/dts/arm/renesas/rzt2m.dtsi @@ -113,5 +113,10 @@ status = "disabled"; }; + pinctrl: pinctrl@800a0000 { + compatible = "renesas,rzt2m-pinctrl"; + reg = <0x800a0000 0x1000 0x81030c00 0x1000>; + reg-names = "port_nsr", "ptadr"; + }; }; }; diff --git a/dts/bindings/pinctrl/renesas,rzt2m-pinctrl.yaml b/dts/bindings/pinctrl/renesas,rzt2m-pinctrl.yaml new file mode 100644 index 000000000000000..82016017201bcc0 --- /dev/null +++ b/dts/bindings/pinctrl/renesas,rzt2m-pinctrl.yaml @@ -0,0 +1,93 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: | + The Renesas RZ/T2M pin controller is a node responsible for controlling + pin function selection and pin properties, such as routing the TX and RX of UART0 + to pin 5 and pin 6 of port 16. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as shown in this example: + + /* You can put this in places like a board-pinctrl.dtsi file in + * your board directory, or a devicetree overlay in your application. + */ + + /* include pre-defined combinations for the SoC variant used by the board */ + #include + + &pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + }; + + The 'uart0_default' child node encodes the pin configurations for a + particular state of a device; in this case, the default (that is, active) + state. + + As shown, pin configurations are organized in groups within each child node. + Each group can specify a list of pin function selections in the 'pinmux' + property. + + A group can also specify shared pin properties common to all the specified + pins, such as the 'input-enable' property in group 2. + +compatible: "renesas,rzt2m-pinctrl" + +include: base.yaml + +child-binding: + description: | + Definitions for a pinctrl state. + child-binding: + + include: + - name: pincfg-node.yaml + property-allowlist: + - input-enable + - bias-pull-up + - bias-pull-down + - bias-high-impedance + - input-schmitt-enable + + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. Each + element of the array is an integer constructed from the + pin number and the alternative function of the pin. + drive-strength: + type: string + enum: + - "low" + - "middle" + - "high" + - "ultrahigh" + default: "low" + description: | + The drive strength of a pin, relative to full-driver strength. + The default value is "low", which is the reset value. + slew-rate: + type: string + enum: + - "slow" + - "fast" + default: "slow" + description: | + Select slew rate for a pin. The default is slow, which is the reset value. diff --git a/include/zephyr/dt-bindings/pinctrl/renesas-rzt2m-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/renesas-rzt2m-pinctrl.h new file mode 100644 index 000000000000000..ed1cbf7ee96b95c --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/renesas-rzt2m-pinctrl.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __RENESAS_RZT2M_PINCTRL_H__ +#define __RENESAS_RZT2M_PINCTRL_H__ + +#define RZT2M_PINMUX(port, pin, func) ((port << 16) | (pin << 8) | func) + +#define UART0TX_P16_5 RZT2M_PINMUX(16, 5, 1) +#define UART0RX_P16_6 RZT2M_PINMUX(16, 6, 2) + +#define UART3TX_P18_0 RZT2M_PINMUX(18, 0, 4) +#define UART3RX_P17_7 RZT2M_PINMUX(17, 7, 4) + +#endif /* __RENESAS_RZT2M_PINCTRL_H__ */ diff --git a/soc/arm/renesas_rzt2m/pinctrl_soc.h b/soc/arm/renesas_rzt2m/pinctrl_soc.h new file mode 100644 index 000000000000000..d740d6c115e9bd9 --- /dev/null +++ b/soc/arm/renesas_rzt2m/pinctrl_soc.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RZT2M_PINCTRL_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RZT2M_PINCTRL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pinctrl_soc_pin_t { + uint32_t port; + uint32_t pin; + uint32_t func; + uint32_t input_enable: 1; + uint32_t output_enable: 1; + uint32_t pull_up: 1; + uint32_t pull_down: 1; + uint32_t high_impedance: 1; + uint32_t slew_rate: 2; + uint8_t drive_strength; + uint32_t schmitt_enable: 1; +} pinctrl_soc_pin_t; + +#define RZT2M_GET_PORT(pinctrl) ((pinctrl >> 16) & 0xff) +#define RZT2M_GET_PIN(pinctrl) ((pinctrl >> 8) & 0xff) +#define RZT2M_GET_FUNC(pinctrl) (pinctrl & 0xff) + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + .port = RZT2M_GET_PORT(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .pin = RZT2M_GET_PIN(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .func = RZT2M_GET_FUNC(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .input_enable = DT_PROP(node_id, input_enable), \ + .pull_up = DT_PROP(node_id, bias_pull_up), \ + .pull_down = DT_PROP(node_id, bias_pull_down), \ + .high_impedance = DT_PROP(node_id, bias_high_impedance), \ + .slew_rate = DT_ENUM_IDX(node_id, slew_rate), \ + .drive_strength = DT_ENUM_IDX(node_id, drive_strength), \ + .schmitt_enable = DT_PROP(node_id, input_schmitt_enable), \ + }, + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + {DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), \ + DT_FOREACH_PROP_ELEM, pinmux, \ + Z_PINCTRL_STATE_PIN_INIT)} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_ARM_RENESAS_RZT2M_PINCTRL_H_ */ From 9265d2de0cd6f72e96e609ab0adbb9e6976bb09a Mon Sep 17 00:00:00 2001 From: Jakub Michalski Date: Tue, 3 Oct 2023 12:42:32 +0200 Subject: [PATCH 0456/1049] drivers: gpio: add rzt2m gpio driver Add Renesas rzt2m gpio driver with basic functionality. It supports pin mode configuration and writing/reading to/from gpio ports. Includes dts changes to build blinky sample. Signed-off-by: Jakub Michalski --- .../rzt2m_starterkit/rzt2m_starter_kit.dts | 24 ++ drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.rzt2m | 9 + drivers/gpio/gpio_rzt2m.c | 233 ++++++++++++++++++ dts/arm/renesas/rzt2m.dtsi | 26 ++ dts/bindings/gpio/renesas,rzt2m-gpio.yaml | 18 ++ .../dt-bindings/gpio/renesas-rzt2m-gpio.h | 39 +++ 8 files changed, 352 insertions(+) create mode 100644 drivers/gpio/Kconfig.rzt2m create mode 100644 drivers/gpio/gpio_rzt2m.c create mode 100644 dts/bindings/gpio/renesas,rzt2m-gpio.yaml create mode 100644 include/zephyr/dt-bindings/gpio/renesas-rzt2m-gpio.h diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts index ddada360b99e6c1..2568a542b5e2631 100644 --- a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts @@ -17,6 +17,30 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; }; + + aliases { + led0 = &led0; + }; + + leds { + compatible = "gpio-leds"; + led0: led0 { + gpios = <&gpio19 6 0>; + label = "led0"; + }; + led1: led1 { + gpios = <&gpio19 4 0>; + label = "led1"; + }; + led2: led2 { + gpios = <&gpio20 0 0>; + label = "led2"; + }; + led3: led3 { + gpios = <&gpio23 4 0>; + label = "led3"; + }; + }; }; diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 19c9d3e976cb0d8..0e94d78dba3d667 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -87,6 +87,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SEDI gpio_sedi.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ALTERA_PIO gpio_altera_pio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RA gpio_ra.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RZT2M gpio_rzt2m.c) if (CONFIG_GPIO_EMUL_SDL) zephyr_library_sources(gpio_emul_sdl.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 92d7b0587e9e78a..7ae1a8d0d939f7e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -214,4 +214,6 @@ source "drivers/gpio/Kconfig.bcm2711" source "drivers/gpio/Kconfig.ra" +source "drivers/gpio/Kconfig.rzt2m" + endif # GPIO diff --git a/drivers/gpio/Kconfig.rzt2m b/drivers/gpio/Kconfig.rzt2m new file mode 100644 index 000000000000000..d9cb6b1e8675592 --- /dev/null +++ b/drivers/gpio/Kconfig.rzt2m @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_RZT2M + bool "Renesas RZT2M GPIO" + default y + depends on DT_HAS_RENESAS_RZT2M_GPIO_ENABLED + help + Enable Renesas RZT2M GPIO driver. diff --git a/drivers/gpio/gpio_rzt2m.c b/drivers/gpio/gpio_rzt2m.c new file mode 100644 index 000000000000000..c2bfd1a4acd8b2c --- /dev/null +++ b/drivers/gpio/gpio_rzt2m.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_rzt2m_gpio + +#include +#include +#include +#include +#include +#include +#include + +#define PMm_OFFSET 0x200 +#define PINm_OFFSET 0x800 +#define DRCTLm_OFFSET 0xa00 + +#define DRIVE_SHIFT 0 +#define SCHMITT_TRIGGER_SHIFT 4 +#define SLEW_RATE_SHIFT 5 + +#define PULL_SHIFT 2 +#define PULL_NONE (0 << PULL_SHIFT) +#define PULL_UP (1 << PULL_SHIFT) +#define PULL_DOWN (2 << PULL_SHIFT) + +struct rzt2m_gpio_config { + struct gpio_driver_config common; + uint8_t *port_nsr; + uint8_t *ptadr; + uint8_t port; +}; + +struct rzt2m_gpio_data { + struct gpio_driver_data common; +}; + +static void rzt2m_gpio_unlock(void) +{ + rzt2m_unlock_prcrn(PRCRN_PRC1); + rzt2m_unlock_prcrs(PRCRS_GPIO); +} + +static void rzt2m_gpio_lock(void) +{ + rzt2m_lock_prcrn(PRCRN_PRC1); + rzt2m_lock_prcrs(PRCRS_GPIO); +} + +/* Port m output data store */ +static volatile uint8_t *rzt2m_gpio_get_p_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint8_t *)(config->port_nsr + config->port); +} + +/* Port m input data store */ +static volatile uint8_t *rzt2m_gpio_get_pin_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint8_t *)(config->port_nsr + PINm_OFFSET + config->port); +} + +/* Port m mode register */ +static volatile uint16_t *rzt2m_gpio_get_pm_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint16_t *)(config->port_nsr + PMm_OFFSET + 0x2 * config->port); +} + +/* IO Buffer m function switching register */ +static volatile uint64_t *rzt2m_gpio_get_drctl_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint64_t *)(config->port_nsr + DRCTLm_OFFSET + 0x8 * config->port); +} + +/* Port m region select register */ +static volatile uint8_t *rzt2m_gpio_get_rselp_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint8_t *)(config->ptadr + config->port); +} + +static int rzt2m_gpio_init(const struct device *dev) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *rselp_reg = rzt2m_gpio_get_rselp_reg(dev); + *rselp_reg = 0xFF; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_gpio_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *pin_reg = rzt2m_gpio_get_pin_reg(dev); + *value = *pin_reg; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *p_reg = rzt2m_gpio_get_p_reg(dev); + *p_reg = (*p_reg & ~mask) | (value & mask); + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *p_reg = rzt2m_gpio_get_p_reg(dev); + *p_reg |= pins; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *p_reg = rzt2m_gpio_get_p_reg(dev); + *p_reg &= ~pins; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_gpio_toggle(const struct device *dev, gpio_port_pins_t pins) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *p_reg = rzt2m_gpio_get_p_reg(dev); + *p_reg ^= pins; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_gpio_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + volatile uint16_t *pm_reg = rzt2m_gpio_get_pm_reg(dev); + volatile uint64_t *drctl_reg = rzt2m_gpio_get_drctl_reg(dev); + + rzt2m_gpio_unlock(); + + WRITE_BIT(*pm_reg, pin * 2, flags & GPIO_INPUT); + WRITE_BIT(*pm_reg, pin * 2 + 1, flags & GPIO_OUTPUT); + + if (flags & GPIO_OUTPUT) { + if (flags & GPIO_OUTPUT_INIT_LOW) { + rzt2m_port_clear_bits_raw(dev, 1 << pin); + } else if (flags & GPIO_OUTPUT_INIT_HIGH) { + rzt2m_port_set_bits_raw(dev, 1 << pin); + } + } + + if (flags & GPIO_PULL_UP && flags & GPIO_PULL_DOWN) { + rzt2m_gpio_lock(); + return -EINVAL; + } + + uint8_t drctl_pin_config = 0; + + if (flags & GPIO_PULL_UP) { + drctl_pin_config |= PULL_UP; + } else if (flags & GPIO_PULL_DOWN) { + drctl_pin_config |= PULL_DOWN; + } else { + drctl_pin_config |= PULL_NONE; + } + + drctl_pin_config |= + (flags & RZT2M_GPIO_DRIVE_MASK) >> (RZT2M_GPIO_DRIVE_OFFSET - DRIVE_SHIFT); + drctl_pin_config |= (flags & RZT2M_GPIO_SCHMITT_TRIGGER_MASK) >> + (RZT2M_GPIO_SCHMITT_TRIGGER_OFFSET - SCHMITT_TRIGGER_SHIFT); + drctl_pin_config |= (flags & RZT2M_GPIO_SLEW_RATE_MASK) >> + (RZT2M_GPIO_SLEW_RATE_OFFSET - SLEW_RATE_SHIFT); + + uint64_t drctl_pin_value = *drctl_reg & ~(0xFFULL << (pin * 8)); + *drctl_reg = drctl_pin_value | ((uint64_t)drctl_pin_config << (pin * 8)); + + rzt2m_gpio_lock(); + + return 0; +} + +static const struct gpio_driver_api rzt2m_gpio_driver_api = { + .pin_configure = rzt2m_gpio_configure, + .port_get_raw = rzt2m_gpio_get_raw, + .port_set_masked_raw = rzt2m_port_set_masked_raw, + .port_set_bits_raw = rzt2m_port_set_bits_raw, + .port_clear_bits_raw = rzt2m_port_clear_bits_raw, + .port_toggle_bits = rzt2m_gpio_toggle}; + +#define RZT2M_GPIO_DEFINE(inst) \ + static struct rzt2m_gpio_data rzt2m_gpio_data##inst; \ + static struct rzt2m_gpio_config rzt2m_gpio_config##inst = { \ + .port_nsr = (uint8_t *)DT_REG_ADDR_BY_NAME(DT_INST_PARENT(inst), port_nsr), \ + .ptadr = (uint8_t *)DT_REG_ADDR_BY_NAME(DT_INST_PARENT(inst), ptadr), \ + .port = DT_INST_REG_ADDR(inst), \ + .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst)}}; \ + DEVICE_DT_INST_DEFINE(inst, rzt2m_gpio_init, NULL, &rzt2m_gpio_data##inst, \ + &rzt2m_gpio_config##inst, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &rzt2m_gpio_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RZT2M_GPIO_DEFINE) diff --git a/dts/arm/renesas/rzt2m.dtsi b/dts/arm/renesas/rzt2m.dtsi index dada6ea55c781fc..9c6c1688d63d34a 100644 --- a/dts/arm/renesas/rzt2m.dtsi +++ b/dts/arm/renesas/rzt2m.dtsi @@ -117,6 +117,32 @@ compatible = "renesas,rzt2m-pinctrl"; reg = <0x800a0000 0x1000 0x81030c00 0x1000>; reg-names = "port_nsr", "ptadr"; + #address-cells = <1>; + #size-cells = <0>; + + gpio19: gpio@13 { + compatible = "renesas,rzt2m-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + reg = <0x13>; + }; + + gpio20: gpio@14 { + compatible = "renesas,rzt2m-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + reg = <0x14>; + }; + + gpio23: gpio@17 { + compatible = "renesas,rzt2m-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + reg = <0x17>; + }; }; }; }; diff --git a/dts/bindings/gpio/renesas,rzt2m-gpio.yaml b/dts/bindings/gpio/renesas,rzt2m-gpio.yaml new file mode 100644 index 000000000000000..e099c81753e1704 --- /dev/null +++ b/dts/bindings/gpio/renesas,rzt2m-gpio.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 +description: Renesas RZT2M GPIO + +compatible: "renesas,rzt2m-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/include/zephyr/dt-bindings/gpio/renesas-rzt2m-gpio.h b/include/zephyr/dt-bindings/gpio/renesas-rzt2m-gpio.h new file mode 100644 index 000000000000000..8bd26d46434d205 --- /dev/null +++ b/include/zephyr/dt-bindings/gpio/renesas-rzt2m-gpio.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZT2M_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZT2M_H_ +#include + +#define RZT2M_GPIO_DRIVE_OFFSET 8 +#define RZT2M_GPIO_DRIVE_MASK GENMASK(RZT2M_GPIO_DRIVE_OFFSET + 2, RZT2M_GPIO_DRIVE_OFFSET) + +/** + * @brief Select GPIO pin drive strength + */ +#define RZT2M_GPIO_DRIVE_LOW (0U << RZT2M_GPIO_DRIVE_OFFSET) +#define RZT2M_GPIO_DRIVE_MIDDLE (1U << RZT2M_GPIO_DRIVE_OFFSET) +#define RZT2M_GPIO_DRIVE_HIGH (2U << RZT2M_GPIO_DRIVE_OFFSET) +#define RZT2M_GPIO_DRIVE_ULTRA_HIGH (3U << RZT2M_GPIO_DRIVE_OFFSET) + +#define RZT2M_GPIO_SCHMITT_TRIGGER_OFFSET 10 +#define RZT2M_GPIO_SCHMITT_TRIGGER_MASK BIT(RZT2M_GPIO_SCHMITT_TRIGGER_OFFSET) + +/** + * @brief Enable GPIO pin schmitt trigger + */ +#define RZT2M_GPIO_SCHMITT_TRIGGER BIT(RZT2M_GPIO_SCHMITT_TRIGGER_OFFSET) + +#define RZT2M_GPIO_SLEW_RATE_OFFSET 11 +#define RZT2M_GPIO_SLEW_RATE_MASK BIT(RZT2M_GPIO_SLEW_RATE_OFFSET) + +/** + * @brief Select GPIO pin slew rate + */ +#define RZT2M_GPIO_SLEW_RATE_SLOW 0U +#define RZT2M_GPIO_SLEW_RATE_FAST BIT(RZT2M_GPIO_SLEW_RATE_OFFSET) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZT2M_H_ */ From 8fe2c958079e7ce0480b09de0846b493c34cc208 Mon Sep 17 00:00:00 2001 From: Jiafei Pan Date: Thu, 31 Aug 2023 16:39:29 +0800 Subject: [PATCH 0457/1049] soc: arm64: mimx8m & 9: define SOC name followed by Core name In hal driver, MCUX_DEVICE is defined from CONFIG_SOC, so unify MCUX_DEVICE definition with mcux-sdk. Signed-off-by: Jiafei Pan --- soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mm | 4 ++-- soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mn | 4 ++-- soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mp | 4 ++-- soc/arm64/nxp_imx/mimx9/Kconfig.defconfig.mimx93 | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mm b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mm index a35ff4951ef2c68..a77d9f837dff8ff 100644 --- a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mm +++ b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mm @@ -1,10 +1,10 @@ -# Copyright 2020-2022 NXP +# Copyright 2020-2023 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_MIMX8MM_A53 config SOC - default "mimx8mm6" + default "mimx8mm6_ca53" # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash diff --git a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mn b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mn index 9c5e7bfe04128ee..c6c2837d74de185 100644 --- a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mn +++ b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mn @@ -1,10 +1,10 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_MIMX8MN_A53 config SOC - default "mimx8mn6" + default "mimx8mn6_ca53" # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash diff --git a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mp b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mp index 5a99f354e5d4a7a..ebdfa764a699172 100644 --- a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mp +++ b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mp @@ -1,10 +1,10 @@ -# Copyright 2021-2022 NXP +# Copyright 2021-2023 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_MIMX8MP_A53 config SOC - default "mimx8ml8" + default "mimx8ml8_ca53" # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash diff --git a/soc/arm64/nxp_imx/mimx9/Kconfig.defconfig.mimx93 b/soc/arm64/nxp_imx/mimx9/Kconfig.defconfig.mimx93 index 5927717506377dd..45e67de35eda52f 100644 --- a/soc/arm64/nxp_imx/mimx9/Kconfig.defconfig.mimx93 +++ b/soc/arm64/nxp_imx/mimx9/Kconfig.defconfig.mimx93 @@ -1,10 +1,10 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_MIMX93_A55 config SOC - default "mimx9352" + default "mimx9352_ca55" # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash From 5b99d826b2e415ed74f3c3b134a2443731fa78a3 Mon Sep 17 00:00:00 2001 From: Jiafei Pan Date: Thu, 31 Aug 2023 17:04:15 +0800 Subject: [PATCH 0458/1049] west.yml: update hal_nxp commit Update to 03bd989de4d2de151470e8b6068bc5686f3fc84c Signed-off-by: Jiafei Pan --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 3c50603e8c8248f..8bd529816648de3 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 78d1912dbc2b5f6e114d7fd19a31053716a3b01d + revision: 03bd989de4d2de151470e8b6068bc5686f3fc84c path: modules/hal/nxp groups: - hal From 6bd52ae87fa4dee0e4df1572a2f59efb0bd8106a Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Mon, 13 Nov 2023 11:06:54 +0100 Subject: [PATCH 0459/1049] doc: dlist: Add "container struct type pointer" description Add "container struct type pointer" description to SYS_DLIST_FOR_EACH_CONTAINER() and SYS_DLIST_FOR_EACH_CONTAINER_SAFE(). Signed-off-by: Andrej Butok --- include/zephyr/sys/dlist.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zephyr/sys/dlist.h b/include/zephyr/sys/dlist.h index 4c330c8f04e41cb..03f2a5e94c802ef 100644 --- a/include/zephyr/sys/dlist.h +++ b/include/zephyr/sys/dlist.h @@ -165,7 +165,7 @@ typedef struct _dnode sys_dnode_t; * } * * @param __dl A pointer on a sys_dlist_t to iterate on - * @param __cn A pointer to peek each entry of the list + * @param __cn A container struct type pointer to peek each entry of the list * @param __n The field name of sys_dnode_t within the container struct */ #define SYS_DLIST_FOR_EACH_CONTAINER(__dl, __cn, __n) \ @@ -184,8 +184,8 @@ typedef struct _dnode sys_dnode_t; * } * * @param __dl A pointer on a sys_dlist_t to iterate on - * @param __cn A pointer to peek each entry of the list - * @param __cns A pointer for the loop to run safely + * @param __cn A container struct type pointer to peek each entry of the list + * @param __cns A container struct type pointer for the loop to run safely * @param __n The field name of sys_dnode_t within the container struct */ #define SYS_DLIST_FOR_EACH_CONTAINER_SAFE(__dl, __cn, __cns, __n) \ From 6348a973c38eeed5e18e6821dcb38a1c2f78ac76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B8e?= Date: Fri, 10 Nov 2023 16:15:56 +0100 Subject: [PATCH 0460/1049] soc: arm: Remove CPU_HAS_NRF_IDAU's dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPU_HAS_NRF_IDAU is depending on SOC_SERIES_NRF91X and SOC_NRF5340_CPUAPP. This makes it more difficult to have an out-of-tree nrf SOC. It is also an unnecessary dependency. There is no prompt for CPU_HAS_NRF_IDAU, so it will not show up in menuconfig and it won't be possible to enable it from a users Kconfig fragment. The only way to enable it is to select it, and those that select this option can themselves make sure that they only do so when appropriate. Also, move NRF_SPU options out to SOC Kconfig files to also make out-of-tree SoCs possible. With the added benefit of not polluting the common soc/arm/Kconfig. Signed-off-by: Sebastian Bøe --- soc/arm/Kconfig | 16 ---------------- soc/arm/nordic_nrf/nrf53/Kconfig.soc | 12 ++++++++++++ soc/arm/nordic_nrf/nrf91/Kconfig.series | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/soc/arm/Kconfig b/soc/arm/Kconfig index 443a0031189f59c..461f0b41f84c0f8 100644 --- a/soc/arm/Kconfig +++ b/soc/arm/Kconfig @@ -34,28 +34,12 @@ config CPU_HAS_ARM_SAU config CPU_HAS_NRF_IDAU bool - depends on SOC_SERIES_NRF91X || SOC_NRF5340_CPUAPP select CPU_HAS_TEE help MCU implements the nRF (vendor-specific) Security Attribution Unit. (IDAU: "Implementation-Defined Attribution Unit", in accordance with ARM terminology). -if CPU_HAS_NRF_IDAU -config NRF_SPU_FLASH_REGION_SIZE - hex - default 0x8000 if SOC_SERIES_NRF91X - default 0x4000 if SOC_NRF5340_CPUAPP - help - FLASH region size for the NRF_SPU peripheral - -config NRF_SPU_RAM_REGION_SIZE - hex - default 0x2000 if SOC_SERIES_NRF91X || SOC_NRF5340_CPUAPP - help - RAM region size for the NRF_SPU peripheral -endif - config HAS_SWO bool help diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index f6a2c019f5fdaea..3afcd96f70d0b3b 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.soc @@ -98,6 +98,18 @@ config SOC_DCDC_NRF53X_HV help Enable nRF53 series System on Chip High Voltage DC/DC converter. +config NRF_SPU_FLASH_REGION_SIZE + hex + default 0x4000 + help + FLASH region size for the NRF_SPU peripheral + +config NRF_SPU_RAM_REGION_SIZE + hex + default 0x2000 + help + RAM region size for the NRF_SPU peripheral + config SOC_NRF_GPIO_FORWARDER_FOR_NRF5340 bool depends on NRF_SOC_SECURE_SUPPORTED diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.series b/soc/arm/nordic_nrf/nrf91/Kconfig.series index c30132c7bac040b..1be69c377e5e0ba 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.series @@ -19,3 +19,17 @@ config SOC_SERIES_NRF91X select HAS_POWEROFF help Enable support for NRF91 MCU series + +if SOC_SERIES_NRF91X +config NRF_SPU_FLASH_REGION_SIZE + hex + default 0x8000 + help + FLASH region size for the NRF_SPU peripheral + +config NRF_SPU_RAM_REGION_SIZE + hex + default 0x2000 + help + RAM region size for the NRF_SPU peripheral +endif From fd9a4644954b73563d29ee4068fa267e7b7ba4cb Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 13 Nov 2023 14:58:46 +0000 Subject: [PATCH 0461/1049] toolchain: llvm: use the "none" vendor triplet This was submitted with "cros" in 77dde5dc9f, it was meant to be "none". Signed-off-by: Fabio Baltieri --- cmake/toolchain/llvm/target.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/toolchain/llvm/target.cmake b/cmake/toolchain/llvm/target.cmake index 380972291254da0..5c06af5f25fa7c4 100644 --- a/cmake/toolchain/llvm/target.cmake +++ b/cmake/toolchain/llvm/target.cmake @@ -16,7 +16,7 @@ if("${ARCH}" STREQUAL "arm") elseif(DEFINED CONFIG_ARMV7_M_ARMV8_M_MAINLINE) # ARMV7_M_ARMV8_M_MAINLINE means that ARMv7-M or backward compatible ARMv8-M # processor is used. - set(triple armv7m-cros-eabi) + set(triple armv7m-none-eabi) elseif(DEFINED CONFIG_ARMV6_M_ARMV8_M_BASELINE) # ARMV6_M_ARMV8_M_BASELINE means that ARMv6-M or ARMv8-M supporting the # Baseline implementation processor is used. From 093f9a9df2934329d366896227f0e3deb578ac7f Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 9 Nov 2023 12:25:32 -0500 Subject: [PATCH 0462/1049] tests: adc: cleanup test tags Remove platform specific tags and be consistent. Signed-off-by: Anas Nashif --- .../boards/stm32/power_mgmt/adc/sample.yaml | 2 +- samples/drivers/adc/sample.yaml | 3 ++- samples/drivers/soc_flash_nrf/sample.yaml | 3 +-- tests/drivers/build_all/adc/testcase.yaml | 23 ------------------- 4 files changed, 4 insertions(+), 27 deletions(-) diff --git a/samples/boards/stm32/power_mgmt/adc/sample.yaml b/samples/boards/stm32/power_mgmt/adc/sample.yaml index e27cc5b268da14d..e3892df7b5cedda 100644 --- a/samples/boards/stm32/power_mgmt/adc/sample.yaml +++ b/samples/boards/stm32/power_mgmt/adc/sample.yaml @@ -3,7 +3,7 @@ sample: tests: sample.boards.stm32.power_mgmt.adc: tags: - - ADC + - adc - power harness: console harness_config: diff --git a/samples/drivers/adc/sample.yaml b/samples/drivers/adc/sample.yaml index 0af996a8babed3f..2ed1681a0e0c004 100644 --- a/samples/drivers/adc/sample.yaml +++ b/samples/drivers/adc/sample.yaml @@ -2,7 +2,8 @@ sample: name: ADC driver sample tests: sample.drivers.adc: - tags: ADC + tags: + - adc depends_on: adc platform_allow: - nucleo_l073rz diff --git a/samples/drivers/soc_flash_nrf/sample.yaml b/samples/drivers/soc_flash_nrf/sample.yaml index 6557988b6e3a572..b8a59328be40778 100644 --- a/samples/drivers/soc_flash_nrf/sample.yaml +++ b/samples/drivers/soc_flash_nrf/sample.yaml @@ -10,8 +10,7 @@ tests: - nrf52dk_nrf52832 tags: - flash - - nrf52 - - nrf9160 + - drivers harness: console harness_config: fixture: external_flash diff --git a/tests/drivers/build_all/adc/testcase.yaml b/tests/drivers/build_all/adc/testcase.yaml index c8a6fe5e3a7786b..a8102364b609211 100644 --- a/tests/drivers/build_all/adc/testcase.yaml +++ b/tests/drivers/build_all/adc/testcase.yaml @@ -9,53 +9,30 @@ tests: platform_allow: - native_posix - native_posix_64 - tags: - - adc_mcp302x - - adc_lmp90xxx - - adc_ads1x1x - - adc_ads1119 - - adc_ads1112 - - adc_ads114s08 - - adc_emul - - adc_max1125x - - adc_ltc2451 extra_args: "CONFIG_GPIO=y" drivers.adc.cc32xx.build: platform_allow: cc3220sf_launchxl - tags: adc_cc32xx drivers.adc.ite.it8xxx2.build: platform_allow: it8xxx2_evb - tags: adc_ite_it8xxx2 drivers.adc.mcux.adc12.build: platform_allow: twr_ke18f - tags: adc_mcux_adc12 drivers.adc.mcux.adc16.build: platform_allow: frdm_k22f - tags: adc_mcux_adc16 drivers.adc.mcux.lpadc.build: platform_allow: lpcxpresso55s28 - tags: adc_mcux_lpadc drivers.adc.npcx.build: platform_allow: npcx7m6fb_evb - tags: adc_npcx drivers.adc.nrf.build: platform_allow: nrf51dk_nrf51422 - tags: adc_nrfx_adc drivers.adc.nrf.saadc.build: platform_allow: nrf21540dk_nrf52840 - tags: adc_nrfx_saadc drivers.adc.sam0.build: platform_allow: atsame54_xpro - tags: adc_sam0 drivers.adc.sam.afec.build: platform_allow: sam_e70_xplained - tags: adc_sam_afec drivers.adc.stm32.build: platform_allow: disco_l475_iot1 - tags: adc_stm32 drivers.adc.xec.build: platform_allow: mec15xxevb_assy6853 - tags: adc_xec drivers.adc.test.build: platform_allow: qemu_cortex_m3 - tags: adc_test From 9ff81c154169babcca29611fb4eb2a90c6073da3 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 9 Nov 2023 12:26:47 -0500 Subject: [PATCH 0463/1049] tests: pwm: cleanup test tags Remove platform specific tags and be consistent. Signed-off-by: Anas Nashif --- tests/drivers/build_all/pwm/testcase.yaml | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/tests/drivers/build_all/pwm/testcase.yaml b/tests/drivers/build_all/pwm/testcase.yaml index 5a4477374ff7fde..61d93f789d07538 100644 --- a/tests/drivers/build_all/pwm/testcase.yaml +++ b/tests/drivers/build_all/pwm/testcase.yaml @@ -6,73 +6,51 @@ common: tests: drivers.pwm.cc13xx_cc26xx_timer.build: platform_allow: cc1352p1_launchxl - tags: pwm_cc13xx_cc26xx_timer drivers.pwm.gecko.build: platform_allow: efr32_radio_brd4250b - tags: pwm_gecko drivers.pwm.imx.build: platform_allow: colibri_imx7d_m4 - tags: pwm_imx drivers.pwm.litex.build: platform_allow: litex_vexriscv - tags: pwm_litex drivers.pwm.mcux.ftm.build: platform_allow: frdm_k22f - tags: pwm_mcux_ftm drivers.pwm.mcux.pwt.build: platform_allow: twr_ke18f - tags: pwm_mcux_pwt extra_configs: - CONFIG_PWM_CAPTURE=y drivers.pwm.mcux.tpm.build: platform_allow: frdm_kw41z - tags: pwm_mcux_tpm drivers.pwm.mcux.build: platform_allow: mimxrt1064_evk - tags: pwm_mcux drivers.pwm.mcux.sctimer.build: platform_allow: mimxrt685_evk_cm33 - tags: pwm_mcux_sctimer drivers.pwm.rv32m1.tpm.build: platform_allow: rv32m1_vega_ri5cy - tags: pwm_rv32m1_tpm drivers.pwm.sifive.build: platform_allow: hifive1_revb - tags: pwm_sifive drivers.pwm.npcx.build: platform_allow: npcx7m6fb_evb - tags: pwm_npcx drivers.pwm.nrf.sw.build: platform_allow: nrf51dk_nrf51422 - tags: pwm_nrf5_sw drivers.pwm.nrf.build: platform_allow: nrf52840dk_nrf52840 - tags: pwm_nrfx drivers.pwm.pca9685.build: platform_allow: nrf52840dk_nrf52840 extra_args: SHIELD=adafruit_pca9685 - tags: pwm_pca9685 drivers.pwm.sam0.tcc.build: platform_allow: atsame54_xpro - tags: pwm_sam0_tcc drivers.pwm.build.sam: platform_allow: - sam_e70_xplained - sam_v71b_xult - tags: pwm_sam drivers.pwm.stm32.build: platform_allow: disco_l475_iot1 - tags: pwm_stm32 drivers.pwm.xec.build: platform_allow: mec15xxevb_assy6853 - tags: pwm_xec drivers.pwm.build.xlnx: platform_allow: arty_a7_arm_designstart_m1 - tags: pwm_xlnx_axi_timer drivers.pwm.build.test: platform_allow: qemu_cortex_m3 - tags: pwm_test drivers.pwm.max31790.build: platform_allow: nucleo_f429zi extra_args: DTC_OVERLAY_FILE=max31790.overlay - tags: pwm_max31790 From d9d7e6a2f4e12908206090d8794addf8fd0e47ce Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 9 Nov 2023 12:27:44 -0500 Subject: [PATCH 0464/1049] tests: watchdog: cleanup test tags Remove platform specific tags and be consistent. Signed-off-by: Anas Nashif --- tests/drivers/build_all/watchdog/testcase.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/drivers/build_all/watchdog/testcase.yaml b/tests/drivers/build_all/watchdog/testcase.yaml index 3102453a7404777..82f8cd027bd2303 100644 --- a/tests/drivers/build_all/watchdog/testcase.yaml +++ b/tests/drivers/build_all/watchdog/testcase.yaml @@ -1,9 +1,10 @@ common: build_only: true - tags: drivers watchdog + tags: + - drivers + - watchdog tests: drivers.watchdog.build: # will cover drivers without in-tree boards platform_allow: qemu_cortex_m3 - tags: wdt_xilinx_axi extra_args: "CONFIG_WATCHDOG=y" From 131aa569003a83e24ad0849dd845dffa1f117e60 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 9 Nov 2023 12:28:23 -0500 Subject: [PATCH 0465/1049] tests: i2c: cleanup test tags Remove platform specific tags and be consistent. Signed-off-by: Anas Nashif --- tests/drivers/build_all/i2c/testcase.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/drivers/build_all/i2c/testcase.yaml b/tests/drivers/build_all/i2c/testcase.yaml index 36513e230a2f9c8..3c672c121676fcd 100644 --- a/tests/drivers/build_all/i2c/testcase.yaml +++ b/tests/drivers/build_all/i2c/testcase.yaml @@ -7,5 +7,4 @@ tests: drivers.i2c.build: # will cover drivers without in-tree boards platform_allow: qemu_cortex_m3 - tags: i2c_xilinx_axi extra_args: "CONFIG_I2C=y" From 743564e89ef9dcd7d12691e1a693b4d933f6080c Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 9 Nov 2023 12:29:48 -0500 Subject: [PATCH 0466/1049] tests: dac: cleanup test tags Remove platform specific tags and be consistent. Signed-off-by: Anas Nashif --- tests/drivers/build_all/dac/testcase.yaml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/drivers/build_all/dac/testcase.yaml b/tests/drivers/build_all/dac/testcase.yaml index 5796038ef9df9c9..12252b8661fa783 100644 --- a/tests/drivers/build_all/dac/testcase.yaml +++ b/tests/drivers/build_all/dac/testcase.yaml @@ -7,23 +7,12 @@ tests: drivers.dac.build: # will cover I2C, SPI based drivers platform_allow: native_posix - tags: - - dac_dacx0508 - - dac_dacx3608 - - dac_mcp4725 - - dac_mcp4728 - - dac_ltc1660 - - dac_ltc1665 extra_args: "CONFIG_GPIO=y" drivers.dac.mcux.build: platform_allow: frdm_k22f - tags: dac_mcux drivers.dac.mcux32.build: platform_allow: twr_ke18f - tags: dac_mcux32 drivers.dac.sam0.build: platform_allow: atsamd21_xpro - tags: dac_sam0 drivers.dac.stm32.build: platform_allow: nucleo_f091rc - tags: dac_stm32 From 153e6d9dc79e839f2f54f8008b2aaabc4af7a567 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 9 Nov 2023 12:38:54 -0500 Subject: [PATCH 0467/1049] tests: uart: cleanup test tags Remove platform specific tags and be consistent. Signed-off-by: Anas Nashif --- tests/drivers/build_all/uart/testcase.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/drivers/build_all/uart/testcase.yaml b/tests/drivers/build_all/uart/testcase.yaml index c652d1cb7671d0b..6c69f06e72012ba 100644 --- a/tests/drivers/build_all/uart/testcase.yaml +++ b/tests/drivers/build_all/uart/testcase.yaml @@ -7,6 +7,5 @@ tests: drivers.uart.build: # will cover drivers without in-tree boards platform_allow: qemu_cortex_m3 - tags: uart_cdns extra_configs: - CONFIG_SERIAL=y From d94bdafda669fdc2807e7664073a6686bebc4b96 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 9 Nov 2023 13:12:56 -0500 Subject: [PATCH 0468/1049] tests: clock_control: cleanup test tags and unify them Remove platform specific tags and be consistent. Signed-off-by: Anas Nashif --- samples/drivers/clock_control_litex/sample.yaml | 4 +--- tests/drivers/clock_control/adsp_clock/testcase.yaml | 2 +- tests/drivers/clock_control/clock_control_api/testcase.yaml | 4 ++-- .../drivers/clock_control/nrf_clock_calibration/testcase.yaml | 2 +- tests/drivers/clock_control/nrf_lf_clock_start/testcase.yaml | 2 +- tests/drivers/clock_control/nrf_onoff_and_bt/testcase.yaml | 2 +- tests/drivers/clock_control/onoff/testcase.yaml | 2 +- .../stm32_clock_configuration/stm32_common_core/testcase.yaml | 3 ++- 8 files changed, 10 insertions(+), 11 deletions(-) diff --git a/samples/drivers/clock_control_litex/sample.yaml b/samples/drivers/clock_control_litex/sample.yaml index 5c9ae55424f34e8..cf5618313c53d69 100644 --- a/samples/drivers/clock_control_litex/sample.yaml +++ b/samples/drivers/clock_control_litex/sample.yaml @@ -4,7 +4,5 @@ tests: sample.driver.clock_control_litex: platform_allow: litex_vexriscv tags: - - clock - - litex - - vexriscv + - clock_control - mmcm diff --git a/tests/drivers/clock_control/adsp_clock/testcase.yaml b/tests/drivers/clock_control/adsp_clock/testcase.yaml index 5abe4765022854b..48df05a84623538 100644 --- a/tests/drivers/clock_control/adsp_clock/testcase.yaml +++ b/tests/drivers/clock_control/adsp_clock/testcase.yaml @@ -2,7 +2,7 @@ tests: drivers.clock.adsp_clock_control: tags: - drivers - - clock + - clock_control platform_allow: intel_adsp_cavs25 integration_platforms: - intel_adsp_cavs25 diff --git a/tests/drivers/clock_control/clock_control_api/testcase.yaml b/tests/drivers/clock_control/clock_control_api/testcase.yaml index 18d75385551959f..be789c8382a316e 100644 --- a/tests/drivers/clock_control/clock_control_api/testcase.yaml +++ b/tests/drivers/clock_control/clock_control_api/testcase.yaml @@ -2,7 +2,7 @@ tests: drivers.clock.clock_control_nrf5: tags: - drivers - - cloc + - clock_control platform_allow: - nrf51dk_nrf51422 - nrf52dk_nrf52832 @@ -13,7 +13,7 @@ tests: drivers.clock.clock_control_nrf5_lfclk_rc: tags: - drivers - - clock + - clock_control platform_allow: - nrf51dk_nrf51422 - nrf52dk_nrf52832 diff --git a/tests/drivers/clock_control/nrf_clock_calibration/testcase.yaml b/tests/drivers/clock_control/nrf_clock_calibration/testcase.yaml index e7ac90ec7b9ad51..092471d30e4d69e 100644 --- a/tests/drivers/clock_control/nrf_clock_calibration/testcase.yaml +++ b/tests/drivers/clock_control/nrf_clock_calibration/testcase.yaml @@ -2,7 +2,7 @@ tests: drivers.clock.nrf5_clock_calibration: tags: - drivers - - clock + - clock_control platform_allow: - nrf51dk_nrf51422 - nrf52dk_nrf52832 diff --git a/tests/drivers/clock_control/nrf_lf_clock_start/testcase.yaml b/tests/drivers/clock_control/nrf_lf_clock_start/testcase.yaml index 01ba725e7807968..f4940d79896f69e 100644 --- a/tests/drivers/clock_control/nrf_lf_clock_start/testcase.yaml +++ b/tests/drivers/clock_control/nrf_lf_clock_start/testcase.yaml @@ -1,7 +1,7 @@ common: tags: - drivers - - clock + - clock_control integration_platforms: - nrf51dk_nrf51422 tests: diff --git a/tests/drivers/clock_control/nrf_onoff_and_bt/testcase.yaml b/tests/drivers/clock_control/nrf_onoff_and_bt/testcase.yaml index 04c107da9548fa3..19c774969335aad 100644 --- a/tests/drivers/clock_control/nrf_onoff_and_bt/testcase.yaml +++ b/tests/drivers/clock_control/nrf_onoff_and_bt/testcase.yaml @@ -2,7 +2,7 @@ tests: drivers.clock.nrf_onoff_and_bt: tags: - drivers - - clock + - clock_control platform_allow: - nrf51dk_nrf51422 - nrf52dk_nrf52832 diff --git a/tests/drivers/clock_control/onoff/testcase.yaml b/tests/drivers/clock_control/onoff/testcase.yaml index abedf82f2a4c5e8..a6e03d9a0eca884 100644 --- a/tests/drivers/clock_control/onoff/testcase.yaml +++ b/tests/drivers/clock_control/onoff/testcase.yaml @@ -2,7 +2,7 @@ tests: drivers.clock.clock_control_onoff: tags: - drivers - - clock + - clock_control platform_allow: - nrf51dk_nrf51422 - nrf52dk_nrf52832 diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/testcase.yaml b/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/testcase.yaml index da7df1639726c05..563108bfe91a965 100644 --- a/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/testcase.yaml +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32_common_core/testcase.yaml @@ -6,7 +6,8 @@ # - add the fixture in map file common: timeout: 5 - tags: clock-control + tags: + - clock_control tests: drivers.clock.stm32_clock_configuration.common_core.l4_l5.sysclksrc_pll_48_msi_4: extra_args: From c7ac9216408e096116578503864cd5cd3cdfccbb Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 15 Nov 2023 09:18:31 +0100 Subject: [PATCH 0469/1049] net: loopback: Register IPv4 netmask A proper netmask should be set on the loopback interface, so that source address selection work properly when there are multiple interfaces in the system. Signed-off-by: Robert Lubos --- drivers/net/loopback.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index cd9a0ee3e1bd38d..d8ae5ca1b05837e 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -42,12 +42,15 @@ static void loopback_init(struct net_if *iface) if (IS_ENABLED(CONFIG_NET_IPV4)) { struct in_addr ipv4_loopback = INADDR_LOOPBACK_INIT; + struct in_addr netmask = { { { 255, 0, 0, 0 } } }; ifaddr = net_if_ipv4_addr_add(iface, &ipv4_loopback, NET_ADDR_AUTOCONF, 0); if (!ifaddr) { LOG_ERR("Failed to register IPv4 loopback address"); } + + net_if_ipv4_set_netmask(iface, &netmask); } if (IS_ENABLED(CONFIG_NET_IPV6)) { From 92560ac0951a70da53ea1fcb28fcbd9bcce0d3a3 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Thu, 2 Nov 2023 18:22:25 +0100 Subject: [PATCH 0470/1049] manifest: update LVGL to add Kconfig guard Related to zephyrproject-rtos/lvgl#48 Signed-off-by: Fabian Blatz --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 8bd529816648de3..59ee67c81f69c57 100644 --- a/west.yml +++ b/west.yml @@ -274,7 +274,7 @@ manifest: revision: 842413c5fb98707eb5f26e619e8e792453877897 path: modules/lib/loramac-node - name: lvgl - revision: 8a6a2d1d29d17d1e4bdc94c243c146a39d635fdd + revision: 7c61a4cec26402d20c845c95dcad0e39dcd319f8 path: modules/lib/gui/lvgl - name: mbedtls revision: 7053083b0cff8462464e3cbb826e87852fc03da6 From 84c7f2fe0afa2e718c421302a280110b66dda111 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Wed, 25 Oct 2023 19:35:48 +0200 Subject: [PATCH 0471/1049] modules: lvgl: Fix usage of LVGL log levels Introduces a Kconfig symbol `LV_Z_LOG_LEVEL` because contrary to Zephyr the numerical value of log levels in LVGL increases with severity. Also support for the `LV_LOG_LEVEL_USER` is added. Resolves issue #64351. Signed-off-by: Fabian Blatz --- modules/lvgl/Kconfig | 30 +++++++++++++++++++++++++ modules/lvgl/input/lvgl_button_input.c | 2 +- modules/lvgl/input/lvgl_common_input.c | 2 +- modules/lvgl/input/lvgl_encoder_input.c | 2 +- modules/lvgl/input/lvgl_pointer_input.c | 2 +- modules/lvgl/input/lvgl_pointer_kscan.c | 2 +- modules/lvgl/lvgl.c | 12 +++++----- 7 files changed, 42 insertions(+), 10 deletions(-) diff --git a/modules/lvgl/Kconfig b/modules/lvgl/Kconfig index 9b73705ddb07364..4bd00b1bc55cd65 100644 --- a/modules/lvgl/Kconfig +++ b/modules/lvgl/Kconfig @@ -22,6 +22,36 @@ config LV_CONF_SKIP bool default n +config LV_USE_LOG + bool + +config LV_LOG_LEVEL_NONE + bool + +config LV_LOG_LEVEL_ERROR + bool + +config LV_LOG_LEVEL_WARN + bool + +config LV_LOG_LEVEL_INFO + bool + +config LV_LOG_LEVEL_USER + bool + +config LV_LOG_LEVEL_TRACE + bool + +config LV_Z_LOG_LEVEL + int + default 0 if LV_LOG_LEVEL_NONE || !LV_USE_LOG + default 1 if LV_LOG_LEVEL_ERROR + default 2 if LV_LOG_LEVEL_WARN + default 3 if LV_LOG_LEVEL_INFO + default 3 if LV_LOG_LEVEL_USER + default 4 if LV_LOG_LEVEL_TRACE + config APP_LINK_WITH_LVGL bool "Link 'app' with LVGL" default y diff --git a/modules/lvgl/input/lvgl_button_input.c b/modules/lvgl/input/lvgl_button_input.c index f9c9d59f4d53655..8ac96b7fed53213 100644 --- a/modules/lvgl/input/lvgl_button_input.c +++ b/modules/lvgl/input/lvgl_button_input.c @@ -11,7 +11,7 @@ #include -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); struct lvgl_button_input_config { struct lvgl_common_input_config common_config; /* Needs to be first member */ diff --git a/modules/lvgl/input/lvgl_common_input.c b/modules/lvgl/input/lvgl_common_input.c index f91b01bacd38ac5..2894538c62bc7c8 100644 --- a/modules/lvgl/input/lvgl_common_input.c +++ b/modules/lvgl/input/lvgl_common_input.c @@ -13,7 +13,7 @@ #include "lvgl_button_input.h" #include "lvgl_encoder_input.h" -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); lv_indev_t *lvgl_input_get_indev(const struct device *dev) { diff --git a/modules/lvgl/input/lvgl_encoder_input.c b/modules/lvgl/input/lvgl_encoder_input.c index a49f1eeca299e36..b68ca67b87149e2 100644 --- a/modules/lvgl/input/lvgl_encoder_input.c +++ b/modules/lvgl/input/lvgl_encoder_input.c @@ -11,7 +11,7 @@ #include -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); struct lvgl_encoder_input_config { struct lvgl_common_input_config common_config; /* Needs to be first member */ diff --git a/modules/lvgl/input/lvgl_pointer_input.c b/modules/lvgl/input/lvgl_pointer_input.c index 19c71eb197217d4..1abfd69d29ac460 100644 --- a/modules/lvgl/input/lvgl_pointer_input.c +++ b/modules/lvgl/input/lvgl_pointer_input.c @@ -12,7 +12,7 @@ #include #include -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); struct lvgl_pointer_input_config { struct lvgl_common_input_config common_config; /* Needs to be first member */ diff --git a/modules/lvgl/input/lvgl_pointer_kscan.c b/modules/lvgl/input/lvgl_pointer_kscan.c index 197106e4f2c3a5b..43c309349ed755f 100644 --- a/modules/lvgl/input/lvgl_pointer_kscan.c +++ b/modules/lvgl/input/lvgl_pointer_kscan.c @@ -10,7 +10,7 @@ #include "lvgl_display.h" #include -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); static lv_indev_drv_t indev_drv; #define KSCAN_NODE DT_CHOSEN(zephyr_keyboard_scan) diff --git a/modules/lvgl/lvgl.c b/modules/lvgl/lvgl.c index 0f4c24e9a34f257..76df359e7fc7361 100644 --- a/modules/lvgl/lvgl.c +++ b/modules/lvgl/lvgl.c @@ -17,9 +17,8 @@ #endif #include LV_MEM_CUSTOM_INCLUDE -#define LOG_LEVEL CONFIG_LV_LOG_LEVEL #include -LOG_MODULE_REGISTER(lvgl); +LOG_MODULE_REGISTER(lvgl, CONFIG_LV_Z_LOG_LEVEL); static lv_disp_drv_t disp_drv; struct lvgl_disp_data disp_data = { @@ -61,7 +60,7 @@ static uint8_t buf1[BUFFER_SIZE] #endif /* CONFIG_LV_Z_BUFFER_ALLOC_STATIC */ -#if CONFIG_LV_LOG_LEVEL != 0 +#if CONFIG_LV_Z_LOG_LEVEL != 0 /* * In LVGLv8 the signature of the logging callback has changes and it no longer * takes the log level as an integer argument. Instead, the log level is now @@ -83,7 +82,7 @@ static void lvgl_log(const char *buf) LOG_ERR("%s", buf + strlen("[Error] ")); break; case 'W': - LOG_WRN("%s", buf + strlen("Warn] ")); + LOG_WRN("%s", buf + strlen("[Warn] ")); break; case 'I': LOG_INF("%s", buf + strlen("[Info] ")); @@ -91,6 +90,9 @@ static void lvgl_log(const char *buf) case 'T': LOG_DBG("%s", buf + strlen("[Trace] ")); break; + case 'U': + LOG_INF("%s", buf + strlen("[User] ")); + break; } } #endif @@ -207,7 +209,7 @@ static int lvgl_init(void) lvgl_heap_init(); #endif -#if CONFIG_LV_LOG_LEVEL != 0 +#if CONFIG_LV_Z_LOG_LEVEL != 0 lv_log_register_print_cb(lvgl_log); #endif From 7fc83e36a3930246826693768f36c74807381f22 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Mon, 13 Nov 2023 17:20:12 +0100 Subject: [PATCH 0472/1049] doc: gsg: macOS: Do not require wget, use curl instead macOS ships with curl by default. There's no need to add additional tools to the installation when a perfectly good one ships with the OS. Signed-off-by: Carles Cufi --- doc/develop/getting_started/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/develop/getting_started/index.rst b/doc/develop/getting_started/index.rst index 495a3792b94ce10..201b2896d242e3f 100644 --- a/doc/develop/getting_started/index.rst +++ b/doc/develop/getting_started/index.rst @@ -132,7 +132,7 @@ The current minimum required version for the main dependencies are: .. code-block:: bash - brew install cmake ninja gperf python3 ccache qemu dtc wget libmagic + brew install cmake ninja gperf python3 ccache qemu dtc libmagic #. Add the Homebrew Python folder to the path, in order to be able to execute ``python`` and ``pip`` as well ``python3`` and ``pip3``. @@ -580,8 +580,8 @@ that are used to emulate, flash and debug Zephyr applications. .. code-block:: bash cd ~ - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_macos-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + curl -L -O https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_macos-x86_64.tar.xz + curl -L https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing If your host architecture is 64-bit ARM (Apple Silicon, also known as M1), replace ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM macOS SDK. From e91040917c4ea23008df0b544f3837705086985b Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 14 Nov 2023 16:58:58 +0100 Subject: [PATCH 0473/1049] doc: Reuse the same Zephyr SDK installation instructions Instead of keeping 2 copies of the same Zephyr SDK installation instructions, reuse a single copy by including it in the getting stated guide from the Zephyr SDK doc page. Signed-off-by: Carles Cufi --- doc/develop/getting_started/index.rst | 157 +------------------ doc/develop/toolchains/zephyr_sdk.rst | 210 ++++++++++++++------------ 2 files changed, 120 insertions(+), 247 deletions(-) diff --git a/doc/develop/getting_started/index.rst b/doc/develop/getting_started/index.rst index 201b2896d242e3f..d95651121bf878b 100644 --- a/doc/develop/getting_started/index.rst +++ b/doc/develop/getting_started/index.rst @@ -500,8 +500,8 @@ additional Python dependencies. pip3 install -r %HOMEPATH%\zephyrproject\zephyr\scripts\requirements.txt -Install Zephyr SDK -****************** +Install the Zephyr SDK +********************** The :ref:`Zephyr Software Development Kit (SDK) ` contains toolchains for each of Zephyr's supported architectures, which @@ -511,156 +511,9 @@ Zephyr applications. It also contains additional host tools, such as custom QEMU and OpenOCD builds that are used to emulate, flash and debug Zephyr applications. -.. tabs:: - - .. group-tab:: Ubuntu - - .. _ubuntu_zephyr_sdk: - - #. Download and verify the `Zephyr SDK bundle - `_: - - .. code-block:: bash - - cd ~ - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing - - If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace ``x86_64`` - with ``aarch64`` in order to download the 64-bit ARM Linux SDK. - - #. Extract the Zephyr SDK bundle archive: - - .. code-block:: bash - - tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz - - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following locations: - - * ``$HOME`` - * ``$HOME/.local`` - * ``$HOME/.local/opt`` - * ``$HOME/bin`` - * ``/opt`` - * ``/usr/local`` - - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. - - #. Run the Zephyr SDK bundle setup script: - - .. code-block:: bash - - cd zephyr-sdk-0.16.3 - ./setup.sh - - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. - - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. - - #. Install `udev `_ rules, which - allow you to flash most Zephyr boards as a regular user: - - .. code-block:: bash - - sudo cp ~/zephyr-sdk-0.16.3/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d - sudo udevadm control --reload - - .. group-tab:: macOS - - .. _macos_zephyr_sdk: - - #. Download and verify the `Zephyr SDK bundle - `_: - - .. code-block:: bash - - cd ~ - curl -L -O https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_macos-x86_64.tar.xz - curl -L https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing - - If your host architecture is 64-bit ARM (Apple Silicon, also known as M1), replace - ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM macOS SDK. - - #. Extract the Zephyr SDK bundle archive: - - .. code-block:: bash - - tar xvf zephyr-sdk-0.16.3_macos-x86_64.tar.xz - - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following locations: - - * ``$HOME`` - * ``$HOME/.local`` - * ``$HOME/.local/opt`` - * ``$HOME/bin`` - * ``/opt`` - * ``/usr/local`` - - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. - - #. Run the Zephyr SDK bundle setup script: - - .. code-block:: bash - - cd zephyr-sdk-0.16.3 - ./setup.sh - - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. - - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. - - .. group-tab:: Windows - - .. _windows_zephyr_sdk: - - #. Open a ``cmd.exe`` terminal window **as a regular user** - - #. Download the `Zephyr SDK bundle - `_: - - .. code-block:: bat - - cd %HOMEPATH% - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_windows-x86_64.7z - - #. Extract the Zephyr SDK bundle archive: - - .. code-block:: bat - - 7z x zephyr-sdk-0.16.3_windows-x86_64.7z - - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following locations: - - * ``%HOMEPATH%`` - * ``%PROGRAMFILES%`` - - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``%HOMEPATH%``, the resulting installation path will be - ``%HOMEPATH%\zephyr-sdk-0.16.3``. - - #. Run the Zephyr SDK bundle setup script: - - .. code-block:: bat - - cd zephyr-sdk-0.16.3 - setup.cmd - - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. - - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. +.. include:: ../toolchains/zephyr_sdk.rst + :start-after: toolchain_zephyr_sdk_install_start + :end-before: toolchain_zephyr_sdk_install_end .. _getting_started_run_sample: diff --git a/doc/develop/toolchains/zephyr_sdk.rst b/doc/develop/toolchains/zephyr_sdk.rst index c128708f50876ca..fc6add9d3eb612d 100644 --- a/doc/develop/toolchains/zephyr_sdk.rst +++ b/doc/develop/toolchains/zephyr_sdk.rst @@ -67,153 +67,173 @@ the recommended version for the corresponding Zephyr version. For the full list of compatible Zephyr and Zephyr SDK versions, refer to the `Zephyr SDK Version Compatibility Matrix`_. -.. _toolchain_zephyr_sdk_install_linux: +.. _toolchain_zephyr_sdk_install: -Install Zephyr SDK on Linux -*************************** +Zephyr SDK installation +*********************** + +.. toolchain_zephyr_sdk_install_start + +.. note:: You can change ``0.16.3`` to another version in the instructions below + if needed; the `Zephyr SDK Releases`_ page contains all available + SDK releases. + +.. note:: If you want to uninstall the SDK, you may simply remove the directory + where you installed it. + +.. tabs:: -#. Download and verify the `Zephyr SDK bundle`_: + .. group-tab:: Ubuntu - .. code-block:: bash + .. _ubuntu_zephyr_sdk: - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + #. Download and verify the `Zephyr SDK bundle + `_: - You can change ``0.16.3`` to another version if needed; the `Zephyr SDK - Releases`_ page contains all available SDK releases. + .. code-block:: bash - If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace - ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM Linux SDK. + cd ~ + wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz + wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing -#. Extract the Zephyr SDK bundle archive: + If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace ``x86_64`` + with ``aarch64`` in order to download the 64-bit ARM Linux SDK. - .. code-block:: bash + #. Extract the Zephyr SDK bundle archive: - cd - tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz + .. code-block:: bash -#. Run the Zephyr SDK bundle setup script: + tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz - .. code-block:: bash + .. note:: + It is recommended to extract the Zephyr SDK bundle at one of the following locations: - cd zephyr-sdk-0.16.3 - ./setup.sh + * ``$HOME`` + * ``$HOME/.local`` + * ``$HOME/.local/opt`` + * ``$HOME/bin`` + * ``/opt`` + * ``/usr/local`` - If this fails, make sure Zephyr's dependencies were installed as described - in :ref:`Install Requirements and Dependencies `. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when + extracted under ``$HOME``, the resulting installation path will be + ``$HOME/zephyr-sdk-0.16.3``. -If you want to uninstall the SDK, remove the directory where you installed it. -If you relocate the SDK directory, you need to re-run the setup script. + #. Run the Zephyr SDK bundle setup script: -.. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following - default locations: + .. code-block:: bash - * ``$HOME`` - * ``$HOME/.local`` - * ``$HOME/.local/opt`` - * ``$HOME/bin`` - * ``/opt`` - * ``/usr/local`` + cd zephyr-sdk-0.16.3 + ./setup.sh - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. + .. note:: + You only need to run the setup script once after extracting the Zephyr SDK bundle. -.. _toolchain_zephyr_sdk_install_macos: + You must rerun the setup script if you relocate the Zephyr SDK bundle directory after + the initial setup. -Install Zephyr SDK on macOS -*************************** + #. Install `udev `_ rules, which + allow you to flash most Zephyr boards as a regular user: -#. Download and verify the `Zephyr SDK bundle`_: + .. code-block:: bash - .. code-block:: bash + sudo cp ~/zephyr-sdk-0.16.3/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d + sudo udevadm control --reload - cd ~ - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_macos-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + .. group-tab:: macOS - If your host architecture is 64-bit ARM (Apple Silicon, also known as M1), replace - ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM macOS SDK. + .. _macos_zephyr_sdk: -#. Extract the Zephyr SDK bundle archive: + #. Download and verify the `Zephyr SDK bundle + `_: - .. code-block:: bash + .. code-block:: bash - tar xvf zephyr-sdk-0.16.3_macos-x86_64.tar.xz + cd ~ + curl -L -O https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_macos-x86_64.tar.xz + curl -L https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following - default locations: + If your host architecture is 64-bit ARM (Apple Silicon, also known as M1), replace + ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM macOS SDK. - * ``$HOME`` - * ``$HOME/.local`` - * ``$HOME/.local/opt`` - * ``$HOME/bin`` - * ``/opt`` - * ``/usr/local`` + #. Extract the Zephyr SDK bundle archive: - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. + .. code-block:: bash -#. Run the Zephyr SDK bundle setup script: + tar xvf zephyr-sdk-0.16.3_macos-x86_64.tar.xz - .. code-block:: bash + .. note:: + It is recommended to extract the Zephyr SDK bundle at one of the following locations: - cd zephyr-sdk-0.16.3 - ./setup.sh + * ``$HOME`` + * ``$HOME/.local`` + * ``$HOME/.local/opt`` + * ``$HOME/bin`` + * ``/opt`` + * ``/usr/local`` - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when + extracted under ``$HOME``, the resulting installation path will be + ``$HOME/zephyr-sdk-0.16.3``. - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. + #. Run the Zephyr SDK bundle setup script: -.. _toolchain_zephyr_sdk_install_windows: + .. code-block:: bash -Install Zephyr SDK on Windows -***************************** + cd zephyr-sdk-0.16.3 + ./setup.sh -#. Open a ``cmd.exe`` window by pressing the Windows key typing "cmd.exe". + .. note:: + You only need to run the setup script once after extracting the Zephyr SDK bundle. -#. Download the `Zephyr SDK bundle`_: + You must rerun the setup script if you relocate the Zephyr SDK bundle directory after + the initial setup. - .. code-block:: console + .. group-tab:: Windows - cd %HOMEPATH% - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_windows-x86_64.7z + .. _windows_zephyr_sdk: -#. Extract the Zephyr SDK bundle archive: + #. Open a ``cmd.exe`` terminal window **as a regular user** - .. code-block:: console + #. Download the `Zephyr SDK bundle + `_: - 7z x zephyr-sdk-0.16.3_windows-x86_64.7z + .. code-block:: bat - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following - default locations: + cd %HOMEPATH% + wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_windows-x86_64.7z - * ``%HOMEPATH%`` - * ``%PROGRAMFILES%`` + #. Extract the Zephyr SDK bundle archive: - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``%HOMEPATH%``, the resulting installation path will be - ``%HOMEPATH%\zephyr-sdk-0.16.3``. + .. code-block:: bat -#. Run the Zephyr SDK bundle setup script: + 7z x zephyr-sdk-0.16.3_windows-x86_64.7z - .. code-block:: console + .. note:: + It is recommended to extract the Zephyr SDK bundle at one of the following locations: - cd zephyr-sdk-0.16.3 - setup.cmd + * ``%HOMEPATH%`` + * ``%PROGRAMFILES%`` - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when + extracted under ``%HOMEPATH%``, the resulting installation path will be + ``%HOMEPATH%\zephyr-sdk-0.16.3``. - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. + #. Run the Zephyr SDK bundle setup script: + + .. code-block:: bat + + cd zephyr-sdk-0.16.3 + setup.cmd + + .. note:: + You only need to run the setup script once after extracting the Zephyr SDK bundle. + + You must rerun the setup script if you relocate the Zephyr SDK bundle directory after + the initial setup. .. _Zephyr SDK bundle: https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.16.3 .. _Zephyr SDK Releases: https://github.com/zephyrproject-rtos/sdk-ng/tags .. _Zephyr SDK Version Compatibility Matrix: https://github.com/zephyrproject-rtos/sdk-ng/wiki/Zephyr-SDK-Version-Compatibility-Matrix + +.. toolchain_zephyr_sdk_install_end From a88facacaa7791472106dd9275b7d2533d324f3a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Sep 2023 09:43:27 +0200 Subject: [PATCH 0474/1049] llext: clarify the use of loop variables, simplify code Several cosmetic changes with no change in functionality: The pos variable in multiple functions is used as a loop variable - it's initialised before the loop starts and then it's incremented for each loop iteration. Move it to the loop header for readability. "return ret" is clearer than "goto out" where the "out" label does nothing but "out: return ret" because one sees immediately that the function is terminated at that location with no further actions without the need to check the "out" label. k_heap_free(heap, NULL) is valid, no need to check the address to be freed for NULL. Object counters can be simple (unsigned) integers, no need to make them size_t or elf_word. "return 0" is simpler than "return ret" because it shows the return value immediately without the need to check what it can be at that location. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 129 +++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 72 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 93c03d18aba89b1..8e1b03128ec07e6 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -90,8 +90,8 @@ const void * const llext_find_sym(const struct llext_symtable *sym_table, const */ static int llext_find_tables(struct llext_loader *ldr) { - int ret = 0; - size_t pos = ldr->hdr.e_shoff; + int str_cnt, i, ret; + size_t pos; elf_shdr_t shdr; ldr->sects[LLEXT_SECT_SHSTRTAB] = @@ -99,21 +99,21 @@ static int llext_find_tables(struct llext_loader *ldr) ldr->sects[LLEXT_SECT_SYMTAB] = (elf_shdr_t){0}; /* Find symbol and string tables */ - for (int i = 0, str_cnt = 0; i < ldr->hdr.e_shnum && str_cnt < 3; i++) { + for (i = 0, str_cnt = 0, pos = ldr->hdr.e_shoff; + i < ldr->hdr.e_shnum && str_cnt < 3; + i++, pos += ldr->hdr.e_shentsize) { ret = llext_seek(ldr, pos); if (ret != 0) { LOG_ERR("failed seeking to position %u\n", pos); - goto out; + return ret; } ret = llext_read(ldr, &shdr, sizeof(elf_shdr_t)); if (ret != 0) { LOG_ERR("failed reading section header at position %u\n", pos); - goto out; + return ret; } - pos += ldr->hdr.e_shentsize; - LOG_DBG("section %d at %x: name %d, type %d, flags %x, addr %x, size %d", i, ldr->hdr.e_shoff + i * ldr->hdr.e_shentsize, @@ -152,11 +152,10 @@ static int llext_find_tables(struct llext_loader *ldr) !ldr->sects[LLEXT_SECT_STRTAB].sh_type || !ldr->sects[LLEXT_SECT_SYMTAB].sh_type) { LOG_ERR("Some sections are missing or present multiple times!"); - ret = -ENOENT; + return -ENOENT; } -out: - return ret; + return 0; } static const char *llext_string(struct llext_loader *ldr, struct llext *ext, @@ -170,24 +169,24 @@ static const char *llext_string(struct llext_loader *ldr, struct llext *ext, */ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext) { - int ret = 0; - size_t pos = ldr->hdr.e_shoff; + int i, ret; + size_t pos; elf_shdr_t shdr; const char *name; - for (int i = 0; i < ldr->hdr.e_shnum; i++) { + for (i = 0, pos = ldr->hdr.e_shoff; + i < ldr->hdr.e_shnum; + i++, pos += ldr->hdr.e_shentsize) { ret = llext_seek(ldr, pos); if (ret != 0) { - goto out; + return ret; } ret = llext_read(ldr, &shdr, sizeof(elf_shdr_t)); if (ret != 0) { - goto out; + return ret; } - pos += ldr->hdr.e_shentsize; - name = llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, shdr.sh_name); LOG_DBG("section %d name %s", i, name); @@ -211,8 +210,7 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext) ldr->sect_map[i] = sect_idx; } -out: - return ret; + return 0; } static inline enum llext_section llext_sect_from_mem(enum llext_mem m) @@ -325,29 +323,29 @@ static int llext_copy_sections(struct llext_loader *ldr, struct llext *ext) static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) { - int ret = 0; - elf_sym_t sym; size_t ent_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_entsize; size_t syms_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_size; - size_t pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset; - size_t sym_cnt = syms_size / sizeof(elf_sym_t); + int sym_cnt = syms_size / sizeof(elf_sym_t); const char *name; + elf_sym_t sym; + int i, ret; + size_t pos; LOG_DBG("symbol count %u", sym_cnt); - for (int i = 0; i < sym_cnt; i++) { + for (i = 0, pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset; + i < sym_cnt; + i++, pos += ent_size) { ret = llext_seek(ldr, pos); if (ret != 0) { - goto out; + return ret; } ret = llext_read(ldr, &sym, ent_size); if (ret != 0) { - goto out; + return ret; } - pos += ent_size; - uint32_t stt = ELF_ST_TYPE(sym.st_info); uint32_t stb = ELF_ST_BIND(sym.st_info); uint32_t sect = sym.st_shndx; @@ -364,8 +362,7 @@ static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) } } -out: - return ret; + return 0; } static inline int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) @@ -384,27 +381,26 @@ static inline int llext_allocate_symtab(struct llext_loader *ldr, struct llext * static inline int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) { - int ret = 0; - elf_sym_t sym; size_t ent_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_entsize; size_t syms_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_size; - size_t pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset; - size_t sym_cnt = syms_size / sizeof(elf_sym_t); - int i, j = 0; + int sym_cnt = syms_size / sizeof(elf_sym_t); + elf_sym_t sym; + int i, j, ret; + size_t pos; - for (i = 0; i < sym_cnt; i++) { + for (i = 0, pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset, j = 0; + i < sym_cnt; + i++, pos += ent_size) { ret = llext_seek(ldr, pos); if (ret != 0) { - goto out; + return ret; } ret = llext_read(ldr, &sym, ent_size); if (ret != 0) { - goto out; + return ret; } - pos += ent_size; - uint32_t stt = ELF_ST_TYPE(sym.st_info); uint32_t stb = ELF_ST_BIND(sym.st_info); uint32_t sect = sym.st_shndx; @@ -422,8 +418,7 @@ static inline int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext } } -out: - return ret; + return 0; } __weak void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval) @@ -432,28 +427,28 @@ __weak void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval static int llext_link(struct llext_loader *ldr, struct llext *ext) { - int ret = 0; uintptr_t loc = 0; elf_shdr_t shdr; elf_rela_t rel; elf_sym_t sym; - size_t pos = ldr->hdr.e_shoff; elf_word rel_cnt = 0; const char *name; + int i, ret; + size_t pos; - for (int i = 0; i < ldr->hdr.e_shnum - 1; i++) { + for (i = 0, pos = ldr->hdr.e_shoff; + i < ldr->hdr.e_shnum - 1; + i++, pos += ldr->hdr.e_shentsize) { ret = llext_seek(ldr, pos); if (ret != 0) { - goto out; + return ret; } ret = llext_read(ldr, &shdr, sizeof(elf_shdr_t)); if (ret != 0) { - goto out; + return ret; } - pos += ldr->hdr.e_shentsize; - /* find relocation sections */ if (shdr.sh_type != SHT_REL && shdr.sh_type != SHT_RELA) { continue; @@ -481,24 +476,24 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) /* get each relocation entry */ ret = llext_seek(ldr, shdr.sh_offset + j * sizeof(elf_rel_t)); if (ret != 0) { - goto out; + return ret; } ret = llext_read(ldr, &rel, sizeof(elf_rel_t)); if (ret != 0) { - goto out; + return ret; } /* get corresponding symbol */ ret = llext_seek(ldr, ldr->sects[LLEXT_SECT_SYMTAB].sh_offset + ELF_R_SYM(rel.r_info) * sizeof(elf_sym_t)); if (ret != 0) { - goto out; + return ret; } ret = llext_read(ldr, &sym, sizeof(elf_sym_t)); if (ret != 0) { - goto out; + return ret; } name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name); @@ -521,8 +516,7 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) LOG_ERR("Undefined symbol with no entry in " "symbol table %s, offset %d, link section %d", name, rel.r_offset, shdr.sh_link); - ret = -ENODATA; - goto out; + return -ENODATA; } else { op_code = (uintptr_t)(loc + rel.r_offset); @@ -556,8 +550,7 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) } } -out: - return ret; + return 0; } /* @@ -640,9 +633,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) } out: - if (ldr->sect_map != NULL) { - k_heap_free(&llext_heap, ldr->sect_map); - } + k_heap_free(&llext_heap, ldr->sect_map); if (ret != 0) { LOG_DBG("Failed to load extension, freeing memory..."); @@ -668,20 +659,19 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) ret = llext_seek(ldr, 0); if (ret != 0) { LOG_ERR("Failed to seek for ELF header"); - goto out; + return ret; } ret = llext_read(ldr, &ehdr, sizeof(ehdr)); if (ret != 0) { LOG_ERR("Failed to read ELF header"); - goto out; + return ret; } /* check whether this is an valid elf file */ if (memcmp(ehdr.e_ident, ELF_MAGIC, sizeof(ELF_MAGIC)) != 0) { LOG_HEXDUMP_ERR(ehdr.e_ident, 16, "Invalid ELF, magic does not match"); - ret = -EINVAL; - goto out; + return -EINVAL; } switch (ehdr.e_type) { @@ -691,8 +681,7 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) *ext = k_heap_alloc(&llext_heap, sizeof(struct llext), K_NO_WAIT); if (*ext == NULL) { LOG_ERR("Not enough memory for extension metadata"); - ret = -ENOMEM; - goto out; + return -ENOMEM; } memset(*ext, 0, sizeof(struct llext)); @@ -706,8 +695,7 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) default: LOG_ERR("Unsupported elf file type %x", ehdr.e_type); *ext = NULL; - ret = -EINVAL; - goto out; + return -EINVAL; } if (ret == 0) { @@ -717,7 +705,6 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) LOG_INF("Loaded extension %s", (*ext)->name); } -out: return ret; } @@ -735,9 +722,7 @@ void llext_unload(struct llext *ext) } } - if (ext->sym_tab.syms != NULL) { - k_heap_free(&llext_heap, ext->sym_tab.syms); - } + k_heap_free(&llext_heap, ext->sym_tab.syms); k_heap_free(&llext_heap, ext); } From 68b4898b7ebb63cda2b8ea952a5b232ab4ff320f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 7 Sep 2023 17:38:12 +0200 Subject: [PATCH 0475/1049] llext: skip first dummy symbol table entry The first entry in the symbol table is empty, skip it. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 8e1b03128ec07e6..4f55a3dd14fdac7 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -336,6 +336,11 @@ static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) for (i = 0, pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset; i < sym_cnt; i++, pos += ent_size) { + if (!i) { + /* A dummy entry */ + continue; + } + ret = llext_seek(ldr, pos); if (ret != 0) { return ret; @@ -391,6 +396,11 @@ static inline int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext for (i = 0, pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset, j = 0; i < sym_cnt; i++, pos += ent_size) { + if (!i) { + /* A dummy entry */ + continue; + } + ret = llext_seek(ldr, pos); if (ret != 0) { return ret; From 6058512b06d0bb435cc25573a1a8e4ec03ac43f5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Sep 2023 15:35:49 +0200 Subject: [PATCH 0476/1049] llext: use provided size for more generic code Use .sh_entsize instead of sizeof(elf_rel_t) to make code suitable for both REL and RELA types. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 4f55a3dd14fdac7..4d0cedef01e21c4 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -464,7 +464,7 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) continue; } - rel_cnt = shdr.sh_size / sizeof(elf_rel_t); + rel_cnt = shdr.sh_size / shdr.sh_entsize; name = llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, shdr.sh_name); @@ -484,12 +484,12 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) for (int j = 0; j < rel_cnt; j++) { /* get each relocation entry */ - ret = llext_seek(ldr, shdr.sh_offset + j * sizeof(elf_rel_t)); + ret = llext_seek(ldr, shdr.sh_offset + j * shdr.sh_entsize); if (ret != 0) { return ret; } - ret = llext_read(ldr, &rel, sizeof(elf_rel_t)); + ret = llext_read(ldr, &rel, shdr.sh_entsize); if (ret != 0) { return ret; } From 6246caa643bf0be8be1bcdabd7522f9b82aa8c98 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 15 Nov 2023 10:36:47 +0100 Subject: [PATCH 0477/1049] llext: (cosmetic) rename a variable to match its role str_cnt in llext_find_tables() is actually used to count sections, rename it to better match that usage. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 4d0cedef01e21c4..fcaa2317c419df0 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -90,7 +90,7 @@ const void * const llext_find_sym(const struct llext_symtable *sym_table, const */ static int llext_find_tables(struct llext_loader *ldr) { - int str_cnt, i, ret; + int sect_cnt, i, ret; size_t pos; elf_shdr_t shdr; @@ -99,8 +99,8 @@ static int llext_find_tables(struct llext_loader *ldr) ldr->sects[LLEXT_SECT_SYMTAB] = (elf_shdr_t){0}; /* Find symbol and string tables */ - for (i = 0, str_cnt = 0, pos = ldr->hdr.e_shoff; - i < ldr->hdr.e_shnum && str_cnt < 3; + for (i = 0, sect_cnt = 0, pos = ldr->hdr.e_shoff; + i < ldr->hdr.e_shnum && sect_cnt < 3; i++, pos += ldr->hdr.e_shentsize) { ret = llext_seek(ldr, pos); if (ret != 0) { @@ -129,7 +129,7 @@ static int llext_find_tables(struct llext_loader *ldr) LOG_DBG("symtab at %d", i); ldr->sects[LLEXT_SECT_SYMTAB] = shdr; ldr->sect_map[i] = LLEXT_SECT_SYMTAB; - str_cnt++; + sect_cnt++; break; case SHT_STRTAB: if (ldr->hdr.e_shstrndx == i) { @@ -141,7 +141,7 @@ static int llext_find_tables(struct llext_loader *ldr) ldr->sects[LLEXT_SECT_STRTAB] = shdr; ldr->sect_map[i] = LLEXT_SECT_STRTAB; } - str_cnt++; + sect_cnt++; break; default: break; From 350747cd099a8db6af8d004eed66710bd9fe0840 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Mon, 13 Nov 2023 12:29:24 +0100 Subject: [PATCH 0478/1049] dts: bq24190: make constant-charge-current/voltage properties required There are no default values for those properties in the driver so let's make them required. Signed-off-by: Bartosz Bilas --- dts/bindings/charger/ti,bq24190.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/bindings/charger/ti,bq24190.yaml b/dts/bindings/charger/ti,bq24190.yaml index 34d271754f3b9c7..6ff662c9c5850e6 100644 --- a/dts/bindings/charger/ti,bq24190.yaml +++ b/dts/bindings/charger/ti,bq24190.yaml @@ -6,3 +6,10 @@ description: Texas Instruments family of BQ24190 of charging ICs include: [battery.yaml, i2c-device.yaml] compatible: "ti,bq24190" + +properties: + constant-charge-current-max-microamp: + required: true + + constant-charge-voltage-max-microvolt: + required: true From 24b004faee153843f0f7b76ae5cae5cb142ab467 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Mon, 13 Nov 2023 12:31:07 +0100 Subject: [PATCH 0479/1049] dts: max20335-charger: make constant-charge-current/voltage props required There are no default values for those properties in the driver so let's make them required. Signed-off-by: Bartosz Bilas --- dts/bindings/charger/maxim,max20335-charger.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/bindings/charger/maxim,max20335-charger.yaml b/dts/bindings/charger/maxim,max20335-charger.yaml index 45b7cc87997da37..f830e03cec5d979 100644 --- a/dts/bindings/charger/maxim,max20335-charger.yaml +++ b/dts/bindings/charger/maxim,max20335-charger.yaml @@ -6,3 +6,10 @@ description: Maxim MAX20335 battery charger include: battery.yaml compatible: "maxim,max20335-charger" + +properties: + constant-charge-current-max-microamp: + required: true + + constant-charge-voltage-max-microvolt: + required: true From 6bb46c7fe7069ed5b67f5d8ee0ba2909ac329921 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 13 Nov 2023 15:41:23 -0800 Subject: [PATCH 0480/1049] ipc: pbuf: fix incorrect doxygen group The ipc/pbuf was tagged as kernel API, which is not correct. As this is for IPC, move it under IPC doxygen group and also give it its own subgroup. So now the packed buffer API appears under IPC in API doc. Signed-off-by: Daniel Leung --- include/zephyr/ipc/pbuf.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/zephyr/ipc/pbuf.h b/include/zephyr/ipc/pbuf.h index 5f953522d3bdd63..7e61950c808da32 100644 --- a/include/zephyr/ipc/pbuf.h +++ b/include/zephyr/ipc/pbuf.h @@ -16,7 +16,8 @@ extern "C" { /** * @brief Packed buffer API - * @ingroup kernel_apis + * @defgroup pbuf Packed Buffer API + * @ingroup ipc * @{ */ From 287b30eb78e5163cd2b56c3e889385d4048e5a1d Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Wed, 15 Nov 2023 11:10:16 +0100 Subject: [PATCH 0481/1049] doc: Fix double 'the' Fix double 'the' in all .rst documentation. Signed-off-by: Andrej Butok --- boards/arm/96b_aerocore2/doc/index.rst | 2 +- boards/arm/96b_carbon/doc/index.rst | 2 +- boards/arm/96b_nitrogen/doc/index.rst | 2 +- boards/arm/adafruit_feather_nrf52840/doc/index.rst | 2 +- boards/arm/arduino_nano_33_ble/doc/index.rst | 2 +- boards/arm/bl5340_dvk/doc/index.rst | 2 +- boards/arm/cc1352p1_launchxl/doc/index.rst | 2 +- boards/arm/cc1352r1_launchxl/doc/index.rst | 2 +- boards/arm/cc26x2r1_launchxl/doc/index.rst | 2 +- boards/arm/lpcxpresso11u68/doc/index.rst | 2 +- boards/arm/nrf9160_innblue21/doc/index.rst | 2 +- boards/arm/nrf9160_innblue22/doc/index.rst | 2 +- .../doc/olimex_lora_stm32wl_devkit.rst | 2 +- boards/posix/doc/arch_soc.rst | 2 +- boards/riscv/rv32m1_vega/doc/index.rst | 2 +- boards/x86/common/net_boot.rst | 2 +- doc/connectivity/networking/overview.rst | 2 +- doc/contribute/guidelines.rst | 4 ++-- doc/develop/manifest/index.rst | 2 +- doc/develop/modules.rst | 2 +- doc/develop/test/twister.rst | 2 +- doc/develop/west/manifest.rst | 4 ++-- doc/glossary.rst | 2 +- doc/kernel/data_structures/rbtree.rst | 2 +- doc/releases/release-notes-3.2.rst | 2 +- doc/releases/release-notes-3.3.rst | 2 +- 26 files changed, 28 insertions(+), 28 deletions(-) diff --git a/boards/arm/96b_aerocore2/doc/index.rst b/boards/arm/96b_aerocore2/doc/index.rst index 79bac17ad279bd2..6d56911c2f1acf0 100644 --- a/boards/arm/96b_aerocore2/doc/index.rst +++ b/boards/arm/96b_aerocore2/doc/index.rst @@ -330,7 +330,7 @@ Replace :code:`` with the port where the board 96Boards Aerocore2 can be found. For example, under Linux, :code:`/dev/ttyUSB0`. The ``-b`` option sets baud rate ignoring the value from config. -Press the Reset button and you should see the the following message in your +Press the Reset button and you should see the following message in your terminal: .. code-block:: console diff --git a/boards/arm/96b_carbon/doc/index.rst b/boards/arm/96b_carbon/doc/index.rst index b4a37cc985d4438..7b63bb20de95410 100644 --- a/boards/arm/96b_carbon/doc/index.rst +++ b/boards/arm/96b_carbon/doc/index.rst @@ -318,7 +318,7 @@ Replace :code:`` with the port where the board 96Boards Carbon can be found. For example, under Linux, :code:`/dev/ttyUSB0`. The ``-b`` option sets baud rate ignoring the value from config. -Press the Reset button and you should see the the following message in your +Press the Reset button and you should see the following message in your terminal: .. code-block:: console diff --git a/boards/arm/96b_nitrogen/doc/index.rst b/boards/arm/96b_nitrogen/doc/index.rst index 86e08e96ccff855..ea971f093a89521 100644 --- a/boards/arm/96b_nitrogen/doc/index.rst +++ b/boards/arm/96b_nitrogen/doc/index.rst @@ -292,7 +292,7 @@ Replace :code:`` with the port where the board 96Boards Nitrogen can be found. For example, under Linux, :code:`/dev/ttyACM0`. The ``-b`` option sets baud rate ignoring the value from config. -Press the Reset button and you should see the the following message in your +Press the Reset button and you should see the following message in your terminal: .. code-block:: console diff --git a/boards/arm/adafruit_feather_nrf52840/doc/index.rst b/boards/arm/adafruit_feather_nrf52840/doc/index.rst index a36bbdd7e3a6f89..6d4af8ca296b187 100644 --- a/boards/arm/adafruit_feather_nrf52840/doc/index.rst +++ b/boards/arm/adafruit_feather_nrf52840/doc/index.rst @@ -129,7 +129,7 @@ Flash the image. :goals: flash :compact: -You should see the the red LED blink. +You should see the red LED blink. References ********** diff --git a/boards/arm/arduino_nano_33_ble/doc/index.rst b/boards/arm/arduino_nano_33_ble/doc/index.rst index ede09b859799023..05c0605b4645068 100644 --- a/boards/arm/arduino_nano_33_ble/doc/index.rst +++ b/boards/arm/arduino_nano_33_ble/doc/index.rst @@ -126,7 +126,7 @@ and there should be a pulsing orange LED near the USB port. Then, you can flash the image using the above script. -You should see the the red LED blink. +You should see the red LED blink. Debugging ========= diff --git a/boards/arm/bl5340_dvk/doc/index.rst b/boards/arm/bl5340_dvk/doc/index.rst index 4a9fe7b12075972..544250baa8420c0 100644 --- a/boards/arm/bl5340_dvk/doc/index.rst +++ b/boards/arm/bl5340_dvk/doc/index.rst @@ -290,7 +290,7 @@ described below. .. note:: - By default the the Secure image for BL5340's application core is + By default the Secure image for BL5340's application core is built using TF-M. Building the Secure firmware with TF-M diff --git a/boards/arm/cc1352p1_launchxl/doc/index.rst b/boards/arm/cc1352p1_launchxl/doc/index.rst index 5e9690fefbd06dd..a5f88cc19ffd6cc 100644 --- a/boards/arm/cc1352p1_launchxl/doc/index.rst +++ b/boards/arm/cc1352p1_launchxl/doc/index.rst @@ -133,7 +133,7 @@ Programming and Debugging ************************* Before flashing or debugging ensure the RESET, TMS, TCK, TDO, and TDI jumpers -are in place. Also place jumpers on the the TXD and RXD signals for a serial +are in place. Also place jumpers on the TXD and RXD signals for a serial console using the XDS110 application serial port. Prerequisites: diff --git a/boards/arm/cc1352r1_launchxl/doc/index.rst b/boards/arm/cc1352r1_launchxl/doc/index.rst index b3c999a1494f269..0002b1e1c6f7995 100644 --- a/boards/arm/cc1352r1_launchxl/doc/index.rst +++ b/boards/arm/cc1352r1_launchxl/doc/index.rst @@ -132,7 +132,7 @@ Programming and Debugging ************************* Before flashing or debugging ensure the RESET, TMS, TCK, TDO, and TDI jumpers -are in place. Also place jumpers on the the TXD and RXD signals for a serial +are in place. Also place jumpers on the TXD and RXD signals for a serial console using the XDS110 application serial port. Prerequisites: diff --git a/boards/arm/cc26x2r1_launchxl/doc/index.rst b/boards/arm/cc26x2r1_launchxl/doc/index.rst index 89bdb035a31891a..8177df13ae3aa3a 100644 --- a/boards/arm/cc26x2r1_launchxl/doc/index.rst +++ b/boards/arm/cc26x2r1_launchxl/doc/index.rst @@ -138,7 +138,7 @@ Programming and Debugging ************************* Before flashing or debugging ensure the RESET, TMS, TCK, TDO, and TDI jumpers -are in place. Also place jumpers on the the TXD and RXD signals for a serial +are in place. Also place jumpers on the TXD and RXD signals for a serial console using the XDS110 application serial port. Prerequisites: diff --git a/boards/arm/lpcxpresso11u68/doc/index.rst b/boards/arm/lpcxpresso11u68/doc/index.rst index 75a4b7f15a5aa1b..23198a359eaa9af 100644 --- a/boards/arm/lpcxpresso11u68/doc/index.rst +++ b/boards/arm/lpcxpresso11u68/doc/index.rst @@ -107,7 +107,7 @@ Flashing The LPCXpresso11U68 board can be flashed by using the on-board LPC-Link2 debug probe (based on a NXP LPC43xx MCU). This MCU provides either a CMSIS-DAP or a J-Link interface. It depends on the embedded firmware image. The default -OpenOCD configuration supports the the CMSIS-DAP interface. If you want to +OpenOCD configuration supports the CMSIS-DAP interface. If you want to switch to J-Link, then you need to edit the ``boards/arm/lpcxpresso11u68/support/openocd.cfg`` file and to replace:: diff --git a/boards/arm/nrf9160_innblue21/doc/index.rst b/boards/arm/nrf9160_innblue21/doc/index.rst index 9ded085dc6f0fe5..c0f9e33cd759b03 100644 --- a/boards/arm/nrf9160_innblue21/doc/index.rst +++ b/boards/arm/nrf9160_innblue21/doc/index.rst @@ -95,7 +95,7 @@ Building Secure/Non-Secure Zephyr applications The process requires the following steps: 1. Build the Secure Zephyr application using ``-DBOARD=nrf9160_innblue21`` and - ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the the application project configuration file. + ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the application project configuration file. 2. Build the Non-Secure Zephyr application using ``-DBOARD=nrf9160_innblue21_ns``. 3. Merge the two binaries together. diff --git a/boards/arm/nrf9160_innblue22/doc/index.rst b/boards/arm/nrf9160_innblue22/doc/index.rst index 06f6b6326f8e43f..0f2f83bcfe1e983 100644 --- a/boards/arm/nrf9160_innblue22/doc/index.rst +++ b/boards/arm/nrf9160_innblue22/doc/index.rst @@ -95,7 +95,7 @@ Building Secure/Non-Secure Zephyr applications The process requires the following steps: 1. Build the Secure Zephyr application using ``-DBOARD=nrf9160_innblue22`` and - ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the the application project configuration file. + ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the application project configuration file. 2. Build the Non-Secure Zephyr application using ``-DBOARD=nrf9160_innblue22_ns``. 3. Merge the two binaries together. diff --git a/boards/arm/olimex_lora_stm32wl_devkit/doc/olimex_lora_stm32wl_devkit.rst b/boards/arm/olimex_lora_stm32wl_devkit/doc/olimex_lora_stm32wl_devkit.rst index be63585fbb1dc30..cd7d3436296d709 100644 --- a/boards/arm/olimex_lora_stm32wl_devkit/doc/olimex_lora_stm32wl_devkit.rst +++ b/boards/arm/olimex_lora_stm32wl_devkit/doc/olimex_lora_stm32wl_devkit.rst @@ -126,7 +126,7 @@ CON1 pin header. :goals: build flash Run a serial terminal to connect with your board. By default, ``usart1`` is -accessible via the the built-in USB to UART converter. +accessible via the built-in USB to UART converter. .. code-block:: console diff --git a/boards/posix/doc/arch_soc.rst b/boards/posix/doc/arch_soc.rst index ff1f947e4834e26..f0e469308abfda6 100644 --- a/boards/posix/doc/arch_soc.rst +++ b/boards/posix/doc/arch_soc.rst @@ -323,7 +323,7 @@ SOC and board layers This description applies to all current POSIX arch based boards on tree, but it is not a requirement for another board to follow what is described here. -When the executable process is started (that is the the board +When the executable process is started (that is the board :c:func:`main`, which is the linux executable C :c:func:`main`), first, early initialization steps are taken care of (command line argument parsing, initialization of the HW models, etc). diff --git a/boards/riscv/rv32m1_vega/doc/index.rst b/boards/riscv/rv32m1_vega/doc/index.rst index 867a86a2c69aba8..a2f3d107224c893 100644 --- a/boards/riscv/rv32m1_vega/doc/index.rst +++ b/boards/riscv/rv32m1_vega/doc/index.rst @@ -126,7 +126,7 @@ BLE Software Link Layer experimental support ================================================== This is an experimental feature supported on the Zephyr's RI5CY configuration, ``rv32m1_vega_ri5cy``. It uses the Software Link Layer -framework by Nordic Semi to enable the the on-SoC radio and transceiver for +framework by Nordic Semi to enable the on-SoC radio and transceiver for implementing a software defined BLE controller. By using both the controller and the host stack available in Zephyr, the following BLE samples can be used with this board: diff --git a/boards/x86/common/net_boot.rst b/boards/x86/common/net_boot.rst index ae301bea0c48ff2..e00dea8312c02f4 100644 --- a/boards/x86/common/net_boot.rst +++ b/boards/x86/common/net_boot.rst @@ -69,7 +69,7 @@ Booting the board .. note:: Use a baud rate of 115200. -#. Power on the the board. +#. Power on the board. #. Verify that the board got an IP address. Run from the Linux host: diff --git a/doc/connectivity/networking/overview.rst b/doc/connectivity/networking/overview.rst index f271bcd8a8c3089..c1de9a1ab674992 100644 --- a/doc/connectivity/networking/overview.rst +++ b/doc/connectivity/networking/overview.rst @@ -56,7 +56,7 @@ can be disabled if not needed. * **TCP** Transmission Control Protocol (`RFC 793 `_) is supported. Both server - and client roles can be used the the application. The amount of TCP sockets + and client roles can be used the application. The amount of TCP sockets that are available to applications can be configured at build time. * **BSD Sockets API** Support for a subset of a diff --git a/doc/contribute/guidelines.rst b/doc/contribute/guidelines.rst index c4ef5ce6bb16a1f..ac88fa768ab4d30 100644 --- a/doc/contribute/guidelines.rst +++ b/doc/contribute/guidelines.rst @@ -316,7 +316,7 @@ Pull Requests and Issues Before starting on a patch, first check in our issues `Zephyr Project Issues`_ system to see what's been reported on the issue you'd like to address. Have a -conversation on the `Zephyr devel mailing list`_ (or the the `Zephyr Discord +conversation on the `Zephyr devel mailing list`_ (or the `Zephyr Discord Server`_) to see what others think of your issue (and proposed solution). You may find others that have encountered the issue you're finding, or that have similar ideas for changes or additions. Send a message to the `Zephyr devel @@ -360,7 +360,7 @@ gitlint When you submit a pull request to the project, a series of checks are performed to verify your commit messages meet the requirements. The same step -done during the CI process can be performed locally using the the ``gitlint`` +done during the CI process can be performed locally using the ``gitlint`` command. Run ``gitlint`` locally in your tree and branch where your patches have been diff --git a/doc/develop/manifest/index.rst b/doc/develop/manifest/index.rst index 2dba5d817dc9f70..4c6d8f99117a7d1 100644 --- a/doc/develop/manifest/index.rst +++ b/doc/develop/manifest/index.rst @@ -30,7 +30,7 @@ Inactive and Optional Projects/Modules The projects below are optional and will not be downloaded when you -call `west update`. You can add any of the the projects or modules listed below +call `west update`. You can add any of the projects or modules listed below and use them to write application code and extend your workspace with the added functionality. diff --git a/doc/develop/modules.rst b/doc/develop/modules.rst index 45167585cd65864..42d10c32e98c2c7 100644 --- a/doc/develop/modules.rst +++ b/doc/develop/modules.rst @@ -818,7 +818,7 @@ to the path containing the CMake file. To include a module's Kconfig file, set the variable ``ZEPHYR__KCONFIG`` to the path to the Kconfig file. -The following is an example on how to add support the the ``FOO`` module. +The following is an example on how to add support the ``FOO`` module. Create the following structure diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index b4cc35f3cb320cb..122e9c3871b415e 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -1050,7 +1050,7 @@ example: id: 000683290670 notes: An nrf5340dk_nrf5340 is detected as an nrf52840dk_nrf52840 with no serial port, and three serial ports with an unknown platform. The board id of the serial - ports is not the same as the board id of the the development kit. If you regenerate + ports is not the same as the board id of the development kit. If you regenerate this file you will need to update serial to reference the third port, and platform to nrf5340dk_nrf5340_cpuapp or another supported board target. platform: nrf52840dk_nrf52840 diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index bb057272b01b5b9..ba0f9f2970658ca 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -248,7 +248,7 @@ next. remote Git repository. If the project has neither, the ``defaults`` section must specify a - ``remote``, which will be used as the the project's remote. Otherwise, + ``remote``, which will be used as the project's remote. Otherwise, the manifest is invalid. * - ``repo-path`` @@ -2049,7 +2049,7 @@ The ultimate outcomes of resolving manifest imports are: - a ``projects`` list, which is produced by combining the ``projects`` defined in the top-level file with those defined in imported files -- a set of extension commands, which are drawn from the the ``west-commands`` +- a set of extension commands, which are drawn from the ``west-commands`` keys in in the top-level file and any imported files - a ``group-filter`` list, which is produced by combining the top-level and any diff --git a/doc/glossary.rst b/doc/glossary.rst index 95781c665f67911..eafda9410fcb05e 100644 --- a/doc/glossary.rst +++ b/doc/glossary.rst @@ -51,7 +51,7 @@ Glossary of Terms device runtime power management Device Runtime Power Management (PM) refers the capability of devices to - save energy independently of the the system power state. Devices will keep + save energy independently of the system power state. Devices will keep reference of their usage and will automatically be suspended or resumed. This feature is enabled via the :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME` Kconfig option. diff --git a/doc/kernel/data_structures/rbtree.rst b/doc/kernel/data_structures/rbtree.rst index 135960200f8fe41..aac446cbad6e313 100644 --- a/doc/kernel/data_structures/rbtree.rst +++ b/doc/kernel/data_structures/rbtree.rst @@ -27,7 +27,7 @@ the algorithm to work correctly. As with the slist and dlist containers, nodes within an rbtree are represented as a :c:struct:`rbnode` structure which exists in -user-managed memory, typically embedded within the the data structure +user-managed memory, typically embedded within the data structure being tracked in the tree. Unlike the list code, the data within an rbnode is entirely opaque. It is not possible for the user to extract the binary tree topology and "manually" traverse the tree as it is for diff --git a/doc/releases/release-notes-3.2.rst b/doc/releases/release-notes-3.2.rst index e9e4bd647db2194..d902ac4481baf42 100644 --- a/doc/releases/release-notes-3.2.rst +++ b/doc/releases/release-notes-3.2.rst @@ -335,7 +335,7 @@ Bluetooth payload updates with the Resolvable Private Address (RPA) rotations when the :kconfig:option:`CONFIG_BT_PRIVACY` is enabled. * Added a new :c:func:`bt_le_set_rpa_timeout()` API call to dynamically change - the the Resolvable Private Address (RPA) timeout when the + the Resolvable Private Address (RPA) timeout when the :kconfig:option:`CONFIG_BT_RPA_TIMEOUT_DYNAMIC` is enabled. * Added :c:func:`bt_conn_auth_cb_overlay` to overlay authentication callbacks for a Bluetooth LE connection. diff --git a/doc/releases/release-notes-3.3.rst b/doc/releases/release-notes-3.3.rst index 93be4649b1e05ab..312ad1e4754ab12 100644 --- a/doc/releases/release-notes-3.3.rst +++ b/doc/releases/release-notes-3.3.rst @@ -811,7 +811,7 @@ Drivers and Sensors * Added new API :c:func:`pcie_scan` to scan for devices. - * This iterates through the the buses and devices which are expected to + * This iterates through the buses and devices which are expected to exist. The old method was to try all possible combination of buses and devices to determine if there is a device there. :c:func:`pci_init` and :c:func:`pcie_bdf_lookup` have been updated to From 72fea5df56849abd11e8751e9dea3623297d753b Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 15 Nov 2023 17:51:46 +0800 Subject: [PATCH 0482/1049] shell: backends: uart: add public function to access smp shell data `smp_shell_input_timeout_handler`. Create a public function in the `shell_uart.c` for it to get the pointer to the `smp_shell_data` and fix the compilation error. Signed-off-by: Yong Cong Sin --- include/zephyr/shell/shell_uart.h | 8 ++++++++ subsys/mgmt/mcumgr/transport/src/smp_shell.c | 5 +---- subsys/shell/backends/shell_uart.c | 13 +++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/include/zephyr/shell/shell_uart.h b/include/zephyr/shell/shell_uart.h index 2b157aac6e78219..5032c56f65eadd6 100644 --- a/include/zephyr/shell/shell_uart.h +++ b/include/zephyr/shell/shell_uart.h @@ -7,6 +7,7 @@ #ifndef SHELL_UART_H__ #define SHELL_UART_H__ +#include #include #ifdef __cplusplus @@ -23,6 +24,13 @@ extern "C" { */ const struct shell *shell_backend_uart_get_ptr(void); +/** + * @brief This function provides pointer to the smp shell data of the UART shell transport. + * + * @returns Pointer to the smp shell data. + */ +struct smp_shell_data *shell_uart_smp_shell_data_get_ptr(void); + #ifdef __cplusplus } #endif diff --git a/subsys/mgmt/mcumgr/transport/src/smp_shell.c b/subsys/mgmt/mcumgr/transport/src/smp_shell.c index fc04bcd75c42ea4..527ab2e47fa89b2 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_shell.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_shell.c @@ -59,13 +59,10 @@ enum smp_shell_mcumgr_state { }; #ifdef CONFIG_MCUMGR_TRANSPORT_SHELL_INPUT_TIMEOUT -extern struct shell_transport shell_transport_uart; - static void smp_shell_input_timeout_handler(struct k_timer *timer) { ARG_UNUSED(timer); - struct shell_uart *sh_uart = (struct shell_uart *)shell_transport_uart.ctx; - struct smp_shell_data *const data = &sh_uart->ctrl_blk->smp; + struct smp_shell_data *const data = shell_uart_smp_shell_data_get_ptr(); atomic_clear_bit(&data->esc_state, ESC_MCUMGR_PKT_1); atomic_clear_bit(&data->esc_state, ESC_MCUMGR_PKT_2); diff --git a/subsys/shell/backends/shell_uart.c b/subsys/shell/backends/shell_uart.c index b06cc4a09b8e242..5e4e3bd2c95e36c 100644 --- a/subsys/shell/backends/shell_uart.c +++ b/subsys/shell/backends/shell_uart.c @@ -554,6 +554,10 @@ static int read(const struct shell_transport *transport, #ifdef CONFIG_MCUMGR_TRANSPORT_SHELL static void update(const struct shell_transport *transport) { + /* + * This is dependent on the fact that `struct shell_uart_common` + * is always the first member, regardless of the UART configuration + */ struct shell_uart_common *sh_uart = (struct shell_uart_common *)transport->ctx; smp_shell_process(&sh_uart->smp); @@ -583,6 +587,15 @@ SHELL_DEFINE(shell_uart, CONFIG_SHELL_PROMPT_UART, &shell_transport_uart, CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_TIMEOUT, SHELL_FLAG_OLF_CRLF); +#ifdef CONFIG_MCUMGR_TRANSPORT_SHELL +struct smp_shell_data *shell_uart_smp_shell_data_get_ptr(void) +{ + struct shell_uart_common *common = (struct shell_uart_common *)shell_transport_uart.ctx; + + return &common->smp; +} +#endif + static int enable_shell_uart(void) { const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart)); From 589f3f435b634fbdb5e223fae69ad6b6a37b1178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sat, 21 Oct 2023 16:46:13 +0700 Subject: [PATCH 0483/1049] soc: nxp_s32: rename s32k to s32k3 for series alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To accommodate support for S32K1 devices, it is necessary to rename the existing `s32k` directory, which currently houses support for the S32K3 series, to align with the respective series names. This adjustment is necessary given the distinct differences in core architecture, MPU, peripherals, and other key aspects between the two series. Signed-off-by: Manuel Argüelles --- soc/arm/nxp_s32/{s32k => s32k3}/CMakeLists.txt | 0 soc/arm/nxp_s32/{s32k => s32k3}/Kconfig.defconfig.s32k344 | 0 soc/arm/nxp_s32/{s32k => s32k3}/Kconfig.defconfig.series | 4 ++-- soc/arm/nxp_s32/{s32k => s32k3}/Kconfig.series | 0 soc/arm/nxp_s32/{s32k => s32k3}/Kconfig.soc | 0 soc/arm/nxp_s32/{s32k => s32k3}/linker.ld | 0 soc/arm/nxp_s32/{s32k => s32k3}/mpu_regions.c | 0 soc/arm/nxp_s32/{s32k => s32k3}/s32k3xx_startup.S | 0 soc/arm/nxp_s32/{s32k => s32k3}/sections.ld | 0 soc/arm/nxp_s32/{s32k => s32k3}/soc.c | 0 soc/arm/nxp_s32/{s32k => s32k3}/soc.h | 0 11 files changed, 2 insertions(+), 2 deletions(-) rename soc/arm/nxp_s32/{s32k => s32k3}/CMakeLists.txt (100%) rename soc/arm/nxp_s32/{s32k => s32k3}/Kconfig.defconfig.s32k344 (100%) rename soc/arm/nxp_s32/{s32k => s32k3}/Kconfig.defconfig.series (87%) rename soc/arm/nxp_s32/{s32k => s32k3}/Kconfig.series (100%) rename soc/arm/nxp_s32/{s32k => s32k3}/Kconfig.soc (100%) rename soc/arm/nxp_s32/{s32k => s32k3}/linker.ld (100%) rename soc/arm/nxp_s32/{s32k => s32k3}/mpu_regions.c (100%) rename soc/arm/nxp_s32/{s32k => s32k3}/s32k3xx_startup.S (100%) rename soc/arm/nxp_s32/{s32k => s32k3}/sections.ld (100%) rename soc/arm/nxp_s32/{s32k => s32k3}/soc.c (100%) rename soc/arm/nxp_s32/{s32k => s32k3}/soc.h (100%) diff --git a/soc/arm/nxp_s32/s32k/CMakeLists.txt b/soc/arm/nxp_s32/s32k3/CMakeLists.txt similarity index 100% rename from soc/arm/nxp_s32/s32k/CMakeLists.txt rename to soc/arm/nxp_s32/s32k3/CMakeLists.txt diff --git a/soc/arm/nxp_s32/s32k/Kconfig.defconfig.s32k344 b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 similarity index 100% rename from soc/arm/nxp_s32/s32k/Kconfig.defconfig.s32k344 rename to soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 diff --git a/soc/arm/nxp_s32/s32k/Kconfig.defconfig.series b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series similarity index 87% rename from soc/arm/nxp_s32/s32k/Kconfig.defconfig.series rename to soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series index 93786720698689c..ed002e941efefc7 100644 --- a/soc/arm/nxp_s32/s32k/Kconfig.defconfig.series +++ b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series @@ -6,7 +6,7 @@ if SOC_SERIES_S32K3_M7 config SOC_SERIES - default "s32k" + default "s32k3" config SYS_CLOCK_HW_CYCLES_PER_SEC default 2000000 @@ -32,6 +32,6 @@ config NET_UDP_CHECKSUM endif # NET_L2_ETHERNET -source "soc/arm/nxp_s32/s32k/Kconfig.defconfig.s32k*" +source "soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k*" endif # SOC_SERIES_S32K_M7 diff --git a/soc/arm/nxp_s32/s32k/Kconfig.series b/soc/arm/nxp_s32/s32k3/Kconfig.series similarity index 100% rename from soc/arm/nxp_s32/s32k/Kconfig.series rename to soc/arm/nxp_s32/s32k3/Kconfig.series diff --git a/soc/arm/nxp_s32/s32k/Kconfig.soc b/soc/arm/nxp_s32/s32k3/Kconfig.soc similarity index 100% rename from soc/arm/nxp_s32/s32k/Kconfig.soc rename to soc/arm/nxp_s32/s32k3/Kconfig.soc diff --git a/soc/arm/nxp_s32/s32k/linker.ld b/soc/arm/nxp_s32/s32k3/linker.ld similarity index 100% rename from soc/arm/nxp_s32/s32k/linker.ld rename to soc/arm/nxp_s32/s32k3/linker.ld diff --git a/soc/arm/nxp_s32/s32k/mpu_regions.c b/soc/arm/nxp_s32/s32k3/mpu_regions.c similarity index 100% rename from soc/arm/nxp_s32/s32k/mpu_regions.c rename to soc/arm/nxp_s32/s32k3/mpu_regions.c diff --git a/soc/arm/nxp_s32/s32k/s32k3xx_startup.S b/soc/arm/nxp_s32/s32k3/s32k3xx_startup.S similarity index 100% rename from soc/arm/nxp_s32/s32k/s32k3xx_startup.S rename to soc/arm/nxp_s32/s32k3/s32k3xx_startup.S diff --git a/soc/arm/nxp_s32/s32k/sections.ld b/soc/arm/nxp_s32/s32k3/sections.ld similarity index 100% rename from soc/arm/nxp_s32/s32k/sections.ld rename to soc/arm/nxp_s32/s32k3/sections.ld diff --git a/soc/arm/nxp_s32/s32k/soc.c b/soc/arm/nxp_s32/s32k3/soc.c similarity index 100% rename from soc/arm/nxp_s32/s32k/soc.c rename to soc/arm/nxp_s32/s32k3/soc.c diff --git a/soc/arm/nxp_s32/s32k/soc.h b/soc/arm/nxp_s32/s32k3/soc.h similarity index 100% rename from soc/arm/nxp_s32/s32k/soc.h rename to soc/arm/nxp_s32/s32k3/soc.h From 8ca4f5b4a1fdad39c99c13d763480df05982531d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Mon, 6 Nov 2023 22:49:27 +0700 Subject: [PATCH 0484/1049] soc: nxp_s32: s32k3: drop `M7` suffix from options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing S32K3 Kconfig options employ the `M7` suffix, which is redundant given that all cores in this series utilize an Arm Cortex-M7 core. Therefore, we should remove it. Signed-off-by: Manuel Argüelles --- boards/arm/mr_canhubk3/Kconfig.board | 2 +- boards/arm/mr_canhubk3/mr_canhubk3_defconfig | 4 ++-- drivers/can/Kconfig.mcux | 4 ++-- drivers/dma/Kconfig.mcux_edma | 4 ++-- soc/arm/nxp_s32/Kconfig | 2 +- soc/arm/nxp_s32/common/CMakeLists.txt | 2 +- soc/arm/nxp_s32/common/osif.c | 2 +- soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 | 6 +++--- soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series | 6 +++--- soc/arm/nxp_s32/s32k3/Kconfig.series | 9 +++++---- soc/arm/nxp_s32/s32k3/Kconfig.soc | 13 ++++++------- 11 files changed, 27 insertions(+), 27 deletions(-) diff --git a/boards/arm/mr_canhubk3/Kconfig.board b/boards/arm/mr_canhubk3/Kconfig.board index 3cea453a2a29c4f..9c3f4e917b269f1 100644 --- a/boards/arm/mr_canhubk3/Kconfig.board +++ b/boards/arm/mr_canhubk3/Kconfig.board @@ -3,5 +3,5 @@ config BOARD_MR_CANHUBK3 bool "mr_canhubk3" - depends on SOC_SERIES_S32K3_M7 + depends on SOC_SERIES_S32K3XX select SOC_PART_NUMBER_S32K344 diff --git a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig index 68613d22f111d56..d8182ce8327bb62 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig +++ b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig @@ -2,8 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_BOARD_MR_CANHUBK3=y -CONFIG_SOC_S32K344_M7=y -CONFIG_SOC_SERIES_S32K3_M7=y +CONFIG_SOC_S32K344=y +CONFIG_SOC_SERIES_S32K3XX=y CONFIG_BUILD_OUTPUT_HEX=y # Use Systick as system clock diff --git a/drivers/can/Kconfig.mcux b/drivers/can/Kconfig.mcux index e584996d7c04d2f..5983be36c8ae0e6 100644 --- a/drivers/can/Kconfig.mcux +++ b/drivers/can/Kconfig.mcux @@ -31,7 +31,7 @@ config CAN_MCUX_FLEXCAN_WAIT_TIMEOUT config CAN_MAX_MB int "Maximum number of message buffers for concurrent active instances" default 16 - depends on SOC_SERIES_S32K3_M7 + depends on SOC_SERIES_S32K3XX range 1 96 help Defines maximum number of message buffers for concurrent active instances. @@ -42,7 +42,7 @@ config CAN_MAX_FILTER range 1 15 if SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_KINETIS_K6X range 1 13 if SOC_SERIES_IMX_RT && CAN_MCUX_FLEXCAN_FD range 1 63 if SOC_SERIES_IMX_RT - range 1 96 if SOC_SERIES_S32K3_M7 + range 1 96 if SOC_SERIES_S32K3XX help Defines maximum number of concurrent active RX filters diff --git a/drivers/dma/Kconfig.mcux_edma b/drivers/dma/Kconfig.mcux_edma index 0362a5faad649fe..d1e513e3c136fb3 100644 --- a/drivers/dma/Kconfig.mcux_edma +++ b/drivers/dma/Kconfig.mcux_edma @@ -28,10 +28,10 @@ config DMA_TCD_QUEUE_SIZE config DMA_MCUX_TEST_SLOT_START int "test slot start num" - depends on (SOC_SERIES_KINETIS_K6X || SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_S32K3_M7) + depends on (SOC_SERIES_KINETIS_K6X || SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_S32K3XX) default 58 if SOC_SERIES_KINETIS_K6X default 60 if SOC_SERIES_KINETIS_KE1XF - default 62 if SOC_SERIES_S32K3_M7 + default 62 if SOC_SERIES_S32K3XX help test slot start num diff --git a/soc/arm/nxp_s32/Kconfig b/soc/arm/nxp_s32/Kconfig index 5a33f2065fffc2b..e991957c03ec864 100644 --- a/soc/arm/nxp_s32/Kconfig +++ b/soc/arm/nxp_s32/Kconfig @@ -37,6 +37,6 @@ source "soc/arm/nxp_s32/*/Kconfig.soc" config SOC_PART_NUMBER default SOC_PART_NUMBER_S32ZE_R52 if SOC_SERIES_S32ZE_R52 - default SOC_PART_NUMBER_S32K3 if SOC_SERIES_S32K3_M7 + default SOC_PART_NUMBER_S32K3 if SOC_SERIES_S32K3XX endif # SOC_FAMILY_NXP_S32 diff --git a/soc/arm/nxp_s32/common/CMakeLists.txt b/soc/arm/nxp_s32/common/CMakeLists.txt index 13ec5b281017967..6142be7ab642d96 100644 --- a/soc/arm/nxp_s32/common/CMakeLists.txt +++ b/soc/arm/nxp_s32/common/CMakeLists.txt @@ -3,4 +3,4 @@ zephyr_include_directories(.) zephyr_sources(osif.c) -zephyr_sources_ifdef(CONFIG_SOC_SERIES_S32K3_M7 power_soc.c) +zephyr_sources_ifdef(CONFIG_SOC_SERIES_S32K3XX power_soc.c) diff --git a/soc/arm/nxp_s32/common/osif.c b/soc/arm/nxp_s32/common/osif.c index 344a1416ee84fb0..52de7a38b7fd1ba 100644 --- a/soc/arm/nxp_s32/common/osif.c +++ b/soc/arm/nxp_s32/common/osif.c @@ -9,7 +9,7 @@ #if defined(CONFIG_SOC_S32Z27_R52) #include -#elif defined(CONFIG_SOC_S32K344_M7) +#elif defined(CONFIG_SOC_S32K344) #include #endif diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 index 3dfab7603379adf..b1b534f6102dad4 100644 --- a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 +++ b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 @@ -1,9 +1,9 @@ -# S32K344 +# NXP S32K344 # Copyright 2023 NXP # SPDX-License-Identifier: Apache-2.0 -if SOC_S32K344_M7 +if SOC_S32K344 config SOC default "s32k344" @@ -11,4 +11,4 @@ config SOC config FPU default y -endif # SOC_S32K344_M7 +endif # SOC_S32K344 diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series index ed002e941efefc7..04d54fdc6666ce5 100644 --- a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series +++ b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series @@ -1,9 +1,9 @@ -# S32 K M7 core series +# NXP S32K3XX MCU series # Copyright 2023 NXP # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_S32K3_M7 +if SOC_SERIES_S32K3XX config SOC_SERIES default "s32k3" @@ -34,4 +34,4 @@ endif # NET_L2_ETHERNET source "soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k*" -endif # SOC_SERIES_S32K_M7 +endif # SOC_SERIES_S32K3XX diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.series b/soc/arm/nxp_s32/s32k3/Kconfig.series index 3567b562cd79014..50be01fe6906dde 100644 --- a/soc/arm/nxp_s32/s32k3/Kconfig.series +++ b/soc/arm/nxp_s32/s32k3/Kconfig.series @@ -1,13 +1,14 @@ -# NXP S32K3 MCUs family +# NXP S32K3XX MCU series # Copyright 2023 NXP # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_S32K3_M7 - bool "S32K3 M7 Core Series" +config SOC_SERIES_S32K3XX + bool "NXP S32K3XX MCU series" select ARM select CPU_CORTEX_M7 select SOC_FAMILY_NXP_S32 + select HAS_NXP_S32_HAL select CPU_HAS_FPU select CPU_HAS_ARM_MPU select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS @@ -21,4 +22,4 @@ config SOC_SERIES_S32K3_M7 select HAS_MCUX_LPSPI select HAS_MCUX_CACHE help - Enable support for NXP S32K3 MCUs family on Cortex-M7 cores + Enable support for NXP S32K3XX MCU series. diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.soc b/soc/arm/nxp_s32/s32k3/Kconfig.soc index 978c5daf65a393c..298477f71c2b753 100644 --- a/soc/arm/nxp_s32/s32k3/Kconfig.soc +++ b/soc/arm/nxp_s32/s32k3/Kconfig.soc @@ -1,19 +1,18 @@ -# NXP S32K MCUs family +# NXP S32K3XX MCU series # Copyright 2023 NXP # SPDX-License-Identifier: Apache-2.0 choice - prompt "NXP S32K MCUs family SoC Selection" - depends on SOC_SERIES_S32K3_M7 + prompt "NXP S32K3XX MCU selection" + depends on SOC_SERIES_S32K3XX -config SOC_S32K344_M7 - bool "SOC_S32K_M7" - select HAS_NXP_S32_HAL +config SOC_S32K344 + bool "s32k344" endchoice -if SOC_SERIES_S32K3_M7 +if SOC_SERIES_S32K3XX config SOC_PART_NUMBER_S32K344 bool From 1a05cfc03a87f65e6450f06925e00b44554c168d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 14 Nov 2023 20:45:38 +0700 Subject: [PATCH 0485/1049] soc: nxp_s32: consolidate part number options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the NXP S32 SoCs have three redundant Kconfig hidden options to define the part number. To streamline this, we will retain `CONFIG_SOC_PART_NUMBER` to store the part number as a string and `CONFIG_SOC_PART_NUMBER_` that can be selected by the boards. Furthermore, for drivers requiring conditional code compilation based on the target SoC, they should utilize the series or SoC config option as applicable, instead of the part number config. Signed-off-by: Manuel Argüelles --- boards/arm/mr_canhubk3/Kconfig.board | 2 +- drivers/ethernet/eth_nxp_s32_gmac.c | 4 ++-- soc/arm/nxp_s32/Kconfig | 4 ---- soc/arm/nxp_s32/common/power_soc.c | 2 +- soc/arm/nxp_s32/s32k3/Kconfig.soc | 6 +++--- soc/arm/nxp_s32/s32ze/Kconfig.soc | 4 ++-- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/boards/arm/mr_canhubk3/Kconfig.board b/boards/arm/mr_canhubk3/Kconfig.board index 9c3f4e917b269f1..af9a09391cd7380 100644 --- a/boards/arm/mr_canhubk3/Kconfig.board +++ b/boards/arm/mr_canhubk3/Kconfig.board @@ -4,4 +4,4 @@ config BOARD_MR_CANHUBK3 bool "mr_canhubk3" depends on SOC_SERIES_S32K3XX - select SOC_PART_NUMBER_S32K344 + select SOC_PART_NUMBER_PS32K344EHVPBS diff --git a/drivers/ethernet/eth_nxp_s32_gmac.c b/drivers/ethernet/eth_nxp_s32_gmac.c index 428a57c6065e13f..71e3e94c176253b 100644 --- a/drivers/ethernet/eth_nxp_s32_gmac.c +++ b/drivers/ethernet/eth_nxp_s32_gmac.c @@ -78,7 +78,7 @@ static inline struct net_if *get_iface(struct eth_nxp_s32_data *ctx, uint16_t vl #endif } -#if defined(CONFIG_SOC_PART_NUMBER_S32K3) +#if defined(CONFIG_SOC_SERIES_S32K3XX) static int select_phy_interface(Gmac_Ip_MiiModeType mode) { uint32_t regval; @@ -105,7 +105,7 @@ static int select_phy_interface(Gmac_Ip_MiiModeType mode) } #else #error "SoC not supported" -#endif /* CONFIG_SOC_PART_NUMBER_S32K3 */ +#endif /* CONFIG_SOC_SERIES_S32K3XX */ static int eth_nxp_s32_init(const struct device *dev) { diff --git a/soc/arm/nxp_s32/Kconfig b/soc/arm/nxp_s32/Kconfig index e991957c03ec864..d014315e4d70b1d 100644 --- a/soc/arm/nxp_s32/Kconfig +++ b/soc/arm/nxp_s32/Kconfig @@ -35,8 +35,4 @@ config NXP_S32_DEST_RESET_THRESHOLD source "soc/arm/nxp_s32/*/Kconfig.soc" -config SOC_PART_NUMBER - default SOC_PART_NUMBER_S32ZE_R52 if SOC_SERIES_S32ZE_R52 - default SOC_PART_NUMBER_S32K3 if SOC_SERIES_S32K3XX - endif # SOC_FAMILY_NXP_S32 diff --git a/soc/arm/nxp_s32/common/power_soc.c b/soc/arm/nxp_s32/common/power_soc.c index eef489ee8df74be..3e277155cb82ea9 100644 --- a/soc/arm/nxp_s32/common/power_soc.c +++ b/soc/arm/nxp_s32/common/power_soc.c @@ -71,7 +71,7 @@ static int nxp_s32_power_init(void) }; const Power_Ip_PMC_ConfigType pmc_cfg = { -#ifdef CONFIG_SOC_PART_NUMBER_S32K3 +#ifdef CONFIG_SOC_SERIES_S32K3XX /* PMC Configuration Register (CONFIG) */ .ConfigRegister = PMC_CONFIG_LMEN(IS_ENABLED(CONFIG_NXP_S32_PMC_LMEN)) | PMC_CONFIG_LMBCTLEN(IS_ENABLED(CONFIG_NXP_S32_PMC_LMBCTLEN)), diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.soc b/soc/arm/nxp_s32/s32k3/Kconfig.soc index 298477f71c2b753..6b8f4e3a8839702 100644 --- a/soc/arm/nxp_s32/s32k3/Kconfig.soc +++ b/soc/arm/nxp_s32/s32k3/Kconfig.soc @@ -14,12 +14,12 @@ endchoice if SOC_SERIES_S32K3XX -config SOC_PART_NUMBER_S32K344 +config SOC_PART_NUMBER_PS32K344EHVPBS bool -config SOC_PART_NUMBER_S32K3 +config SOC_PART_NUMBER string - default "S32K344" if SOC_PART_NUMBER_S32K344 + default "PS32K344EHVPBS" if SOC_PART_NUMBER_PS32K344EHVPBS help This string holds the full part number of the SoC. It is a hidden option that you should not set directly. The part number selection choice defines diff --git a/soc/arm/nxp_s32/s32ze/Kconfig.soc b/soc/arm/nxp_s32/s32ze/Kconfig.soc index 757b40966349836..790751362d3e634 100644 --- a/soc/arm/nxp_s32/s32ze/Kconfig.soc +++ b/soc/arm/nxp_s32/s32ze/Kconfig.soc @@ -1,6 +1,6 @@ # NXP S32Z/E MCUs family -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 choice @@ -18,7 +18,7 @@ if SOC_SERIES_S32ZE_R52 config SOC_PART_NUMBER_S32Z27 bool -config SOC_PART_NUMBER_S32ZE_R52 +config SOC_PART_NUMBER string default "S32Z27" if SOC_PART_NUMBER_S32Z27 help From 7433a203ef606d5ccb8b6cb16371e00c90906d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 15 Nov 2023 16:12:12 +0100 Subject: [PATCH 0486/1049] doc: boards: Clean up repeated words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed a bunch from repeated words across board READMEs. Signed-off-by: Benjamin Cabé --- boards/arm/arduino_nano_33_iot/doc/index.rst | 2 +- boards/arm/dragino_lsn50/doc/index.rst | 2 +- boards/arm/dragino_nbsn95/doc/index.rst | 2 +- boards/arm/faze/doc/index.rst | 2 +- boards/arm/reel_board/doc/index.rst | 3 +-- boards/arm/ronoth_lodev/doc/index.rst | 2 +- boards/arm/twr_ke18f/doc/index.rst | 2 +- boards/arm64/mimx93_evk/doc/index.rst | 2 +- boards/shields/atmel_rf2xx/doc/index.rst | 2 +- 9 files changed, 9 insertions(+), 10 deletions(-) diff --git a/boards/arm/arduino_nano_33_iot/doc/index.rst b/boards/arm/arduino_nano_33_iot/doc/index.rst index dfcf2a6bbcb5c61..62353ecbe1eb9aa 100644 --- a/boards/arm/arduino_nano_33_iot/doc/index.rst +++ b/boards/arm/arduino_nano_33_iot/doc/index.rst @@ -6,7 +6,7 @@ Arduino Nano 33 IOT Overview ******** -The Arduino Nano 33 IOT is a a small form factor development board with USB, +The Arduino Nano 33 IOT is a small form factor development board with USB, Wifi, Bluetooth, a 6 axis IMU, and secure element. .. image:: img/nano_33_iot.jpg diff --git a/boards/arm/dragino_lsn50/doc/index.rst b/boards/arm/dragino_lsn50/doc/index.rst index 7931d8f9db879e4..732e0ec1394b2f8 100644 --- a/boards/arm/dragino_lsn50/doc/index.rst +++ b/boards/arm/dragino_lsn50/doc/index.rst @@ -85,7 +85,7 @@ More information about STM32L072CZ can be found here: Supported Features ================== -The Zephyr Dragino LSN50 Board board configuration supports the following hardware features: +The Zephyr Dragino LSN50 board configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | Interface | Controller | Driver/Component | diff --git a/boards/arm/dragino_nbsn95/doc/index.rst b/boards/arm/dragino_nbsn95/doc/index.rst index 71e9f2c9711b785..ca0b3d8cc1d31db 100644 --- a/boards/arm/dragino_nbsn95/doc/index.rst +++ b/boards/arm/dragino_nbsn95/doc/index.rst @@ -84,7 +84,7 @@ More information about STM32L072CZ can be found here: Supported Features ================== -The Zephyr Dragino NBSN95 Board board configuration supports the following hardware features: +The Zephyr Dragino NBSN95 board configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | Interface | Controller | Driver/Component | diff --git a/boards/arm/faze/doc/index.rst b/boards/arm/faze/doc/index.rst index ed432753fd7cde1..1d61d997cd08585 100644 --- a/boards/arm/faze/doc/index.rst +++ b/boards/arm/faze/doc/index.rst @@ -31,7 +31,7 @@ Hardware - External devices connected to the NXP LPC11U67 MCU: - ASMedia ASM2364 USB-to-PCIe bridge (I2C master on port O). - - 6 RGB LEDs connected connected to a TI LP5030 LED controller (I2C device on + - 6 RGB LEDs connected to a TI LP5030 LED controller (I2C device on port 1). - 1 white LED (SSD activity blinking). diff --git a/boards/arm/reel_board/doc/index.rst b/boards/arm/reel_board/doc/index.rst index dc490249abd004d..dec81bd88ec61cc 100644 --- a/boards/arm/reel_board/doc/index.rst +++ b/boards/arm/reel_board/doc/index.rst @@ -462,8 +462,7 @@ Meaning of the Power Source Switch positions: X9 or X5. USB - link board BASE is powered from from USB connector - (via DCDC converter). + link board BASE is powered from USB connector (via DCDC converter). RB link board BASE is powered from reel board. The available power is diff --git a/boards/arm/ronoth_lodev/doc/index.rst b/boards/arm/ronoth_lodev/doc/index.rst index f1c60567a996466..58f0756ecb30f7f 100644 --- a/boards/arm/ronoth_lodev/doc/index.rst +++ b/boards/arm/ronoth_lodev/doc/index.rst @@ -8,7 +8,7 @@ Overview ======== The Ronoth_ LoDev_ is a small open source board containing a `AcSIP S76S`_ SiP from AcSIP_. -The `full LoDev design details`_ are available on on GitHub. The LoDev_ board can be purchased +The `full LoDev design details`_ are available on GitHub. The LoDev_ board can be purchased from Ronoth_ or from CrowdSupply_. The S76S contains an STMicro STM32L073RZ MCU, a `Semtech SX1276`_ LoRaWAN transceiver, diff --git a/boards/arm/twr_ke18f/doc/index.rst b/boards/arm/twr_ke18f/doc/index.rst index fd2c8c803d8b560..04aa94f0dfe73df 100644 --- a/boards/arm/twr_ke18f/doc/index.rst +++ b/boards/arm/twr_ke18f/doc/index.rst @@ -113,7 +113,7 @@ accelerometer and magnetometer for sensor values (``CONFIG_FXOS8700_TRIGGER_NONE=y``). In order to support FXOS8700 triggers (interrupts) the 0 ohm resistors -``R47`` and and ``R57`` must be mounted on the TWR-KE18F board. The +``R47`` and ``R57`` must be mounted on the TWR-KE18F board. The devicetree must also be modified to describe the FXOS8700 interrupt GPIOs: diff --git a/boards/arm64/mimx93_evk/doc/index.rst b/boards/arm64/mimx93_evk/doc/index.rst index 7ff38891d2235bf..67997a3fbbea723 100644 --- a/boards/arm64/mimx93_evk/doc/index.rst +++ b/boards/arm64/mimx93_evk/doc/index.rst @@ -168,7 +168,7 @@ Firstly, we need to explain a few Jailhouse concepts that will be referred to la cell can utilize. * **Root cell**: refers to the cell in which Linux is running. This is the main cell which - will contain all the hardware resources that Linux will utilize and will be used used to assign + will contain all the hardware resources that Linux will utilize and will be used to assign resources to the inmates. The inmates CANNOT use resources such as the CPU that haven't been assigned to the root cell. diff --git a/boards/shields/atmel_rf2xx/doc/index.rst b/boards/shields/atmel_rf2xx/doc/index.rst index dbcdccbd3e8494a..e9d2777fafe5709 100644 --- a/boards/shields/atmel_rf2xx/doc/index.rst +++ b/boards/shields/atmel_rf2xx/doc/index.rst @@ -179,7 +179,7 @@ Pins Assignment of the Arduino Shield Modules MikroBus Shields ================ -MikroBus header is available available without advanced features. It is +MikroBus header is available without advanced features. It is enabled selecting `atmel_rf2xx_mikrobus`_ variant option. Pins Assignment of the MikroBus Shield Modules From 18d28ea1449f905f8cbdce824c342086caafc12a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 15 Nov 2023 13:09:18 +0100 Subject: [PATCH 0487/1049] linker: common-rom-logging: Use DEVNULL_REGION only if it exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Log string removal is by default enabled for RISCV and Cortex-M and support is added to the default linker template. However, if SoC is not using default linker template then DEVNULL_REGION is not defined. In that case string removal cannot be used. Signed-off-by: Krzysztof Chruściński --- include/zephyr/linker/common-rom/common-rom-logging.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/linker/common-rom/common-rom-logging.ld b/include/zephyr/linker/common-rom/common-rom-logging.ld index 4e146375b43baa7..9bb3e34626c9a27 100644 --- a/include/zephyr/linker/common-rom/common-rom-logging.ld +++ b/include/zephyr/linker/common-rom/common-rom-logging.ld @@ -2,7 +2,7 @@ #include -#ifdef CONFIG_LOG_FMT_SECTION_STRIP +#if defined(CONFIG_LOG_FMT_SECTION_STRIP) && defined(DEVNULL_REGION) SECTION_PROLOGUE(log_strings,(COPY),SUBALIGN(4)) { Z_LINK_ITERABLE(log_strings); From 447f12d942c39439d1f0446a2d6c50328185562e Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 15 Nov 2023 11:52:12 -0600 Subject: [PATCH 0488/1049] drivers: nxp_flexram: Fix GPR 17 calculation GPR17 calculation for configuration of RAM banks is incorrect, bit shift should be 2 per idx, not 1, this is major bug that needs correcting, currently all RT boards are affected with wrong configuration. Signed-off-by: Declan Snyder --- drivers/memc/memc_nxp_flexram.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memc/memc_nxp_flexram.h b/drivers/memc/memc_nxp_flexram.h index 34f606e6b86c1f8..397b60bf55da0d1 100644 --- a/drivers/memc/memc_nxp_flexram.h +++ b/drivers/memc/memc_nxp_flexram.h @@ -44,7 +44,7 @@ void memc_flexram_register_callback(flexram_callback_t callback, void *user_data * call from platform_init to set up flexram if using runtime map * must be inlined because cannot use stack */ -#define GPR17_REG_FILL(node_id, prop, idx) + (DT_PROP_BY_IDX(node_id, prop, idx) << idx) +#define GPR17_REG_FILL(node_id, prop, idx) + (DT_PROP_BY_IDX(node_id, prop, idx) << (2*idx)) static inline void memc_flexram_dt_partition(void) { /* iomuxc_gpr must be const (in ROM region) because used in reconfiguring ram */ From ad3b3a9b9330bf6b3214fc96bfc8d0201aa25713 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 15 Nov 2023 14:00:33 -0600 Subject: [PATCH 0489/1049] drivers: memc_nxp_flexram: Use nodelabel for GPR Get GPR base address using nodelabel as this will align for all the current in tree platforms. Currently inst 0 of the compat gets wrong node and base address on RT11xx. Signed-off-by: Declan Snyder --- drivers/memc/memc_nxp_flexram.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memc/memc_nxp_flexram.h b/drivers/memc/memc_nxp_flexram.h index 397b60bf55da0d1..5ea2e89d0cce64e 100644 --- a/drivers/memc/memc_nxp_flexram.h +++ b/drivers/memc/memc_nxp_flexram.h @@ -8,7 +8,7 @@ #include #define FLEXRAM_DT_NODE DT_INST(0, nxp_flexram) -#define IOMUXC_GPR_DT_NODE DT_INST(0, nxp_imx_gpr) +#define IOMUXC_GPR_DT_NODE DT_NODELABEL(iomuxcgpr) #if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) || \ defined(CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT) From 78afda36f120c1cf2c58088b8e252b0c66a3c5e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 15 Nov 2023 15:34:31 +0100 Subject: [PATCH 0490/1049] scripts: Add "the the" as a common typo in spellchecker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Somehow this is seems to be a very common typo. Adding it to spelling.txt to catch it as part of compliance check. Signed-off-by: Benjamin Cabé --- scripts/spelling.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/spelling.txt b/scripts/spelling.txt index fd3c5170303b5d9..84e4d944a77d6ed 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -1080,6 +1080,7 @@ targetting||targeting teh||the temorary||temporary temproarily||temporarily +the the||the therfore||therefore thier||their threds||threads From 05e6e1ce15835d791f47aa1b138b69d9110cf973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 15 Nov 2023 17:04:10 +0100 Subject: [PATCH 0491/1049] scripts: sync spelling.txt with version from Linux kernel v6.7-rc1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync the spelling.txt file with a recent version of the one found in Linux kernel. List sorting was preserved (however inconsistent it might be) to simplify future syncs. Signed-off-by: Benjamin Cabé --- scripts/spelling.txt | 529 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 527 insertions(+), 2 deletions(-) diff --git a/scripts/spelling.txt b/scripts/spelling.txt index 84e4d944a77d6ed..ffa9e7cb8e38702 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -9,7 +9,12 @@ # abandonning||abandoning abigious||ambiguous +abitrary||arbitrary abitrate||arbitrate +abnornally||abnormally +abnrormal||abnormal +abord||abort +aboslute||absolute abov||above abreviated||abbreviated absense||absence @@ -17,6 +22,8 @@ absolut||absolute absoulte||absolute acccess||access acceess||access +accelaration||acceleration +accelearion||acceleration acceleratoin||acceleration accelleration||acceleration accesing||accessing @@ -25,6 +32,7 @@ accessable||accessible accesss||access accidentaly||accidentally accidentually||accidentally +acclerated||accelerated accoding||according accomodate||accommodate accomodates||accommodates @@ -34,8 +42,11 @@ accout||account accquire||acquire accquired||acquired accross||across +accumalate||accumulate +accumalator||accumulator acessable||accessible acess||access +acessing||accessing achitecture||architecture acient||ancient acitions||actions @@ -48,24 +59,36 @@ acording||according activete||activate actived||activated actualy||actually +actvie||active acumulating||accumulating +acumulative||accumulative acumulator||accumulator +acutally||actually adapater||adapter +adderted||asserted addional||additional additionaly||additionally +additonal||additional addres||address +adddress||address addreses||addresses addresss||address +addrress||address aditional||additional aditionally||additionally aditionaly||additionally adminstrative||administrative adress||address adresses||addresses +adrresses||addresses +advertisment||advertisement adviced||advised afecting||affecting againt||against agaist||against +aggreataon||aggregation +aggreation||aggregation +ajust||adjust albumns||albums alegorical||allegorical algined||aligned @@ -73,15 +96,19 @@ algorith||algorithm algorithmical||algorithmically algoritm||algorithm algoritms||algorithms +algorithmn||algorithm algorrithm||algorithm algorritm||algorithm aligment||alignment alignement||alignment allign||align alligned||aligned +alllocate||allocate +alloated||allocated allocatote||allocate allocatrd||allocated allocte||allocate +allocted||allocated allpication||application alocate||allocate alogirhtms||algorithms @@ -89,11 +116,17 @@ alogrithm||algorithm alot||a lot alow||allow alows||allows +alreay||already +alredy||already altough||although alue||value ambigious||ambiguous +ambigous||ambiguous amoung||among +amount of times||number of times amout||amount +amplifer||amplifier +amplifyer||amplifier an union||a union an user||a user an userspace||a userspace @@ -122,35 +155,56 @@ aquired||acquired aquisition||acquisition arbitary||arbitrary architechture||architecture +archtecture||architecture arguement||argument arguements||arguments +arithmatic||arithmetic aritmetic||arithmetic arne't||aren't arraival||arrival artifical||artificial artillary||artillery asign||assign +asser||assert assertation||assertion +assertting||asserting +assgined||assigned assiged||assigned assigment||assignment assigments||assignments assistent||assistant +assocaited||associated +assocating||associating assocation||association associcated||associated assotiated||associated +asssert||assert assum||assume assumtpion||assumption asuming||assuming asycronous||asynchronous +asychronous||asynchronous asynchnous||asynchronous +asynchronus||asynchronous +asynchromous||asynchronous +asymetric||asymmetric +asymmeric||asymmetric +atleast||at least atomatically||automatically atomicly||atomically atempt||attempt +atrributes||attributes attachement||attachment +attatch||attach attched||attached +attemp||attempt attemps||attempts +attemping||attempting +attepmpt||attempt +attnetion||attention attruibutes||attributes authentification||authentication +authenicated||authenticated automaticaly||automatically automaticly||automatically automatize||automate @@ -164,10 +218,12 @@ avaible||available availabe||available availabled||available availablity||availability +availaible||available availale||available availavility||availability availble||available availiable||available +availible||available avalable||available avaliable||available aysnc||async @@ -181,6 +237,7 @@ baloons||balloons bandwith||bandwidth banlance||balance batery||battery +battey||battery beacuse||because becasue||because becomming||becoming @@ -192,30 +249,57 @@ beter||better betweeen||between bianries||binaries bitmast||bitmask +bitwiedh||bitwidth boardcast||broadcast borad||board boundry||boundary brievely||briefly +brigde||bridge +broadcase||broadcast broadcat||broadcast +bufer||buffer +bufferred||buffered +bufufer||buffer cacluated||calculated +caculate||calculate caculation||calculation +cadidate||candidate +cahces||caches calender||calendar +calescing||coalescing calle||called callibration||calibration +callled||called +callser||caller calucate||calculate calulate||calculate cancelation||cancellation +cancle||cancel +cant||can't +cant'||can't +canot||cannot +cann't||can't +cannnot||cannot +capabiity||capability capabilites||capabilities +capabilties||capabilities +capabilty||capability capabitilies||capabilities +capablity||capability capatibilities||capabilities +capapbilities||capabilities +caputure||capture carefuly||carefully cariage||carriage +casued||caused catagory||category cehck||check challange||challenge challanges||challenges +chache||cache chanell||channel changable||changeable +chanined||chained channle||channel channnel||channel charachter||character @@ -226,6 +310,7 @@ charaters||characters charcter||character chcek||check chck||check +checksumed||checksummed checksuming||checksumming childern||children childs||children @@ -233,6 +318,7 @@ chiled||child chked||checked chnage||change chnages||changes +chnange||change chnnel||channel choosen||chosen chouse||chose @@ -241,6 +327,9 @@ claread||cleared clared||cleared closeing||closing clustred||clustered +cnfiguration||configuration +coexistance||coexistence +colescing||coalescing collapsable||collapsible colorfull||colorful comand||command @@ -251,14 +340,18 @@ comminucation||communication commited||committed commiting||committing committ||commit +commnunication||communication commoditiy||commodity comsume||consume comsumer||consumer comsuming||consuming +comaptible||compatible compability||compatibility compaibility||compatibility +comparsion||comparison compatability||compatibility compatable||compatible +compatibililty||compatibility compatibiliy||compatibility compatibilty||compatibility compatiblity||compatibility @@ -269,16 +362,29 @@ completition||completion completly||completely complient||compliant componnents||components +compoment||component +comppatible||compatible compres||compress compresion||compression +compresser||compressor comression||compression +comsumed||consumed +comunicate||communicate comunication||communication conbination||combination concurent||concurrent conditionaly||conditionally +conditon||condition +condtion||condition +condtional||conditional conected||connected connecetd||connected +conector||connector +configration||configuration +configred||configured configuartion||configuration +configuation||configuration +configued||configured configuratoin||configuration configuraton||configuration configuretion||configuration @@ -286,6 +392,7 @@ configutation||configuration conider||consider conjuction||conjunction connectinos||connections +connetor||connector connnection||connection connnections||connections consistancy||consistency @@ -295,10 +402,13 @@ containts||contains contaisn||contains contant||contact contence||contents +contiguos||contiguous +continious||continuous continous||continuous continously||continuously continueing||continuing contraints||constraints +contruct||construct contol||control contoller||controller controled||controlled @@ -316,22 +426,35 @@ correponding||corresponding correponds||corresponds correspoding||corresponding cotrol||control +cound||could couter||counter coutner||counter +creationg||creating cryptocraphic||cryptographic +cummulative||cumulative cunter||counter curent||current curently||currently cylic||cyclic dafault||default +deactive||deactivate deafult||default deamon||daemon +debouce||debounce +decendant||descendant +decendants||descendants decompres||decompress +decsribed||described decription||description +dectected||detected defailt||default +deferal||deferral +deffered||deferred defferred||deferred definate||definite definately||definitely +definiation||definition +definiton||definition defintion||definition defintions||definitions defualt||default @@ -345,25 +468,38 @@ delare||declare delares||declares delaring||declaring delemiter||delimiter +delibrately||deliberately +delievered||delivered +demodualtor||demodulator +demension||dimension dependancies||dependencies dependancy||dependency dependant||dependent +dependend||dependent depreacted||deprecated depreacte||deprecate desactivate||deactivate desciptor||descriptor desciptors||descriptors +descripto||descriptor descripton||description descrition||description descritptor||descriptor desctiptor||descriptor desriptor||descriptor desriptors||descriptors +desination||destination +destionation||destination +destoried||destroyed destory||destroy destoryed||destroyed destorys||destroys destroied||destroyed detabase||database +deteced||detected +detecion||detection +detectt||detect +detroyed||destroyed develope||develop developement||development developped||developed @@ -373,43 +509,77 @@ developpment||development deveolpment||development devided||divided deviece||device +devision||division diable||disable +diabled||disabled +dicline||decline dictionnary||dictionary didnt||didn't diferent||different differrence||difference diffrent||different +differenciate||differentiate +diffreential||differential diffrentiate||differentiate difinition||definition +digial||digital +dimention||dimension +dimesions||dimensions +diconnected||disconnected +disabed||disabled +disasembler||disassembler +disgest||digest +disired||desired +dispalying||displaying +dissable||disable diplay||display +directon||direction +direcly||directly direectly||directly +diregard||disregard disassocation||disassociation disapear||disappear disapeared||disappeared disappared||disappeared +disbale||disable +disbaled||disabled disble||disable disbled||disabled disconnet||disconnect discontinous||discontinuous +disharge||discharge +disnabled||disabled dispertion||dispersion dissapears||disappears +dissconect||disconnect distiction||distinction +divisable||divisible +divsiors||divisors +dsiabled||disabled docuentation||documentation documantation||documentation documentaion||documentation documment||document doesnt||doesn't +donwload||download +donwloading||downloading dorp||drop dosen||doesn downlad||download downlads||downloads +droped||dropped +droput||dropout druing||during +dyanmic||dynamic dynmaic||dynamic +eanable||enable +eanble||enable easilly||easily ecspecially||especially edditable||editable editting||editing efective||effective +effectivness||effectiveness efficently||efficiently ehther||ether eigth||eight @@ -417,14 +587,23 @@ elementry||elementary eletronic||electronic embeded||embedded enabledi||enabled +enbale||enable +enble||enable enchanced||enhanced encorporating||incorporating encrupted||encrypted encrypiton||encryption +encryptio||encryption endianess||endianness +enpoint||endpoint enhaced||enhanced enlightnment||enlightenment +enqueing||enqueuing +entires||entries +entites||entities +entrys||entries enocded||encoded +enought||enough enterily||entirely enviroiment||environment enviroment||environment @@ -435,19 +614,37 @@ equiped||equipped equivelant||equivalent equivilant||equivalent eror||error +errorr||error +errror||error estbalishment||establishment etsablishment||establishment etsbalishment||establishment +evalute||evaluate +evalutes||evaluates +evalution||evaluation excecutable||executable +excceed||exceed exceded||exceeded +exceds||exceeds +exceeed||exceed excellant||excellent +exchnage||exchange +execeeded||exceeded +execeeds||exceeds +exeed||exceed +exeeds||exceeds +exeuction||execution existance||existence existant||existent exixt||exist +exsits||exists exlcude||exclude +exlcuding||excluding exlcusive||exclusive +exlusive||exclusive exmaple||example expecially||especially +experies||expires explicite||explicit explicitely||explicitly explict||explicit @@ -456,47 +653,69 @@ explictly||explicitly expresion||expression exprimental||experimental extened||extended +exteneded||extended extensability||extensibility extention||extension +extenstion||extension extracter||extractor -falied||failed +faied||failed +faield||failed faild||failed +failded||failed +failer||failure faill||fail failied||failed faillure||failure failue||failure failuer||failure +failng||failing faireness||fairness falied||failed faliure||failure +fallbck||fallback familar||familiar fatser||faster feauture||feature feautures||features fetaure||feature fetaures||features +fetcing||fetching fileystem||filesystem +fimrware||firmware fimware||firmware +firmare||firmware +firmaware||firmware +firtly||firstly +firware||firmware +firwmare||firmware finanize||finalize findn||find finilizes||finalizes finsih||finish +fliter||filter flusing||flushing folloing||following followign||following followings||following follwing||following +fonud||found forseeable||foreseeable forse||force fortan||fortran forwardig||forwarding +frambuffer||framebuffer framming||framing framwork||framework +frequence||frequency frequncy||frequency +frequancy||frequency frome||from +fronend||frontend fucntion||function fuction||function fuctions||functions +fullill||fulfill +funcation||function funcion||function functionallity||functionality functionaly||functionally @@ -507,41 +726,64 @@ funtions||functions furthur||further futhermore||furthermore futrue||future +gatable||gateable +gateing||gating +gauage||gauge gaurenteed||guaranteed generiously||generously genereate||generate +genereted||generated genric||generic +gerenal||general +geting||getting globel||global grabing||grabbing grahical||graphical grahpical||graphical +granularty||granularity grapic||graphic +grranted||granted guage||gauge guarenteed||guaranteed guarentee||guarantee halfs||halves hander||handler handfull||handful +hanlde||handle hanled||handled happend||happened +hardare||hardware harware||hardware +hardward||hardware +havind||having heirarchically||hierarchically +heirarchy||hierarchy helpfull||helpful +hearbeat||heartbeat +heterogenous||heterogeneous +hexdecimal||hexadecimal +hybernate||hibernate hierachy||hierarchy hierarchie||hierarchy +homogenous||homogeneous howver||however hsould||should hypervior||hypervisor hypter||hyper +idel||idle identidier||identifier iligal||illegal illigal||illegal +illgal||illegal +iomaped||iomapped imblance||imbalance immeadiately||immediately immedaite||immediate +immedate||immediate immediatelly||immediately immediatly||immediately immidiate||immediate +immutible||immutable impelentation||implementation impementated||implemented implemantation||implementation @@ -549,24 +791,34 @@ implemenation||implementation implementaiton||implementation implementated||implemented implemention||implementation +implementd||implemented implemetation||implementation implemntation||implementation implentation||implementation implmentation||implementation implmenting||implementing +incative||inactive incomming||incoming +incompaitiblity||incompatibility incompatabilities||incompatibilities incompatable||incompatible +incompatble||incompatible inconsistant||inconsistent increas||increase +incremeted||incremented incrment||increment +incuding||including +inculde||include indendation||indentation indended||intended independant||independent independantly||independently independed||independent indiate||indicate +indicat||indicate inexpect||inexpected +inferface||interface +infinit||infinite infomation||information informatiom||information informations||information @@ -581,27 +833,41 @@ initalize||initialize initation||initiation initators||initiators initialiazation||initialization +initializationg||initialization initializiation||initialization +initialze||initialize initialzed||initialized +initialzing||initializing initilization||initialization initilize||initialize +initliaze||initialize +initilized||initialized inofficial||unofficial +inrerface||interface insititute||institute +instace||instance instal||install +instanciate||instantiate instanciated||instantiated +instuments||instruments +insufficent||insufficient inteface||interface integreated||integrated integrety||integrity integrey||integrity intendet||intended intented||intended +interal||internal interanl||internal interchangable||interchangeable interferring||interfering interger||integer +intergrated||integrated intermittant||intermittent internel||internal interoprability||interoperability +interuupt||interrupt +interupts||interrupts interrface||interface interrrupt||interrupt interrup||interrupt @@ -609,6 +875,7 @@ interrups||interrupts interruptted||interrupted interupted||interrupted interupt||interrupt +intiailized||initialized intial||initial intialisation||initialisation intialised||initialised @@ -617,24 +884,35 @@ intialization||initialization intialized||initialized intialize||initialize intregral||integral +intrerrupt||interrupt intrrupt||interrupt intterrupt||interrupt intuative||intuitive +inavlid||invalid invaid||invalid +invaild||invalid +invailid||invalid +invald||invalid invalde||invalid invalide||invalid +invalidiate||invalidate invalud||invalid invididual||individual invokation||invocation invokations||invocations +ireelevant||irrelevant irrelevent||irrelevant isnt||isn't isssue||issue +issus||issues +iteraions||iterations iternations||iterations itertation||iteration itslef||itself +ivalid||invalid jave||java jeffies||jiffies +jumpimng||jumping juse||just jus||just kown||known @@ -644,6 +922,7 @@ langauge||language langugage||language lauch||launch layed||laid +legnth||length leightweight||lightweight lengh||length lenght||length @@ -654,40 +933,66 @@ libary||library librairies||libraries libraris||libraries licenceing||licencing +limted||limited +logaritmic||logarithmic loggging||logging loggin||login logile||logfile +loobpack||loopback loosing||losing losted||lost +maangement||management machinary||machinery +maibox||mailbox maintainance||maintenance maintainence||maintenance maintan||maintain makeing||making +mailformed||malformed malplaced||misplaced malplace||misplace managable||manageable +managament||management managment||management mangement||management +manger||manager manoeuvering||maneuvering +manufaucturing||manufacturing mappping||mapping +maping||mapping +matchs||matches mathimatical||mathematical mathimatic||mathematic mathimatics||mathematics +maxmium||maximum +maximium||maximum maxium||maximum mechamism||mechanism +mechanim||mechanism meetign||meeting +memeory||memory +memmber||member +memoery||memory +memroy||memory ment||meant mergable||mergeable mesage||message +mesages||messages messags||messages messgaes||messages messsage||message messsages||messages +metdata||metadata +micropone||microphone microprocesspr||microprocessor +migrateable||migratable +millenium||millennium milliseonds||milliseconds +minimim||minimum minium||minimum minimam||minimum +minimun||minimum +miniumum||minimum minumum||minimum misalinged||misaligned miscelleneous||miscellaneous @@ -695,21 +1000,35 @@ misformed||malformed mispelled||misspelled mispelt||misspelt mising||missing +mismactch||mismatch +missign||missing +missmanaged||mismanaged +missmatch||mismatch +misssing||missing miximum||maximum mmnemonic||mnemonic mnay||many +modfiy||modify +modifer||modifier +modul||module modulues||modules momery||memory +memomry||memory +monitring||monitoring monochorome||monochrome monochromo||monochrome monocrome||monochrome mopdule||module mroe||more mulitplied||multiplied +muliple||multiple +multipler||multiplier multidimensionnal||multidimensional +multipe||multiple multple||multiple mumber||number muticast||multicast +mutilcast||multicast mutiple||multiple mutli||multi nams||names @@ -726,45 +1045,67 @@ negotation||negotiation nerver||never nescessary||necessary nessessary||necessary +none existent||non-existent noticable||noticeable +notication||notification notications||notifications +notifcations||notifications notifed||notified +notity||notify +nubmer||number numebr||number +numer||number numner||number +nunber||number obtaion||obtain +obusing||abusing occassionally||occasionally occationally||occasionally occurance||occurrence occurances||occurrences -occured||occurred +occurd||occurred occurence||occurrence occure||occurred occured||occurred occuring||occurring +ocurrence||occurrence +offser||offset offet||offset +offlaod||offload +offloded||offloaded +offseting||offsetting +oflload||offload omited||omitted omiting||omitting omitt||omit ommiting||omitting ommitted||omitted onself||oneself +onthe||on the ony||only +openning||opening operatione||operation opertaions||operations +opportunies||opportunities optionnal||optional optmizations||optimizations orientatied||orientated orientied||oriented orignal||original +originial||original otherise||otherwise ouput||output oustanding||outstanding overaall||overall overhread||overhead overlaping||overlapping +oveflow||overflow +overflw||overflow +overlfow||overflow overide||override overrided||overridden overriden||overridden +overrrun||overrun overun||overrun overwritting||overwriting overwriten||overwritten @@ -775,8 +1116,10 @@ packege||package packge||package packtes||packets pakage||package +paket||packet pallette||palette paln||plan +palne||plane paramameters||parameters paramaters||parameters paramater||parameter @@ -784,22 +1127,36 @@ parametes||parameters parametised||parametrised paramter||parameter paramters||parameters +parmaters||parameters particuarly||particularly particularily||particularly +partion||partition +partions||partitions partiton||partition pased||passed passin||passing pathes||paths +pattrns||patterns pecularities||peculiarities peformance||performance +peforming||performing peice||piece pendantic||pedantic peprocessor||preprocessor +perfomance||performance perfoming||performing +perfomring||performing +periperal||peripheral +peripherial||peripheral permissons||permissions +permited||permitted peroid||period persistance||persistence persistant||persistent +phoneticly||phonetically +plaform||platform +plalform||platform +platfoem||platform platfrom||platform plattform||platform pleaes||please @@ -811,7 +1168,12 @@ poiter||pointer posible||possible positon||position possibilites||possibilities +potocol||protocol powerfull||powerful +pramater||parameter +preamle||preamble +preample||preamble +preapre||prepare preceeded||preceded preceeding||preceding preceed||precede @@ -820,17 +1182,28 @@ precission||precision preemptable||preemptible prefered||preferred prefferably||preferably +prefitler||prefilter +preform||perform premption||preemption prepaired||prepared +prepate||prepare +preperation||preparation +preprare||prepare pressre||pressure +presuambly||presumably +previosuly||previously +previsously||previously primative||primitive princliple||principle priorty||priority +priting||printing privilaged||privileged privilage||privilege priviledge||privilege priviledges||privileges +privleges||privileges probaly||probably +probabalistic||probabilistic procceed||proceed proccesors||processors procesed||processed @@ -843,12 +1216,17 @@ processsed||processed processsing||processing procteted||protected prodecure||procedure +progamming||programming progams||programs progess||progress +programable||programmable programers||programmers programm||program programms||programs +progres||progress progresss||progress +prohibitted||prohibited +prohibitting||prohibiting promiscous||promiscuous promps||prompts pronnounced||pronounced @@ -858,34 +1236,45 @@ pronunce||pronounce propery||property propigate||propagate propigation||propagation +propogation||propagation propogate||propagate prosess||process protable||portable protcol||protocol protecion||protection +protedcted||protected protocoll||protocol promixity||proximity psudo||pseudo psuedo||pseudo psychadelic||psychedelic +purgable||purgeable pwoer||power +queing||queuing quering||querying +queus||queues +randomally||randomly raoming||roaming reasearcher||researcher reasearchers||researchers reasearch||research +receieve||receive recepient||recipient +recevied||received receving||receiving +recievd||received recieved||received recieve||receive reciever||receiver recieves||receives +recieving||receiving recogniced||recognised recognizeable||recognizable recommanded||recommended recyle||recycle redircet||redirect redirectrion||redirection +redundacy||redundancy reename||rename refcounf||refcount refence||reference @@ -895,8 +1284,12 @@ refering||referring refernces||references refernnce||reference refrence||reference +regiser||register +registed||registered registerd||registered +registeration||registration registeresd||registered +registerred||registered registes||registers registraration||registration regsiter||register @@ -907,6 +1300,7 @@ regulamentations||regulations reigstration||registration releated||related relevent||relevant +reloade||reload remoote||remote remore||remote removeable||removable @@ -917,29 +1311,45 @@ replys||replies reponse||response representaion||representation reqeust||request +reqister||register +requed||requeued requestied||requested requiere||require requirment||requirement requred||required requried||required requst||request +requsted||requested +reregisteration||reregistration reseting||resetting +reseved||reserved +reseverd||reserved resizeable||resizable +resotre||restore +resouce||resource resouces||resources resoures||resources responce||response +resrouce||resource ressizes||resizes ressource||resource ressources||resources +restesting||retesting +resumbmitting||resubmitting retransmited||retransmitted retreived||retrieved retreive||retrieve +retreiving||retrieving retrive||retrieve +retrived||retrieved +retrun||return +retun||return retuned||returned reudce||reduce reuest||request reuqest||request reutnred||returned +revsion||revision rmeoved||removed rmeove||remove rmeoves||removes @@ -948,20 +1358,29 @@ routins||routines rquest||request runing||running runned||ran +runnnig||running runnning||running runtine||runtime sacrifying||sacrificing safly||safely safty||safety +satify||satisfy +satisifed||satisfied savable||saveable +scaleing||scaling scaned||scanned scaning||scanning scarch||search +schdule||schedule seach||search searchs||searches +secion||section secquence||sequence secund||second segement||segment +seleted||selected +semaphone||semaphore +senario||scenario senarios||scenarios sentivite||sensitive separatly||separately @@ -973,11 +1392,19 @@ seperate||separate seperatly||separately seperator||separator sepperate||separate +seqeunce||sequence +seqeuncer||sequencer +seqeuencer||sequencer sequece||sequence +sequemce||sequence sequencial||sequential +serivce||service serveral||several +servive||service setts||sets settting||setting +shapshot||snapshot +shoft||shift shotdown||shutdown shoud||should shouldnt||shouldn't @@ -985,24 +1412,35 @@ shoule||should shrinked||shrunk siginificantly||significantly signabl||signal +significanly||significantly similary||similarly similiar||similar simlar||similar simliar||similar simpified||simplified +simultaneusly||simultaneously +simultanous||simultaneous singaled||signaled singal||signal singed||signed +slect||select sleeped||slept +sliped||slipped +softwade||software softwares||software +soley||solely +souce||source speach||speech specfic||specific +specfield||specified speciefied||specified specifc||specific specifed||specified specificatin||specification specificaton||specification +specificed||specified specifing||specifying +specifiy||specify specifiying||specifying speficied||specified speicify||specify @@ -1019,8 +1457,12 @@ staion||station standardss||standards standartization||standardization standart||standard +standy||standby +stardard||standard staticly||statically +statuss||status stoped||stopped +stoping||stopping stoppped||stopped straming||streaming struc||struct @@ -1032,12 +1474,18 @@ sturcture||structure subdirectoires||subdirectories suble||subtle substract||subtract +submited||submitted +submition||submission +succeded||succeeded +suceed||succeed +succesfuly||successfully succesfully||successfully succesful||successful successed||succeeded successfull||successful successfuly||successfully sucessfully||successfully +sucessful||successful sucess||success superflous||superfluous superseeded||superseded @@ -1046,14 +1494,18 @@ suported||supported suport||support supportet||supported suppored||supported +supporing||supporting supportin||supporting suppoted||supported suppported||supported suppport||support +supprot||support supress||suppress +surpressed||suppressed surpresses||suppresses susbsystem||subsystem suspeneded||suspended +suspsend||suspend suspicously||suspiciously swaping||swapping switchs||switches @@ -1064,9 +1516,14 @@ swithced||switched swithcing||switching swithed||switched swithing||switching +swtich||switch +syfs||sysfs symetric||symmetric synax||syntax synchonized||synchronized +sychronization||synchronization +sychronously||synchronously +synchronuously||synchronously syncronize||synchronize syncronized||synchronized syncronizing||synchronizing @@ -1075,43 +1532,78 @@ syste||system sytem||system sythesis||synthesis taht||that +tained||tainted +tarffic||traffic +tansmit||transmit targetted||targeted targetting||targeting +taskelt||tasklet teh||the +temeprature||temperature temorary||temporary temproarily||temporarily +temperture||temperature the the||the +theads||threads therfore||therefore thier||their threds||threads +threee||three threshhold||threshold +thresold||threshold throught||through +tansition||transition +trackling||tracking +troughput||throughput +trys||tries thses||these +tiggers||triggers tiggered||triggered tipically||typically +timeing||timing timout||timeout tmis||this +toogle||toggle torerable||tolerable +torlence||tolerance +traget||target +traking||tracking tramsmitted||transmitted tramsmit||transmit +tranasction||transaction +tranceiver||transceiver tranfer||transfer +tranmission||transmission +transcevier||transceiver transciever||transceiver transferd||transferred transfered||transferred transfering||transferring transision||transition +transistioned||transitioned transmittd||transmitted transormed||transformed +trasfer||transfer trasmission||transmission treshold||threshold +triggerd||triggered +trigerred||triggered trigerring||triggering trun||turn +tunning||tuning ture||true tyep||type udpate||update +updtes||updates uesd||used +unknwon||unknown +uknown||unknown +usccess||success uncommited||uncommitted +uncompatible||incompatible unconditionaly||unconditionally +undeflow||underflow +undelying||underlying underun||underrun unecessary||unnecessary unexecpted||unexpected @@ -1122,31 +1614,52 @@ unexpeted||unexpected unexpexted||unexpected unfortunatelly||unfortunately unifiy||unify +uniterrupted||uninterrupted +uninterruptable||uninterruptible unintialized||uninitialized +unitialized||uninitialized unkmown||unknown unknonw||unknown +unknouwn||unknown unknow||unknown unkown||unknown +unamed||unnamed +uneeded||unneeded unneded||unneeded +unneccecary||unnecessary +unneccesary||unnecessary +unneccessary||unnecessary +unnecesary||unnecessary unneedingly||unnecessarily unnsupported||unsupported +unuspported||unsupported unmached||unmatched +unprecise||imprecise +unpriviledged||unprivileged +unpriviliged||unprivileged unregester||unregister unresgister||unregister unrgesiter||unregister unsinged||unsigned unstabel||unstable +unsolicted||unsolicited unsolicitied||unsolicited unsuccessfull||unsuccessful unsuported||unsupported untill||until +ununsed||unused unuseful||useless +unvalid||invalid upate||update +upsupported||unsupported +upto||up to +useable||usable usefule||useful usefull||useful usege||usage usera||users usualy||usually +usupported||unsupported utilites||utilities utillities||utilities utilties||utilities @@ -1161,8 +1674,12 @@ varible||variable varient||variant vaule||value verbse||verbose +veify||verify +verfication||verification +veriosn||version verisons||versions verison||version +veritical||vertical verson||version vicefersa||vice-versa virtal||virtual @@ -1170,7 +1687,12 @@ virtaul||virtual virtiual||virtual visiters||visitors vitual||virtual +vunerable||vulnerable +wakeus||wakeups +was't||wasn't +wathdog||watchdog wating||waiting +wiat||wait wether||whether whataver||whatever whcih||which @@ -1178,12 +1700,15 @@ whenver||whenever wheter||whether whe||when wierd||weird +wihout||without wiil||will wirte||write withing||within wnat||want +wont||won't workarould||workaround writeing||writing writting||writing +wtih||with zombe||zombie zomebie||zombie From 155420522b403f42b5f1943cb33ca90f04bffd2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 15 Nov 2023 16:29:08 +0100 Subject: [PATCH 0492/1049] doc: Fix occurrences of repeated words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Another round of repeated words cleanup. This commit tries to keep the diff minimal and line wrapping was mostly left intact in the touched files, as having them consistent across the documentation is probably the topic of a future tree-wide cleanup (or not) Signed-off-by: Benjamin Cabé --- doc/build/cmake/index.rst | 2 +- doc/build/dts/intro-syntax-structure.rst | 2 +- doc/build/kconfig/setting.rst | 3 +-- doc/connectivity/bluetooth/api/gatt.rst | 2 +- doc/connectivity/bluetooth/api/shell/cap.rst | 2 +- doc/connectivity/bluetooth/api/shell/csip.rst | 2 +- doc/connectivity/bluetooth/api/shell/mcp.rst | 3 +-- doc/connectivity/bluetooth/api/shell/tmap.rst | 2 +- doc/connectivity/bluetooth/bluetooth-tools.rst | 2 +- doc/connectivity/networking/api/lwm2m.rst | 2 +- doc/connectivity/networking/conn_mgr/main.rst | 2 +- doc/develop/getting_started/installation_linux.rst | 2 +- doc/develop/languages/c/newlib.rst | 2 +- doc/develop/west/manifest.rst | 4 ++-- doc/develop/west/release-notes.rst | 2 +- doc/develop/west/sign.rst | 2 +- doc/glossary.rst | 2 +- doc/hardware/peripherals/auxdisplay.rst | 2 +- doc/hardware/peripherals/bc12.rst | 2 +- doc/kernel/services/synchronization/events.rst | 8 ++++---- doc/services/device_mgmt/smp_groups/smp_group_1.rst | 4 ++-- doc/services/device_mgmt/smp_groups/smp_group_3.rst | 6 +++--- doc/services/sensing/index.rst | 2 +- 23 files changed, 30 insertions(+), 32 deletions(-) diff --git a/doc/build/cmake/index.rst b/doc/build/cmake/index.rst index 479e044b68e2cc6..534c3ff34e106bc 100644 --- a/doc/build/cmake/index.rst +++ b/doc/build/cmake/index.rst @@ -108,7 +108,7 @@ Devicetree :ref:`dt-guide`. Kconfig - :file:`Kconfig` files define available configuration options for for the + :file:`Kconfig` files define available configuration options for the target architecture, SoC, board, and application, as well as dependencies between options. diff --git a/doc/build/dts/intro-syntax-structure.rst b/doc/build/dts/intro-syntax-structure.rst index f3b7c6cebd7ba4d..1fd7eead9f85cc8 100644 --- a/doc/build/dts/intro-syntax-structure.rst +++ b/doc/build/dts/intro-syntax-structure.rst @@ -370,7 +370,7 @@ curious about details, see the devicetree specification. Additional notes on the above: - The values in the ``phandle``, ``phandles``, and ``phandle-array`` types are - are described further in :ref:`dt-phandles` + described further in :ref:`dt-phandles` - Boolean properties are true if present. They should not have a value. A boolean property is only false if it is completely missing in the DTS. diff --git a/doc/build/kconfig/setting.rst b/doc/build/kconfig/setting.rst index 041aed5fc3663bd..57dd7828978c446 100644 --- a/doc/build/kconfig/setting.rst +++ b/doc/build/kconfig/setting.rst @@ -373,5 +373,4 @@ The :ref:`kconfig_tips_and_tricks` page has some tips for writing Kconfig files. The :zephyr_file:`kconfiglib.py ` docstring -docstring (at the top of the file) goes over how symbol values are calculated -in detail. +(at the top of the file) goes over how symbol values are calculated in detail. diff --git a/doc/connectivity/bluetooth/api/gatt.rst b/doc/connectivity/bluetooth/api/gatt.rst index 3cc1af64387b862..bb4487f57dd833f 100644 --- a/doc/connectivity/bluetooth/api/gatt.rst +++ b/doc/connectivity/bluetooth/api/gatt.rst @@ -56,7 +56,7 @@ respective operations. thus it is not recommended to block for long periods of time in them. Attribute value changes can be notified using :c:func:`bt_gatt_notify` API, -alternatively there is :c:func:`bt_gatt_notify_cb` where is is possible to +alternatively there is :c:func:`bt_gatt_notify_cb` where it is possible to pass a callback to be called when it is necessary to know the exact instant when the data has been transmitted over the air. Indications are supported by :c:func:`bt_gatt_indicate` API. diff --git a/doc/connectivity/bluetooth/api/shell/cap.rst b/doc/connectivity/bluetooth/api/shell/cap.rst index 74bf5bac72fc069..5ab57a8d3209963 100644 --- a/doc/connectivity/bluetooth/api/shell/cap.rst +++ b/doc/connectivity/bluetooth/api/shell/cap.rst @@ -14,7 +14,7 @@ Using the CAP Acceptor ====================== When the Bluetooth stack has been initialized (:code:`bt init`), the Acceptor can be registered by -by calling :code:`cap_acceptor init`, which will register the CAS and CSIS services, as well as +calling :code:`cap_acceptor init`, which will register the CAS and CSIS services, as well as register callbacks. .. code-block:: console diff --git a/doc/connectivity/bluetooth/api/shell/csip.rst b/doc/connectivity/bluetooth/api/shell/csip.rst index e2daf744cacbea1..d0fddaa61f3c41a 100644 --- a/doc/connectivity/bluetooth/api/shell/csip.rst +++ b/doc/connectivity/bluetooth/api/shell/csip.rst @@ -14,7 +14,7 @@ or a laptop. The client is able to lock and release members of a coordinated set. While the coordinated set is locked, no other clients may lock the set. To lock a set, the client must connect to each of the set members it wants to -lock. This implementation will always try to to connect to all the members of +lock. This implementation will always try to connect to all the members of the set, and at the same time. Thus if the set size is 3, then :code:`BT_MAX_CONN` shall be at least 3. diff --git a/doc/connectivity/bluetooth/api/shell/mcp.rst b/doc/connectivity/bluetooth/api/shell/mcp.rst index a48ef50685c2c92..e0930852e10c232 100644 --- a/doc/connectivity/bluetooth/api/shell/mcp.rst +++ b/doc/connectivity/bluetooth/api/shell/mcp.rst @@ -27,8 +27,7 @@ Also note that this documentation does not list all shell commands, it just shows examples of some of them. The set of commands is explorable from the mcc shell and the mpl shell, by typing :code:`mcc` or :code:`mpl` and pressing TAB. A help text for each command can be -found by doing :code:`mcc help` or or :code:`mpl -help`. +found by doing :samp:`mcc {} help` or :samp:`mpl {} help`. Overview ******** diff --git a/doc/connectivity/bluetooth/api/shell/tmap.rst b/doc/connectivity/bluetooth/api/shell/tmap.rst index 416644b30692944..8a562a813615718 100644 --- a/doc/connectivity/bluetooth/api/shell/tmap.rst +++ b/doc/connectivity/bluetooth/api/shell/tmap.rst @@ -10,7 +10,7 @@ Using the TMAP Shell ******************** When the Bluetooth stack has been initialized (:code:`bt init`), the TMAS can be registered by -by calling :code:`tmap init`. +calling :code:`tmap init`. .. code-block:: console diff --git a/doc/connectivity/bluetooth/bluetooth-tools.rst b/doc/connectivity/bluetooth/bluetooth-tools.rst index daa8107e0f3a36d..9da5c5feb1ea3d2 100644 --- a/doc/connectivity/bluetooth/bluetooth-tools.rst +++ b/doc/connectivity/bluetooth/bluetooth-tools.rst @@ -212,7 +212,7 @@ To connect your application to the Android Emulator follow the next steps: #. Build your Zephyr application and disable the HCI ACL flow control (i.e. ``CONFIG_BT_HCI_ACL_FLOW_CONTROL=n``) as the - the virtual controller from android does not support it at the moment. + virtual controller from android does not support it at the moment. #. Install Android Emulator version >= 33.1.4.0. The easiest way to do this is by installing the latest `Android Studio Preview`_ version. diff --git a/doc/connectivity/networking/api/lwm2m.rst b/doc/connectivity/networking/api/lwm2m.rst index b8c4756b5d638ed..8a36adf88601ac3 100644 --- a/doc/connectivity/networking/api/lwm2m.rst +++ b/doc/connectivity/networking/api/lwm2m.rst @@ -478,7 +478,7 @@ Support for time series data LwM2M version 1.1 adds support for SenML CBOR and SenML JSON data formats. These data formats add support for time series data. Time series formats can be used for READ, NOTIFY and SEND operations. When data cache is enabled for a resource, each write will create a timestamped entry in a cache, -and its content is then returned as a content in in READ, NOTIFY or SEND operation for a given +and its content is then returned as a content in READ, NOTIFY or SEND operation for a given resource. Data cache is only supported for resources with a fixed data size. diff --git a/doc/connectivity/networking/conn_mgr/main.rst b/doc/connectivity/networking/conn_mgr/main.rst index 4bde856f0ce01d4..675be831418edf4 100644 --- a/doc/connectivity/networking/conn_mgr/main.rst +++ b/doc/connectivity/networking/conn_mgr/main.rst @@ -421,7 +421,7 @@ There are a few actions related to connectivity that are (by default at least) p By default, Connection Manager will automatically take any bound iface admin-down if it has given up on associating. - Applications can disable this for all ifaces by disabling the :kconfig:option:`CONFIG_NET_CONNECTION_MANAGER_AUTO_IF_DOWN` Kconfig option, or for individual ifaces by setting the :c:enumerator:`~conn_mgr_if_flag.CONN_MGR_IF_NO_AUTO_DOWN` connectivity flag with with :c:func:`conn_mgr_if_set_flag`. + Applications can disable this for all ifaces by disabling the :kconfig:option:`CONFIG_NET_CONNECTION_MANAGER_AUTO_IF_DOWN` Kconfig option, or for individual ifaces by setting the :c:enumerator:`~conn_mgr_if_flag.CONN_MGR_IF_NO_AUTO_DOWN` connectivity flag with :c:func:`conn_mgr_if_set_flag`. .. _conn_mgr_control_api: diff --git a/doc/develop/getting_started/installation_linux.rst b/doc/develop/getting_started/installation_linux.rst index d9598f4170d99ec..f507a8d823cac7d 100644 --- a/doc/develop/getting_started/installation_linux.rst +++ b/doc/develop/getting_started/installation_linux.rst @@ -303,7 +303,7 @@ toolchains for all Zephyr target architectures, and does not require any extra flags when building applications or running tests. In addition to cross-compilers, the Zephyr SDK also provides prebuilt host tools. It is, however, possible to build without the SDK's toolchain by using another -toolchain as as described in the :ref:`toolchains` section. +toolchain as described in the :ref:`toolchains` section. As already noted above, the SDK also includes prebuilt host tools. To use the SDK's prebuilt host tools with a toolchain from another source, you must set the diff --git a/doc/develop/languages/c/newlib.rst b/doc/develop/languages/c/newlib.rst index f79d00c01e26c0e..a0daba2b9712e32 100644 --- a/doc/develop/languages/c/newlib.rst +++ b/doc/develop/languages/c/newlib.rst @@ -31,7 +31,7 @@ The Newlib full variant (:file:`libc.a` and :file:`libm.a`) is the most capable variant of the Newlib available in the Zephyr SDK, and supports almost all standard C library features. It is optimized for performance (prefers performance over code size) and its footprint is significantly larger than the -the nano variant. +nano variant. This variant can be enabled by selecting the :kconfig:option:`CONFIG_NEWLIB_LIBC` and de-selecting the diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index ba0f9f2970658ca..f989cdcae1e2ba6 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -1124,7 +1124,7 @@ recursively update the project's Git submodules whenever it updates the project itself. If it's ``false`` or missing, it has no effect. For example, let's say you have a source code repository ``foo``, which has -some submodules, and you want ``west update`` to keep all of them them in sync, +some submodules, and you want ``west update`` to keep all of them in sync, along with another project named ``bar`` in the same workspace. You can do that with this manifest file: @@ -2050,7 +2050,7 @@ The ultimate outcomes of resolving manifest imports are: in the top-level file with those defined in imported files - a set of extension commands, which are drawn from the ``west-commands`` - keys in in the top-level file and any imported files + keys in the top-level file and any imported files - a ``group-filter`` list, which is produced by combining the top-level and any imported filters diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 49dcc0a31163b95..951cc4c3e374589 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -669,7 +669,7 @@ The developer-visible changes to the :ref:`west-apis` are: West now requires Python 3.6 or later. Additionally, some features may rely on Python dictionaries being insertion-ordered; this is only an implementation -detail in CPython 3.6, but is is part of the language specification as of +detail in CPython 3.6, but it is part of the language specification as of Python 3.7. v0.6.3 diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 44193d4611f3231..8cc55ffeea4e80b 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -40,7 +40,7 @@ Notes on the above commands: - ``YOUR_BOARD`` should be changed to match your board - The ``CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`` value is the insecure default - provided and used by by MCUboot for development and testing + provided and used by MCUboot for development and testing - You can change the ``hello_world`` application directory to any other application that can be loaded by MCUboot, such as the :zephyr:code-sample:`smp-svr` sample. diff --git a/doc/glossary.rst b/doc/glossary.rst index eafda9410fcb05e..8571f4b6d491eb0 100644 --- a/doc/glossary.rst +++ b/doc/glossary.rst @@ -89,7 +89,7 @@ Glossary of Terms system power state System power states describe the power consumption of the system as a - whole. System power states are are represented by :c:enum:`pm_state`. + whole. System power states are represented by :c:enum:`pm_state`. west A multi-repo meta-tool developed for the Zephyr project. See :ref:`west`. diff --git a/doc/hardware/peripherals/auxdisplay.rst b/doc/hardware/peripherals/auxdisplay.rst index b3cb6cbae5babeb..913b43f2779c87e 100644 --- a/doc/hardware/peripherals/auxdisplay.rst +++ b/doc/hardware/peripherals/auxdisplay.rst @@ -9,7 +9,7 @@ Overview Auxiliary Displays are text-based displays that have simple interfaces for displaying textual, numeric or alphanumeric data, as opposed to the :ref:`display_api`, auxiliary displays do not support custom -graphical output to displays (and and most often monochrome), the most +graphical output to displays (and most often monochrome), the most advanced custom feature supported is generation of custom characters. These inexpensive displays are commonly found with various configurations and sizes, a common display size is 16 characters by 2 lines. diff --git a/doc/hardware/peripherals/bc12.rst b/doc/hardware/peripherals/bc12.rst index 00c9bcdb677b017..a612a403dbbd96c 100644 --- a/doc/hardware/peripherals/bc12.rst +++ b/doc/hardware/peripherals/bc12.rst @@ -74,7 +74,7 @@ Charging port mode is used by the application when the USB port is configured as a downstream facing port, i.e. a USB host port. For charging port mode, the BC1.2 driver powers up the detection chip and configures the charger type specified by a devicetree property. If the driver supports detection of plug and -and unplug events, the BC1.2 driver notifies the callback registered with +unplug events, the BC1.2 driver notifies the callback registered with ``bc12_set_result_cb()`` to indicate the current connection state of the portable device partner. diff --git a/doc/kernel/services/synchronization/events.rst b/doc/kernel/services/synchronization/events.rst index 7182803883a75f0..cbb86894723c3dc 100644 --- a/doc/kernel/services/synchronization/events.rst +++ b/doc/kernel/services/synchronization/events.rst @@ -33,10 +33,10 @@ conditions of multiple threads waiting on the event object. All threads whose match conditions have been met are made active at the same time. Threads may wait on one or more events. They may either wait for all of the -the requested events, or for any of them. Furthermore, threads making a wait -request have the option of resetting the current set of events tracked by the -event object prior to waiting. Care must be taken with this option when -multiple threads wait on the same event object. +requested events, or for any of them. Furthermore, threads making a wait request +have the option of resetting the current set of events tracked by the event +object prior to waiting. Care must be taken with this option when multiple +threads wait on the same event object. .. note:: The kernel does allow an ISR to query an event object, however the ISR must diff --git a/doc/services/device_mgmt/smp_groups/smp_group_1.rst b/doc/services/device_mgmt/smp_groups/smp_group_1.rst index 819d83301497253..2a1d1f2708632b6 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_1.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_1.rst @@ -3,7 +3,7 @@ Application/software image management group ########################################### -Application/software image management management group defines following commands: +Application/software image management group defines following commands: .. table:: :align: center @@ -75,7 +75,7 @@ Get state of images request header fields: | ``0`` | ``1`` | ``0`` | +--------+--------------+----------------+ -The command sends sends empty CBOR map as data. +The command sends an empty CBOR map as data. .. _mcumgr_smp_protocol_op_1_grp_1_cmd_0: diff --git a/doc/services/device_mgmt/smp_groups/smp_group_3.rst b/doc/services/device_mgmt/smp_groups/smp_group_3.rst index a6f1ee73b7aaab2..c70897809e1c33f 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_3.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_3.rst @@ -333,7 +333,7 @@ Commit settings request header fields: | ``2`` | ``3`` | ``2`` | +--------+--------------+----------------+ -The command sends sends empty CBOR map as data. +The command sends an empty CBOR map as data. Commit settings response ======================== @@ -409,7 +409,7 @@ Load settings request header fields: | ``0`` | ``3`` | ``3`` | +--------+--------------+----------------+ -The command sends sends empty CBOR map as data. +The command sends an empty CBOR map as data. Load settings response ====================== @@ -479,7 +479,7 @@ Save settings request header fields: | ``2`` | ``3`` | ``3`` | +--------+--------------+----------------+ -The command sends sends empty CBOR map as data. +The command sends an empty CBOR map as data. Save settings response ====================== diff --git a/doc/services/sensing/index.rst b/doc/services/sensing/index.rst index 99fdc48d6b70743..d0ae0bea5ee9663 100644 --- a/doc/services/sensing/index.rst +++ b/doc/services/sensing/index.rst @@ -197,7 +197,7 @@ Sensor Sample Value The ``header`` defines a **base_timestamp**, and each element in the **readings[]** array defines **timestamp_delta**. - The **timestamp_delta** is is in relation to the previous **readings** (or the **base_timestamp**) + The **timestamp_delta** is in relation to the previous **readings** (or the **base_timestamp**) For example: From 483dd8a40a143215c03b634eb3bb87e7265c933d Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 14 Nov 2023 14:03:04 -0800 Subject: [PATCH 0493/1049] doc: doxygen: move mpsc and spsc under data structure API group Both MPSC and SPSC should be under data structure API group instead of kernel API group. So move them, and fix some doxygen cosmetic grouping issues for SPSC. Signed-off-by: Daniel Leung --- include/zephyr/sys/mpsc_pbuf.h | 2 +- include/zephyr/sys/spsc_pbuf.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/zephyr/sys/mpsc_pbuf.h b/include/zephyr/sys/mpsc_pbuf.h index a80cc2db4646428..72f6e99515b89ee 100644 --- a/include/zephyr/sys/mpsc_pbuf.h +++ b/include/zephyr/sys/mpsc_pbuf.h @@ -19,7 +19,7 @@ extern "C" { /** * @brief Multi producer, single consumer packet buffer API * @defgroup mpsc_buf MPSC (Multi producer, single consumer) packet buffer API - * @ingroup kernel_apis + * @ingroup datastructure_apis * @{ */ diff --git a/include/zephyr/sys/spsc_pbuf.h b/include/zephyr/sys/spsc_pbuf.h index 682d610e34b4fef..0e7f018fa63cccf 100644 --- a/include/zephyr/sys/spsc_pbuf.h +++ b/include/zephyr/sys/spsc_pbuf.h @@ -16,11 +16,12 @@ extern "C" { /** * @brief Single producer, single consumer packet buffer API - * @ingroup kernel_apis + * @defgroup spsc_buf SPSC (Single producer, single consumer) packet buffer API + * @ingroup datastructure_apis * @{ */ -/**@defgroup SPSC_PBUF_FLAGS MPSC packet buffer flags +/**@defgroup SPSC_PBUF_FLAGS SPSC packet buffer flags * @{ */ From 76b0aab6cc263701cc42652f25d0fb78092f958e Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Tue, 14 Nov 2023 19:20:32 -0800 Subject: [PATCH 0494/1049] soc: arm: npcx: fix clock reference of APB4/FIU1 buses This CL fixes the clock reference of APB4/FIU1 buses by introducing new Kconfig options. Signed-off-by: Mulin Chao --- drivers/clock_control/Kconfig.npcx | 12 ++++++++++++ soc/arm/nuvoton_npcx/common/soc_clock.h | 16 ++++++++++++++++ soc/arm/nuvoton_npcx/npcx4/soc.h | 12 ------------ soc/arm/nuvoton_npcx/npcx9/soc.h | 6 ------ 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/clock_control/Kconfig.npcx b/drivers/clock_control/Kconfig.npcx index b4b91d5f8d3b392..76e5acf985a4326 100644 --- a/drivers/clock_control/Kconfig.npcx +++ b/drivers/clock_control/Kconfig.npcx @@ -18,3 +18,15 @@ config CLOCK_CONTROL_NPCX_EXTERNAL_SRC is generated by the on-chip Crystal Oscillator (XTOSC). This includes an on-chip oscillator, to which an external crystal and the related passive components are connected. + +config CLOCK_CONTROL_NPCX_SUPP_APB4 + bool "Indicates that the clock controller supports APB4 bus" + default y if !SOC_SERIES_NPCX7 + help + Selected if NPCX series supports APB4 bus. + +config CLOCK_CONTROL_NPCX_SUPP_FIU1 + bool "Indicates that the clock controller supports FIU1 bus" + default y if SOC_SERIES_NPCX4 + help + Selected if NPCX series supports FIU1 bus. diff --git a/soc/arm/nuvoton_npcx/common/soc_clock.h b/soc/arm/nuvoton_npcx/common/soc_clock.h index 6b302f2e885d74a..d43a70d4529df6a 100644 --- a/soc/arm/nuvoton_npcx/common/soc_clock.h +++ b/soc/arm/nuvoton_npcx/common/soc_clock.h @@ -42,6 +42,14 @@ struct npcx_clk_cfg { #define APB2DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb2_prescaler) - 1) /* APB3 clock divider */ #define APB3DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb3_prescaler) - 1) +/* APB4 clock divider if supported */ +#if DT_NODE_HAS_PROP(DT_NODELABEL(pcc), apb4_prescaler) +#if defined(CONFIG_CLOCK_CONTROL_NPCX_SUPP_APB4) /* Supported in NPCX9 and later series */ +#define APB4DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb4_prescaler) - 1) +#else +#error "APB4 clock divider is not supported but defined in pcc node!" +#endif /* CONFIG_CLOCK_CONTROL_NPCX_SUPP_APB4 */ +#endif /* Construct a uint8_t array from 'pwdwn-ctl-val' prop for PWDWN_CTL initialization. */ #define NPCX_PWDWN_CTL_ITEMS_INIT(node, prop, idx) DT_PROP_BY_IDX(node, prop, idx), @@ -89,6 +97,14 @@ struct npcx_clk_cfg { #define FIUDIV_VAL 0 /* FIU_CLK = CORE_CLK */ #endif +#if defined(CONFIG_CLOCK_CONTROL_NPCX_SUPP_FIU1) +#if (CORE_CLK > (MAX_OFMCLK / 2)) +#define FIU1DIV_VAL 1 /* FIU1_CLK = CORE_CLK/2 */ +#else +#define FIU1DIV_VAL 0 /* FIU1_CLK = CORE_CLK */ +#endif +#endif /* CONFIG_CLOCK_CONTROL_NPCX_SUPP_FIU1 */ + /* Get APB clock freq */ #define NPCX_APB_CLOCK(no) (APBSRC_CLK / (APB##no##DIV_VAL + 1)) diff --git a/soc/arm/nuvoton_npcx/npcx4/soc.h b/soc/arm/nuvoton_npcx/npcx4/soc.h index 5c3f7cf59272529..a9d4e88424ba457 100644 --- a/soc/arm/nuvoton_npcx/npcx4/soc.h +++ b/soc/arm/nuvoton_npcx/npcx4/soc.h @@ -58,16 +58,4 @@ #include #include -/* NPCX4 Clock definitions */ -#if DT_NODE_HAS_PROP(DT_NODELABEL(pcc), apb4_prescaler) -/* APB4 clock divider if supported */ -#define APB4DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb4_prescaler) - 1) -#endif - -#if (CORE_CLK > (MAX_OFMCLK / 2)) -#define FIU1DIV_VAL 1 /* If CORE_CLK > MAX_OFMCLK / 2, FIU1_CLK = CORE_CLK/2 */ -#else -#define FIU1DIV_VAL 0 /* Else, FIU1_CLK = CORE_CLK */ -#endif - #endif /* _NUVOTON_NPCX_SOC_H_ */ diff --git a/soc/arm/nuvoton_npcx/npcx9/soc.h b/soc/arm/nuvoton_npcx/npcx9/soc.h index 0e9e23cda36ee6a..6b6c3f30a44bdce 100644 --- a/soc/arm/nuvoton_npcx/npcx9/soc.h +++ b/soc/arm/nuvoton_npcx/npcx9/soc.h @@ -56,10 +56,4 @@ #include #include -/* NPCX9 Clock definitions */ -#if DT_NODE_HAS_PROP(DT_NODELABEL(pcc), apb4_prescaler) -/* APB4 clock divider if supported */ -#define APB4DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb4_prescaler) - 1) -#endif - #endif /* _NUVOTON_NPCX_SOC_H_ */ From d17b1c8cbbcbebb0fc3b90472924a8a99d595e6a Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 15 Nov 2023 18:19:16 +0100 Subject: [PATCH 0495/1049] tests: build_all: sensor: fix i2c.dtsi typo Fix lps22df i2c address in order to be unique. Signed-off-by: Armando Visconti --- tests/drivers/build_all/sensor/i2c.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 42beeab095e6317..ebafddab96c6e9c 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -801,9 +801,9 @@ test_i2c_tsl2561: tsl2561@78 { reg = <0x78>; }; -test_i2c_lps22df: lps22df@78 { +test_i2c_lps22df: lps22df@79 { compatible = "st,lps22df"; - reg = <0x78>; + reg = <0x79>; drdy-gpios = <&test_gpio 0 0>; status = "okay"; }; From 5a4e0af54a20c9c1ec1059206e79086790dd1f17 Mon Sep 17 00:00:00 2001 From: Vilem Gottwald Date: Tue, 3 Oct 2023 14:01:07 +0200 Subject: [PATCH 0496/1049] samples: synchronization: fix comments & structure This commit has no functional changes. It makes the comments up to date with the code and changes the code structure to ensure consistency. These inconsistencies were introduced when the static thread definition was replaced with dynamic, but the comments remained unchanged. - Fixed outdated comments about the static approach that were not corresponding to the code. - Rearrange thread definitions, to obtain similar code structure for both threads. Signed-off-by: Vilem Gottwald --- samples/synchronization/src/main.c | 36 +++++++++++++----------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/samples/synchronization/src/main.c b/samples/synchronization/src/main.c index 027abd1ed9671e7..cf535773741fdbe 100644 --- a/samples/synchronization/src/main.c +++ b/samples/synchronization/src/main.c @@ -1,4 +1,4 @@ -/* main.c - Hello World demo */ +/* main.c - Synchronization demo */ /* * Copyright (c) 2012-2014 Wind River Systems, Inc. @@ -10,10 +10,10 @@ #include /* - * The hello world demo has two threads that utilize semaphores and sleeping + * The synchronization demo has two threads that utilize semaphores and sleeping * to take turns printing a greeting message at a controlled rate. The demo - * shows both the static and dynamic approaches for spawning a thread; a real - * world application would likely use the static approach for both threads. + * shows only the dynamic approach for spawning a thread. Alternatively, + * a thread can be declared at compile time by calling K_THREAD_DEFINE. */ #define PIN_THREADS (IS_ENABLED(CONFIG_SMP) && IS_ENABLED(CONFIG_SCHED_CPU_MASK)) @@ -34,7 +34,7 @@ * @param other_sem other thread's semaphore */ void helloLoop(const char *my_name, - struct k_sem *my_sem, struct k_sem *other_sem) + struct k_sem *my_sem, struct k_sem *other_sem) { const char *tname; uint8_t cpu; @@ -68,41 +68,37 @@ void helloLoop(const char *my_name, } /* define semaphores */ - K_SEM_DEFINE(threadA_sem, 1, 1); /* starts off "available" */ K_SEM_DEFINE(threadB_sem, 0, 1); /* starts off "not available" */ - -/* threadB is a dynamic thread that is spawned by threadA */ - -void threadB(void *dummy1, void *dummy2, void *dummy3) +/* threadA is a dynamic thread that is spawned in main */ +void threadA(void *dummy1, void *dummy2, void *dummy3) { ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); ARG_UNUSED(dummy3); - /* invoke routine to ping-pong hello messages with threadA */ - helloLoop(__func__, &threadB_sem, &threadA_sem); + /* invoke routine to ping-pong hello messages with threadB */ + helloLoop(__func__, &threadA_sem, &threadB_sem); } -K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); -static struct k_thread threadA_data; - K_THREAD_STACK_DEFINE(threadB_stack_area, STACKSIZE); static struct k_thread threadB_data; -/* threadA is a static thread that is spawned automatically */ - -void threadA(void *dummy1, void *dummy2, void *dummy3) +/* threadB is a dynamic thread that is spawned in main */ +void threadB(void *dummy1, void *dummy2, void *dummy3) { ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); ARG_UNUSED(dummy3); - /* invoke routine to ping-pong hello messages with threadB */ - helloLoop(__func__, &threadA_sem, &threadB_sem); + /* invoke routine to ping-pong hello messages with threadA */ + helloLoop(__func__, &threadB_sem, &threadA_sem); } +K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); +static struct k_thread threadA_data; + int main(void) { k_thread_create(&threadA_data, threadA_stack_area, From 1c7eb9ee729cce326f724b373dfb06745bd1a214 Mon Sep 17 00:00:00 2001 From: Vilem Gottwald Date: Tue, 3 Oct 2023 14:01:30 +0200 Subject: [PATCH 0497/1049] samples: synchronization: add static thread Replace one of the dynamic threads with a static thread to show the all the possible ways of creating threads. Signed-off-by: Vilem Gottwald --- samples/synchronization/src/main.c | 62 +++++++++++++----------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/samples/synchronization/src/main.c b/samples/synchronization/src/main.c index cf535773741fdbe..e72eea92f92533a 100644 --- a/samples/synchronization/src/main.c +++ b/samples/synchronization/src/main.c @@ -12,8 +12,8 @@ /* * The synchronization demo has two threads that utilize semaphores and sleeping * to take turns printing a greeting message at a controlled rate. The demo - * shows only the dynamic approach for spawning a thread. Alternatively, - * a thread can be declared at compile time by calling K_THREAD_DEFINE. + * shows both the static and dynamic approaches for spawning a thread; a real + * world application would likely use the static approach for both threads. */ #define PIN_THREADS (IS_ENABLED(CONFIG_SMP) && IS_ENABLED(CONFIG_SCHED_CPU_MASK)) @@ -33,7 +33,7 @@ * @param my_sem thread's own semaphore * @param other_sem other thread's semaphore */ -void helloLoop(const char *my_name, +void hello_loop(const char *my_name, struct k_sem *my_sem, struct k_sem *other_sem) { const char *tname; @@ -68,62 +68,52 @@ void helloLoop(const char *my_name, } /* define semaphores */ -K_SEM_DEFINE(threadA_sem, 1, 1); /* starts off "available" */ -K_SEM_DEFINE(threadB_sem, 0, 1); /* starts off "not available" */ +K_SEM_DEFINE(thread_a_sem, 1, 1); /* starts off "available" */ +K_SEM_DEFINE(thread_b_sem, 0, 1); /* starts off "not available" */ -/* threadA is a dynamic thread that is spawned in main */ -void threadA(void *dummy1, void *dummy2, void *dummy3) +/* thread_a is a dynamic thread that is spawned in main */ +void thread_a_entry_point(void *dummy1, void *dummy2, void *dummy3) { ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); ARG_UNUSED(dummy3); - /* invoke routine to ping-pong hello messages with threadB */ - helloLoop(__func__, &threadA_sem, &threadB_sem); + /* invoke routine to ping-pong hello messages with thread_b */ + hello_loop(__func__, &thread_a_sem, &thread_b_sem); } +K_THREAD_STACK_DEFINE(thread_a_stack_area, STACKSIZE); +static struct k_thread thread_a_data; -K_THREAD_STACK_DEFINE(threadB_stack_area, STACKSIZE); -static struct k_thread threadB_data; - -/* threadB is a dynamic thread that is spawned in main */ -void threadB(void *dummy1, void *dummy2, void *dummy3) +/* thread_b is a static thread spawned immediately */ +void thread_b_entry_point(void *dummy1, void *dummy2, void *dummy3) { ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); ARG_UNUSED(dummy3); - /* invoke routine to ping-pong hello messages with threadA */ - helloLoop(__func__, &threadB_sem, &threadA_sem); + /* invoke routine to ping-pong hello messages with thread_a */ + hello_loop(__func__, &thread_b_sem, &thread_a_sem); } - -K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); -static struct k_thread threadA_data; +K_THREAD_DEFINE(thread_b, STACKSIZE, + thread_b_entry_point, NULL, NULL, NULL, + PRIORITY, 0, 0); +extern const k_tid_t thread_b; int main(void) { - k_thread_create(&threadA_data, threadA_stack_area, - K_THREAD_STACK_SIZEOF(threadA_stack_area), - threadA, NULL, NULL, NULL, + k_thread_create(&thread_a_data, thread_a_stack_area, + K_THREAD_STACK_SIZEOF(thread_a_stack_area), + thread_a_entry_point, NULL, NULL, NULL, PRIORITY, 0, K_FOREVER); - k_thread_name_set(&threadA_data, "thread_a"); -#if PIN_THREADS - if (arch_num_cpus() > 1) { - k_thread_cpu_pin(&threadA_data, 0); - } -#endif + k_thread_name_set(&thread_a_data, "thread_a"); - k_thread_create(&threadB_data, threadB_stack_area, - K_THREAD_STACK_SIZEOF(threadB_stack_area), - threadB, NULL, NULL, NULL, - PRIORITY, 0, K_FOREVER); - k_thread_name_set(&threadB_data, "thread_b"); #if PIN_THREADS if (arch_num_cpus() > 1) { - k_thread_cpu_pin(&threadB_data, 1); + k_thread_cpu_pin(&thread_a_data, 0); + k_thread_cpu_pin(thread_b, 1); } #endif - k_thread_start(&threadA_data); - k_thread_start(&threadB_data); + k_thread_start(&thread_a_data); return 0; } From eceb27c6c819b3467b1178e8bf505d03433f1832 Mon Sep 17 00:00:00 2001 From: Gabriel Freitas Date: Mon, 30 Oct 2023 11:34:09 -0300 Subject: [PATCH 0498/1049] dts: add support for uart1 usage on imx8ml_m7 devicetree include file Add support for UART1 usage by adding uart1 node and configuration to the i.MX 8ML devicetree include. Signed-off-by: Gabriel Freitas --- dts/arm/nxp/nxp_imx8ml_m7.dtsi | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dts/arm/nxp/nxp_imx8ml_m7.dtsi b/dts/arm/nxp/nxp_imx8ml_m7.dtsi index 4afe8e138a637d5..41f22deb9914424 100644 --- a/dts/arm/nxp/nxp_imx8ml_m7.dtsi +++ b/dts/arm/nxp/nxp_imx8ml_m7.dtsi @@ -155,10 +155,6 @@ status = "disabled"; }; - /* - * For now only UART4 is supported and - * tested with the serial driver - */ uart4: uart@30a60000 { compatible = "nxp,imx-iuart"; reg = <0x30a60000 0x10000>; @@ -167,6 +163,14 @@ status = "disabled"; }; + uart1: uart@30860000 { + compatible = "nxp,imx-iuart"; + reg = <0x30860000 0x10000>; + interrupts = <26 3>; + clocks = <&ccm IMX_CCM_UART1_CLK 0x7c 24>; + status = "disabled"; + }; + mailbox0: mailbox@30ab0000 { compatible = "nxp,imx-mu"; reg = <0x30ab0000 DT_SIZE_K(64)>; From eaec581fb9fa4d88971009a9c8e310354e581ba3 Mon Sep 17 00:00:00 2001 From: Gabriel Freitas Date: Mon, 21 Aug 2023 13:44:22 -0300 Subject: [PATCH 0499/1049] boards: arm: add toradex verdin imx8m plus board Add Verdin iMX8M Plus board with i.MX8MP SoC and ARM Cortex-M7 processor. Add two targets (DDR and ITCM) for the iMX8M Plus board. Port and documentation are based on NXP MIMX8MM EVK board. This code is intented to be used with the Cortex-M7. Signed-off-by: Gabriel Freitas --- boards/arm/verdin_imx8mp_m7/Kconfig.board | 9 + boards/arm/verdin_imx8mp_m7/Kconfig.defconfig | 18 ++ boards/arm/verdin_imx8mp_m7/board.cmake | 11 + boards/arm/verdin_imx8mp_m7/doc/index.rst | 290 ++++++++++++++++++ .../doc/verdin_imx8mp_front.jpg | Bin 0 -> 101622 bytes .../verdin_imx8mp_m7-pinctrl.dtsi | 28 ++ .../verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.dts | 46 +++ .../verdin_imx8mp_m7_ddr.yaml | 18 ++ .../verdin_imx8mp_m7_ddr_defconfig | 16 + .../verdin_imx8mp_m7_itcm.dts | 46 +++ .../verdin_imx8mp_m7_itcm.yaml | 18 ++ .../verdin_imx8mp_m7_itcm_defconfig | 16 + dts/arm/nxp/nxp_imx8ml_m7.dtsi | 12 +- 13 files changed, 522 insertions(+), 6 deletions(-) create mode 100644 boards/arm/verdin_imx8mp_m7/Kconfig.board create mode 100644 boards/arm/verdin_imx8mp_m7/Kconfig.defconfig create mode 100644 boards/arm/verdin_imx8mp_m7/board.cmake create mode 100644 boards/arm/verdin_imx8mp_m7/doc/index.rst create mode 100644 boards/arm/verdin_imx8mp_m7/doc/verdin_imx8mp_front.jpg create mode 100644 boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7-pinctrl.dtsi create mode 100644 boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.dts create mode 100644 boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.yaml create mode 100644 boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig create mode 100644 boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.dts create mode 100644 boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.yaml create mode 100644 boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig diff --git a/boards/arm/verdin_imx8mp_m7/Kconfig.board b/boards/arm/verdin_imx8mp_m7/Kconfig.board new file mode 100644 index 000000000000000..fb86601179c6675 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/Kconfig.board @@ -0,0 +1,9 @@ +# VERDIN_IMX8MP_M7 board + +# Copyright (c) 2023 Toradex +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_VERDIN_IMX8MP_M7 + bool "Toradex iMX8M Plus M7" + depends on SOC_SERIES_IMX8ML_M7 + select SOC_PART_NUMBER_MIMX8ML8DVNLZ diff --git a/boards/arm/verdin_imx8mp_m7/Kconfig.defconfig b/boards/arm/verdin_imx8mp_m7/Kconfig.defconfig new file mode 100644 index 000000000000000..3c3ab2db770b285 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/Kconfig.defconfig @@ -0,0 +1,18 @@ +# VERDIN_IMX8MP_M7 board defconfig + +# Copyright (c) 2023 Toradex +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_VERDIN_IMX8MP_M7 + +config BOARD + default "verdin_imx8mp_m7" + +if !XIP +config FLASH_SIZE + default 0 +config FLASH_BASE_ADDRESS + default 0 +endif + +endif # BOARD_VERDIN_IMX8MP_M7 diff --git a/boards/arm/verdin_imx8mp_m7/board.cmake b/boards/arm/verdin_imx8mp_m7/board.cmake new file mode 100644 index 000000000000000..546ba82f8a9c799 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/board.cmake @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023, Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_set_debugger_ifnset(jlink) +board_set_flasher_ifnset(jlink) + +board_runner_args(jlink "--device=MIMX8ML8_M7") +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/verdin_imx8mp_m7/doc/index.rst b/boards/arm/verdin_imx8mp_m7/doc/index.rst new file mode 100644 index 000000000000000..6a35534a99f0e69 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/doc/index.rst @@ -0,0 +1,290 @@ +.. _verdin_imx8mp_m7: + +Toradex Verdin iMX8M Plus SoM + +############################################ + +Overview +******** + +The Verdin iMX8M Plus is a Computer on Module (CoM) developed by Toradex. It is based on the NXP® i.MX 8M Plus family of +processors (or System on Chips - SoCs). + +The Verdin iMX8M Plus family consists of: + ++-------------------------------------------------+-----------------------+ +| CoM | SoC | ++=================================================+=======================+ +| Verdin iMX8M Plus Quad 8GB Wi-Fi / Bluetooth IT | i.MX 8M Plus Quad | ++-------------------------------------------------+-----------------------+ +| Verdin iMX8M Plus Quad 4GB Wi-Fi / Bluetooth IT | i.MX 8M Plus Quad | ++-------------------------------------------------+-----------------------+ +| Verdin iMX8M Plus Quad 4GB IT | i.MX 8M Plus Quad | ++-------------------------------------------------+-----------------------+ +| Verdin iMX8M Plus Quad 2GB Wi-Fi / Bluetooth IT | i.MX 8M Plus Quad | ++-------------------------------------------------+-----------------------+ +| Verdin iMX8M Plus QuadLite 1GB IT | i.MX 8M Plus QuadLite | ++-------------------------------------------------+-----------------------+ + +Quoting NXP + +:: + + The i.MX 8M Plus family focuses on machine learning and vision, advanced multimedia, and industrial automation with high reliability. + It is built to meet the needs of Smart Home, Building, City and Industry 4.0 applications. + +The Verdin iMX8M Plus integrates a total of 4 Arm Cortex™-A53 CPUs, operating at 1.6 GHz, alongside a single Arm Cortex™-M7F microcontroller operating at 800 MHz. + +.. image:: verdin_imx8mp_front.jpg + :align: center + :alt: Toradex Verdin iMX8M Plus (Credit: Toradex) + +Regarding the Cortex-A53 cluster, it employs the ARMv8-A architecture as a mid-range and energy-efficient processor. With four cores in this cluster, each core is +equipped with its own L1 memory system. Moreover, the cluster incorporates a unified L2 cache that offers supplementary functions. This cache is housed within a single APR region. +Facilitating debugging processes, the cores support both real-time trace through the ETM system and static debugging via JTAG. Furthermore, the platform features support for real-time trace +capabilities, achieved through ARM's CoreSight ETM modules, and also enables cross-triggering by utilizing CTI and CTM modules. + +The Arm® Cortex®-M7 microcontroller is indicated for Real-time control, combining high-performance with a minimal interrupt latency. +It stands out for its compatibility with existing Cortex-M profile processors. The microcontroller employs an efficient in-order super-scalar pipeline, +allowing dual-issued instructions such as load/load and load/store pairs, thanks to its multiple memory interfaces. These interfaces encompass Tightly-Coupled Memory (TCM), Harvard caches, and an AXI master interface. +The Arm Cortex-M7 Platform boasts features like a 32 KB L1 Instruction Cache, 32 KB L1 Data Cache, Floating Point Unit (FPU) with FPv5 architecture support, and an Internal Trace (TRC) mechanism. +Furthermore, the chip supports 160 IRQs, and integrates crucial Arm CoreSight components including ETM and CTI, dedicated to facilitating debug and trace functions. + +Hardware +******** + +- SoC name: NXP® i.MX 8M Plus +- CPU Type: 4x Arm Cortex™-A53 (1.6 GHz) +- Microcontroller: 1x Arm Cortex™-M7F (800 MHz) + +- Memory: + + - RAM -> A53: 1GB, 2GB, 4GB or 8GB + - RAM -> M7: 3x32KB (TCML, TCMU, OCRAM_S), 1x128KB (OCRAM) and 1x256MB (DDR) + - Flash -> A53: Up to 32GB eMMC + +- Connectivity: + + - USB 3.1: 1x Host / 1x OTG (Gen 1) + - USB 2.0: 1x Host / 1x OTG + - Ethernet Gigabit with TSN (+2nd RGMII) + - Wi-Fi Dual-band 802.11ac 2x2 MU-MIMO + - Bluetooth 5 + - 5x I2C + - 3x SPI + - 1 QSPI + - 4x UART + - Up to 92 GPIO + - 4x Analog Input + - 2x CAN (FlexCAN) + +- Multimedia: + + - Neural Processing Unit (NPU) + - Image Signal Processor (ISP) + - 2D and 3D acceleration + - HDMI, MIPI-DSI and MIPI-CSI interface + +For more information about the Verdin iMX8M Plus and the i.MX 8M Plus SoC refer to these links: + +- `i.MX 8M Plus Applications Processor page`_ +- `Verdin iMX8M Plus homepage`_ +- `Verdin iMX8M Plus developer page`_ +- `Verdin Development Board developer page`_ +- `Verdin iMX8M Plus Datasheet`_ +- `Verdin Development Board Datasheet`_ + +Supported Features +================== + +The Zephyr verdin_imx8mp_m7 board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | GPIO output | +| | | GPIO input | ++-----------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: + +- :zephyr_file:`boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig`, if you choose to use the ITCM memory. + +- :zephyr_file:`boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig`, if you choose to use the DDR memory. + +It is recommended to disable peripherals used by the M7 core on the Linux host. + +Other hardware features are not currently supported by the port. + +Connections and IOs +=================== + +UART: + +Zephyr is configured to use the UART4 by default, which is connected to the FTDI +USB converter on most Toradex carrier boards. + +This is also the UART connected to WiFi/BT chip in modules that have the WiFi/BT +chip. Therefore, if UART4 is used, WiFI/BT will not work properly. + +If the WiFi/BT is needed, then another UART should be used for Zephyr (UART1 for +example). You can change the UART by changing the ``zephyr,console`` and +``zephyr,shell-uart`` in the :zephyr_file:`boards/arm/verdin_imx8mp_m7_itcm.dts` or :zephyr_file:`boards/arm/verdin_imx8mp_m7_ddr.dts` file. + ++---------------+-----------------+---------------------------+ +| Board Name | SoC Name | Usage | ++===============+=================+===========================+ +| UART_1 | UART1 | General purpose UART | ++---------------+-----------------+---------------------------+ +| UART_4 | UART4 | Cortex-M4 debug UART | ++---------------+-----------------+---------------------------+ + +GPIO: + +All the GPIO banks available are enabled in the :zephyr_file:`dts/arm/nxp/nxp_imx8ml_m7.dtsi`. + +System Clock +============ + +The M7 Core is configured to run at a 800 MHz clock speed. + +Serial Port +=========== + +The i.MX8M Plus SoC has four UARTs. UART_4 is configured for the console and +the remaining are not used/tested. + +Programming and Debugging +************************* + +The Verdin iMX8M Plus board doesn't have QSPI flash for the M7, and it needs +to be started by the A53 core. The A53 core is responsible to load the M7 binary +application into the RAM, put the M7 in reset, set the M7 Program Counter and +Stack Pointer, and get the M7 out of reset. The A53 can perform these steps at +bootloader level or after the Linux system has booted. + +The M7 can use up to 3 different RAMs (currently, only two configurations are +supported: ITCM and DDR). These are the memory mapping for A53 and M7: + ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| Region | Cortex-A53 | Cortex-M7 (System Bus) | Cortex-M7 (Code Bus) | Size | ++============+=========================+========================+=======================+======================+ +| OCRAM | 0x00900000-0x0098FFFF | 0x20200000-0x2028FFFF | 0x00900000-0x0098FFFF | 576KB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| DTCM | 0x00800000-0x0081FFFF | 0x20000000-0x2001FFFF | | 128KB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| ITCM | 0x007E0000-0x007FFFFF | | 0x00000000-0x0001FFFF | 128KB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| OCRAM_S | 0x00180000-0x00188FFF | 0x20180000-0x20188FFF | 0x00180000-0x00188FFF | 36KB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| DDR | 0x80000000-0x803FFFFF | 0x80200000-0x803FFFFF | 0x80000000-0x801FFFFF | 2MB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ + +For more information about memory mapping see the +`i.MX 8M Plus Applications Processor Reference Manual`_ (section 2.1 to 2.3) + +At compilation time you have to choose which RAM will be used. To facilitate this process, there are two targets available: + +- verdin_imx8mp_m7_itcm, which uses the ITCM configuration. +- verdin_imx8mp_m7_ddr, which uses the DDR configuration. + + +Starting the Cortex-M7 via U-Boot +================================= + +Load and run Zephyr on M7 from A53 using u-boot by copying the compiled +``zephyr.bin`` to the first FAT partition of the SD card and plug the SD +card into the board. Power it up and stop the u-boot execution at prompt. + +Load the M7 binary onto the desired memory and start its execution using: + +ITCM +=== + +Loading the binary from an EXT4 partition: + +.. code-block:: console + + ext4load mmc 2:2 ${loadaddr} //zephyr.bin + cp.b ${loadaddr} 0x7e0000 + bootaux 0x7e0000 + +DDR +=== + +Loading the binary from an EXT4 partition: + +.. code-block:: console + + ext4load mmc 2:2 ${loadaddr} //zephyr.bin + cp.b ${loadaddr} 0x80000000 + bootaux 0x80000000 + +Debugging +========= + +Toradex Verdin iMX8M Plus SoM can be debugged by connecting an external JLink JTAG debugger to the X56 debug connector and to the PC, or simply connecting a USB-C to X66 on the Verdin Development Board. +Then, the application can be debugged using the usual way. + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: verdin_imx8mp_m7 + :goals: debug + +Open a serial terminal, step through the application in your debugger, and you +should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.4.0-2300-g03905f7e55d2 *** + Hello World! verdin_imx8mp_m7 + +References +========== + +- `How to Load Compiled Binaries into Cortex-M`_ +- `Cortex-M JTAG Debugging`_ +- `NXP website`_ + +.. _NXP website: + https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/evaluation-kit-for-the-i-mx-8m-plus-applications-processor:8MPLUSLPD4-EVK + +.. _i.MX 8M Plus Applications Processor Reference Manual: + https://www.nxp.com/webapp/Download?colCode=IMX8MPRM + +.. _How to Load Compiled Binaries into Cortex-M: + https://developer.toradex.com/software/real-time/cortex-m/how-to-load-binaries + +.. _Cortex-M JTAG Debugging: + https://developer.toradex.com/software/real-time/cortex-m/cortexm-jtag-debugging/ + +.. _i.MX 8M Plus Applications Processor page: + https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/i-mx-applications-processors/i-mx-8-applications-processors/i-mx-8m-plus-arm-cortex-a53-machine-learning-vision-multimedia-and-industrial-iot:IMX8MPLUS + +.. _Verdin iMX8M Plus homepage: + https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx-8m-plus + +.. _Verdin iMX8M Plus developer page: + https://developer.toradex.com/hardware/verdin-som-family/modules/verdin-imx8m-plus + +.. _Verdin Development Board developer page: + https://developer.toradex.com/hardware/verdin-som-family/carrier-boards/verdin-development-board/ + +.. _Verdin iMX8M Plus Datasheet: + https://docs.toradex.com/110977-verdin_imx8m_plus_v1.1_datasheet.pdf + +.. _Verdin Development Board Datasheet: + https://docs.toradex.com/109463-verdin_development_board_datasheet_v1.1.pdf diff --git a/boards/arm/verdin_imx8mp_m7/doc/verdin_imx8mp_front.jpg b/boards/arm/verdin_imx8mp_m7/doc/verdin_imx8mp_front.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e5089eace4b0e24e8ce74d154edfd7fc855928ff GIT binary patch literal 101622 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 z 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 + +&pinctrl { + uart1_default: uart1_default { + group0 { + drive-strength = "x1"; + pinmux = <&iomuxc_uart1_rxd_uart_rx_uart1_rx>, + <&iomuxc_uart1_txd_uart_tx_uart1_tx>; + slew-rate = "slow"; + }; + }; + + uart4_default: uart4_default { + group0 { + bias-pull-up; + drive-strength = "x1"; + pinmux = <&iomuxc_uart4_rxd_uart_rx_uart4_rx>, + <&iomuxc_uart4_txd_uart_tx_uart4_tx>; + slew-rate = "slow"; + }; + }; +}; diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.dts b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.dts new file mode 100644 index 000000000000000..861077246fd04d1 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.dts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Toradex + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "verdin_imx8mp_m7-pinctrl.dtsi" +#include + +/ { + model = "Toradex Verdin iMX8M Plus M7"; + compatible = "nxp,mimx8mp_evk"; + + chosen { + /* DDR */ + zephyr,flash = &ddr_code; + zephyr,sram = &ddr_sys; + + zephyr,console = &uart4; + zephyr,shell-uart = &uart4; + }; +}; + +&gpio3 { + status = "okay"; +}; + +&mailbox0 { + status = "okay"; +}; + +&uart1 { + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&uart4 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart4_default>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.yaml b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.yaml new file mode 100644 index 000000000000000..fc64d8c3db8859d --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2023 Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: verdin_imx8mp_m7_ddr +name: Toradex Verdin iMX8M Plus (DDR) +type: mcu +arch: arm +ram: 2048 +flash: 2048 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - uart diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig new file mode 100644 index 000000000000000..7c0d4073679355c --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig @@ -0,0 +1,16 @@ +# +# Copyright (c) 2023 Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_SERIES_IMX8ML_M7=y +CONFIG_SOC_MIMX8ML8=y +CONFIG_BOARD_VERDIN_IMX8MP_M7=y +CONFIG_CLOCK_CONTROL=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_XIP=y +CONFIG_CODE_DDR=y +CONFIG_PINCTRL=y diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.dts b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.dts new file mode 100644 index 000000000000000..5744928f8a7f9d6 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.dts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Toradex + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "verdin_imx8mp_m7-pinctrl.dtsi" +#include + +/ { + model = "Toradex Verdin iMX8M Plus M7"; + compatible = "nxp,mimx8mp_evk"; + + chosen { + /* TCM */ + zephyr,flash = &itcm; + zephyr,sram = &dtcm; + + zephyr,console = &uart4; + zephyr,shell-uart = &uart4; + }; +}; + +&gpio3 { + status = "okay"; +}; + +&mailbox0 { + status = "okay"; +}; + +&uart1 { + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&uart4 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart4_default>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.yaml b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.yaml new file mode 100644 index 000000000000000..8db4c170c5de939 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2023 Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: verdin_imx8mp_m7_itcm +name: Toradex Verdin iMX8M Plus (ITCM) +type: mcu +arch: arm +ram: 128 +flash: 128 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - uart diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig new file mode 100644 index 000000000000000..52c354abc1f95a9 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig @@ -0,0 +1,16 @@ +# +# Copyright (c) 2023 Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_SERIES_IMX8ML_M7=y +CONFIG_SOC_MIMX8ML8=y +CONFIG_BOARD_VERDIN_IMX8MP_M7=y +CONFIG_CLOCK_CONTROL=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_XIP=y +CONFIG_CODE_ITCM=y +CONFIG_PINCTRL=y diff --git a/dts/arm/nxp/nxp_imx8ml_m7.dtsi b/dts/arm/nxp/nxp_imx8ml_m7.dtsi index 41f22deb9914424..f9406fc7546db54 100644 --- a/dts/arm/nxp/nxp_imx8ml_m7.dtsi +++ b/dts/arm/nxp/nxp_imx8ml_m7.dtsi @@ -164,12 +164,12 @@ }; uart1: uart@30860000 { - compatible = "nxp,imx-iuart"; - reg = <0x30860000 0x10000>; - interrupts = <26 3>; - clocks = <&ccm IMX_CCM_UART1_CLK 0x7c 24>; - status = "disabled"; - }; + compatible = "nxp,imx-iuart"; + reg = <0x30860000 0x10000>; + interrupts = <26 3>; + clocks = <&ccm IMX_CCM_UART1_CLK 0x7c 24>; + status = "disabled"; + }; mailbox0: mailbox@30ab0000 { compatible = "nxp,imx-mu"; From 8246d14742501bdd1c857e0f8b90e8453941f5b0 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Thu, 28 Sep 2023 17:51:57 -0400 Subject: [PATCH 0500/1049] drivers: xmc4xxx: spi: Update buffers before transmitting data In the interrupt driven spi, spi_context_update_tx() is called once from the calling thread and then once in spi_xmc4xxx_isr() after each new byte is received. This actually means that there is one extra call to spi_context_update_tx(). This is fine if spi_context_update_tx() complete it's call in the calling thread before the interrupt fires, however, this cannot be guaranteed especially if the calling thread is pre-emptive and has a low priority. Fix this by calling spi_context_update_tx() in the calling thread before transmitting the first byte. Signed-off-by: Andriy Gelman --- drivers/spi/spi_xmc4xxx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_xmc4xxx.c b/drivers/spi/spi_xmc4xxx.c index 9c48fb050983335..d6aa60a527f290b 100644 --- a/drivers/spi/spi_xmc4xxx.c +++ b/drivers/spi/spi_xmc4xxx.c @@ -123,10 +123,10 @@ static void spi_xmc4xxx_shift_frames(const struct device *dev) XMC_SPI_CH_STATUS_FLAG_RECEIVE_INDICATION | XMC_SPI_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION); - XMC_SPI_CH_Transmit(config->spi, tx_data, XMC_SPI_CH_MODE_STANDARD); - spi_context_update_tx(ctx, 1, 1); + XMC_SPI_CH_Transmit(config->spi, tx_data, XMC_SPI_CH_MODE_STANDARD); + #if defined(CONFIG_SPI_XMC4XXX_INTERRUPT) return; #endif From a34d4d1ce9d96ddb2ed67686d5c30b8a0930734e Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Thu, 28 Sep 2023 18:55:51 -0400 Subject: [PATCH 0501/1049] drivers: spi: xmc4xxx: Fix potential runtime error Fixes an unhandled interrupt runtime crash if CONFIG_SPI_XMC4XXX_DMA=y and CONFIG_SPI_XMC4XXX_INTERRUPT=n. The unhandled interrupt error is triggered because irq_enable() was called without calling IRQ_CONNECT() when CONFIG_SPI_XMC4XXX_INTERRUPT=n. Signed-off-by: Andriy Gelman --- drivers/spi/spi_xmc4xxx.c | 2 ++ tests/drivers/spi/spi_loopback/boards/xmc45_relax_kit.conf | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_xmc4xxx.c b/drivers/spi/spi_xmc4xxx.c index d6aa60a527f290b..1706572bddb50e7 100644 --- a/drivers/spi/spi_xmc4xxx.c +++ b/drivers/spi/spi_xmc4xxx.c @@ -468,7 +468,9 @@ static int spi_xmc4xxx_transceive_dma(const struct device *dev, const struct spi spi_context_cs_control(ctx, false); } +#if defined(CONFIG_SPI_XMC4XXX_INTERRUPT) irq_enable(config->irq_num_rx); +#endif spi_context_release(ctx, ret); return ret; diff --git a/tests/drivers/spi/spi_loopback/boards/xmc45_relax_kit.conf b/tests/drivers/spi/spi_loopback/boards/xmc45_relax_kit.conf index d066213b5da9b21..3f96b399e0ed31c 100644 --- a/tests/drivers/spi/spi_loopback/boards/xmc45_relax_kit.conf +++ b/tests/drivers/spi/spi_loopback/boards/xmc45_relax_kit.conf @@ -1,3 +1,2 @@ -CONFIG_SPI_XMC4XXX_INTERRUPT=y CONFIG_SPI_XMC4XXX_DMA=y CONFIG_SPI_LOOPBACK_MODE_LOOP=y From 325e28218f22f932f49b26836b6cea5d95322125 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Thu, 28 Sep 2023 19:04:54 -0400 Subject: [PATCH 0502/1049] drivers: spi: xmc4xxx: Fix compiler warning with debug flags enabled Fixes warning when CONFIG_DEBUG_OPTIMIZATION=y: zephyrproject/modules/hal/infineon/XMCLib/drivers/inc/xmc_usic.h:2132:18: warning: 'clock_settings' may be used uninitialized [-Wmaybe-uninitialized] 2132 | (uint32_t)passive_level | | ^~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Andriy Gelman --- drivers/spi/spi_xmc4xxx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_xmc4xxx.c b/drivers/spi/spi_xmc4xxx.c index 1706572bddb50e7..97b32f20e049b58 100644 --- a/drivers/spi/spi_xmc4xxx.c +++ b/drivers/spi/spi_xmc4xxx.c @@ -195,7 +195,8 @@ static int spi_xmc4xxx_configure(const struct device *dev, const struct spi_conf bool CPOL = SPI_MODE_GET(settings) & SPI_MODE_CPOL; bool CPHA = SPI_MODE_GET(settings) & SPI_MODE_CPHA; XMC_SPI_CH_CONFIG_t usic_cfg = {.baudrate = spi_cfg->frequency}; - XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_t clock_settings; + XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_t clock_settings = + XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_0_DELAY_ENABLED; if (spi_context_configured(ctx, spi_cfg)) { return 0; From 415b6fc945fd3748d2c8c5191abbc484fe551cad Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 22 Sep 2023 09:08:17 +0200 Subject: [PATCH 0503/1049] drivers: watchdog: wdt_nrfx: Implement disable API nRF5340 SoC has `TASK_STOP` this patch implements disabling watchdog for that SoC. Changed body of `wdt_nrf_setup()` to utilize `nrfx_wdt_reconfigure()` driver API. Signed-off-by: Adam Wojasinski --- drivers/watchdog/wdt_nrfx.c | 41 +++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index 8d61f11d6fbe5ad..5d2e036a2136d6b 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -28,29 +28,32 @@ static int wdt_nrf_setup(const struct device *dev, uint8_t options) { const struct wdt_nrfx_config *config = dev->config; struct wdt_nrfx_data *data = dev->data; - uint32_t behaviour; + nrfx_err_t err_code; /* Activate all available options. Run in all cases. */ - behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK | NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; + config->config.behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK | +#if NRF_WDT_HAS_STOP + NRF_WDT_BEHAVIOUR_STOP_ENABLE_MASK | +#endif + NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; /* Deactivate running in sleep mode. */ if (options & WDT_OPT_PAUSE_IN_SLEEP) { - behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK; + config->config.behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK; } /* Deactivate running when debugger is attached. */ if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { - behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; + config->config.behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; } - nrf_wdt_behaviour_set(config->wdt.p_reg, behaviour); - /* The watchdog timer is driven by the LFCLK clock running at 32768 Hz. - * The timeout value given in milliseconds needs to be converted here - * to watchdog ticks.*/ - nrf_wdt_reload_value_set( - config->wdt.p_reg, - (uint32_t)(((uint64_t)data->m_timeout * 32768U) - / 1000)); + config->config.reload_value = data->m_timeout; + + err_code = nrfx_wdt_reconfigure(&config->wdt, &config->config); + + if (err_code != NRFX_SUCCESS) { + return -EBUSY; + } nrfx_wdt_enable(&config->wdt); @@ -59,9 +62,21 @@ static int wdt_nrf_setup(const struct device *dev, uint8_t options) static int wdt_nrf_disable(const struct device *dev) { - /* Started watchdog cannot be stopped on nRF devices. */ +#if NRFX_WDT_HAS_STOP + const struct wdt_nrfx_config *config = dev->config; + nrfx_err_t err_code; + + err_code = nrfx_wdt_stop(&config->wdt); + + if (err_code != NRFX_SUCCESS) { + return -ENOTSUP; + } + + return 0; +#else ARG_UNUSED(dev); return -EPERM; +#endif } static int wdt_nrf_install_timeout(const struct device *dev, From a13364112ee634af5ad4c1f185897740d54f0213 Mon Sep 17 00:00:00 2001 From: Xudong Zheng <7pkvm5aw@slicealias.com> Date: Tue, 31 Oct 2023 12:29:27 -0400 Subject: [PATCH 0504/1049] boards: arm: adafruit_feather_nrf52840: add voltage divider for battery This allows firmware to read the voltage for LiPoly battery. Schematic: https://learn.adafruit.com/introducing-the-adafruit-nrf52840-feather/downloads Signed-off-by: Xudong Zheng <7pkvm5aw@slicealias.com> --- .../adafruit_feather_nrf52840.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boards/arm/adafruit_feather_nrf52840/adafruit_feather_nrf52840.dts b/boards/arm/adafruit_feather_nrf52840/adafruit_feather_nrf52840.dts index 284a4d245424347..2333e5becbeda1b 100644 --- a/boards/arm/adafruit_feather_nrf52840/adafruit_feather_nrf52840.dts +++ b/boards/arm/adafruit_feather_nrf52840/adafruit_feather_nrf52840.dts @@ -47,6 +47,13 @@ }; }; + vbatt { + compatible = "voltage-divider"; + io-channels = <&adc 5>; + output-ohms = <100000>; + full-ohms = <(100000 + 100000)>; + }; + /* These aliases are provided for compatibility with samples */ aliases { led0 = &led0; From ea2185dd1cc83fe844cb5ea35720b91e0da064a5 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 7 Nov 2023 12:35:19 +0100 Subject: [PATCH 0505/1049] arm arch: Replace use of TOSTR with STRINGIFY One of the ARM architure files, defined since long ago TOSTR having the exact same purpose as Zephyr's STRINGIFY. Remove the use of this macro in the tree (only used in another ARM header file) in favour of STRINGIFY. Signed-off-by: Alberto Escolar Piedras --- include/zephyr/arch/arm/asm_inline_gcc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/zephyr/arch/arm/asm_inline_gcc.h b/include/zephyr/arch/arm/asm_inline_gcc.h index 61f8a9f088d49c2..3b8e8e19c92595e 100644 --- a/include/zephyr/arch/arm/asm_inline_gcc.h +++ b/include/zephyr/arch/arm/asm_inline_gcc.h @@ -18,6 +18,7 @@ #ifndef _ASMLANGUAGE +#include #include #include @@ -68,7 +69,7 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) || defined(CONFIG_ARMV7_A) __asm__ volatile( "mrs %0, cpsr;" - "and %0, #" TOSTR(I_BIT) ";" + "and %0, #" STRINGIFY(I_BIT) ";" "cpsid i;" : "=r" (key) : From e92021b7b581f4d43c23585da8796037d06ef94d Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 7 Nov 2023 12:38:10 +0100 Subject: [PATCH 0506/1049] arm arch: Remove definition of CONCAT and TOSTR One of the ARM architure files, defined since long ago CONCAT and TOSTR having the exact same purpose as Zephyr's _CONCAT & STRINGIFY. This arm header file is included thru dependencies into almost all code built for ARM, which leads to these macros being usable everywhere. This can easily make developers belive the macros are provided by Zephyr itself, and use them, leading to code which is not portable between architectures. Remove this macros definitions from the architecture headers. Signed-off-by: Alberto Escolar Piedras --- include/zephyr/arch/arm/irq.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/zephyr/arch/arm/irq.h b/include/zephyr/arch/arm/irq.h index e363b963803f157..357c91a83ae4c7e 100644 --- a/include/zephyr/arch/arm/irq.h +++ b/include/zephyr/arch/arm/irq.h @@ -75,14 +75,6 @@ extern void z_arm_int_exit(void); extern void z_arm_interrupt_init(void); -/* macros convert value of its argument to a string */ -#define DO_TOSTR(s) #s -#define TOSTR(s) DO_TOSTR(s) - -/* concatenate the values of the arguments into one */ -#define DO_CONCAT(x, y) x ## y -#define CONCAT(x, y) DO_CONCAT(x, y) - /* Flags for use with IRQ_CONNECT() */ /** * Set this interrupt up as a zero-latency IRQ. If CONFIG_ZERO_LATENCY_LEVELS From f9685cd347fc9a5f1a01f0cee23f96ab5bab95cc Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 7 Nov 2023 12:47:54 +0100 Subject: [PATCH 0507/1049] include: util: Add CONCAT as a general Zephyr utility macro Provide the CONCAT macro as a general Zephyr utility macro to paste two tokens during the preprocessor pass. Note that this macro is based on the _CONCAT macro defined in toolchain/common.h. This toolchain header needs a CONCAT like macro, but requires minimal include dependencies. So we leave _CONCAT where it is. Signed-off-by: Alberto Escolar Piedras --- include/zephyr/sys/util.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index b3cbb917b46e8b6..a812ee4d37eab2f 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -250,6 +250,15 @@ extern "C" { ((type *)(((char *)(ptr)) - offsetof(type, field))); \ }) +/** + * @brief Concatenate two tokens into one + * + * Concatenate two tokens, @p x and @p y, into a combined token during the preprocessor pass. + * This can be used to, for ex., build an identifier out of two parts, + * where one of those parts may be, for ex, a number, another macro, or a macro argument. + */ +#define CONCAT(x, y) _DO_CONCAT(x, y) + /** * @brief Value of @p x rounded up to the next multiple of @p align. */ From da35f117a44c03318bc183f174b05b4b09d1e02d Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 7 Nov 2023 08:55:19 +0700 Subject: [PATCH 0508/1049] dt-bindings: clock: update clock to RTD 1.0.0 Update clock sources Signed-off-by: Cong Nguyen Huu --- .../dt-bindings/clock/nxp_s32z2_clock.h | 201 +++++++++--------- 1 file changed, 102 insertions(+), 99 deletions(-) diff --git a/include/zephyr/dt-bindings/clock/nxp_s32z2_clock.h b/include/zephyr/dt-bindings/clock/nxp_s32z2_clock.h index 47eb060c5455972..6471a2c54069f19 100644 --- a/include/zephyr/dt-bindings/clock/nxp_s32z2_clock.h +++ b/include/zephyr/dt-bindings/clock/nxp_s32z2_clock.h @@ -39,7 +39,7 @@ #define NXP_S32_LFAST0_PLL_PH0_CLK 30U #define NXP_S32_LFAST1_PLL_PH0_CLK 31U #define NXP_S32_ETH_RGMII_REF_CLK 32U -#define NXP_S32_ETH_EXT_TS_CLK 33U +#define NXP_S32_TMR_1588_CLK 33U #define NXP_S32_ETH0_EXT_RX_CLK 34U #define NXP_S32_ETH0_EXT_TX_CLK 35U #define NXP_S32_ETH1_EXT_RX_CLK 36U @@ -188,110 +188,113 @@ #define NXP_S32_ETH0_RX_MII_CLK 180U #define NXP_S32_ETH0_RX_RGMII_CLK 181U #define NXP_S32_ETH0_TX_RGMII_CLK 182U -#define NXP_S32_ETH0_TX_RGMII_LPBK_CLK 183U +#define NXP_S32_ETH0_PS_TX_CLK 183U #define NXP_S32_ETH1_REF_RMII_CLK 184U #define NXP_S32_ETH1_RX_MII_CLK 185U #define NXP_S32_ETH1_RX_RGMII_CLK 186U #define NXP_S32_ETH1_TX_MII_CLK 187U #define NXP_S32_ETH1_TX_RGMII_CLK 188U -#define NXP_S32_ETH1_TX_RGMII_LPBK_CLK 189U +#define NXP_S32_ETH1_PS_TX_CLK 189U #define NXP_S32_P1_LFAST0_REF_CLK 190U #define NXP_S32_P1_LFAST1_REF_CLK 191U -#define NXP_S32_P1_LFAST_DFT_CLK 192U -#define NXP_S32_P1_NETC_AXI_CLK 193U -#define NXP_S32_P1_LIN_CLK 194U -#define NXP_S32_P1_REG_INTF_CLK 195U -#define NXP_S32_P2_DBG_ATB_CLK 196U -#define NXP_S32_P2_REG_INTF_CLK 197U -#define NXP_S32_P3_AES_CLK 198U -#define NXP_S32_P3_CLKOUT_SRC_CLK 199U -#define NXP_S32_P3_DBG_TS_CLK 200U -#define NXP_S32_P3_REG_INTF_CLK 201U -#define NXP_S32_P3_SYS_MON1_CLK 202U -#define NXP_S32_P3_SYS_MON2_CLK 203U -#define NXP_S32_P3_SYS_MON3_CLK 204U -#define NXP_S32_P4_CLKOUT_SRC_CLK 205U -#define NXP_S32_P4_DSPI60_CLK 206U -#define NXP_S32_P4_EMIOS_LCU_CLK 207U -#define NXP_S32_P4_LIN_CLK 208U -#define NXP_S32_P4_PSI5_125K_CLK 209U -#define NXP_S32_P4_PSI5_189K_CLK 210U -#define NXP_S32_P4_PSI5_S_BAUD_CLK 211U -#define NXP_S32_P4_PSI5_S_CORE_CLK 212U -#define NXP_S32_P4_PSI5_S_TRIG0_CLK 213U -#define NXP_S32_P4_PSI5_S_TRIG1_CLK 214U -#define NXP_S32_P4_PSI5_S_TRIG2_CLK 215U -#define NXP_S32_P4_PSI5_S_TRIG3_CLK 216U -#define NXP_S32_P4_PSI5_S_UART_CLK 217U -#define NXP_S32_P4_PSI5_S_WDOG0_CLK 218U -#define NXP_S32_P4_PSI5_S_WDOG1_CLK 219U -#define NXP_S32_P4_PSI5_S_WDOG2_CLK 220U -#define NXP_S32_P4_PSI5_S_WDOG3_CLK 221U -#define NXP_S32_P4_QSPI0_2X_CLK 222U -#define NXP_S32_P4_QSPI0_1X_CLK 223U -#define NXP_S32_P4_QSPI1_2X_CLK 224U -#define NXP_S32_P4_QSPI1_1X_CLK 225U -#define NXP_S32_P4_REG_INTF_2X_CLK 226U -#define NXP_S32_P4_REG_INTF_CLK 227U -#define NXP_S32_P4_SDHC_IP_CLK 228U -#define NXP_S32_P4_SDHC_IP_DIV2_CLK 229U -#define NXP_S32_P5_DIPORT_CLK 230U -#define NXP_S32_P5_AE_CLK 231U -#define NXP_S32_P5_CANXL_PE_CLK 232U -#define NXP_S32_P5_CANXL_CHI_CLK 233U -#define NXP_S32_P5_CLKOUT_SRC_CLK 234U -#define NXP_S32_P5_LIN_CLK 235U -#define NXP_S32_P5_REG_INTF_CLK 236U -#define NXP_S32_P6_REG_INTF_CLK 237U -#define NXP_S32_PIT0_CLK 238U -#define NXP_S32_PIT1_CLK 239U -#define NXP_S32_PIT4_CLK 240U -#define NXP_S32_PIT5_CLK 241U -#define NXP_S32_P0_PSI5_1US_CLK 242U -#define NXP_S32_PSI5_0_CLK 243U -#define NXP_S32_P4_PSI5_1US_CLK 244U -#define NXP_S32_PSI5_1_CLK 245U -#define NXP_S32_PSI5S_0_CLK 246U -#define NXP_S32_PSI5S_1_CLK 247U -#define NXP_S32_QSPI0_CLK 248U -#define NXP_S32_QSPI1_CLK 249U -#define NXP_S32_RTU0_CORE_MON1_CLK 250U -#define NXP_S32_RTU0_CORE_MON2_CLK 251U -#define NXP_S32_RTU0_CORE_DIV2_MON1_CLK 252U -#define NXP_S32_RTU0_CORE_DIV2_MON2_CLK 253U -#define NXP_S32_RTU0_CORE_DIV2_MON3_CLK 254U -#define NXP_S32_RTU0_REG_INTF_CLK 255U -#define NXP_S32_RTU1_CORE_MON1_CLK 256U -#define NXP_S32_RTU1_CORE_MON2_CLK 257U -#define NXP_S32_RTU1_CORE_DIV2_MON1_CLK 258U -#define NXP_S32_RTU1_CORE_DIV2_MON2_CLK 259U -#define NXP_S32_RTU1_CORE_DIV2_MON3_CLK 260U -#define NXP_S32_RTU1_REG_INTF_CLK 261U -#define NXP_S32_P4_SDHC_CLK 262U -#define NXP_S32_RXLUT_CLK 263U -#define NXP_S32_SDHC0_CLK 264U -#define NXP_S32_SINC_CLK 265U -#define NXP_S32_SIPI0_CLK 266U -#define NXP_S32_SIPI1_CLK 267U -#define NXP_S32_SIUL2_0_CLK 268U -#define NXP_S32_SIUL2_1_CLK 269U -#define NXP_S32_SIUL2_4_CLK 270U -#define NXP_S32_SIUL2_5_CLK 271U -#define NXP_S32_P0_DSPI_CLK 272U -#define NXP_S32_SPI0_CLK 273U -#define NXP_S32_SPI1_CLK 274U -#define NXP_S32_P1_DSPI_CLK 275U -#define NXP_S32_SPI2_CLK 276U -#define NXP_S32_SPI3_CLK 277U -#define NXP_S32_SPI4_CLK 278U -#define NXP_S32_P4_DSPI_CLK 279U -#define NXP_S32_SPI5_CLK 280U -#define NXP_S32_SPI6_CLK 281U -#define NXP_S32_SPI7_CLK 282U -#define NXP_S32_P5_DSPI_CLK 283U -#define NXP_S32_SPI8_CLK 284U -#define NXP_S32_SPI9_CLK 285U -#define NXP_S32_SRX0_CLK 286U -#define NXP_S32_SRX1_CLK 287U +#define NXP_S32_P1_NETC_AXI_CLK 192U +#define NXP_S32_P1_LIN_CLK 193U +#define NXP_S32_P1_REG_INTF_CLK 194U +#define NXP_S32_P2_DBG_ATB_CLK 195U +#define NXP_S32_P2_REG_INTF_CLK 196U +#define NXP_S32_P3_AES_CLK 197U +#define NXP_S32_P3_CLKOUT_SRC_CLK 198U +#define NXP_S32_P3_DBG_TS_CLK 199U +#define NXP_S32_P3_REG_INTF_CLK 200U +#define NXP_S32_P3_SYS_MON1_CLK 201U +#define NXP_S32_P3_SYS_MON2_CLK 202U +#define NXP_S32_P3_SYS_MON3_CLK 203U +#define NXP_S32_P4_CLKOUT_SRC_CLK 204U +#define NXP_S32_P4_DSPI60_CLK 205U +#define NXP_S32_P4_EMIOS_LCU_CLK 206U +#define NXP_S32_P4_LIN_CLK 207U +#define NXP_S32_P4_PSI5_125K_CLK 208U +#define NXP_S32_P4_PSI5_189K_CLK 209U +#define NXP_S32_P4_PSI5_S_BAUD_CLK 210U +#define NXP_S32_P4_PSI5_S_CORE_CLK 211U +#define NXP_S32_P4_PSI5_S_TRIG0_CLK 212U +#define NXP_S32_P4_PSI5_S_TRIG1_CLK 213U +#define NXP_S32_P4_PSI5_S_TRIG2_CLK 214U +#define NXP_S32_P4_PSI5_S_TRIG3_CLK 215U +#define NXP_S32_P4_PSI5_S_UART_CLK 216U +#define NXP_S32_P4_PSI5_S_WDOG0_CLK 217U +#define NXP_S32_P4_PSI5_S_WDOG1_CLK 218U +#define NXP_S32_P4_PSI5_S_WDOG2_CLK 219U +#define NXP_S32_P4_PSI5_S_WDOG3_CLK 220U +#define NXP_S32_P4_QSPI0_2X_CLK 221U +#define NXP_S32_P4_QSPI0_1X_CLK 222U +#define NXP_S32_P4_QSPI1_2X_CLK 223U +#define NXP_S32_P4_QSPI1_1X_CLK 224U +#define NXP_S32_P4_REG_INTF_2X_CLK 225U +#define NXP_S32_P4_REG_INTF_CLK 226U +#define NXP_S32_P4_SDHC_IP_CLK 227U +#define NXP_S32_P4_SDHC_IP_DIV2_CLK 228U +#define NXP_S32_P5_DIPORT_CLK 229U +#define NXP_S32_P5_AE_CLK 230U +#define NXP_S32_P5_CANXL_PE_CLK 231U +#define NXP_S32_P5_CANXL_CHI_CLK 232U +#define NXP_S32_P5_CLKOUT_SRC_CLK 233U +#define NXP_S32_P5_LIN_CLK 234U +#define NXP_S32_P5_REG_INTF_CLK 235U +#define NXP_S32_P6_REG_INTF_CLK 236U +#define NXP_S32_PIT0_CLK 237U +#define NXP_S32_PIT1_CLK 238U +#define NXP_S32_PIT4_CLK 239U +#define NXP_S32_PIT5_CLK 240U +#define NXP_S32_P0_PSI5_1US_CLK 241U +#define NXP_S32_PSI5_0_CLK 242U +#define NXP_S32_P4_PSI5_1US_CLK 243U +#define NXP_S32_PSI5_1_CLK 244U +#define NXP_S32_PSI5S_0_CLK 245U +#define NXP_S32_PSI5S_1_CLK 246U +#define NXP_S32_QSPI0_CLK 247U +#define NXP_S32_QSPI1_CLK 248U +#define NXP_S32_RTU0_CORE_MON1_CLK 249U +#define NXP_S32_RTU0_CORE_MON2_CLK 250U +#define NXP_S32_RTU0_CORE_DIV2_MON1_CLK 251U +#define NXP_S32_RTU0_CORE_DIV2_MON2_CLK 252U +#define NXP_S32_RTU0_CORE_DIV2_MON3_CLK 253U +#define NXP_S32_RTU0_REG_INTF_CLK 254U +#define NXP_S32_RTU1_CORE_MON1_CLK 255U +#define NXP_S32_RTU1_CORE_MON2_CLK 256U +#define NXP_S32_RTU1_CORE_DIV2_MON1_CLK 257U +#define NXP_S32_RTU1_CORE_DIV2_MON2_CLK 258U +#define NXP_S32_RTU1_CORE_DIV2_MON3_CLK 259U +#define NXP_S32_RTU1_REG_INTF_CLK 260U +#define NXP_S32_P4_SDHC_CLK 261U +#define NXP_S32_RXLUT_CLK 262U +#define NXP_S32_SDHC0_CLK 263U +#define NXP_S32_SINC_CLK 264U +#define NXP_S32_SIPI0_CLK 265U +#define NXP_S32_SIPI1_CLK 266U +#define NXP_S32_SIUL2_0_CLK 267U +#define NXP_S32_SIUL2_1_CLK 268U +#define NXP_S32_SIUL2_4_CLK 269U +#define NXP_S32_SIUL2_5_CLK 270U +#define NXP_S32_P0_DSPI_CLK 271U +#define NXP_S32_SPI0_CLK 272U +#define NXP_S32_SPI1_CLK 273U +#define NXP_S32_P1_DSPI_CLK 274U +#define NXP_S32_SPI2_CLK 275U +#define NXP_S32_SPI3_CLK 276U +#define NXP_S32_SPI4_CLK 277U +#define NXP_S32_P4_DSPI_CLK 278U +#define NXP_S32_SPI5_CLK 279U +#define NXP_S32_SPI6_CLK 280U +#define NXP_S32_SPI7_CLK 281U +#define NXP_S32_P5_DSPI_CLK 282U +#define NXP_S32_SPI8_CLK 283U +#define NXP_S32_SPI9_CLK 284U +#define NXP_S32_SRX0_CLK 285U +#define NXP_S32_SRX1_CLK 286U +#define NXP_S32_CORE_PLL_REFCLKOUT 287U +#define NXP_S32_CORE_PLL_FBCLKOUT 288U +#define NXP_S32_PERIPH_PLL_REFCLKOUT 289U +#define NXP_S32_PERIPH_PLL_FBCLKOUT 290U #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_S32Z2_CLOCK_H_ */ From 2a932ccab163ca5a249a3bdbf14533d69afe9790 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 7 Nov 2023 08:57:31 +0700 Subject: [PATCH 0509/1049] drivers: uart_nxp_s32_linflexed: update to RTD 1.0.0 Set default configuration BaudRateDivisor = 16U. Signed-off-by: Cong Nguyen Huu --- drivers/serial/uart_nxp_s32_linflexd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/serial/uart_nxp_s32_linflexd.c b/drivers/serial/uart_nxp_s32_linflexd.c index 9a8d8fe3790c310..4fa6badb7963363 100644 --- a/drivers/serial/uart_nxp_s32_linflexd.c +++ b/drivers/serial/uart_nxp_s32_linflexd.c @@ -347,6 +347,7 @@ static const struct uart_driver_api uart_nxp_s32_driver_api = { { \ .BaudRate = 115200, \ .BaudRateMantissa = 26U, \ + .BaudRateDivisor = 16U, \ .BaudRateFractionalDivisor = 1U, \ .ParityCheck = false, \ .ParityType = LINFLEXD_UART_IP_PARITY_EVEN, \ From e02c27aeb836fab20bf1a817fc53ed552f834cca Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 7 Nov 2023 09:13:03 +0700 Subject: [PATCH 0510/1049] drivers: counter_nxp_s32_sys_timer: update to RTD 1.0.0 Rename function Stm_Ip_GetInterruptFlag to Stm_Ip_GetInterruptStatusFlag. Signed-off-by: Cong Nguyen Huu --- drivers/counter/counter_nxp_s32_sys_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/counter_nxp_s32_sys_timer.c b/drivers/counter/counter_nxp_s32_sys_timer.c index b6c7f8a1d96fdf2..47c1d0e3c3eeae7 100644 --- a/drivers/counter/counter_nxp_s32_sys_timer.c +++ b/drivers/counter/counter_nxp_s32_sys_timer.c @@ -116,7 +116,7 @@ static uint32_t nxp_s32_sys_timer_get_pending_int(const struct device *dev) uint8_t i; for (i = 0; i < counter_get_num_of_channels(dev); i++) { - flags = Stm_Ip_GetInterruptFlag(config->instance, i); + flags = Stm_Ip_GetInterruptStatusFlag(config->instance, i); if (flags) { break; } From 5095d9d9e796a9ec5548060c1d1e9b7ef7d44f54 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 7 Nov 2023 09:18:47 +0700 Subject: [PATCH 0511/1049] drivers: mbox_nxp_s32_mru: update to RTD 1.0.0 Update NOTIFYAdd configuration Signed-off-by: Cong Nguyen Huu --- drivers/mbox/mbox_nxp_s32_mru.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mbox/mbox_nxp_s32_mru.c b/drivers/mbox/mbox_nxp_s32_mru.c index 8981e260d503162..2c6246d8dce37a6 100644 --- a/drivers/mbox/mbox_nxp_s32_mru.c +++ b/drivers/mbox/mbox_nxp_s32_mru.c @@ -283,8 +283,8 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { .ChannelCfg = COND_CODE_0(MRU_RX_CHANNELS(n), \ (NULL), (nxp_s32_mru_##n##_ch_cfg)), \ .NOTIFYAdd = { \ - &MRU_BASE(n)->NOTIFY0, \ - &MRU_BASE(n)->NOTIFY1 \ + &MRU_BASE(n)->NOTIFY[0], \ + &MRU_BASE(n)->NOTIFY[1] \ }, \ }, \ .irq_group = MRU_INT_GROUP(DT_INST_IRQN(n)), \ From 8dcd61e36e2fe0eaa38b197e614f5267c8d260b8 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Thu, 9 Nov 2023 15:16:03 +0700 Subject: [PATCH 0512/1049] soc: nxp_s32: pinctrl: update to RTD 1.0.0 Add alias "FEATURE_SIUL2_MAX_NUMBER_OF_INPUT" for compatibility with with previous RTD versions. Signed-off-by: Cong Nguyen Huu --- soc/arm/nxp_s32/common/pinctrl_soc.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/soc/arm/nxp_s32/common/pinctrl_soc.h b/soc/arm/nxp_s32/common/pinctrl_soc.h index 46c1c77bfd1c80e..60c609497aa0853 100644 --- a/soc/arm/nxp_s32/common/pinctrl_soc.h +++ b/soc/arm/nxp_s32/common/pinctrl_soc.h @@ -19,6 +19,11 @@ /** @brief Type for NXP S32 pin configuration. */ typedef Siul2_Port_Ip_PinSettingsConfig pinctrl_soc_pin_t; +/* Alias for compatibility with previous RTD versions */ +#if !defined(FEATURE_SIUL2_MAX_NUMBER_OF_INPUT) && defined(FEATURE_SIUL2_MAX_NUMBER_OF_INPUT_U8) +#define FEATURE_SIUL2_MAX_NUMBER_OF_INPUT FEATURE_SIUL2_MAX_NUMBER_OF_INPUT_U8 +#endif + #if defined(SIUL2_PORT_IP_MULTIPLE_SIUL2_INSTANCES) #define NXP_S32_SIUL2_IDX(n) \ n == 0 ? IP_SIUL2_0 : (n == 1 ? IP_SIUL2_1 : ( \ From e59991abfe0da173eac3c5266ab9c74e612d5379 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Thu, 9 Nov 2023 14:10:31 +0700 Subject: [PATCH 0513/1049] drivers: spi_nxp_s32: update StateIndex configuration Set Spi StateIndex equal to index of DT Spi node. Because number of State array is set base on number of DT Spi node used. If StateIndex is set equal to Spi instance, StateIndex can be over array. Signed-off-by: Cong Nguyen Huu --- drivers/spi/spi_nxp_s32.c | 2 +- west.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_nxp_s32.c b/drivers/spi/spi_nxp_s32.c index 5acfa1c68a8769d..ae2384079674776 100644 --- a/drivers/spi/spi_nxp_s32.c +++ b/drivers/spi/spi_nxp_s32.c @@ -671,7 +671,7 @@ static const struct spi_driver_api spi_nxp_s32_driver_api = { SPI_MCR_PCSIS(BIT_MASK(SPI_NXP_S32_NUM_CS(n))) | \ SPI_MCR_MDIS(0U) | SPI_MCR_XSPI(1U) | SPI_MCR_HALT(1U)), \ .TransferMode = SPI_IP_POLLING, \ - .StateIndex = SPI_NXP_S32_HW_INSTANCE(n), \ + .StateIndex = n, \ SPI_NXP_S32_SET_SLAVE(n) \ } diff --git a/west.yml b/west.yml index 59ee67c81f69c57..3e7d49affecf14a 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 03bd989de4d2de151470e8b6068bc5686f3fc84c + revision: 69046233b7a7fac3138ae4dd5bcf6158e82529bb path: modules/hal/nxp groups: - hal From 85fb2873e4e20594e9955aaf09a54bda2a97787a Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Mon, 13 Nov 2023 14:23:48 -0800 Subject: [PATCH 0514/1049] logging: log_core: support CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD value of 1 Previous implementation didn't work if CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD was set to 1. Minmimum value that worked was 2. A value of 1 would just be ignored and act like 0 with threshold triggerring disabled. Signed-off-by: Mike J. Chen --- subsys/logging/log_core.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/subsys/logging/log_core.c b/subsys/logging/log_core.c index 8f5e33e1e1ebaee..de96cfe2fb3a766 100644 --- a/subsys/logging/log_core.c +++ b/subsys/logging/log_core.c @@ -163,19 +163,30 @@ static void z_log_msg_post_finalize(void) k_spin_unlock(&process_lock, key); } else if (proc_tid != NULL) { - if (cnt == 0) { - k_timer_start(&log_process_thread_timer, - K_MSEC(CONFIG_LOG_PROCESS_THREAD_SLEEP_MS), - K_NO_WAIT); - } else if (CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD && - (cnt + 1) == CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD) { - k_timer_stop(&log_process_thread_timer); - k_sem_give(&log_process_thread_sem); + /* + * If CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD == 1, + * timer is never needed. We release the processing + * thread after every message is posted. + */ + if (CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD == 1) { + if (cnt == 0) { + k_sem_give(&log_process_thread_sem); + } } else { - /* No action needed. Message processing will be triggered by the - * timeout or when number of upcoming messages exceeds the - * threshold. - */ + if (cnt == 0) { + k_timer_start(&log_process_thread_timer, + K_MSEC(CONFIG_LOG_PROCESS_THREAD_SLEEP_MS), + K_NO_WAIT); + } else if (CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD && + (cnt + 1) == CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD) { + k_timer_stop(&log_process_thread_timer); + k_sem_give(&log_process_thread_sem); + } else { + /* No action needed. Message processing will be triggered by the + * timeout or when number of upcoming messages exceeds the + * threshold. + */ + } } } } From c9da68290aecee508bd0c5b5f07e99d8ba9bbe79 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 14 Nov 2023 12:00:43 +0100 Subject: [PATCH 0515/1049] modules: canopennode: use zephyr/dsp/types.h for float32_t/float64_t Include the zephyr/dsp/types.h header for float32_t/float64_t type definitions to avoid conflicts with other subsystems including this header. Add compile-time asserts to ensure the typedefs meet the requirements of the CANopenNode module. Fixes: #63896 Signed-off-by: Henrik Brix Andersen --- modules/canopennode/CO_driver_target.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/canopennode/CO_driver_target.h b/modules/canopennode/CO_driver_target.h index 3e76b5290b02c75..27b1f1caa9d6a99 100644 --- a/modules/canopennode/CO_driver_target.h +++ b/modules/canopennode/CO_driver_target.h @@ -22,6 +22,7 @@ extern "C" { #include #include #include +#include /* float32_t, float64_t */ /* Use static variables instead of calloc() */ #define CO_USE_GLOBALS @@ -46,12 +47,13 @@ extern "C" { #endif typedef bool bool_t; -typedef float float32_t; -typedef long double float64_t; typedef char char_t; typedef unsigned char oChar_t; typedef unsigned char domain_t; +BUILD_ASSERT(sizeof(float32_t) >= 4); +BUILD_ASSERT(sizeof(float64_t) >= 8); + typedef struct canopen_rx_msg { uint8_t data[8]; uint16_t ident; From afe1ca6847851f24cd72c7efc60730726ab4b684 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 14 Nov 2023 13:21:02 +0100 Subject: [PATCH 0516/1049] linker: allow tagging variables with __nocache_noinit Allow tagging variables with __nocach_noinit. With CONFIG_NOCACHE_MEMORY=y, this will resolve to __nocache, which implies __noinit. With CONFIG_NOCACHE_MEMORY=n, this simply resolves to __noinit. Signed-off-by: Henrik Brix Andersen --- include/zephyr/linker/section_tags.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/zephyr/linker/section_tags.h b/include/zephyr/linker/section_tags.h index d0ef2ecf1266106..5678a07325bc6b7 100644 --- a/include/zephyr/linker/section_tags.h +++ b/include/zephyr/linker/section_tags.h @@ -49,8 +49,10 @@ #if defined(CONFIG_NOCACHE_MEMORY) #define __nocache __in_section_unique(_NOCACHE_SECTION_NAME) +#define __nocache_noinit __nocache #else #define __nocache +#define __nocache_noinit __noinit #endif /* CONFIG_NOCACHE_MEMORY */ #if defined(CONFIG_KERNEL_COHERENCE) From 58e1963c6b7a7d6966244be9b89fb099aa6d66d7 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 14 Nov 2023 13:23:13 +0100 Subject: [PATCH 0517/1049] drivers: can: mcan: use __nocache_noinit for MRAM data variables Use __nocache_noinit for the Bosch M_CAN MRAM data variables on SoCs without dedicated MRAM. Fixes: #64691 Signed-off-by: Henrik Brix Andersen --- include/zephyr/drivers/can/can_mcan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/drivers/can/can_mcan.h b/include/zephyr/drivers/can/can_mcan.h index 6cc632fb13e3da6..b29adc857f7f295 100644 --- a/include/zephyr/drivers/can/can_mcan.h +++ b/include/zephyr/drivers/can/can_mcan.h @@ -640,7 +640,7 @@ enum can_mcan_psr_lec { */ #define CAN_MCAN_DT_MRAM_DEFINE(node_id, _name) \ BUILD_ASSERT(CAN_MCAN_DT_MRAM_OFFSET(node_id) == 0, "offset must be 0"); \ - static char __noinit __nocache __aligned(4) _name[CAN_MCAN_DT_MRAM_ELEMENTS_SIZE(node_id)]; + static char __nocache_noinit __aligned(4) _name[CAN_MCAN_DT_MRAM_ELEMENTS_SIZE(node_id)]; /** * @brief Assert that the Message RAM configuration meets the Bosch M_CAN IP core restrictions From d10e0e524735a7875b1129dde7bb472bd582f831 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 14 Nov 2023 16:59:01 +0200 Subject: [PATCH 0518/1049] MAINTAINERS: Fixes to Networking Buffers section Add a missing c-file (buf_simple.c) and use a dedicated label for Networking Buffers. Also add explicit excludes of the same files to the Networking section. Without the dedicated label it seems that the wrong maintainer gets set as assignee for pull requests. Signed-off-by: Johan Hedberg --- MAINTAINERS.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index b65679cb6a1bb94..7562f3587c7a1b5 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2032,10 +2032,12 @@ Networking: - include/zephyr/net/gptp.h - include/zephyr/net/ieee802154*.h - include/zephyr/net/wifi*.h + - include/zephyr/net/buf.h - samples/net/gptp/ - samples/net/sockets/coap_*/ - samples/net/lwm2m_client/ - samples/net/wifi/ + - subsys/net/buf*.c - subsys/net/l2/ethernet/gptp/ - subsys/net/l2/ieee802154/ - subsys/net/l2/wifi/ @@ -2070,10 +2072,10 @@ Networking: - jukkar files: - include/zephyr/net/buf.h - - subsys/net/buf.c + - subsys/net/buf*.c - tests/net/buf/ labels: - - "area: Networking" + - "area: Networking Buffers" "Networking: Connection Manager": status: maintained From 8c745831256aea8d3cdc2973b27833a4f7f291c3 Mon Sep 17 00:00:00 2001 From: David Brown Date: Tue, 14 Nov 2023 08:14:43 -0700 Subject: [PATCH 0519/1049] boards: stm32h747i_disco: Add Segger JLink support Add configuration lines to be able to use the jlink debugger with this board. The disco board leaves the debug lines tri-stated until connecting to stlink, so it is safe to just plug in the jlink and use it. Signed-off-by: David Brown --- boards/arm/stm32h747i_disco/board.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/arm/stm32h747i_disco/board.cmake b/boards/arm/stm32h747i_disco/board.cmake index b0b8e82485875c9..ac0e473e57d15d0 100644 --- a/boards/arm/stm32h747i_disco/board.cmake +++ b/boards/arm/stm32h747i_disco/board.cmake @@ -1,11 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 if(CONFIG_BOARD_STM32H747I_DISCO_M7) +board_runner_args(jlink "--device=STM32H747ZI_M7") board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_stm32h747i_disco_m7.cfg") board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) elseif(CONFIG_BOARD_STM32H747I_DISCO_M4) +board_runner_args(jlink "--device=STM32H747ZI_M4") board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_stm32h747i_disco_m4.cfg") board_runner_args(openocd --target-handle=_CHIPNAME.cpu1) endif() include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) From 16629cbabd66134bc3fe3a835599a3587ad1772e Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Tue, 14 Nov 2023 12:09:29 -0300 Subject: [PATCH 0520/1049] tests: coredump: Remove matching pattern On xtensa architectures the string "ZEPHYR FATAL ERROR" comes after the coredump itself. The ordered regex will incorrectly fail for this arch. Signed-off-by: Lucas Tamborrino --- tests/subsys/debug/coredump/testcase.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/subsys/debug/coredump/testcase.yaml b/tests/subsys/debug/coredump/testcase.yaml index 5b7dde692b1cd90..0f9e2ecead21e89 100644 --- a/tests/subsys/debug/coredump/testcase.yaml +++ b/tests/subsys/debug/coredump/testcase.yaml @@ -14,7 +14,6 @@ tests: type: multi_line regex: - "Coredump: (.*)" - - ">>> ZEPHYR FATAL ERROR " - "E: #CD:BEGIN#" - "E: #CD:5([aA])45([0-9a-fA-F]+)" - "E: #CD:41([0-9a-fA-F]+)" From a089fa241f6e93ed0aa14271b5d4aecb2185cdf4 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 14 Nov 2023 17:11:17 +0000 Subject: [PATCH 0521/1049] input: npcx: drop the input_ prefix from the internal functions Drop the input_ prefix fromthe internal functions. Trying to unify the input drivers to use the same style for function naming, this makes it a bit more compact and makes it easier to distinguish the common keyboard structures and functions from the driver ones. Signed-off-by: Fabio Baltieri --- drivers/input/input_npcx_kbd.c | 54 +++++++++++++++++----------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index 1de14726a6d2a0f..e703bd65f3ffeaa 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -24,7 +24,7 @@ LOG_MODULE_REGISTER(input_npcx_kbd); #define ROW_SIZE DT_INST_PROP(0, row_size) /* Driver config */ -struct input_npcx_kbd_config { +struct npcx_kbd_config { struct input_kbd_matrix_common_config common; /* Keyboard scan controller base address */ struct kbs_reg *base; @@ -40,24 +40,24 @@ struct input_npcx_kbd_config { struct npcx_wui wui_maps[]; }; -struct input_npcx_kbd_data { +struct npcx_kbd_data { struct input_kbd_matrix_common_data common; struct miwu_callback ksi_callback[ROW_SIZE]; }; -INPUT_KBD_STRUCT_CHECK(struct input_npcx_kbd_config, struct input_npcx_kbd_data); +INPUT_KBD_STRUCT_CHECK(struct npcx_kbd_config, struct npcx_kbd_data); /* Keyboard scan local functions */ -static void input_npcx_kbd_ksi_isr(const struct device *dev, struct npcx_wui *wui) +static void npcx_kbd_ksi_isr(const struct device *dev, struct npcx_wui *wui) { ARG_UNUSED(wui); input_kbd_matrix_poll_start(dev); } -static void input_npcx_kbd_set_detect_mode(const struct device *dev, bool enabled) +static void npcx_kbd_set_detect_mode(const struct device *dev, bool enabled) { - const struct input_npcx_kbd_config *const config = dev->config; + const struct npcx_kbd_config *const config = dev->config; if (enabled) { irq_enable(config->irq); @@ -66,9 +66,9 @@ static void input_npcx_kbd_set_detect_mode(const struct device *dev, bool enable } } -static void input_npcx_kbd_drive_column(const struct device *dev, int col) +static void npcx_kbd_drive_column(const struct device *dev, int col) { - const struct input_npcx_kbd_config *config = dev->config; + const struct npcx_kbd_config *config = dev->config; const struct input_kbd_matrix_common_config *common = &config->common; struct kbs_reg *const inst = config->base; uint32_t mask; @@ -98,9 +98,9 @@ static void input_npcx_kbd_drive_column(const struct device *dev, int col) inst->KBSOUT1 = ((mask >> 16) & 0x03); } -static int input_npcx_kbd_read_row(const struct device *dev) +static int npcx_kbd_read_row(const struct device *dev) { - const struct input_npcx_kbd_config *config = dev->config; + const struct npcx_kbd_config *config = dev->config; const struct input_kbd_matrix_common_config *common = &config->common; struct kbs_reg *const inst = config->base; int val; @@ -113,10 +113,10 @@ static int input_npcx_kbd_read_row(const struct device *dev) return val; } -static void input_npcx_kbd_init_ksi_wui_callback(const struct device *dev, - struct miwu_callback *callback, - const struct npcx_wui *wui, - miwu_dev_callback_handler_t handler) +static void npcx_kbd_init_ksi_wui_callback(const struct device *dev, + struct miwu_callback *callback, + const struct npcx_wui *wui, + miwu_dev_callback_handler_t handler) { /* KSI signal which has no wake-up input source */ if (wui->table == NPCX_MIWU_TABLE_NONE) { @@ -132,12 +132,12 @@ static void input_npcx_kbd_init_ksi_wui_callback(const struct device *dev, npcx_miwu_irq_enable(wui); } -static int input_npcx_kbd_init(const struct device *dev) +static int npcx_kbd_init(const struct device *dev) { const struct device *clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); - const struct input_npcx_kbd_config *const config = dev->config; + const struct npcx_kbd_config *const config = dev->config; const struct input_kbd_matrix_common_config *common = &config->common; - struct input_npcx_kbd_data *const data = dev->data; + struct npcx_kbd_data *const data = dev->data; struct kbs_reg *const inst = config->base; int ret; @@ -176,7 +176,7 @@ static int input_npcx_kbd_init(const struct device *dev) } /* Drive all column lines to low for detection any key press */ - input_npcx_kbd_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); + npcx_kbd_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); if (common->row_size != ROW_SIZE) { LOG_ERR("Unexpected ROW_SIZE: %d != %d", common->row_size, ROW_SIZE); @@ -185,9 +185,9 @@ static int input_npcx_kbd_init(const struct device *dev) /* Configure wake-up input and callback for keyboard input signal */ for (int i = 0; i < common->row_size; i++) { - input_npcx_kbd_init_ksi_wui_callback( + npcx_kbd_init_ksi_wui_callback( dev, &data->ksi_callback[i], &config->wui_maps[i], - input_npcx_kbd_ksi_isr); + npcx_kbd_ksi_isr); } /* Configure pin-mux for keyboard scan device */ @@ -205,12 +205,12 @@ PINCTRL_DT_INST_DEFINE(0); INPUT_KBD_MATRIX_DT_INST_DEFINE(0); static const struct input_kbd_matrix_api npcx_kbd_api = { - .drive_column = input_npcx_kbd_drive_column, - .read_row = input_npcx_kbd_read_row, - .set_detect_mode = input_npcx_kbd_set_detect_mode, + .drive_column = npcx_kbd_drive_column, + .read_row = npcx_kbd_read_row, + .set_detect_mode = npcx_kbd_set_detect_mode, }; -static const struct input_npcx_kbd_config npcx_kbd_cfg = { +static const struct npcx_kbd_config npcx_kbd_cfg_0 = { .common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(0, &npcx_kbd_api), .base = (struct kbs_reg *)DT_INST_REG_ADDR(0), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), @@ -220,10 +220,10 @@ static const struct input_npcx_kbd_config npcx_kbd_cfg = { .wui_maps = NPCX_DT_WUI_ITEMS_LIST(0), }; -static struct input_npcx_kbd_data npcx_kbd_data; +static struct npcx_kbd_data npcx_kbd_data_0; -DEVICE_DT_INST_DEFINE(0, input_npcx_kbd_init, NULL, - &npcx_kbd_data, &npcx_kbd_cfg, +DEVICE_DT_INST_DEFINE(0, npcx_kbd_init, NULL, + &npcx_kbd_data_0, &npcx_kbd_cfg_0, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, From 1af78e04810f2fcbfd3b29cd23d4d7acc2910f1b Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 14 Nov 2023 13:29:01 +0200 Subject: [PATCH 0522/1049] boards: up_squared_pro_7000: Update documentation Add chapter describing serial console connection and cleanup. Signed-off-by: Andrei Emeltchenko --- .../x86/intel_adl/doc/up_squared_pro_7000.rst | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/boards/x86/intel_adl/doc/up_squared_pro_7000.rst b/boards/x86/intel_adl/doc/up_squared_pro_7000.rst index 8f322080d96ede7..762340e10495a83 100644 --- a/boards/x86/intel_adl/doc/up_squared_pro_7000.rst +++ b/boards/x86/intel_adl/doc/up_squared_pro_7000.rst @@ -2,8 +2,8 @@ .. _up_squared_pro_7000_board: -UP SQUARED PRO 7000 board -######################### +UP Squared Pro 7000 +################### Overview ******** @@ -20,16 +20,17 @@ This board configuration enables kernel support for the UP Squared Pro 7000 boar Hardware ******** -General information about the board can be found at the `UP_SQUARED_PRO_7000`_ website. +General information about the board can be found at the `UP Squared Pro 7000`_ website. Connections and IOs =================== -Refer to the `UP_SQUARED_PRO_7000`_ website for more information. +Refer to the `UP Squared Pro 7000`_ website for more information. Programming and Debugging ************************* -Use the following procedures for booting an image for an UP SQUARED PRO 7000 board. + +Use the following procedures for booting an image for an UP Squared Pro 7000 board. .. contents:: :depth: 1 @@ -40,7 +41,7 @@ Build Zephyr application ======================== #. Build a Zephyr application; for instance, to build the ``hello_world`` - application for UP SQUARED PRO 7000 board: + application for UP Squared Pro 7000 board: .. zephyr-app-commands:: :zephyr-app: samples/hello_world @@ -52,6 +53,16 @@ Build Zephyr application A Zephyr EFI image file named :file:`zephyr.efi` is automatically created in the build directory after the application is built. +Connect Serial Console +====================== + +Current board configuration assumes that serial console is connected to +connector ``CN14 USB 2.0/UART 1x10P Wafer``. Refer to `User Manual`_ for +description of the connector and location on the board. + +Refer to `UP Serial Console`_ for additional information about serial +connection setup. + Booting the UP Squared Pro 7000 Board using UEFI ================================================ @@ -64,4 +75,11 @@ Booting the UP Squared Pro 7000 Board over network .. include:: ../../common/net_boot.rst :start-after: start_include_here -.. _UP_SQUARED_PRO_7000: https://up-board.org/up-squared-pro-7000/ +References +********** + +.. target-notes:: + +.. _UP Squared Pro 7000: https://up-board.org/up-squared-pro-7000/ +.. _User Manual: https://downloads.up-community.org/download/up-squared-pro-7000-user-manual/ +.. _UP Serial Console: https://github.com/up-board/up-community/wiki/Serial-Console From 1c8b668d2388c141f645cf64a19bfea2cb22ced9 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Wed, 15 Nov 2023 18:04:28 +0100 Subject: [PATCH 0523/1049] tfm: Fix include order between platform_ns and tfm_api_ns libraries Fix include order between platform_ns and tfm_api_ns libraries. platform_ns functions may depend on tfm_api_ns. This would typically be platform specific IOCTL services added to the platform_ns library requiring the tfm_platform_ioctl from the TF-M platform partition exposed in tfm_platform_api.c Signed-off-by: Joakim Andersson --- modules/trusted-firmware-m/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index f00116cda2c5fdd..177a47e28d67322 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -435,8 +435,8 @@ if (CONFIG_BUILD_WITH_TFM) else() zephyr_library_link_libraries( - ${TFM_API_NS_PATH} ${PLATFORM_NS_FILE} + ${TFM_API_NS_PATH} ) endif() From e7123253a3211897016be148d9aee72cb2837bb6 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Wed, 15 Nov 2023 12:41:16 +0100 Subject: [PATCH 0524/1049] boards: arm: nrf9131ek: add docs This patch adds a readme file for the nRF9131-EK. Signed-off-by: Maximilian Deubel --- .../doc/img/nrf9131ek_nrf9131.webp | Bin 0 -> 75800 bytes boards/arm/nrf9131ek_nrf9131/doc/index.rst | 228 ++++++++++++++++++ .../nrf9131ek_nrf9131_common.dtsi | 4 +- 3 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 boards/arm/nrf9131ek_nrf9131/doc/img/nrf9131ek_nrf9131.webp create mode 100644 boards/arm/nrf9131ek_nrf9131/doc/index.rst diff --git a/boards/arm/nrf9131ek_nrf9131/doc/img/nrf9131ek_nrf9131.webp b/boards/arm/nrf9131ek_nrf9131/doc/img/nrf9131ek_nrf9131.webp new file mode 100644 index 0000000000000000000000000000000000000000..056296ebbbcab5b514be7a6f30771f3b12167bc3 GIT binary patch literal 75800 zcmaI6V~{36w>A2-d)l_AZTGZo+t##g+qP}np0;iGv~53k-g9o;^ZoeF-4R*2YHeiZ zu8OLR9jPQKCWb@_0#FwfQczR)r2zu~0BHX;LNEXs2tZO;SRo(u-z@+%-`d#537ioC zu(5S^R1y~=($Lf*f;s`f0uTZ402%;}p|O*_pn`(Tf2{xS^1K27`HyCi?mw~q?>7G{ z3vXiTWDEd+5dE_dFt&Ge{)Y|zVRkoX`~Tqde;Cd9x1q^DT>THzI{usBKfLxI-sr#a z<$tjGf8qaH6q=)olJLK^q5b2D%>NH;^nYOE-;Or_Y*_!fYLv` z(Es9(^I!f7|GbR;d07CA|9OZ2>;N_Z!~gOJ{O1|`v-v0glUpY<7Uut=K;VP`0EitR z@PP~ffJy=YzT$zvj{+d@s}KMH+X4XkZU4vLE*}8+_4JRA{~wMt4*)<61^`7ya7)+4_8Gf2DovKjq#03pn-x{~h&p_MbzqJMU}qGwr$Va`%yc!8-=nc4W8w zZy@z=tLNFRz9T|S--@rK&#*VdEB?>EC7-FUx)1eN#I?MO-B-VrkG$L6SB5+NX2QL` zYrm5Zh)=uM(IzIwuqz7M~m_tf-YS&-MkUF=CBv`$h6mpE7U1}MMS@U;n1`^lhVO)O1 zMf{kS6i=~4K^vR|Q2F^?k2fS;2K$8DL&^Kks3BYARb*F1+ zUz@4ujr{Ffg>5-IG;XBt7KJzVbcHTfF(2VpwUCm~217(>?su zT}Y}m&@(}vkb&WHwNHv4kB$qgF8+?+27a!n0LarnE#Ss+23ZTfR^RFL;71ERyHT84 z{;R_|E#-_TkNWiUFv=NP!~(Z7`|i8O&1o;H2;_8&e>JOo%AtM51S$KyeE#&siXYxj zTSM2zkW-^t`ueib6YADfoyrnvZ~x4--``5ML&dCF{>NR00(O^39Vr<*464!DLedjP zGq%b|b{2q+o*jB0Yo1m>;iDs<%G!W=)2q%s2g##c`}~B4segW%@Xy-bW|ok4Tt{7s zU^}#f)2^t@(~B^bm9s&Tz+cNkp}A4UUx9qA6T9gol0V~9F6Oasj42*Iz}4+6Q|#)* zXR~P)tCwEN3SNT$iq$@(W=hT|#WwGHAB(ntKN=j;e&4T|K0MCyr3c{=Fl)cFL6@bMITf@!@UYD37d(14! zI3Ic>ra=`?asp#7Q>c#YI|d^KC5`!{yB#EamLoMNf^MYZ>$G`KcFKmrseA)|lf zgSQ=f{NGmylRDMX z(tprBS2OGi%x1*NC}Yz^l&wmj;FHl8G#3(E07t?(kiDxG_SaY%St`hxCoM;sDB8vx&UpT;1A8e`(8JkgT zLDl*lI~g{GQD+>B^_VaWRKu{3mrQ!@7q_&T-jYu0pWBbEMKt^;K51%1z{ig+G3oVO zmu*tdN9b8GfLk8@4~&?rg2U{4K^JxFpM#R^8-r%1qq&PigHU0h4;H|>`$U)p`_VRC zB$oa>`45IhhDH}dxUHh(k@3am6DHN@mmncqT#oUA8o%U^SFZ7a0R-jl0b1xBGo0+7 z8{gg-_1cXGB$ubbx!(PsU0%8VYjUTw5*qbwT~12wSjGu0Gn5fEWSw)FqKsZT?cjgV zjg@Bsg}U8(MC{c-tS67V7{fWBstH6L-ly0{1>rke_0VF*c?rWN4Vwg zEk_D(;Ca&^jh-pA#Z+liisC`WC?qLkB?tVcW$q_aHroTvtM*SnwI6Tp z6jizLq*WHYF4_Ddvab>olyOEdN#;6^cxh0#4l*)F!YqM*0#70lVO_l}GZ}vx z?R||78^<*hUX7D+Oy8us=FS==)>Oe0=G2`22PNr`t_p`Tm1?Vor}uRmYZA=yHx_4V zCfO^2Lle>h548c?B%xF^qC^{Wvu;FpoyJ)$H`E*@V;51~>ATx$Rg0_sh?YWCE%34} zIINp4HhlOXge%eXcdq``;tGIV=Srg9+Y=G+~+Lnk$vO<#qV zAaw_vh$GT`KZG=_$<&A|#ly}hm1lMrbgSmtp@G*R%Ee@ifXX=c2BiTL%_xs5P$b4q zGz6(}KOk9r1@u$&@;8-J3^z2%`e^!LSy^LE(VZ4yFQuuzibwFWzN=-K`S=xt6B>L= zYrD*VVvrH*=JY+zQ+c4>ozx93$BcCl zbWgLz@H0$apZ5OwZ8urEhkg&57E?u!I7*+80a_im7X1mQFHM7&w18s$2DdR0=#-Sr zv?A56v+yp<$nR{Yw{XJz=xo0{#uhxC&@}}&} z5O(9QirJ{qyM@M)HmWhUoj8kFHwt2S25BI48IH*P?6JTvr7(lD(KuIFoP}j=w~5lO+TJ<~B&S`bGkiFJ-~?Do09a(k%Nw z3s}j2hnRnQK6wvJ{|IaQ2!`6lEF0-~7H_(D{p#+>%qN&6KqhgXbq*vEL4K7GiY(|s z1A;;C^GXUrEdB-SMWtmHPPCv5nX#$tas9J5O{2p5tR{c=Hw8H&s`i7?bQzA67|4PFp2)PihNS8l{Kh;&NAT=LQid#lq;vW}Hg<6MgGy?Vg4 z-l(O;+%!bq>J&9%8^7GoNv;0KYU`Dn8Z#zgj5hiei0;BHo3GPg0-^xhAF3cJ{9PfDG5 zoACvimvP8ws=9e}x6ZKZrkP8l?O!rj{uCVHkpNf^p2HK;S&E-q;dgJ$*_+8M`pk4i z7IlScRdZ$4zBT4$MRcgXGhkFsvuMW6u8Aw?zEZw+FQ;TS8$Pie@7^v(c(U5dH%M&L z{FASFl3`sUgcy+)H8#oY)nN6z)NH}BnJpvFQ$nY&FHKc&jOtH<7iFSeXS2gV+YSuQ zPN*9=jD@NlRCE-74F&QBsDl9GM0UC5qIU@YV4Rn1HnNuDNe5P-F1>So4 za@4;-U6DVQr^x<5q`ij3`Iv~F1?7HcFRoa9aTL%&*>(K2-#rt3#5GHMu-wy0BGyLP z40;zf6Mx41aF9)bKDCtH+y=1*L?sA3nIeC=DdS!*E~b3s7f&HXH9|08cv8sK?wM#r z(j`oJpvtB^V)YmeU#r0$0pse}9LJv@3{c?@7F}1{g`K|YQ_z?n)9OjT8d)8}(8T`w zl${wuM%Ig7eCf0&_|e!ltp!O5SL@ofMuN=4h1GET~+H_ZtSwf<-&XrlFu->vuFeHjuB#77} zJp3AdbUXAEsVS3iKrgAJA6I@lMLIUB@9)q&LgTXXz;Zp!Pn$$7yM63D!li6u%Ar@M zE{UT>Lo(RI?L20u5=+VZ1F+K?lbXFhi2rq}{r8eNzJZDzR0}73#6HCpaIHoeb=~KW`Y>v>2?~rz+);qlN*gbCawbD+~pc zL*||;ZbT5*I=9Cq=e(&LnL_}VT>kfxM==+=;AQom^Y&jN!AL$V0uL03aHGRkA*qF0 znopL~f378(F8%nY7v?P?b=0vk3fEJORj+{JKK$nl6k!zC`IS{x8!;vFID0lfsOYwVO^GjDs)ev5NhzgrNsq(weimQ8Ksl zM5FL1H0{S4DsOBE4^?+I_(!UGn*Czby?z66YMtapJ}tX8#b5u`WWIsD|EVbb zx6qqSg?J6*XL+LD{Xsq@o;&Il_$j;mi}!Q0ympW(mu8=cLIDK|J~^BZ9_Np_;Y3PD z%7$sGIbqHuRS_3+Jn_RUC*8->_1lPsj_NO}u2)(lck6QCU|Z;hww~@h+SRM)c45Ie zP2a|QZwrrl(hKzx~?oJ2)7$vyj>L~yW#h5O~>YS zqIZrNGwGe;qu{}4+$IQkb_l{#+eNKmNQY%U70jk*;Wm$WgxjRPJpMDi>Lo0uDx{cj zfj`Mc6Lm8e-!Or(es!d_yE#iRzb^#&9ev9JTXjwA+NX@K-mSG*7P>;U)6nf3AHzN= zOMFQ|x!oMRd@D6Om=Ukjx6z^S*62HU%j*R96cDl_gL87M=Ui>yppAMHDC-Kt-$L%D zq1MRGAX>}kKXPtBH9W-J?p}A`JLJzrPk;RIV23&+7Tw;3pjAbrK@1Q_eo#^3N)MtJ zmP?(vM!3)S?Jc5BN3lQf$?>t5z!rZwFss_7$hrK&jMX2QymuRZj?uE^f+;r`%0lW> zZ)~JefoI}>NJ-Uba=nWA+nzI5m0}-`X(#31qL!uTL{&&Z@~JPq#9)Y+ylE?$%ul?KuM$OfnWL+Pth^j7wWwIc|E! z4HZzX1YTEL_;bSClhxpsEV{icKAGTfT=M5eX;zf;FR2o2;Klnu(h%~tL}*H#WCtXZ zWZ0fatJ~0_H&EbJJ^`QHlBh-5MjfuxD?6ne3^D)m>w@*4+IC51XR;b z%F}x4CF$>l77+6AhjC(cMxNGK>Soeum-DAyusVz~KW|-$VFCGMNQ%?F(q-5{F3}j} zN|g+(hJuTc{BCr4z($m|AMyTc>7#g&Z-pQW`DrSiUw27$81hTY`gXQ`REEhXU$$Zz zi09d>lhlg0>~Rr}Y>_F3KpSLTk*|!i=!>^<5#(#y*ISp|Od+$RUFdgbwV5Pa6p}4) zIhZN}@ue|Vv-BsIS-#V^O4m(Aov0}}>ZFCQ?6p?D1pnK>l^6IXl4cr?t*X}t*x$47 z$*uN}jYCp}kK?>)oZ)P3@E@&lJ#K5zulD08n~jfRo*ROs=eN7iK}hcUsNt_}IyhUr z+tr3aEejj|wlEm!KwMF$4J9dzeH`Dj4=YoHEGfsILeVZOu+pcy&`naE~rk#JF_q;dpSeZYXaf`>5jDqjALRrd$27%H_ri=U# z*xhmGLZof`JADH4y9-(O(b4ovk`F|vFTC}9!K_kSayBe|F9^0++JE*EQl8sVLeOp6 z)X(tK&N>>VqU_5MnjMXg&4EzuQ{z&1L?e)PQZnUAm;@gDa%PYL zR92oAoP6&YuJ@%0i4dQfiMEjOevkUvf>*=JW{`3P{)hTmt`ik(WBSItkcvo8j(X(Wy}d3|*kJQ4=R z>?BsOb&(iaShzO6CEt<neRr1tm#_daE{KpF zyf4&lYui#jndHgswr)Kplqc-f{`=kQW>?QW?$-EMeJ7^kM$>FvBPtUA>MGO7-uYo` z2I(v}sRKlLh1fMy=TAQY9V|)}Ib(7x_umJx({mBKK-=0L`?Rz{kA?$hCLnHZIbK!p0;?id)Ue9@iyqGR5gw96wB%RsNhjVY0XGM7i6{Z}2}SG9{{9%&pG&vK=y9Zu zdoZ2E(ru7^F_xvXgxoRJb?gf`gW}AG33p6P6YKy%8JDRb)8=BGPffNFVC3+d0kUgE z0cPVS!PR5x(JZ@Bk*um8IcW z2?r1b5k9VI!8$l+I)i@hgWr!I$8)`FDyf8p8V6p3ZxwgcV)G;&(Ag^q6+R4TeLO$h z?)O*_gdT{Gx}PCtK#>i3aog|(9tH-zNKYpdM`00bJ$*YcUJZ_@;2l^QzF3REC{9EmR$yZIc5b=idg$&ybj;ZSx_oCQ;3?)yL`)WbbO<{j$rtPKX4SFAt}e9A|(Y@0G>w=6&6ekt9~ z*-TALmCZBGY@>`=^@2xdnl=gE^C-1dd!Qu8AX3E{q31*54r0;*!QnT< zZ&kc)j5~hXNIT-i&ulgTdm{Ks%s?i6iFn$bYZ)qLj04le4$zxgZmGjh7o;^H6--ZS z1mAYr=8*!0Q_kcNOPMhHpp6$M!{W=PgovsYGgDW6oO0ClP(y= zO%6f7gT7z-)3$jR@nuG$n`una$5@Ro_jlbBg05%w9(EvM< zl1n<3pQWs2Bz+O258}nboT5rTo7EN#w{DU$xe&80L;Vvd9z-=9=IXWL<|TNs6V^A_ zh&?o~m_HQyhn2CKjW8g%$IfHKaCM|mYqD58 zR18F5L1cy^P(K3Tn#Cx)S5_1C(Q!RG35StcZpV5=-~8pCD;LPBF3P@wL@ZbZof1dI zbXB9bWVWjKSBIpsL`lEN1nu;z`%g*a%d-e)I+`*^wtpa!E#KQk@~@Zb-}Kd^JFL3O%pX1fbMg(Lgkn`!_9&rl+g9YuSds&#O#D7gwkFs^*84l}l0QW^DOAvl zltRv`&kl7m-CxuV)?pal)ASU`$sEHHY z{-)5{A};E3)!5CsIfw~iqv{bW}AEr&OM~5LsL(e zW-NNvLsST}zQ%@!-rJOuH(T=ufiC~o6!4{}x z*5FGwitRAe3a!sNxlzFs%AaZ-cIAa^*DjM81*8jXj>p`3G zU+p8e2cu*aTC{Ysq^q8KhJpYr*q%s{jz#f!C;m;tZPY9b_vv>gUm5enr{y*UpGPR+{(y2}>;Oho2h77~L3Ubv$M3AKpwzj=f6F`MifV6V!fU zvln7uM>;*`d^`JtCd`EX1vXuL1VN$<{sNF<9gG4 zSdMT8zoIvm7_AohOM-N;lS1iX&9zCrCLW8ysr+;Zn4SSBm{dmoHf{ZkYR`VClY;e9u8z{-- zX&D?W6?z<#FVpJX=Ia5KGkNJT3`4aSLB{7FQu;glKHQz}(Z?*Z>NHPghiYOIa*^tI zDnbKWFmMMmE`nyft1gsE)ySaaM)ji(PkTW5C`$XF)|aK@q-edq4{qehkayy}5)Fy; zbG!p%S@JHvcz@RKrTew}*i=oMmg4Fc7oxFEl)(&X|2t|q70%YuGg91O-c@jR7hFU5AhL)MGuIQRzFElik_|P!qw5AD?Xf#|k^JBMOZ7RzNMD zO+@K1lwo131*;4wQN~O^{`vkTACp)zRx}hZ=+8?Rx>FFg#2t>m15X4MB<2%SDAN{e zknan&3^jK0%?fWl@`0z-am&;r$-)&r@ASX6-@pb8Q&gH)vfXZ#&INxntd!IQRy*Im z1S&EohQp7)0(d}W6`^Z`MHXDS9 zA@=;PqP_>KzYY<7BA!}H-rUk;(P#ViDomQP7wZeUov(xiM-1!f)iw_D1`n5F1PTr= znHW%t4Jid-U4{2$t&irlX4lSp=t2F@4Io1ewVo_yj?|X!puIatb>`Gy;P99?xnyQA z#R^h=66URg_P-LRh zk%#w2|2)_tESg@5SgWL;;V3=!;&WZP`?5|E@iIRr1objfmg&&4~=#A4* zJMD)2DT>doDTF{KbYK&jq3#ekMFx8^(p`OwAjSe0g@z~XNSw0qvTJgr@-j!1YAckH%rJ8EDES-*P)(K6K2WCJbD@fFWb=rudOAL$TG zCeou2*{S3y{TFpo{lqH{-LO$U0a0cKD5b&9<>V@!{9WtuH;#uq(2$?`k59z)(Hxo3 z?DSE#=(m3PAkqRvv{nIuTmY9!m$ar`0j>2`bz~d|DP4egmU@BgVzaGB!wKm#4SrGY=GazBj1;IS*+AXafmUacjy{Yz6)b_2y>m-L__!hRx zH$8Wl2#gv_0ikcH1QQ^ZDfJxyUb-PuMx^edU^1r+D>*CpS_yr)eWnAsFo*AICXujc zcS`5grQAhneKDdni`*R3$SltAlL!D5|K0UH{L@0V%v8!}S_x&&UvK92az%I>q6X`! zHMNNr0$b9m!TD-wXHRwkmr!u`=^3?qj#-!U;a}NTdI(caS#dHIt~TA@?>CR%A>kNO z1!BXnk*o@yadT>Hlwg$iQK`VGLn`{oiZ#9S3(uk+h3Y0Ap?SmUkX-^K+ka0$Gnrw1l?lm=we%iV0T+@bs&zvGVI(PC*q)v;)3p7B%Hw4s4r zQ2JXJ&kTL$;zSwctVQ#&lO!Z&1lGTO7`8kwosanFA-V6U;xSW?W_itoq{(-vVU8$j zc*=ArL>WtH{LEsnqPdh9zpEEsP3yy1J=(mbQiNj5RODUmcbjHje zX+x zK(JUlz66E#bcz1@DIoyA*(reNmIlvWl0F~zyz_*pf&~!p>GtP<@_&9j z9Ox4B5F_|<>qVNh?x1I+pPtd+7N^yg{!B}FQT|p(fuqw!XZr!NnR#97g{@`W8&g>c z-(E1p1DckIvaAS-`umDGL&Kw_cl$`IqBOMj5-`S2LBHC4qE}*8Dg(v*N{oTBJvQlP z4U74SK+mp&W2@Vz%wo6(ty53tjuI{rjY$Mw78!8nqvhB=Xm(kx8k_E)_UJYNadx!{ z_j#WSr^>U^^9htmZ&|s$!zk2MF*UtGyx2TKjzMv5NDeOA?EVftz268`UJ@vHl2HNm zwc0UnOeh&B?4lT{o*z{pPSO-XWR++l4`|1X40(5*GHBSlE;zASNVbXP{f*Pd(#jk5 zoUWxYU3%r|UTv8WP&4>!Gc~b}Xy(kSU8^5YUKLa*1A=CSdb#)z9dnSOi{%OF+f5pd z?vOJkO7@nvMO+`eAp0*ZQ-bWPefSsb+rQ}l+%c-;UUq#qfUB;>_6>i4U`7XOdBzTq zW@e;P#=PqKqp9>$PrW!2Q(Yod)aN8)FJj5AUAQjU(xR%xe_BK%Y z6I&As1TcLzW?I!?a63`qB<1R=f@ek8@`WwCDY8wl!3DWT0Y&1P$$SmO^LVK1edk_a_46kDcCn&2%5#baEL5P(VD}PtDCeu9?_@-7$75e}V2+Q; zLCSNINh0i7k{(poz>h-DVwv&k>xYH!c@}cz!u0W&6%`QG6YB#F93bsLB>rf~=y4sX zkz*nKX@T7|WQ^Umo)Dp|me{wTiZA+bKQXPu9Y)tYrHJR)PYu|byXoI5aBpH%4a65z zLe0*~_RV3)9v;hUEv7seNNfC8>vmv+B=q>~qx<5IWoc7lwLQMY8p|u$z6q-uc({Cc zUJt3vGY56ut~E{a?N;}MKldmG(~I-|Q%87GJ5-* zkHS6Avr4tnTc&*+-qJ!}xrZ<=s+KGr)XqD&rMaLDFP4a}VNS^jW7?x+ZiOU%m^gSY zK~KsCL=J*))U<%YXbp95O;RZTgecs1C_C%yn*A9;)KpRWiC;l9=3ju!1fR@dtq|>s zEZt5GO=Z})s@Wy6Cyk(1u#iVOF5rKH~WTC zSiTk0de3Rkb1&mfT=6lYMAu=v?v=hDTqcmQV0Ug6=SK5d;zj+qQ z&)=O!!nBXLLUk=^c11f>ZYn&WnYuFOu^L=_;Xn3klc#RueX@jvGI7k0608*G{@ zqn}O94dXR(uS{FNkAuuu{bDv`vXs!ji%4=x@QHpa<>z7}BDYoc>ddbVbjhtF+&6(Y z&$pxL1L-UK2oMRPRj@91e`ruz8IJ9N_IJXY{-F^X#-)1hKIshY9tAgusK9Go2w(bb zw+yk+TXTNz;E5d;Pvu(D2}^m+RqpTy`RVMu}F-EI~ylet(42w3? zgE~P+O4u{Ir{W>eg47LzAx;GD3ZCN>1F=X}H-b$t4Lk+Nm7{_fK>3MiZ!CzcxMG0| zJ8{YJ&t+a`^2*jSs~>uN6N@_*#Cl9 z;Ea6C)oj;XxaJoeZs6s8q(P+}7_jrFzGTquaw3s-?dw`BKCeGg!_=yP?G}-3f6)lW zxk>DnnA0ixLFO2)Pq#w1eB?sDQrDc0ouJDLaVF2ZU8vY@2*jHs#h_h!a5aX_1fzgo zxGJK&lvfj6tYuzI2(429m`Gu7b?>;0Ohz`i?K`N2*?_=st#zk4#xSuowBY)N`>K?X z5fap_#|+nAzJE6);%T^5@F7l>RgBkL$yu9XwXxQt@bk|@qASo5I7Wq=a?iShZd(<- z0ajg_KRP|4lZRodlAchEe1J7`g@hJc9U~UvlGzhO6m@_K@q<%`SH<`1^FZX0{;6#1e zk^p=_^X443)zQnFI5`<@=1#)P4dgdD-8gVee066=)ka1+cc#e|U=TLpAosM0Mq6NO z^uAWF^5rUeA-0LxS=TVYb4~fRVikTwjGGn*UY@q$O2g+bv$m>&v>Tx5F|m%ZHU!7w zgYo2Vy~jp(3XMpWB0|49=8}awD}aLD=&-SEwL(@Kx*4+4jC>(-GyR&$C_KYVQ~3CN z9NfwvNQ3tyFjM!apUfcyrnJBbwG}#FWRzkTZYV+%CLGts%T&doU*S9UN|chNDDmLX z3zM++8Pzx@^)~N=bH1Y6W=j}Bk~}SA5FpEBPcqr>0&Bae{o!EP z_4N=v)~K&OeMBIWr2mI_r4dxSVbmcq4m`UNw$In!6shOc#{F%OmqCJg?57}n`QjO- z7?~%yE+%I8Vjbvc+OC2&H@)jcvIwjAsmO#iUb0Gvehlb2?!boNEpi0Y>^+kq(WdVo zzF(qwLi{lWeEPcjY^090kvkWyIM%s$x9ggnUWNk{>5U_ca?&*W;cB^7n2e02Zr&(< zNz-kRkAZXa9dVo19eBX^aZ6z&orEXJ#il14-^U8b#Ie2VK?t|nVX-s4y^ODVbnf3X z31sA-vZG9xi*__L4Lw(uY{WA&!>yc!DjuMCZsr&6zyQj-ALEJmGb6X{r_UXt?rOJR zgZ4xWmJm!-^OyXwSk-tu(rM@Alpas127~!*`xpz3c((E{WLuAtG4fI)E3X%bgg?P; zK&a>7FEEquz+{jhHqr<`tMou!3%0goZqMU(BLM?Pa!6~%(4?zbPoYXiV2C=L%UJRe z6r8Y*Wh*BOrjkRg#y?X?qJLTbE?s}^6E+1@KDw8<)Ov@~NXL-FlW%}(bX!T)T(S&3 zG~3IpPDZ&V-m&4eZ(u1>5-m~K@AXU-t|9H!keF=d*SYRyG+_ws>o z*90m+*uGz{Kk{R9B+(76B2oz(HA3Y(!+0?H$QM9p?2gA?2?>tTNnSlkHFffJXJ(rCY{EeBl=CBSv+O&mK3|5Wc{wx zw)pfmZ(Y49p*=;^6@%Sam{R}huE@i`612?ozd$(2HnB}VD|I5}B2)WaN|J4XB>O(E-J zl|bX*n^T{yhmLXV?D*u3!Kfix_8??Ixk<;Ftf6T3*qM2*yKt0dBhTH=BTzg9a~;o7 zp{k4M8g|U<0wxSZlvf8A>cSw8G50Y;=YSfZOMO}&sfg}U_xg8v2LW}nVq%&=r3c2TZzz2KxRtg$^*yG#+sH!;8~Sb zD)Fj^U4O{8w#DcX6vB>#YKksHrr4U1)Pgu`xFELqa~@jahx@`$V%5rE(N^O&Jd_0! zS`<#h9GrR;n2O>rs3+WzsoufAt>zm;Z6&>^k;*N&>sG?7C$%jowl;X!Pkf<9Dmo&E zcw1MEdm#c@*X2#Y+I4=Lm4iM|5>?f_k?TM`P^9;x_SedY5;a8w1wR+zUv#AgL|T_~ z4}1Pp>-Rm5dGxv`V~>(T4f8W77*osl7Oj9d%%VaKry>8gHL*O&$4+`#te=jbztn66 z8R&R+0)ewlkg`>gZAJZzDMI9GEp+aG$Gy9%!L%15>a{GrM!DHV2w6SL;76prsZPau zM&3<(rC~-G?14$HIs~$;&D|!1*Q7Fpw9i>N>}$455+e(k8tuY>OnQGb*fxLX+L>=7 zB#jJp%s?U#In0ogYwHTOCJE-Kk5-2Jr=(^XzUKNzYk$)B=`Jp}oM@W9w=dBU2&%++xs9OEMr|&;Fotnm=z#>fjs>J$Z+(bx z#pto~#Xn{)Uhp)`)e@XU#D$`GDAOGyZovM{8OL9FQz^P{FYr$LhismLF#2`LtxDgC z-C94|Lm9VXmm0*p4(fzI%D&&8cYc9N@ux`IW--6auDf#f;~M!Pkdv|w2imHAnej$a zz+^I(wP*$2RA*%}W@M0Ri*G&TdO{E}%kqT#Ex~`Fx2z0qcqByLztk80@qxYW|1mD3 zIKK8YFGrY@;7WCsX}kRfd&)76YTU$CnNDgKQX!NgvWGB)L%k13Tiqy1>0NsE@mNCG zzmYzR?i(qN&LgXoDO!d-C}C{{slx_%;D~T)KsjD`OV(!O$kRzGiz7~I;Im7k$A!r;24N4)yK5yD z1^8-JlOg;>bk76SOZ`F5_Gkkkt$r4L*RTs{m-Xt2A~G`OYb?pU`5_fh263)}ZRs7* z?%0TdIPhw6tf4+U&xizfa1wir15?~+2^v$Y52&l5|2d`9tIXyqq+sKiAQR|QWSUE% zkfk}Is!u)sE7kqb9#5=%DHdsJKqs46-&L1EM31Z^*9Sj0AnpTtx;pp{4hP9GVMe=8 zovn9wV*W`2p?~%J>22L8e<{-fj&GkM^t+!iY39hU(hi;lmF6#}FK`!F(rpvXN{8?6 z-XdMKO8TWf%FWrwo5?~$dG3t~{nwy%IJHc^@#mf7)zAG*j*e>nqgx{_(V5Z=srOzN z8rk=csFt;b5%h`5JejPXN1i`r^IECvIagjea(KOMtF@D%Jg`J*sCYay#0O%rWF{Fk z`Z9`nUAvPikvQ{GF`T16k1a{03_29`&hX&il4=zU%2NtyS1%M1P}Mb3tIS1k?M*r3 z3A})Pp#JG(FdTydSHLvP!^T3X#xTLR{UkKzGzhXEmR>A7+bTC9&lwCi8hM(GDr~*E zgbw+GQG(K35BB!TEr^r`K>NF08YNFZ##r#hO4ZZ+S|?Pj$Jtn=3e9v2^?6oNZXQXm7^l>q@0-50ASh8}(MHRpGjZJ4;D zR*r#>rqz_oZO!wGN-&rVHrHxPsoXdZ$rC%?6#LFLpx-xt?3?DS$64BAj`< z;=xD2Rb(eqV=cEo4B#&QTAhq?>-O|<*BOI@sKJXd=1^#LGJ?fQVg4w@)l6%8^tfgl zKYkzBn0xqa1oB|hk|KMeT#CIcvZJ*e>f}}0NYmzlzhx7?iXrvEzWA3FCHdF3J_#c} zeltG{$cCGb%h@J%PoYl@v94SJM7WD9y12KhaBb1aJ#E{IPnI@P1|`(hcMY*#8epY_ z3*@&bD8F^RagGxj#jyXkDQn1D&S96HN3*JO+uW1bib*Jj-i3wVO+&F$$iRDmQ^~>e zoz$DQ9s6%e??dZQ4IV~=J8jRui*A)#?jTJ54vz{4KGRSaX%uj&5E?wRxz1mEb_4WR z`SZ?XJ_t^W3V*X&su-gDIa8Jq-htX~H|2zNHo0Q5$&5iL?#G!PaqM8--a7$SMsvMR zHc&^}xdc=x8?(9df0t2Qg(-{B!l^!c6O0Fgdj?MLvC~Xz!k2=uz3P=als9@rDrl?x zApO2xEwYB1bsQ*y6ucz9vkf=D#bNQkp6hoApt^vd%6L!-v z>x$E-t@r{QTGQOooX1a`H^$w%rLH%*2DM_+O8R@=ah|}4c(yRQa?nKh<8Nwd45YZs z>zx@aD$0FxHaB?cCCPN)VVzwPp8heu)JrXU_}vWe&{h2|zxmwBQK*n^GY3n5P^NY% zt0Zk*ChcCBCv&sm<~)I*5-yLrnhvQB?5P(Cgo1STi`fn9y#YbKac$=u4gP-qK@R8TA-d$O_U0Z%Dl+Njp!={-*7 zD98xmLu)T$hP)ucK5dU-sQi$zcr_E|ARyxc2RZrKnUe2VJQ6ybE z2VJqZuC|CeIixFc|KRFHOWmu8wsMX!5YR+BGI>d#lwaG7xyuZ_z8_fm&6M;&0rC~Z zfaH17R{-D8sn}g)b>;@d4_YN5VLaGGdYd>EWKscaIWuU+&ujr_-w+N+<%(%KwRRW2 zq4F4PGWl9G0awc}2uKq!k9+V1#&*t_1p#&qt%JI3p-9}=;FgQN?5#O4{_018 za=T`Nn}N&9ZX%8#@4z05Sz#Jsq}G4g^~W&AwmkdTjho%?2T@sz zx|%5W*fF)Ht|j0-?EI=horsi~l_T!FG@#>nSb?Rc0S==+qu*Q|8r)}@6q>COYDLOP zQOywa3w~4nM-$xOZO1J{(29zQZEU`p34rv*8^LBy>Kg7CP?13KTNi>dV*Af%Nzb<@ zwch&y`L@*yjCko%ZF$ZVnGCE9BrWny*Zq0gpOK(_P+GoRI^IvJTdpBt8Au1_3WvuS z4%qK9CkGE)9f^Iu0aOHRZ@$|g4M?2D93AmBskh!;gY)KNU!{K$FKbc~?9-vtBe`pl z>)0A-A-guUCYH-0y7iG3Z$K70ugNk}?Kb)Y+yaeq%6PU5fsB&is2(1bY1P$<2CI3Z z;tqW-Ns5E0^CYp-k)#JxcqPAxa!lh<63Y9RI{H#Kcb1)2v z^%!Oi^ToTk<(oK;UykjA7r=ape17WYlRK(+$O$_I4(r25zLBEjD|jMZjj~sy1bkk| zs>aqK-nIY`b0E{X&^XSI_Q~3tf&o1lAz2P^>AuLAzccH+bPlSwzzH239tb<6Q(#J~ zNS}vkZ+meIGYv)Mllbr=eCq7KS8lQUKM8v4d~=5ZD;9C$z-?`C@ey&bufHj%d#@PR{z9U%R$h0}zpq;3S_9zikuaM+sdJ!o(j2p-!eAewbxr?U zlt8D@uo10?D}zVn2sXv36?8yElYq`L1c)#HtWUAb%L`uAZ)X#9lnP;Qd$hBbEII60 zbJ(!wnstHK4JTQ;dsgV>*KJ(bVocd^6_a4Hh)}(GID{6i^jee~AEht8n9N~rG^hBu zyJ-4Pe7|YnoIoi!&pZ#Uf8k0Qk#bGd{y^cbgIQyDVJi?@B3T#Ksv7)kMqdA~!nh~# zD5X$!k51iD`AA2AK#L#*qEQ3VZe$$+-L?;CeYO0puk2tNkIun-C0-Mftxtt4f9%Z- z?29G4xVspQY%h0j<9p1nqBXmtDXTT0#+VT}Me}Dp)BxFgIndFTb#nFa2i(9tx91uU}i}03IR$To~;EMbVI9e z+BpR6?wVur9(&@cUV!sUZ@DbYym(bg>!>O&p{~{Gh(9nUL9{)O}?@a4`)giu@m-U!F}oJWI@i2g70?{ zhs;MV%V%W?5#OY24<7Wcs+4!ejo~*Vgzs9Hk?XR_{FOMLZzGdALW?K%7Vi#JFWHnz z4<1~8C3etXlc^d=cT~`EQG_WhG#ctD?tw}(OVfG)_&5@?*a-l8Bx_~=>%|Q^ACZy~ zvt<+hQJ?(Jdi^O0H(V7%(%UD)77Yh0v8kbq?m6|v9IrG_aY10|GC0R}k*Y$D=GPP8 z0Y7Vrtn*NLRjF6DnWQ@$F@v z!a5X{{wb0V^tX`yZeQY`^xQBd<_I|_KAmkHm5B%7LA`V|vfUlh54ke$9F)OmGNaa(`#C_ER_`XLYc6%(ctZkhUYYh(EIP3k4k2 zZ*hwZBKc`qz1r|@IpSWv8*(b#5J|pG)p^_cx44ZRi^=Z4X;)v+j1(8$vTf zsg-)@*(jLo0+A6|i$HAz0F;93$fcDajab007`Nhx-|J5sYT?<2N$}4TQ$)TYfzzk8 zYEy?`{DoT~I?-AXLF9&pp>3mIx(JLu;`68OBA$=Q(mWbWyx!D{zNBax0vjWctXlzN zD@`PCgu>oGv_v}=%7SqwWmxQFg7Livd7F6t-Z>inigg1_zc>me`x3=%j5giD=Ccye zqGwmg7u|`pMOAB;l00$_eieR9|Eg z)Pz1O-ms?w2~P32&lEWC__pHL?@0lWDkVxz*d#z9UWU;D?V&g(4mUvtqg8+s1q0WF zD*&n4BV2|i@pH99%i7|*y)hK{i=5<+;0vb% zJz)36@!PTULVlHWw3}|ph$X!#3!o}=i$bA_f3fmRCA$^C1_|dXA?!2xKCHHIhW%6~li_AejY`mdJC#X-s!Mcb1 z0RQZ@niPlO(MnB@qWdJn;qZe`zlJ{Flfw;z?i4rKV@=B^n2*VK<@umiB>+tD{q;2+ zKer!wdwnxS+R6F9g^q*G&fzElc^{X~4!)V3X8N&|NNWd#sl_64tK=M91bnJ_dr4^g z5t&$Yc6HIWG*Kot`ZPK}1CFLoR|y-sAE?N7opsIDXo24tv?t?`MiyA0#clieDwI=R z1Bjj-4ztGj^4JESRc!%JXVaC?p}v0M!Pfq+wiVuy?jX_K4HVDYrNz)G{V_pJpGd=N3db+sWlx@V^e1+#1nM?8)uu?Qd$DZ>TB?JWlI zmqIaEK;?HrKGyKlfF0X;CtfVd}dNl(oQfWZUHz z+|Z;^`C9jrog!rK(ZHWolId7Ov{4*(D zp9kadlVKaSF7wXOwGuLaqDOj{tOF%#MU#2w;w^!hg zj)vz?FisG@H&R98&!w03*nciR1tA8praGRHB}+uWIF64a+RmMORiWNa7)S5&CSn-m zCCJ6Jxir}%)O#sZoYESc%k(Wha^j_XOmu6C;tXthb1Na)*81b&zo{msZ?L1@b>LQ- z{Gg~|oI?_pNe4FQB_b#y5X8W5-`=5ihM2~|?G*Bsobr1twB%9SyfYKs5N60HzHu?k zUv1oWy;|yCAXVxtEHc!fRGU#|nkJkB;-TSfJWGj6b*~)OkLBq|sh`5ug@+{vWy^~4 z#!#bD#-(yZ=-2C2u!gL9?gidw;|ka9TYXz} zN7gWib|F+Yz<|3SFfX1U`rv^dS>^_On#qM`Mp76pEN;xt)h5xsogHq!kI?%)reTUl z8oRL3*YwIsa4Td#w;=7VTsG2?xp9h;))JYyGUW%|RjjT_WD}5GFnjqdj z?dKVwqi+o^?1-g^)|GINqA)nRO-h{0lYf)1UdMbSigWc#Vhz)hlR2Kr$44d4xU;0W z+g=ucw6ffxGEwWDY-|jqV6Q}~JpsuRXGXmP%Iy8NpylIO&^D}F{~_0{OrD0qj6OTd z^luI(p(s;IEd3FarhoR7ind@uO?GdS}NEo&Fa2ezp;p_I7v44ku@j|xR~vr4%fHNoYmxFkr#HPNzN&PVc$sA+k1_MZp?;isN%cB}yFrFLxLKlr6wb-wAPeFV`32`Sf(*sj*5$*){9SrB$}^X#>FPZT%sKWMQ^az| zvpE^$EZ-+_Y#P2ACN*DrXDmCgf5M-XeUaBAdv&5k$Yv zL7p-x@;27_P9dnrihZ$el=uvLd0qA2MasPE$AcJ#y)i>jzF=UMMvUy z0^-tH>FIG^2gu^Refg}}0NOEgWl~Fa%IA%CHUweqHB70S7KylMJAyY>wQ6$6cDz&#JQ!W71z zrv?Fv>asEa*9Go+QK=3%ljNTVIi6>2C-|DgddIX3A|Q;C=>v{~Lp%Snl(6Rr}>-Q~b9X z-~vyhN;VgmuH&!B^`kRAnCQE^mU`Dq@-2~f{m}l?xgvK{U~vMpapEhA$)OLRdFH0) z4feRMbH5=;AYk|F0#1*oYw`nH*HmT622uJLJ44^N}* zONhzy3lCb!y2bqmN2n1GSiPVn5)KLPxxd`ZhdCoBw%a4MODr3I<$5d10Jv~hGvog8 z=TCeUP1YL=Qq_}m{J%fRWmpAKmZ1rlI#vMT>y8I!U+hsx19n0STTGik{c4`o4ZI9#K`asg6jv!b z2#z~IJ#y`F=%4!y_&U+eA#=w8VQ@LzFWm5!Ek$Y(h?vCI77IZMJ-GmxktiV_ zsIzAI3iYy3{Yv?xTo%@0#`;i2GU3ZX~ac~8IUWXFcg3N%$UdAK`)Q;alDl;Q|-nBGm}^zY0)3M!owOZz{ocog@Ibj6w0+LB|a=ACqGYOnX`W_2T50ps9Do zEFv8D!t?Iskr*xlv30MRiTzG+&3cQiY$!-Ph1nMZL${USIu!y~UhH2lyyBJ;Znk)t z)}L#{gxsMqdZ2ez%?KkvA;+A>phPq=doBeMG^v=d37vpeRutUx6L)Wp8#M3KPvw5hu@y=HPO^Nvz>qf zEo|$uRHxP9>Gspf|9baA5V&|Y>XKQ;gJohdUQ1;edOLp@2~OA^E4?&LRxwffM!z4D ziu~@7QAUT~0!Kz{fgH_?Mc{3`C9sEw%aeAz;e`8z**t1(|0p&+S8miarPJL%*vy{> zB(6N8+X%EPiSkq3t&I+?XB_F8R{BbA=FnDg^_DoCfpC#{Z}(OQrc9nS(}Gf%hMI>A z^ZGQNEgg1cxD8;F!s9cY7HW@QpILUmNB;M;!?tq+x^j}QJaI8O-e!eX|3%gOj0DMa zHiQ;t&QZ1Z*r0SdCGf(gfHXPjbOga}o{`}?_Ndl^b^PJS8O}SU^}J@4Bv#v9gDmPg zOLlU_*BYzG!!~b(xfKphb>GeaX1v^6aib;t*lDNWcXOa%hj0nML$-7)=@DAKJHtx4*K7HX=r1OkKLhYIe`$8f5!Ac@=q$508KmERca44*Mb zfq@RvmA161aUEGsE_dq%V*`BZBQUJ(!{WR{-k$tfM90Vw|@TltA zPi67s%{adB_=M@{R4_um`lMXQr1p7D7AtBLw`lw?Udn{x?6&zrLpL0jt3@iyyN+|_ ztS9{7hC+B6Sno_Q2!}GZY=UM9!Zp2kuszHBG*T@|o{U*RHZq}xVd;56JF6vk9pu9~ zeiwN6d2PyuJt440wgHPa@(PDpH!9rw^A&u&Rd2D)y+gHw0l#j4W70=aa@6~>#X>m+ zY@3{D-?l4j8Q9f+<`iJeGMvyvJerHXK+^+X;i)vuuH57VYn> zT~M9*4K!MAfC+Rs{Vg5D?dU||GpRi&nkSY!On;F>uk5TP%QRQjCj~;3p{9PsCuNe> zSv|)5BoA?wdg_$g=Ria$S<9DMY~oS*Yr>ixY9YH(?t(-#(35v#HKH(~04pta2CV}m z20*YcN9h2l+^F6c9{ldeca_hHMc#7LN!MHi?~J9W1qtsVMv^YTQR(1B^5E@CrU&_U zXE$PJsq+Sxp3r^jF^L|(r%@bI+*9|I&@6r%i&fKW5Bl!Ji!-A=eQNWSAf=)NlQF0k z9W>f+<%}Ge9LY(~ugc*JeTB5ZS%)r|{6K;_70Ov~*?r?*nF*Mp4t*){fQj`S%?$P| zO}Jj^N9zhw;@d@8ATq6&mpJ{X7XiC&4=Lo$K!f*Ae+SN_n(78Z0XW3Au-ed#!oLJV z;yXgKAe!rj$3r`}Q*75vLy!NzMh3z=5XuI>k+w9z_h8zLpF?XyJ)+tFSQG(#pus_Q z<9>`HgIIqZ2(BZ`YV!(H#vm;#13Y&$3J7{+DcAcdA4EFJ6xP6AWX5?QY-K8FEL{jK z^tG*YQl#SJn=F80m?{bJS3D>wFcG12B)qu5OfF^>%H3(hv5A5homNpyl76TH9nM3y z4roBZAWH6Ke+Z6`0#r$vJCa6QA@1*>9kXhPaeOKBUw6FgpP zxA3YS93Lz7cV2W&y{`Mr5HD)N(ELL~eve_k&3WljewV9p?6mdv?hCNG7o7gz1UMng zts(O;V+!>O!HB5c@+NoW2oCU%Nat-sKlMxo*^mylaAIOXqxUZJ?sVRnQ`*l*NKeOg zz3(s{$z+d@QF66La zDFBc2%<`9s&ka|EmaGn5w?kq~S3sKC(zt4>=}e{lnfLFy$QklKQp9Cj_0Z${_i!{z zcQp%*Xe@Li&Ig1R#VneTCyU&A^Hw1hu9+PSmG>{;$|Ng~>1;8-Wofpv44@SUqjKO! z;&u;YslGApQ=VFGG&&f?p1y4LFA*$z7K!htQu=ledGT-J9mU8$rny>JZixB|Xm)>} z{hKd0vv;(s51tz4K4Al|$Xj8o(wD?oTW?AmCwZH_9=dkq@Bd|`t)w5(d?V&b1s2;v zDYC*+gS(n`-<+O&09IeK&?WtP zdI2Nd&OYLe*4XLN-rtx+K0#X-a-cw1@uni)#Jrf}{ZfK94F%n5Q{RM=Do@q(O6+?$ zo;3S2F6>JG8WgIhBe(-twiaI|)X4>DxP`^i%G@8r5qMb&C}Glk&51ubtnKTj+?ykm z?U1R}VW%UvJkGx7U>Q1OXk-k^r`((J^2!=ymdU;=h*=O33~aC! zWnHDwH5S#m$8zo6|G5fNpyaVj1X1GvyeuMFD=MvIO&?0E3*MYgo5xIm`yqU6 zd?I(sG?r}y!ItHAvz><+tU4X7C;>pgSWulOyeu(H>8)pI;X5cN5-|Rdu_}K|U}M3L zT0I(@?zBq%1zkMsJ0HY*sp(7jDr~Mkg$h@Q2b0uW5c*26jjh)j?em(rY#A;aA=|^p zNe+a#8vt&y_<}oS7Q4)K(xGBShxtX^LMWbtG)ER?bwaa#Z-4~MmMuEpYcH@BR*X$ zjQ0A;?GQedIVW5(37hjfQ>39GH5Zus$@2~_2>IQp+?59OQrhg!nR5jrFZBRx<32g% zrR#tfNcGQ~z;&wKkD^7d@J?WreW2W424GZ?gm><;F?Pf=ShmI0SK;c6n+#R@?+GZM zX7xlgy4c3Q7bpSxaI)_6iJWo=8JIxQFdlz1y`aq}SWFm0HS0}JUHNLW@xa{y{*3H?(PQdzK)&tjVt{9@5s%?28u`Q8jnMmrtyWXmz*V?iC ztl=Wc{x67iA^Rxf;IpfXa_OIAW?0l*K`2U*8+?pZu~GVLWN#L0?5_BwX@yyX=AIB*W0#hB0PqEo)j$Viu=n9TqAy}u~jYp(T<}T&QbGyn= zw9tfExu*2e0yWGzR~4soHe1EDDKX>B{u^v5=!zD6oR z@TQa_WrJ9`d67DO(-D!RZZzh_#DDrvY^jXofo0O+Q?powF$e*r;dGXecqcmV<$?tF zR`9*GY0mzh)YJZ0oX^Yrro11ywH&O$kGIsiQQp{Eu%^XSAebPM2d?Q5_{*t%>i>O2 zhjP>;m?9XJ^#L{af_pxB8M~x`hYp1eP5&9DN6?gbOv4X7dw&Gi;wW;mxce{gu>vY$A>g0ylH?b%LY6In4e#)ts0#i@wECL#)1iyz^ce>FLgsg5EWXArD zyffD9k(o!q&pZ`dFA)#4Lar4unXF;s->Pi)CR-(xEJE8@otmH8>hC?UydM2$+f8da zMl&$W_^{e@b9$okYxh~L0n_5Gq%6v_#ga#|jiuu-&+cmh(EGwKi8J(xT+XWYks?$* z$Uz)aiuyulWQ=}9To75?zzLhMNpoep_C3zc?E$ZWm^IX*cm0vf;^tIv@>NxJy187y zozrRIT*H@ikF2p_OX|;xZN;wG_FM>}k-QP7`O{%Y{Gk0%o}nwvY;S_3a|r=g8jj{ z6%KqXKYDN9!75Gz)-su)4^@F7G!2}TFJZR$!q&La>ixi}i;gPoFezPF-0ReQ$7SFg zwlb-bu<++ECol&pylg;(2Y=^4stI_au{*x64|jtt2$bZx?1on{>;kqX{_1NJ8T=$j zw4Aq~2vxX?5NayPT$Fi@CM=y^qPF|nX^R26vCe&^8(&x&~)f8u{d5M;1@V zHnw`;hu7|;=%%=wLLt#VaCjwX@L7)eg@7*DwW56BHA0oBxmxoTJ@Q7iU?U#aCZyLJMJq=Uk+1In`oN@iCYW-x)*jN^60e37oWOkEW4Y?(8 z&N32}=@liI0t7r6!8 zVEHcD5^Vf$&Uoj-2$nlFUN#3C(9oiu7L?L+v?>`}wkvvR;%3OB%!K1iHjC>?W^;cx zEu)?Wh~h5Gi~I=bsdg2i;2NaGLsw1jE)r^VbK`k~^ zMPK-Bz8hbkZr;n&h~Sq`1xYvgsPN%!gS!*=>a3=QtE!GB8?woQ`3 z$N(piCwtwsTX20a;~`ICXXaQ-qPD;?+hYcoxMOS^JbrYnRjkNBVy{;m6<3VJJZ{{- z=|V|DYu2o7gGC<06k|%;A$1}g zeEMN$Kh6OL=I8}G=$)1wIRm`=NIRdxgESUs|3r#_$1G}u;_f!kyu_WRY;)@0#;{=3 zo9$QFDU;7e3e~xU(w-2L)}swNW)xmD+dtnE%b>KEMF)h-W-OIX)C!?g6!KI$n64Ix zCF*YO(-$5e1uXz;Uj|nLU%LPC1Rr9u)Va9i74gARp{AI1$fGq65V0q)d*snLQDe3J z%AFH`t--MS3F4t}uk?6p>^p8Lqe5Hzl{8QHa67Aklm^(DIi2`NXuKI($5@DC zMA~x)`|;z&*edOL;1-lWJD6qk-PF|}<~fNOs+#tM6r+!bmiYP0WP7Q^Tgx;zjXg7R z53e*OZt1PpB}9S3{5FZl$;aI)$vZK74gf&Sgy=5r6{v!+`Df2j>*!f{^63yg`Ch-xodGcsQc9Yyj9sRnb& z%(2_i-7g*Q+!*;}OJl}7V;kv)U-;|gCvf2`0a!Z?Qp6q(%LTxz2XdMvMr9fWHG`#nLIBO54|QQR?Af?{X|Me-Xl z{|Dca$eg`RtCvXHT@-|XLdC_30T#Ws_5dryZOFyUj8<MWx}j3o0`ubK!?L@p8w5EEZW=rR19cJbTLtB-pw zvw^8UF{}OjmWLFBY;1r^iE+i9YXh!I^|D2!*});y`h#)Cx0S;Q3Bs?YSNVbvMA|^{ zW{l}HtjV)%Z!UGTPbK zG-ofIB9>BS6AJhkce^k6K&I+TccIsQ0c50dav0(KN+x8g1Yap+A-JIyLd<6SM(ymC z4qwNRouOGMt|+!6cD0!3AY6)#3j;{Kp`|W(kJZt(T8q&8@v$pBE7~s`Wv|h8jitsh z=fmBgpEi@rLe1?9OQZlG(3~C*6_{z)vW7u3zUG%K z@0|-U{wOWDd>erwN=6cFF=FC7;gK+!L(ltqHS!@LKieWMYkC%u=sNn429WITbR6Vq z|A=KcZO|JX!t-^nsg$iNvIBdJeowT_d3yV!S@RREOw$t&MlOtDZicC?{ z*iE&Fh^Y~e@rxQ};6-gu87ws+bvoO@tJ~CLK2rH`;Qh=#fE^>%+=EUYXlM!*&O2P` z4KbZ{yJ+!nT5@hgbxyx$druw|D|+-1AXQBBUdq_hJrTJ+2fc3p(d&B#0^_m-L-+@(u-DL zR~w~&lz?_#CLstW36X?pU_~biRJ8G#R1bS(v6L)ZH-I@{IoTwTpHM-7i@EVtz_K zK~&4sR$RLbE-{(6b5*0R3@s$&@uXA(Ll#{_u@hC%iAVT*sv5;rg^Yu1ax&e_40y}o zi!PnB%0ZC8(MS5$E`0r(mxS3NZ;lWj-1oOK%^?JjHetM=phdzyPeV~;M5vB=Efslu z>VfnSEQovW_d7s2zB);;)^3)%mEN!%07+3jMRU8AGM9kpF0LYPbk}agee@@}?yI?C zY3RDAMSZlGtkck|gI;$4qgd(SS+9Y8B)vy5@)mBhd74kRbBj{QHhn2I{7D5K@XV8% z*;SNEq(;nYr~j^Y$~b$mjrI4^M(_3tge?gm(GMx>EO0Ub-`)X6cqVjOwzp4+EBGN< zW@aIVi$A0yEpe!~qGb#yLg6QoBS%9kG30yh5$yaHElNu5c3<=Nv4!0sx71l;6kvPx zLx4RY`1>cfc*z+`ML?#2zjE=fBd~G_20dqteKz>VY%8q&&(_=u1!QqZj-u`&y=+}+ zV^4q@8y&fccwcX+a#7d7=vgUJ5I%<1*v?lC{mKON(n4f0*_I(vaBY{Rv_%(v2lOyF z6zuFwW1P6*M#3!A@n0pXC^|(O3gbn=PFkJE$#@`qIBlH99XVdjt$ULy;#p?903NGQ zV^3IAZ?^ki+J28)!gm6ouk{Bv_^}0}6DcjrLLn?D>-8wrR!rJdUQcK;e-6 z#kA-pOA`BMLEn??-eL4&2(73&#rFMU!|Y7IC&;nX4RkGV^=?rVgIE&rG=40dTOdr{ ziLumMpl*Lrf`2Lf0VK=8k-&WmKtw+7U_oD^d}{<@q4<+PdpR`vUxZdhK@U#TJeO5R zv!Sw4a>t2VMqX5DBC}kY$o#YjDDZJNHd?JXgu#N7k3sgE9y55#AfGQO4VXKJFlnoq zRA@(P-r`lO8Ie}V>F=4zk-X-|I#L*Y24rKr7#A|s>iP)zDb;1Jo*nljc^wQZrgzUo znz%HyJoZFytOGQ=@7~G4#$Y^GWevG;ng^vxgmAU00}wsse5@+KW-mA=T_9>@GEwdb z8QDk&;IeJxH>6IzU6P5XCha1fii@sr8y>JP=MJPSyqYeufzeA>k5NeDDDGl7 z533(>@`dtlzgt-@wl>e{-As$$VHjr60gS8hXSoGXjrjIAwVZb@iR(PtpzaNR8k4Ib^?+_3|iM29!v7?sPCfJTxLVi0l+ZF2|uBJxGXYk~Z(Mpet^5NtJv zsJiIgeQ87Hzb#8$Piqn)omKSurIsWvvO8 zx{=-)I)Y+kutTVhDpt1>MqidhIDmfqcN% zaljF{0fHmSsLk_CWVgbdrtLQ92*bBd$jz4{XdQWs*pn}2tDwffQDjINjDu#)0|Ulu zB3CuSN5}sDD$^#j8n||-M-;ki^lNC8?)Y^RTd&3x=B)Z+h3k@385~VK;#5wY;Q3z(8C*xYT}CMaO9OgLxE;Efczf$Y z{LzH|a8&=-?<|i~UP&T<&B(Cq1M0ZRg>Grlr&x@wi|E? zdBF1IZjAl=cle8R#*K>{7dy!!d=5cTi_8vqYtFqg2dpDq9aE#CRO%;h1&22t=_toX(?Z!Wc~k82@5#szP+XI^PUp+Ji`* zevWA5$pAhId8deQ2_Kyri;SHR7iXZuO%<@W`G3_w-$^g)Kifjl62j&1?imQNU|@%* z(aGXZB$|z(_aI?XUXMY@FJ*GP?^kV%($}EKuhC1Rr8O5QV+_JmVi2ibn!-LW|d zp6rqLFyOVeXs)Yl0L1bW3ys-`q8YIuNtHlwTzT2%D+$pGq;BeRE%EllCdP7_6#a6P zrt6jRwS4fzLcmDijZ`1^c!GwFQX4|+mW#`Jx%ez6_u4SFXf!mI&&bJTp1uQ z92N#XaLw1@Uu_n-b1!>@%#qdWS2(eVpf<&}ib5thmge`-oi{2=X8P8*LEzU0W?3NP zuNM3ZyAysvc16{W9ljjPAlbAcs(XokBK57x5?|?fj>K?s;dalrGsA1$f}b$meCE_6 zqlWxZ=ij%bI_Sx4H#U?Blqds1+W7KWEIxIZ->-Ll;K$8MH)*QZ-A4 zPt#@n)l*U@@v47nsf|TM!a0yPadbYYCv?rwOor~ObE+Vy{Z-sO9A4x`-`c?=$O*>| z?ypB_yXw7Nv{+IJ3^wEx6DfQ8c7wwCu+HCuMg;#In=4r!KePMM%MU1$MQwDlwMC|Mo@H0p4 zv!2^IKx;fKEr|3vzQZ?7tbssJvR-0du7}*A`&O;|9s{#M@FhhLgvDT9w=75CGM(W| zT1Hhqj>N%ogciF}$N(1Yr9N4&l2wOhV2VnNcoio}e@bU{?n(GhfLgZXh&eU=S1K3x}M_%AkV~EBGn7Ni*4M2dsRz z&*^V>C8oOlc2;&^X_1ez%-r$5lat}A>8XT|lRnKbHum}4+(6y7>}5HLe4ni+;g3CA zE{Ghn%YAvYZ|)~zKy$u->zmO|%B_J9_bdvENP_x(oeJQmkZQbnsQ4QSf!6!J zH;6i^;l$mY`?)7J;ZF&CR(lLF%+4`V5 z7{kWnZw?xKAjHq_g#5Gb_0TCH(!U-Y5MszpxPd~ko6D& zrf}Kd5_o{7GemQ2`#6N-j6T(Zcfu22fP6+|W^(AJ*4&;GF32<{&jLbtGbsDdWXT{@ z%sqGeMQZ4hKT1nj60#tzRBF+qb>Q^|24M+I<27kNxWj`>j&V)kfiBN=o=n-{BN9j9 zctyB)*|`r$?7d25+rY?MAnANh&#-RbP+;Z0`TPwZGOD}h1!#zZ-wJgqGJ?@6+%Lu52`rMKjw34iF;{ks~*8Db9GYb};Ig-c2QYv8D!@A|q5%qY(q zqS3j`;n7T;lj(5juc)7}TP(7fhhu3(TEI$X%S3Z#D1D6!{0W4&DuT!na(LH7S%AU- z)gU`_G9cYRC%D!WCZ<8Tt7oa}Zb>s4!f8r~iyJ~f>6L@Jx6RMS z>^zz^!@jK1wzwft@tEq(Z~J^Q2bC^x9yrUk<7zcJVm4Rd_%Be?b4cD$Rf#AcCBfHY zh`71mY%oxF!YRi$aE(GI)jvVbLizmEc!ru`Tgj5mkp6zRa~PV)h&IkLdtELMiOk() z+|*!smlujn-^=|*k(+%SsCxxZYpyZNKMr*ZMMkVm64f2fN-L$0k^CK%_g}GQeq+`N zSgJS$Y!huDw^K-e_c(1S7kL$Uw|3y5%3~+2I7)0(uW*2IkyI%_<_-7fXi8IUM@ka; zlmNHFjOvGolAV!^TmV5pzQ1i`*E{Gf|9ubGRz4DDm6r=2UqFYbRskqz!~9glb%83y zR>#Ib&*P4DRY-4s_$CwR=HDss8KyFM7wNQyJWog2&k|2@Q9>Cf_H)8+Q{uW0(TT1Z zybHk(uGG0q{wq>TUZyMb-dTqx{CRjxPr;b%xxpkQ%R4wb=OcG0guOnP}Sf4d^E4=}PRmKtkfpGLV{ETyq z8L;Q1+&FRZiemRaqxwYU3A0@y9=X9)2QfWZfq7gMbZw9yS$9|#Y8M`+*oE0CE0(dJd z^4NGNcXMtq8f_FNvz$lS~iYix~DW5I7gE(bYEXa z-z!Q{#3*mm4(Wrpk+Ll(-|)fie>$m7igdl9A)Y3e>?}Z8$39~+Fnrg=GC}b)-pF>A ziwwzFf5>Ox=bVwDD0No^Nh3iTw@I|3&QK-8Ct=8P1?H%fs^|Ks7AVbf-i`CRXJ^@# z6t}3-M0JCoF@9uvKOCZvZU7oGDtM~Za3oFY{n-BVsj_B_Z*rhW*LFisNzqC`C{X#J zQsvx01BNo*_D_vt>pZ_se0g?>(4EZ0jMe9z-(to-zc60}rv;A4Vt{Uae+L#tVp}vO zyIx&uEFZS_)Zfh{izHRP1fWf?+&(SjbD;L?@=j02bv)K=oZTFpZLY=7FWFX)bUp#) zDk7FM(_Le6Ej(DXl_)vb_7J_bS)%j2ciX~4UQrftppQ(3&F9BbX?ZGnqpee}vQ!k! zAQa`>Skazrv)mPAZ7D-xJ@DcU2PHf&^Q?q4X}%lKL$u}>X+1tATy3}5 zdmpxe09N|G<)Q%of6JGX>f|K=U<|7v{)W=s6;amCK@ekd3)xNXqGxIl4W3IQd7uW?J zrP_L@Y)#+E@laBPR#5gtPW~kKZ{pS~qYV%C%g^&Za3Mae&IVMVZ7~o36S||7xQko_ zBIOmZwpR<^$jQfa7m2mxWc|X8giAp5SiVCQl$d^Tg=2ulD_a$u zxUQ2jkNTu2<+7ew`_F&*oD34^bNYdmiH@-S3C^G(9qC#=!Mx~SnM`BoN(JE@@8D0q zm$zg@T|N=%)Tcyo5FYZe=Un%J%^Jt+OJ(6n;=BkR8LpIUJ{-KYzSOPQ zRD3gg3GD=*UYMV^5veR2qgxl;P`F(|qJ%EZH~`gM;G4zHpB;w+JXC=35E5d0#865c za&ZVKy$7H?!4?b7TE17Bv3UH5qUY?RcQ(+I^D+4kT zf@0jxLzw81>ys3>fP!#`b9L|D;i4>F+|fl-RKv0%CUh}MblJYUP8nlCtPKm~b7eU- zAgtU81p&ATOmi32`RTQE`qC|8=$p6Xl*4Zd+>W?y(m1oQY0U;bSv8JSUqW>d?G10h zZC2u%H+~JLI^QBG>f^oKXg6tV1#Fk=!Hr0b#~9gmOtt&z2+En)6>=} zqEC6>xitLmf;d=sv663_jicJf;0Xb$F_3o2mW`Z9_{0p=0D2WxZ3&+?CdjO6k|ze( zaF!mr!rtAZo~yjJOx)uNRb}^G^f}k1fm|5IAjFW#P@Zhg8*P4Y_%Zt_v(93@|LMPO zn4YA`u3~DekKJ^uiU}WW*v-bKF@P0V-+PP0&sZ6-UV^-bm7v04#X)G+T)+1<%o1_h z4OSvOBN6Q+3jdaiePko`AGLVhcVaqS~Ur{c5F8VQY~hl1Lg;Li{%%ChOIZ% zN=wILKD~t{5+*DbuGB- z!pCxvS*{YNOPo6aOn8a{i3DOac{OulW?YPBQ@Asmz5Bpj^X)dUaoi;A*nv~amBdX6 z$_mz#9F2L7P|Ku6Zs>nh0fIn~!a8_|T-s>mS(pN_8qv^_gn3<_eMsauP|1hvnRS@6 zf3%j=)QGqNX_t$l)txyLT}*%&me4mvjmzi(ulY$OxW z`Rl)?F?6lu%7iDEnJWeyAr?Tk7X_YM7?f5aj)7W$A|m zs70Db#~Wkjs)`V6VZB0eq{}& z>%A9cmor2(0DQUt2ISxd1ag4w`X6qF=o=w-Qm&8OxykB^Pl);R$6c##KqdNnC~AsO zG{dx=!2DOhC6YLF1hRUk<^*6bymQD{tDC>NR+VGjF$TQWDKX-(O@AsK;%RI)t?TVJ ziVa(StUqY`>mUTzyAC~PSXR%x9gy}^u2C$!&c3)0u&I9P+56ka9AY-WA8P4dYO=WK zC{|r#`m?Q4bJxpx3U$Q-u6ApO(q+Y}2Nmxb^* zF0dC2Y7tqKLM7TYWN=P}6dPV?cnbEX-Uk?AgwtxgvzH~x4|6u(nFft94`a#{`jfC$ zrRHgnki3dApSIJCslelaOy%*TK_-TF6o_Q#^8;J@UdIp0CEvGo5n_jntHsc=49h;p-g4qLe45T>h zc^o2n@WWiJq1=?wiO;KO3Rh4BF7Vn(Jy|S#=9FMOOHr=hv4qm7Xhl*_rFn`2j*X~J z7Y#zdDH4E1F+p)T13#{Z&hxB}g@nJe=k@+`XX0hqoJDC%S<|&(KcD*b2=|B@mc^qO zmKdlcziW2HPMEz!=ZV|gKs2w={0%M|#r1B2Zl~Gkv3_>?n;DX6_-ec2zSRXgf0>wH z9}Q0IZ?ij|Xu7IUOeYLgg*e-)(ZZUwZ)*odQy3UUcp~tv7A~?%x6^$iGdQqrN%0PU z-MrKMbaO%G&cZRj<8)H5*Xu~P&t6co7EPz+BC!-WcW$?$kk|oX2)-8$X~E$b1;ghZ4hQU~USS9w zHq-%}!0}F>oimO(saG882j-^i&2rQ$fkCzh+jfY66#1tBf_(U;Xpr*5_Ez_M!*kZ(M5bVUNg7IfaPI@bfK)9GA!F&xqDiB2Oh zl*xfF=;Ys2vk(q}380K-bu|eq3k3Q=+(8Y5{ zh6WzAqER(rnfg4z_U(G%Zy`Nqn|Xk4n9qqF`d6X+tbowsfqTw7oF#Sy7YKo9I?X?r z?yZQYd8ZAxAo|CZ*cpc(V&~L5f}7g%?Kb?79VR856lDzQsn)noKk|F?Hj&KYeCB04 z6;IQE0e2YW+%{wr(f}-pPb7}Zby5!257*g%@urmLFJ<^)VE=Y#Ox>C!V0 zIU(w9krS57=rI;L9{?}Nno`YS-Dv<@w?Jf>05vX2=XFwx^ukuX>p4rCJ|YVd?H%92 z9@L4);zw+=)` zu!$zwDDbaM*+R)s;BF?v9~OTIdnxiYnM!2rax})P+K%(Gr#b~if7&N^1KqwX&YwA(0CkdX&*Fb=7=9qyrrBgGKt>_M=t6 zsVCYvBU!^upWTbHH^*wxq@71WmvimsdgbfT_s5FLO3)w;@K1{ZvNldg%B~_#+$v1u zrk5im@s&;35fVd**}u)eCz@?JwS&<*iO|-K@;{?>>t(EF7pCrz2HLFbaC(8#48Dk- zq!-T;@8PMK+8n-1?@dl)5UCTb^?+>VN9}+8#65CU-o`D|jutKT#2t=y>XQl}c(t1- zg+0f<1hj~;4MNF!|k4Df>%G zsphd4+!RL<@m=+;r7GO$%8^Xo$`0yuyp>?m7-g6X-~uOS-N(UT`zSGVSd#FNA=H)o z#*Ln)8JllI^i?|)Dvku4+H2t+*LP%rDM?@fXX>O6<%8T5@jx7av(cmQYSX` z+~qTvIf=X#BP2+zv$zp?-Xn3XUB>^1%6f5cUGT_KZeuJ8%Ren0xJ&Xm;aG6*OM;h3 zDJSc}c6ovNne@SSg@@hd52s?_oW5vxa7GqHWBg@VLEnigR+fJxN6Z`PeCAR_`jK@s z{Y3Zs;R@woY+3p$(azmSSvR)d4L=cKP_Qg|aG?_Pq7jK=D@wMOWUmk&N%jDGuu+QQ zoXXA<{ka98DIf?cg@8~dBv-V83{5g)@{1By27i<(MifYG@8SRDC9hG<9Vi;XQEdN3 z1}G_5j%V+lJCIICX0OKmX9arGAE5-DLoa@|I!>i;m84ituk6I>a)q3q$c)-D9Cc){ zR=H2ug8CZp(4&)?^8gO34K1Q+oxXSV0D<*%CwvBkX4}hWue%Ggpg0f}Yg81$1zFi2VfH{Ma)` zTaGYt0os@Gu1VyR4Jh>teM>SFv0KEL2!Ul*dAy0wSt#UbD^{W_-^Qm(vip+>_?DxJ z%|0#Jp8KQJU&y+h!*nfpS*ulZ3&e#`Imx75$Fb!Lit=P%r>+GZ$1$xUx@@+7`kj4z zKmllmmB&c~o4-0>H`%OUYGYMFn5?RBYLjy_RoseI$_t z9tipY?y(;_o?<)Rr4?+JQthN`9gKAnNsz(^kZ~QtL6M{k8)M{J;4*LXcCs|<(kQU*7kd+ ztpt^l_>kLfBpz9|D(%8T@$)I7$f>wgZa4sNbKW->A#@FbC(irQrq3>50CSnHW-RPR z#+&&r!iMW7b#EPc48h$MKhJQ!Um;=JHKtp1fW$<=eNNPcWUVrl;RThZMczVH36ajiMf; zp>%_pP6*9HwXshaqiPH?#Vd7SL?5+#LTvm?i6%E0$Zy_5sLx6ylplnJmx+7P(WQsQ zT=xDR=!)?J*GC_}%(|;@|ECv^J1C?JE3_>{)wKHG=hX>C0$qfF%!+9;b(QCrQ~2H1$Iq!wF#;1bHPJ$wia7o0bjiq0T;IhxPFY@ zaHHLLax@Q+n$okZTFWU9ENyfOBN-;w4qkMsI5W?X{?-9X!2=Y}(>=Li;9K@7cOw(C zX-Yu1s{funE8)A3c~eL5>HT;S}haz>PsQ)ljw{IZ-+Gmwit~JJR#jgwBPP%rC#!S zt9~(M)5Mk9xjF!?FEPi=4y;Iwx5!}mr16n!u(#LWB%)2^9Z)mot> z{=*J3MPKa~HG|ueYK2^PqG-_785a4a&}(i}C5z-{uZ|jt!0;5GD$*9VXK8E(A}Zg= zFDc=I6mF#qvNuhzz-QyK-gM7|H}QT3`s$z`LnSIYW5`Mt{5$Ug4O0S8T`gU9h6VBa z=mxvZ=IC`)+MdN&b@fL;l}C0zjrOBdFlh+SIYm4mUeEvELKZ*TuL1eSeI+w$Yksu> zkcV^E=k@d%lW0zL09padIVm&p4kO$DvbGQCf`ell?}IYc$PnV*QX8s0$oCPPuwM8% z2?R?onul|^UiePQVMnk~>?tp1J3FYsE5=CfO`piV54re) zV$EjcpRyf7{Y6l=<@IxRyOktC z+0CkCr0J&5Ip%*#Dm^u53K?5L)*i!D11HkH`R%k7q$A2!6y@j9`)6uER|~ zn;+~$5cy~$dz)rcMSui_Fc|mHty^vh7JXTvKJvA=dMdZrAE_PoMYC}bfm}RCcT7?s zsI0Pg?C=nLKg}>C1qvBCL;WUdVKIpANk?8w^$1NJu=wigYcww0`@&Oh#b9OIW`0x1 z#|~wI2Ca?QCGN_x#tJTh4_q&<_@#-oirWA?--x1(D3DwC(D%!u@x$X!0|RA}$q&_F z4wKX$E~tN&bxtAQzY>hItG~Xiiocw`1HiE2rIwReURrJr5K57M!x`UsJ4;UX-|29o zs{fImYkw^1ppBDYBo^nN;LHrF$Wqe~{=1P#JWNFku_snEwF7o^HkfJju*yChb#;=Y z7)(Zp%5!T%$kY+UAby-XcM1Bz2L|gmd88-xj`IX0PSb7_?De8d!5R=`t)_R;aEA*a zo?&s%YFO|R;VAg2pU~=SA0w8tv5!uq?RN}WDj^Sg`-_~HY?FZReJ!W3jF@75xm;fW z2V*F?V$Q=jQ<%kUc+*xpkp!#p=xgyFD*V!KHwW(@W~fsOa$jS|TOw=<3=qB(ti^qj2u!I5Hp}82O*Gla(30d4UP~swm zXXnll35xfQ3zof-jpq7&p#A;w2||ELwx`~MA~{U+jr12?hWec^`LgK= zTwnD53!?FKblF*0YYB=aj5w(B{4o{-oS`Mzt$~t?sfPzWK<28)rO%xJ&VV#*^$`Az z>CACjcAPh@T{B~^Lou%ZA^!XRUk39`OaAF8uCW-qI$=|{SOMZAfc0~z*-l!yM!v<* z(+q>eNj}LxtpeQoPPr!3D99P=Cqzu*QX}h1?3w<}%gLGqkTG!k-IxbA+-jxuf&f34 zs3`&|4GQEFRx#Bstkkc<6wbhN9mSuF!IZv!|65!l5I7i(bemSladQA-9i1;?rY+E( zCqCm8=RJ7qQNNi=J9{#_Q>?`kWs>krI}eAQ%Z)1wzP#p-FZ7;he{OvPMjc>q-=DJO z+FI?c-)(<#s}-8O_it6AW$(xB7J*buQwZ&g$EPvLv8|oKHv~`wp<+Cl9uVXMgiZW^ zk3P?;sR}PV_P3ay{)(cc=8Zk*c710bxB3s~vRffPXZ1D_3`q@fw2x~V&k!&kE(6h- z+$xd{MoVDTsOKO&_3DkvjJ#6;jJ?kD13G3$hT#+eLlP1l>zI7)k~d;tDLN>@bbmxr zn+5z5BWK|}>UGJ;p>-9o)Ac{~g4mT`cZri`yTtv*HneAwEjK@;B3Bl|_q8=bCum_- zcCE3geR;5?Ww*#hFhGmy%3kh5jz0WYwmT4}GyK~a#pCgO8qpLyAiKP~v-G}$^n({B zlJCe9W%`C|N?L`!TUy$i8pJ=&dJ?>D6^8jMU9nbP#b=xbI$cRN{%UTV%Tb{kDu|~E2p2B&2UH@({HQ33bR*9bscc$%0h=MZ3HgWpA z==0cWk`HU4`rENi$IMRDYT>9`s>4-S51#{g&@xrkb_|!I_J>F4YTUqE-sJZ?y_`kf z#f~*@KDz&joe0wk`u-`}TwiyT@G2Gi*|_nFPi?9F5il$9e*<}m5%9r90F+8*B+(sC zWDzV}Q$r3qh<6>T`=fV!Y%y zT^jy7gGgp+u{= zfmFceNh8;{$!o0W@C-eAnE0s`8E7T6cnQ8M-tWHrMd7jld;I%2(o%ju+?DpMP6 z7k2jwN4JHn)}%EEt)uoeBzXtFZ~6S&RvQGH1n6SnQJJ9l2cI$6!)ozS|D*Z1l(Bbs za9Fer{o}scz6~KJU)t?njAcP9x`F1AMr@5aF+g zxv}-*v&GU`JBJ0yaT#H1G>r~Viqu2o>hX?QBUON;M+CQVe87B9ezJ)dz!sZ0K~0_b zrN4pp?%1)Xj`dg`SmSTKlyQDIjT+$USAbuqC^a2F_z6Nxj$503m} zb5TLar=-?X2B6WY0rH&8ER=J7V=Y+=)lX2E6@|zd`qTcBJq0VVYaY3!H|jp#TG8G= z{N_gCN2AyX?4q7k!A0ld;$VjDVeu8x)zvVTs!Oe4g#KsWYuv}<`D?E)q;MFlCF>jd23AmcxBPZ@O58AaAE}FO zu8@Bmv`Vq~2smdyG^DVCyU6_nC)qZtD&#&S<~Y`f`?SqTX?j)=qzipja?K_nGmkRr z9!&G;h|`(WOvleca}BEbid>hcUR8qrPXZ$8_(`)Xr8(??en>=bXrB7-?PXQKvc{sP zA|hjV+k4O`{6qm!o3LJ5j53K|GRo=WvVLBS(D5l;EBbwvuq??LLK4sS(f#F85u62U zXWWVZrNV|+&!ZW4<42Z0&4P#mT!)Z`izcg;n0t4?{ELVi6;CTeD8*q_#=e6NM@+%kn&>yOg2{5D zbc!w(tiOcOgi#1(K?{K)0@0&`$0*3r*{OC)7&(G7R?0xQNVURP865g3o|6IwhjAH4 z+jT&J!#N!p~Pm4831)fsVgIgmyI|p0ij20gKy~e_#MBt&{5p?ubJElO&X~ac)|lELAulYc(_){rprC zXw4+J0V&uO&i*G+JA&bX^Tmro&CU6ce_LsK@A6fr7mz(v_8cbrhb;DNC3hl_mEjuYl6qumh9MFhJaC1KE(D)gA*k2EZLpE zc>3qTShhRUDlOhe+3#=JAYy>95#;d^&ZI!l77F?W82u7pT)v!k38Wz3Hw_l$@e(;) zKic2s9F~6w@|p!@&aA}t~7BP`+u`ObEUsFum z>LN$sC+ww8ASu3>)i4;r@Gn{GFg;Bo;?$k1n5Q@67@!Kn8~`Cu!;9zsn2fV%gqwC{ zJHB1~4CcuqD&eyz>EKEF+uu{uq3u}FQ3&W5ahYt>Lq-RvfVHxC1)^^0$SuN6=<(0f zN0W#m^reH&(6c9T&e^r9>w0u^`EK65vs#vxCk__uIOZ`gbi$I|*7i5&Ond`G?2S6B zi8R~D2A(gDags7)w|*0sb=n97WT=Z;T!2pjvNZ~djW80Kl}6VH*khO zqkkZq{}!7I#Gv91MmuBXY2_%a%x!Nj67>e5L3ul@t#JYlkYHMq@M52P?bGnIY=jbK za?C_rs>?VzwATDn4D+&~m_5vycTym}akZ~3 z7&fW@R)O$Sw&ph#(-yfHhLk|=-KmqHNzAksclOAOuuCjJg2$vfq~-30vON-?95YM|isk^;K)w#IH!5+=RB{JQlA=HA=k0w_V-;`sZLilRnQJQRQ6us&XgqlGCkdK? zs2yBYg~G4gVmPnWc?&*!HJrm57wM}_qH*?0rO;k~D>*aK`r+P{Pd`SK@KI6>4{-*ohga1a^1kQ?h)h)#&gp<{FmO2pp}X?I z!Q_>0NPxLemdY{+$gpsO5fU0A;o~j zH^uSJ5x@!&h!u8PfYGNZZ}1Zi%3-Vp`~I4NA$bjy{( zl{p76`QlO^S=JQ;c24_pi9uo)!3vE~?u8tgkipqx=N#*e_&YyGcpVA2_zmAy*mui2 zLqXRhccbM#vKWH@+Wn#Lj{=6>2N^QB$8jBp+8x#I+4@mtzY-D%f6>5`vx^H$#&WHC z)M?HEAM_q@)0aGtxTtlBrV9Mgd^`mQh_l95HDjtu3s%rD&9M~p$f8J-;Jv*0u~gZ8xUEUcX(f}H z1jfdHk|30GL8O zeFv6aYnYfq&%2H{u_n)7pN-1qIln39_*Hllk)Fds>$+V_ZdgZ^Gh;Ab^^x+-@%N9$ zf!Y`5Gey~=&kQ(^3{Q~`bXaDHfNq|Ttt3A$$I&q1gQVg(kZckq%y(S1>Ia_}5An38 zfvSi_9`k@ctup>ICYjI~HU@yn_l#wlQ)k4!EKP0%qS`jfM>N@g%nqlxHDM&v(J5kB z2*%o|yXwsgPve3T6-r1da;#h5_Uiwc_$$bx1>nF@=jOh7J^5sAOK5``bbvzabl4F! zp8ThIWS=nUTCy=ql4ODdZz;zcGJi&IF*mu^?5AbP{$Ac%Wd0g`We8Q35a8vz6o#WP zh;SWX##Hp$w&*#NAVVk4YAkKL@iMSKs%CRO5Zgu;C{xFiy8NB0qmwb3^I>#f z@>w+Cs$N~Wo@bARoU$*13f#0)q9iWcuiX>08#}9=m71QBI$^6EU^z1;u6TUaRqzmN zC}F}3uFRG_u<`6WoT#2h4S)`N+--sGe%MFcev3wxk}bT6OdS|#8YpE73`0w(goSqw1Y`fni!c0T=R{dV7&?KX3bx66!k!nwmY~a)>*LpP|6I9(7KWqL!-! zyeVh1GFHGCAEX~L9^<;d z<^3{TQ}d;r1tCPTwiRJIi`Do1gpHbozHeAh*H{%CWYy3;`3V}$BNFNk@&FHK)x(H{ zL=bww>#I#R&(6eNMRK@s_q2;5S~qj(M)#~fR2(0)-%vPfSW($}y_A$rEH(E&{HVgi z+TP-jw91?B$75kTRE(pS+c+p3YZGvWOuFrF;GR=+W4c~r=*bQ33Lq1U7P5pII$Eed z^3`~J)SI!5%N^8CoJ-I@sDBTSe~^0W5X7PW#-Mu_XsnzNu;X zE4K_ujD!~48V=I58iu(#OVK1n5q5+Q^%iv(LlT$PGuwy#9ao(B(-eWbFo927p^mWr zs@Ju9KsSp#ilg`CG8$WOW*qOh=0&>YQ3psj=i<)Pl1?QD;(AQ5N@G z2Gp{U`wDb4FR@S~53HPCYTLO6F?DHuxQRo5+lvQQYKgIQP)3V~ke9s_9x>ql;S6v6D3P_?@CLAJju%Xf8npC~>$S?l zAHiT+AJW)(!q~}v?F+7ITSe?OXTq@#eqD`_4tW2kCFqCS@j%ow@}h@T(=VguOSNGk zw@$I#eX@!moc1U4nskJSRrdnD+(C>}ge+Ax4g~f8+_C_}RlmT;hT>2>j1Y|T@UYlr znxL6UeGlrsYbmi-3~}SV&ycSrL>2VpmDCe^exQkxr-s0~c7KujZ;C*qi*zcesc-CE z);BrQRL*^jByD+XJ48v7v%_)9xFzau(#gfeBNW{Z(&Y7VL>4x*gUo+OVJHP#N#Pv5 z=l6*eI-w?+em*1P0MJpXKS7G}&KHim&Hu`P>BiI=d>o4_?lBGL3Vk|)pJvqb<5;2$ z33LH~SCTN#MIiw}G}(mOil4^pm$OX}paFmZflf~8Xe}l$mgI6~_Zz@xnvvda_Qpil z^^~H32h38=E)Tn6&vMM@h?ETbidkouZ>74y_0@1@@3Tfk&Gu`=qwrPbEf_4EOn^AN znE`0OY3q%iWMfJaF!zBS$Z(9Cwimc^#S-B+r@6Yq?m0XTjzbI|yvuvafg>jX!56t< z+I@jSWJTt*{M{Nwz-Up zJ~1e12cC{$)L)K!Z^J>Z({Bqdk?RjUQ|o97}u>wBqA%1O=MgNIwa?}9|kPAWm7CVG$ zsK{$sv|L+`#98Z^{SA4ZWnk3&vB*1}lzuIT<>(>%eg!Ri=~%-6YCJ_)9TFkP8hxo3 ze@(m})LGWDNqX<706}Bm-8!3+jVZ2FL31;@T9itQ$fg%JgFYbXQqDr@^ad8&`-WG3 zif9-n6YZ3(1vZn@VKM4V#wipEmB$Fg>Z+@88t?kWGj^+Pv9|rTdlcvUJMjbmDKD?X zZC>VR9g_g1l40s3=v{eoA&>d;?Hbz2g;GW`Qm)B?!AAa3)pxw?iRlObX~#@uQg<DT$$Z2#hEpP}Yl(?31^B5~L$mIE7YSELQQ(#1SnUQP{+suo1G0YtqHzhL z_NZJyXL-s5Lp2mTS3<$U{W`A2MtO*8&LY~e8S;=$$+m6{9=lE_@g}vYO_G-T$hpv- zdl@FD-EBCGIcO)TRq)QCw_ww9-W#$`!`4TZ7qM5pU|3~^{-mJiw_wbk@Q3}e^lenk zZgXt20>T2lTb$uy6ElQs;hNx}sR0n-I(Ik^^);x-_nGiFQKEM-A4KtBflUZ9!@ocE z1ewTKkp{JyheiHkqP;zUn>?I0ccuzQE{l7|q}P3|-Uyyq`Q4{nT6<75Gt|m6tb;JL2s_J`r)Kt-|VbKtz0V{T48*(;R60eQ0wzU<$;r zudpWvyx=3AdJFBHq{(hX*70w{p)C7C<`nX(-mb%H30BJ}s`?{+C_ zPSmmt4R$Vd;mzG4i?lnvRheFh*b6(KtZipsrRRc#Y>`51qU2O^uwP>1@yJV_HWsk;D%a(#ovmC||2{ zhkc7n@4tqRng?z%xL+ivhcg{s;Cy>Ca4>hU*nR2(aWVIi_;?><9zhjBXn1lY5qdQ= zA@a{7cVr{$@)m)rbhf$yu|mR{8;I5e=EqqP^pO5TpwuB@Bu>q!$wVmQNoN4E#0XTR zTAZ%`{TWz665f_7JF{U@uRmuO-|El3Yyg-dV{*IYHFv) zYb8in8r18ZyT16Tbuo(Ocwrfw1QLum1qn^(IBwS(4*O>~BL#O*h09z?k8$D;gu$kJ zkIyq9!Z%i4^9I;?I?4%5xDeCsNNlK9fC1~|v&Uk$dLM2Yfg($i35n3}s+!t8_*}E} z!EiC1A~Bx5RH1|aA%H1t5oo05)=lR9L(D=C->vn##D?@!8RLak1CWxOYbt2_KlX8` zfWoe6wOoipgk$QgtAIp%;0an|@uPtns|u>J4b&L3VRL8aj21Rgc-fd7H>*Yb3ey$Xo#WQ%MHbGqB>kYVFIAxO538eDhI!*hwnkAoUr zT@)$N2NPygkS$=ixbrPQ1R@idCqr`b;NP;t{MI3mPI!d@NjB@`V8wjjUhXcP_M;um8 zIeAq2q}O*Uc;~)wDqJ?X#qNF@eNG*nqV-4{~)SdZIhMCrk2hvE9vk{sRdS){{>zys;hSe@)^p{% zV+BLgYz+RY4t(V$R;qG)1gC2zyjwp6xU&vLs7S_`Ii=tohLKVAx_wWMY4;%@>Bq;s zDrlXRLccQu1pA_11rgIWOB4u6f4q&1aHW^GwP?oOE!gv^sN6)z$uA*~_q??NeIRh6 zYUw^U(F;*@|)Q3%nuOTDi1V+T>)_q2uebs}aPs%;`-u;HN16LCS$hJ%9n`x%(0 zV5()grMND9A4wA}nVZUYVCQqASaw=G%P9an>FOWw40chYN_4c}l+AQ1jc8I7E}TM< zb-u?P+r&fqu$Oel_wa=GScCs^Camh-3slzKx1 z8i5TYF>$J=D|P!awOp2&E!|urF!nlWqI3B;CO9Sqo)G{qoJoQ2t;??OPv6Rsu~}ua zCSz5Do>r7A<{hz{CZJnVUS^TrqH+NOIbBg0gIRbpLW+3II~WuyZT~jYQp`ee9Jm#{ zDvBC7wMeI?9>%+36go5gD&xs~k@BPB7xW^?w0}KV8;qW5S%hSK!GPbs{OIKAlhu3T zF=)k0bpAd}M4kQ3P8fwA;l>Vt$ot2pSQlXw{ID-5%>Q*>+&U)OOoWE4hKXe-dQWqj ze9yn6xBLXX;!_& z8v`OEYxoC1I0KPq6RlWYn7gl^LkVf;-1{qd)wCX564`EVu_VREg_akO{tzCVy)=KE zIfDUVEmpddS-S3)=HFeG!H^_+RM}NMPs%JTZu-9AGGD1LXMsAGw-k6lagQTA3C+$) zZ(}l(rE36@c~KQO#D1wknYf=S4Awa;X8b3oI~@IZF%U@PaB}YQn*PZ35mfZ@9)3S2 zcIv00@r6)RJ|u{{?xD@&Sd0iy*|rVYas-;v>r0fs=9X;|7u7l@T3t}uKPW2)S%UYJ zi3^Rr1;cd4U>E%&F+u|es&aLzfTOo=?PQjLeToddvVf?ceqaE1q=UFOLD(l1Xs-{Z z24xpzB2V6VfF`f!?SsP6v|H*wNm;U1)%O5xI-?1niJDfsTwmlL zdcnA6;IcgfAn>>Eipc4JGUq)p?KVkcYE8k|`bAjOZs$G!GIX8QM_%Lhq?&HFd0?Ky zfmC=>ft6G=&;)U9gbI-)R-{r@Tzh;#BFu}TGIAYWYt4n6y>pZ;L9;Ko+qP}nwolu( zZR@n%r)}G|ZJc(Wwr#tozjyDQ_tyM1Gr3pnjEc&vh+kz@?X@c-Blt`OX2=Moqq{Og zitML2w~=0A+-Fj>9~SR6Z2HYfZ=)^JU|YgI(G^-;#l&{vE95#coVXzk)UuU4^jgE$ zSC4#QSpTdQl?Ms-O1ttJLgh?%E=M;yk9barYSn#tB%3YXLZ6SCtxiJw>4!LH4ac^B$6 zmWGIiS45<9$cT5JeA6awg^8QwiDdNrsKZ5yfI~%{6srM{tdJ$R{=x&#W5(5 zWvtaMV2rE&Y6CawE3(9QW{Dp657Q%J4m|< z!ka&3+4jX7_sPnNJ|;X^QPBcrI7ZFVvY3g7{hPlU^eQMQipA zJX%GUoy&+ot4}+}c=84A&lP)0KrtEt_4a0PZ*KW-s=BD|oy62_ONZv@JP+*=Z4yb> zk9%5_7Lh=v?e`PF=U>#trJ3tn)ga!jf(z&aPjnO48?ba{#+_kqFqnu*kERVusEg^Q zg&(C@t;g#iZQnvLor*}DreBW@P0Y<>`AdZx@VInD>tSp|_Hu!*!|XiT)=2$8 zIz0Hp@v`!mv^$y1`T)3ZEzcHy&Qxr5B854dWul=O9V@v=I7epc+Cw7?kjqUix-vrl zDGzYF8OCgpdG&Q;vK8(J3mx*XJdI?ru@Upd--8b~ZZHps6`%4o_HDwCuO!}jsCk3G z$yHoef0U-m2AjMkiUkROd5%?0Z;17C)W7zl$yV&_g+hfBhv*h6_=P)OjCg1~X`nF?`D0bT5iMjT>d$#}n1v(P$`(vzrE z(y4%_Ik4@(&ZYvjCs6aEAZd-D)vPARiaY*HeRt;o&-;9_X0fb!oUDe66POb+oP|eg z8IQ5I;s0vXak{)*N?AA(X(~;=@ya{`A;d%WFen5G4FqLnY zue&b$&J=#0X$)qq5>?zi@1AA5sEf&c&5xTWQ*~YKBztgZE}csy(tss1C_>WUY(s80 zMh5e7FGN$a)F+%3U@>likiCi4tA~SxiKiLW@kSf8)EJl&OpAY&d&*9r6X(C8(-~*L znLI7^7jIU2HI~R@uy!7Zy5aZIPzNdO(f1J@vncVAy6Y|QzjNff(&hjnFdUI_TATe? zxP5zF>`5aW%Yk}d;`8XX+761nIz+oge*o_H<2tkfroR}Q6A6gYPOKHPpK*N6J=5gq zK1-#z%bD(U2v*m5So?zLe zAfK~OFvX?`lI!%jx^MZ{{Wo-mFT9C^8m%U zLN}!YeoBqTz@xy)td|E?-Y7>vl6GgU#hb#`9-Z_vt&v{`c~}i;$PeZ{Bh?LZd?XLr z?mrTTlGPy37&~rK!BAoeV-E!*1byv0KjSmQDIqHxBwif#JNRihSEKr_N78rdB2WkZ zDMKF-)+JrVylnD&7c23q2x0vGd$J>nhHmO^bEQAO8&GII1=rE^C}Jw4D?+F26n zz`Iy|4t};C&tv`97cRb%Sqf45-X7C}2XlqkMY=shziYPz*!g8Z_;BQpF#LcEK%`_AdFsWpYeA1~D2;6%6PkO9kh!dfhn`mMRU zkwip&f1x7)&bjN?!6RD=`Cg^9hTinl+hAiS>V$@VXHTuaJgiflB?VsccLFlV`IRHI z#oyg$hpcx?8zWonCU`Z=vM7>vzXN+Ha&n^JwXnF;f7OK759EBD>&2JPo|O>hnDW%g zM>nwOIiI*+S-_$d|NM0*eE{Q)$?n#=!WUZ1eA0^Soc}~<*@cMh{xSaUjtuG=G$Y%Xem5=2Ia6LI zUQB+`slfhoTz1zT>x>Z(6ol7l7K+`4pD*ls9)2mmL*;mK><*z%m~Muz^K0w^LofSP z>NDjEeK0!W5%dpn&cjmH$qJDCtcM#!F8W`l5|y8)5E9p|K}VYXwx{JMLX*(T*BpJ< zklXqlo`#!`-o2eMej4$giS@0Sc8BUDFs)SSBg4yI|8&)-fq$QFIjpI^ZbI{u16r~^ z1h^3A8l*FgM2;+DuU1YZfd|;k2SW;=VH{k=g4D*`tHS;&8lsRLED`}aIMKGxGFP|_ zq6^#jVXNQwD^I^c?S9PzJ#)^KTw?ia_>ofiGm_v07GHw9Yp~#QSN2d@ z(MAwaN9EuwyZXM!buO$fx~nU9xbvo%kqhHq@EO)WSFZSbX{Q4(;KSJ=jl|!PMio=J zpS_2inPkueEB-g@A>$1mZi)d;p4=y8fpKJ?wzDbNIqeK$8HSV=nmY}*=`Uw>t3ZYW z)Gw*gd19!^m&(gYJk<>LWV0(!UzpyMFpQCna*)H}u}Cu5^~_PCqUoa;kjP0YTy8#t z9daN%?C(#!=m-|U8VqCJS)1{BJNpF194(F;nyELba}?OzsD_s<`me@S)sL^qjpEd4&0(IWnutrBPS-;13tVMY=&D5dg)~@%!q$3bdeF%20le^uA z>NwV+?+_01ic0~%64zz_sXsL7v0=dMT}dSmc}MOLCN12iIw1wm`bgfnQ>t-duboHU z&DjuWgea-zW{a0>3xWz#l&t32MsjD>K>asJF% z^eZw9LK%(gX|7u|R^ymGk6wxV%`7q)u2W2Ypm$KbaECN4+~A1G-ZCDw%d#*uedhFy zKkqte`U4W7A^yO))>e&v3q?*>N`dcer$v&pMIF0V*Ouuu=baq?5^aCQ0- zE46HXo@(?5RAnU`NH_7hI%?$)W{p+#KrB!swJI2b+@l@U;)0hSZzhSLl6O*l8+)kL zb|>hq-l+|hYNtZB?3zHU85{^9j-AXp2H@o`-J*^<61j|JwM&_+m)zAg`9bg?(Z0W% z!GUf99C!^I=kETv>u|ewS{0tUdo=76)nFXB0VLx zv6A}O!yf89Rpb?sh7-;)-S}10N#g?Q$@O-9K~M#T)J;`Ti4o6niSa`i{v&#BM0JFC z@P2jw(JfW4B-vrcAKw?cN{}(|)A=xLSP7MyR=a#~;N5badn#|nAr9TJA!BWLPA_uo zq^62UejY8>js9m~8hZeXlu~)yBjoj4cFciFYx02h(Efq_#!7Fw;x?BQ-FDzxVWC`WPxyVf7#>Vwwsrx@T)p__+fkMx&`Qtnk=|f zxt@E|7w9V=>8V4}QCI22h(V@b6w0h_^anGrn(U*Qk6aX!73by$REg_A*-qG^-#r>ye&@B_1<3+l7aX8(nktByLA`+M#ElYJy@N*l+URbn|PLuweiK4IKcO#eCZd4aMUh%gUxo5&8*9}HY zeb6*)g`cpN9Lm~%H{UBvo+*Q=ez!^Ibz3gP>lOw@vbR6NwG_!uK=cnW1kjFXJs(IF zk%&$)od?r;+*-agPBI8i(Z<84un?*#)tMFhOk2T=dlLQxDEs0CQyyq#Rn6m{^yr1s6eNr5NT%%tHSk* zgsm(-%h$N7R*%XnTvBU}cn@&ksbHX(5^A~SHlm&fZf$|(Rtz}Mdr4*_SsmbDT9PoP z8x4@ZOvS1nM9YA+P<+?WPS$d1yYPj}h8!iggqe})zIT!H#i`}Up-3cQQ`bJ-)gx^h z9zF@6O5u6irTR*)ZTaG1w!i5Kzru9Q_XYK;_hZ#P>zrEn1$R)5hYz8j-GeP?bdaiE za8O!q`5PHkgqYzIsQPfB*;pgS|Oq&FRqQ^pBWLAw|z z?#1Gd26`190EJ`WKUMm)mTYjLP+87kQzTAifspKK)I8#2>k5rXb8PF6h|@Bh^fS`8|F)P1&W%32^0 zJ5K*@G-qD7WmM;;KjYSP--Y63s5m()04SyrjcA^0WOBP6o^F-nbV2Hkxv^&BIA|c$ z*cdf|1EyK0gj$yc2voP_&@6J+U249$(q~-U)-bzOHUU%fGjgxEV8DuK&SP&aDcD-To=ncWNQ|-U zCQ=q_5%{hoGbTOm98qMLJv`KS=hSz}e%zj%6A8)t1h@n7iG0Vnf_Ed#ld{zO5@mymimO}|+7*qeUMeNxrU9hF74(YT`mDzt5f>gMV57W$Z z6;xN9jPG$nIJL1c43V!h#9~eKOt|X4zd_Ks8|909*1~I4JJ1>VT1{PipYu@}6A{CJ zA@neG$`Y2}i#hD+IY(ytSQQ?qg#Ky5I>mRVsU;*t17`pO=G7k{VoavKT4Z;fNU~*~ z(ISn%E3<)sjQxi{(ndPzR5-p~jwn(R&T03pQ%^=IpE_mIf#clze-eTi?^ z+hM!cd#<&Ykzb$S1ez>R^bKk(B%WMK@c4J&ILp`zu3QC?87m*7mMl^}5&1E=N*5CcN#0X&6}m zMe22>PkMRZN!Ih$WpwthZnLX8t2ZHnfShLf9HNWp3HgTb=y6#`1uEkN=ewSpyy0-> zUlDkaD2V)AQ~;kK1vlCji~H3t+A71ItE6ywSb`8n;N#)ze4Dj1W>g2!zH}el*gLE~ z{3Iyt^04YWL4qo(#x;As@0}|yZ8jw(@gpjXs_oiSFsg+9f=R3U@2z7;xGF?o5biSEj`y{a#T!|}7WO3TIS z`SK0kJ2L=Ll0#OM^3?RL_$)7acs;HxHxC7Hw>#49J(83ap^Z!`r-}L@SYK)^>qum) z4s|pnw{zyRE6m8>sWd~;6ubPNh~WZD*^yukaFBKWF+{Sr>Ibz#?F|l7J6U)iGGCgH zLpou4WRqN_zfH}uf08U1hVt}^ilX7Z`Wkl-uyaFI*sB{?>obxn z1*Y-UTTqZv5GXx_kNQa6R8*|TPhMOg@y2y=Iv22o(PZs zX1L1k>1uCVSRH0c()k*cwUnG7mD*f7q7hm}sr4S?gS<#uGGyQ zrb`;PFBp0ESYQ|-s@yXxv}WvQNgUA%x-C~+wyu+$ac37vj201XaCLs0gs2c z<=@I{Iba1T0pXq1$Ra1^y5>Ywux*R%^b2!zdWI0~=a1b5(z^pkd2k$Gb=UcqdjHlA zIcSaEim3Cnc932J&O7XN^m&zO_k3FDlRN9jFa&568*-Hz*Ge}x7#{k;-?04)FSHK= zLeqAn8RIpeCwjX3`{G@K2`jWmoOl1SjV7ykB$!O2IgcwqN^A07Bz3=s^t_XOYD+Ft z{9gs_qDJ~Fb+aXDU`xu8Y?d5Wn*fW>9^K0fmG3@9!01SAe=@~9`y?4Qz-wSme*18M zq3@g|ah91y5h9Oh5syOeU>OWn-aJj$0A1HPwp_CTT5WFDB}E6Ig5Dxe@E=`6UEm3@I^p_(@r3_#!EaNUC`_Bk)6-Tn@=eRTdC z^l+ugN`Yot;W&vE3ARbK5T8End%L=rYzh|6# zSEOteMF`2VEQ-8NS5b^L3Kf{8)n5B8fK~AfB4lY0+*FuW8_0<+oS|)E^>^f-8pr6O z93AE@=8C6~CTPoh;vEQu?v-tXAW+>((4fJdm;)dyS5dRuAal53lwx0fvZZ!^if`AG zzuiRmCUy||56JHOK4UI){RYHw%D4q;GUY<5n*}OM=E63)BPwlht$wg~ip3&`aoG-o0EVyFSBtN>FYglSnS) zUM#}mCC}Z)ibLo7qMmU{+*v=@UH#t2~5As$H5 zp!^2-W}P#V-vSVyttyiXamOes2`%lTG&qJcSaX>aCNgQ75-!FTDU|FLuIE$duT7J+ zGEf-?iDlN5zhOAe zZ1iq#OXdzTF~57gxr~66dL1uZ&ciPaj?*Fc7nd0X1+$PJ1~qZS$V_#Q6wJ}gnESd= z$xTKl<3VdB*^%gY_^Fj?5uKJEhY2QhxNJO=?h=jVeIChYb3>2Jzn6_gJnhc1wRJh` zhCC4_;9s#&KTAUUrCva3MQ+Zrm*Mm{4=`z!UxJwQ@}<*vw4Mj`K7J!6eL1oxLYUMs zm%XFuN%53F8h}7SUVj{tvp5Aa>NU|Sr=m3%s#IYLI2(&IzCYZ*MFng=c$;2j?||A; znIi0#3KyF7$S`F<1-hwDs*jTXo3aa6AxspAeD`of?pz^ml6~K-88%9O{QRAnrh-A-UnLL3hd9^!gJ0<-W=u-8O3a zXF)Kb>W-ZOe8($mHW4A_u_#i})j`0RxEz9oVSzEPE5Y(HM#d;G@MUC$%sYESXuBCk z7hXoAmZDRVao~Kgh=@LA+*9E7i_^a#auf-L;QI4%S&MD`!sZ)_eK%&7xB!2X#XY%F z~r2b{)}I>CM^Bz)1-4CWsdCR2oHazeCVFem-)?#hGtF zyQLZflf?-5jg^dt4s_KOya*{lXCdzCQqNf)*E3=_}JZ0nJg_LoFV zV~GxpYziBaG6g@xL8emWRtb3o#-FXTC1$QdqFa4P5S_SVfSSY0kRGx;2v_TyAm~0r z%HsF6=AtuF#*GjEuZd&gxN&G&Xh9SLgJB*m6*|2KWRY(x%8`XD`DPDuGOw4Z%hIYNTF$Hq`)*b>g z=GkZ(2Ry5U>Q`dUR4zFIPk|LIF>MZ>SNO@$)p!wf(Z7AbY#A@8+5yYP0Nm1BXLzFC zuNoCC^#@NV7@)Cf7GUBPA3wEry} zVa%mj^{*X%TpPuzhj_2RfBn^f*$CVY$`ZswDu%;#JdBTmfC)WQcg(o#0SLsS7_~9r z`$pH)fvAgOJ9S7(t0nrkrvG`&*&Vo#tVDcAY!^87CxE;lxfZjAR>?S@n8&Qb@9#cJ zF|W^1UUd;k8n2Ip?QOc6l&epD>>|T?%q{fU&0`tg94I*gE!*GmdJos%L@W#kI@h!U z{j=9P;JSgAj1eb+E8J}lIu&5cphx55fQHHs=5_APBiuD2_tx3Dm}|@{WW4=sA^L*0 z;pq#pG=Gd*9Hsh0L2I0!2b0D@4j7Uj=b2^F9MgcAHrI<6ylbG^%S=BT;jNJie39`$ z5@m4MTn{%u2F=_oy4d#XpiyWTf|rb*>pGSEts=4@0l&IyOr(A&UumRl@0v_$7|UqZ zGCJia!Xn|ACuj9u9@_@?aiX+G-wmwE@~;qE%1lFUR(zU#NHCbx&{m^p8g~{~h3Bf? z<2e9sqr!F(CIPt7?hv{SdJkXAc3-MIqvm=XKf$)n+t8{souiiV+!zsUkd~fx(}1$| zL;dithzH<~)ikxU;JGWBMQ4(W^DtIi;eKAkH}oFYQ9ktC*p;fsXM&`tH8mP z6Fsxp@;oN=4Qh;DS}w>1{hrgl_;9zO*S8JJHsP0w7@>!%f^MsYIP>Tw3=8Ik^OHHS zi|?PqgJ+-0C_UOKuB6wWty?ka8RIsC>MAS?l8qR@o72=(KCJWDu#l{+>K+vs|+j(1MNdf9F{{Oow`H?sMf@eMcWm349_uQp+`-a}(9MMt3?n|XBYV+fW{(3ZaOLD8u&nxh5+X-q?< zfbjMCvK1$+E1h+@VwTqEcwEY*4bN^`*3=pnc9g_4UjL<*K@L9CWUvHc%$1b+N!H=` zDtz#qr9$YVQ8vINTl&;mV}JOX7?NFz6zK1Tl*sbsb7oKG`7={22{kX*>4iBT-T46| z8a(uJ_lo2WLS+;!7y6#;7zWJ`vOK0)8P>v0V+S zuLxu!8#rj!NuovhfG3#_<%E5U9Ii+erl^HN;7-&E2jr!YPHNVo7b3N<#L?(KC#CDZ z19WV&JM)K&`$fH7e3>cxasQksw)ux(i8lJOcX59rrzMg#SQI3d?_8x|O>NioV3e#! zdNrROYGg!pBiCAlTdEuq(Ld398^7&i161u++aq4NhbM0AMN`B zRLcL^ps$%_hwkL7ZNiZ@DGMPz(cLa;_NKrQj)x?W*GC zy8POVj#nh)`#G46O&VQGbZqdV5%%2e;+4VguyEi(lN?a88I%0W{CdECFHHIMH#jgD zg&+xHuF~x(M||mj&+@|e{NgZJ#$o^zdXtZMw4fPLa*{W{Lm~C;u^ch)LtzlSSzca0 z1tGH|v)vH2S>F(o~qboN=t?@$*N^hb#%&96|9&}!P0KI*SOb5D^dUF<4!U3 z6_Hr40Hf&RBDrYUtHdg~yGpzVD?{CM(t7RDJD!Qn8Fzg%x7l(9;&Yf(MmET6bA&_~ z(2<-PJNR%has!=-@1$aZYQ>%tv6A`B*d!0a-6%16~C3> zmHgEv(_KIha8$tTz}tE`frF++~w;UsCEJp|IDH?xONwY#8-HIMW9w zSQ4~%md9}amM(1?Qz?zvo)lf|tQ+W{%m)h5Eku5IHb@1$RuEAxz8wqYUDErYBC5q4 z1PR!yCj@Jlbmj$hC?W1JZkL$mvBX#xR97^Oo6p;lhv9md9H1W(ATrz`YuL#-hXOGi zysPn;hey4lXv?K{mv$|+rBJ(x>Hxpi7-|*00cjTS_V}AIh}T%3JH?yqI;=p}=twwZ zrV(@>Yq7KaaY+vyLZB*3gGe<5Q)nX4VAoXgXa&UsTcR_b{PZWB%ebc~ z^Icg=30S$!;d9`=hq%RMaYmoZ`w_0$hrGtWGm|00n2V%X@NT2cEiCD_$pMxL?%uJ% zf}8f%%cF(|jCV~`!}`PUPgM$fHX4Jn!2}cvZw5N={!N^A#ct8O05~ayMPm+D+7HQ; zd(;B;OAE&qWPQ^iv_H7+V_D5$>Z4q!x`+zwlfR{@e04?F=-O*n5P1-U(|ZpYRw2g| zx)t(3qG&=HV;*&P98X;Pli5bHAqC@8LvNRV623nfuWA+63aHt1l7g=tXtg>Vf+;Tq z)pzKQOr;NzeIUDJVC+;l?dkT?vG2rs7=yVNwC~Ahx1;%X&l9Pl*>>q`7D59x7>=va9LYg+lz$o-O*9Nj`T8Trs@;C&>- z)9IspYT>MU7RW!ahdX0S zB|OlQ>b{-qwaqASf4JQy#&e?`>OJLh+{stgS@!6#9Hvj)DZ!U~P2p-@#(-)!aJk(y zJy`E`vVwz%oyh4k;iU9UGAkD$EXT!aiK6pd4)V7_=MPtPW%t-=YybRjtoYKxK3b;L zZ1frdi#ghAu{N^Wh>L~=qtLDS{JGh5=fJ3Sr4<`Lw?V{6sseHt00ET*DRm_|^KX?>7)V-_d{Hc@QVKwM0oc6P9!W;=+ zhHb82YQjbbCZxk?$f7G%$YYkYGh^}&zy=GDyLHt8kOf~}rerNhF2He}BBat~wDO{h zLg+M&b=+m^HnC>3LQFCA;z3mf_d}4^NEEvi>&Ev!#1_h4Huw zMwui0)!97sDgEOVs?C&snd{W>A7iHQW>-03+7Xf$nGMzAwOj8nbrZ!_& zS__Q!GNvXspOA3XO$8kW3&hnF` zDma5c_p7YIas!G-e}Th%2Bg{zyay(C$PnpZ<~3-#t7V52TqhJ2nNlyO1+?)_gEvmZ zcstcwnUm`&vh#qwIJ$ZWI9TNQKMOUP(cKmQwdjlRnRR4w$+42LdEt>4Mp&h2xY!w2 zty{Vgv2u0o71`w|}C|!Vnm%qBdeRFB!fU+LTsrY{PSmv`I%tS}!&fpC! zim3fi$34p1+Mmd?0V6)@ncaC6>2|gm3jkrdi+>Vt0o7>>G*O=gUu5%IXSJo3%OOl) zBCS~3X!Dsw-7OAmS_4YLd!jl7fM~v_1&v(OU1rOdJW|j@yi{fH+v|$4iSUb@bqg0GSvP-HbXz^zRWftV{qdy0q z1vN2vWgZi^tMiIOYA`qJ* zppFCTx^2~=`#9atm=>0>n<#tXM)*)F=c0^*;J|sJg~dGHc@R*g0Qi4XK-jG+!jlZ5 z=(ortF9KA+1?$Mkf93r26w{Cr2c-l6q@<_;kU!hd000mu0O*G!1o>hAnDGr z`hoKPw?#i)0Z@Q1z<(Y4KQ{gkrvDiFKbZ7>#Q%dy_(u-%-}Zw4$ie>)9_|0Y0R;SC z$CUhO5B%SJC;5LA{EzM5tKT~S#9!i4;y;T1bAo=pzSjXF07!6f2yie+2nYx$C`f2n zR5(}|7+5T16a-W}Yyx~dY+PJIQhEwPVpH^niZA5(9vdfIyIdzJ~w=KX!rv{jc(0P=2<7 zK|sO4At0fkVSXAkBmU=1fdGSofPsO6{_OSr*$)6k0z)QZ5&}n2G=v~_L}d<$&xa%t zuJ1=vn!6!oF>(rof=0){#KI;cr=X;wW@TgN;N;>K5fu}ckd*qRtfH!>uA!-AY+`C= zZeeNV?BeR??&0Yb6dV#779J6qkeHO5lA4yDQBYV^TvA$AUeVCl)ZEhA_Os4>aA z1Qg;wxPXA&{{tKe6pV-o99c*a!q5?gm^lCvRX9Gsz8{K&Md=33$Y~B5os@N#?Djv< z{ui?UcfbPweYXDdfpr645K>`Q>p5JDdT&EdCLd=#JcACUFm1%bBpYVPb z**8l)VAaNdXx8e!{25YrUrAuGi%(&l5w$>o=HtvmDD2%eec|~EYWW5v`iBtQG<@KF z1BBN7$9o6bY5_hR3l#GSzT)##oBI-;`bRuzcB>U004hCC()!cLk=x#Z=^V1U)|(Hj z2rq4?PM>&Ntjz^N1A+xSN6m_e?k1clKC8iz4DhnE7LIR#1^qC_M8qmO2&p-q;|z`V zWxf9_&!6|3Z@{je_swUlJYga=8->noRVO175M6ZndrCxL^Quk2GnN$K} zaVR{1Yg8bhGCC=FdBC!I>}#Fiv3x(-e|4 zQy&O0VmM^*C9Pyc=d;-G2UeR=4ZY+q~h$PBNj}~HZ{I={4GZmYx@`BDTg&q zlUlnJBJ73P4CE{X7Q{`JZ_(nbrx(UVwRcWE!;n0*@H^QuaZJbVT>qDf)Gf+DJQ%Yz z5}{%8Ml3U5TP@W~X3gpTP=~1S5Q>?ar6ku@Isv&n-yeOg#67p}(k%;a(<(;r^szYU zc8xNSteqRV9S6=~6?5`^kLwqIJvXxAn$mKPA$_PSYZ7ZDP`hZw8-H8{e&QFIAye!j zJq=EV`rF(Zn&}VSJwER9-R#xRu9vXyJp$fUpH@usWL=6vwvCdvFWEWbG#BI9K)5JyQW7%PBMx> zt<-%04cz_g(m3aPRW2#^b~pW%#{<&jl+xJVVRIJw@8Qsl#XP$F8! ztA=8tcjNoNR1dtK!<$xnXtlP+P4Hn1>N^5)Xq`lYavZQ6bFZE%36R*Nt^c5(T!N?E z)0O-y76S?npXyY;SMI-Bq>^fCcNd&*Tzr)J84o#H&x|3dHWNDutWQe&A1$Klwnl_8 zbCLWAr+V7ABASg$HWyVkHrb^Rv-D}c6?vh!<`ASNZtGh7oJ-aAU0{}AEeW@>t__@d z0Q86exMvB%-$jn+Gu%qi2aCR&-+-DyOPVt;gb!MIXiq)+ry)H($6n+8`(c=$Yc4kW zv`TcW*E5g{XrNue$P% zKyZg#^^fnNy1Hjk#-;lxu6?tj^N8a(MK7B}Vv^lb@KSdC`I=p&VU-q4HTNA(8Pv#2 z79+&pH|%yjFl%eqo5{V9nCz@tvXF-;81dOb8g{N{EHwfhlY6~)6`}@b9A7veOSh`l z#!6tw_yCAjwkMT_A|&31AD`RyhzpwIT9i|x`@P96F@pt5C!L{r&fv6FTiv1CS*~e{ z0vkFvsh!>^f}1~|=Y3 z(NYk!)pZGm4>IoHVp7Cc#EO>dq}C~U{KCWI&)RB7Y_^dIwHTIhCmM5&|0 z%}9(k<;K4eFd_IKrAjVn@a^}68$BjvLT!&&mug>P(9*tcZ~=Wmvt>05!wIi`tUcMp z9{^P48I{k15Rrc6hk+LLxtu4y1O&pH!#S;V zvz6si8&QrIFJKl@s!@_1pu}4Wa*V0-hMztRceg!;+$nj~eELY!*=F~MLt(4ub<-6KtXV3L?EAQv_ zSF@6l)v&G;*Uk-iFqx5(xVhM!W0TMJ5a$&_`E|4klDs{};Aw$&+4N8=rnR%c6b7{j zD8*_lxF_yDaW{q#Kk_0kn~7MK@+*4EI8RC1J!%%nQP6t>yi-^7GjYme4~`aFaY{Wb zqs}n-tJ|s+N}S5R+aeYgAK>9_ZVH`~04^f6KZi6~Ykv|lavZr_IV-wFh}Rn_w(Ftz z1~J=YsU+k82CvXw<1d%t3MOw(SU~h!>xG~A7Vkz!S31Fcyzlo9HG&>t+NAzN`wHKHzSM63_Akp$;w&BaGk1KN zrN>T~b1a*~ZtFs`+iBL8IYx(<4e+J)MKANxDQBhgwc7CN2U{354h&=~nWO!wcjR3t z<&#bcxCID4Imlt&Yc0l}%ptELWVVsvXqnL;7c6?N8RjALJd%vj6_XX0Ym^O( z7O&+}m$?a&KNtw@GZ2^%wXDuG>vc|@&hFee)zbRyH>B#%$~sbx$9dr}WJ5;mIDTh4 zzFVcWGVT?VWoKHmA=g)InnSIWdYn5Z8vlZTrKw{IL%C)!bAs@!c?7wuufs!=t2}}f z7w)kPdoJ>61*vZm(UkYmzI-MdD6@s`%uk9@+sA~7P3#Jne*I52ViQ~rpS?OhRL-Iv-L zH|tLyO~x|bvlj(6EC?qiW^^>!CKv_C@UGE8(H04kLd-Jn(Xkm(h zuv4i5w9eRGF3Ul_yw>K1|5&qNo&;2Z4P z=lxpW?TGQ8X`|PEoFq4h_ko`H#^%N_xyaR_w3a`UQo8P}j>G}0Cb^je!dAs;xj}^2qKsqE7?7yXP_uX|2o@%XXwEwSmuKXYB z@B5F4ghYsDEDhc&>ln+73`s}x1VDN7QvXU|Tu@B5ymEMwo| zJ9;ml@Av!o{s-Up{B&RUbY-kSv)OIEQTqu-zki^aDppCD44XA$Etl*+A+SP`Qe1@~V*E zz$i3bFGdw%$8E3A=hYLk;l-;hJ1*C=x)OGOr93<-ph!P@iFEj**LnKlR8B4@fQsk> z7YT^o&;G1MF#FtokcZM@>I2&0~jdb46GcX$j)bL{?}KskD&O$gJv;C`=I`^8p@8pICkY3p7$~+iEP{yp6x8W3e=irVr8o+&Lho2`Ln>EEWYr#Eq~ei z==BHi_F8dDnpTDpa4gn1ZMzeFBZ!kvz={sZ?GsX@z`GkzSLPb%Y;xVC{LxX5WLcv* zRu({KpL*_gk(ofs>MCKQR95R|Mi9P2L#&7=Z<^sswqTrR6c{-Oa`^n(>}ysH+Ya!s zgqN>njL%f@f{9j`yyja{On)PjthT?=<5Z@dgL!J`YoDvOjpvWm#@_?yV*Xb!Fmon z7}s&Lng_T7oY>hdd%BDr)K}~yy*}2Z{wk=wWcpGpQbg52kfYjaFDi}@`)z(@hy5n* z`s<6kmIw9Bskcg8Wqj$m*gKyO`9bCic&U@-VcXv?zcnyeu-Qrc#-Ub)W&nLEb4xZ5 zew8}Q0f2BjHl>;Nc!GL%y@6T69Wu!$|f2{SX;XBy+|Px)Ti8HDVUs#6s>H$oigc~i8FfksxP~=XK~w`zZ5Mu zTqBy6yNd5VU1P=a3E<3Up3DsA=Y~&u5{}~5#%uR+M4IgPdD@+lQBC$8l-ZfcPBxS4 zG}{qRU#^IbS}_!2h7fQSr0g}UIL9pbl)9vvA&X>c#2GS!Gt104OV)IeL?Q zfGs)w;(~61W`5$VajTW}hX0wkYzq-c&#TfIc64|*{khtuk0}+Y%}hH_#}@3Nn`v*e zVi5kzY%5Y(45h;!FM;rMpGtxFJSY#OMcAMUtc{v#F)yO0F*W{?&-SR1QIb{SjlCLg z96|45sLw2&_(81CLh#i)*J_CMrJGs9n56D8CB^-p zrgYq=wWkfF6-y5D$C}MWOVaYj+|~Os zvs8l~XIop20pNl-Sc{8?agOEd=$`}CZ0K^bS9)B!kr5&_0efK#TJS4+KMF6v0NjrXWJlCt5Q0|mQWjNj9_1L?7`jt=&f#{NSEcq$X@{hq2pW5J6-IB)o)z=dBv|^b zh^%VgDX?lrec=-F8`N`oL1s|uUp<}tN+7`%sNv?&sQzWiZNI0;ciOq-up>||>$F#l zmeUtmUHo(h7m=E*(NvD7KMW*Da)w;YY zD56`NfKh#FbKCS?|&Kr$zZ3&l*h)BvTaNMB3i?89-3tNTrX>Z<{X=S7x zc;MEgh14zGi%n=B^Q>)+QAZHc_T4-yz7=s0ywJs31UA?FUx`4XZF$#r$+t(barIt+ zcD4B;>;yI$TEX;ID+h}NDKkKcK-PTsvp0Qre~?t3G$VC{DALPvVG zN+iLFf8Lg!~Wr1zSgQqH*8f zwD4M)&4)}YfOaEwyDP5aY{t1NKNpC!vCm#DcM$UcnKMTB4tyLN&(2O7ppx$aVQN*C z#Qi$mW4p`vKE9THK32vfOJ=UC;^|tI8Y;{(123<>Q@=U;M<=t=j>oyUV8XN!x1vGs zX13~xb7A7go{IbnBIb?&i5aG5(0osKiM(r$O=9<|vS!-S$YPL(xv&yn<*+B7vn%;J#W{p#-}y zSEKy1MWbZC3epiz4Hc=b&}F;rf^y(lHub2XAJL1QGvk$VqBo}%&zRt9={<+0p`4dg zYu7IFZ8dRq?BGJljghn&lVjo!$|^iOLOuAwDg~sdB!{FhrN5F`x_ADcn-QJ&j{J1$QJ^rZ3aSUiaYqmpis*6=Gz^2Tw=KCwd0WOCU zN2@u?d!I;j9fHMM{#2>fi(S?E;+#S$1ko!^5&*+6q z8m7ZkQ}jcIHP6GETD~3wN_NWD@41289liOwSWOt}92OH9$>Sz}$Tyt5+hh&h zC?v%1iyJCrW?mSEyYy_n2S0mCdrPxj7r&<@RLZx}#4deJUG{XjX0EW&mNzQwVU8Pg z;Sxu1wlxmxaeXN(s|nP<-kf3UaimAtt*JUbpY3(oST$v;l679sXi=)%r?^h&xzNLF z4gOhIVTjw@Ucx2W*n5i^Wo&Up=cA~E-sHv~-kyF=P!QCdW*~9BiJ0QzM-_g$L01J0 z*^kiL(%O_JzZy97>Np0N0QdUCO$?&*#!0c$?RnV(4uem7dQhp)?SD>vIzwkY(o_#Q&)N0~<>Bp{lBK)ZpB~c7+AYA6Uw==*!j(HCg2`=qAy6w& zb?Xf#8GPs3h}it;-W3tu;<54wB>*ZZFn!nX(YrOXpj*+m+Vk@CqkMH7+4q<&hyhEm zY!q8uv}o}bf?9<<@syC`irwePb?l#n=$|)dJr&S;jxvzv`Y=4q7Zkk_FzC`WkfuDz zg()HHinD$HZSyUmyv}ZE?8So1M ztJLk-Me@bEMDd{S$ADnVLdsmW3Czrw>VvowX^A4Yn#f{R=^nyS$Bb*s3R;-@z#I-y(o*%8l zED}kXEwHiX<|XgAYe_m~hKX`TAULqgNzUgSX@7m-OV^e$ADJ_RX+0kA9q#qkjUheQ-~nojRiuS@|k%CzxQ7H?WeuA}%H{c6K;FDP9PBy|hW1 zShJl-Q}T&HR73lz&VgKk?|HE!jrU)ZVa7g5P}Rt~lKqKSGVd~ta2H0u-Hs0~dXzUZ zxJ5Ici$JvbW;vUSHeYMU6Jya)X%^tpwqJ8Jj4W6hOF5Fky+Kj#uE#Ozn65p&hr*u&6=>54v zTBhpVIz%d$eh{bXfXbE+WIs1K6z#WLat!#8+F7Wnu(XZ-)YsPVg|clFQT+@ao*)=% zPE{^6B3(W;VnTbx85n-yLGOz<4`bBOEJx&10nHe0pwGQ8#2Bbft&1V3z%OITFig&` zfL7&{Jk zm4q_x5=F}n$m(@Tr+rPZJReUv##mN4xsH>IE?JmC`RUDyfti;F8uyF(z9*yN&aiV< zw}$z{Zw}3Fgy}v|PSKcFH`1=`HLupFxg`0M^Q^D%1%GG-v#lNj6MNq=K>wJszN%ed zG~E%rES^}WUZifSp%1O-PM@fN0eBpK?CQVACI*a>ynBBtxgo-2L-zQIpRW7Qqyv88 zYUJIx0_r>LEE7>|Ht7Z~bNfl;txfjjYDQ1QsoiUh>r2xfrFQQoHrnSbO#Rrbr~x|R zS8nzj*$T<5I&NpbZ{Z0O;|~VMBeX>ZIhaZfkwD0544fuu0kXmLYUlThrd&Tm5u(>~`6>UUHr?mo;iuo;kxcxt^9f1xzC<*{81 zSc~6!HjGkFD7Wn`!$w(+dzC4kJjnFZj!`e_4 zc*K`b8lKNhoL`y{{Xgw8DA<*M^Z8?tA%zp0F;6INgp}6J;5ak1TUF!G!Ln2=_ zbqJ4=tLaR}t-a4DXjZNze;S~6rPd;TpN*|)N~!6{aL--aT0NA_Ff&@>VehMtDRp-K z6rC>t;Fb&Xf-g~yoJn7($rPJR?W>49x29d)C9j@kI=-u+_lO{1_4t?HNGtI9GK_0Q z&Rxf;;QffFTKPcwT72&I)y7`hnw`tF;e$O}wP(9Ujh+-y&;i~LcrpF-y#+idu+_XKt zJ}kKoZxbo|Mt^=hcdv~{kj%2h%(_?{U*_|q$ctQ7O3Y|3zoB>9-BF!y-ySZFYrN>{ zJ`vEPnZFj13;Oxtl#kWt^HE>jXFAVA1}SS9gA1vdN>_5~9PN&*!e5rxtxY*;PjMUA zHRSm={d)Ze*Y>2sPZZZ)C2_B7>Uvfsutqa&jN%sVnWYGA@_YwPY}gDn-xK)q57QQv zb77YpR#reOJMy=`(A{7A9{qlplArnp-yIjP4XRCu0fu2q5)R4mbduDPoOqCQR_kke zo2VwwhHP?1^ABbbmnd3?=EcR4lFwb5J)w?X^(Uk=bgQOVk$L8gU)CDdG=^^Otd}%< zc5Es5?1o!q?I!LIZBkYQY(9s2FM8L2(Uip{mSo68DXc+nZ9Ic4Tsw@zZeLvX>JVcXf3YbA^f#9IeD5 za5!9CLQ-5(Qj{VgN_4YxLXt%7i2Q#e+`>skl&-|8nF1lqTxB*<-{XV2A`~M-)cI z1!L#L|F=3C^^dN-v!m_r0MICLj4cLF5hGHpLH;pyQt0@P^hv;0SiJpj4GOdWNI79G z|3l0F@aN>tZ}@?|(@C9p{N4g$%h{1eEiMKkBy-;1i>AXaWk0miyhrSV*DZ zmNIBjOBpCiR0;x@6-7d%k)krvma;H390`$uL;l85w<9_s?NFE#915}+mI5LpiAG7n zAy82$T#BM^0h1JkVI*WlEirH@2pWyDl$J*St*_;XrDPn^_P_gcf`g{uNJz@aNXVe1 zM5Uon2nELyB?^a0AVn=LBqSx^NNE`v85EcgjgnI(IO36%M~1~CtuW%Q7z=wa-wCyH zO838;D72^PxACn-qo-~ z%5As5GG7Pd@K?(g%lA9) -b 115200 + +Replace :code:`` with the port where the nRF9131 EK +can be found. For example, under Linux, :code:`/dev/ttyACM0`. + +Then build and flash the application in the usual way. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nrf9131ek_nrf9131 + :goals: build flash + +Debugging +========= + +Refer to the :ref:`nordic_segger` page to learn about debugging Nordic boards with a +Segger IC. + + +Testing the LEDs and buttons in the nRF9131 EK +********************************************** + +There are 2 samples that allow you to test that the button and LED on +the board are working properly with Zephyr: + +* :zephyr:code-sample:`blinky` +* :zephyr:code-sample:`button` + +You can build and flash the examples to make sure Zephyr is running correctly on +your board. The button and LED definitions can be found in +:zephyr_file:`boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi`. + +References +********** + +.. target-notes:: + +.. _IDAU: + https://developer.arm.com/docs/100690/latest/attribution-units-sau-and-idau +.. _Nordic Semiconductor Infocenter: https://infocenter.nordicsemi.com +.. _Trusted Firmware M: https://www.trustedfirmware.org/projects/tf-m/ diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi index 35314cd0784f777..2c3b8481d2ae86e 100644 --- a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi @@ -20,7 +20,7 @@ compatible = "gpio-leds"; led0: led_0 { gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; - label = "Green LED 1"; + label = "Red LED 1"; }; led1: led_1 { gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; @@ -28,7 +28,7 @@ }; led2: led_2 { gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; - label = "Green LED 3"; + label = "Blue LED 3"; }; }; From 9fe225d2b8a467b62ea652cbf181b65c3427229e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 12:24:32 +0100 Subject: [PATCH 0525/1049] doc/connectivity/usb: Replace references to native_posix w native_sim Replace the references to native_posix with native_sim, and update link names accordingly. Background: during this release native_sim is replacing native_posix as the main host test/development platform. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 2 +- doc/connectivity/usb/device/usb_device.rst | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 94eb8d43580503a..5cd060930e4e2b5 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -390,7 +390,7 @@ The following peripherals are currently provided with this board: **USB controller** It's possible to use the Virtual USB controller working over USB/IP protocol. More information can be found in - :ref:`Testing USB over USP/IP in native_posix `. + :ref:`Testing USB over USP/IP in native_sim `. **Display driver** A display driver is provided that creates a window on the host machine to diff --git a/doc/connectivity/usb/device/usb_device.rst b/doc/connectivity/usb/device/usb_device.rst index 3362f07840fe467..134ec5972cddf74 100644 --- a/doc/connectivity/usb/device/usb_device.rst +++ b/doc/connectivity/usb/device/usb_device.rst @@ -445,14 +445,14 @@ the vendor requests: The class driver waits for the :makevar:`USB_DC_CONFIGURED` device status code before transmitting any data. -.. _testing_USB_native_posix: +.. _testing_USB_native_sim: -Testing over USPIP in native_posix -*********************************** +Testing over USPIP in native_sim +******************************** A virtual USB controller implemented through USBIP might be used to test the USB device stack. Follow the general build procedure to build the USB sample for -the native_posix configuration. +the :ref:`native_sim ` configuration. Run built sample with: From 5776d74943b7b561b1e6a6cfd4efce793c599906 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 15 Nov 2023 13:35:59 +0100 Subject: [PATCH 0526/1049] samples/subsys/usb/console: Remove platform_exclude native_posix and native_sim are already excluded thru the lack of required tags. Let's remove the platform exclude instead of adding also native_sim to it explicitly. Signed-off-by: Alberto Escolar Piedras --- samples/subsys/usb/console/sample.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/samples/subsys/usb/console/sample.yaml b/samples/subsys/usb/console/sample.yaml index f7fc8c03c0eef9b..0a291d23a678a9b 100644 --- a/samples/subsys/usb/console/sample.yaml +++ b/samples/subsys/usb/console/sample.yaml @@ -6,9 +6,6 @@ tests: - usb_device - usb_cdc tags: usb - platform_exclude: - - native_posix - - native_posix_64 harness: console harness_config: fixture: fixture_usb_cdc From 5bf7109767c128a877bdbac7b46ff76454167689 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 15 Nov 2023 13:37:12 +0100 Subject: [PATCH 0527/1049] samples/subsys/usb/cdc_acm: Enable for native_sim Allow this sample in native_sim, and set it as default integration platform instead of native_posix. Signed-off-by: Alberto Escolar Piedras --- samples/subsys/usb/cdc_acm/sample.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/subsys/usb/cdc_acm/sample.yaml b/samples/subsys/usb/cdc_acm/sample.yaml index 19e645174f71ef3..61b72fa41efdc1e 100644 --- a/samples/subsys/usb/cdc_acm/sample.yaml +++ b/samples/subsys/usb/cdc_acm/sample.yaml @@ -41,4 +41,4 @@ tests: arch_allow: posix build_only: true integration_platforms: - - native_posix + - native_sim From 063ce9caf54fa656f02ae48f3c9d537659a10dec Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 15 Nov 2023 13:37:48 +0100 Subject: [PATCH 0528/1049] samples/subsys/usb/hid: Enable for native_sim Allow this sample in native_sim, and set it as default integration platform instead of native_posix. Signed-off-by: Alberto Escolar Piedras --- samples/subsys/usb/hid/sample.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/subsys/usb/hid/sample.yaml b/samples/subsys/usb/hid/sample.yaml index 7f63562bbf73eb9..ba6cf22a2d4fbe2 100644 --- a/samples/subsys/usb/hid/sample.yaml +++ b/samples/subsys/usb/hid/sample.yaml @@ -17,6 +17,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 build_only: true integration_platforms: - - native_posix + - native_sim From feb6742a8e2ef2579efa5c236bfd338fdbf0eb35 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 15 Nov 2023 08:49:32 -0500 Subject: [PATCH 0529/1049] CODEOWNERS: cleanup and remove duplicates Remove anything that would be covered by MAINTAINERS.yml leaving only mostly instances that are not covered. Signed-off-by: Anas Nashif --- CODEOWNERS | 469 ----------------------------------------------------- 1 file changed, 469 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 1db37fb9dd586f4..ab9197825c53055 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -13,23 +13,6 @@ # Do not use wildcard on all source yet # * @galak @nashif -/.github/ @nashif @stephanosio -/.github/workflows/ @galak @nashif -/MAINTAINERS.yml @MaureenHelm -/arch/arc/ @abrodkin @ruuddw @evgeniy-paltsev -/arch/arm/ @MaureenHelm @galak @ioannisg -/arch/arm/core/cortex_m/cmse/ @ioannisg -/arch/arm/include/cortex_m/cmse.h @ioannisg -/arch/arm/core/cortex_a_r/ @MaureenHelm @galak @ioannisg @bbolen @stephanosio -/arch/arm64/ @carlocaione -/arch/arm64/core/cortex_r/ @povergoing -/arch/arm64/core/xen/ @lorc @firscity -/arch/common/ @ioannisg @andyross -/arch/mips/ @frantony -/soc/arc/snps_*/ @abrodkin @ruuddw @evgeniy-paltsev -/soc/nios2/ @nashif -/soc/arm/ @MaureenHelm @galak @ioannisg -/soc/arm/arm/mps2/ @fvincenzo /soc/arm/aspeed/ @aspeeddylan /soc/arm/atmel_sam/common/*_sam4l_*.c @nandojve /soc/arm/atmel_sam/sam3x/ @ioannisg @@ -38,18 +21,9 @@ /soc/arm/atmel_sam/sam4s/ @fallrisk /soc/arm/atmel_sam/same70/ @nandojve /soc/arm/atmel_sam/samv71/ @nandojve -/soc/arm/cypress/ @ifyall @npal-cy /soc/arm/bcm*/ @sbranden -/soc/arm/gigadevice/ @nandojve /soc/arm/infineon_cat1/ @ifyall @npal-cy /soc/arm/infineon_xmc/ @parthitce -/soc/arm/nxp*/ @mmahadevan108 @dleach02 -/soc/arm/nxp_s32/ @manuargue -/soc/arm/nordic_nrf/ @anangl -/soc/arm/nuvoton_npcx/ @MulinChao @ChiHuaL -/soc/arm/nuvoton_numicro/ @ssekar15 -/soc/arm/quicklogic_eos_s3/ @fkokosinski @kgugala -/soc/arm/rpi_pico/ @yonsch /soc/arm/silabs_exx32/efm32pg1b/ @rdmeneze /soc/arm/silabs_exx32/efr32mg21/ @l-alfred /soc/arm/st_stm32/ @erwango @@ -63,37 +37,11 @@ /soc/arm/xilinx_zynq7000/ @ibirnbaum /soc/arm/xilinx_zynqmp/ @stephanosio /soc/arm/renesas_rcar/ @aaillet -/soc/arm64/ @carlocaione -/soc/arm64/qemu_cortex_a53/ @carlocaione -/soc/arm64/bcm_vk/ @abhishek-brcm -/soc/arm64/nxp_layerscape/ @JiafeiPan -/soc/arm64/xenvm/ @lorc @firscity -/soc/arm64/nxp_imx/ @MrVan @JiafeiPan -/soc/arm64/arm/ @povergoing -/soc/arm64/arm/fvp_aemv8a/ @carlocaione -/soc/arm64/intel_socfpga/* @siclim -/soc/arm64/renesas_rcar/ @lorc @xakep-amatop -/soc/Kconfig @tejlmand @galak @nashif @nordicjm -/submanifests/* @mbolivar-ampere -/arch/x86/ @jhedberg @nashif -/arch/nios2/ @nashif -/arch/posix/ @aescolar @daor-oti -/arch/riscv/ @kgugala @pgielda -/soc/mips/ @frantony -/soc/posix/ @aescolar @daor-oti -/soc/riscv/ @kgugala @pgielda /soc/riscv/openisa*/ @dleach02 /soc/riscv/riscv-privileged/andes_v5/ @cwshu @kevinwang821020 @jimmyzhe /soc/riscv/riscv-privileged/neorv32/ @henrikbrixandersen /soc/riscv/riscv-privileged/gd32vf103/ @soburi /soc/riscv/riscv-privileged/niosv/ @sweeaun -/soc/x86/ @dcpleung @nashif -/arch/xtensa/ @dcpleung @andyross @nashif -/soc/xtensa/ @dcpleung @andyross @nashif -/arch/sparc/ @julius-barendt -/soc/sparc/ @julius-barendt -/boards/arc/ @abrodkin @ruuddw @evgeniy-paltsev -/boards/arm/ @MaureenHelm @galak /boards/arm/96b_argonkey/ @avisconti /boards/arm/96b_avenger96/ @Mani-Sadhasivam /boards/arm/96b_carbon/ @idlethread @@ -102,7 +50,6 @@ /boards/arm/96b_neonkey/ @Mani-Sadhasivam /boards/arm/96b_stm32_sensor_mez/ @Mani-Sadhasivam /boards/arm/96b_wistrio/ @Mani-Sadhasivam -/boards/arm/arduino_due/ @ioannisg /boards/arm/acn52832/ @sven-hm /boards/arm/arduino_mkrzero/ @soburi /boards/arm/bbc_microbit_v2/ @LingaoM @@ -168,15 +115,7 @@ /boards/arm/rcar_*/ @aaillet /boards/arm/ubx_bmd345eval_nrf52840/ @Navin-Sankar @brec-u-blox /boards/arm/nrf5340_audio_dk_nrf5340 @koffes @alexsven @erikrobstad @rick1082 @gWacey -/boards/common/ @mbolivar-ampere -/boards/deprecated.cmake @tejlmand -/boards/mips/ @frantony -/boards/nios2/ @nashif -/boards/nios2/altera_max10/ @nashif /boards/arm/stm32_min_dev/ @sidcha -/boards/posix/ @aescolar @daor-oti -/boards/posix/nrf52_bsim/ @aescolar @wopu-ot -/boards/riscv/ @kgugala @pgielda /boards/riscv/rv32m1_vega/ @dleach02 /boards/riscv/adp_xc7k_ae350/ @cwshu @kevinwang821020 @jimmyzhe /boards/riscv/longan_nano/ @soburi @@ -184,16 +123,11 @@ /boards/riscv/niosv*/ @sweeaun /boards/riscv/sparkfun_red_v_things_plus/ @soburi /boards/riscv/stamp_c3/ @soburi -/boards/shields/ @erwango /boards/shields/atmel_rf2xx/ @nandojve /boards/shields/esp_8266/ @nandojve /boards/shields/inventek_eswifi/ @nandojve -/boards/x86/ @dcpleung @nashif -/boards/x86/acrn/ @enjiamai -/boards/xtensa/ @nashif @dcpleung /boards/xtensa/odroid_go/ @ydamigos /boards/xtensa/nxp_adsp_imx8/ @iuliana-prodan @dbaluta -/boards/sparc/ @julius-barendt /boards/arm64/qemu_cortex_a53/ @carlocaione /boards/arm64/bcm958402m2_a72/ @abhishek-brcm /boards/arm64/mimx8mm_evk/ @MrVan @JiafeiPan @@ -207,25 +141,13 @@ /boards/arm64/intel_socfpga_agilex_socdk/ @siclim @ngboonkhai /boards/arm64/intel_socfpga_agilex5_socdk/ @chongteikheng /boards/arm64/rcar_*/ @lorc @xakep-amatop -/boards/Kconfig @tejlmand @galak @nashif @nordicjm # All cmake related files -/cmake/ @tejlmand @nashif -/cmake/*/arcmwdt/ @abrodkin @evgeniy-paltsev @tejlmand -/CMakeLists.txt @tejlmand @nashif -/doc/ @carlescufi /doc/develop/tools/coccinelle.rst @himanshujha199640 @JuliaLawall /doc/services/device_mgmt/smp_protocol.rst @de-nordic @nordicjm /doc/services/device_mgmt/smp_groups/ @de-nordic @nordicjm /doc/services/sensing/ @lixuzha @ghu0510 @qianruh /doc/CMakeLists.txt @carlescufi /doc/_scripts/ @carlescufi -/doc/connectivity/bluetooth/ @alwa-nordic @jhedberg @Vudentz -/doc/connectivity/networking/conn_mgr @carlescufi @glarsennordic -/doc/build/dts/ @galak @mbolivar-ampere -/doc/build/sysbuild/ @tejlmand @nordicjm -/doc/hardware/peripherals/canbus/ @alexanderwachter @henrikbrixandersen -/doc/security/ @ceolin @d3zd3z -/drivers/debug/ @nashif /drivers/*/*sam4l* @nandojve /drivers/*/*cc13xx_cc26xx* @bwitherspoon /drivers/*/*gd32* @nandojve @@ -239,7 +161,6 @@ /drivers/*/*ifx_cat1* @ifyall @npal-cy /drivers/*/*neorv32* @henrikbrixandersen /drivers/*/*_s32* @manuargue -/drivers/adc/ @anangl /drivers/adc/adc_ads1x1x.c @XenuIsWatching /drivers/adc/adc_stm32.c @cybertale /drivers/adc/adc_rpi_pico.c @soburi @@ -252,16 +173,12 @@ /drivers/bbram/* @yperess @sjg20 @jackrosenthal /drivers/bluetooth/ @alwa-nordic @jhedberg @Vudentz /drivers/bluetooth/hci/hci_esp32.c @sylvioalves -/drivers/cache/ @carlocaione -/drivers/syscon/ @carlocaione @yperess -/drivers/can/ @alexanderwachter @henrikbrixandersen /drivers/can/*mcp2515* @karstenkoenig /drivers/can/*rcar* @aaillet /drivers/clock_control/*agilex* @siclim @gdengi /drivers/clock_control/*nrf* @nordic-krch /drivers/clock_control/*esp32* @extremegtx @sylvioalves /drivers/clock_control/*cpg_mssr* @aaillet -/drivers/counter/ @nordic-krch /drivers/console/ipm_console.c @finikorg /drivers/console/semihost_console.c @luozhongyao /drivers/console/jailhouse_debug_console.c @MrVan @@ -273,7 +190,6 @@ /drivers/crypto/*nrf_ecb* @maciekfabia @anangl /drivers/display/*rm68200* @mmahadevan108 /drivers/display/display_ili9342c.* @extremegtx -/drivers/dac/ @martinjaeger /drivers/dac/*ad56xx* @benediktibk /drivers/dac/dac_ad5592.c @bbilas /drivers/dai/ @kv2019i @marcinszkudlinski @abonislawski @@ -290,15 +206,11 @@ /drivers/dma/*intel_adsp* @teburd @abonislawski /drivers/dma/*rpi_pico* @soburi /drivers/dma/*xmc4xxx* @talih0 -/drivers/edac/ @finikorg -/drivers/eeprom/ @henrikbrixandersen /drivers/eeprom/eeprom_stm32.c @KwonTae-young /drivers/entropy/*b91* @andy-liu-telink /drivers/entropy/*bt_hci* @JordanYates /drivers/entropy/*rv32m1* @dleach02 /drivers/entropy/*litex* @mateusz-holenko @kgugala @pgielda -/drivers/espi/ @albertofloyd @franciscomunoz @sjvasanth1 -/drivers/ethernet/ @tbursztyka @jukkar /drivers/ethernet/*dwmac* @npitre /drivers/ethernet/*stm32* @Nukersson @lochej /drivers/ethernet/*w5500* @parthitce @@ -309,17 +221,13 @@ /drivers/ethernet/*lan865x* @lmajewski /drivers/ethernet/phy/ @rlubos @tbursztyka @arvinf @jukkar /drivers/ethernet/phy/*adin2111* @GeorgeCGV -/drivers/mdio/ @rlubos @tbursztyka @arvinf /drivers/mdio/*adin2111* @GeorgeCGV -/drivers/flash/ @nashif @de-nordic /drivers/flash/*stm32_qspi* @lmajewski /drivers/flash/*b91* @andy-liu-telink /drivers/flash/*cadence* @ngboonkhai /drivers/flash/*cc13xx_cc26xx* @pepe2k /drivers/flash/*nrf* @de-nordic /drivers/flash/*esp32* @sylvioalves -/drivers/fpga/ @tgorochowik @kgugala -/drivers/gpio/ @mnkp /drivers/gpio/*b91* @andy-liu-telink /drivers/gpio/*lmp90xxx* @henrikbrixandersen /drivers/gpio/*nct38xx* @MulinChao @ChiHuaL @@ -334,7 +242,6 @@ /drivers/gpio/*pcal64xxa* @benediktibk /drivers/gpio/gpio_altera_pio.c @shilinte /drivers/gpio/gpio_ad5592.c @bbilas -/drivers/hwinfo/ @alexanderwachter /drivers/i2c/i2c_common.c @sjg20 /drivers/i2c/i2c_emul.c @sjg20 /drivers/i2c/i2c_ite_enhance.c @GTLin08 @@ -349,7 +256,6 @@ /drivers/i2s/*litex* @mateusz-holenko @kgugala @pgielda /drivers/i2s/i2s_ll_stm32* @avisconti /drivers/i2s/*nrfx* @anangl -/drivers/i3c/ @dcpleung /drivers/i3c/i3c_cdns.c @XenuIsWatching /drivers/ieee802154/ @rlubos @tbursztyka @jukkar @fgrandel /drivers/ieee802154/*b91* @andy-liu-telink @@ -370,33 +276,22 @@ /drivers/ipm/ipm_stm32_hsem.c @cameled /drivers/ipm/ipm_esp32.c @uLipe /drivers/ipm/ipm_ivshmem.c @uLipe -/drivers/kscan/ @VenkatKotakonda @franciscomunoz @sjvasanth1 /drivers/kscan/*xec* @franciscomunoz @sjvasanth1 /drivers/kscan/*ft5336* @MaureenHelm /drivers/kscan/*ht16k33* @henrikbrixandersen -/drivers/led/ @Mani-Sadhasivam /drivers/led_strip/ @mbolivar-ampere -/drivers/lora/ @Mani-Sadhasivam -/drivers/mbox/ @carlocaione /drivers/mfd/mfd_ad5592.c @bbilas /drivers/mfd/mfd_max20335.c @bbilas -/drivers/misc/ @tejlmand /drivers/misc/ft8xx/ @hubertmis -/drivers/mm/ @dcpleung /drivers/modem/hl7800.c @rerickson1 /drivers/modem/simcom-sim7080.c @lgehreke /drivers/modem/simcom-sim7080.h @lgehreke /drivers/modem/Kconfig.hl7800 @rerickson1 /drivers/modem/Kconfig.simcom-sim7080 @lgehreke -/drivers/pcie/ @dcpleung @nashif @jhedberg -/drivers/peci/ @albertofloyd @franciscomunoz @sjvasanth1 -/drivers/pinctrl/ @gmarull /drivers/pinctrl/*esp32* @sylvioalves /drivers/pinctrl/*it8xxx2* @ite -/drivers/pm_cpu_ops/ @carlocaione @gdengi /drivers/pm_cpu_ops/psci_shell.c @nbalabak @gdengi /drivers/power_domain/ @ceolin -/drivers/ps2/ @franciscomunoz @sjvasanth1 /drivers/ps2/*xec* @franciscomunoz @sjvasanth1 /drivers/ps2/*npcx* @MulinChao @ChiHuaL /drivers/pwm/*b91* @andy-liu-telink @@ -418,10 +313,8 @@ /drivers/regulator/regulator_pca9420.c @danieldegrasse /drivers/regulator/regulator_rpi_pico.c @soburi /drivers/regulator/regulator_shell.c @danieldegrasse -/drivers/reset/ @andrei-edward-popa /drivers/reset/reset_intel_socfpga.c @nbalabak /drivers/reset/Kconfig.intel_socfpga @nbalabak -/drivers/sensor/ @MaureenHelm /drivers/sensor/ams_iAQcore/ @alexanderwachter /drivers/sensor/ens210/ @alexanderwachter /drivers/sensor/grow_r502a/ @DineshDK03 @@ -452,29 +345,19 @@ /drivers/serial/*numicro* @ssekar15 /drivers/serial/*apbuart* @julius-barendt /drivers/serial/*rcar* @aaillet -/drivers/serial/Kconfig.test @str4t0m -/drivers/serial/serial_test.c @str4t0m /drivers/serial/Kconfig.xen @lorc @firscity /drivers/serial/uart_hvc_xen.c @lorc @firscity /drivers/serial/uart_hvc_xen_consoleio.c @lorc @firscity /drivers/serial/Kconfig.it8xxx2 @GTLin08 /drivers/serial/uart_ite_it8xxx2.c @GTLin08 /drivers/serial/*intel_lw* @shilinte -/drivers/smbus/ @finikorg -/drivers/sip_svc/ @maheshraotm -/drivers/disk/ @jfischer-no /drivers/disk/sdmmc_sdhc.h @JunYangNXP /drivers/disk/sdmmc_stm32.c @anthonybrandon -/drivers/net/ @rlubos @tbursztyka @jukkar /drivers/ptp_clock/ @tbursztyka @jukkar -/drivers/spi/ @tbursztyka /drivers/spi/*b91* @andy-liu-telink /drivers/spi/spi_rv32m1_lpspi* @karstenkoenig /drivers/spi/*esp32* @sylvioalves /drivers/spi/*pl022* @soburi -/drivers/sdhc/ @danieldegrasse -/drivers/timer/*apic* @dcpleung @nashif -/drivers/timer/apic_tsc.c @andyross /drivers/timer/*arm_arch* @carlocaione /drivers/timer/*cortex_m_systick* @anangl /drivers/timer/*altera_avalon* @nashif @@ -494,10 +377,7 @@ /drivers/timer/*rv32m1_lptmr* @mbolivar /drivers/timer/*nrf_rtc* @anangl /drivers/timer/*hpet* @dcpleung -/drivers/usb/ @jfischer-no /drivers/usb/device/usb_dc_stm32.c @ydamigos @loicpoulain -/drivers/usb_c/ @sambhurst -/drivers/video/ @loicpoulain /drivers/i2c/*b91* @andy-liu-telink /drivers/i2c/i2c_ll_stm32* @ydamigos /drivers/i2c/i2c_rv32m1_lpi2c* @henrikbrixandersen @@ -505,7 +385,6 @@ /drivers/i2c/i2c_dw* @dcpleung /drivers/i2c/*tca954x* @kurddt /drivers/*/*xec* @franciscomunoz @albertofloyd @sjvasanth1 -/drivers/w1/ @str4t0m /drivers/watchdog/*gecko* @oanerer /drivers/watchdog/*sifive* @katsuster /drivers/watchdog/wdt_handlers.c @dcpleung @nashif @@ -516,12 +395,10 @@ /drivers/watchdog/*rpi_pico* @thedjnK /drivers/watchdog/*dw* @softwarecki /drivers/watchdog/*ifx* @sreeramIfx -/drivers/wifi/ @rlubos @tbursztyka @jukkar /drivers/wifi/esp_at/ @mniestroj /drivers/wifi/eswifi/ @loicpoulain @nandojve /drivers/wifi/winc1500/ @kludentwo /drivers/virtualization/ @tbursztyka -/drivers/xen/ @lorc @firscity /dts/arc/ @abrodkin @ruuddw @iriszzw @evgeniy-paltsev /dts/arm/acsip/ @NorthernDean /dts/arm/aspeed/ @aspeeddylan @@ -537,7 +414,6 @@ /dts/arm/gigadevice/ @nandojve /dts/arm/infineon/xmc4* @parthitce @ifyall @npal-cy /dts/arm/infineon/psoc6/ @ifyall @npal-cy -/dts/arm64/ @carlocaione /dts/arm64/armv8-r.dtsi @povergoing /dts/arm64/intel/*intel_socfpga* @siclim /dts/arm64/nxp/ @JiafeiPan @@ -564,7 +440,6 @@ /dts/arm/silabs/efm32pg1b* @rdmeneze /dts/arm/silabs/efr32mg21* @l-alfred /dts/arm/silabs/efr32fg13* @yonsch -/dts/riscv/ @kgugala @pgielda /dts/riscv/ite/ @ite /dts/riscv/microchip/microchip-miv.dtsi @galak /dts/riscv/openisa/rv32m1* @dleach02 @@ -577,13 +452,10 @@ /dts/arm/armv7-r.dtsi @bbolen @stephanosio /dts/arm/xilinx/ @bbolen @stephanosio /dts/arm/renesas/rcar/ @aaillet -/dts/x86/ @jhedberg /dts/xtensa/xtensa.dtsi @ydamigos /dts/xtensa/intel/ @dcpleung /dts/xtensa/espressif/ @sylvioalves /dts/xtensa/nxp/ @iuliana-prodan @dbaluta -/dts/sparc/ @julius-barendt -/dts/bindings/ @galak /dts/bindings/can/ @alexanderwachter @henrikbrixandersen /dts/bindings/i2c/zephyr*i2c-emul*.yaml @sjg20 /dts/bindings/adc/st*stm32-adc.yaml @cybertale @@ -615,7 +487,6 @@ /dts/bindings/ethernet/*gem.yaml @ibirnbaum /dts/bindings/auxdisplay/*pt6314.yaml @xingrz /dts/bindings/auxdisplay/* @thedjnK -/dts/posix/ @aescolar @daor-oti /dts/bindings/sensor/*bme680* @BoschSensortec /dts/bindings/sensor/*ina23* @bbilas /dts/bindings/sensor/st* @avisconti @@ -630,343 +501,3 @@ /dts/bindings/gpio/*ads114s0x* @benediktibk /dts/bindings/pwm/*max31790* @benediktibk /dts/bindings/dac/*ad56* @benediktibk -/dts/common/ @galak -/include/ @nashif @carlescufi @galak @MaureenHelm -/include/zephyr/drivers/*/*litex* @mateusz-holenko @kgugala @pgielda -/include/zephyr/drivers/adc.h @anangl -/include/zephyr/drivers/adc/ads114s0x.h @benediktibk -/include/zephyr/drivers/auxdisplay.h @thedjnK -/include/zephyr/drivers/can.h @alexanderwachter @henrikbrixandersen -/include/zephyr/drivers/can/ @alexanderwachter @henrikbrixandersen -/include/zephyr/drivers/counter.h @nordic-krch -/include/zephyr/drivers/dac.h @martinjaeger -/include/zephyr/drivers/espi.h @albertofloyd @franciscomunoz @sjvasanth1 -/include/zephyr/drivers/bluetooth/ @alwa-nordic @jhedberg @Vudentz -/include/zephyr/drivers/flash.h @nashif @carlescufi @galak @MaureenHelm @de-nordic -/include/zephyr/drivers/i2c_emul.h @sjg20 -/include/zephyr/drivers/i3c.h @dcpleung -/include/zephyr/drivers/i3c/ @dcpleung -/include/zephyr/drivers/led/ht16k33.h @henrikbrixandersen -/include/zephyr/drivers/interrupt_controller/ @dcpleung @nashif -/include/zephyr/drivers/interrupt_controller/gic.h @stephanosio -/include/zephyr/drivers/modem/hl7800.h @rerickson1 -/include/zephyr/drivers/pcie/ @dcpleung -/include/zephyr/drivers/hwinfo.h @alexanderwachter -/include/zephyr/drivers/led.h @Mani-Sadhasivam -/include/zephyr/drivers/led_strip.h @mbolivar-ampere -/include/zephyr/drivers/sensor.h @MaureenHelm -/include/zephyr/drivers/smbus.h @finikorg -/include/zephyr/drivers/spi.h @tbursztyka -/include/zephyr/drivers/sip_svc/ @maheshraotm -/include/zephyr/drivers/lora.h @Mani-Sadhasivam -/include/zephyr/drivers/peci.h @albertofloyd @franciscomunoz @sjvasanth1 -/include/zephyr/drivers/pm_cpu_ops.h @carlocaione -/include/zephyr/drivers/pm_cpu_ops/ @carlocaione -/include/zephyr/drivers/w1.h @str4t0m -/include/zephyr/drivers/pwm/max31790.h @benediktibk -/include/zephyr/app_memory/ @dcpleung -/include/zephyr/arch/arc/ @abrodkin @ruuddw @evgeniy-paltsev -/include/zephyr/arch/arc/arch.h @abrodkin @ruuddw @evgeniy-paltsev -/include/zephyr/arch/arc/v2/irq.h @abrodkin @ruuddw @evgeniy-paltsev -/include/zephyr/arch/arm @MaureenHelm @galak @ioannisg -/include/zephyr/arch/arm/cortex_a_r/ @stephanosio -/include/zephyr/arch/arm64/ @carlocaione -/include/zephyr/arch/arm64/cortex_r/ @povergoing -/include/zephyr/arch/arm/irq.h @carlocaione -/include/zephyr/arch/mips/ @frantony -/include/zephyr/arch/nios2/ @nashif -/include/zephyr/arch/nios2/arch.h @nashif -/include/zephyr/arch/posix/ @aescolar @daor-oti -/include/zephyr/arch/riscv/ @kgugala @pgielda -/include/zephyr/arch/x86/ @jhedberg @dcpleung -/include/zephyr/arch/common/ @andyross @nashif -/include/zephyr/arch/xtensa/ @andyross @dcpleung -/include/zephyr/arch/sparc/ @julius-barendt -/include/zephyr/sys/atomic.h @andyross -/include/zephyr/bluetooth/ @alwa-nordic @jhedberg @Vudentz @sjanc -/include/zephyr/bluetooth/audio/ @jhedberg @Vudentz @Thalley -/include/zephyr/cache.h @carlocaione @andyross -/include/zephyr/canbus/ @alexanderwachter @henrikbrixandersen -/include/zephyr/tracing/ @nashif -/include/zephyr/debug/ @nashif -/include/zephyr/debug/coredump.h @dcpleung -/include/zephyr/debug/gdbstub.h @ceolin -/include/zephyr/device.h @tbursztyka @nashif -/include/zephyr/devicetree.h @galak -/include/zephyr/devicetree/can.h @henrikbrixandersen -/include/zephyr/dt-bindings/clock/kinetis_mcg.h @henrikbrixandersen -/include/zephyr/dt-bindings/clock/kinetis_scg.h @henrikbrixandersen -/include/zephyr/dt-bindings/ethernet/xlnx_gem.h @ibirnbaum -/include/zephyr/dt-bindings/pcie/ @dcpleung -/include/zephyr/dt-bindings/pinctrl/esp* @sylvioalves -/include/zephyr/dt-bindings/pwm/*it8xxx2* @RuibinChang -/include/zephyr/dt-bindings/usb/usb.h @galak -/include/zephyr/dt-bindings/adc/ads114s0x_adc.h @benediktibk -/include/zephyr/drivers/emul.h @sjg20 -/include/zephyr/data/ @d3zd3z -/include/zephyr/fs/ @nashif @de-nordic -/include/zephyr/init.h @nashif @andyross -/include/zephyr/irq.h @dcpleung @nashif @andyross -/include/zephyr/irq_offload.h @dcpleung @nashif @andyross -/include/zephyr/kernel.h @dcpleung @nashif @andyross -/include/zephyr/kernel_version.h @dcpleung @nashif @andyross -/include/zephyr/linker/app_smem*.ld @dcpleung @nashif -/include/zephyr/linker/ @dcpleung @nashif @andyross -/include/zephyr/logging/ @nordic-krch -/include/zephyr/lorawan/lorawan.h @Mani-Sadhasivam -/include/zephyr/mgmt/osdp.h @sidcha -/include/zephyr/mgmt/mcumgr/ @nordicjm -/include/zephyr/net/ @rlubos @tbursztyka @jukkar -/include/zephyr/net/buf.h @jhedberg @tbursztyka @rlubos @jukkar -/include/zephyr/net/coap*.h @rlubos -/include/zephyr/net/conn_mgr*.h @rlubos @glarsennordic @jukkar -/include/zephyr/net/gptp.h @rlubos @jukkar @fgrandel -/include/zephyr/net/ieee802154*.h @rlubos @tbursztyka @jukkar @fgrandel -/include/zephyr/net/lwm2m*.h @rlubos -/include/zephyr/net/mqtt.h @rlubos -/include/zephyr/net/mqtt_sn.h @rlubos @BeckmaR -/include/zephyr/net/net_pkt_filter.h @npitre -/include/zephyr/posix/ @cfreidt -/include/zephyr/pm/pm.h @nashif @ceolin -/include/zephyr/drivers/ptp_clock.h @tbursztyka @jukkar -/include/zephyr/rtio/ @teburd -/include/zephyr/sensing/ @lixuzha @ghu0510 @qianruh -/include/zephyr/shared_irq.h @dcpleung @nashif @andyross -/include/zephyr/shell/ @jakub-uC @nordic-krch -/include/zephyr/shell/shell_mqtt.h @ycsin -/include/zephyr/sw_isr_table.h @dcpleung @nashif @andyross -/include/zephyr/sd/ @danieldegrasse -/include/zephyr/sip_svc/ @maheshraotm -/include/zephyr/sys_clock.h @dcpleung @nashif @andyross -/include/zephyr/sys/sys_io.h @dcpleung @nashif @andyross -/include/zephyr/sys/kobject.h @dcpleung @nashif -/include/zephyr/toolchain.h @dcpleung @andyross @nashif -/include/zephyr/toolchain/ @dcpleung @nashif @andyross -/include/zephyr/zephyr.h @dcpleung @nashif @andyross -/kernel/ @dcpleung @nashif @andyross -/lib/cpp/ @stephanosio -/lib/smf/ @sambhurst -/lib/util/ @carlescufi @jakub-uC -/lib/util/fnmatch/ @carlescufi @jakub-uC -/lib/open-amp/ @arnopo -/lib/os/ @dcpleung @nashif @andyross -/lib/os/cbprintf_packaged.c @npitre -/lib/os/json.c @d3zd3z -/lib/posix/ @cfriedt -/lib/posix/getopt/ @jakub-uC -/subsys/portability/ @nashif -/subsys/sensing/ @lixuzha @ghu0510 @qianruh -/lib/libc/ @nashif -/lib/libc/arcmwdt/ @abrodkin @ruuddw @evgeniy-paltsev -/misc/ @tejlmand -/modules/ @nashif -/modules/canopennode/ @henrikbrixandersen -/modules/mbedtls/ @ceolin @d3zd3z -/modules/hal_gigadevice/ @nandojve -/modules/hal_nordic/nrf_802154/ @jciupis -/modules/trusted-firmware-m/ @microbuilder -/kernel/device.c @andyross @nashif -/kernel/idle.c @andyross @nashif -/samples/ @nashif -/samples/application_development/sysbuild/ @tejlmand @nordicjm -/samples/basic/minimal/ @carlescufi -/samples/basic/servo_motor/boards/*microbit* @jhe -/samples/bluetooth/ @jhedberg @Vudentz @alwa-nordic @sjanc -/samples/compression/ @Navin-Sankar -/samples/drivers/can/ @alexanderwachter @henrikbrixandersen -/samples/drivers/clock_control_litex/ @mateusz-holenko @kgugala @pgielda -/samples/drivers/eeprom/ @henrikbrixandersen -/samples/drivers/ht16k33/ @henrikbrixandersen -/samples/drivers/lora/ @Mani-Sadhasivam -/samples/drivers/smbus/ @finikorg -/samples/subsys/lorawan/ @Mani-Sadhasivam -/samples/modules/canopennode/ @henrikbrixandersen -/samples/net/ @rlubos @tbursztyka @jukkar -/samples/net/cloud/tagoio_http_post/ @nandojve -/samples/net/dns_resolve/ @rlubos @tbursztyka @jukkar -/samples/net/gptp/ @rlubos @jukkar @fgrandel -/samples/net/lwm2m_client/ @rlubos -/samples/net/mqtt_publisher/ @rlubos -/samples/net/mqtt_sn_publisher/ @rlubos @BeckmaR -/samples/net/sockets/coap_*/ @rlubos -/samples/net/sockets/ @rlubos @tbursztyka @jukkar -/samples/sensor/ @MaureenHelm -/samples/shields/ @avisconti -/samples/subsys/ipc/ipc_service/icmsg @emob-nordic -/samples/subsys/logging/ @nordic-krch @jakub-uC -/samples/subsys/logging/syst/ @dcpleung -/samples/subsys/shell/ @jakub-uC @nordic-krch @gdengi -/samples/subsys/sip_svc/ @maheshraotm -/samples/subsys/mgmt/mcumgr/ @de-nordic @nordicjm -/samples/subsys/mgmt/updatehub/ @nandojve @otavio -/samples/subsys/mgmt/osdp/ @sidcha -/samples/subsys/usb/ @jfischer-no -/samples/subsys/usb_c/ @sambhurst -/samples/subsys/pm/ @nashif @ceolin -/samples/subsys/sensing/ @lixuzha @ghu0510 @qianruh -/samples/tfm_integration/ @microbuilder -/samples/userspace/ @dcpleung @nashif -/scripts/release/bug_bash.py @cfriedt -/scripts/coccicheck @himanshujha199640 @JuliaLawall -/scripts/coccinelle/ @himanshujha199640 @JuliaLawall -/scripts/coredump/ @dcpleung -/scripts/footprint/ @nashif -/scripts/kconfig/ @ulfalizer -/scripts/logging/dictionary/ @dcpleung -/scripts/native_simulator/ @aescolar -/scripts/pylib/twister/expr_parser.py @nashif -/scripts/schemas/twister/ @nashif -/scripts/build/gen_app_partitions.py @dcpleung @nashif -scripts/build/gen_image_info.py @tejlmand -/scripts/get_maintainer.py @nashif -/scripts/dts/ @mbolivar-ampere @galak -/scripts/release/ @nashif -/scripts/ci/ @nashif -/scripts/ci/check_compliance.py @nashif @carlescufi -/arch/x86/gen_gdt.py @dcpleung @nashif -/arch/x86/gen_idt.py @dcpleung @nashif -/scripts/build/gen_kobject_list.py @dcpleung @nashif -/scripts/build/gen_kobject_placeholders.py @dcpleung -/scripts/build/gen_syscalls.py @dcpleung @nashif -/scripts/list_boards.py @mbolivar-ampere -/scripts/build/process_gperf.py @dcpleung @nashif -/scripts/build/gen_relocate_app.py @dcpleung -/scripts/generate_usb_vif/ @madhurimaparuchuri -/scripts/requirements*.txt @mbolivar-ampere @galak @nashif -/scripts/tests/build/test_subfolder_list.py @rmstoi -/scripts/tracing/ @nashif -/scripts/pylib/twister/ @nashif -/scripts/twister @nashif -/scripts/series-push-hook.sh @erwango -/scripts/utils/pinctrl_nrf_migrate.py @gmarull -/scripts/utils/migrate_mcumgr_kconfigs.py @de-nordic -/scripts/west_commands/ @mbolivar-ampere -/scripts/west_commands/blobs.py @carlescufi -/scripts/west_commands/fetchers/ @carlescufi -/scripts/west_commands/runners/gd32isp.py @mbolivar-ampere @nandojve -/scripts/west_commands/tests/test_gd32isp.py @mbolivar-ampere @nandojve -/scripts/west-commands.yml @mbolivar-ampere -/scripts/zephyr_module.py @tejlmand -/scripts/build/uf2conv.py @petejohanson -/scripts/build/user_wordsize.py @cfriedt -/scripts/valgrind.supp @aescolar @daor-oti -/share/sysbuild/ @tejlmand @nordicjm -/share/zephyr-package/ @tejlmand -/share/zephyrunittest-package/ @tejlmand -/subsys/bluetooth/ @alwa-nordic @jhedberg @Vudentz -/subsys/bluetooth/audio/ @jhedberg @Vudentz @Thalley @sjanc -/subsys/bluetooth/controller/ @carlescufi @cvinayak @thoh-ot @kruithofa -/subsys/bluetooth/host/ @alwa-nordic @jhedberg @Vudentz @sjanc -/subsys/bluetooth/mesh/ @jhedberg @PavelVPV @Vudentz @LingaoM -/subsys/canbus/ @alexanderwachter @henrikbrixandersen -/subsys/debug/ @nashif -/subsys/debug/coredump/ @dcpleung -/subsys/debug/gdbstub/ @ceolin -/subsys/debug/gdbstub.c @ceolin -/subsys/dfu/ @de-nordic @nordicjm -/subsys/disk/ @jfischer-no -/subsys/dsp/ @yperess -/subsys/tracing/ @nashif -/subsys/debug/asan_hacks.c @aescolar @daor-oti -/subsys/demand_paging/ @dcpleung @nashif -/subsys/emul/ @sjg20 -/subsys/fb/ @jfischer-no -/subsys/fs/ @nashif -/subsys/fs/nvs/ @Laczen -/subsys/ipc/ @carlocaione -/subsys/ipc/ipc_service/*/*icmsg* @emob-nordic -/subsys/jwt/ @d3zd3z -/subsys/logging/ @nordic-krch -/subsys/logging/backends/log_backend_net.c @nordic-krch @rlubos @jukkar -/subsys/lorawan/ @Mani-Sadhasivam -/subsys/mgmt/ec_host_cmd/ @jettr -/subsys/mgmt/mcumgr/ @carlescufi @de-nordic @nordicjm -/subsys/mgmt/hawkbit/ @Navin-Sankar -/subsys/mgmt/updatehub/ @nandojve @otavio -/subsys/mgmt/osdp/ @sidcha -/subsys/modbus/ @jfischer-no -/subsys/net/buf.c @jhedberg @tbursztyka @rlubos @jukkar -/subsys/net/conn_mgr/ @rlubos @glarsennordic @jukkar -/subsys/net/ip/ @rlubos @tbursztyka @jukkar -/subsys/net/lib/ @rlubos @tbursztyka @jukkar -/subsys/net/lib/dns/ @rlubos @tbursztyka @cfriedt @jukkar -/subsys/net/lib/lwm2m/ @rlubos -/subsys/net/lib/config/ @rlubos @tbursztyka @jukkar -/subsys/net/lib/mqtt/ @rlubos -/subsys/net/lib/mqtt_sn/ @rlubos @BeckmaR -/subsys/net/lib/coap/ @rlubos -/subsys/net/lib/sockets/socketpair.c @cfriedt -/subsys/net/lib/sockets/ @rlubos @tbursztyka @jukkar -/subsys/net/lib/tls_credentials/ @rlubos -/subsys/net/l2/ @rlubos @tbursztyka @jukkar -/subsys/net/l2/ethernet/gptp/ @rlubos @jukkar @fgrandel -/subsys/net/l2/ieee802154/ @rlubos @tbursztyka @jukkar @fgrandel -/subsys/net/l2/canbus/ @alexanderwachter -/subsys/net/pkt_filter/ @npitre -/subsys/net/*/openthread/ @rlubos -/subsys/pm/ @nashif @ceolin -/subsys/random/ @dleach02 -/subsys/shell/ @jakub-uC @nordic-krch -/subsys/shell/backends/shell_mqtt.c @ycsin -/subsys/sd/ @danieldegrasse -/subsys/sip_svc/ @maheshraotm -/subsys/task_wdt/ @martinjaeger -/subsys/testsuite/ @nashif -/subsys/testsuite/ztest/*/ztress* @nordic-krch -/subsys/timing/ @nashif @dcpleung -/subsys/usb/ @jfischer-no -/subsys/usb/usb_c/ @sambhurst -/tests/ @nashif -/tests/arch/arm/ @ioannisg @stephanosio -/tests/benchmarks/cmsis_dsp/ @stephanosio -/tests/boards/native_posix/ @aescolar @daor-oti -/tests/bluetooth/ @alwa-nordic @jhedberg @Vudentz @sjanc -/tests/bluetooth/audio/ @jhedberg @Vudentz @wopu-ot @Thalley -/tests/bluetooth/controller/ @cvinayak @thoh-ot @kruithofa @erbr-ot @sjanc @ppryga -/tests/bsim/bluetooth/ @alwa-nordic @jhedberg @Vudentz @wopu-ot -/tests/bsim/bluetooth/audio/ @jhedberg @Vudentz @wopu-ot @Thalley -/tests/bsim/bluetooth/mesh/ @jhedberg @Vudentz @wopu-ot @PavelVPV -/tests/bluetooth/mesh_shell/ @jhedberg @Vudentz @sjanc @PavelVPV -/tests/bluetooth/tester/ @alwa-nordic @jhedberg @Vudentz @sjanc -/tests/posix/ @cfriedt -/tests/crypto/ @ceolin -/tests/crypto/mbedtls/ @nashif @ceolin @d3zd3z -/tests/drivers/can/ @alexanderwachter @henrikbrixandersen -/tests/drivers/counter/ @nordic-krch -/tests/drivers/eeprom/ @henrikbrixandersen @sjg20 -/tests/drivers/flash_simulator/ @de-nordic -/tests/drivers/gpio/ @mnkp -/tests/drivers/hwinfo/ @alexanderwachter -/tests/drivers/smbus/ @finikorg -/tests/drivers/spi/ @tbursztyka -/tests/drivers/uart/uart_async_api/ @anangl -/tests/drivers/w1/ @str4t0m -/tests/kernel/ @dcpleung @andyross @nashif -/tests/lib/ @nashif -/tests/lib/cmsis_dsp/ @stephanosio -/tests/lib/json/ @d3zd3z -/tests/net/ @rlubos @tbursztyka @jukkar -/tests/net/buf/ @jhedberg @tbursztyka @jukkar -/tests/net/conn_mgr_monitor/ @rlubos @glarsennordic @jukkar -/tests/net/conn_mgr_conn/ @rlubos @glarsennordic @jukkar -/tests/net/ieee802154/l2/ @rlubos @tbursztyka @jukkar @fgrandel -/tests/net/lib/ @rlubos @tbursztyka @jukkar -/tests/net/lib/http_header_fields/ @rlubos @tbursztyka @jukkar -/tests/net/lib/mqtt_packet/ @rlubos -/tests/net/lib/mqtt_sn_packet/ @rlubos @BeckmaR -/tests/net/lib/mqtt_sn_client/ @rlubos @BeckmaR -/tests/net/lib/coap/ @rlubos -/tests/net/npf/ @npitre -/tests/net/socket/socketpair/ @cfriedt -/tests/net/socket/ @rlubos @tbursztyka @jukkar -/tests/subsys/debug/coredump/ @dcpleung -/tests/subsys/fs/ @nashif @de-nordic -/tests/subsys/jwt/ @d3zd3z -/tests/subsys/mgmt/mcumgr/ @de-nordic @nordicjm -/tests/subsys/sd/ @danieldegrasse -/tests/subsys/rtio/ @teburd -/tests/subsys/shell/ @jakub-uC @nordic-krch -# Get all docs reviewed -*.rst @nashif -/doc/kernel/ @andyross @nashif -*posix*.rst @aescolar @daor-oti From 538abf3332e411de916670f538445385b2aff4a4 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 15 Nov 2023 11:40:00 -0500 Subject: [PATCH 0530/1049] doc: clarify role of CODEOWNERS and MAINTAINERS files Change docs to use MAINTAINERS file as the main file for managing code areas and 'ownership'. Signed-off-by: Anas Nashif --- CODEOWNERS | 7 ++++++- doc/contribute/guidelines.rst | 4 ++-- doc/project/dev_env_and_tools.rst | 9 +++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index ab9197825c53055..54f2b65933ad982 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -11,7 +11,12 @@ # add others as needed. # Do not use wildcard on all source yet -# * @galak @nashif +# +# +++++++++++ NOTE ++++++++++++++++ +# +# Please use the MAINTAINERS file to add yourself in an area or to add a new +# component or code. This file is going to be deprecated and currently only had +# entries that are not covered by the MAINTAINERS file. /soc/arm/aspeed/ @aspeeddylan /soc/arm/atmel_sam/common/*_sam4l_*.c @nandojve diff --git a/doc/contribute/guidelines.rst b/doc/contribute/guidelines.rst index ac88fa768ab4d30..b3dd735dd423c89 100644 --- a/doc/contribute/guidelines.rst +++ b/doc/contribute/guidelines.rst @@ -651,8 +651,8 @@ workflow here: request for the ``main`` branch. The title and message from your commit message should appear as well. -#. GitHub will assign one or more suggested reviewers (based on the - CODEOWNERS file in the repo). If you are a project member, you can +#. A bot will assign one or more suggested reviewers (based on the + MAINTAINERS file in the repo). If you are a project member, you can select additional reviewers now too. #. Click on the submit button and your pull request is sent and awaits diff --git a/doc/project/dev_env_and_tools.rst b/doc/project/dev_env_and_tools.rst index 37356ec3232cbe8..8269e891d430738 100644 --- a/doc/project/dev_env_and_tools.rst +++ b/doc/project/dev_env_and_tools.rst @@ -20,10 +20,11 @@ and linked to any relevant :ref:`bug or feature tracking issues` The Zephyr project uses GitHub for code reviews and Git tree management. When submitting a change or an enhancement to any Zephyr component, a developer -should use GitHub. GitHub automatically assigns a responsible reviewer on a -component basis, as defined in the :zephyr_file:`CODEOWNERS` file stored with the code -tree in the Zephyr project repository. A limited set of release managers are -allowed to merge a pull request into the main branch once reviews are complete. +should use GitHub. GitHub Actions automatically assigns a responsible reviewer +on a component basis, as defined in the :zephyr_file:`MAINTAINERS.yml` file +stored with the code tree in the Zephyr project repository. A limited set of +release managers are allowed to merge a pull request into the main branch once +reviews are complete. .. _review_time: From a48e68441ba47d179ab3a04f673d103c8d7ef305 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 14 Nov 2023 05:20:47 +0000 Subject: [PATCH 0531/1049] logging: Remove syscall for z_log_msg_runtime_vcreate This syscall is completely problematic in userspace, it does not check ANY parameter that is given and it uses variadic argument that are not copied / checked before being used in the implementation, instead it just pass a pointer to user stack with unknown data is blindly consumed by the kernel. Signed-off-by: Flavio Ceolin --- include/zephyr/logging/log_msg.h | 10 +++++----- subsys/logging/log_msg.c | 14 +------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/include/zephyr/logging/log_msg.h b/include/zephyr/logging/log_msg.h index c35a69d85ccec1a..fabc7a16b0cbdc3 100644 --- a/include/zephyr/logging/log_msg.h +++ b/include/zephyr/logging/log_msg.h @@ -679,11 +679,11 @@ __syscall void z_log_msg_static_create(const void *source, * * @param ap Variable list of string arguments. */ -__syscall void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source, - uint8_t level, const void *data, - size_t dlen, uint32_t package_flags, - const char *fmt, - va_list ap); +void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source, + uint8_t level, const void *data, + size_t dlen, uint32_t package_flags, + const char *fmt, + va_list ap); /** @brief Create message at runtime. * diff --git a/subsys/logging/log_msg.c b/subsys/logging/log_msg.c index a28f1ddc10aca44..8023cefbf8c2bbe 100644 --- a/subsys/logging/log_msg.c +++ b/subsys/logging/log_msg.c @@ -281,7 +281,7 @@ static inline void z_vrfy_z_log_msg_static_create(const void *source, #include #endif -void z_impl_z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source, +void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source, uint8_t level, const void *data, size_t dlen, uint32_t package_flags, const char *fmt, va_list ap) { @@ -330,15 +330,3 @@ void z_impl_z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source, z_log_msg_finalize(msg, source, desc, data); } } - -#ifdef CONFIG_USERSPACE -static inline void z_vrfy_z_log_msg_runtime_vcreate(uint8_t domain_id, - const void *source, - uint8_t level, const void *data, size_t dlen, - uint32_t package_flags, const char *fmt, va_list ap) -{ - return z_impl_z_log_msg_runtime_vcreate(domain_id, source, level, data, - dlen, package_flags, fmt, ap); -} -#include -#endif From d027d26298ba2dd7dd8924d5de84cf706633e997 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 14 Nov 2023 05:12:06 +0000 Subject: [PATCH 0532/1049] logging: LOG_PRINTK disabled in userspace LOG_PRINTK needs to run in supervisor mode and since there is no syscall that allows it to be called from userspace, this option has to be disabled when userspace is selected. Signed-off-by: Flavio Ceolin --- subsys/logging/Kconfig.processing | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/logging/Kconfig.processing b/subsys/logging/Kconfig.processing index 9051b6e3b460bfb..bc553aa239c92d9 100644 --- a/subsys/logging/Kconfig.processing +++ b/subsys/logging/Kconfig.processing @@ -7,6 +7,7 @@ if !LOG_MODE_MINIMAL config LOG_PRINTK bool "Process printk messages" + depends on !USERSPACE default y if PRINTK help If enabled, printk messages are redirected to the logging subsystem. From df7114456e17c8ff208f8f315286cea586d1a3c7 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 16 Nov 2023 12:05:04 +0100 Subject: [PATCH 0533/1049] tfm: Change default TF-M model for profile small to match profile conf Change the default TF-M model for small profile to match the configuration set in the profile small configuration file. Otherwise we would be overriding the profile default. Signed-off-by: Joakim Andersson --- modules/trusted-firmware-m/Kconfig.tfm | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index 2a5edb64343880c..d29b7093de01fea 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -302,6 +302,7 @@ endif # TFM_BL2 choice TFM_MODEL prompt "TF-M Firmware Framework model" + default TFM_SFN if TFM_PROFILE_TYPE_SMALL default TFM_IPC help The Firmware Framework M (FF-M) provides different programming models From ab08f34fd939a06daa5712e2a03e4b7d3b8da358 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Tue, 14 Nov 2023 12:00:30 +0800 Subject: [PATCH 0534/1049] Bluetooth: Mesh: Make bt_mesh_model as rodata Since model struct most of member should not change at run time, so mark as const will be suitable and safely. Signed-off-by: Lingao Meng --- .../bluetooth/api/mesh/blob_cli.rst | 2 +- .../bluetooth/api/mesh/blob_srv.rst | 2 +- include/zephyr/bluetooth/mesh/access.h | 89 ++++--- include/zephyr/bluetooth/mesh/blob_cli.h | 2 +- include/zephyr/bluetooth/mesh/blob_srv.h | 2 +- include/zephyr/bluetooth/mesh/cfg_cli.h | 2 +- include/zephyr/bluetooth/mesh/dfd_srv.h | 2 +- include/zephyr/bluetooth/mesh/dfu_cli.h | 2 +- include/zephyr/bluetooth/mesh/dfu_srv.h | 2 +- include/zephyr/bluetooth/mesh/health_cli.h | 2 +- include/zephyr/bluetooth/mesh/health_srv.h | 14 +- .../bluetooth/mesh/large_comp_data_cli.h | 2 +- .../zephyr/bluetooth/mesh/od_priv_proxy_cli.h | 2 +- .../zephyr/bluetooth/mesh/priv_beacon_cli.h | 2 +- include/zephyr/bluetooth/mesh/rpr_cli.h | 2 +- include/zephyr/bluetooth/mesh/sar_cfg_cli.h | 2 +- .../zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h | 2 +- include/zephyr/bluetooth/testing.h | 4 +- samples/bluetooth/mesh/src/main.c | 16 +- samples/bluetooth/mesh_demo/src/main.c | 10 +- samples/bluetooth/mesh_provisioner/src/main.c | 2 +- samples/boards/nrf/mesh/onoff-app/src/main.c | 34 +-- .../src/mesh/device_composition.c | 168 ++++++------ .../src/mesh/device_composition.h | 20 +- .../boards/reel_board/mesh_badge/src/mesh.c | 34 +-- subsys/bluetooth/host/testing.c | 4 +- subsys/bluetooth/host/testing.h | 4 +- subsys/bluetooth/mesh/access.c | 251 +++++++++--------- subsys/bluetooth/mesh/access.h | 22 +- subsys/bluetooth/mesh/blob_cli.c | 24 +- subsys/bluetooth/mesh/blob_srv.c | 44 +-- subsys/bluetooth/mesh/cfg_cli.c | 58 ++-- subsys/bluetooth/mesh/cfg_srv.c | 182 ++++++------- subsys/bluetooth/mesh/dfd_srv.c | 76 +++--- subsys/bluetooth/mesh/dfu_cli.c | 27 +- subsys/bluetooth/mesh/dfu_srv.c | 36 +-- subsys/bluetooth/mesh/foundation.h | 2 +- subsys/bluetooth/mesh/health_cli.c | 24 +- subsys/bluetooth/mesh/health_srv.c | 56 ++-- subsys/bluetooth/mesh/large_comp_data_cli.c | 12 +- subsys/bluetooth/mesh/large_comp_data_srv.c | 12 +- subsys/bluetooth/mesh/main.c | 6 +- subsys/bluetooth/mesh/msg.c | 4 +- subsys/bluetooth/mesh/msg.h | 4 +- subsys/bluetooth/mesh/od_priv_proxy_cli.c | 8 +- subsys/bluetooth/mesh/od_priv_proxy_srv.c | 22 +- subsys/bluetooth/mesh/op_agg.h | 4 +- subsys/bluetooth/mesh/op_agg_cli.c | 8 +- subsys/bluetooth/mesh/op_agg_srv.c | 8 +- subsys/bluetooth/mesh/priv_beacon_cli.c | 12 +- subsys/bluetooth/mesh/priv_beacon_srv.c | 28 +- subsys/bluetooth/mesh/rpr_cli.c | 40 +-- subsys/bluetooth/mesh/rpr_srv.c | 28 +- subsys/bluetooth/mesh/sar_cfg_cli.c | 16 +- subsys/bluetooth/mesh/sar_cfg_srv.c | 27 +- subsys/bluetooth/mesh/shell/blob.c | 20 +- subsys/bluetooth/mesh/shell/dfd.c | 22 +- subsys/bluetooth/mesh/shell/dfu.c | 30 +-- subsys/bluetooth/mesh/shell/health.c | 16 +- subsys/bluetooth/mesh/shell/rpr.c | 22 +- subsys/bluetooth/mesh/shell/shell.c | 12 +- subsys/bluetooth/mesh/shell/utils.c | 10 +- subsys/bluetooth/mesh/shell/utils.h | 4 +- subsys/bluetooth/mesh/sol_pdu_rpl_cli.c | 6 +- subsys/bluetooth/mesh/sol_pdu_rpl_srv.c | 10 +- tests/bluetooth/mesh/basic/src/main.c | 14 +- tests/bluetooth/mesh_shell/src/main.c | 2 +- tests/bluetooth/tester/src/btp_mesh.c | 20 +- tests/bsim/bluetooth/mesh/src/mesh_test.c | 24 +- tests/bsim/bluetooth/mesh/src/mesh_test.h | 6 +- tests/bsim/bluetooth/mesh/src/test_access.c | 48 ++-- tests/bsim/bluetooth/mesh/src/test_blob.c | 4 +- tests/bsim/bluetooth/mesh/src/test_cdp1.c | 26 +- tests/bsim/bluetooth/mesh/src/test_dfu.c | 8 +- tests/bsim/bluetooth/mesh/src/test_lcd.c | 13 +- tests/bsim/bluetooth/mesh/src/test_op_agg.c | 7 +- .../bluetooth/mesh/src/test_persistence.c | 8 +- .../bsim/bluetooth/mesh/src/test_provision.c | 6 +- tests/bsim/bluetooth/mesh/src/test_sar.c | 8 +- 79 files changed, 929 insertions(+), 887 deletions(-) diff --git a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst index 2232153f5498b50..25b90c281c49bba 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst @@ -25,7 +25,7 @@ The BLOB Transfer Client is instantiated on an element with a set of event handl .cb = &blob_cb, }; - static struct bt_mesh_model models[] = { + static const struct bt_mesh_model models[] = { BT_MESH_MODEL_BLOB_CLI(&blob_cli), }; diff --git a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst index a76ac34d6fb6a72..918b9493ff9a791 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst @@ -35,7 +35,7 @@ The BLOB Transfer Server is instantiated on an element with a set of event handl .cb = &blob_cb, }; - static struct bt_mesh_model models[] = { + static const struct bt_mesh_model models[] = { BT_MESH_MODEL_BLOB_SRV(&blob_srv), }; diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index 5272abe56452090..aa6235498147996 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -30,6 +30,13 @@ #define BT_MESH_MODEL_UUIDS_UNASSIGNED() #endif +#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS +#define BT_MESH_MODEL_NEXT_UNASSIGNED() \ + .next = (const struct bt_mesh_model *[]){ NULL }, +#else +#define BT_MESH_MODEL_NEXT_UNASSIGNED() +#endif + /** * @brief Access layer * @defgroup bt_mesh_access Access layer @@ -159,9 +166,9 @@ struct bt_mesh_elem { const uint8_t vnd_model_count; /** The list of SIG models in this element */ - struct bt_mesh_model * const models; + const struct bt_mesh_model * const models; /** The list of vendor models in this element */ - struct bt_mesh_model * const vnd_models; + const struct bt_mesh_model * const vnd_models; }; /** @@ -370,7 +377,7 @@ struct bt_mesh_model_op { * * @return Zero on success or (negative) error code otherwise. */ - int (*const func)(struct bt_mesh_model *model, + int (*const func)(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); }; @@ -403,7 +410,7 @@ struct bt_mesh_model_op { * This macro uses compound literal feature of C99 standard and thus is available only from C, * not C++. */ -#define BT_MESH_MODEL_NONE ((struct bt_mesh_model []){}) +#define BT_MESH_MODEL_NONE ((const struct bt_mesh_model []){}) /** * @brief Composition data SIG model entry with callback functions @@ -425,6 +432,9 @@ struct bt_mesh_model_op { #define BT_MESH_MODEL_CNT_CB(_id, _op, _pub, _user_data, _keys, _grps, _cb) \ { \ .id = (_id), \ + .elem_idx = (uint8_t []) { 0 }, \ + .mod_idx = (uint8_t []) { 0 }, \ + .flags = (uint16_t []) { 0 }, \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(_keys), \ .keys_cnt = _keys, \ @@ -433,7 +443,8 @@ struct bt_mesh_model_op { BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ - .user_data = _user_data, \ + BT_MESH_MODEL_NEXT_UNASSIGNED() \ + .user_data = (void *[]){ _user_data }, \ } /** @@ -458,6 +469,9 @@ struct bt_mesh_model_op { { \ .vnd.company = (_company), \ .vnd.id = (_id), \ + .elem_idx = (uint8_t []) { 0 }, \ + .mod_idx = (uint8_t []) { 0 }, \ + .flags = (uint16_t []) { 0 }, \ .op = _op, \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(_keys), \ @@ -465,7 +479,8 @@ struct bt_mesh_model_op { .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \ .groups_cnt = _grps, \ BT_MESH_MODEL_UUIDS_UNASSIGNED() \ - .user_data = _user_data, \ + BT_MESH_MODEL_NEXT_UNASSIGNED() \ + .user_data = (void *[]){ _user_data }, \ .cb = _cb, \ } @@ -505,6 +520,9 @@ struct bt_mesh_model_op { #define BT_MESH_MODEL_METADATA_CB(_id, _op, _pub, _user_data, _cb, _metadata) \ { \ .id = (_id), \ + .elem_idx = (uint8_t []) { 0 }, \ + .mod_idx = (uint8_t []) { 0 }, \ + .flags = (uint16_t []) { 0 }, \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(CONFIG_BT_MESH_MODEL_KEY_COUNT), \ .keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \ @@ -513,7 +531,8 @@ struct bt_mesh_model_op { BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ - .user_data = _user_data, \ + BT_MESH_MODEL_NEXT_UNASSIGNED() \ + .user_data = (void *[]){ _user_data }, \ .metadata = _metadata, \ } #else @@ -559,6 +578,9 @@ struct bt_mesh_model_op { { \ .vnd.company = (_company), \ .vnd.id = (_id), \ + .elem_idx = (uint8_t []) { 0 }, \ + .mod_idx = (uint8_t []) { 0 }, \ + .flags = (uint16_t []) { 0 }, \ .op = _op, \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(CONFIG_BT_MESH_MODEL_KEY_COUNT), \ @@ -566,7 +588,8 @@ struct bt_mesh_model_op { .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \ .groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \ BT_MESH_MODEL_UUIDS_UNASSIGNED() \ - .user_data = _user_data, \ + BT_MESH_MODEL_NEXT_UNASSIGNED() \ + .user_data = (void *[]){ _user_data }, \ .cb = _cb, \ .metadata = _metadata, \ } @@ -690,7 +713,7 @@ struct bt_mesh_model_op { */ struct bt_mesh_model_pub { /** The model the context belongs to. Initialized by the stack. */ - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; uint16_t addr; /**< Publish Address. */ const uint8_t *uuid; /**< Label UUID if Publish Address is Virtual Address. */ @@ -735,7 +758,7 @@ struct bt_mesh_model_pub { * * @return Zero on success or (negative) error code otherwise. */ - int (*update)(struct bt_mesh_model *mod); + int (*update)(const struct bt_mesh_model *mod); /** Publish Period Timer. Only for stack-internal use. */ struct k_work_delayable timer; @@ -805,7 +828,7 @@ struct bt_mesh_model_cb { * * @return 0 on success, error otherwise. */ - int (*const settings_set)(struct bt_mesh_model *model, + int (*const settings_set)(const struct bt_mesh_model *model, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg); @@ -821,7 +844,7 @@ struct bt_mesh_model_cb { * * @return 0 on success, error otherwise. */ - int (*const start)(struct bt_mesh_model *model); + int (*const start)(const struct bt_mesh_model *model); /** @brief Model init callback. * @@ -835,7 +858,7 @@ struct bt_mesh_model_cb { * * @return 0 on success, error otherwise. */ - int (*const init)(struct bt_mesh_model *model); + int (*const init)(const struct bt_mesh_model *model); /** @brief Model reset callback. * @@ -847,7 +870,7 @@ struct bt_mesh_model_cb { * * @param model Model this callback belongs to. */ - void (*const reset)(struct bt_mesh_model *model); + void (*const reset)(const struct bt_mesh_model *model); /** @brief Callback used to store pending model's user data. * @@ -857,7 +880,7 @@ struct bt_mesh_model_cb { * * @param model Model this callback belongs to. */ - void (*const pending_store)(struct bt_mesh_model *model); + void (*const pending_store)(const struct bt_mesh_model *model); }; /** Vendor model ID */ @@ -878,9 +901,9 @@ struct bt_mesh_model { }; /* Internal information, mainly for persistent storage */ - uint8_t elem_idx; /* Belongs to Nth element */ - uint8_t mod_idx; /* Is the Nth model in the element */ - uint16_t flags; /* Model flags for internal bookkeeping */ + uint8_t * const elem_idx; /* Belongs to Nth element */ + uint8_t * const mod_idx; /* Is the Nth model in the element */ + uint16_t * const flags; /* Model flags for internal bookkeeping */ /** Model Publication */ struct bt_mesh_model_pub * const pub; @@ -906,7 +929,7 @@ struct bt_mesh_model { #ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS /* Pointer to the next model in a model extension list. */ - struct bt_mesh_model *next; + const struct bt_mesh_model ** const next; #endif #if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) || defined(__DOXYGEN__) @@ -915,7 +938,7 @@ struct bt_mesh_model { #endif /** Model-specific user data */ - void *user_data; + void ** const user_data; }; /** Callback structure for monitoring model message sending */ @@ -952,7 +975,7 @@ struct bt_mesh_send_cb { * * @return 0 on success, or (negative) error code on failure. */ -int bt_mesh_model_send(struct bt_mesh_model *model, +int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, @@ -971,7 +994,7 @@ int bt_mesh_model_send(struct bt_mesh_model *model, * * @return 0 on success, or (negative) error code on failure. */ -int bt_mesh_model_publish(struct bt_mesh_model *model); +int bt_mesh_model_publish(const struct bt_mesh_model *model); /** @brief Check if a message is being retransmitted. * @@ -992,7 +1015,7 @@ static inline bool bt_mesh_model_pub_is_retransmission(const struct bt_mesh_mode * * @return Pointer to the element that the given model belongs to. */ -struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod); +struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod); /** @brief Find a SIG model. * @@ -1002,7 +1025,7 @@ struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod); * @return A pointer to the Mesh model matching the given parameters, or NULL * if no SIG model with the given ID exists in the given element. */ -struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, +const struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, uint16_t id); /** @brief Find a vendor model. @@ -1014,7 +1037,7 @@ struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, * @return A pointer to the Mesh model matching the given parameters, or NULL * if no vendor model with the given ID exists in the given element. */ -struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, +const struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, uint16_t company, uint16_t id); /** @brief Get whether the model is in the primary element of the device. @@ -1025,7 +1048,7 @@ struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, */ static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod) { - return (mod->elem_idx == 0); + return (*(mod->elem_idx) == 0); } /** @brief Immediately store the model's user data in persistent storage. @@ -1039,7 +1062,7 @@ static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod) * * @return 0 on success, or (negative) error code on failure. */ -int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, +int bt_mesh_model_data_store(const struct bt_mesh_model *mod, bool vnd, const char *name, const void *data, size_t data_len); @@ -1054,7 +1077,7 @@ int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, * * @param mod Mesh model. */ -void bt_mesh_model_data_store_schedule(struct bt_mesh_model *mod); +void bt_mesh_model_data_store_schedule(const struct bt_mesh_model *mod); /** @brief Let a model extend another. * @@ -1079,8 +1102,8 @@ void bt_mesh_model_data_store_schedule(struct bt_mesh_model *mod); * * @retval 0 Successfully extended the base_mod model. */ -int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, - struct bt_mesh_model *base_mod); +int bt_mesh_model_extend(const struct bt_mesh_model *extending_mod, + const struct bt_mesh_model *base_mod); /** @brief Let a model correspond to another. * @@ -1102,8 +1125,8 @@ int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, * @retval -ENOTSUP Composition Data Page 1 is not supported. */ -int bt_mesh_model_correspond(struct bt_mesh_model *corresponding_mod, - struct bt_mesh_model *base_mod); +int bt_mesh_model_correspond(const struct bt_mesh_model *corresponding_mod, + const struct bt_mesh_model *base_mod); /** @brief Check if model is extended by another model. * @@ -1111,7 +1134,7 @@ int bt_mesh_model_correspond(struct bt_mesh_model *corresponding_mod, * * @retval true If model is extended by another model, otherwise false */ -bool bt_mesh_model_is_extended(struct bt_mesh_model *model); +bool bt_mesh_model_is_extended(const struct bt_mesh_model *model); /** @brief Indicate that the composition data will change on next bootup. * diff --git a/include/zephyr/bluetooth/mesh/blob_cli.h b/include/zephyr/bluetooth/mesh/blob_cli.h index 3bf65beae39f74b..8e239b314571d87 100644 --- a/include/zephyr/bluetooth/mesh/blob_cli.h +++ b/include/zephyr/bluetooth/mesh/blob_cli.h @@ -291,7 +291,7 @@ struct bt_mesh_blob_cli { const struct bt_mesh_blob_cli_cb *cb; /* Runtime state */ - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct { struct bt_mesh_blob_target *target; diff --git a/include/zephyr/bluetooth/mesh/blob_srv.h b/include/zephyr/bluetooth/mesh/blob_srv.h index 57237f1d4bb860d..bf807bad92fb97f 100644 --- a/include/zephyr/bluetooth/mesh/blob_srv.h +++ b/include/zephyr/bluetooth/mesh/blob_srv.h @@ -136,7 +136,7 @@ struct bt_mesh_blob_srv { const struct bt_mesh_blob_io *io; struct k_work_delayable rx_timeout; struct bt_mesh_blob_block block; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; enum bt_mesh_blob_xfer_phase phase; struct bt_mesh_blob_srv_state { diff --git a/include/zephyr/bluetooth/mesh/cfg_cli.h b/include/zephyr/bluetooth/mesh/cfg_cli.h index 1a7c8ed7e2c1276..0e8c26131ffee40 100644 --- a/include/zephyr/bluetooth/mesh/cfg_cli.h +++ b/include/zephyr/bluetooth/mesh/cfg_cli.h @@ -332,7 +332,7 @@ struct bt_mesh_cfg_cli_cb { /** Mesh Configuration Client Model Context */ struct bt_mesh_cfg_cli { /** Composition data model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Optional callback for Mesh Configuration Client Status messages. */ const struct bt_mesh_cfg_cli_cb *cb; diff --git a/include/zephyr/bluetooth/mesh/dfd_srv.h b/include/zephyr/bluetooth/mesh/dfd_srv.h index 666e0d8ad3d36ac..f15768080d79696 100644 --- a/include/zephyr/bluetooth/mesh/dfd_srv.h +++ b/include/zephyr/bluetooth/mesh/dfd_srv.h @@ -210,7 +210,7 @@ struct bt_mesh_dfd_srv_cb { /** Firmware Distribution Server instance. */ struct bt_mesh_dfd_srv { const struct bt_mesh_dfd_srv_cb *cb; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_dfu_cli dfu; struct bt_mesh_dfu_target targets[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX]; struct bt_mesh_blob_target_pull pull_ctxs[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX]; diff --git a/include/zephyr/bluetooth/mesh/dfu_cli.h b/include/zephyr/bluetooth/mesh/dfu_cli.h index 51f534f2828ce8c..3cbc220d825d1ca 100644 --- a/include/zephyr/bluetooth/mesh/dfu_cli.h +++ b/include/zephyr/bluetooth/mesh/dfu_cli.h @@ -190,7 +190,7 @@ struct bt_mesh_dfu_cli { /* runtime state */ uint32_t op; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct { const struct bt_mesh_dfu_slot *slot; diff --git a/include/zephyr/bluetooth/mesh/dfu_srv.h b/include/zephyr/bluetooth/mesh/dfu_srv.h index 53d9144713c2a54..e136701e6643448 100644 --- a/include/zephyr/bluetooth/mesh/dfu_srv.h +++ b/include/zephyr/bluetooth/mesh/dfu_srv.h @@ -184,7 +184,7 @@ struct bt_mesh_dfu_srv { size_t img_count; /* Runtime state */ - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct { /* Effect of transfer, @see bt_mesh_dfu_effect. */ uint8_t effect; diff --git a/include/zephyr/bluetooth/mesh/health_cli.h b/include/zephyr/bluetooth/mesh/health_cli.h index 2f13dd88ccfb258..2d8904ea6f279a7 100644 --- a/include/zephyr/bluetooth/mesh/health_cli.h +++ b/include/zephyr/bluetooth/mesh/health_cli.h @@ -26,7 +26,7 @@ extern "C" { /** Health Client Model Context */ struct bt_mesh_health_cli { /** Composition data model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Publication structure instance */ struct bt_mesh_model_pub pub; diff --git a/include/zephyr/bluetooth/mesh/health_srv.h b/include/zephyr/bluetooth/mesh/health_srv.h index 9665e3bc62a9d36..bb1e48004b93648 100644 --- a/include/zephyr/bluetooth/mesh/health_srv.h +++ b/include/zephyr/bluetooth/mesh/health_srv.h @@ -53,7 +53,7 @@ struct bt_mesh_health_srv_cb { * * @return 0 on success, or (negative) error code otherwise. */ - int (*fault_get_cur)(struct bt_mesh_model *model, uint8_t *test_id, + int (*fault_get_cur)(const struct bt_mesh_model *model, uint8_t *test_id, uint16_t *company_id, uint8_t *faults, uint8_t *fault_count); @@ -79,7 +79,7 @@ struct bt_mesh_health_srv_cb { * * @return 0 on success, or (negative) error code otherwise. */ - int (*fault_get_reg)(struct bt_mesh_model *model, uint16_t company_id, + int (*fault_get_reg)(const struct bt_mesh_model *model, uint16_t company_id, uint8_t *test_id, uint8_t *faults, uint8_t *fault_count); @@ -91,7 +91,7 @@ struct bt_mesh_health_srv_cb { * * @return 0 on success, or (negative) error code otherwise. */ - int (*fault_clear)(struct bt_mesh_model *model, uint16_t company_id); + int (*fault_clear)(const struct bt_mesh_model *model, uint16_t company_id); /** @brief Run a self-test. * @@ -108,7 +108,7 @@ struct bt_mesh_health_srv_cb { * (negative) error code otherwise. Note that the fault array will not * be reported back to the client if the test execution didn't start. */ - int (*fault_test)(struct bt_mesh_model *model, uint8_t test_id, + int (*fault_test)(const struct bt_mesh_model *model, uint8_t test_id, uint16_t company_id); /** @brief Start calling attention to the device. @@ -125,7 +125,7 @@ struct bt_mesh_health_srv_cb { * * @param model Health Server model to start the attention state of. */ - void (*attn_on)(struct bt_mesh_model *model); + void (*attn_on)(const struct bt_mesh_model *model); /** @brief Stop the attention state. * @@ -134,7 +134,7 @@ struct bt_mesh_health_srv_cb { * * @param model */ - void (*attn_off)(struct bt_mesh_model *model); + void (*attn_off)(const struct bt_mesh_model *model); }; /** @@ -149,7 +149,7 @@ struct bt_mesh_health_srv_cb { /** Mesh Health Server Model Context */ struct bt_mesh_health_srv { /** Composition data model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Optional callback struct */ const struct bt_mesh_health_srv_cb *cb; diff --git a/include/zephyr/bluetooth/mesh/large_comp_data_cli.h b/include/zephyr/bluetooth/mesh/large_comp_data_cli.h index b7ed07762045253..520fcb3a6b53785 100644 --- a/include/zephyr/bluetooth/mesh/large_comp_data_cli.h +++ b/include/zephyr/bluetooth/mesh/large_comp_data_cli.h @@ -69,7 +69,7 @@ struct bt_mesh_large_comp_data_cli_cb { /** Large Composition Data Client model context */ struct bt_mesh_large_comp_data_cli { /** Model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Internal parameters for tracking message responses. */ struct bt_mesh_msg_ack_ctx ack_ctx; diff --git a/include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h b/include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h index f9734d78d3ebb34..0234158b04691d1 100644 --- a/include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h +++ b/include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h @@ -22,7 +22,7 @@ extern "C" { /** On-Demand Private Proxy Client Model Context */ struct bt_mesh_od_priv_proxy_cli { /** Solicitation PDU RPL model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /* Internal parameters for tracking message responses. */ struct bt_mesh_msg_ack_ctx ack_ctx; diff --git a/include/zephyr/bluetooth/mesh/priv_beacon_cli.h b/include/zephyr/bluetooth/mesh/priv_beacon_cli.h index 835dc38c773d602..24fba6f67be68e8 100644 --- a/include/zephyr/bluetooth/mesh/priv_beacon_cli.h +++ b/include/zephyr/bluetooth/mesh/priv_beacon_cli.h @@ -90,7 +90,7 @@ struct bt_mesh_priv_beacon_cli_cb { /** Mesh Private Beacon Client model */ struct bt_mesh_priv_beacon_cli { - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /* Internal parameters for tracking message responses. */ struct bt_mesh_msg_ack_ctx ack_ctx; diff --git a/include/zephyr/bluetooth/mesh/rpr_cli.h b/include/zephyr/bluetooth/mesh/rpr_cli.h index 5c0374fecc3bb5d..414e2887bdf059f 100644 --- a/include/zephyr/bluetooth/mesh/rpr_cli.h +++ b/include/zephyr/bluetooth/mesh/rpr_cli.h @@ -91,7 +91,7 @@ struct bt_mesh_rpr_cli { enum bt_mesh_rpr_link_state state; } link; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; }; /** @brief Get scanning capabilities of Remote Provisioning Server. diff --git a/include/zephyr/bluetooth/mesh/sar_cfg_cli.h b/include/zephyr/bluetooth/mesh/sar_cfg_cli.h index 7882174512e4b03..5e8409d38412a99 100644 --- a/include/zephyr/bluetooth/mesh/sar_cfg_cli.h +++ b/include/zephyr/bluetooth/mesh/sar_cfg_cli.h @@ -27,7 +27,7 @@ extern "C" { /** Mesh SAR Configuration Client Model Context */ struct bt_mesh_sar_cfg_cli { /** Access model pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /* Publication structure instance */ struct bt_mesh_model_pub pub; diff --git a/include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h b/include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h index 5a3dcdd784dc224..5a6c49bd2119ace 100644 --- a/include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h +++ b/include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h @@ -22,7 +22,7 @@ extern "C" { /** Solicitation PDU RPL Client Model Context */ struct bt_mesh_sol_pdu_rpl_cli { /** Solicitation PDU RPL model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /* Internal parameters for tracking message responses. */ struct bt_mesh_msg_ack_ctx ack_ctx; diff --git a/include/zephyr/bluetooth/testing.h b/include/zephyr/bluetooth/testing.h index 9cfda4e11779908..58aae9726ffa1a3 100644 --- a/include/zephyr/bluetooth/testing.h +++ b/include/zephyr/bluetooth/testing.h @@ -39,9 +39,9 @@ struct bt_test_cb { const void *payload, size_t payload_len); void (*mesh_model_recv)(uint16_t src, uint16_t dst, const void *payload, size_t payload_len); - void (*mesh_model_bound)(uint16_t addr, struct bt_mesh_model *model, + void (*mesh_model_bound)(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx); - void (*mesh_model_unbound)(uint16_t addr, struct bt_mesh_model *model, + void (*mesh_model_unbound)(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx); void (*mesh_prov_invalid_bearer)(uint8_t opcode); void (*mesh_trans_incomp_timer_exp)(void); diff --git a/samples/bluetooth/mesh/src/main.c b/samples/bluetooth/mesh/src/main.c index 6914c4fc40975d5..5555edef9bbbee3 100644 --- a/samples/bluetooth/mesh/src/main.c +++ b/samples/bluetooth/mesh/src/main.c @@ -25,12 +25,12 @@ #define OP_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03) #define OP_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04) -static void attention_on(struct bt_mesh_model *mod) +static void attention_on(const struct bt_mesh_model *mod) { board_led_set(true); } -static void attention_off(struct bt_mesh_model *mod) +static void attention_off(const struct bt_mesh_model *mod) { board_led_set(false); } @@ -102,7 +102,7 @@ static inline uint8_t model_time_encode(int32_t ms) return 0x3f; } -static int onoff_status_send(struct bt_mesh_model *model, +static int onoff_status_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { uint32_t remaining; @@ -151,7 +151,7 @@ static void onoff_timeout(struct k_work *work) /* Generic OnOff Server message handlers */ -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -159,7 +159,7 @@ static int gen_onoff_get(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -202,7 +202,7 @@ static int gen_onoff_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -221,7 +221,7 @@ static const struct bt_mesh_model_op gen_onoff_srv_op[] = { /* Generic OnOff Client */ -static int gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -248,7 +248,7 @@ static const struct bt_mesh_model_op gen_onoff_cli_op[] = { }; /* This application only needs one element to contain its models */ -static struct bt_mesh_model models[] = { +static const struct bt_mesh_model models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, NULL, diff --git a/samples/bluetooth/mesh_demo/src/main.c b/samples/bluetooth/mesh_demo/src/main.c index 642cce1d18ec6e0..08d6a1aae9b59bf 100644 --- a/samples/bluetooth/mesh_demo/src/main.c +++ b/samples/bluetooth/mesh_demo/src/main.c @@ -50,14 +50,14 @@ static void heartbeat(const struct bt_mesh_hb_sub *sub, uint8_t hops, static struct bt_mesh_cfg_cli cfg_cli = { }; -static void attention_on(struct bt_mesh_model *model) +static void attention_on(const struct bt_mesh_model *model) { printk("attention_on()\n"); board_attention(true); board_play("100H100C100H100C100H100C"); } -static void attention_off(struct bt_mesh_model *model) +static void attention_off(const struct bt_mesh_model *model) { printk("attention_off()\n"); board_attention(false); @@ -74,13 +74,13 @@ static struct bt_mesh_health_srv health_srv = { BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0); -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), }; -static int vnd_button_pressed(struct bt_mesh_model *model, +static int vnd_button_pressed(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -101,7 +101,7 @@ static const struct bt_mesh_model_op vnd_ops[] = { BT_MESH_MODEL_OP_END, }; -static struct bt_mesh_model vnd_models[] = { +static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(BT_COMP_ID_LF, MOD_LF, vnd_ops, NULL, NULL), }; diff --git a/samples/bluetooth/mesh_provisioner/src/main.c b/samples/bluetooth/mesh_provisioner/src/main.c index 42eaa31207b2095..057087a2e8afa09 100644 --- a/samples/bluetooth/mesh_provisioner/src/main.c +++ b/samples/bluetooth/mesh_provisioner/src/main.c @@ -53,7 +53,7 @@ static struct bt_mesh_health_cli health_cli = { .current_status = health_current_status, }; -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_CLI(&health_cli), diff --git a/samples/boards/nrf/mesh/onoff-app/src/main.c b/samples/boards/nrf/mesh/onoff-app/src/main.c index 9e8788d464260da..817d2c023a61cd5 100644 --- a/samples/boards/nrf/mesh/onoff-app/src/main.c +++ b/samples/boards/nrf/mesh/onoff-app/src/main.c @@ -54,19 +54,19 @@ #define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03) #define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04) -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); -static int gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -167,7 +167,7 @@ static struct led_onoff_state led_onoff_states[] = { * Element 0 Root Models */ -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), @@ -181,7 +181,7 @@ static struct bt_mesh_model root_models[] = { * Element 1 Models */ -static struct bt_mesh_model secondary_0_models[] = { +static const struct bt_mesh_model secondary_0_models[] = { BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, &gen_onoff_pub_srv_s_0, &led_onoff_states[1]), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, @@ -192,7 +192,7 @@ static struct bt_mesh_model secondary_0_models[] = { * Element 2 Models */ -static struct bt_mesh_model secondary_1_models[] = { +static const struct bt_mesh_model secondary_1_models[] = { BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, &gen_onoff_pub_srv_s_1, &led_onoff_states[2]), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, @@ -203,7 +203,7 @@ static struct bt_mesh_model secondary_1_models[] = { * Element 3 Models */ -static struct bt_mesh_model secondary_2_models[] = { +static const struct bt_mesh_model secondary_2_models[] = { BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, &gen_onoff_pub_srv_s_2, &led_onoff_states[3]), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, @@ -214,7 +214,7 @@ static struct bt_mesh_model secondary_2_models[] = { * Button to Client Model Assignments */ -struct bt_mesh_model *mod_cli_sw[] = { +const struct bt_mesh_model *mod_cli_sw[] = { &root_models[4], &secondary_0_models[1], &secondary_1_models[1], @@ -225,7 +225,7 @@ struct bt_mesh_model *mod_cli_sw[] = { * LED to Server Model Assignments */ -struct bt_mesh_model *mod_srv_sw[] = { +const struct bt_mesh_model *mod_srv_sw[] = { &root_models[3], &secondary_0_models[0], &secondary_1_models[0], @@ -281,12 +281,12 @@ static uint16_t primary_net_idx; * */ -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); - struct led_onoff_state *onoff_state = model->user_data; + struct led_onoff_state *onoff_state = *(model->user_data); printk("addr 0x%04x onoff 0x%02x\n", bt_mesh_model_elem(model)->addr, onoff_state->current); @@ -300,12 +300,12 @@ static int gen_onoff_get(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct net_buf_simple *msg = model->pub->msg; - struct led_onoff_state *onoff_state = model->user_data; + struct led_onoff_state *onoff_state = *(model->user_data); int err; onoff_state->current = net_buf_simple_pull_u8(buf); @@ -340,7 +340,7 @@ static int gen_onoff_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -352,7 +352,7 @@ static int gen_onoff_set(struct bt_mesh_model *model, return 0; } -static int gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -465,7 +465,7 @@ static void button_cnt_timer(struct k_timer *work) static void button_pressed_worker(struct k_work *work) { - struct bt_mesh_model *mod_cli, *mod_srv; + const struct bt_mesh_model *mod_cli, *mod_srv; struct bt_mesh_model_pub *pub_cli, *pub_srv; struct switch_data *button_sw = CONTAINER_OF(work, struct switch_data, button_work); int err; diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c index 2cf7abc30485694..54a5a2c8af730e1 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c @@ -68,7 +68,7 @@ static struct bt_mesh_elem elements[]; /* message handlers (Start) */ /* Generic OnOff Server message handlers */ -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -95,7 +95,7 @@ static int gen_onoff_get(struct bt_mesh_model *model, return 0; } -void gen_onoff_publish(struct bt_mesh_model *model) +void gen_onoff_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -119,7 +119,7 @@ void gen_onoff_publish(struct bt_mesh_model *model) } } -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -188,7 +188,7 @@ static int gen_onoff_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -261,7 +261,7 @@ static int gen_onoff_set(struct bt_mesh_model *model, } /* Generic OnOff Client message handlers */ -static int gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -277,7 +277,7 @@ static int gen_onoff_status(struct bt_mesh_model *model, } /* Generic Level (LIGHTNESS) Server message handlers */ -static int gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -304,7 +304,7 @@ static int gen_level_get(struct bt_mesh_model *model, return 0; } -void gen_level_publish(struct bt_mesh_model *model) +void gen_level_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -328,7 +328,7 @@ void gen_level_publish(struct bt_mesh_model *model) } } -static int gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -394,7 +394,7 @@ static int gen_level_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -463,7 +463,7 @@ static int gen_level_set(struct bt_mesh_model *model, return 0; } -static int gen_delta_set_unack(struct bt_mesh_model *model, +static int gen_delta_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -545,7 +545,7 @@ static int gen_delta_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_delta_set(struct bt_mesh_model *model, +static int gen_delta_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -630,7 +630,7 @@ static int gen_delta_set(struct bt_mesh_model *model, return 0; } -static int gen_move_set_unack(struct bt_mesh_model *model, +static int gen_move_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -705,7 +705,7 @@ static int gen_move_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_move_set(struct bt_mesh_model *model, +static int gen_move_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t tid, tt, delay; @@ -783,7 +783,7 @@ static int gen_move_set(struct bt_mesh_model *model, } /* Generic Level Client message handlers */ -static int gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -799,7 +799,7 @@ static int gen_level_status(struct bt_mesh_model *model, } /* Generic Default Transition Time Server message handlers */ -static int gen_def_trans_time_get(struct bt_mesh_model *model, +static int gen_def_trans_time_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -815,7 +815,7 @@ static int gen_def_trans_time_get(struct bt_mesh_model *model, return 0; } -static void gen_def_trans_time_publish(struct bt_mesh_model *model) +static void gen_def_trans_time_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -833,7 +833,7 @@ static void gen_def_trans_time_publish(struct bt_mesh_model *model) } } -static int gen_def_trans_time_set_unack(struct bt_mesh_model *model, +static int gen_def_trans_time_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -855,7 +855,7 @@ static int gen_def_trans_time_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_def_trans_time_set(struct bt_mesh_model *model, +static int gen_def_trans_time_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -881,7 +881,7 @@ static int gen_def_trans_time_set(struct bt_mesh_model *model, } /* Generic Default Transition Time Client message handlers */ -static int gen_def_trans_time_status(struct bt_mesh_model *model, +static int gen_def_trans_time_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -892,7 +892,7 @@ static int gen_def_trans_time_status(struct bt_mesh_model *model, } /* Generic Power OnOff Server message handlers */ -static int gen_onpowerup_get(struct bt_mesh_model *model, +static int gen_onpowerup_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -909,7 +909,7 @@ static int gen_onpowerup_get(struct bt_mesh_model *model, } /* Generic Power OnOff Client message handlers */ -static int gen_onpowerup_status(struct bt_mesh_model *model, +static int gen_onpowerup_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -921,7 +921,7 @@ static int gen_onpowerup_status(struct bt_mesh_model *model, /* Generic Power OnOff Setup Server message handlers */ -static void gen_onpowerup_publish(struct bt_mesh_model *model) +static void gen_onpowerup_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -939,7 +939,7 @@ static void gen_onpowerup_publish(struct bt_mesh_model *model) } } -static int gen_onpowerup_set_unack(struct bt_mesh_model *model, +static int gen_onpowerup_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -961,7 +961,7 @@ static int gen_onpowerup_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onpowerup_set(struct bt_mesh_model *model, +static int gen_onpowerup_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -987,11 +987,11 @@ static int gen_onpowerup_set(struct bt_mesh_model *model, } /* Vendor Model message handlers*/ -static int vnd_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct net_buf_simple *msg = NET_BUF_SIMPLE(3 + 6 + 4); - struct vendor_state *state = model->user_data; + struct vendor_state *state = *(model->user_data); /* This is dummy response for demo purpose */ state->response = 0xA578FEB3; @@ -1007,14 +1007,14 @@ static int vnd_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int vnd_set_unack(struct bt_mesh_model *model, +static int vnd_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t tid; int current; int64_t now; - struct vendor_state *state = model->user_data; + struct vendor_state *state = *(model->user_data); current = net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -1040,7 +1040,7 @@ static int vnd_set_unack(struct bt_mesh_model *model, return 0; } -static int vnd_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { (void)vnd_set_unack(model, ctx, buf); @@ -1049,7 +1049,7 @@ static int vnd_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int vnd_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { printk("Acknowledgement from Vendor\n"); @@ -1060,7 +1060,7 @@ static int vnd_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, } /* Light Lightness Server message handlers */ -static int light_lightness_get(struct bt_mesh_model *model, +static int light_lightness_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1087,7 +1087,7 @@ static int light_lightness_get(struct bt_mesh_model *model, return 0; } -void light_lightness_publish(struct bt_mesh_model *model) +void light_lightness_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1111,7 +1111,7 @@ void light_lightness_publish(struct bt_mesh_model *model) } } -static int light_lightness_set_unack(struct bt_mesh_model *model, +static int light_lightness_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1177,7 +1177,7 @@ static int light_lightness_set_unack(struct bt_mesh_model *model, return 0; } -static int light_lightness_set(struct bt_mesh_model *model, +static int light_lightness_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1246,7 +1246,7 @@ static int light_lightness_set(struct bt_mesh_model *model, return 0; } -static int light_lightness_linear_get(struct bt_mesh_model *model, +static int light_lightness_linear_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1274,7 +1274,7 @@ static int light_lightness_linear_get(struct bt_mesh_model *model, return 0; } -void light_lightness_linear_publish(struct bt_mesh_model *model) +void light_lightness_linear_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1299,7 +1299,7 @@ void light_lightness_linear_publish(struct bt_mesh_model *model) } } -static int light_lightness_linear_set_unack(struct bt_mesh_model *model, +static int light_lightness_linear_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1365,7 +1365,7 @@ static int light_lightness_linear_set_unack(struct bt_mesh_model *model, return 0; } -static int light_lightness_linear_set(struct bt_mesh_model *model, +static int light_lightness_linear_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1434,7 +1434,7 @@ static int light_lightness_linear_set(struct bt_mesh_model *model, return 0; } -static int light_lightness_last_get(struct bt_mesh_model *model, +static int light_lightness_last_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1450,7 +1450,7 @@ static int light_lightness_last_get(struct bt_mesh_model *model, return 0; } -static int light_lightness_default_get(struct bt_mesh_model *model, +static int light_lightness_default_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1467,7 +1467,7 @@ static int light_lightness_default_get(struct bt_mesh_model *model, return 0; } -static int light_lightness_range_get(struct bt_mesh_model *model, +static int light_lightness_range_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1489,7 +1489,7 @@ static int light_lightness_range_get(struct bt_mesh_model *model, /* Light Lightness Setup Server message handlers */ -static void light_lightness_default_publish(struct bt_mesh_model *model) +static void light_lightness_default_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1508,7 +1508,7 @@ static void light_lightness_default_publish(struct bt_mesh_model *model) } } -static int light_lightness_default_set_unack(struct bt_mesh_model *model, +static int light_lightness_default_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1527,7 +1527,7 @@ static int light_lightness_default_set_unack(struct bt_mesh_model *model, return 0; } -static int light_lightness_default_set(struct bt_mesh_model *model, +static int light_lightness_default_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1549,7 +1549,7 @@ static int light_lightness_default_set(struct bt_mesh_model *model, return 0; } -static void light_lightness_range_publish(struct bt_mesh_model *model) +static void light_lightness_range_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1569,7 +1569,7 @@ static void light_lightness_range_publish(struct bt_mesh_model *model) } } -static int light_lightness_range_set_unack(struct bt_mesh_model *model, +static int light_lightness_range_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1603,7 +1603,7 @@ static int light_lightness_range_set_unack(struct bt_mesh_model *model, return 0; } -static int light_lightness_range_set(struct bt_mesh_model *model, +static int light_lightness_range_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1641,7 +1641,7 @@ static int light_lightness_range_set(struct bt_mesh_model *model, } /* Light Lightness Client message handlers */ -static int light_lightness_status(struct bt_mesh_model *model, +static int light_lightness_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1657,7 +1657,7 @@ static int light_lightness_status(struct bt_mesh_model *model, return 0; } -static int light_lightness_linear_status(struct bt_mesh_model *model, +static int light_lightness_linear_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1673,7 +1673,7 @@ static int light_lightness_linear_status(struct bt_mesh_model *model, return 0; } -static int light_lightness_last_status(struct bt_mesh_model *model, +static int light_lightness_last_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1683,7 +1683,7 @@ static int light_lightness_last_status(struct bt_mesh_model *model, return 0; } -static int light_lightness_default_status(struct bt_mesh_model *model, +static int light_lightness_default_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1693,7 +1693,7 @@ static int light_lightness_default_status(struct bt_mesh_model *model, return 0; } -static int light_lightness_range_status(struct bt_mesh_model *model, +static int light_lightness_range_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1706,7 +1706,7 @@ static int light_lightness_range_status(struct bt_mesh_model *model, } /* Light CTL Server message handlers */ -static int light_ctl_get(struct bt_mesh_model *model, +static int light_ctl_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1736,7 +1736,7 @@ static int light_ctl_get(struct bt_mesh_model *model, return 0; } -void light_ctl_publish(struct bt_mesh_model *model) +void light_ctl_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1766,7 +1766,7 @@ void light_ctl_publish(struct bt_mesh_model *model) } } -static int light_ctl_set_unack(struct bt_mesh_model *model, +static int light_ctl_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1845,7 +1845,7 @@ static int light_ctl_set_unack(struct bt_mesh_model *model, return 0; } -static int light_ctl_set(struct bt_mesh_model *model, +static int light_ctl_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1927,7 +1927,7 @@ static int light_ctl_set(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_range_get(struct bt_mesh_model *model, +static int light_ctl_temp_range_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1947,7 +1947,7 @@ static int light_ctl_temp_range_get(struct bt_mesh_model *model, return 0; } -static int light_ctl_default_get(struct bt_mesh_model *model, +static int light_ctl_default_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1967,7 +1967,7 @@ static int light_ctl_default_get(struct bt_mesh_model *model, /* Light CTL Setup Server message handlers */ -static void light_ctl_default_publish(struct bt_mesh_model *model) +static void light_ctl_default_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1987,7 +1987,7 @@ static void light_ctl_default_publish(struct bt_mesh_model *model) } } -static int light_ctl_default_set_unack(struct bt_mesh_model *model, +static int light_ctl_default_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2018,7 +2018,7 @@ static int light_ctl_default_set_unack(struct bt_mesh_model *model, return 0; } -static int light_ctl_default_set(struct bt_mesh_model *model, +static int light_ctl_default_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2052,7 +2052,7 @@ static int light_ctl_default_set(struct bt_mesh_model *model, return 0; } -static void light_ctl_temp_range_publish(struct bt_mesh_model *model) +static void light_ctl_temp_range_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -2072,7 +2072,7 @@ static void light_ctl_temp_range_publish(struct bt_mesh_model *model) } } -static int light_ctl_temp_range_set_unack(struct bt_mesh_model *model, +static int light_ctl_temp_range_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2108,7 +2108,7 @@ static int light_ctl_temp_range_set_unack(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_range_set(struct bt_mesh_model *model, +static int light_ctl_temp_range_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2148,7 +2148,7 @@ static int light_ctl_temp_range_set(struct bt_mesh_model *model, } /* Light CTL Client message handlers */ -static int light_ctl_status(struct bt_mesh_model *model, +static int light_ctl_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2168,7 +2168,7 @@ static int light_ctl_status(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_range_status(struct bt_mesh_model *model, +static int light_ctl_temp_range_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2180,7 +2180,7 @@ static int light_ctl_temp_range_status(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_status(struct bt_mesh_model *model, +static int light_ctl_temp_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2201,7 +2201,7 @@ static int light_ctl_temp_status(struct bt_mesh_model *model, return 0; } -static int light_ctl_default_status(struct bt_mesh_model *model, +static int light_ctl_default_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2214,7 +2214,7 @@ static int light_ctl_default_status(struct bt_mesh_model *model, } /* Light CTL Temp. Server message handlers */ -static int light_ctl_temp_get(struct bt_mesh_model *model, +static int light_ctl_temp_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2244,7 +2244,7 @@ static int light_ctl_temp_get(struct bt_mesh_model *model, return 0; } -void light_ctl_temp_publish(struct bt_mesh_model *model) +void light_ctl_temp_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -2270,7 +2270,7 @@ void light_ctl_temp_publish(struct bt_mesh_model *model) } } -static int light_ctl_temp_set_unack(struct bt_mesh_model *model, +static int light_ctl_temp_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2345,7 +2345,7 @@ static int light_ctl_temp_set_unack(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_set(struct bt_mesh_model *model, +static int light_ctl_temp_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2424,7 +2424,7 @@ static int light_ctl_temp_set(struct bt_mesh_model *model, } /* Generic Level (TEMPERATURE) Server message handlers */ -static int gen_level_get_temp(struct bt_mesh_model *model, +static int gen_level_get_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2451,7 +2451,7 @@ static int gen_level_get_temp(struct bt_mesh_model *model, return 0; } -void gen_level_publish_temp(struct bt_mesh_model *model) +void gen_level_publish_temp(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -2475,7 +2475,7 @@ void gen_level_publish_temp(struct bt_mesh_model *model) } } -static int gen_level_set_unack_temp(struct bt_mesh_model *model, +static int gen_level_set_unack_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2541,7 +2541,7 @@ static int gen_level_set_unack_temp(struct bt_mesh_model *model, return 0; } -static int gen_level_set_temp(struct bt_mesh_model *model, +static int gen_level_set_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2610,7 +2610,7 @@ static int gen_level_set_temp(struct bt_mesh_model *model, return 0; } -static int gen_delta_set_unack_temp(struct bt_mesh_model *model, +static int gen_delta_set_unack_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2692,7 +2692,7 @@ static int gen_delta_set_unack_temp(struct bt_mesh_model *model, return 0; } -static int gen_delta_set_temp(struct bt_mesh_model *model, +static int gen_delta_set_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2777,7 +2777,7 @@ static int gen_delta_set_temp(struct bt_mesh_model *model, return 0; } -static int gen_move_set_unack_temp(struct bt_mesh_model *model, +static int gen_move_set_unack_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2852,7 +2852,7 @@ static int gen_move_set_unack_temp(struct bt_mesh_model *model, return 0; } -static int gen_move_set_temp(struct bt_mesh_model *model, +static int gen_move_set_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2931,7 +2931,7 @@ static int gen_move_set_temp(struct bt_mesh_model *model, } /* Generic Level (TEMPERATURE) Client message handlers */ -static int gen_level_status_temp(struct bt_mesh_model *model, +static int gen_level_status_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -3112,7 +3112,7 @@ static const struct bt_mesh_model_op gen_level_cli_op_temp[] = { BT_MESH_MODEL_OP_END, }; -struct bt_mesh_model root_models[] = { +const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), @@ -3172,12 +3172,12 @@ struct bt_mesh_model root_models[] = { NULL), }; -struct bt_mesh_model vnd_models[] = { +const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(CID_ZEPHYR, 0x4321, vnd_ops, &vnd_pub, &vnd_user_data), }; -struct bt_mesh_model s0_models[] = { +const struct bt_mesh_model s0_models[] = { BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, gen_level_srv_op_temp, &gen_level_srv_pub_s0, NULL), diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.h b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.h index 2bc4c836926607f..108075379b00dbd 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.h +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.h @@ -93,18 +93,18 @@ struct light_ctl_state { extern struct vendor_state vnd_user_data; extern struct light_ctl_state *const ctl; -extern struct bt_mesh_model root_models[]; -extern struct bt_mesh_model vnd_models[]; -extern struct bt_mesh_model s0_models[]; +extern const struct bt_mesh_model root_models[]; +extern const struct bt_mesh_model vnd_models[]; +extern const struct bt_mesh_model s0_models[]; extern const struct bt_mesh_comp comp; -void gen_onoff_publish(struct bt_mesh_model *model); -void gen_level_publish(struct bt_mesh_model *model); -void light_lightness_publish(struct bt_mesh_model *model); -void light_lightness_linear_publish(struct bt_mesh_model *model); -void light_ctl_publish(struct bt_mesh_model *model); -void light_ctl_temp_publish(struct bt_mesh_model *model); -void gen_level_publish_temp(struct bt_mesh_model *model); +void gen_onoff_publish(const struct bt_mesh_model *model); +void gen_level_publish(const struct bt_mesh_model *model); +void light_lightness_publish(const struct bt_mesh_model *model); +void light_lightness_linear_publish(const struct bt_mesh_model *model); +void light_ctl_publish(const struct bt_mesh_model *model); +void light_ctl_temp_publish(const struct bt_mesh_model *model); +void gen_level_publish_temp(const struct bt_mesh_model *model); #endif diff --git a/samples/boards/reel_board/mesh_badge/src/mesh.c b/samples/boards/reel_board/mesh_badge/src/mesh.c index d2916d141e652f0..ae219387cf58267 100644 --- a/samples/boards/reel_board/mesh_badge/src/mesh.c +++ b/samples/boards/reel_board/mesh_badge/src/mesh.c @@ -159,12 +159,12 @@ static struct bt_mesh_cfg_cli cfg_cli = { .cb = &cfg_cli_cb, }; -static void attention_on(struct bt_mesh_model *model) +static void attention_on(const struct bt_mesh_model *model) { board_show_text("Attention!", false, K_SECONDS(2)); } -static void attention_off(struct bt_mesh_model *model) +static void attention_off(const struct bt_mesh_model *model) { board_refresh_display(); } @@ -179,12 +179,12 @@ static struct bt_mesh_health_srv health_srv = { }; /* Generic OnOff Server message handlers */ -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); - struct led_onoff_state *state = model->user_data; + struct led_onoff_state *state = *(model->user_data); printk("addr 0x%04x onoff 0x%02x\n", bt_mesh_model_elem(model)->addr, state->current); @@ -198,12 +198,12 @@ static int gen_onoff_get(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct net_buf_simple *msg = model->pub->msg; - struct led_onoff_state *state = model->user_data; + struct led_onoff_state *state = *(model->user_data); int err; uint8_t tid, onoff; int64_t now; @@ -263,7 +263,7 @@ static int gen_onoff_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -273,7 +273,7 @@ static int gen_onoff_set(struct bt_mesh_model *model, return 0; } -static int sensor_desc_get(struct bt_mesh_model *model, +static int sensor_desc_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -333,7 +333,7 @@ static void sensor_create_status(uint16_t id, struct net_buf_simple *msg) } } -static int sensor_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int sensor_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, 1 + MAX_SENS_STATUS_LEN + 4); @@ -349,7 +349,7 @@ static int sensor_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int sensor_col_get(struct bt_mesh_model *model, +static int sensor_col_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -357,7 +357,7 @@ static int sensor_col_get(struct bt_mesh_model *model, return 0; } -static int sensor_series_get(struct bt_mesh_model *model, +static int sensor_series_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -385,7 +385,7 @@ static const struct bt_mesh_model_op sensor_srv_op[] = { { BT_MESH_MODEL_OP_SENS_SERIES_GET, BT_MESH_LEN_EXACT(2), sensor_series_get }, }; -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), @@ -396,7 +396,7 @@ static struct bt_mesh_model root_models[] = { sensor_srv_op, NULL, NULL), }; -static int vnd_hello(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_hello(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { char str[32]; @@ -423,7 +423,7 @@ static int vnd_hello(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int vnd_baduser(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_baduser(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { char str[32]; @@ -448,7 +448,7 @@ static int vnd_baduser(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int vnd_heartbeat(struct bt_mesh_model *model, +static int vnd_heartbeat(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -477,7 +477,7 @@ static const struct bt_mesh_model_op vnd_ops[] = { BT_MESH_MODEL_OP_END, }; -static int pub_update(struct bt_mesh_model *mod) +static int pub_update(const struct bt_mesh_model *mod) { struct net_buf_simple *msg = mod->pub->msg; @@ -491,7 +491,7 @@ static int pub_update(struct bt_mesh_model *mod) BT_MESH_MODEL_PUB_DEFINE(vnd_pub, pub_update, 3 + 1); -static struct bt_mesh_model vnd_models[] = { +static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(BT_COMP_ID_LF, MOD_LF, vnd_ops, &vnd_pub, NULL), }; diff --git a/subsys/bluetooth/host/testing.c b/subsys/bluetooth/host/testing.c index 3c118c51e0f1837..5e2f507bb589926 100644 --- a/subsys/bluetooth/host/testing.c +++ b/subsys/bluetooth/host/testing.c @@ -56,7 +56,7 @@ void bt_test_mesh_model_recv(uint16_t src, uint16_t dst, const void *payload, } } -void bt_test_mesh_model_bound(uint16_t addr, struct bt_mesh_model *model, +void bt_test_mesh_model_bound(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx) { struct bt_test_cb *cb; @@ -68,7 +68,7 @@ void bt_test_mesh_model_bound(uint16_t addr, struct bt_mesh_model *model, } } -void bt_test_mesh_model_unbound(uint16_t addr, struct bt_mesh_model *model, +void bt_test_mesh_model_unbound(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx) { struct bt_test_cb *cb; diff --git a/subsys/bluetooth/host/testing.h b/subsys/bluetooth/host/testing.h index 0e6cfbaf7853769..8ed1fa61e468c3a 100644 --- a/subsys/bluetooth/host/testing.h +++ b/subsys/bluetooth/host/testing.h @@ -14,9 +14,9 @@ void bt_test_mesh_net_recv(uint8_t ttl, uint8_t ctl, uint16_t src, uint16_t dst, const void *payload, size_t payload_len); void bt_test_mesh_model_recv(uint16_t src, uint16_t dst, const void *payload, size_t payload_len); -void bt_test_mesh_model_bound(uint16_t addr, struct bt_mesh_model *model, +void bt_test_mesh_model_bound(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx); -void bt_test_mesh_model_unbound(uint16_t addr, struct bt_mesh_model *model, +void bt_test_mesh_model_unbound(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx); void bt_test_mesh_prov_invalid_bearer(uint8_t opcode); void bt_test_mesh_trans_incomp_timer_exp(void); diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 4f1941a9e66db2f..2911a42c7aff3f4 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -92,12 +92,12 @@ static struct mod_relation mod_rel_list[MOD_REL_LIST_SIZE]; (idx)++) #define IS_MOD_BASE(mod, idx, offset) \ - (mod_rel_list[(idx)].elem_base == (mod)->elem_idx && \ - mod_rel_list[(idx)].idx_base == (mod)->mod_idx + (offset)) + (mod_rel_list[(idx)].elem_base == *((mod)->elem_idx) && \ + mod_rel_list[(idx)].idx_base == *((mod)->mod_idx) + (offset)) #define IS_MOD_EXTENSION(mod, idx, offset) \ - (mod_rel_list[(idx)].elem_ext == (mod)->elem_idx && \ - mod_rel_list[(idx)].idx_ext == (mod)->mod_idx + (offset)) + (mod_rel_list[(idx)].elem_ext == *((mod)->elem_idx) && \ + mod_rel_list[(idx)].idx_ext == *((mod)->mod_idx) + (offset)) #define RELATION_TYPE_EXT 0xFF @@ -114,7 +114,7 @@ static const struct { #endif }; -void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, +void bt_mesh_model_foreach(void (*func)(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data), @@ -126,13 +126,13 @@ void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, struct bt_mesh_elem *elem = &dev_comp->elem[i]; for (j = 0; j < elem->model_count; j++) { - struct bt_mesh_model *model = &elem->models[j]; + const struct bt_mesh_model *model = &elem->models[j]; func(model, elem, false, i == 0, user_data); } for (j = 0; j < elem->vnd_model_count; j++) { - struct bt_mesh_model *model = &elem->vnd_models[j]; + const struct bt_mesh_model *model = &elem->vnd_models[j]; func(model, elem, true, i == 0, user_data); } @@ -181,7 +181,7 @@ static void data_buf_add_mem_offset(struct net_buf_simple *buf, uint8_t *data, s *offset = 0; } -static void comp_add_model(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void comp_add_model(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, void *user_data) { struct comp_foreach_model_arg *arg = user_data; @@ -196,7 +196,7 @@ static void comp_add_model(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, #if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) -static size_t metadata_model_size(struct bt_mesh_model *mod, +static size_t metadata_model_size(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd) { const struct bt_mesh_models_metadata_entry *entry; @@ -237,13 +237,13 @@ size_t bt_mesh_metadata_page_0_size(void) sizeof(elem->vnd_model_count); for (j = 0; j < elem->model_count; j++) { - struct bt_mesh_model *model = &elem->models[j]; + const struct bt_mesh_model *model = &elem->models[j]; size += metadata_model_size(model, elem, false); } for (j = 0; j < elem->vnd_model_count; j++) { - struct bt_mesh_model *model = &elem->vnd_models[j]; + const struct bt_mesh_model *model = &elem->vnd_models[j]; size += metadata_model_size(model, elem, true); } @@ -252,7 +252,7 @@ size_t bt_mesh_metadata_page_0_size(void) return size; } -static int metadata_add_model(struct bt_mesh_model *mod, +static int metadata_add_model(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, void *user_data) { @@ -322,7 +322,7 @@ int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset) vnd_count_ptr = data_buf_add_u8_offset(buf, 0, &offset); for (j = 0; j < elem->model_count; j++) { - struct bt_mesh_model *model = &elem->models[j]; + const struct bt_mesh_model *model = &elem->models[j]; if (!model->metadata) { continue; @@ -339,7 +339,7 @@ int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset) } for (j = 0; j < elem->vnd_model_count; j++) { - struct bt_mesh_model *model = &elem->vnd_models[j]; + const struct bt_mesh_model *model = &elem->vnd_models[j]; if (!model->metadata) { continue; @@ -396,13 +396,13 @@ static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem, data_buf_add_u8_offset(buf, elem->vnd_model_count, offset); for (i = 0; i < elem->model_count; i++) { - struct bt_mesh_model *model = &elem->models[i]; + const struct bt_mesh_model *model = &elem->models[i]; comp_add_model(model, elem, false, &arg); } for (i = 0; i < elem->vnd_model_count; i++) { - struct bt_mesh_model *model = &elem->vnd_models[i]; + const struct bt_mesh_model *model = &elem->vnd_models[i]; comp_add_model(model, elem, true, &arg); } @@ -452,7 +452,8 @@ int bt_mesh_comp_data_get_page_0(struct net_buf_simple *buf, size_t offset) return 0; } -static uint8_t count_mod_ext(struct bt_mesh_model *mod, uint8_t *max_offset, uint8_t sig_offset) +static uint8_t count_mod_ext(const struct bt_mesh_model *mod, + uint8_t *max_offset, uint8_t sig_offset) { int i; uint8_t extensions = 0; @@ -476,7 +477,7 @@ static uint8_t count_mod_ext(struct bt_mesh_model *mod, uint8_t *max_offset, uin return extensions; } -static bool is_cor_present(struct bt_mesh_model *mod, uint8_t *cor_id, uint8_t sig_offset) +static bool is_cor_present(const struct bt_mesh_model *mod, uint8_t *cor_id, uint8_t sig_offset) { int i; @@ -494,8 +495,9 @@ static bool is_cor_present(struct bt_mesh_model *mod, uint8_t *cor_id, uint8_t s return false; } -static void prep_model_item_header(struct bt_mesh_model *mod, uint8_t *cor_id, uint8_t *mod_cnt, - struct net_buf_simple *buf, size_t *offset, uint8_t sig_offset) +static void prep_model_item_header(const struct bt_mesh_model *mod, uint8_t *cor_id, + uint8_t *mod_cnt, struct net_buf_simple *buf, + size_t *offset, uint8_t sig_offset) { uint8_t ext_mod_cnt; bool cor_present; @@ -522,7 +524,7 @@ static void prep_model_item_header(struct bt_mesh_model *mod, uint8_t *cor_id, u memset(mod_cnt, ext_mod_cnt, sizeof(uint8_t)); } -static void add_items_to_page(struct net_buf_simple *buf, struct bt_mesh_model *mod, +static void add_items_to_page(struct net_buf_simple *buf, const struct bt_mesh_model *mod, uint8_t ext_mod_cnt, size_t *offset, uint8_t sig_offset) { int i, elem_offset; @@ -531,7 +533,7 @@ static void add_items_to_page(struct net_buf_simple *buf, struct bt_mesh_model * MOD_REL_LIST_FOR_EACH(i) { if (IS_MOD_EXTENSION(mod, i, sig_offset) && mod_rel_list[i].type == RELATION_TYPE_EXT) { - elem_offset = mod->elem_idx - mod_rel_list[i].elem_base; + elem_offset = *(mod->elem_idx) - mod_rel_list[i].elem_base; mod_idx = mod_rel_list[i].idx_base; if (ext_mod_cnt < 32 && elem_offset < 4 && @@ -555,7 +557,7 @@ static void add_items_to_page(struct net_buf_simple *buf, struct bt_mesh_model * } } -static size_t mod_items_size(struct bt_mesh_model *mod, uint8_t sig_offset) +static size_t mod_items_size(const struct bt_mesh_model *mod, uint8_t sig_offset) { int i, offset; size_t temp_size = 0; @@ -567,7 +569,7 @@ static size_t mod_items_size(struct bt_mesh_model *mod, uint8_t sig_offset) MOD_REL_LIST_FOR_EACH(i) { if (IS_MOD_EXTENSION(mod, i, sig_offset)) { - offset = mod->elem_idx - mod_rel_list[i].elem_base; + offset = *(mod->elem_idx) - mod_rel_list[i].elem_base; temp_size += (ext_mod_cnt < 32 && offset < 4 && offset > -5) ? 1 : 2; } } @@ -701,7 +703,7 @@ static int bt_mesh_comp_data_get_page_2(struct net_buf_simple *buf, size_t offse return 0; } -int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) +int32_t bt_mesh_model_pub_period_get(const struct bt_mesh_model *mod) { int32_t period; @@ -741,7 +743,7 @@ int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) } } -static int32_t next_period(struct bt_mesh_model *mod) +static int32_t next_period(const struct bt_mesh_model *mod) { struct bt_mesh_model_pub *pub = mod->pub; uint32_t period = 0; @@ -782,7 +784,7 @@ static int32_t next_period(struct bt_mesh_model *mod) static void publish_sent(int err, void *user_data) { - struct bt_mesh_model *mod = user_data; + const struct bt_mesh_model *mod = user_data; int32_t delay; LOG_DBG("err %d, time %u", err, k_uptime_get_32()); @@ -812,7 +814,7 @@ static const struct bt_mesh_send_cb pub_sent_cb = { .end = publish_sent, }; -static int publish_transmit(struct bt_mesh_model *mod) +static int publish_transmit(const struct bt_mesh_model *mod) { NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX); struct bt_mesh_model_pub *pub = mod->pub; @@ -825,7 +827,7 @@ static int publish_transmit(struct bt_mesh_model *mod) net_buf_simple_add_mem(&sdu, pub->msg->data, pub->msg->len); - return bt_mesh_trans_send(&tx, &sdu, &pub_sent_cb, mod); + return bt_mesh_trans_send(&tx, &sdu, &pub_sent_cb, (void *)mod); } static int pub_period_start(struct bt_mesh_model_pub *pub) @@ -846,7 +848,7 @@ static int pub_period_start(struct bt_mesh_model_pub *pub) /* Skip this publish attempt. */ LOG_DBG("Update failed, skipping publish (err: %d)", err); pub->count = 0; - publish_sent(err, pub->mod); + publish_sent(err, (void *)pub->mod); return err; } @@ -878,7 +880,7 @@ static void mod_publish(struct k_work *work) bt_mesh_model_pub_is_retransmission(pub->mod)) { err = pub->update(pub->mod); if (err) { - publish_sent(err, pub->mod); + publish_sent(err, (void *)pub->mod); return; } } @@ -893,16 +895,16 @@ static void mod_publish(struct k_work *work) err = publish_transmit(pub->mod); if (err) { LOG_ERR("Failed to publish (err %d)", err); - publish_sent(err, pub->mod); + publish_sent(err, (void *)pub->mod); } } -struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod) +struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod) { - return &dev_comp->elem[mod->elem_idx]; + return &dev_comp->elem[*(mod->elem_idx)]; } -struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx) +const struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx) { struct bt_mesh_elem *elem; @@ -931,7 +933,7 @@ struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_ } #if defined(CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE) -static int bt_mesh_vnd_mod_msg_cid_check(struct bt_mesh_model *mod) +static int bt_mesh_vnd_mod_msg_cid_check(const struct bt_mesh_model *mod) { uint16_t cid; const struct bt_mesh_model_op *op; @@ -954,7 +956,7 @@ static int bt_mesh_vnd_mod_msg_cid_check(struct bt_mesh_model *mod) } #endif -static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void mod_init(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { int i; @@ -973,9 +975,9 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, mod->keys[i] = BT_MESH_KEY_UNUSED; } - mod->elem_idx = elem - dev_comp->elem; + *(mod->elem_idx) = elem - dev_comp->elem; if (vnd) { - mod->mod_idx = mod - elem->vnd_models; + *(mod->mod_idx) = mod - elem->vnd_models; if (IS_ENABLED(CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE)) { *err = bt_mesh_vnd_mod_msg_cid_check(mod); @@ -985,7 +987,7 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, } } else { - mod->mod_idx = mod - elem->models; + *(mod->mod_idx) = mod - elem->models; } if (mod->cb && mod->cb->init) { @@ -1082,7 +1084,7 @@ uint16_t bt_mesh_primary_addr(void) return dev_primary_addr; } -static uint16_t *model_group_get(struct bt_mesh_model *mod, uint16_t addr) +static uint16_t *model_group_get(const struct bt_mesh_model *mod, uint16_t addr) { int i; @@ -1097,15 +1099,15 @@ static uint16_t *model_group_get(struct bt_mesh_model *mod, uint16_t addr) struct find_group_visitor_ctx { uint16_t *entry; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; uint16_t addr; }; -static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod, void *user_data) +static enum bt_mesh_walk find_group_mod_visitor(const struct bt_mesh_model *mod, void *user_data) { struct find_group_visitor_ctx *ctx = user_data; - if (mod->elem_idx != ctx->mod->elem_idx) { + if (*(mod->elem_idx) != *(ctx->mod->elem_idx)) { return BT_MESH_WALK_CONTINUE; } @@ -1118,7 +1120,7 @@ static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod, void return BT_MESH_WALK_CONTINUE; } -uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr) +uint16_t *bt_mesh_model_find_group(const struct bt_mesh_model **mod, uint16_t addr) { struct find_group_visitor_ctx ctx = { .mod = *mod, @@ -1133,7 +1135,7 @@ uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr) } #if CONFIG_BT_MESH_LABEL_COUNT > 0 -static const uint8_t **model_uuid_get(struct bt_mesh_model *mod, const uint8_t *uuid) +static const uint8_t **model_uuid_get(const struct bt_mesh_model *mod, const uint8_t *uuid) { int i; @@ -1155,15 +1157,15 @@ static const uint8_t **model_uuid_get(struct bt_mesh_model *mod, const uint8_t * struct find_uuid_visitor_ctx { const uint8_t **entry; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; const uint8_t *uuid; }; -static enum bt_mesh_walk find_uuid_mod_visitor(struct bt_mesh_model *mod, void *user_data) +static enum bt_mesh_walk find_uuid_mod_visitor(const struct bt_mesh_model *mod, void *user_data) { struct find_uuid_visitor_ctx *ctx = user_data; - if (mod->elem_idx != ctx->mod->elem_idx) { + if (*(mod->elem_idx) != *(ctx->mod->elem_idx)) { return BT_MESH_WALK_CONTINUE; } @@ -1177,7 +1179,7 @@ static enum bt_mesh_walk find_uuid_mod_visitor(struct bt_mesh_model *mod, void * } #endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ -const uint8_t **bt_mesh_model_find_uuid(struct bt_mesh_model **mod, const uint8_t *uuid) +const uint8_t **bt_mesh_model_find_uuid(const struct bt_mesh_model **mod, const uint8_t *uuid) { #if CONFIG_BT_MESH_LABEL_COUNT > 0 struct find_uuid_visitor_ctx ctx = { @@ -1195,10 +1197,10 @@ const uint8_t **bt_mesh_model_find_uuid(struct bt_mesh_model **mod, const uint8_ #endif } -static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem, +static const struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem, uint16_t group_addr) { - struct bt_mesh_model *model; + const struct bt_mesh_model *model; uint16_t *match; int i; @@ -1295,7 +1297,7 @@ uint8_t bt_mesh_elem_count(void) return dev_comp->elem_count; } -bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key) +bool bt_mesh_model_has_key(const struct bt_mesh_model *mod, uint16_t key) { int i; @@ -1310,14 +1312,14 @@ bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key) return false; } -static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst, const uint8_t *uuid) +static bool model_has_dst(const struct bt_mesh_model *mod, uint16_t dst, const uint8_t *uuid) { if (BT_MESH_ADDR_IS_UNICAST(dst)) { - return (dev_comp->elem[mod->elem_idx].addr == dst); + return (dev_comp->elem[*(mod->elem_idx)].addr == dst); } else if (BT_MESH_ADDR_IS_VIRTUAL(dst)) { return !!bt_mesh_model_find_uuid(&mod, uuid); } else if (BT_MESH_ADDR_IS_GROUP(dst) || - (BT_MESH_ADDR_IS_FIXED_GROUP(dst) && mod->elem_idx != 0)) { + (BT_MESH_ADDR_IS_FIXED_GROUP(dst) && *(mod->elem_idx) != 0)) { return !!bt_mesh_model_find_group(&mod, dst); } @@ -1325,17 +1327,17 @@ static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst, const uint8_t * the lower layers have already confirmed that we are subscribing to * it. All models on the primary element should receive the message. */ - return mod->elem_idx == 0; + return *(mod->elem_idx) == 0; } static const struct bt_mesh_model_op *find_op(struct bt_mesh_elem *elem, - uint32_t opcode, struct bt_mesh_model **model) + uint32_t opcode, const struct bt_mesh_model **model) { uint8_t i; uint8_t count; /* This value shall not be used in shipping end products. */ uint32_t cid = UINT32_MAX; - struct bt_mesh_model *models; + const struct bt_mesh_model *models; /* SIG models cannot contain 3-byte (vendor) OpCodes, and * vendor models cannot contain SIG (1- or 2-byte) OpCodes, so @@ -1416,7 +1418,7 @@ static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple struct bt_mesh_elem *elem, uint32_t opcode) { const struct bt_mesh_model_op *op; - struct bt_mesh_model *model; + const struct bt_mesh_model *model; struct net_buf_simple_state state; int err; @@ -1502,7 +1504,7 @@ int bt_mesh_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) return err; } -int bt_mesh_model_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data) { @@ -1520,7 +1522,7 @@ int bt_mesh_model_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return bt_mesh_access_send(ctx, msg, bt_mesh_model_elem(model)->addr, cb, cb_data); } -int bt_mesh_model_publish(struct bt_mesh_model *model) +int bt_mesh_model_publish(const struct bt_mesh_model *model) { struct bt_mesh_model_pub *pub = model->pub; @@ -1560,7 +1562,7 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) return 0; } -struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, +const struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, uint16_t company, uint16_t id) { uint8_t i; @@ -1575,7 +1577,7 @@ struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, return NULL; } -struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, +const struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, uint16_t id) { uint8_t i; @@ -1594,8 +1596,8 @@ const struct bt_mesh_comp *bt_mesh_comp_get(void) return dev_comp; } -void bt_mesh_model_extensions_walk(struct bt_mesh_model *model, - enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, +void bt_mesh_model_extensions_walk(const struct bt_mesh_model *model, + enum bt_mesh_walk (*cb)(const struct bt_mesh_model *mod, void *user_data), void *user_data) { @@ -1603,14 +1605,14 @@ void bt_mesh_model_extensions_walk(struct bt_mesh_model *model, (void)cb(model, user_data); return; #else - struct bt_mesh_model *it; + const struct bt_mesh_model *it; - if (cb(model, user_data) == BT_MESH_WALK_STOP || !model->next) { + if (cb(model, user_data) == BT_MESH_WALK_STOP || !*(model->next)) { return; } /* List is circular. Step through all models until we reach the start: */ - for (it = model->next; it != model; it = it->next) { + for (it = *(model->next); it != model; it = *(it->next)) { if (cb(it, user_data) == BT_MESH_WALK_STOP) { return; } @@ -1622,7 +1624,7 @@ void bt_mesh_model_extensions_walk(struct bt_mesh_model *model, /* For vendor models, determine the offset within the model relation list * by counting the number of standard SIG models in the associated element. */ -static uint8_t get_sig_offset(struct bt_mesh_model *mod) +static uint8_t get_sig_offset(const struct bt_mesh_model *mod) { const struct bt_mesh_elem *elem = bt_mesh_model_elem(mod); uint8_t i; @@ -1635,16 +1637,16 @@ static uint8_t get_sig_offset(struct bt_mesh_model *mod) return 0; } -static int mod_rel_register(struct bt_mesh_model *base, - struct bt_mesh_model *ext, +static int mod_rel_register(const struct bt_mesh_model *base, + const struct bt_mesh_model *ext, uint8_t type) { LOG_DBG(""); struct mod_relation extension = { - base->elem_idx, - base->mod_idx + get_sig_offset(base), - ext->elem_idx, - ext->mod_idx + get_sig_offset(ext), + *(base->elem_idx), + *(base->mod_idx) + get_sig_offset(base), + *(ext->elem_idx), + *(ext->mod_idx) + get_sig_offset(ext), type, }; int i; @@ -1663,22 +1665,23 @@ static int mod_rel_register(struct bt_mesh_model *base, return -ENOMEM; } -int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_model *base_mod) +int bt_mesh_model_extend(const struct bt_mesh_model *extending_mod, + const struct bt_mesh_model *base_mod) { - struct bt_mesh_model *a = extending_mod; - struct bt_mesh_model *b = base_mod; - struct bt_mesh_model *a_next = a->next; - struct bt_mesh_model *b_next = b->next; - struct bt_mesh_model *it; + const struct bt_mesh_model *a = extending_mod; + const struct bt_mesh_model *b = base_mod; + const struct bt_mesh_model *a_next = *(a->next); + const struct bt_mesh_model *b_next = *(b->next); + const struct bt_mesh_model *it; - base_mod->flags |= BT_MESH_MOD_EXTENDED; + *(base_mod->flags) |= BT_MESH_MOD_EXTENDED; if (a == b) { return 0; } /* Check if a's list contains b */ - for (it = a; (it != NULL) && (it->next != a); it = it->next) { + for (it = a; (it != NULL) && (*(it->next) != a); it = *(it->next)) { if (it == b) { goto register_extension; } @@ -1686,15 +1689,15 @@ int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_mod /* Merge lists */ if (a_next) { - b->next = a_next; + *(b->next) = a_next; } else { - b->next = a; + *(b->next) = a; } if (b_next) { - a->next = b_next; + *(a->next) = b_next; } else { - a->next = b; + *(a->next) = b; } register_extension: @@ -1705,8 +1708,8 @@ int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_mod return 0; } -int bt_mesh_model_correspond(struct bt_mesh_model *corresponding_mod, - struct bt_mesh_model *base_mod) +int bt_mesh_model_correspond(const struct bt_mesh_model *corresponding_mod, + const struct bt_mesh_model *base_mod) { int i, err; uint8_t cor_id = 0; @@ -1740,12 +1743,12 @@ int bt_mesh_model_correspond(struct bt_mesh_model *corresponding_mod, } #endif /* CONFIG_BT_MESH_MODEL_EXTENSIONS */ -bool bt_mesh_model_is_extended(struct bt_mesh_model *model) +bool bt_mesh_model_is_extended(const struct bt_mesh_model *model) { - return model->flags & BT_MESH_MOD_EXTENDED; + return *(model->flags) & BT_MESH_MOD_EXTENDED; } -static int mod_set_bind(struct bt_mesh_model *mod, size_t len_rd, +static int mod_set_bind(const struct bt_mesh_model *mod, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { ssize_t len; @@ -1773,7 +1776,7 @@ static int mod_set_bind(struct bt_mesh_model *mod, size_t len_rd, return 0; } -static int mod_set_sub(struct bt_mesh_model *mod, size_t len_rd, +static int mod_set_sub(const struct bt_mesh_model *mod, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { size_t size = mod->groups_cnt * sizeof(mod->groups[0]); @@ -1820,7 +1823,7 @@ static int mod_set_sub(struct bt_mesh_model *mod, size_t len_rd, return 0; } -static int mod_set_sub_va(struct bt_mesh_model *mod, size_t len_rd, +static int mod_set_sub_va(const struct bt_mesh_model *mod, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { #if CONFIG_BT_MESH_LABEL_COUNT > 0 @@ -1857,7 +1860,7 @@ static int mod_set_sub_va(struct bt_mesh_model *mod, size_t len_rd, return 0; } -static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd, +static int mod_set_pub(const struct bt_mesh_model *mod, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { struct mod_pub_val pub; @@ -1927,7 +1930,7 @@ static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd, return 0; } -static int mod_data_set(struct bt_mesh_model *mod, +static int mod_data_set(const struct bt_mesh_model *mod, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { @@ -1946,7 +1949,7 @@ static int mod_data_set(struct bt_mesh_model *mod, static int mod_set(bool vnd, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; uint8_t elem_idx, mod_idx; uint16_t mod_key; int len; @@ -2035,10 +2038,10 @@ static int comp_set(const char *name, size_t len_rd, settings_read_cb read_cb, } BT_MESH_SETTINGS_DEFINE(comp, "cmp", comp_set); -static void encode_mod_path(struct bt_mesh_model *mod, bool vnd, +static void encode_mod_path(const struct bt_mesh_model *mod, bool vnd, const char *key, char *path, size_t path_len) { - uint16_t mod_key = (((uint16_t)mod->elem_idx << 8) | mod->mod_idx); + uint16_t mod_key = (((uint16_t)*(mod->elem_idx) << 8) | *(mod->mod_idx)); if (vnd) { snprintk(path, path_len, "bt/mesh/v/%x/%s", mod_key, key); @@ -2047,7 +2050,7 @@ static void encode_mod_path(struct bt_mesh_model *mod, bool vnd, } } -static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd) +static void store_pending_mod_bind(const struct bt_mesh_model *mod, bool vnd) { uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT]; char path[20]; @@ -2075,7 +2078,7 @@ static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd) } } -static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) +static void store_pending_mod_sub(const struct bt_mesh_model *mod, bool vnd) { uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT]; char path[20]; @@ -2102,7 +2105,7 @@ static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) } } -static void store_pending_mod_sub_va(struct bt_mesh_model *mod, bool vnd) +static void store_pending_mod_sub_va(const struct bt_mesh_model *mod, bool vnd) { #if CONFIG_BT_MESH_LABEL_COUNT > 0 uint16_t uuidxs[CONFIG_BT_MESH_LABEL_COUNT]; @@ -2134,7 +2137,7 @@ static void store_pending_mod_sub_va(struct bt_mesh_model *mod, bool vnd) #endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ } -static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) +static void store_pending_mod_pub(const struct bt_mesh_model *mod, bool vnd) { struct mod_pub_val pub = {0}; char path[20]; @@ -2167,32 +2170,32 @@ static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) } } -static void store_pending_mod(struct bt_mesh_model *mod, +static void store_pending_mod(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { - if (!mod->flags) { + if (!*(mod->flags)) { return; } - if (mod->flags & BT_MESH_MOD_BIND_PENDING) { - mod->flags &= ~BT_MESH_MOD_BIND_PENDING; + if (*(mod->flags) & BT_MESH_MOD_BIND_PENDING) { + *(mod->flags) &= ~BT_MESH_MOD_BIND_PENDING; store_pending_mod_bind(mod, vnd); } - if (mod->flags & BT_MESH_MOD_SUB_PENDING) { - mod->flags &= ~BT_MESH_MOD_SUB_PENDING; + if (*(mod->flags) & BT_MESH_MOD_SUB_PENDING) { + *(mod->flags) &= ~BT_MESH_MOD_SUB_PENDING; store_pending_mod_sub(mod, vnd); store_pending_mod_sub_va(mod, vnd); } - if (mod->flags & BT_MESH_MOD_PUB_PENDING) { - mod->flags &= ~BT_MESH_MOD_PUB_PENDING; + if (*(mod->flags) & BT_MESH_MOD_PUB_PENDING) { + *(mod->flags) &= ~BT_MESH_MOD_PUB_PENDING; store_pending_mod_pub(mod, vnd); } - if (mod->flags & BT_MESH_MOD_DATA_PENDING) { - mod->flags &= ~BT_MESH_MOD_DATA_PENDING; + if (*(mod->flags) & BT_MESH_MOD_DATA_PENDING) { + *(mod->flags) &= ~BT_MESH_MOD_DATA_PENDING; mod->cb->pending_store(mod); } } @@ -2202,21 +2205,21 @@ void bt_mesh_model_pending_store(void) bt_mesh_model_foreach(store_pending_mod, NULL); } -void bt_mesh_model_bind_store(struct bt_mesh_model *mod) +void bt_mesh_model_bind_store(const struct bt_mesh_model *mod) { - mod->flags |= BT_MESH_MOD_BIND_PENDING; + *(mod->flags) |= BT_MESH_MOD_BIND_PENDING; bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } -void bt_mesh_model_sub_store(struct bt_mesh_model *mod) +void bt_mesh_model_sub_store(const struct bt_mesh_model *mod) { - mod->flags |= BT_MESH_MOD_SUB_PENDING; + *(mod->flags) |= BT_MESH_MOD_SUB_PENDING; bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } -void bt_mesh_model_pub_store(struct bt_mesh_model *mod) +void bt_mesh_model_pub_store(const struct bt_mesh_model *mod) { - mod->flags |= BT_MESH_MOD_PUB_PENDING; + *(mod->flags) |= BT_MESH_MOD_PUB_PENDING; bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } @@ -2401,7 +2404,7 @@ int bt_mesh_comp_read(struct net_buf_simple *buf, uint8_t page) return 0; } -int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, +int bt_mesh_model_data_store(const struct bt_mesh_model *mod, bool vnd, const char *name, const void *data, size_t data_len) { @@ -2550,7 +2553,7 @@ int bt_mesh_models_metadata_change_prepare(void) #endif } -static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void commit_mod(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { if (mod->pub && mod->pub->update && @@ -2579,9 +2582,9 @@ void bt_mesh_model_settings_commit(void) bt_mesh_model_foreach(commit_mod, NULL); } -void bt_mesh_model_data_store_schedule(struct bt_mesh_model *mod) +void bt_mesh_model_data_store_schedule(const struct bt_mesh_model *mod) { - mod->flags |= BT_MESH_MOD_DATA_PENDING; + *(mod->flags) |= BT_MESH_MOD_DATA_PENDING; bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index f58c6f1d449173c..663f99c84d23881 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -32,23 +32,23 @@ int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset); struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); bool bt_mesh_has_addr(uint16_t addr); -bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key); +bool bt_mesh_model_has_key(const struct bt_mesh_model *mod, uint16_t key); -void bt_mesh_model_extensions_walk(struct bt_mesh_model *root, - enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, +void bt_mesh_model_extensions_walk(const struct bt_mesh_model *root, + enum bt_mesh_walk (*cb)(const struct bt_mesh_model *mod, void *user_data), void *user_data); -uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr); -const uint8_t **bt_mesh_model_find_uuid(struct bt_mesh_model **mod, const uint8_t *uuid); +uint16_t *bt_mesh_model_find_group(const struct bt_mesh_model **mod, uint16_t addr); +const uint8_t **bt_mesh_model_find_uuid(const struct bt_mesh_model **mod, const uint8_t *uuid); -void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, +void bt_mesh_model_foreach(void (*func)(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data), void *user_data); -int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod); +int32_t bt_mesh_model_pub_period_get(const struct bt_mesh_model *mod); void bt_mesh_comp_provision(uint16_t addr); void bt_mesh_comp_unprovision(void); @@ -57,7 +57,7 @@ uint16_t bt_mesh_primary_addr(void); const struct bt_mesh_comp *bt_mesh_comp_get(void); -struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx); +const struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx); int bt_mesh_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -74,9 +74,9 @@ void bt_mesh_comp_data_clear(void); int bt_mesh_comp_data_get_page(struct net_buf_simple *buf, size_t page, size_t offset); void bt_mesh_model_pending_store(void); -void bt_mesh_model_bind_store(struct bt_mesh_model *mod); -void bt_mesh_model_sub_store(struct bt_mesh_model *mod); -void bt_mesh_model_pub_store(struct bt_mesh_model *mod); +void bt_mesh_model_bind_store(const struct bt_mesh_model *mod); +void bt_mesh_model_sub_store(const struct bt_mesh_model *mod); +void bt_mesh_model_pub_store(const struct bt_mesh_model *mod); void bt_mesh_model_settings_commit(void); /** @brief Register a callback function hook for mesh model messages. diff --git a/subsys/bluetooth/mesh/blob_cli.c b/subsys/bluetooth/mesh/blob_cli.c index 0effbf61be70448..4fd0fe7bac97da5 100644 --- a/subsys/bluetooth/mesh/blob_cli.c +++ b/subsys/bluetooth/mesh/blob_cli.c @@ -1204,10 +1204,10 @@ static void rx_block_status(struct bt_mesh_blob_cli *cli, blob_cli_broadcast_rsp(cli, target); } -static int handle_xfer_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_xfer_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_cli *cli = *(mod->user_data); enum bt_mesh_blob_xfer_phase expected_phase; struct bt_mesh_blob_target *target; struct bt_mesh_blob_xfer_info info = { 0 }; @@ -1276,10 +1276,10 @@ static int handle_xfer_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_block_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_block_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_cli *cli = *(mod->user_data); struct block_status status = { .status = BT_MESH_BLOB_SUCCESS, .block.number = cli->block.number, @@ -1330,10 +1330,10 @@ static int handle_block_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_block_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_block_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_cli *cli = *(mod->user_data); struct bt_mesh_blob_target *target; struct block_status status = { 0 }; uint8_t status_and_format; @@ -1401,10 +1401,10 @@ static int handle_block_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_info_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_cli *cli = *(mod->user_data); struct bt_mesh_blob_cli_caps caps; enum bt_mesh_blob_status status; struct bt_mesh_blob_target *target; @@ -1458,9 +1458,9 @@ const struct bt_mesh_model_op _bt_mesh_blob_cli_op[] = { BT_MESH_MODEL_OP_END, }; -static int blob_cli_init(struct bt_mesh_model *mod) +static int blob_cli_init(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_cli *cli = *(mod->user_data); cli->mod = mod; @@ -1471,9 +1471,9 @@ static int blob_cli_init(struct bt_mesh_model *mod) return 0; } -static void blob_cli_reset(struct bt_mesh_model *mod) +static void blob_cli_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_cli *cli = *(mod->user_data); cli_state_reset(cli); } diff --git a/subsys/bluetooth/mesh/blob_srv.c b/subsys/bluetooth/mesh/blob_srv.c index 1e6cb9bc91a0865..2fee121415d1947 100644 --- a/subsys/bluetooth/mesh/blob_srv.c +++ b/subsys/bluetooth/mesh/blob_srv.c @@ -415,10 +415,10 @@ static void block_status_rsp(struct bt_mesh_blob_srv *srv, (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); } -static int handle_xfer_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_xfer_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); LOG_DBG(""); @@ -435,10 +435,10 @@ static int handle_xfer_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ct return 0; } -static int handle_xfer_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_xfer_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); enum bt_mesh_blob_status status; enum bt_mesh_blob_xfer_mode mode; uint64_t id; @@ -566,11 +566,11 @@ static int handle_xfer_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx * return 0; } -static int handle_xfer_cancel(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_xfer_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { enum bt_mesh_blob_status status = BT_MESH_BLOB_SUCCESS; - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); uint64_t id; id = net_buf_simple_pull_le64(buf); @@ -594,11 +594,11 @@ static int handle_xfer_cancel(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_block_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_block_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { enum bt_mesh_blob_status status; - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); switch (srv->phase) { case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK: @@ -625,10 +625,10 @@ static int handle_block_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *c return 0; } -static int handle_block_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_block_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); enum bt_mesh_blob_status status; uint16_t block_number, chunk_size; int err; @@ -720,10 +720,10 @@ static int handle_block_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_chunk(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_chunk(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); struct bt_mesh_blob_chunk chunk; size_t expected_size = 0; uint16_t idx; @@ -810,10 +810,10 @@ static int handle_chunk(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, return 0; } -static int handle_info_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); LOG_DBG(""); @@ -847,9 +847,9 @@ const struct bt_mesh_model_op _bt_mesh_blob_srv_op[] = { BT_MESH_MODEL_OP_END, }; -static int blob_srv_init(struct bt_mesh_model *mod) +static int blob_srv_init(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); srv->mod = mod; srv->state.ttl = BT_MESH_TTL_DEFAULT; @@ -861,11 +861,11 @@ static int blob_srv_init(struct bt_mesh_model *mod) return 0; } -static int blob_srv_settings_set(struct bt_mesh_model *mod, const char *name, +static int blob_srv_settings_set(const struct bt_mesh_model *mod, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); ssize_t len; if (len_rd < offsetof(struct bt_mesh_blob_srv_state, blocks)) { @@ -903,9 +903,9 @@ static int blob_srv_settings_set(struct bt_mesh_model *mod, const char *name, return 0; } -static int blob_srv_start(struct bt_mesh_model *mod) +static int blob_srv_start(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); int err = -ENOTSUP; if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { @@ -931,9 +931,9 @@ static int blob_srv_start(struct bt_mesh_model *mod) return 0; } -static void blob_srv_reset(struct bt_mesh_model *mod) +static void blob_srv_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_srv *srv = *(mod->user_data); phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; diff --git a/subsys/bluetooth/mesh/cfg_cli.c b/subsys/bluetooth/mesh/cfg_cli.c index 7ee3a590cd0e15f..2f05fea2f15f178 100644 --- a/subsys/bluetooth/mesh/cfg_cli.c +++ b/subsys/bluetooth/mesh/cfg_cli.c @@ -48,7 +48,7 @@ static int32_t msg_timeout; static struct bt_mesh_cfg_cli *cli; -static int comp_data_status(struct bt_mesh_model *model, +static int comp_data_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -85,7 +85,7 @@ static int comp_data_status(struct bt_mesh_model *model, return 0; } -static uint8_t state_status_u8(struct bt_mesh_model *model, +static uint8_t state_status_u8(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint32_t expect_status) @@ -111,7 +111,7 @@ static uint8_t state_status_u8(struct bt_mesh_model *model, return status; } -static int beacon_status(struct bt_mesh_model *model, +static int beacon_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -126,7 +126,7 @@ static int beacon_status(struct bt_mesh_model *model, return 0; } -static int ttl_status(struct bt_mesh_model *model, +static int ttl_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -141,7 +141,7 @@ static int ttl_status(struct bt_mesh_model *model, return 0; } -static int friend_status(struct bt_mesh_model *model, +static int friend_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -156,7 +156,7 @@ static int friend_status(struct bt_mesh_model *model, return 0; } -static int gatt_proxy_status(struct bt_mesh_model *model, +static int gatt_proxy_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -178,7 +178,7 @@ struct krp_param { uint8_t *phase; }; -static int krp_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int krp_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { int err = 0; @@ -223,7 +223,7 @@ struct relay_param { uint8_t *transmit; }; -static int relay_status(struct bt_mesh_model *model, +static int relay_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -257,7 +257,7 @@ static int relay_status(struct bt_mesh_model *model, return 0; } -static int net_transmit_status(struct bt_mesh_model *model, +static int net_transmit_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -277,7 +277,7 @@ struct net_key_param { uint16_t net_idx; }; -static int net_key_status(struct bt_mesh_model *model, +static int net_key_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -345,7 +345,7 @@ int bt_mesh_key_idx_unpack_list(struct net_buf_simple *buf, uint16_t *dst_arr, return buf->len > 0 ? -EMSGSIZE : 0; } -static int net_key_list(struct bt_mesh_model *model, +static int net_key_list(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -381,7 +381,7 @@ static int net_key_list(struct bt_mesh_model *model, return err; } -static int node_reset_status(struct bt_mesh_model *model, +static int node_reset_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -412,7 +412,7 @@ struct app_key_param { uint16_t app_idx; }; -static int app_key_status(struct bt_mesh_model *model, +static int app_key_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -461,7 +461,7 @@ struct app_key_list_param { size_t *key_cnt; }; -static int app_key_list(struct bt_mesh_model *model, +static int app_key_list(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -521,7 +521,7 @@ struct mod_app_param { uint16_t cid; }; -static int mod_app_status(struct bt_mesh_model *model, +static int mod_app_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -695,7 +695,7 @@ static int mod_app_list_handle(struct bt_mesh_msg_ctx *ctx, struct net_buf_simpl return err; } -static int mod_app_list(struct bt_mesh_model *model, +static int mod_app_list(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, @@ -704,7 +704,7 @@ static int mod_app_list(struct bt_mesh_model *model, return mod_app_list_handle(ctx, buf, OP_SIG_MOD_APP_LIST, false); } -static int mod_app_list_vnd(struct bt_mesh_model *model, +static int mod_app_list_vnd(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -722,7 +722,7 @@ struct mod_pub_param { struct bt_mesh_cfg_cli_mod_pub *pub; }; -static int mod_pub_status(struct bt_mesh_model *model, +static int mod_pub_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -807,7 +807,7 @@ struct mod_sub_param { uint16_t cid; }; -static int mod_sub_status(struct bt_mesh_model *model, +static int mod_sub_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -866,7 +866,7 @@ static int mod_sub_status(struct bt_mesh_model *model, return err; } -static int mod_sub_list(struct bt_mesh_model *model, +static int mod_sub_list(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, @@ -875,7 +875,7 @@ static int mod_sub_list(struct bt_mesh_model *model, return mod_sub_list_handle(ctx, buf, OP_MOD_SUB_LIST, false); } -static int mod_sub_list_vnd(struct bt_mesh_model *model, +static int mod_sub_list_vnd(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -890,7 +890,7 @@ struct hb_sub_param { struct bt_mesh_cfg_cli_hb_sub *sub; }; -static int hb_sub_status(struct bt_mesh_model *model, +static int hb_sub_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -934,7 +934,7 @@ struct hb_pub_param { struct bt_mesh_cfg_cli_hb_pub *pub; }; -static int hb_pub_status(struct bt_mesh_model *model, +static int hb_pub_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -979,7 +979,7 @@ struct node_idt_param { uint8_t *identity; }; -static int node_identity_status(struct bt_mesh_model *model, +static int node_identity_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1020,7 +1020,7 @@ struct lpn_timeout_param { int32_t *polltimeout; }; -static int lpn_timeout_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int lpn_timeout_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct lpn_timeout_param *param; @@ -1087,19 +1087,19 @@ const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { BT_MESH_MODEL_OP_END, }; -static int cfg_cli_init(struct bt_mesh_model *model) +static int cfg_cli_init(const struct bt_mesh_model *model) { if (!bt_mesh_model_in_primary(model)) { LOG_ERR("Configuration Client only allowed in primary element"); return -EINVAL; } - if (!model->user_data) { + if (!*(model->user_data)) { LOG_ERR("No Configuration Client context provided"); return -EINVAL; } - cli = model->user_data; + cli = *(model->user_data); cli->model = model; msg_timeout = CONFIG_BT_MESH_CFG_CLI_TIMEOUT; @@ -1108,7 +1108,7 @@ static int cfg_cli_init(struct bt_mesh_model *model) * and remote keys are allowed to access this model. */ model->keys[0] = BT_MESH_KEY_DEV_ANY; - model->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 1684748ba83e012..5920ecd6dc10638 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -48,7 +48,7 @@ static void node_reset_pending_handler(struct k_work *work) static K_WORK_DEFINE(node_reset_pending, node_reset_pending_handler); -static int dev_comp_data_get(struct bt_mesh_model *model, +static int dev_comp_data_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -86,7 +86,7 @@ static int dev_comp_data_get(struct bt_mesh_model *model, return err; } -static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, +static const struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, struct net_buf_simple *buf, bool *vnd) { if (buf->len < 4) { @@ -113,9 +113,9 @@ static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, } } -static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, const uint8_t *uuid, - uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, uint8_t period, - uint8_t retransmit, bool store) +static uint8_t _mod_pub_set(const struct bt_mesh_model *model, uint16_t pub_addr, + const uint8_t *uuid, uint16_t app_idx, uint8_t cred_flag, + uint8_t ttl, uint8_t period, uint8_t retransmit, bool store) { if (!model->pub) { return STATUS_NVAL_PUB_PARAM; @@ -199,7 +199,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, cons return STATUS_SUCCESS; } -static uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) +static uint8_t mod_bind(const struct bt_mesh_model *model, uint16_t key_idx) { int i; @@ -232,7 +232,7 @@ static uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) return STATUS_INSUFF_RESOURCES; } -static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store) +static uint8_t mod_unbind(const struct bt_mesh_model *model, uint16_t key_idx, bool store) { int i; @@ -284,7 +284,7 @@ static void key_idx_pack_list(struct net_buf_simple *buf, uint16_t *arr, size_t } -static int send_app_key_status(struct bt_mesh_model *model, +static int send_app_key_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t status, uint16_t app_idx, uint16_t net_idx) @@ -302,7 +302,7 @@ static int send_app_key_status(struct bt_mesh_model *model, return 0; } -static int app_key_add(struct bt_mesh_model *model, +static int app_key_add(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -318,7 +318,7 @@ static int app_key_add(struct bt_mesh_model *model, return send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } -static int app_key_update(struct bt_mesh_model *model, +static int app_key_update(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -335,7 +335,7 @@ static int app_key_update(struct bt_mesh_model *model, return send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } -static void mod_app_key_del(struct bt_mesh_model *mod, +static void mod_app_key_del(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { @@ -354,7 +354,7 @@ static void app_key_evt(uint16_t app_idx, uint16_t net_idx, BT_MESH_APP_KEY_CB_DEFINE(app_key_evt); -static int app_key_del(struct bt_mesh_model *model, +static int app_key_del(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -373,7 +373,7 @@ static int app_key_del(struct bt_mesh_model *model, /* Index list length: 3 bytes for every pair and 2 bytes for an odd idx */ #define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2) -static int app_key_get(struct bt_mesh_model *model, +static int app_key_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -422,7 +422,7 @@ static int app_key_get(struct bt_mesh_model *model, return 0; } -static int beacon_get(struct bt_mesh_model *model, +static int beacon_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -441,7 +441,7 @@ static int beacon_get(struct bt_mesh_model *model, return 0; } -static int beacon_set(struct bt_mesh_model *model, +static int beacon_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -467,7 +467,7 @@ static int beacon_set(struct bt_mesh_model *model, return 0; } -static int default_ttl_get(struct bt_mesh_model *model, +static int default_ttl_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -486,7 +486,7 @@ static int default_ttl_get(struct bt_mesh_model *model, return 0; } -static int default_ttl_set(struct bt_mesh_model *model, +static int default_ttl_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -512,7 +512,7 @@ static int default_ttl_set(struct bt_mesh_model *model, return 0; } -static int send_gatt_proxy_status(struct bt_mesh_model *model, +static int send_gatt_proxy_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { BT_MESH_MODEL_BUF_DEFINE(msg, OP_GATT_PROXY_STATUS, 1); @@ -527,7 +527,7 @@ static int send_gatt_proxy_status(struct bt_mesh_model *model, return 0; } -static int gatt_proxy_get(struct bt_mesh_model *model, +static int gatt_proxy_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -537,7 +537,7 @@ static int gatt_proxy_get(struct bt_mesh_model *model, return send_gatt_proxy_status(model, ctx); } -static int gatt_proxy_set(struct bt_mesh_model *model, +static int gatt_proxy_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -561,7 +561,7 @@ static int gatt_proxy_set(struct bt_mesh_model *model, return send_gatt_proxy_status(model, ctx); } -static int net_transmit_get(struct bt_mesh_model *model, +static int net_transmit_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -580,7 +580,7 @@ static int net_transmit_get(struct bt_mesh_model *model, return 0; } -static int net_transmit_set(struct bt_mesh_model *model, +static int net_transmit_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -604,7 +604,7 @@ static int net_transmit_set(struct bt_mesh_model *model, return 0; } -static int relay_get(struct bt_mesh_model *model, +static int relay_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -624,7 +624,7 @@ static int relay_get(struct bt_mesh_model *model, return 0; } -static int relay_set(struct bt_mesh_model *model, +static int relay_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -651,10 +651,10 @@ static int relay_set(struct bt_mesh_model *model, return 0; } -static int send_mod_pub_status(struct bt_mesh_model *cfg_mod, +static int send_mod_pub_status(const struct bt_mesh_model *cfg_mod, struct bt_mesh_msg_ctx *ctx, uint16_t elem_addr, uint16_t pub_addr, bool vnd, - struct bt_mesh_model *mod, uint8_t status, + const struct bt_mesh_model *mod, uint8_t status, uint8_t *mod_id) { BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_STATUS, 14); @@ -691,11 +691,11 @@ static int send_mod_pub_status(struct bt_mesh_model *cfg_mod, return 0; } -static int mod_pub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int mod_pub_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint16_t elem_addr, pub_addr = 0U; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; @@ -742,13 +742,13 @@ static int mod_pub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, status, mod_id); } -static int mod_pub_set(struct bt_mesh_model *model, +static int mod_pub_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t retransmit, status, pub_ttl, pub_period, cred_flag; uint16_t elem_addr, pub_addr, pub_app_idx; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint8_t *mod_id; bool vnd; @@ -807,7 +807,7 @@ static int mod_pub_set(struct bt_mesh_model *model, status, mod_id); } -static size_t mod_sub_list_clear(struct bt_mesh_model *mod) +static size_t mod_sub_list_clear(const struct bt_mesh_model *mod) { size_t clear_count; int i; @@ -838,7 +838,7 @@ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) return clear_count; } -static int mod_pub_va_set(struct bt_mesh_model *model, +static int mod_pub_va_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -846,7 +846,7 @@ static int mod_pub_va_set(struct bt_mesh_model *model, uint8_t retransmit, status, pub_ttl, pub_period, cred_flag; uint16_t elem_addr, pub_app_idx; uint16_t pub_addr = 0U; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; const uint8_t *uuid; uint8_t *mod_id; @@ -915,7 +915,7 @@ static int mod_pub_va_set(struct bt_mesh_model *model, status, mod_id); } -static int send_mod_sub_status(struct bt_mesh_model *model, +static int send_mod_sub_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t status, uint16_t elem_addr, uint16_t sub_addr, uint8_t *mod_id, bool vnd) @@ -943,12 +943,12 @@ static int send_mod_sub_status(struct bt_mesh_model *model, return 0; } -static int mod_sub_add(struct bt_mesh_model *model, +static int mod_sub_add(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint16_t elem_addr, sub_addr; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint8_t *mod_id; uint8_t status; @@ -1021,12 +1021,12 @@ static int mod_sub_add(struct bt_mesh_model *model, mod_id, vnd); } -static int mod_sub_del(struct bt_mesh_model *model, +static int mod_sub_del(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint16_t elem_addr, sub_addr; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint8_t *mod_id; uint16_t *match; @@ -1092,7 +1092,7 @@ static int mod_sub_del(struct bt_mesh_model *model, mod_id, vnd); } -static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod, void *user_data) +static enum bt_mesh_walk mod_sub_clear_visitor(const struct bt_mesh_model *mod, void *user_data) { if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { bt_mesh_lpn_group_del(mod->groups, mod->groups_cnt); @@ -1103,12 +1103,12 @@ static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod, void * return BT_MESH_WALK_CONTINUE; } -static int mod_sub_overwrite(struct bt_mesh_model *model, +static int mod_sub_overwrite(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint16_t elem_addr, sub_addr; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint8_t *mod_id; uint8_t status; @@ -1174,11 +1174,11 @@ static int mod_sub_overwrite(struct bt_mesh_model *model, mod_id, vnd); } -static int mod_sub_del_all(struct bt_mesh_model *model, +static int mod_sub_del_all(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint16_t elem_addr; uint8_t *mod_id; @@ -1232,13 +1232,13 @@ struct mod_sub_list_ctx { struct net_buf_simple *msg; }; -static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod, void *ctx) +static enum bt_mesh_walk mod_sub_list_visitor(const struct bt_mesh_model *mod, void *ctx) { struct mod_sub_list_ctx *visit = ctx; int count = 0; int i; - if (mod->elem_idx != visit->elem_idx) { + if (*(mod->elem_idx) != visit->elem_idx) { return BT_MESH_WALK_CONTINUE; } @@ -1257,18 +1257,18 @@ static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod, void *c count++; } - LOG_DBG("sublist: model %u:%x: %u groups", mod->elem_idx, mod->id, count); + LOG_DBG("sublist: model %u:%x: %u groups", *(mod->elem_idx), mod->id, count); return BT_MESH_WALK_CONTINUE; } -static int mod_sub_get(struct bt_mesh_model *model, +static int mod_sub_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, BT_MESH_TX_SDU_MAX); struct mod_sub_list_ctx visit_ctx; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint16_t addr, id; @@ -1306,7 +1306,7 @@ static int mod_sub_get(struct bt_mesh_model *model, net_buf_simple_add_le16(&msg, id); visit_ctx.msg = &msg; - visit_ctx.elem_idx = mod->elem_idx; + visit_ctx.elem_idx = *(mod->elem_idx); bt_mesh_model_extensions_walk(mod, mod_sub_list_visitor, &visit_ctx); send_list: @@ -1317,13 +1317,13 @@ static int mod_sub_get(struct bt_mesh_model *model, return 0; } -static int mod_sub_get_vnd(struct bt_mesh_model *model, +static int mod_sub_get_vnd(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, BT_MESH_TX_SDU_MAX); struct mod_sub_list_ctx visit_ctx; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint16_t company, addr, id; @@ -1365,7 +1365,7 @@ static int mod_sub_get_vnd(struct bt_mesh_model *model, net_buf_simple_add_le16(&msg, id); visit_ctx.msg = &msg; - visit_ctx.elem_idx = mod->elem_idx; + visit_ctx.elem_idx = *(mod->elem_idx); bt_mesh_model_extensions_walk(mod, mod_sub_list_visitor, &visit_ctx); send_list: @@ -1376,13 +1376,13 @@ static int mod_sub_get_vnd(struct bt_mesh_model *model, return 0; } -static int mod_sub_va_add(struct bt_mesh_model *model, +static int mod_sub_va_add(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { const struct bt_mesh_va *va; uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; const uint8_t *uuid; uint8_t *mod_id; @@ -1478,13 +1478,13 @@ static int mod_sub_va_add(struct bt_mesh_model *model, mod_id, vnd); } -static int mod_sub_va_del(struct bt_mesh_model *model, +static int mod_sub_va_del(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { const struct bt_mesh_va *va; uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; const uint8_t *uuid; uint8_t *mod_id; @@ -1562,13 +1562,13 @@ static int mod_sub_va_del(struct bt_mesh_model *model, mod_id, vnd); } -static int mod_sub_va_overwrite(struct bt_mesh_model *model, +static int mod_sub_va_overwrite(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { const struct bt_mesh_va *va; uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; const uint8_t *uuid; uint8_t *mod_id; @@ -1638,7 +1638,7 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model, mod_id, vnd); } -static int send_net_key_status(struct bt_mesh_model *model, +static int send_net_key_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint16_t idx, uint8_t status) { @@ -1656,7 +1656,7 @@ static int send_net_key_status(struct bt_mesh_model *model, return 0; } -static int net_key_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int net_key_add(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t status; @@ -1675,7 +1675,7 @@ static int net_key_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return send_net_key_status(model, ctx, idx, status); } -static int net_key_update(struct bt_mesh_model *model, +static int net_key_update(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1693,7 +1693,7 @@ static int net_key_update(struct bt_mesh_model *model, return send_net_key_status(model, ctx, idx, status); } -static int net_key_del(struct bt_mesh_model *model, +static int net_key_del(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1720,7 +1720,7 @@ static int net_key_del(struct bt_mesh_model *model, return send_net_key_status(model, ctx, del_idx, STATUS_SUCCESS); } -static int net_key_get(struct bt_mesh_model *model, +static int net_key_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1745,7 +1745,7 @@ static int net_key_get(struct bt_mesh_model *model, return 0; } -static int send_node_id_status(struct bt_mesh_model *model, +static int send_node_id_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t status, uint16_t net_idx, uint8_t node_id) @@ -1764,7 +1764,7 @@ static int send_node_id_status(struct bt_mesh_model *model, return 0; } -static int node_identity_get(struct bt_mesh_model *model, +static int node_identity_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1786,7 +1786,7 @@ static int node_identity_get(struct bt_mesh_model *model, return send_node_id_status(model, ctx, status, idx, node_id); } -static int node_identity_set(struct bt_mesh_model *model, +static int node_identity_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1824,7 +1824,7 @@ static int node_identity_set(struct bt_mesh_model *model, } static void create_mod_app_status(struct net_buf_simple *msg, - struct bt_mesh_model *mod, bool vnd, + const struct bt_mesh_model *mod, bool vnd, uint16_t elem_addr, uint16_t app_idx, uint8_t status, uint8_t *mod_id) { @@ -1841,13 +1841,13 @@ static void create_mod_app_status(struct net_buf_simple *msg, } } -static int mod_app_bind(struct bt_mesh_model *model, +static int mod_app_bind(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_APP_STATUS, 9); uint16_t elem_addr, key_app_idx; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; @@ -1881,7 +1881,7 @@ static int mod_app_bind(struct bt_mesh_model *model, } /* Some models only allow device key based access */ - if (mod->flags & BT_MESH_MOD_DEVKEY_ONLY) { + if (*(mod->flags) & BT_MESH_MOD_DEVKEY_ONLY) { LOG_ERR("Client tried to bind AppKey to DevKey based model"); status = STATUS_CANNOT_BIND; goto send_status; @@ -1905,13 +1905,13 @@ static int mod_app_bind(struct bt_mesh_model *model, return 0; } -static int mod_app_unbind(struct bt_mesh_model *model, +static int mod_app_unbind(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_APP_STATUS, 9); uint16_t elem_addr, key_app_idx; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; @@ -1964,7 +1964,7 @@ static int mod_app_unbind(struct bt_mesh_model *model, #define KEY_LIST_LEN (CONFIG_BT_MESH_MODEL_KEY_COUNT * 2) -static int mod_app_get(struct bt_mesh_model *model, +static int mod_app_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1973,7 +1973,7 @@ static int mod_app_get(struct bt_mesh_model *model, 9 + KEY_LIST_LEN), BT_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST, 9 + KEY_LIST_LEN))); - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint8_t *mod_id, status; uint16_t elem_addr; @@ -2050,7 +2050,7 @@ static void reset_send_end(int err, void *cb_data) k_work_submit(&node_reset_pending); } -static int node_reset(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int node_reset(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { static const struct bt_mesh_send_cb reset_cb = { @@ -2072,7 +2072,7 @@ static int node_reset(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int send_friend_status(struct bt_mesh_model *model, +static int send_friend_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { BT_MESH_MODEL_BUF_DEFINE(msg, OP_FRIEND_STATUS, 1); @@ -2087,7 +2087,7 @@ static int send_friend_status(struct bt_mesh_model *model, return 0; } -static int friend_get(struct bt_mesh_model *model, +static int friend_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2097,7 +2097,7 @@ static int friend_get(struct bt_mesh_model *model, return send_friend_status(model, ctx); } -static int friend_set(struct bt_mesh_model *model, +static int friend_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2114,7 +2114,7 @@ static int friend_set(struct bt_mesh_model *model, return send_friend_status(model, ctx); } -static int lpn_timeout_get(struct bt_mesh_model *model, +static int lpn_timeout_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2160,7 +2160,7 @@ static int lpn_timeout_get(struct bt_mesh_model *model, return 0; } -static int send_krp_status(struct bt_mesh_model *model, +static int send_krp_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint16_t idx, uint8_t phase, uint8_t status) { @@ -2179,7 +2179,7 @@ static int send_krp_status(struct bt_mesh_model *model, return 0; } -static int krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int krp_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t kr_phase, status; @@ -2198,7 +2198,7 @@ static int krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return send_krp_status(model, ctx, idx, kr_phase, status); } -static int krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int krp_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t phase, status; @@ -2254,7 +2254,7 @@ struct hb_pub_param { uint16_t net_idx; } __packed; -static int hb_pub_send_status(struct bt_mesh_model *model, +static int hb_pub_send_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t status, const struct bt_mesh_hb_pub *pub) { @@ -2284,7 +2284,7 @@ static int hb_pub_send_status(struct bt_mesh_model *model, return 0; } -static int heartbeat_pub_get(struct bt_mesh_model *model, +static int heartbeat_pub_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2297,7 +2297,7 @@ static int heartbeat_pub_get(struct bt_mesh_model *model, return hb_pub_send_status(model, ctx, STATUS_SUCCESS, &pub); } -static int heartbeat_pub_set(struct bt_mesh_model *model, +static int heartbeat_pub_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2357,7 +2357,7 @@ static int heartbeat_pub_set(struct bt_mesh_model *model, return hb_pub_send_status(model, ctx, status, &pub); } -static int hb_sub_send_status(struct bt_mesh_model *model, +static int hb_sub_send_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, const struct bt_mesh_hb_sub *sub) { @@ -2382,7 +2382,7 @@ static int hb_sub_send_status(struct bt_mesh_model *model, return 0; } -static int heartbeat_sub_get(struct bt_mesh_model *model, +static int heartbeat_sub_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2395,7 +2395,7 @@ static int heartbeat_sub_get(struct bt_mesh_model *model, return hb_sub_send_status(model, ctx, &sub); } -static int heartbeat_sub_set(struct bt_mesh_model *model, +static int heartbeat_sub_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2508,7 +2508,7 @@ const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = { BT_MESH_MODEL_OP_END, }; -static int cfg_srv_init(struct bt_mesh_model *model) +static int cfg_srv_init(const struct bt_mesh_model *model) { if (!bt_mesh_model_in_primary(model)) { LOG_ERR("Configuration Server only allowed in primary element"); @@ -2520,7 +2520,7 @@ static int cfg_srv_init(struct bt_mesh_model *model) * device-key is allowed to access this model. */ model->keys[0] = BT_MESH_KEY_DEV_LOCAL; - model->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } @@ -2529,7 +2529,7 @@ const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb = { .init = cfg_srv_init, }; -static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void mod_reset(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { size_t clear_count; diff --git a/subsys/bluetooth/mesh/dfd_srv.c b/subsys/bluetooth/mesh/dfd_srv.c index 0a9ecba6cecf65c..245052b58f8b3a5 100644 --- a/subsys/bluetooth/mesh/dfd_srv.c +++ b/subsys/bluetooth/mesh/dfd_srv.c @@ -112,11 +112,11 @@ static void receivers_status_rsp(struct bt_mesh_dfd_srv *srv, bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); } -static int handle_receivers_add(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_receivers_add(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { enum bt_mesh_dfd_status status = BT_MESH_DFD_SUCCESS; - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); if (buf->len % 3) { return -EINVAL; @@ -143,20 +143,20 @@ static int handle_receivers_add(struct bt_mesh_model *mod, struct bt_mesh_msg_ct return 0; } -static int handle_receivers_delete_all(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_receivers_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); receivers_status_rsp(srv, ctx, bt_mesh_dfd_srv_receivers_delete_all(srv)); return 0; } -static int handle_receivers_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_receivers_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); uint16_t first, cnt; uint8_t progress; int i; @@ -206,7 +206,7 @@ static enum bt_mesh_dfu_iter slot_space_cb(const struct bt_mesh_dfu_slot *slot, return BT_MESH_DFU_ITER_CONTINUE; } -static int handle_capabilities_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_capabilities_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { size_t size = 0; @@ -226,7 +226,7 @@ static int handle_capabilities_get(struct bt_mesh_model *mod, struct bt_mesh_msg net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE - size); #ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); if (srv->oob_schemes.count > 0) { net_buf_simple_add_u8(&rsp, 1); @@ -268,20 +268,20 @@ static void status_rsp(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); } -static int handle_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); return 0; } -static int handle_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); struct bt_mesh_dfd_start_params params; uint8_t byte; @@ -310,31 +310,31 @@ static int handle_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, return 0; } -static int handle_suspend(struct bt_mesh_model *mod, +static int handle_suspend(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); status_rsp(srv, ctx, bt_mesh_dfd_srv_suspend(srv)); return 0; } -static int handle_cancel(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); bt_mesh_dfd_srv_cancel(srv, ctx); return 0; } -static int handle_apply(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); status_rsp(srv, ctx, bt_mesh_dfd_srv_apply(srv)); @@ -393,10 +393,10 @@ static void upload_status_rsp(struct bt_mesh_dfd_srv *srv, upload_status_rsp_with_progress(srv, ctx, status, progress); } -static int handle_upload_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_upload_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); @@ -438,10 +438,10 @@ static inline int set_upload_fwid(struct bt_mesh_dfd_srv *srv, struct bt_mesh_ms return err; } -static int handle_upload_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); size_t meta_len, fwid_len, size; const uint8_t *meta, *fwid; uint16_t timeout_base; @@ -560,10 +560,10 @@ static int handle_upload_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_upload_start_oob(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_upload_start_oob(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); uint8_t uri_len; uint8_t *uri; uint16_t fwid_len; @@ -651,10 +651,10 @@ static int handle_upload_start_oob(struct bt_mesh_model *mod, struct bt_mesh_msg return 0; } -static int handle_upload_cancel(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_upload_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; #ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD @@ -690,10 +690,10 @@ static void fw_status_rsp(struct bt_mesh_dfd_srv *srv, bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); } -static int handle_fw_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_fw_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); struct bt_mesh_dfu_slot *slot; const uint8_t *fwid; size_t fwid_len; @@ -714,10 +714,10 @@ static int handle_fw_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, return 0; } -static int handle_fw_get_by_index(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_fw_get_by_index(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); const struct bt_mesh_dfu_slot *slot; uint16_t idx; @@ -735,10 +735,10 @@ static int handle_fw_get_by_index(struct bt_mesh_model *mod, struct bt_mesh_msg_ return 0; } -static int handle_fw_delete(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_fw_delete(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); const uint8_t *fwid; size_t fwid_len; @@ -764,10 +764,10 @@ static enum bt_mesh_dfu_iter slot_del_cb(const struct bt_mesh_dfu_slot *slot, return BT_MESH_DFU_ITER_CONTINUE; } -static int handle_fw_delete_all(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_fw_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); fw_status_rsp(srv, ctx, bt_mesh_dfd_srv_fw_delete_all(srv), 0xffff, NULL, 0); @@ -923,9 +923,9 @@ const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb = { .suspended = upload_timeout, }; -static int dfd_srv_init(struct bt_mesh_model *mod) +static int dfd_srv_init(const struct bt_mesh_model *mod) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); srv->mod = mod; @@ -936,9 +936,9 @@ static int dfd_srv_init(struct bt_mesh_model *mod) return 0; } -static void dfd_srv_reset(struct bt_mesh_model *mod) +static void dfd_srv_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_srv *srv = *(mod->user_data); dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; diff --git a/subsys/bluetooth/mesh/dfu_cli.c b/subsys/bluetooth/mesh/dfu_cli.c index 3adb63644d02ae4..70b03f4e814dc31 100644 --- a/subsys/bluetooth/mesh/dfu_cli.c +++ b/subsys/bluetooth/mesh/dfu_cli.c @@ -305,8 +305,9 @@ static void tx_end(int err, void *cb_data) blob_cli_broadcast_tx_complete(&cli->blob); } -static int tx(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, - const struct bt_mesh_send_cb *cb, struct bt_mesh_dfu_cli *cli) +static int tx(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf, const struct bt_mesh_send_cb *cb, + struct bt_mesh_dfu_cli *cli) { int err; @@ -698,10 +699,10 @@ static void cancelled(struct bt_mesh_blob_cli *b) * Message handlers ******************************************************************************/ -static int handle_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_cli *cli = mod->user_data; + struct bt_mesh_dfu_cli *cli = *(mod->user_data); enum bt_mesh_dfu_status status; enum bt_mesh_dfu_phase phase; struct bt_mesh_dfu_target *target; @@ -824,10 +825,10 @@ static int handle_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, return 0; } -static int handle_info_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_cli *cli = mod->user_data; + struct bt_mesh_dfu_cli *cli = *(mod->user_data); struct bt_mesh_dfu_target *target; enum bt_mesh_dfu_iter it = BT_MESH_DFU_ITER_CONTINUE; uint8_t img_cnt, idx; @@ -923,10 +924,10 @@ static int handle_info_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_metadata_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_metadata_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_cli *cli = mod->user_data; + struct bt_mesh_dfu_cli *cli = *(mod->user_data); struct bt_mesh_dfu_metadata_status *rsp = cli->req.params; uint8_t hdr, idx; @@ -960,11 +961,11 @@ const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[] = { BT_MESH_MODEL_OP_END, }; -static int dfu_cli_init(struct bt_mesh_model *mod) +static int dfu_cli_init(const struct bt_mesh_model *mod) { - struct bt_mesh_dfu_cli *cli = mod->user_data; + struct bt_mesh_dfu_cli *cli = *(mod->user_data); - if (mod->elem_idx != 0) { + if (*(mod->elem_idx) != 0) { LOG_ERR("DFU update client must be instantiated on first elem"); return -EINVAL; } @@ -980,9 +981,9 @@ static int dfu_cli_init(struct bt_mesh_model *mod) return 0; } -static void dfu_cli_reset(struct bt_mesh_model *mod) +static void dfu_cli_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_dfu_cli *cli = mod->user_data; + struct bt_mesh_dfu_cli *cli = *(mod->user_data); cli->req.type = REQ_NONE; cli->req.addr = BT_MESH_ADDR_UNASSIGNED; diff --git a/subsys/bluetooth/mesh/dfu_srv.c b/subsys/bluetooth/mesh/dfu_srv.c index 462a777b46c88d1..edd61e6da40b35e 100644 --- a/subsys/bluetooth/mesh/dfu_srv.c +++ b/subsys/bluetooth/mesh/dfu_srv.c @@ -125,10 +125,10 @@ static void verify(struct bt_mesh_dfu_srv *srv) } } -static int handle_info_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->user_data; + struct bt_mesh_dfu_srv *srv = *(mod->user_data); uint8_t idx, limit; if (srv->update.phase == BT_MESH_DFU_PHASE_APPLYING) { @@ -187,10 +187,10 @@ static int handle_info_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ct return 0; } -static int handle_metadata_check(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_metadata_check(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->user_data; + struct bt_mesh_dfu_srv *srv = *(mod->user_data); enum bt_mesh_dfu_status status; enum bt_mesh_dfu_effect effect; uint8_t idx; @@ -239,10 +239,10 @@ static void update_status_rsp(struct bt_mesh_dfu_srv *srv, bt_mesh_model_send(srv->mod, ctx, &buf, send_cb, srv); } -static int handle_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->user_data; + struct bt_mesh_dfu_srv *srv = *(mod->user_data); LOG_DBG(""); @@ -262,10 +262,10 @@ static inline bool is_active_update(struct bt_mesh_dfu_srv *srv, uint8_t idx, srv->update.meta != meta_checksum); } -static int handle_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->user_data; + struct bt_mesh_dfu_srv *srv = *(mod->user_data); const struct bt_mesh_blob_io *io; uint16_t timeout_base, meta_checksum; enum bt_mesh_dfu_status status; @@ -371,10 +371,10 @@ static int handle_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, return 0; } -static int handle_cancel(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->user_data; + struct bt_mesh_dfu_srv *srv = *(mod->user_data); if (srv->update.idx == UPDATE_IDX_NONE) { goto rsp; @@ -392,10 +392,10 @@ static int handle_cancel(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, return 0; } -static int handle_apply(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->user_data; + struct bt_mesh_dfu_srv *srv = *(mod->user_data); static const struct bt_mesh_send_cb send_cb = { .start = apply_rsp_sending, .end = apply_rsp_sent, @@ -435,9 +435,9 @@ const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[] = { BT_MESH_MODEL_OP_END, }; -static int dfu_srv_init(struct bt_mesh_model *mod) +static int dfu_srv_init(const struct bt_mesh_model *mod) { - struct bt_mesh_dfu_srv *srv = mod->user_data; + struct bt_mesh_dfu_srv *srv = *(mod->user_data); srv->mod = mod; srv->update.idx = UPDATE_IDX_NONE; @@ -455,11 +455,11 @@ static int dfu_srv_init(struct bt_mesh_model *mod) return 0; } -static int dfu_srv_settings_set(struct bt_mesh_model *mod, const char *name, +static int dfu_srv_settings_set(const struct bt_mesh_model *mod, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { - struct bt_mesh_dfu_srv *srv = mod->user_data; + struct bt_mesh_dfu_srv *srv = *(mod->user_data); ssize_t len; if (len_rd < sizeof(srv->update)) { @@ -484,9 +484,9 @@ static int dfu_srv_settings_set(struct bt_mesh_model *mod, const char *name, return 0; } -static void dfu_srv_reset(struct bt_mesh_model *mod) +static void dfu_srv_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_dfu_srv *srv = mod->user_data; + struct bt_mesh_dfu_srv *srv = *(mod->user_data); srv->update.phase = BT_MESH_DFU_PHASE_IDLE; erase_state(srv); diff --git a/subsys/bluetooth/mesh/foundation.h b/subsys/bluetooth/mesh/foundation.h index 01cbf93c39e533f..8a9beef642e8b3e 100644 --- a/subsys/bluetooth/mesh/foundation.h +++ b/subsys/bluetooth/mesh/foundation.h @@ -150,7 +150,7 @@ void bt_mesh_model_reset(void); -void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time); +void bt_mesh_attention(const struct bt_mesh_model *model, uint8_t time); #include diff --git a/subsys/bluetooth/mesh/health_cli.c b/subsys/bluetooth/mesh/health_cli.c index 924005f488218f8..d34d869e243ec74 100644 --- a/subsys/bluetooth/mesh/health_cli.c +++ b/subsys/bluetooth/mesh/health_cli.c @@ -36,11 +36,11 @@ struct health_fault_param { size_t *fault_count; }; -static int health_fault_status(struct bt_mesh_model *model, +static int health_fault_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_cli *cli = model->user_data; + struct bt_mesh_health_cli *cli = *(model->user_data); struct health_fault_param *param; uint8_t test_id; uint16_t cid; @@ -89,11 +89,11 @@ static int health_fault_status(struct bt_mesh_model *model, return 0; } -static int health_current_status(struct bt_mesh_model *model, +static int health_current_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_cli *cli = model->user_data; + struct bt_mesh_health_cli *cli = *(model->user_data); uint8_t test_id; uint16_t cid; @@ -117,11 +117,11 @@ struct health_period_param { uint8_t *divisor; }; -static int health_period_status(struct bt_mesh_model *model, +static int health_period_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_cli *cli = model->user_data; + struct bt_mesh_health_cli *cli = *(model->user_data); struct health_period_param *param; uint8_t divisor; @@ -151,11 +151,11 @@ struct health_attention_param { uint8_t *attention; }; -static int health_attention_status(struct bt_mesh_model *model, +static int health_attention_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_cli *cli = model->user_data; + struct bt_mesh_health_cli *cli = *(model->user_data); struct health_attention_param *param; uint8_t attention; @@ -402,9 +402,9 @@ void bt_mesh_health_cli_timeout_set(int32_t timeout) msg_timeout = timeout; } -static int health_cli_init(struct bt_mesh_model *model) +static int health_cli_init(const struct bt_mesh_model *model) { - struct bt_mesh_health_cli *cli = model->user_data; + struct bt_mesh_health_cli *cli = *(model->user_data); LOG_DBG("primary %u", bt_mesh_model_in_primary(model)); @@ -423,9 +423,9 @@ static int health_cli_init(struct bt_mesh_model *model) return 0; } -static void health_cli_reset(struct bt_mesh_model *model) +static void health_cli_reset(const struct bt_mesh_model *model) { - struct bt_mesh_health_cli *cli = model->user_data; + struct bt_mesh_health_cli *cli = *(model->user_data); net_buf_simple_reset(cli->pub.msg); } diff --git a/subsys/bluetooth/mesh/health_srv.c b/subsys/bluetooth/mesh/health_srv.c index bfab40b6ef96b8c..4ae55266ebfbb67 100644 --- a/subsys/bluetooth/mesh/health_srv.c +++ b/subsys/bluetooth/mesh/health_srv.c @@ -31,11 +31,11 @@ LOG_MODULE_REGISTER(bt_mesh_health_srv); /* Health Server context of the primary element */ struct bt_mesh_health_srv *health_srv; -static void health_get_registered(struct bt_mesh_model *mod, +static void health_get_registered(const struct bt_mesh_model *mod, uint16_t company_id, struct net_buf_simple *msg) { - struct bt_mesh_health_srv *srv = mod->user_data; + struct bt_mesh_health_srv *srv = *(mod->user_data); uint8_t *test_id; LOG_DBG("Company ID 0x%04x", company_id); @@ -64,10 +64,10 @@ static void health_get_registered(struct bt_mesh_model *mod, } } -static size_t health_get_current(struct bt_mesh_model *mod, +static size_t health_get_current(const struct bt_mesh_model *mod, struct net_buf_simple *msg) { - struct bt_mesh_health_srv *srv = mod->user_data; + struct bt_mesh_health_srv *srv = *(mod->user_data); const struct bt_mesh_comp *comp; uint8_t *test_id, *company_ptr; uint16_t company_id; @@ -105,7 +105,7 @@ static size_t health_get_current(struct bt_mesh_model *mod, return fault_count; } -static int health_fault_get(struct bt_mesh_model *model, +static int health_fault_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -125,11 +125,11 @@ static int health_fault_get(struct bt_mesh_model *model, return 0; } -static int health_fault_clear_unrel(struct bt_mesh_model *model, +static int health_fault_clear_unrel(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_srv *srv = model->user_data; + struct bt_mesh_health_srv *srv = *(model->user_data); uint16_t company_id; company_id = net_buf_simple_pull_le16(buf); @@ -143,12 +143,12 @@ static int health_fault_clear_unrel(struct bt_mesh_model *model, return 0; } -static int health_fault_clear(struct bt_mesh_model *model, +static int health_fault_clear(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX); - struct bt_mesh_health_srv *srv = model->user_data; + struct bt_mesh_health_srv *srv = *(model->user_data); uint16_t company_id; company_id = net_buf_simple_pull_le16(buf); @@ -173,11 +173,11 @@ static int health_fault_clear(struct bt_mesh_model *model, return 0; } -static int health_fault_test_unrel(struct bt_mesh_model *model, +static int health_fault_test_unrel(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_srv *srv = model->user_data; + struct bt_mesh_health_srv *srv = *(model->user_data); uint16_t company_id; uint8_t test_id; @@ -193,12 +193,12 @@ static int health_fault_test_unrel(struct bt_mesh_model *model, return 0; } -static int health_fault_test(struct bt_mesh_model *model, +static int health_fault_test(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX); - struct bt_mesh_health_srv *srv = model->user_data; + struct bt_mesh_health_srv *srv = *(model->user_data); uint16_t company_id; uint8_t test_id; @@ -228,12 +228,12 @@ static int health_fault_test(struct bt_mesh_model *model, return 0; } -static int send_attention_status(struct bt_mesh_model *model, +static int send_attention_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { /* Needed size: opcode (2 bytes) + msg + MIC */ BT_MESH_MODEL_BUF_DEFINE(msg, OP_ATTENTION_STATUS, 1); - struct bt_mesh_health_srv *srv = model->user_data; + struct bt_mesh_health_srv *srv = *(model->user_data); uint8_t time; time = k_ticks_to_ms_floor32( @@ -251,7 +251,7 @@ static int send_attention_status(struct bt_mesh_model *model, return 0; } -static int attention_get(struct bt_mesh_model *model, +static int attention_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -260,7 +260,7 @@ static int attention_get(struct bt_mesh_model *model, return send_attention_status(model, ctx); } -static int attention_set_unrel(struct bt_mesh_model *model, +static int attention_set_unrel(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -275,7 +275,7 @@ static int attention_set_unrel(struct bt_mesh_model *model, return 0; } -static int attention_set(struct bt_mesh_model *model, +static int attention_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -291,7 +291,7 @@ static int attention_set(struct bt_mesh_model *model, return send_attention_status(model, ctx); } -static int send_health_period_status(struct bt_mesh_model *model, +static int send_health_period_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { /* Needed size: opcode (2 bytes) + msg + MIC */ @@ -308,7 +308,7 @@ static int send_health_period_status(struct bt_mesh_model *model, return 0; } -static int health_period_get(struct bt_mesh_model *model, +static int health_period_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -317,7 +317,7 @@ static int health_period_get(struct bt_mesh_model *model, return send_health_period_status(model, ctx); } -static int health_period_set_unrel(struct bt_mesh_model *model, +static int health_period_set_unrel(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -336,7 +336,7 @@ static int health_period_set_unrel(struct bt_mesh_model *model, return 0; } -static int health_period_set(struct bt_mesh_model *model, +static int health_period_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -367,7 +367,7 @@ const struct bt_mesh_model_op bt_mesh_health_srv_op[] = { BT_MESH_MODEL_OP_END, }; -static int health_pub_update(struct bt_mesh_model *mod) +static int health_pub_update(const struct bt_mesh_model *mod) { struct bt_mesh_model_pub *pub = mod->pub; size_t count; @@ -386,7 +386,7 @@ static int health_pub_update(struct bt_mesh_model *mod) int bt_mesh_health_srv_fault_update(struct bt_mesh_elem *elem) { - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; mod = bt_mesh_model_find(elem, BT_MESH_MODEL_ID_HEALTH_SRV); if (!mod) { @@ -418,9 +418,9 @@ static void attention_off(struct k_work *work) } } -static int health_srv_init(struct bt_mesh_model *model) +static int health_srv_init(const struct bt_mesh_model *model) { - struct bt_mesh_health_srv *srv = model->user_data; + struct bt_mesh_health_srv *srv = *(model->user_data); if (!srv) { LOG_ERR("No Health Server context provided"); @@ -449,7 +449,7 @@ const struct bt_mesh_model_cb bt_mesh_health_srv_cb = { .init = health_srv_init, }; -void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time) +void bt_mesh_attention(const struct bt_mesh_model *model, uint8_t time) { struct bt_mesh_health_srv *srv; @@ -462,7 +462,7 @@ void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time) model = srv->model; } else { - srv = model->user_data; + srv = *(model->user_data); } if ((time > 0) && srv->cb && srv->cb->attn_on) { diff --git a/subsys/bluetooth/mesh/large_comp_data_cli.c b/subsys/bluetooth/mesh/large_comp_data_cli.c index 614569d54ae6991..dc1152f415f1ede 100644 --- a/subsys/bluetooth/mesh/large_comp_data_cli.c +++ b/subsys/bluetooth/mesh/large_comp_data_cli.c @@ -33,7 +33,7 @@ LOG_MODULE_REGISTER(bt_mesh_large_comp_data_cli); static struct bt_mesh_large_comp_data_cli *cli; static int32_t msg_timeout; -static int data_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int data_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint32_t op, void (*cb)(struct bt_mesh_large_comp_data_cli *cli, uint16_t addr, struct bt_mesh_large_comp_data_rsp *rsp)) @@ -78,7 +78,7 @@ static int data_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int large_comp_data_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int large_comp_data_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return data_status(model, ctx, buf, OP_LARGE_COMP_DATA_STATUS, @@ -86,7 +86,7 @@ static int large_comp_data_status(struct bt_mesh_model *model, struct bt_mesh_ms cli->cb->large_comp_data_status : NULL)); } -static int models_metadata_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int models_metadata_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return data_status(model, ctx, buf, OP_MODELS_METADATA_STATUS, @@ -100,7 +100,7 @@ const struct bt_mesh_model_op _bt_mesh_large_comp_data_cli_op[] = { BT_MESH_MODEL_OP_END, }; -static int large_comp_data_cli_init(struct bt_mesh_model *model) +static int large_comp_data_cli_init(const struct bt_mesh_model *model) { if (!bt_mesh_model_in_primary(model)) { LOG_ERR("Large Comp Data Client only allowed in primary element"); @@ -108,9 +108,9 @@ static int large_comp_data_cli_init(struct bt_mesh_model *model) } model->keys[0] = BT_MESH_KEY_DEV_ANY; - model->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; - cli = model->user_data; + cli = *(model->user_data); cli->model = model; msg_timeout = 5000; diff --git a/subsys/bluetooth/mesh/large_comp_data_srv.c b/subsys/bluetooth/mesh/large_comp_data_srv.c index 4ee591d9efd538d..5d724b9f0837004 100644 --- a/subsys/bluetooth/mesh/large_comp_data_srv.c +++ b/subsys/bluetooth/mesh/large_comp_data_srv.c @@ -37,10 +37,11 @@ LOG_MODULE_REGISTER(bt_mesh_large_comp_data_srv); /** Mesh Large Composition Data Server Model Context */ static struct bt_mesh_large_comp_data_srv { /** Composition data model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; } srv; -static int handle_large_comp_data_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int handle_large_comp_data_get(const struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { BT_MESH_MODEL_BUF_DEFINE(rsp, OP_LARGE_COMP_DATA_STATUS, @@ -101,7 +102,8 @@ static int handle_large_comp_data_get(struct bt_mesh_model *model, struct bt_mes return 0; } -static int handle_models_metadata_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int handle_models_metadata_get(const struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { BT_MESH_MODEL_BUF_DEFINE(rsp, OP_MODELS_METADATA_STATUS, @@ -166,7 +168,7 @@ const struct bt_mesh_model_op _bt_mesh_large_comp_data_srv_op[] = { BT_MESH_MODEL_OP_END, }; -static int large_comp_data_srv_init(struct bt_mesh_model *model) +static int large_comp_data_srv_init(const struct bt_mesh_model *model) { if (!bt_mesh_model_in_primary(model)) { LOG_ERR("Large Composition Data Server only allowed in primary element"); @@ -175,7 +177,7 @@ static int large_comp_data_srv_init(struct bt_mesh_model *model) /* Large Composition Data Server model shall use the device key */ model->keys[0] = BT_MESH_KEY_DEV; - model->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; srv.model = model; diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index fb70eef669a2f3d..3aedf19af487f8f 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -419,7 +419,7 @@ bool bt_mesh_is_provisioned(void) return atomic_test_bit(bt_mesh.flags, BT_MESH_VALID); } -static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void model_suspend(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { if (mod->pub && mod->pub->update) { @@ -463,7 +463,7 @@ int bt_mesh_suspend(void) return 0; } -static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void model_resume(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { if (mod->pub && mod->pub->update) { @@ -552,7 +552,7 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, return 0; } -static void model_start(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void model_start(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { if (mod->cb && mod->cb->start) { diff --git a/subsys/bluetooth/mesh/msg.c b/subsys/bluetooth/mesh/msg.c index 458b387539f0963..6ba497be0c0c6ce 100644 --- a/subsys/bluetooth/mesh/msg.c +++ b/subsys/bluetooth/mesh/msg.c @@ -87,7 +87,7 @@ bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack, return true; } -int bt_mesh_msg_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +int bt_mesh_msg_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { if (!ctx && !model->pub) { @@ -104,7 +104,7 @@ int bt_mesh_msg_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return bt_mesh_model_publish(model); } -int bt_mesh_msg_ackd_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +int bt_mesh_msg_ackd_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, const struct bt_mesh_msg_rsp_ctx *rsp) { int err; diff --git a/subsys/bluetooth/mesh/msg.h b/subsys/bluetooth/mesh/msg.h index a5d759491308757..ff52260b626ee33 100644 --- a/subsys/bluetooth/mesh/msg.h +++ b/subsys/bluetooth/mesh/msg.h @@ -18,7 +18,7 @@ * @retval -EADDRNOTAVAIL A message context was not provided and publishing is not configured. * @retval -EAGAIN The device has not been provisioned. */ -int bt_mesh_msg_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +int bt_mesh_msg_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); /** @@ -51,5 +51,5 @@ struct bt_mesh_msg_rsp_ctx { * @retval -EAGAIN The device has not been provisioned. * @retval -ETIMEDOUT The request timed out without a response. */ -int bt_mesh_msg_ackd_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +int bt_mesh_msg_ackd_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, const struct bt_mesh_msg_rsp_ctx *rsp); diff --git a/subsys/bluetooth/mesh/od_priv_proxy_cli.c b/subsys/bluetooth/mesh/od_priv_proxy_cli.c index 67f5ac961ad536c..f2844d2ecc68ba2 100644 --- a/subsys/bluetooth/mesh/od_priv_proxy_cli.c +++ b/subsys/bluetooth/mesh/od_priv_proxy_cli.c @@ -20,7 +20,7 @@ static struct bt_mesh_od_priv_proxy_cli *cli; static int32_t msg_timeout; -static int handle_proxy_status(struct bt_mesh_model *mod, +static int handle_proxy_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -93,17 +93,17 @@ void bt_mesh_od_priv_proxy_cli_timeout_set(int32_t timeout) msg_timeout = timeout; } -static int on_demand_proxy_cli_init(struct bt_mesh_model *mod) +static int on_demand_proxy_cli_init(const struct bt_mesh_model *mod) { if (!bt_mesh_model_in_primary(mod)) { LOG_ERR("On-Demand Private Proxy client not in primary element"); return -EINVAL; } - cli = mod->user_data; + cli = *(mod->user_data); cli->model = mod; mod->keys[0] = BT_MESH_KEY_DEV_ANY; - mod->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; msg_timeout = CONFIG_BT_MESH_OD_PRIV_PROXY_CLI_TIMEOUT; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); diff --git a/subsys/bluetooth/mesh/od_priv_proxy_srv.c b/subsys/bluetooth/mesh/od_priv_proxy_srv.c index b18a8ec7530f318..e671a80e9de6662 100644 --- a/subsys/bluetooth/mesh/od_priv_proxy_srv.c +++ b/subsys/bluetooth/mesh/od_priv_proxy_srv.c @@ -16,7 +16,7 @@ LOG_MODULE_REGISTER(bt_mesh_od_priv_proxy_srv); -static struct bt_mesh_model *od_priv_proxy_srv; +static const struct bt_mesh_model *od_priv_proxy_srv; static uint8_t on_demand_state; static int od_priv_proxy_store(bool delete) @@ -31,7 +31,7 @@ static int od_priv_proxy_store(bool delete) return bt_mesh_model_data_store(od_priv_proxy_srv, false, "pp", data, len); } -static int proxy_status_rsp(struct bt_mesh_model *mod, +static int proxy_status_rsp(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx) { BT_MESH_MODEL_BUF_DEFINE(buf, OP_OD_PRIV_PROXY_STATUS, 1); @@ -44,7 +44,7 @@ static int proxy_status_rsp(struct bt_mesh_model *mod, return 0; } -static int handle_proxy_get(struct bt_mesh_model *mod, +static int handle_proxy_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -55,7 +55,7 @@ static int handle_proxy_get(struct bt_mesh_model *mod, return 0; } -static int handle_proxy_set(struct bt_mesh_model *mod, +static int handle_proxy_set(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -79,13 +79,13 @@ const struct bt_mesh_model_op _bt_mesh_od_priv_proxy_srv_op[] = { BT_MESH_MODEL_OP_END }; -static int od_priv_proxy_srv_init(struct bt_mesh_model *mod) +static int od_priv_proxy_srv_init(const struct bt_mesh_model *mod) { od_priv_proxy_srv = mod; - struct bt_mesh_model *priv_beacon_srv = bt_mesh_model_find( + const struct bt_mesh_model *priv_beacon_srv = bt_mesh_model_find( bt_mesh_model_elem(mod), BT_MESH_MODEL_ID_PRIV_BEACON_SRV); - struct bt_mesh_model *sol_pdu_rpl_srv = bt_mesh_model_find( + const struct bt_mesh_model *sol_pdu_rpl_srv = bt_mesh_model_find( bt_mesh_model_elem(mod), BT_MESH_MODEL_ID_SOL_PDU_RPL_SRV); if (priv_beacon_srv == NULL) { @@ -98,7 +98,7 @@ static int od_priv_proxy_srv_init(struct bt_mesh_model *mod) } mod->keys[0] = BT_MESH_KEY_DEV_LOCAL; - mod->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) { bt_mesh_model_extend(mod, priv_beacon_srv); @@ -108,14 +108,14 @@ static int od_priv_proxy_srv_init(struct bt_mesh_model *mod) return 0; } -static void od_priv_proxy_srv_reset(struct bt_mesh_model *model) +static void od_priv_proxy_srv_reset(const struct bt_mesh_model *model) { on_demand_state = 0; od_priv_proxy_store(true); } #ifdef CONFIG_BT_SETTINGS -static int od_priv_proxy_srv_settings_set(struct bt_mesh_model *model, const char *name, +static int od_priv_proxy_srv_settings_set(const struct bt_mesh_model *model, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_data) { int err; @@ -135,7 +135,7 @@ static int od_priv_proxy_srv_settings_set(struct bt_mesh_model *model, const cha return 0; } -static void od_priv_proxy_srv_pending_store(struct bt_mesh_model *model) +static void od_priv_proxy_srv_pending_store(const struct bt_mesh_model *model) { on_demand_state = bt_mesh_od_priv_proxy_get(); od_priv_proxy_store(false); diff --git a/subsys/bluetooth/mesh/op_agg.h b/subsys/bluetooth/mesh/op_agg.h index 8bb3d6c97ba8cb2..a56a30ccd31388e 100644 --- a/subsys/bluetooth/mesh/op_agg.h +++ b/subsys/bluetooth/mesh/op_agg.h @@ -19,8 +19,8 @@ struct op_agg_ctx { int bt_mesh_op_agg_encode_msg(struct net_buf_simple *msg, struct net_buf_simple *buf); int bt_mesh_op_agg_decode_msg(struct net_buf_simple *msg, struct net_buf_simple *buf); -int bt_mesh_op_agg_cli_send(struct bt_mesh_model *model, struct net_buf_simple *msg); +int bt_mesh_op_agg_cli_send(const struct bt_mesh_model *model, struct net_buf_simple *msg); int bt_mesh_op_agg_cli_accept(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); -int bt_mesh_op_agg_srv_send(struct bt_mesh_model *model, struct net_buf_simple *msg); +int bt_mesh_op_agg_srv_send(const struct bt_mesh_model *model, struct net_buf_simple *msg); int bt_mesh_op_agg_srv_accept(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); bool bt_mesh_op_agg_is_op_agg_msg(struct net_buf_simple *buf); diff --git a/subsys/bluetooth/mesh/op_agg_cli.c b/subsys/bluetooth/mesh/op_agg_cli.c index 612843a98cc9dfe..b74b8245cfd56da 100644 --- a/subsys/bluetooth/mesh/op_agg_cli.c +++ b/subsys/bluetooth/mesh/op_agg_cli.c @@ -24,7 +24,7 @@ NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_TX_SDU_MAX); /** Mesh Opcodes Aggregator Client Model Context */ static struct bt_mesh_op_agg_cli { /** Composition data model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Acknowledge context. */ struct bt_mesh_msg_ack_ctx ack_ctx; /** List of source element addresses. @@ -39,7 +39,7 @@ static struct bt_mesh_op_agg_cli { static int32_t msg_timeout; -static int handle_status(struct bt_mesh_model *model, +static int handle_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -102,7 +102,7 @@ const struct bt_mesh_model_op _bt_mesh_op_agg_cli_op[] = { BT_MESH_MODEL_OP_END, }; -static int op_agg_cli_init(struct bt_mesh_model *model) +static int op_agg_cli_init(const struct bt_mesh_model *model) { if (!bt_mesh_model_in_primary(model)) { LOG_ERR("Opcodes Aggregator Client only allowed in primary element"); @@ -203,7 +203,7 @@ void bt_mesh_op_agg_cli_timeout_set(int32_t timeout) msg_timeout = timeout; } -int bt_mesh_op_agg_cli_send(struct bt_mesh_model *model, struct net_buf_simple *msg) +int bt_mesh_op_agg_cli_send(const struct bt_mesh_model *model, struct net_buf_simple *msg) { uint16_t src = bt_mesh_model_elem(model)->addr; diff --git a/subsys/bluetooth/mesh/op_agg_srv.c b/subsys/bluetooth/mesh/op_agg_srv.c index a6e5f6664112a3c..9bbe01384e2b9d0 100644 --- a/subsys/bluetooth/mesh/op_agg_srv.c +++ b/subsys/bluetooth/mesh/op_agg_srv.c @@ -22,7 +22,7 @@ NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_TX_SDU_MAX); /** Mesh Opcodes Aggragator Server Model Context */ static struct bt_mesh_op_agg_srv { /** Composition data model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Response error code. */ int rsp_err; /** Indicates that the received aggregated message @@ -33,7 +33,7 @@ static struct bt_mesh_op_agg_srv { struct op_agg_ctx ctx; } srv = {.ctx.sdu = &sdu}; -static int handle_sequence(struct bt_mesh_model *model, +static int handle_sequence(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -114,7 +114,7 @@ const struct bt_mesh_model_op _bt_mesh_op_agg_srv_op[] = { BT_MESH_MODEL_OP_END, }; -static int op_agg_srv_init(struct bt_mesh_model *model) +static int op_agg_srv_init(const struct bt_mesh_model *model) { if (!bt_mesh_model_in_primary(model)) { LOG_ERR("Opcodes Aggregator Server only allowed in primary element"); @@ -131,7 +131,7 @@ static int op_agg_srv_init(struct bt_mesh_model *model) return 0; } -int bt_mesh_op_agg_srv_send(struct bt_mesh_model *model, struct net_buf_simple *msg) +int bt_mesh_op_agg_srv_send(const struct bt_mesh_model *model, struct net_buf_simple *msg) { int err; diff --git a/subsys/bluetooth/mesh/priv_beacon_cli.c b/subsys/bluetooth/mesh/priv_beacon_cli.c index d14454c7cf5f995..fd48ef0583b35ea 100644 --- a/subsys/bluetooth/mesh/priv_beacon_cli.c +++ b/subsys/bluetooth/mesh/priv_beacon_cli.c @@ -18,7 +18,7 @@ static struct bt_mesh_priv_beacon_cli *cli; static int32_t msg_timeout; -static int handle_beacon_status(struct bt_mesh_model *model, +static int handle_beacon_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -56,7 +56,7 @@ static int handle_beacon_status(struct bt_mesh_model *model, return 0; } -static int handle_gatt_proxy_status(struct bt_mesh_model *model, +static int handle_gatt_proxy_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -86,7 +86,7 @@ static int handle_gatt_proxy_status(struct bt_mesh_model *model, return 0; } -static int handle_node_id_status(struct bt_mesh_model *model, +static int handle_node_id_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -134,18 +134,18 @@ const struct bt_mesh_model_op bt_mesh_priv_beacon_cli_op[] = { BT_MESH_MODEL_OP_END, }; -static int priv_beacon_cli_init(struct bt_mesh_model *model) +static int priv_beacon_cli_init(const struct bt_mesh_model *model) { if (!bt_mesh_model_in_primary(model)) { LOG_ERR("Private Beacon Client only allowed in primary element"); return -EINVAL; } - cli = model->user_data; + cli = *(model->user_data); cli->model = model; msg_timeout = 2 * MSEC_PER_SEC; model->keys[0] = BT_MESH_KEY_DEV_ANY; - model->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); diff --git a/subsys/bluetooth/mesh/priv_beacon_srv.c b/subsys/bluetooth/mesh/priv_beacon_srv.c index 377703e8352ebb4..5b5e62f17363f6d 100644 --- a/subsys/bluetooth/mesh/priv_beacon_srv.c +++ b/subsys/bluetooth/mesh/priv_beacon_srv.c @@ -17,7 +17,7 @@ #include LOG_MODULE_REGISTER(bt_mesh_priv_beacon_srv); -static struct bt_mesh_model *priv_beacon_srv; +static const struct bt_mesh_model *priv_beacon_srv; /* Private Beacon configuration server model states */ struct { @@ -38,7 +38,7 @@ static int priv_beacon_store(bool delete) return bt_mesh_model_data_store(priv_beacon_srv, false, "pb", data, len); } -static int beacon_status_rsp(struct bt_mesh_model *mod, +static int beacon_status_rsp(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx) { BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_BEACON_STATUS, 2); @@ -52,7 +52,7 @@ static int beacon_status_rsp(struct bt_mesh_model *mod, return 0; } -static int handle_beacon_get(struct bt_mesh_model *mod, +static int handle_beacon_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -63,7 +63,7 @@ static int handle_beacon_get(struct bt_mesh_model *mod, return 0; } -static int handle_beacon_set(struct bt_mesh_model *mod, +static int handle_beacon_set(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -90,7 +90,7 @@ static int handle_beacon_set(struct bt_mesh_model *mod, return 0; } -static void gatt_proxy_status_rsp(struct bt_mesh_model *mod, +static void gatt_proxy_status_rsp(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx) { BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_STATUS, 1); @@ -101,7 +101,7 @@ static void gatt_proxy_status_rsp(struct bt_mesh_model *mod, bt_mesh_model_send(mod, ctx, &buf, NULL, NULL); } -static int handle_gatt_proxy_get(struct bt_mesh_model *mod, +static int handle_gatt_proxy_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -112,7 +112,7 @@ static int handle_gatt_proxy_get(struct bt_mesh_model *mod, return 0; } -static int handle_gatt_proxy_set(struct bt_mesh_model *mod, +static int handle_gatt_proxy_set(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -134,7 +134,7 @@ static int handle_gatt_proxy_set(struct bt_mesh_model *mod, return 0; } -static void node_id_status_rsp(struct bt_mesh_model *mod, +static void node_id_status_rsp(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, uint8_t status, uint16_t net_idx, uint8_t node_id) { @@ -148,7 +148,7 @@ static void node_id_status_rsp(struct bt_mesh_model *mod, bt_mesh_model_send(mod, ctx, &buf, NULL, NULL); } -static int handle_node_id_get(struct bt_mesh_model *mod, +static int handle_node_id_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -163,7 +163,7 @@ static int handle_node_id_get(struct bt_mesh_model *mod, return 0; } -static int handle_node_id_set(struct bt_mesh_model *mod, +static int handle_node_id_set(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -194,7 +194,7 @@ const struct bt_mesh_model_op bt_mesh_priv_beacon_srv_op[] = { BT_MESH_MODEL_OP_END }; -static int priv_beacon_srv_init(struct bt_mesh_model *mod) +static int priv_beacon_srv_init(const struct bt_mesh_model *mod) { if (!bt_mesh_model_in_primary(mod)) { LOG_ERR("Priv beacon server not in primary element"); @@ -207,14 +207,14 @@ static int priv_beacon_srv_init(struct bt_mesh_model *mod) return 0; } -static void priv_beacon_srv_reset(struct bt_mesh_model *model) +static void priv_beacon_srv_reset(const struct bt_mesh_model *model) { (void)memset(&priv_beacon_state, 0, sizeof(priv_beacon_state)); priv_beacon_store(true); } #ifdef CONFIG_BT_SETTINGS -static int priv_beacon_srv_settings_set(struct bt_mesh_model *model, const char *name, +static int priv_beacon_srv_settings_set(const struct bt_mesh_model *model, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_data) { int err; @@ -236,7 +236,7 @@ static int priv_beacon_srv_settings_set(struct bt_mesh_model *model, const char return 0; } -static void priv_beacon_srv_pending_store(struct bt_mesh_model *model) +static void priv_beacon_srv_pending_store(const struct bt_mesh_model *model) { priv_beacon_state.state = bt_mesh_priv_beacon_get(); priv_beacon_state.interval = bt_mesh_priv_beacon_update_interval_get(); diff --git a/subsys/bluetooth/mesh/rpr_cli.c b/subsys/bluetooth/mesh/rpr_cli.c index 3ebd3afcd6a1a01..7a1dd493b875dfe 100644 --- a/subsys/bluetooth/mesh/rpr_cli.c +++ b/subsys/bluetooth/mesh/rpr_cli.c @@ -90,11 +90,11 @@ static void tx_complete(struct bt_mesh_rpr_cli *cli, int err, void *cb_data) } } -static int handle_extended_scan_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_extended_scan_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_rpr_node srv = RPR_NODE(ctx); - struct bt_mesh_rpr_cli *cli = mod->user_data; + struct bt_mesh_rpr_cli *cli = *(mod->user_data); struct bt_mesh_rpr_unprov dev = { 0 }; enum bt_mesh_rpr_status status; bool found_dev = false; @@ -123,11 +123,11 @@ static int handle_extended_scan_report(struct bt_mesh_model *mod, struct bt_mesh return 0; } -static int handle_link_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_link_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_rpr_node srv = RPR_NODE(ctx); - struct bt_mesh_rpr_cli *cli = mod->user_data; + struct bt_mesh_rpr_cli *cli = *(mod->user_data); struct bt_mesh_rpr_link link; uint8_t reason = PROV_BEARER_LINK_STATUS_SUCCESS; @@ -161,10 +161,10 @@ static int handle_link_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_link_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_link_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = mod->user_data; + struct bt_mesh_rpr_cli *cli = *(mod->user_data); struct bt_mesh_rpr_node srv = RPR_NODE(ctx); struct bt_mesh_rpr_link *rsp; struct bt_mesh_rpr_link link; @@ -195,10 +195,10 @@ static int handle_link_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_pdu_outbound_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_pdu_outbound_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = mod->user_data; + struct bt_mesh_rpr_cli *cli = *(mod->user_data); struct bt_mesh_rpr_node srv = RPR_NODE(ctx); void *cb_data; uint8_t num; @@ -226,10 +226,10 @@ static int handle_pdu_outbound_report(struct bt_mesh_model *mod, struct bt_mesh_ return 0; } -static int handle_pdu_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_pdu_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = mod->user_data; + struct bt_mesh_rpr_cli *cli = *(mod->user_data); struct bt_mesh_rpr_node srv = RPR_NODE(ctx); struct pb_remote_ctx cb_ctx = { cli, @@ -257,10 +257,10 @@ static int handle_pdu_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx * return 0; } -static int handle_scan_caps_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_scan_caps_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = mod->user_data; + struct bt_mesh_rpr_cli *cli = *(mod->user_data); struct bt_mesh_rpr_node srv = RPR_NODE(ctx); struct bt_mesh_rpr_caps *caps; @@ -281,10 +281,10 @@ static int handle_scan_caps_status(struct bt_mesh_model *mod, struct bt_mesh_msg return 0; } -static int handle_scan_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_scan_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = mod->user_data; + struct bt_mesh_rpr_cli *cli = *(mod->user_data); struct bt_mesh_rpr_node srv = RPR_NODE(ctx); struct bt_mesh_rpr_unprov dev = { 0 }; @@ -313,10 +313,10 @@ static int handle_scan_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx return 0; } -static int handle_scan_status(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_scan_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = mod->user_data; + struct bt_mesh_rpr_cli *cli = *(mod->user_data); struct bt_mesh_rpr_scan_status *status; struct bt_mesh_rpr_node srv = RPR_NODE(ctx); @@ -361,15 +361,15 @@ static void link_timeout(struct k_work *work) } } -static int rpr_cli_init(struct bt_mesh_model *mod) +static int rpr_cli_init(const struct bt_mesh_model *mod) { - if (mod->elem_idx) { + if (*(mod->elem_idx)) { LOG_ERR("Remote provisioning client must be initialized " "on first element"); return -EINVAL; } - struct bt_mesh_rpr_cli *cli = mod->user_data; + struct bt_mesh_rpr_cli *cli = *(mod->user_data); cli->mod = mod; cli->link.time = LINK_TIMEOUT_SECONDS_DEFAULT; @@ -378,7 +378,7 @@ static int rpr_cli_init(struct bt_mesh_model *mod) bt_mesh_msg_ack_ctx_init(&cli->prov_ack_ctx); k_work_init_delayable(&cli->link.timeout, link_timeout); mod->keys[0] = BT_MESH_KEY_DEV_ANY; - mod->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } diff --git a/subsys/bluetooth/mesh/rpr_srv.c b/subsys/bluetooth/mesh/rpr_srv.c index fb2b57fad2e4141..e008aa0a8b13fcf 100644 --- a/subsys/bluetooth/mesh/rpr_srv.c +++ b/subsys/bluetooth/mesh/rpr_srv.c @@ -47,7 +47,7 @@ enum { /** Remote provisioning server instance. */ static struct { - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; ATOMIC_DEFINE(flags, RPR_SRV_NUM_FLAGS); @@ -536,7 +536,7 @@ static const struct prov_bearer_cb prov_bearer_cb = { * Message handlers ******************************************************************************/ -static int handle_scan_caps_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_scan_caps_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { BT_MESH_MODEL_BUF_DEFINE(rsp, RPR_OP_SCAN_CAPS_STATUS, 2); @@ -549,7 +549,7 @@ static int handle_scan_caps_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ct return 0; } -static int handle_scan_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_scan_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { scan_status_send(ctx, BT_MESH_RPR_SUCCESS); @@ -557,7 +557,7 @@ static int handle_scan_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ct return 0; } -static int handle_scan_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_scan_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_rpr_node cli = RPR_NODE(ctx); @@ -621,7 +621,7 @@ static int handle_scan_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx * return 0; } -static int handle_extended_scan_start(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_extended_scan_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { BT_MESH_MODEL_BUF_DEFINE(rsp, RPR_OP_EXTENDED_SCAN_REPORT, @@ -784,7 +784,7 @@ static int handle_extended_scan_start(struct bt_mesh_model *mod, struct bt_mesh_ return 0; } -static int handle_scan_stop(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_scan_stop(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { if (atomic_test_bit(srv.flags, SCANNING)) { @@ -797,7 +797,7 @@ static int handle_scan_stop(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *c return 0; } -static int handle_link_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_link_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_DBG(""); @@ -807,7 +807,7 @@ static int handle_link_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ct return 0; } -static int handle_link_open(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_link_open(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { bool is_refresh_procedure = (buf->len == 1); @@ -938,7 +938,7 @@ static int handle_link_open(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *c return 0; } -static int handle_link_close(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_link_close(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_rpr_node cli = RPR_NODE(ctx); @@ -975,7 +975,7 @@ static int handle_link_close(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx * return 0; } -static int handle_pdu_send(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int handle_pdu_send(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_rpr_node cli = RPR_NODE(ctx); @@ -1303,9 +1303,9 @@ static struct bt_le_scan_cb scan_cb = { .recv = scan_packet_recv, }; -static int rpr_srv_init(struct bt_mesh_model *mod) +static int rpr_srv_init(const struct bt_mesh_model *mod) { - if (mod->elem_idx || srv.mod) { + if (*(mod->elem_idx) || srv.mod) { LOG_ERR("Remote provisioning server must be initialized " "on first element"); return -EINVAL; @@ -1320,12 +1320,12 @@ static int rpr_srv_init(struct bt_mesh_model *mod) k_work_init(&srv.link.report, link_report_send_and_clear); bt_le_scan_cb_register(&scan_cb); mod->keys[0] = BT_MESH_KEY_DEV_LOCAL; - mod->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } -static void rpr_srv_reset(struct bt_mesh_model *mod) +static void rpr_srv_reset(const struct bt_mesh_model *mod) { cli_link_clear(); cli_scan_clear(); diff --git a/subsys/bluetooth/mesh/sar_cfg_cli.c b/subsys/bluetooth/mesh/sar_cfg_cli.c index b5a33b975e5ec31..aaf07451e1d7709 100644 --- a/subsys/bluetooth/mesh/sar_cfg_cli.c +++ b/subsys/bluetooth/mesh/sar_cfg_cli.c @@ -21,7 +21,7 @@ LOG_MODULE_REGISTER(bt_mesh_sar_cfg_cli); static struct bt_mesh_sar_cfg_cli *cli; -static int transmitter_status(struct bt_mesh_model *model, +static int transmitter_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -45,7 +45,7 @@ static int transmitter_status(struct bt_mesh_model *model, return 0; } -static int receiver_status(struct bt_mesh_model *model, +static int receiver_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -87,35 +87,35 @@ void bt_mesh_sar_cfg_cli_timeout_set(int32_t timeout) cli->timeout = timeout; } -static int bt_mesh_sar_cfg_cli_init(struct bt_mesh_model *model) +static int bt_mesh_sar_cfg_cli_init(const struct bt_mesh_model *model) { if (!bt_mesh_model_in_primary(model)) { LOG_ERR("SAR Configuration Client only allowed in primary element"); return -EINVAL; } - if (!model->user_data) { + if (!*(model->user_data)) { LOG_ERR("No SAR Configuration Client context provided"); return -EINVAL; } - cli = model->user_data; + cli = *(model->user_data); cli->model = model; cli->timeout = 2 * MSEC_PER_SEC; model->keys[0] = BT_MESH_KEY_DEV_ANY; - model->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); return 0; } -static void bt_mesh_sar_cfg_cli_reset(struct bt_mesh_model *model) +static void bt_mesh_sar_cfg_cli_reset(const struct bt_mesh_model *model) { struct bt_mesh_sar_cfg_cli *model_cli; - model_cli = model->user_data; + model_cli = *(model->user_data); bt_mesh_msg_ack_ctx_clear(&model_cli->ack_ctx); } diff --git a/subsys/bluetooth/mesh/sar_cfg_srv.c b/subsys/bluetooth/mesh/sar_cfg_srv.c index e05489ee0cfd735..59ec36907c59550 100644 --- a/subsys/bluetooth/mesh/sar_cfg_srv.c +++ b/subsys/bluetooth/mesh/sar_cfg_srv.c @@ -27,7 +27,7 @@ #include LOG_MODULE_REGISTER(bt_mesh_sar_cfg_srv); -static int sar_rx_store(struct bt_mesh_model *model, bool delete) +static int sar_rx_store(const struct bt_mesh_model *model, bool delete) { const void *data = delete ? NULL : &bt_mesh.sar_rx; size_t len = delete ? 0 : sizeof(struct bt_mesh_sar_rx); @@ -35,7 +35,7 @@ static int sar_rx_store(struct bt_mesh_model *model, bool delete) return bt_mesh_model_data_store(model, false, "sar_rx", data, len); } -static int sar_tx_store(struct bt_mesh_model *model, bool delete) +static int sar_tx_store(const struct bt_mesh_model *model, bool delete) { const void *data = delete ? NULL : &bt_mesh.sar_tx; size_t len = delete ? 0 : sizeof(struct bt_mesh_sar_tx); @@ -43,7 +43,7 @@ static int sar_tx_store(struct bt_mesh_model *model, bool delete) return bt_mesh_model_data_store(model, false, "sar_tx", data, len); } -static void transmitter_status(struct bt_mesh_model *model, +static void transmitter_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { BT_MESH_MODEL_BUF_DEFINE(msg, OP_SAR_CFG_TX_STATUS, BT_MESH_SAR_TX_LEN); @@ -63,7 +63,7 @@ static void transmitter_status(struct bt_mesh_model *model, } } -static void receiver_status(struct bt_mesh_model *model, +static void receiver_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { BT_MESH_MODEL_BUF_DEFINE(msg, OP_SAR_CFG_RX_STATUS, BT_MESH_SAR_RX_LEN); @@ -81,7 +81,7 @@ static void receiver_status(struct bt_mesh_model *model, } } -static int transmitter_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int transmitter_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_DBG("src 0x%04x", ctx->addr); @@ -91,7 +91,7 @@ static int transmitter_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx * return 0; } -static int transmitter_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int transmitter_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_sar_tx *tx = &bt_mesh.sar_tx; @@ -108,7 +108,7 @@ static int transmitter_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx * return 0; } -static int receiver_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int receiver_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_DBG("src 0x%04x", ctx->addr); @@ -118,7 +118,7 @@ static int receiver_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx return 0; } -static int receiver_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int receiver_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct bt_mesh_sar_rx *rx = &bt_mesh.sar_rx; @@ -143,7 +143,7 @@ const struct bt_mesh_model_op bt_mesh_sar_cfg_srv_op[] = { BT_MESH_MODEL_OP_END, }; -static int sar_cfg_srv_init(struct bt_mesh_model *model) +static int sar_cfg_srv_init(const struct bt_mesh_model *model) { if (!bt_mesh_model_in_primary(model)) { LOG_ERR("Configuration Server only allowed in primary element"); @@ -155,12 +155,12 @@ static int sar_cfg_srv_init(struct bt_mesh_model *model) * device-key is allowed to access this model. */ model->keys[0] = BT_MESH_KEY_DEV_LOCAL; - model->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } -static void sar_cfg_srv_reset(struct bt_mesh_model *model) +static void sar_cfg_srv_reset(const struct bt_mesh_model *model) { struct bt_mesh_sar_tx sar_tx = BT_MESH_SAR_TX_INIT; struct bt_mesh_sar_rx sar_rx = BT_MESH_SAR_RX_INIT; @@ -175,8 +175,9 @@ static void sar_cfg_srv_reset(struct bt_mesh_model *model) } #ifdef CONFIG_BT_SETTINGS -static int sar_cfg_srv_settings_set(struct bt_mesh_model *model, const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_data) +static int sar_cfg_srv_settings_set(const struct bt_mesh_model *model, const char *name, + size_t len_rd, settings_read_cb read_cb, + void *cb_data) { if (!strncmp(name, "sar_rx", 5)) { return bt_mesh_settings_set(read_cb, cb_data, &bt_mesh.sar_rx, diff --git a/subsys/bluetooth/mesh/shell/blob.c b/subsys/bluetooth/mesh/shell/blob.c index a3ecdee241e9543..ed0f4fbd4584e6d 100644 --- a/subsys/bluetooth/mesh/shell/blob.c +++ b/subsys/bluetooth/mesh/shell/blob.c @@ -271,7 +271,7 @@ static int cmd_flash_stream_unset(const struct shell *sh, size_t argc, char *arg #if defined(CONFIG_BT_MESH_SHELL_BLOB_CLI) -static struct bt_mesh_model *mod_cli; +static const struct bt_mesh_model *mod_cli; static void blob_cli_inputs_prepare(uint16_t group) { @@ -351,7 +351,7 @@ static int cmd_tx(const struct shell *sh, size_t argc, char *argv[]) "pull", blob_cli_xfer.xfer.size, group); - err = bt_mesh_blob_cli_send((struct bt_mesh_blob_cli *)mod_cli->user_data, + err = bt_mesh_blob_cli_send((struct bt_mesh_blob_cli *)*(mod_cli->user_data), &blob_cli_xfer.inputs, &blob_cli_xfer.xfer, bt_mesh_shell_blob_io); if (err) { @@ -421,7 +421,7 @@ static int cmd_caps(const struct shell *sh, size_t argc, char *argv[]) blob_cli_inputs_prepare(group); - err = bt_mesh_blob_cli_caps_get((struct bt_mesh_blob_cli *)mod_cli->user_data, + err = bt_mesh_blob_cli_caps_get((struct bt_mesh_blob_cli *)*(mod_cli->user_data), &blob_cli_xfer.inputs); if (err) { shell_print(sh, "Boundary check start failed (err: %d)", err); @@ -438,7 +438,7 @@ static int cmd_tx_cancel(const struct shell *sh, size_t argc, } shell_print(sh, "Cancelling transfer"); - bt_mesh_blob_cli_cancel((struct bt_mesh_blob_cli *)mod_cli->user_data); + bt_mesh_blob_cli_cancel((struct bt_mesh_blob_cli *)*(mod_cli->user_data)); return 0; } @@ -465,7 +465,7 @@ static int cmd_tx_get(const struct shell *sh, size_t argc, char *argv[]) blob_cli_inputs_prepare(group); - err = bt_mesh_blob_cli_xfer_progress_get((struct bt_mesh_blob_cli *)mod_cli->user_data, + err = bt_mesh_blob_cli_xfer_progress_get((struct bt_mesh_blob_cli *)*(mod_cli->user_data), &blob_cli_xfer.inputs); if (err) { shell_print(sh, "ERR %d", err); @@ -482,7 +482,7 @@ static int cmd_tx_suspend(const struct shell *sh, size_t argc, } shell_print(sh, "Suspending transfer"); - bt_mesh_blob_cli_suspend((struct bt_mesh_blob_cli *)mod_cli->user_data); + bt_mesh_blob_cli_suspend((struct bt_mesh_blob_cli *)*(mod_cli->user_data)); return 0; } @@ -494,7 +494,7 @@ static int cmd_tx_resume(const struct shell *sh, size_t argc, char *argv[]) } shell_print(sh, "Resuming transfer"); - bt_mesh_blob_cli_resume((struct bt_mesh_blob_cli *)mod_cli->user_data); + bt_mesh_blob_cli_resume((struct bt_mesh_blob_cli *)*(mod_cli->user_data)); return 0; } @@ -503,7 +503,7 @@ static int cmd_tx_resume(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_BT_MESH_SHELL_BLOB_SRV) -static struct bt_mesh_model *mod_srv; +static const struct bt_mesh_model *mod_srv; static int cmd_rx(const struct shell *sh, size_t argc, char *argv[]) { @@ -530,7 +530,7 @@ static int cmd_rx(const struct shell *sh, size_t argc, char *argv[]) } shell_print(sh, "Receive BLOB 0x%x", id); - err = bt_mesh_blob_srv_recv((struct bt_mesh_blob_srv *)mod_srv->user_data, + err = bt_mesh_blob_srv_recv((struct bt_mesh_blob_srv *)*(mod_srv->user_data), id, bt_mesh_shell_blob_io, BT_MESH_TTL_MAX, timeout_base); if (err) { shell_print(sh, "BLOB RX setup failed (%d)", err); @@ -548,7 +548,7 @@ static int cmd_rx_cancel(const struct shell *sh, size_t argc, char *argv[]) } shell_print(sh, "Cancelling BLOB rx"); - err = bt_mesh_blob_srv_cancel((struct bt_mesh_blob_srv *)mod_srv->user_data); + err = bt_mesh_blob_srv_cancel((struct bt_mesh_blob_srv *)*(mod_srv->user_data)); if (err) { shell_print(sh, "BLOB cancel failed (%d)", err); } diff --git a/subsys/bluetooth/mesh/shell/dfd.c b/subsys/bluetooth/mesh/shell/dfd.c index 0415929dfec44b6..464a5340342b244 100644 --- a/subsys/bluetooth/mesh/shell/dfd.c +++ b/subsys/bluetooth/mesh/shell/dfd.c @@ -14,7 +14,7 @@ #include "../dfd_srv_internal.h" #include "../access.h" -static struct bt_mesh_model *mod; +static const struct bt_mesh_model *mod; static void print_receivers_status(const struct shell *sh, struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_status status) @@ -70,7 +70,7 @@ static int cmd_dfd_receivers_add(const struct shell *sh, size_t argc, char *argv return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); if (bt_mesh_dfu_cli_is_busy(&dfd_srv->dfu)) { print_receivers_status(sh, dfd_srv, @@ -122,7 +122,7 @@ static int cmd_dfd_receivers_delete_all(const struct shell *sh, size_t argc, cha return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_receivers_delete_all( dfd_srv); @@ -142,7 +142,7 @@ static int cmd_dfd_receivers_get(const struct shell *sh, size_t argc, char *argv return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); int err = 0; uint16_t first = shell_strtoul(argv[1], 0, &err); @@ -197,7 +197,7 @@ static int cmd_dfd_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); print_dfd_status(sh, dfd_srv, BT_MESH_DFD_SUCCESS); @@ -210,7 +210,7 @@ static int cmd_dfd_start(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); struct bt_mesh_dfd_start_params params; int err = 0; @@ -267,7 +267,7 @@ static int cmd_dfd_suspend(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_suspend(dfd_srv); @@ -285,7 +285,7 @@ static int cmd_dfd_cancel(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_cancel(dfd_srv, NULL); @@ -303,7 +303,7 @@ static int cmd_dfd_apply(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_apply(dfd_srv); @@ -364,7 +364,7 @@ static int cmd_dfd_fw_delete(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); uint8_t fwid_buf[CONFIG_BT_MESH_DFU_FWID_MAXLEN]; size_t hexlen = strlen(argv[1]); @@ -394,7 +394,7 @@ static int cmd_dfd_fw_delete_all(const struct shell *sh, size_t argc, char *argv return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = mod->user_data; + struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_fw_delete_all(dfd_srv); diff --git a/subsys/bluetooth/mesh/shell/dfu.c b/subsys/bluetooth/mesh/shell/dfu.c index 8d7fc96e0141afd..22c60dc17c88b1b 100644 --- a/subsys/bluetooth/mesh/shell/dfu.c +++ b/subsys/bluetooth/mesh/shell/dfu.c @@ -505,7 +505,7 @@ static int cmd_dfu_slot_get(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_BT_MESH_SHELL_DFU_CLI) -static struct bt_mesh_model *mod_cli; +static const struct bt_mesh_model *mod_cli; static struct { struct bt_mesh_dfu_target targets[32]; @@ -587,7 +587,7 @@ static int cmd_dfu_target_state(const struct shell *sh, size_t argc, char *argv[ return -ENODEV; } - err = bt_mesh_dfu_cli_status_get((struct bt_mesh_dfu_cli *)mod_cli->user_data, + err = bt_mesh_dfu_cli_status_get((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), &ctx, &rsp); if (err) { shell_print(sh, "Failed getting target status (err: %d)", @@ -654,7 +654,7 @@ static int cmd_dfu_target_imgs(const struct shell *sh, size_t argc, char *argv[] shell_print(sh, "Requesting DFU images in 0x%04x", bt_mesh_shell_target_ctx.dst); - err = bt_mesh_dfu_cli_imgs_get((struct bt_mesh_dfu_cli *)mod_cli->user_data, + err = bt_mesh_dfu_cli_imgs_get((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), &ctx, dfu_img_cb, NULL, img_cnt); if (err) { shell_print(sh, "Request failed (err: %d)", err); @@ -694,7 +694,7 @@ static int cmd_dfu_target_check(const struct shell *sh, size_t argc, char *argv[ return 0; } - err = bt_mesh_dfu_cli_metadata_check((struct bt_mesh_dfu_cli *)mod_cli->user_data, + err = bt_mesh_dfu_cli_metadata_check((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), &ctx, img_idx, slot, &rsp); if (err) { shell_print(sh, "Metadata check failed. err: %d", err); @@ -765,7 +765,7 @@ static int cmd_dfu_send(const struct shell *sh, size_t argc, char *argv[]) dfu_tx.inputs.app_idx = bt_mesh_shell_target_ctx.app_idx; dfu_tx.inputs.ttl = BT_MESH_TTL_DEFAULT; - err = bt_mesh_dfu_cli_send((struct bt_mesh_dfu_cli *)mod_cli->user_data, + err = bt_mesh_dfu_cli_send((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), &dfu_tx.inputs, bt_mesh_shell_blob_io, &xfer); if (err) { shell_print(sh, "Failed (err: %d)", err); @@ -800,7 +800,7 @@ static int cmd_dfu_tx_cancel(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Cancelling DFU"); } - err = bt_mesh_dfu_cli_cancel((struct bt_mesh_dfu_cli *)mod_cli->user_data, + err = bt_mesh_dfu_cli_cancel((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), (argc == 2) ? &ctx : NULL); if (err) { shell_print(sh, "Failed (err: %d)", err); @@ -819,7 +819,7 @@ static int cmd_dfu_apply(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Applying DFU"); - err = bt_mesh_dfu_cli_apply((struct bt_mesh_dfu_cli *)mod_cli->user_data); + err = bt_mesh_dfu_cli_apply((struct bt_mesh_dfu_cli *)*(mod_cli->user_data)); if (err) { shell_print(sh, "Failed (err: %d)", err); } @@ -837,7 +837,7 @@ static int cmd_dfu_confirm(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Confirming DFU"); - err = bt_mesh_dfu_cli_confirm((struct bt_mesh_dfu_cli *)mod_cli->user_data); + err = bt_mesh_dfu_cli_confirm((struct bt_mesh_dfu_cli *)*(mod_cli->user_data)); if (err) { shell_print(sh, "Failed (err: %d)", err); } @@ -855,7 +855,7 @@ static int cmd_dfu_suspend(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Suspending DFU"); - err = bt_mesh_dfu_cli_suspend((struct bt_mesh_dfu_cli *)mod_cli->user_data); + err = bt_mesh_dfu_cli_suspend((struct bt_mesh_dfu_cli *)*(mod_cli->user_data)); if (err) { shell_print(sh, "Failed (err: %d)", err); } @@ -873,7 +873,7 @@ static int cmd_dfu_resume(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Resuming DFU"); - err = bt_mesh_dfu_cli_resume((struct bt_mesh_dfu_cli *)mod_cli->user_data); + err = bt_mesh_dfu_cli_resume((struct bt_mesh_dfu_cli *)*(mod_cli->user_data)); if (err) { shell_print(sh, "Failed (err: %d)", err); } @@ -888,7 +888,7 @@ static int cmd_dfu_tx_progress(const struct shell *sh, size_t argc, char *argv[] } shell_print(sh, "DFU progress: %u %%", - bt_mesh_dfu_cli_progress((struct bt_mesh_dfu_cli *)mod_cli->user_data)); + bt_mesh_dfu_cli_progress((struct bt_mesh_dfu_cli *)*(mod_cli->user_data))); return 0; } @@ -896,7 +896,7 @@ static int cmd_dfu_tx_progress(const struct shell *sh, size_t argc, char *argv[] #if defined(CONFIG_BT_MESH_SHELL_DFU_SRV) -static struct bt_mesh_model *mod_srv; +static const struct bt_mesh_model *mod_srv; static int cmd_dfu_applied(const struct shell *sh, size_t argc, char *argv[]) { @@ -904,7 +904,7 @@ static int cmd_dfu_applied(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - bt_mesh_dfu_srv_applied((struct bt_mesh_dfu_srv *)mod_srv->user_data); + bt_mesh_dfu_srv_applied((struct bt_mesh_dfu_srv *)*(mod_srv->user_data)); return 0; } @@ -914,7 +914,7 @@ static int cmd_dfu_rx_cancel(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - bt_mesh_dfu_srv_cancel((struct bt_mesh_dfu_srv *)mod_srv->user_data); + bt_mesh_dfu_srv_cancel((struct bt_mesh_dfu_srv *)*(mod_srv->user_data)); return 0; } @@ -925,7 +925,7 @@ static int cmd_dfu_rx_progress(const struct shell *sh, size_t argc, char *argv[] } shell_print(sh, "DFU progress: %u %%", - bt_mesh_dfu_srv_progress((struct bt_mesh_dfu_srv *)mod_srv->user_data)); + bt_mesh_dfu_srv_progress((struct bt_mesh_dfu_srv *)*(mod_srv->user_data))); return 0; } diff --git a/subsys/bluetooth/mesh/shell/health.c b/subsys/bluetooth/mesh/shell/health.c index efc7eb84e62dd83..a0ca150ae152e81 100644 --- a/subsys/bluetooth/mesh/shell/health.c +++ b/subsys/bluetooth/mesh/shell/health.c @@ -13,7 +13,7 @@ #include "utils.h" #include -static struct bt_mesh_model *mod; +static const struct bt_mesh_model *mod; static void show_faults(const struct shell *sh, uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) @@ -40,7 +40,7 @@ static int cmd_fault_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_health_cli *cli = mod->user_data; + struct bt_mesh_health_cli *cli = *(mod->user_data); struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t faults[32]; @@ -74,7 +74,7 @@ static int fault_clear(const struct shell *sh, size_t argc, char *argv[], bool a return -ENODEV; } - struct bt_mesh_health_cli *cli = mod->user_data; + struct bt_mesh_health_cli *cli = *(mod->user_data); struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t test_id; @@ -126,7 +126,7 @@ static int fault_test(const struct shell *sh, size_t argc, char *argv[], bool ac return -ENODEV; } - struct bt_mesh_health_cli *cli = mod->user_data; + struct bt_mesh_health_cli *cli = *(mod->user_data); struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t test_id; @@ -179,7 +179,7 @@ static int cmd_period_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_health_cli *cli = mod->user_data; + struct bt_mesh_health_cli *cli = *(mod->user_data); struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t divisor; @@ -201,7 +201,7 @@ static int period_set(const struct shell *sh, size_t argc, char *argv[], bool ac return -ENODEV; } - struct bt_mesh_health_cli *cli = mod->user_data; + struct bt_mesh_health_cli *cli = *(mod->user_data); struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t divisor; @@ -251,7 +251,7 @@ static int cmd_attention_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_health_cli *cli = mod->user_data; + struct bt_mesh_health_cli *cli = *(mod->user_data); struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t attention; @@ -273,7 +273,7 @@ static int attention_set(const struct shell *sh, size_t argc, char *argv[], bool return -ENODEV; } - struct bt_mesh_health_cli *cli = mod->user_data; + struct bt_mesh_health_cli *cli = *(mod->user_data); struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t attention; diff --git a/subsys/bluetooth/mesh/shell/rpr.c b/subsys/bluetooth/mesh/shell/rpr.c index c8f0581710486fc..1ddb11f497dc8e2 100644 --- a/subsys/bluetooth/mesh/shell/rpr.c +++ b/subsys/bluetooth/mesh/shell/rpr.c @@ -11,7 +11,7 @@ #include "utils.h" -static struct bt_mesh_model *mod; +static const struct bt_mesh_model *mod; /*************************************************************************************************** * Implementation of the model's instance @@ -108,7 +108,7 @@ static int cmd_scan(const struct shell *sh, size_t argc, char *argv[]) hex2bin(argv[2], strlen(argv[2]), uuid, 16); } - err = bt_mesh_rpr_scan_start((struct bt_mesh_rpr_cli *)mod->user_data, + err = bt_mesh_rpr_scan_start((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, argc > 2 ? uuid : NULL, timeout, BT_MESH_RPR_SCAN_MAX_DEVS_ANY, &rsp); if (err) { @@ -153,7 +153,7 @@ static int cmd_scan_ext(const struct shell *sh, size_t argc, char *argv[]) return err; } - err = bt_mesh_rpr_scan_start_ext((struct bt_mesh_rpr_cli *)mod->user_data, + err = bt_mesh_rpr_scan_start_ext((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, uuid, timeout, ad_types, (argc - 3)); if (err) { @@ -189,7 +189,7 @@ static int cmd_scan_srv(const struct shell *sh, size_t argc, char *argv[]) return err; } - err = bt_mesh_rpr_scan_start_ext((struct bt_mesh_rpr_cli *)mod->user_data, + err = bt_mesh_rpr_scan_start_ext((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, NULL, 0, ad_types, (argc - 1)); if (err) { shell_print(sh, "Scan start failed: %d", err); @@ -213,7 +213,7 @@ static int cmd_scan_caps(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - err = bt_mesh_rpr_scan_caps_get((struct bt_mesh_rpr_cli *)mod->user_data, &srv, &caps); + err = bt_mesh_rpr_scan_caps_get((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &caps); if (err) { shell_print(sh, "Scan capabilities get failed: %d", err); return err; @@ -241,7 +241,7 @@ static int cmd_scan_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - err = bt_mesh_rpr_scan_get((struct bt_mesh_rpr_cli *)mod->user_data, &srv, &rsp); + err = bt_mesh_rpr_scan_get((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &rsp); if (err) { shell_print(sh, "Scan get failed: %d", err); return err; @@ -269,7 +269,7 @@ static int cmd_scan_stop(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - err = bt_mesh_rpr_scan_stop((struct bt_mesh_rpr_cli *)mod->user_data, &srv, &rsp); + err = bt_mesh_rpr_scan_stop((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &rsp); if (err || rsp.status) { shell_print(sh, "Scan stop failed: %d %u", err, rsp.status); return err; @@ -294,7 +294,7 @@ static int cmd_link_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - err = bt_mesh_rpr_link_get((struct bt_mesh_rpr_cli *)mod->user_data, &srv, &rsp); + err = bt_mesh_rpr_link_get((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &rsp); if (err) { shell_print(sh, "Link get failed: %d %u", err, rsp.status); return err; @@ -316,7 +316,7 @@ static int cmd_link_close(const struct shell *sh, size_t argc, char *argv[]) }; int err; - err = bt_mesh_rpr_link_close((struct bt_mesh_rpr_cli *)mod->user_data, &srv, &rsp); + err = bt_mesh_rpr_link_close((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &rsp); if (err) { shell_print(sh, "Link close failed: %d %u", err, rsp.status); return err; @@ -355,7 +355,7 @@ static int cmd_provision_remote(const struct shell *sh, size_t argc, char *argv[ return err; } - err = bt_mesh_provision_remote((struct bt_mesh_rpr_cli *)mod->user_data, + err = bt_mesh_provision_remote((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, uuid, net_idx, addr); if (err) { shell_print(sh, "Prov remote start failed: %d", err); @@ -396,7 +396,7 @@ static int cmd_reprovision_remote(const struct shell *sh, size_t argc, char *arg return err; } - err = bt_mesh_reprovision_remote((struct bt_mesh_rpr_cli *)mod->user_data, + err = bt_mesh_reprovision_remote((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, addr, composition_changed); if (err) { shell_print(sh, "Reprovisioning failed: %d", err); diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index c1bad5d24adb181..3a28829877b6720 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -68,7 +68,7 @@ static void get_faults(uint8_t *faults, uint8_t faults_size, uint8_t *dst, uint8 } } -static int fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, +static int fault_get_cur(const struct bt_mesh_model *model, uint8_t *test_id, uint16_t *company_id, uint8_t *faults, uint8_t *fault_count) { shell_print_ctx("Sending current faults"); @@ -81,7 +81,7 @@ static int fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, return 0; } -static int fault_get_reg(struct bt_mesh_model *model, uint16_t cid, +static int fault_get_reg(const struct bt_mesh_model *model, uint16_t cid, uint8_t *test_id, uint8_t *faults, uint8_t *fault_count) { if (cid != CONFIG_BT_COMPANY_ID) { @@ -99,7 +99,7 @@ static int fault_get_reg(struct bt_mesh_model *model, uint16_t cid, return 0; } -static int fault_clear(struct bt_mesh_model *model, uint16_t cid) +static int fault_clear(const struct bt_mesh_model *model, uint16_t cid) { if (cid != CONFIG_BT_COMPANY_ID) { return -EINVAL; @@ -110,7 +110,7 @@ static int fault_clear(struct bt_mesh_model *model, uint16_t cid) return 0; } -static int fault_test(struct bt_mesh_model *model, uint8_t test_id, +static int fault_test(const struct bt_mesh_model *model, uint8_t test_id, uint16_t cid) { if (cid != CONFIG_BT_COMPANY_ID) { @@ -124,12 +124,12 @@ static int fault_test(struct bt_mesh_model *model, uint8_t test_id, return 0; } -static void attention_on(struct bt_mesh_model *model) +static void attention_on(const struct bt_mesh_model *model) { shell_print_ctx("Attention On"); } -static void attention_off(struct bt_mesh_model *model) +static void attention_off(const struct bt_mesh_model *model) { shell_print_ctx("Attention Off"); } diff --git a/subsys/bluetooth/mesh/shell/utils.c b/subsys/bluetooth/mesh/shell/utils.c index 8b7ca7406631461..1d8ab79951de769 100644 --- a/subsys/bluetooth/mesh/shell/utils.c +++ b/subsys/bluetooth/mesh/shell/utils.c @@ -13,7 +13,7 @@ #include "mesh/access.h" #include "utils.h" -bool bt_mesh_shell_mdl_first_get(uint16_t id, struct bt_mesh_model **mod) +bool bt_mesh_shell_mdl_first_get(uint16_t id, const struct bt_mesh_model **mod) { const struct bt_mesh_comp *comp = bt_mesh_comp_get(); @@ -27,10 +27,10 @@ bool bt_mesh_shell_mdl_first_get(uint16_t id, struct bt_mesh_model **mod) return false; } -int bt_mesh_shell_mdl_instance_set(const struct shell *sh, struct bt_mesh_model **mod, +int bt_mesh_shell_mdl_instance_set(const struct shell *sh, const struct bt_mesh_model **mod, uint16_t mod_id, uint8_t elem_idx) { - struct bt_mesh_model *mod_temp; + const struct bt_mesh_model *mod_temp; const struct bt_mesh_comp *comp = bt_mesh_comp_get(); if (elem_idx >= comp->elem_count) { @@ -53,14 +53,14 @@ int bt_mesh_shell_mdl_instance_set(const struct shell *sh, struct bt_mesh_model int bt_mesh_shell_mdl_print_all(const struct shell *sh, uint16_t mod_id) { const struct bt_mesh_comp *comp = bt_mesh_comp_get(); - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; for (int i = 0; i < comp->elem_count; i++) { mod = bt_mesh_model_find(&comp->elem[i], mod_id); if (mod) { shell_print(sh, "Client model instance found at addr 0x%.4X. Element index: %d", - comp->elem[i].addr, mod->elem_idx); + comp->elem[i].addr, *(mod->elem_idx)); } } diff --git a/subsys/bluetooth/mesh/shell/utils.h b/subsys/bluetooth/mesh/shell/utils.h index 222f1f2936001b5..83d025d47ea97d3 100644 --- a/subsys/bluetooth/mesh/shell/utils.h +++ b/subsys/bluetooth/mesh/shell/utils.h @@ -34,9 +34,9 @@ 0), \ SHELL_SUBCMD_SET_END); -bool bt_mesh_shell_mdl_first_get(uint16_t id, struct bt_mesh_model **mod); +bool bt_mesh_shell_mdl_first_get(uint16_t id, const struct bt_mesh_model **mod); -int bt_mesh_shell_mdl_instance_set(const struct shell *sh, struct bt_mesh_model **mod, +int bt_mesh_shell_mdl_instance_set(const struct shell *sh, const struct bt_mesh_model **mod, uint16_t mod_id, uint8_t elem_idx); int bt_mesh_shell_mdl_print_all(const struct shell *sh, uint16_t mod_id); diff --git a/subsys/bluetooth/mesh/sol_pdu_rpl_cli.c b/subsys/bluetooth/mesh/sol_pdu_rpl_cli.c index 3b8f6799b28f344..05457eff3387045 100644 --- a/subsys/bluetooth/mesh/sol_pdu_rpl_cli.c +++ b/subsys/bluetooth/mesh/sol_pdu_rpl_cli.c @@ -22,7 +22,7 @@ struct sol_rpl_param { uint8_t *len; }; -static int handle_status(struct bt_mesh_model *mod, +static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -160,7 +160,7 @@ void bt_mesh_sol_pdu_rpl_cli_timeout_set(int32_t timeout) msg_timeout = timeout; } -static int sol_pdu_rpl_cli_init(struct bt_mesh_model *mod) +static int sol_pdu_rpl_cli_init(const struct bt_mesh_model *mod) { if (!bt_mesh_model_in_primary(mod)) { LOG_ERR("Solicitation PDU RPL Configuration client not in primary element"); @@ -169,7 +169,7 @@ static int sol_pdu_rpl_cli_init(struct bt_mesh_model *mod) msg_timeout = CONFIG_BT_MESH_SOL_PDU_RPL_CLI_TIMEOUT; - cli = mod->user_data; + cli = *(mod->user_data); cli->model = mod; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); return 0; diff --git a/subsys/bluetooth/mesh/sol_pdu_rpl_srv.c b/subsys/bluetooth/mesh/sol_pdu_rpl_srv.c index e0fff397640a79c..547494be3bee92c 100644 --- a/subsys/bluetooth/mesh/sol_pdu_rpl_srv.c +++ b/subsys/bluetooth/mesh/sol_pdu_rpl_srv.c @@ -14,7 +14,7 @@ #include LOG_MODULE_REGISTER(bt_mesh_sol_pdu_rpl_srv); -static void sol_rpl_status_rsp(struct bt_mesh_model *mod, +static void sol_rpl_status_rsp(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, uint16_t range, uint8_t len) @@ -32,7 +32,7 @@ static void sol_rpl_status_rsp(struct bt_mesh_model *mod, bt_mesh_model_send(mod, ctx, &buf, NULL, NULL); } -static int item_clear(struct bt_mesh_model *mod, +static int item_clear(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, bool acked) @@ -78,14 +78,14 @@ static int item_clear(struct bt_mesh_model *mod, return 0; } -static int handle_item_clear(struct bt_mesh_model *mod, +static int handle_item_clear(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return item_clear(mod, ctx, buf, true); } -static int handle_item_clear_unacked(struct bt_mesh_model *mod, +static int handle_item_clear_unacked(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -99,7 +99,7 @@ const struct bt_mesh_model_op _bt_mesh_sol_pdu_rpl_srv_op[] = { BT_MESH_MODEL_OP_END }; -static int sol_pdu_rpl_srv_init(struct bt_mesh_model *mod) +static int sol_pdu_rpl_srv_init(const struct bt_mesh_model *mod) { if (!bt_mesh_model_in_primary(mod)) { LOG_ERR("Solicitation PDU RPL Configuration server not in primary element"); diff --git a/tests/bluetooth/mesh/basic/src/main.c b/tests/bluetooth/mesh/basic/src/main.c index 8c6c1796c02274e..34f94d486c3f70c 100644 --- a/tests/bluetooth/mesh/basic/src/main.c +++ b/tests/bluetooth/mesh/basic/src/main.c @@ -15,7 +15,7 @@ static bool has_reg_fault = true; -static int fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, +static int fault_get_cur(const struct bt_mesh_model *model, uint8_t *test_id, uint16_t *company_id, uint8_t *faults, uint8_t *fault_count) { uint8_t reg_faults[MAX_FAULT] = { [0 ... (MAX_FAULT - 1)] = 0xff }; @@ -30,7 +30,7 @@ static int fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, return 0; } -static int fault_get_reg(struct bt_mesh_model *model, uint16_t company_id, +static int fault_get_reg(const struct bt_mesh_model *model, uint16_t company_id, uint8_t *test_id, uint8_t *faults, uint8_t *fault_count) { if (company_id != BT_COMP_ID_LF) { @@ -53,7 +53,7 @@ static int fault_get_reg(struct bt_mesh_model *model, uint16_t company_id, return 0; } -static int fault_clear(struct bt_mesh_model *model, uint16_t company_id) +static int fault_clear(const struct bt_mesh_model *model, uint16_t company_id) { if (company_id != BT_COMP_ID_LF) { return -EINVAL; @@ -64,7 +64,7 @@ static int fault_clear(struct bt_mesh_model *model, uint16_t company_id) return 0; } -static int fault_test(struct bt_mesh_model *model, uint8_t test_id, +static int fault_test(const struct bt_mesh_model *model, uint8_t test_id, uint16_t company_id) { if (company_id != BT_COMP_ID_LF) { @@ -90,12 +90,12 @@ static struct bt_mesh_health_srv health_srv = { BT_MESH_HEALTH_PUB_DEFINE(health_pub, MAX_FAULT); -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), }; -static int vnd_publish(struct bt_mesh_model *mod) +static int vnd_publish(const struct bt_mesh_model *mod) { printk("Vendor publish\n"); return 0; @@ -109,7 +109,7 @@ static const struct bt_mesh_model_op vnd_ops[] = { BT_MESH_MODEL_OP_END, }; -static struct bt_mesh_model vnd_models[] = { +static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(BT_COMP_ID_LF, 0x1234, vnd_ops, &vnd_pub, NULL), BT_MESH_MODEL_VND(BT_COMP_ID_LF, 0x4321, vnd_ops, &vnd_pub2, NULL), }; diff --git a/tests/bluetooth/mesh_shell/src/main.c b/tests/bluetooth/mesh_shell/src/main.c index 60863f7455a3f59..b562e428d11ed0c 100644 --- a/tests/bluetooth/mesh_shell/src/main.c +++ b/tests/bluetooth/mesh_shell/src/main.c @@ -43,7 +43,7 @@ struct bt_mesh_large_comp_data_cli large_comp_data_cli; BT_MESH_SHELL_HEALTH_PUB_DEFINE(health_pub); -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_SRV(&bt_mesh_shell_health_srv, &health_pub), diff --git a/tests/bluetooth/tester/src/btp_mesh.c b/tests/bluetooth/tester/src/btp_mesh.c index bdc37c2f2e5aaf4..36e627abe8c2d24 100644 --- a/tests/bluetooth/tester/src/btp_mesh.c +++ b/tests/bluetooth/tester/src/btp_mesh.c @@ -454,7 +454,7 @@ static struct bt_mesh_dfu_srv dfu_srv = #define AUTH_METHOD_INPUT 0x03 static struct model_data { - struct bt_mesh_model *model; + const struct bt_mesh_model *model; uint16_t addr; uint16_t appkey_idx; } model_bound[MODEL_BOUNDS_MAX]; @@ -587,7 +587,7 @@ static void get_faults(uint8_t *faults, uint8_t faults_size, uint8_t *dst, uint8 } } -static int fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, +static int fault_get_cur(const struct bt_mesh_model *model, uint8_t *test_id, uint16_t *company_id, uint8_t *faults, uint8_t *fault_count) { LOG_DBG(""); @@ -600,7 +600,7 @@ static int fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, return 0; } -static int fault_get_reg(struct bt_mesh_model *model, uint16_t company_id, +static int fault_get_reg(const struct bt_mesh_model *model, uint16_t company_id, uint8_t *test_id, uint8_t *faults, uint8_t *fault_count) { LOG_DBG("company_id 0x%04x", company_id); @@ -616,7 +616,7 @@ static int fault_get_reg(struct bt_mesh_model *model, uint16_t company_id, return 0; } -static int fault_clear(struct bt_mesh_model *model, uint16_t company_id) +static int fault_clear(const struct bt_mesh_model *model, uint16_t company_id) { LOG_DBG("company_id 0x%04x", company_id); @@ -629,7 +629,7 @@ static int fault_clear(struct bt_mesh_model *model, uint16_t company_id) return 0; } -static int fault_test(struct bt_mesh_model *model, uint8_t test_id, +static int fault_test(const struct bt_mesh_model *model, uint8_t test_id, uint16_t company_id) { LOG_DBG("test_id 0x%02x company_id 0x%04x", test_id, company_id); @@ -1024,7 +1024,7 @@ static uint8_t proxy_solicit(const void *cmd, uint16_t cmd_len, } #endif /* CONFIG_BT_MESH_PROXY_SOLICITATION */ -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), @@ -1091,7 +1091,7 @@ struct model_data *lookup_model_bound(uint16_t id) return NULL; } -static struct bt_mesh_model vnd_models[] = { +static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(CID_LOCAL, VND_MODEL_ID_1, BT_MESH_MODEL_NO_OPS, NULL, NULL), }; @@ -1715,7 +1715,7 @@ static uint8_t model_send(const void *cmd, uint16_t cmd_len, { const struct btp_mesh_model_send_cmd *cp = cmd; NET_BUF_SIMPLE_DEFINE(msg, UINT8_MAX); - struct bt_mesh_model *model = NULL; + const struct bt_mesh_model *model = NULL; uint16_t src; int err; @@ -5228,7 +5228,7 @@ void model_recv_ev(uint16_t src, uint16_t dst, const void *payload, tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_MODEL_RECV, buf.data, buf.len); } -static void model_bound_cb(uint16_t addr, struct bt_mesh_model *model, +static void model_bound_cb(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx) { int i; @@ -5249,7 +5249,7 @@ static void model_bound_cb(uint16_t addr, struct bt_mesh_model *model, LOG_ERR("model_bound is full"); } -static void model_unbound_cb(uint16_t addr, struct bt_mesh_model *model, +static void model_unbound_cb(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx) { int i; diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.c b/tests/bsim/bluetooth/mesh/src/mesh_test.c index 538af49109e9a28..ea209d9609c7255 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.c +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.c @@ -27,7 +27,7 @@ struct bt_mesh_test_stats test_stats; struct bt_mesh_msg_ctx test_send_ctx; static void (*ra_cb)(uint8_t *, size_t); -static int msg_rx(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int msg_rx(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { size_t len = buf->len + BT_MESH_MODEL_OP_LEN(TEST_MSG_OP_1); @@ -75,7 +75,7 @@ static int msg_rx(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, return 0; } -static int ra_rx(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, +static int ra_rx(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_INF("\tlen: %d bytes", buf->len); @@ -97,19 +97,19 @@ static const struct bt_mesh_model_op model_op[] = { BT_MESH_MODEL_OP_END }; -int __weak test_model_pub_update(struct bt_mesh_model *mod) +int __weak test_model_pub_update(const struct bt_mesh_model *mod) { return -1; } -int __weak test_model_settings_set(struct bt_mesh_model *model, +int __weak test_model_settings_set(const struct bt_mesh_model *model, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { return -1; } -void __weak test_model_reset(struct bt_mesh_model *model) +void __weak test_model_reset(const struct bt_mesh_model *model) { /* No-op. */ } @@ -128,19 +128,19 @@ static const struct bt_mesh_model_op vnd_model_op[] = { BT_MESH_MODEL_OP_END, }; -int __weak test_vnd_model_pub_update(struct bt_mesh_model *mod) +int __weak test_vnd_model_pub_update(const struct bt_mesh_model *mod) { return -1; } -int __weak test_vnd_model_settings_set(struct bt_mesh_model *model, +int __weak test_vnd_model_settings_set(const struct bt_mesh_model *model, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { return -1; } -void __weak test_vnd_model_reset(struct bt_mesh_model *model) +void __weak test_vnd_model_reset(const struct bt_mesh_model *model) { /* No-op. */ } @@ -174,7 +174,7 @@ static struct bt_mesh_priv_beacon_cli priv_beacon_cli; static struct bt_mesh_od_priv_proxy_cli priv_proxy_cli; #endif -static struct bt_mesh_model models[] = { +static const struct bt_mesh_model models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_CB(TEST_MOD_ID, model_op, &pub, NULL, &test_model_cb), @@ -195,14 +195,14 @@ static struct bt_mesh_model models[] = { #endif }; -struct bt_mesh_model *test_model = &models[2]; +const struct bt_mesh_model *test_model = &models[2]; -static struct bt_mesh_model vnd_models[] = { +static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND_CB(TEST_VND_COMPANY_ID, TEST_VND_MOD_ID, vnd_model_op, &vnd_pub, NULL, &test_vnd_model_cb), }; -struct bt_mesh_model *test_vnd_model = &vnd_models[0]; +const struct bt_mesh_model *test_vnd_model = &vnd_models[0]; static struct bt_mesh_elem elems[] = { BT_MESH_ELEM(0, models, vnd_models), diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.h b/tests/bsim/bluetooth/mesh/src/mesh_test.h index 08cf217779640d7..a5c8694947b82b0 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.h +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.h @@ -31,7 +31,7 @@ #define TEST_VND_COMPANY_ID 0x1234 #define TEST_VND_MOD_ID 0x5678 -#define MODEL_LIST(...) ((struct bt_mesh_model[]){ __VA_ARGS__ }) +#define MODEL_LIST(...) ((const struct bt_mesh_model[]){ __VA_ARGS__ }) #define FAIL(msg, ...) \ do { \ @@ -171,8 +171,8 @@ struct bt_mesh_test_sync_ctx { extern enum bst_result_t bst_result; extern const struct bt_mesh_test_cfg *cfg; -extern struct bt_mesh_model *test_model; -extern struct bt_mesh_model *test_vnd_model; +extern const struct bt_mesh_model *test_model; +extern const struct bt_mesh_model *test_vnd_model; extern const uint8_t test_net_key[16]; extern const uint8_t test_app_key[16]; extern const uint8_t test_va_uuid[16]; diff --git a/tests/bsim/bluetooth/mesh/src/test_access.c b/tests/bsim/bluetooth/mesh/src/test_access.c index 9bddf0e8058439b..dacc30c741e0704 100644 --- a/tests/bsim/bluetooth/mesh/src/test_access.c +++ b/tests/bsim/bluetooth/mesh/src/test_access.c @@ -35,15 +35,15 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); #define RX_JITTER_MAX (10 + CONFIG_BT_MESH_NETWORK_TRANSMIT_COUNT * \ (CONFIG_BT_MESH_NETWORK_TRANSMIT_INTERVAL + 10)) -static int model1_init(struct bt_mesh_model *model); -static int model2_init(struct bt_mesh_model *model); -static int model3_init(struct bt_mesh_model *model); -static int model4_init(struct bt_mesh_model *model); -static int model5_init(struct bt_mesh_model *model); -static int test_msg_handler(struct bt_mesh_model *model, +static int model1_init(const struct bt_mesh_model *model); +static int model2_init(const struct bt_mesh_model *model); +static int model3_init(const struct bt_mesh_model *model); +static int model4_init(const struct bt_mesh_model *model); +static int model5_init(const struct bt_mesh_model *model); +static int test_msg_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); -static int test_msg_ne_handler(struct bt_mesh_model *model, +static int test_msg_ne_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -99,7 +99,7 @@ static const struct { static struct k_sem publish_sem; static bool publish_allow; -static int model1_update(struct bt_mesh_model *model) +static int model1_update(const struct bt_mesh_model *model) { model->pub->msg->data[1]++; @@ -108,7 +108,7 @@ static int model1_update(struct bt_mesh_model *model) return publish_allow ? k_sem_give(&publish_sem), 0 : -1; } -static int test_msgf_handler(struct bt_mesh_model *model, +static int test_msgf_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -204,7 +204,7 @@ static const struct bt_mesh_model_op model_ne_op5[] = { static struct bt_mesh_cfg_cli cfg_cli; /* do not change model sequence. it will break pointer arithmetic. */ -static struct bt_mesh_model models[] = { +static const struct bt_mesh_model models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_CB(TEST_MODEL_ID_1, model_op1, &model_pub1, NULL, &test_model1_cb), @@ -215,7 +215,7 @@ static struct bt_mesh_model models[] = { }; /* do not change model sequence. it will break pointer arithmetic. */ -static struct bt_mesh_model models_ne[] = { +static const struct bt_mesh_model models_ne[] = { BT_MESH_MODEL_CB(TEST_MODEL_ID_1, model_ne_op1, NULL, NULL, &test_model1_cb), BT_MESH_MODEL_CB(TEST_MODEL_ID_2, model_ne_op2, NULL, NULL, &test_model2_cb), BT_MESH_MODEL_CB(TEST_MODEL_ID_3, model_ne_op3, NULL, NULL, &test_model3_cb), @@ -223,7 +223,7 @@ static struct bt_mesh_model models_ne[] = { BT_MESH_MODEL_CB(TEST_MODEL_ID_5, model_ne_op5, NULL, NULL, &test_model5_cb), }; -static struct bt_mesh_model vnd_models[] = {}; +static const struct bt_mesh_model vnd_models[] = {}; static struct bt_mesh_elem elems[] = { BT_MESH_ELEM(0, models, vnd_models), @@ -246,43 +246,43 @@ const struct bt_mesh_comp local_comp = { * m4 mne4 */ -static int model1_init(struct bt_mesh_model *model) +static int model1_init(const struct bt_mesh_model *model) { return 0; } -static int model2_init(struct bt_mesh_model *model) +static int model2_init(const struct bt_mesh_model *model) { return 0; } -static int model3_init(struct bt_mesh_model *model) +static int model3_init(const struct bt_mesh_model *model) { ASSERT_OK(bt_mesh_model_extend(model, model - 2)); ASSERT_OK(bt_mesh_model_extend(model, model - 1)); - if (model->elem_idx == 1) { + if (*(model->elem_idx) == 1) { ASSERT_OK(bt_mesh_model_extend(model, &models[4])); } return 0; } -static int model4_init(struct bt_mesh_model *model) +static int model4_init(const struct bt_mesh_model *model) { ASSERT_OK(bt_mesh_model_extend(model, model - 1)); return 0; } -static int model5_init(struct bt_mesh_model *model) +static int model5_init(const struct bt_mesh_model *model) { ASSERT_OK(bt_mesh_model_extend(model, model - 4)); return 0; } -static int test_msg_handler(struct bt_mesh_model *model, +static int test_msg_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -292,7 +292,7 @@ static int test_msg_handler(struct bt_mesh_model *model, return 0; } -static int test_msg_ne_handler(struct bt_mesh_model *model, +static int test_msg_ne_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -515,7 +515,7 @@ static void pub_param_set(uint8_t period, uint8_t transmit) static void msgf_publish(void) { - struct bt_mesh_model *model = &models[2]; + const struct bt_mesh_model *model = &models[2]; bt_mesh_model_msg_init(model->pub->msg, TEST_MESSAGE_OP_F); net_buf_simple_add_u8(model->pub->msg, 1); @@ -591,7 +591,7 @@ static void recv_jitter_check(int32_t interval, uint8_t count) */ static void test_tx_period(void) { - struct bt_mesh_model *model = &models[2]; + const struct bt_mesh_model *model = &models[2]; bt_mesh_test_cfg_set(NULL, 60); bt_mesh_device_setup(&prov, &local_comp); @@ -647,7 +647,7 @@ static void test_rx_period(void) */ static void test_tx_transmit(void) { - struct bt_mesh_model *model = &models[2]; + const struct bt_mesh_model *model = &models[2]; uint8_t status; int err; @@ -719,7 +719,7 @@ static void test_rx_transmit(void) */ static void test_tx_cancel(void) { - struct bt_mesh_model *model = &models[2]; + const struct bt_mesh_model *model = &models[2]; int err; bt_mesh_test_cfg_set(NULL, 20); diff --git a/tests/bsim/bluetooth/mesh/src/test_blob.c b/tests/bsim/bluetooth/mesh/src/test_blob.c index e3c564d973945d8..f9661fa0be03024 100644 --- a/tests/bsim/bluetooth/mesh/src/test_blob.c +++ b/tests/bsim/bluetooth/mesh/src/test_blob.c @@ -261,7 +261,7 @@ static const struct bt_mesh_comp cli_comp = { static struct k_sem info_get_sem; -static int mock_handle_info_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int mock_handle_info_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { k_sem_give(&info_get_sem); @@ -1310,7 +1310,7 @@ static void test_srv_fail_on_block_get(void) PASS(); } -static int dummy_xfer_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int dummy_xfer_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { return 0; diff --git a/tests/bsim/bluetooth/mesh/src/test_cdp1.c b/tests/bsim/bluetooth/mesh/src/test_cdp1.c index 7884ef174376d5c..03b71dce970811f 100644 --- a/tests/bsim/bluetooth/mesh/src/test_cdp1.c +++ b/tests/bsim/bluetooth/mesh/src/test_cdp1.c @@ -29,7 +29,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); #define TEST_VND_MODEL_ID_1 0x3a3a #define TEST_MODEL_DECLARE(number) \ - static int model_##number##_init(struct bt_mesh_model *model); \ + static int model_##number##_init(const struct bt_mesh_model *model); \ static const struct bt_mesh_model_cb test_model_##number##_cb = { \ .init = model_##number##_init, \ }; \ @@ -56,7 +56,7 @@ static const struct bt_mesh_test_cfg node_1_cfg = { static struct bt_mesh_prov prov; static struct bt_mesh_cfg_cli cfg_cli; -static struct bt_mesh_model models_1[] = { +static const struct bt_mesh_model models_1[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_CB(TEST_MODEL_ID_1, model_op_1, NULL, NULL, &test_model_1_cb), @@ -64,19 +64,19 @@ static struct bt_mesh_model models_1[] = { BT_MESH_MODEL_CB(TEST_MODEL_ID_3, model_op_3, NULL, NULL, &test_model_3_cb), }; -static struct bt_mesh_model models_2[] = { +static const struct bt_mesh_model models_2[] = { BT_MESH_MODEL_CB(TEST_MODEL_ID_4, model_op_4, NULL, NULL, &test_model_4_cb), }; -static struct bt_mesh_model models_3[] = { +static const struct bt_mesh_model models_3[] = { BT_MESH_MODEL_CB(TEST_MODEL_ID_5, model_op_5, NULL, NULL, &test_model_5_cb), }; -static struct bt_mesh_model models_4[] = { +static const struct bt_mesh_model models_4[] = { BT_MESH_MODEL_CB(TEST_MODEL_ID_6, model_op_6, NULL, NULL, &test_model_6_cb), }; -static struct bt_mesh_model models_vnd1[] = { +static const struct bt_mesh_model models_vnd1[] = { BT_MESH_MODEL_VND_CB(TEST_VND_COMPANY_ID, TEST_VND_MODEL_ID_1, model_op_vnd1, NULL, NULL, &test_model_vnd1_cb), }; @@ -106,41 +106,41 @@ static const struct bt_mesh_comp comp = { * M2 on E0 and M4 on E1 corresponds. * M6 on E4 extends M1 on E0 */ -static int model_1_init(struct bt_mesh_model *model) +static int model_1_init(const struct bt_mesh_model *model) { return 0; } -static int model_2_init(struct bt_mesh_model *model) +static int model_2_init(const struct bt_mesh_model *model) { ASSERT_OK(bt_mesh_model_extend(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_1))); return 0; } -static int model_3_init(struct bt_mesh_model *model) +static int model_3_init(const struct bt_mesh_model *model) { return 0; } -static int model_4_init(struct bt_mesh_model *model) +static int model_4_init(const struct bt_mesh_model *model) { ASSERT_OK(bt_mesh_model_extend(bt_mesh_model_find(&elems[0], TEST_MODEL_ID_3), model)); ASSERT_OK(bt_mesh_model_correspond(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_2))); return 0; } -static int model_5_init(struct bt_mesh_model *model) +static int model_5_init(const struct bt_mesh_model *model) { return 0; } -static int model_6_init(struct bt_mesh_model *model) +static int model_6_init(const struct bt_mesh_model *model) { ASSERT_OK(bt_mesh_model_extend(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_1))); return 0; } -static int model_vnd1_init(struct bt_mesh_model *model) +static int model_vnd1_init(const struct bt_mesh_model *model) { ASSERT_OK(bt_mesh_model_extend(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_1))); ASSERT_OK(bt_mesh_model_correspond(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_3))); diff --git a/tests/bsim/bluetooth/mesh/src/test_dfu.c b/tests/bsim/bluetooth/mesh/src/test_dfu.c index 0eed5d1478d2529..83037ea6e73ad83 100644 --- a/tests/bsim/bluetooth/mesh/src/test_dfu.c +++ b/tests/bsim/bluetooth/mesh/src/test_dfu.c @@ -1309,7 +1309,7 @@ static void test_cli_stop(void) static struct k_sem caps_get_sem; -static int mock_handle_caps_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int mock_handle_caps_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_WRN("Rejecting BLOB Information Get message"); @@ -1340,7 +1340,7 @@ static const struct bt_mesh_comp srv_caps_broken_comp = { .elem_count = 1, }; -static int mock_handle_chunks(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int mock_handle_chunks(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_WRN("Skipping receiving block"); @@ -1373,7 +1373,7 @@ static const struct bt_mesh_comp broken_target_comp = { static struct k_sem update_get_sem; -static int mock_handle_update_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int mock_handle_update_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_WRN("Rejecting Firmware Update Get message"); @@ -1406,7 +1406,7 @@ static const struct bt_mesh_comp srv_update_get_broken_comp = { static struct k_sem update_apply_sem; -static int mock_handle_update_apply(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int mock_handle_update_apply(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_WRN("Rejecting Firmware Update Apply message"); diff --git a/tests/bsim/bluetooth/mesh/src/test_lcd.c b/tests/bsim/bluetooth/mesh/src/test_lcd.c index c4b644479879b06..7e1d9ffca3ce4c4 100644 --- a/tests/bsim/bluetooth/mesh/src/test_lcd.c +++ b/tests/bsim/bluetooth/mesh/src/test_lcd.c @@ -31,9 +31,19 @@ LOG_MODULE_REGISTER(test_lcd, LOG_LEVEL_INF); LCD_STATUS_FIELDS_LEN - \ BT_MESH_MIC_SHORT) /* 378 bytes */ +#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS +#define BT_MESH_MODEL_NEXT_UNASSIGNED() \ + .next = (const struct bt_mesh_model *[]){ NULL }, +#else +#define BT_MESH_MODEL_NEXT_UNASSIGNED() +#endif + #define TEST_MODEL_CNT_CB(_dummy_op, _metadata) \ { \ .id = 0x1234, \ + .elem_idx = (uint8_t []) { 0 }, \ + .mod_idx = (uint8_t []) { 0 }, \ + .flags = (uint16_t []) { 0 }, \ .pub = NULL, \ .keys = NULL, \ .keys_cnt = 0, \ @@ -41,7 +51,8 @@ LOG_MODULE_REGISTER(test_lcd, LOG_LEVEL_INF); .groups_cnt = 0, \ .op = _dummy_op, \ .cb = NULL, \ - .user_data = NULL, \ + BT_MESH_MODEL_NEXT_UNASSIGNED() \ + .user_data = (void *[]){ NULL }, \ .metadata = _metadata, \ } diff --git a/tests/bsim/bluetooth/mesh/src/test_op_agg.c b/tests/bsim/bluetooth/mesh/src/test_op_agg.c index d8bb50b3fd39b04..8735bdf524d3442 100644 --- a/tests/bsim/bluetooth/mesh/src/test_op_agg.c +++ b/tests/bsim/bluetooth/mesh/src/test_op_agg.c @@ -54,7 +54,7 @@ static uint8_t cli_sent_array[TEST_SEND_ITR], cli_rcvd_array[TEST_SEND_ITR]; static struct bt_mesh_prov prov; static struct bt_mesh_cfg_cli cfg_cli; -static int get_handler(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int get_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t seq = net_buf_simple_pull_u8(buf); @@ -78,7 +78,7 @@ static int get_handler(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return bt_mesh_model_send(model, ctx, &msg, NULL, NULL); } -static int status_handler(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int status_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t seq = net_buf_simple_pull_u8(buf); @@ -93,7 +93,8 @@ static int status_handler(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *c return 0; } -static int dummy_vnd_mod_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t seq) +static int dummy_vnd_mod_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + uint8_t seq) { BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_DUMMY_VND_MOD_GET_OP, BT_MESH_DUMMY_VND_MOD_MSG_MAXLEN); diff --git a/tests/bsim/bluetooth/mesh/src/test_persistence.c b/tests/bsim/bluetooth/mesh/src/test_persistence.c index 17244be15fede60..df3eaa19989cc1e 100644 --- a/tests/bsim/bluetooth/mesh/src/test_persistence.c +++ b/tests/bsim/bluetooth/mesh/src/test_persistence.c @@ -338,7 +338,7 @@ static void check_mod_pub_params(const struct bt_mesh_cfg_cli_mod_pub *expected, ASSERT_EQUAL(expected->transmit, got->transmit); } -int test_model_settings_set(struct bt_mesh_model *model, +int test_model_settings_set(const struct bt_mesh_model *model, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { @@ -364,12 +364,12 @@ int test_model_settings_set(struct bt_mesh_model *model, return 0; } -void test_model_reset(struct bt_mesh_model *model) +void test_model_reset(const struct bt_mesh_model *model) { ASSERT_OK(bt_mesh_model_data_store(test_model, false, TEST_MOD_DATA_NAME, NULL, 0)); } -int test_vnd_model_settings_set(struct bt_mesh_model *model, +int test_vnd_model_settings_set(const struct bt_mesh_model *model, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { @@ -395,7 +395,7 @@ int test_vnd_model_settings_set(struct bt_mesh_model *model, return 0; } -void test_vnd_model_reset(struct bt_mesh_model *model) +void test_vnd_model_reset(const struct bt_mesh_model *model) { ASSERT_OK(bt_mesh_model_data_store(test_vnd_model, true, TEST_VND_MOD_DATA_NAME, NULL, 0)); } diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 24e1f627382a8a7..80eb9ff38cd2eae 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -152,7 +152,7 @@ static const struct bt_mesh_comp rpr_cli_srv_comp = { .elem_count = 1, }; -static int mock_pdu_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int mock_pdu_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { /* Device becomes unresponsive and doesn't communicate with other nodes anymore */ @@ -168,10 +168,10 @@ static const struct bt_mesh_model_op model_rpr_op1[] = { BT_MESH_MODEL_OP_END }; -static int mock_model_init(struct bt_mesh_model *mod) +static int mock_model_init(const struct bt_mesh_model *mod) { mod->keys[0] = BT_MESH_KEY_DEV_LOCAL; - mod->flags |= BT_MESH_MOD_DEVKEY_ONLY; + *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } diff --git a/tests/bsim/bluetooth/mesh/src/test_sar.c b/tests/bsim/bluetooth/mesh/src/test_sar.c index a928d973a253399..7214366247dd39d 100644 --- a/tests/bsim/bluetooth/mesh/src/test_sar.c +++ b/tests/bsim/bluetooth/mesh/src/test_sar.c @@ -91,7 +91,7 @@ static void data_integrity_check(struct net_buf_simple *buf) net_buf_simple_restore(buf, &state); } -static int get_handler(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int get_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { data_integrity_check(buf); @@ -104,7 +104,7 @@ static int get_handler(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return bt_mesh_model_send(model, ctx, &msg, NULL, NULL); } -static int status_handler(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int status_handler(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { data_integrity_check(buf); @@ -112,7 +112,7 @@ static int status_handler(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *c return 0; } -static int dummy_vnd_mod_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int dummy_vnd_mod_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t msg[]) { BT_MESH_MODEL_BUF_DEFINE(buf, DUMMY_VND_MOD_GET_OP, MAX_SDU_MSG_LEN); @@ -185,7 +185,7 @@ static void array_random_fill(uint8_t array[], uint16_t len, int seed) static void cli_max_len_sdu_send(struct bt_mesh_sar_rx *sar_rx_config, struct bt_mesh_sar_tx *sar_tx_config) { - struct bt_mesh_model *dummy_vnd_mod = &elements[0].vnd_models[0]; + const struct bt_mesh_model *dummy_vnd_mod = &elements[0].vnd_models[0]; bt_mesh_test_cfg_set(NULL, WAIT_TIME); bt_mesh_device_setup(&prov, &comp); From 2cd8d40b97c8bb9d9c1fabe9088c1970a11667f6 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Wed, 15 Nov 2023 18:03:40 +0800 Subject: [PATCH 0535/1049] Bluetooth: Mesh: Split Model Structure Split Model Variables to separate structue. Signed-off-by: Lingao Meng --- include/zephyr/bluetooth/mesh/access.h | 58 +++++------- samples/boards/nrf/mesh/onoff-app/src/main.c | 4 +- .../src/mesh/device_composition.c | 4 +- .../boards/reel_board/mesh_badge/src/mesh.c | 4 +- subsys/bluetooth/mesh/access.c | 88 +++++++++---------- subsys/bluetooth/mesh/blob_cli.c | 12 +-- subsys/bluetooth/mesh/blob_srv.c | 22 ++--- subsys/bluetooth/mesh/cfg_cli.c | 6 +- subsys/bluetooth/mesh/cfg_srv.c | 12 +-- subsys/bluetooth/mesh/dfd_srv.c | 38 ++++---- subsys/bluetooth/mesh/dfu_cli.c | 12 +-- subsys/bluetooth/mesh/dfu_srv.c | 18 ++-- subsys/bluetooth/mesh/health_cli.c | 12 +-- subsys/bluetooth/mesh/health_srv.c | 18 ++-- subsys/bluetooth/mesh/large_comp_data_cli.c | 4 +- subsys/bluetooth/mesh/large_comp_data_srv.c | 2 +- subsys/bluetooth/mesh/od_priv_proxy_cli.c | 4 +- subsys/bluetooth/mesh/od_priv_proxy_srv.c | 2 +- subsys/bluetooth/mesh/priv_beacon_cli.c | 4 +- subsys/bluetooth/mesh/rpr_cli.c | 22 ++--- subsys/bluetooth/mesh/rpr_srv.c | 4 +- subsys/bluetooth/mesh/sar_cfg_cli.c | 8 +- subsys/bluetooth/mesh/sar_cfg_srv.c | 2 +- subsys/bluetooth/mesh/shell/blob.c | 16 ++-- subsys/bluetooth/mesh/shell/dfd.c | 20 ++--- subsys/bluetooth/mesh/shell/dfu.c | 26 +++--- subsys/bluetooth/mesh/shell/health.c | 14 +-- subsys/bluetooth/mesh/shell/rpr.c | 20 ++--- subsys/bluetooth/mesh/shell/utils.c | 2 +- subsys/bluetooth/mesh/sol_pdu_rpl_cli.c | 2 +- tests/bsim/bluetooth/mesh/src/test_access.c | 2 +- tests/bsim/bluetooth/mesh/src/test_lcd.c | 13 +-- .../bsim/bluetooth/mesh/src/test_provision.c | 2 +- 33 files changed, 226 insertions(+), 251 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index aa6235498147996..45042b87d9b8d93 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -31,10 +31,11 @@ #endif #ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS -#define BT_MESH_MODEL_NEXT_UNASSIGNED() \ - .next = (const struct bt_mesh_model *[]){ NULL }, +#define BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ + .rt = (void *)(void *[]){ NULL, NULL, (_user_data) }, #else -#define BT_MESH_MODEL_NEXT_UNASSIGNED() +#define BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ + .rt = (void *)(void *[]){ NULL, (_user_data) }, #endif /** @@ -432,9 +433,7 @@ struct bt_mesh_model_op { #define BT_MESH_MODEL_CNT_CB(_id, _op, _pub, _user_data, _keys, _grps, _cb) \ { \ .id = (_id), \ - .elem_idx = (uint8_t []) { 0 }, \ - .mod_idx = (uint8_t []) { 0 }, \ - .flags = (uint16_t []) { 0 }, \ + BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(_keys), \ .keys_cnt = _keys, \ @@ -443,8 +442,6 @@ struct bt_mesh_model_op { BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ - BT_MESH_MODEL_NEXT_UNASSIGNED() \ - .user_data = (void *[]){ _user_data }, \ } /** @@ -469,9 +466,7 @@ struct bt_mesh_model_op { { \ .vnd.company = (_company), \ .vnd.id = (_id), \ - .elem_idx = (uint8_t []) { 0 }, \ - .mod_idx = (uint8_t []) { 0 }, \ - .flags = (uint16_t []) { 0 }, \ + BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ .op = _op, \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(_keys), \ @@ -479,8 +474,6 @@ struct bt_mesh_model_op { .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \ .groups_cnt = _grps, \ BT_MESH_MODEL_UUIDS_UNASSIGNED() \ - BT_MESH_MODEL_NEXT_UNASSIGNED() \ - .user_data = (void *[]){ _user_data }, \ .cb = _cb, \ } @@ -520,9 +513,7 @@ struct bt_mesh_model_op { #define BT_MESH_MODEL_METADATA_CB(_id, _op, _pub, _user_data, _cb, _metadata) \ { \ .id = (_id), \ - .elem_idx = (uint8_t []) { 0 }, \ - .mod_idx = (uint8_t []) { 0 }, \ - .flags = (uint16_t []) { 0 }, \ + BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(CONFIG_BT_MESH_MODEL_KEY_COUNT), \ .keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \ @@ -531,8 +522,6 @@ struct bt_mesh_model_op { BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ - BT_MESH_MODEL_NEXT_UNASSIGNED() \ - .user_data = (void *[]){ _user_data }, \ .metadata = _metadata, \ } #else @@ -578,9 +567,7 @@ struct bt_mesh_model_op { { \ .vnd.company = (_company), \ .vnd.id = (_id), \ - .elem_idx = (uint8_t []) { 0 }, \ - .mod_idx = (uint8_t []) { 0 }, \ - .flags = (uint16_t []) { 0 }, \ + BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ .op = _op, \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(CONFIG_BT_MESH_MODEL_KEY_COUNT), \ @@ -588,8 +575,6 @@ struct bt_mesh_model_op { .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \ .groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \ BT_MESH_MODEL_UUIDS_UNASSIGNED() \ - BT_MESH_MODEL_NEXT_UNASSIGNED() \ - .user_data = (void *[]){ _user_data }, \ .cb = _cb, \ .metadata = _metadata, \ } @@ -900,10 +885,19 @@ struct bt_mesh_model { const struct bt_mesh_mod_id_vnd vnd; }; - /* Internal information, mainly for persistent storage */ - uint8_t * const elem_idx; /* Belongs to Nth element */ - uint8_t * const mod_idx; /* Is the Nth model in the element */ - uint16_t * const flags; /* Model flags for internal bookkeeping */ + /* Model runtime information */ + struct { + uint8_t elem_idx; /* Belongs to Nth element */ + uint8_t mod_idx; /* Is the Nth model in the element */ + uint16_t flags; /* Model flags for internal bookkeeping */ + +#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS + /* Pointer to the next model in a model extension list. */ + const struct bt_mesh_model *next; +#endif + /** Model-specific user data */ + void *user_data; + } * const rt; /** Model Publication */ struct bt_mesh_model_pub * const pub; @@ -927,18 +921,10 @@ struct bt_mesh_model { /** Model callback structure. */ const struct bt_mesh_model_cb * const cb; -#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS - /* Pointer to the next model in a model extension list. */ - const struct bt_mesh_model ** const next; -#endif - #if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) || defined(__DOXYGEN__) /* Pointer to the array of model metadata entries. */ struct bt_mesh_models_metadata_entry **metadata; #endif - - /** Model-specific user data */ - void ** const user_data; }; /** Callback structure for monitoring model message sending */ @@ -1048,7 +1034,7 @@ const struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *el */ static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod) { - return (*(mod->elem_idx) == 0); + return (mod->rt->elem_idx == 0); } /** @brief Immediately store the model's user data in persistent storage. diff --git a/samples/boards/nrf/mesh/onoff-app/src/main.c b/samples/boards/nrf/mesh/onoff-app/src/main.c index 817d2c023a61cd5..71b787fe4979ca0 100644 --- a/samples/boards/nrf/mesh/onoff-app/src/main.c +++ b/samples/boards/nrf/mesh/onoff-app/src/main.c @@ -286,7 +286,7 @@ static int gen_onoff_get(const struct bt_mesh_model *model, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); - struct led_onoff_state *onoff_state = *(model->user_data); + struct led_onoff_state *onoff_state = model->rt->user_data; printk("addr 0x%04x onoff 0x%02x\n", bt_mesh_model_elem(model)->addr, onoff_state->current); @@ -305,7 +305,7 @@ static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct net_buf_simple *buf) { struct net_buf_simple *msg = model->pub->msg; - struct led_onoff_state *onoff_state = *(model->user_data); + struct led_onoff_state *onoff_state = model->rt->user_data; int err; onoff_state->current = net_buf_simple_pull_u8(buf); diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c index 54a5a2c8af730e1..775c793bb377ef3 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c @@ -991,7 +991,7 @@ static int vnd_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ct struct net_buf_simple *buf) { struct net_buf_simple *msg = NET_BUF_SIMPLE(3 + 6 + 4); - struct vendor_state *state = *(model->user_data); + struct vendor_state *state = model->rt->user_data; /* This is dummy response for demo purpose */ state->response = 0xA578FEB3; @@ -1014,7 +1014,7 @@ static int vnd_set_unack(const struct bt_mesh_model *model, uint8_t tid; int current; int64_t now; - struct vendor_state *state = *(model->user_data); + struct vendor_state *state = model->rt->user_data; current = net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); diff --git a/samples/boards/reel_board/mesh_badge/src/mesh.c b/samples/boards/reel_board/mesh_badge/src/mesh.c index ae219387cf58267..61af8cc0b6d3a5e 100644 --- a/samples/boards/reel_board/mesh_badge/src/mesh.c +++ b/samples/boards/reel_board/mesh_badge/src/mesh.c @@ -184,7 +184,7 @@ static int gen_onoff_get(const struct bt_mesh_model *model, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); - struct led_onoff_state *state = *(model->user_data); + struct led_onoff_state *state = model->rt->user_data; printk("addr 0x%04x onoff 0x%02x\n", bt_mesh_model_elem(model)->addr, state->current); @@ -203,7 +203,7 @@ static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct net_buf_simple *buf) { struct net_buf_simple *msg = model->pub->msg; - struct led_onoff_state *state = *(model->user_data); + struct led_onoff_state *state = model->rt->user_data; int err; uint8_t tid, onoff; int64_t now; diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 2911a42c7aff3f4..4b6a45ae5c83f4f 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -92,12 +92,12 @@ static struct mod_relation mod_rel_list[MOD_REL_LIST_SIZE]; (idx)++) #define IS_MOD_BASE(mod, idx, offset) \ - (mod_rel_list[(idx)].elem_base == *((mod)->elem_idx) && \ - mod_rel_list[(idx)].idx_base == *((mod)->mod_idx) + (offset)) + (mod_rel_list[(idx)].elem_base == mod->rt->elem_idx && \ + mod_rel_list[(idx)].idx_base == mod->rt->mod_idx + (offset)) #define IS_MOD_EXTENSION(mod, idx, offset) \ - (mod_rel_list[(idx)].elem_ext == *((mod)->elem_idx) && \ - mod_rel_list[(idx)].idx_ext == *((mod)->mod_idx) + (offset)) + (mod_rel_list[(idx)].elem_ext == mod->rt->elem_idx && \ + mod_rel_list[(idx)].idx_ext == mod->rt->mod_idx + (offset)) #define RELATION_TYPE_EXT 0xFF @@ -533,7 +533,7 @@ static void add_items_to_page(struct net_buf_simple *buf, const struct bt_mesh_m MOD_REL_LIST_FOR_EACH(i) { if (IS_MOD_EXTENSION(mod, i, sig_offset) && mod_rel_list[i].type == RELATION_TYPE_EXT) { - elem_offset = *(mod->elem_idx) - mod_rel_list[i].elem_base; + elem_offset = mod->rt->elem_idx - mod_rel_list[i].elem_base; mod_idx = mod_rel_list[i].idx_base; if (ext_mod_cnt < 32 && elem_offset < 4 && @@ -569,7 +569,7 @@ static size_t mod_items_size(const struct bt_mesh_model *mod, uint8_t sig_offset MOD_REL_LIST_FOR_EACH(i) { if (IS_MOD_EXTENSION(mod, i, sig_offset)) { - offset = *(mod->elem_idx) - mod_rel_list[i].elem_base; + offset = mod->rt->elem_idx - mod_rel_list[i].elem_base; temp_size += (ext_mod_cnt < 32 && offset < 4 && offset > -5) ? 1 : 2; } } @@ -901,7 +901,7 @@ static void mod_publish(struct k_work *work) struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod) { - return &dev_comp->elem[*(mod->elem_idx)]; + return &dev_comp->elem[mod->rt->elem_idx]; } const struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx) @@ -975,9 +975,9 @@ static void mod_init(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, mod->keys[i] = BT_MESH_KEY_UNUSED; } - *(mod->elem_idx) = elem - dev_comp->elem; + mod->rt->elem_idx = elem - dev_comp->elem; if (vnd) { - *(mod->mod_idx) = mod - elem->vnd_models; + mod->rt->mod_idx = mod - elem->vnd_models; if (IS_ENABLED(CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE)) { *err = bt_mesh_vnd_mod_msg_cid_check(mod); @@ -987,7 +987,7 @@ static void mod_init(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, } } else { - *(mod->mod_idx) = mod - elem->models; + mod->rt->mod_idx = mod - elem->models; } if (mod->cb && mod->cb->init) { @@ -1107,7 +1107,7 @@ static enum bt_mesh_walk find_group_mod_visitor(const struct bt_mesh_model *mod, { struct find_group_visitor_ctx *ctx = user_data; - if (*(mod->elem_idx) != *(ctx->mod->elem_idx)) { + if (mod->rt->elem_idx != ctx->mod->rt->elem_idx) { return BT_MESH_WALK_CONTINUE; } @@ -1165,7 +1165,7 @@ static enum bt_mesh_walk find_uuid_mod_visitor(const struct bt_mesh_model *mod, { struct find_uuid_visitor_ctx *ctx = user_data; - if (*(mod->elem_idx) != *(ctx->mod->elem_idx)) { + if (mod->rt->elem_idx != ctx->mod->rt->elem_idx) { return BT_MESH_WALK_CONTINUE; } @@ -1315,11 +1315,11 @@ bool bt_mesh_model_has_key(const struct bt_mesh_model *mod, uint16_t key) static bool model_has_dst(const struct bt_mesh_model *mod, uint16_t dst, const uint8_t *uuid) { if (BT_MESH_ADDR_IS_UNICAST(dst)) { - return (dev_comp->elem[*(mod->elem_idx)].addr == dst); + return (dev_comp->elem[mod->rt->elem_idx].addr == dst); } else if (BT_MESH_ADDR_IS_VIRTUAL(dst)) { return !!bt_mesh_model_find_uuid(&mod, uuid); } else if (BT_MESH_ADDR_IS_GROUP(dst) || - (BT_MESH_ADDR_IS_FIXED_GROUP(dst) && *(mod->elem_idx) != 0)) { + (BT_MESH_ADDR_IS_FIXED_GROUP(dst) && mod->rt->elem_idx != 0)) { return !!bt_mesh_model_find_group(&mod, dst); } @@ -1327,7 +1327,7 @@ static bool model_has_dst(const struct bt_mesh_model *mod, uint16_t dst, const u * the lower layers have already confirmed that we are subscribing to * it. All models on the primary element should receive the message. */ - return *(mod->elem_idx) == 0; + return mod->rt->elem_idx == 0; } static const struct bt_mesh_model_op *find_op(struct bt_mesh_elem *elem, @@ -1607,12 +1607,12 @@ void bt_mesh_model_extensions_walk(const struct bt_mesh_model *model, #else const struct bt_mesh_model *it; - if (cb(model, user_data) == BT_MESH_WALK_STOP || !*(model->next)) { + if (cb(model, user_data) == BT_MESH_WALK_STOP || !model->rt->next) { return; } /* List is circular. Step through all models until we reach the start: */ - for (it = *(model->next); it != model; it = *(it->next)) { + for (it = model->rt->next; it != model; it = it->rt->next) { if (cb(it, user_data) == BT_MESH_WALK_STOP) { return; } @@ -1643,10 +1643,10 @@ static int mod_rel_register(const struct bt_mesh_model *base, { LOG_DBG(""); struct mod_relation extension = { - *(base->elem_idx), - *(base->mod_idx) + get_sig_offset(base), - *(ext->elem_idx), - *(ext->mod_idx) + get_sig_offset(ext), + base->rt->elem_idx, + base->rt->mod_idx + get_sig_offset(base), + ext->rt->elem_idx, + ext->rt->mod_idx + get_sig_offset(ext), type, }; int i; @@ -1670,18 +1670,18 @@ int bt_mesh_model_extend(const struct bt_mesh_model *extending_mod, { const struct bt_mesh_model *a = extending_mod; const struct bt_mesh_model *b = base_mod; - const struct bt_mesh_model *a_next = *(a->next); - const struct bt_mesh_model *b_next = *(b->next); + const struct bt_mesh_model *a_next = a->rt->next; + const struct bt_mesh_model *b_next = b->rt->next; const struct bt_mesh_model *it; - *(base_mod->flags) |= BT_MESH_MOD_EXTENDED; + base_mod->rt->flags |= BT_MESH_MOD_EXTENDED; if (a == b) { return 0; } /* Check if a's list contains b */ - for (it = a; (it != NULL) && (*(it->next) != a); it = *(it->next)) { + for (it = a; (it != NULL) && (it->rt->next != a); it = it->rt->next) { if (it == b) { goto register_extension; } @@ -1689,15 +1689,15 @@ int bt_mesh_model_extend(const struct bt_mesh_model *extending_mod, /* Merge lists */ if (a_next) { - *(b->next) = a_next; + b->rt->next = a_next; } else { - *(b->next) = a; + b->rt->next = a; } if (b_next) { - *(a->next) = b_next; + a->rt->next = b_next; } else { - *(a->next) = b; + a->rt->next = b; } register_extension: @@ -1745,7 +1745,7 @@ int bt_mesh_model_correspond(const struct bt_mesh_model *corresponding_mod, bool bt_mesh_model_is_extended(const struct bt_mesh_model *model) { - return *(model->flags) & BT_MESH_MOD_EXTENDED; + return model->rt->flags & BT_MESH_MOD_EXTENDED; } static int mod_set_bind(const struct bt_mesh_model *mod, size_t len_rd, @@ -2041,7 +2041,7 @@ BT_MESH_SETTINGS_DEFINE(comp, "cmp", comp_set); static void encode_mod_path(const struct bt_mesh_model *mod, bool vnd, const char *key, char *path, size_t path_len) { - uint16_t mod_key = (((uint16_t)*(mod->elem_idx) << 8) | *(mod->mod_idx)); + uint16_t mod_key = (((uint16_t)mod->rt->elem_idx << 8) | mod->rt->mod_idx); if (vnd) { snprintk(path, path_len, "bt/mesh/v/%x/%s", mod_key, key); @@ -2174,28 +2174,28 @@ static void store_pending_mod(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { - if (!*(mod->flags)) { + if (!mod->rt->flags) { return; } - if (*(mod->flags) & BT_MESH_MOD_BIND_PENDING) { - *(mod->flags) &= ~BT_MESH_MOD_BIND_PENDING; + if (mod->rt->flags & BT_MESH_MOD_BIND_PENDING) { + mod->rt->flags &= ~BT_MESH_MOD_BIND_PENDING; store_pending_mod_bind(mod, vnd); } - if (*(mod->flags) & BT_MESH_MOD_SUB_PENDING) { - *(mod->flags) &= ~BT_MESH_MOD_SUB_PENDING; + if (mod->rt->flags & BT_MESH_MOD_SUB_PENDING) { + mod->rt->flags &= ~BT_MESH_MOD_SUB_PENDING; store_pending_mod_sub(mod, vnd); store_pending_mod_sub_va(mod, vnd); } - if (*(mod->flags) & BT_MESH_MOD_PUB_PENDING) { - *(mod->flags) &= ~BT_MESH_MOD_PUB_PENDING; + if (mod->rt->flags & BT_MESH_MOD_PUB_PENDING) { + mod->rt->flags &= ~BT_MESH_MOD_PUB_PENDING; store_pending_mod_pub(mod, vnd); } - if (*(mod->flags) & BT_MESH_MOD_DATA_PENDING) { - *(mod->flags) &= ~BT_MESH_MOD_DATA_PENDING; + if (mod->rt->flags & BT_MESH_MOD_DATA_PENDING) { + mod->rt->flags &= ~BT_MESH_MOD_DATA_PENDING; mod->cb->pending_store(mod); } } @@ -2207,19 +2207,19 @@ void bt_mesh_model_pending_store(void) void bt_mesh_model_bind_store(const struct bt_mesh_model *mod) { - *(mod->flags) |= BT_MESH_MOD_BIND_PENDING; + mod->rt->flags |= BT_MESH_MOD_BIND_PENDING; bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } void bt_mesh_model_sub_store(const struct bt_mesh_model *mod) { - *(mod->flags) |= BT_MESH_MOD_SUB_PENDING; + mod->rt->flags |= BT_MESH_MOD_SUB_PENDING; bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } void bt_mesh_model_pub_store(const struct bt_mesh_model *mod) { - *(mod->flags) |= BT_MESH_MOD_PUB_PENDING; + mod->rt->flags |= BT_MESH_MOD_PUB_PENDING; bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } @@ -2584,7 +2584,7 @@ void bt_mesh_model_settings_commit(void) void bt_mesh_model_data_store_schedule(const struct bt_mesh_model *mod) { - *(mod->flags) |= BT_MESH_MOD_DATA_PENDING; + mod->rt->flags |= BT_MESH_MOD_DATA_PENDING; bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } diff --git a/subsys/bluetooth/mesh/blob_cli.c b/subsys/bluetooth/mesh/blob_cli.c index 4fd0fe7bac97da5..f96a9af06531948 100644 --- a/subsys/bluetooth/mesh/blob_cli.c +++ b/subsys/bluetooth/mesh/blob_cli.c @@ -1207,7 +1207,7 @@ static void rx_block_status(struct bt_mesh_blob_cli *cli, static int handle_xfer_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = *(mod->user_data); + struct bt_mesh_blob_cli *cli = mod->rt->user_data; enum bt_mesh_blob_xfer_phase expected_phase; struct bt_mesh_blob_target *target; struct bt_mesh_blob_xfer_info info = { 0 }; @@ -1279,7 +1279,7 @@ static int handle_xfer_status(const struct bt_mesh_model *mod, struct bt_mesh_ms static int handle_block_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = *(mod->user_data); + struct bt_mesh_blob_cli *cli = mod->rt->user_data; struct block_status status = { .status = BT_MESH_BLOB_SUCCESS, .block.number = cli->block.number, @@ -1333,7 +1333,7 @@ static int handle_block_report(const struct bt_mesh_model *mod, struct bt_mesh_m static int handle_block_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = *(mod->user_data); + struct bt_mesh_blob_cli *cli = mod->rt->user_data; struct bt_mesh_blob_target *target; struct block_status status = { 0 }; uint8_t status_and_format; @@ -1404,7 +1404,7 @@ static int handle_block_status(const struct bt_mesh_model *mod, struct bt_mesh_m static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = *(mod->user_data); + struct bt_mesh_blob_cli *cli = mod->rt->user_data; struct bt_mesh_blob_cli_caps caps; enum bt_mesh_blob_status status; struct bt_mesh_blob_target *target; @@ -1460,7 +1460,7 @@ const struct bt_mesh_model_op _bt_mesh_blob_cli_op[] = { static int blob_cli_init(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_cli *cli = *(mod->user_data); + struct bt_mesh_blob_cli *cli = mod->rt->user_data; cli->mod = mod; @@ -1473,7 +1473,7 @@ static int blob_cli_init(const struct bt_mesh_model *mod) static void blob_cli_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_cli *cli = *(mod->user_data); + struct bt_mesh_blob_cli *cli = mod->rt->user_data; cli_state_reset(cli); } diff --git a/subsys/bluetooth/mesh/blob_srv.c b/subsys/bluetooth/mesh/blob_srv.c index 2fee121415d1947..3773a17e9afed84 100644 --- a/subsys/bluetooth/mesh/blob_srv.c +++ b/subsys/bluetooth/mesh/blob_srv.c @@ -418,7 +418,7 @@ static void block_status_rsp(struct bt_mesh_blob_srv *srv, static int handle_xfer_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; LOG_DBG(""); @@ -438,7 +438,7 @@ static int handle_xfer_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_c static int handle_xfer_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; enum bt_mesh_blob_status status; enum bt_mesh_blob_xfer_mode mode; uint64_t id; @@ -570,7 +570,7 @@ static int handle_xfer_cancel(const struct bt_mesh_model *mod, struct bt_mesh_ms struct net_buf_simple *buf) { enum bt_mesh_blob_status status = BT_MESH_BLOB_SUCCESS; - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; uint64_t id; id = net_buf_simple_pull_le64(buf); @@ -598,7 +598,7 @@ static int handle_block_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ struct net_buf_simple *buf) { enum bt_mesh_blob_status status; - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; switch (srv->phase) { case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK: @@ -628,7 +628,7 @@ static int handle_block_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ static int handle_block_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; enum bt_mesh_blob_status status; uint16_t block_number, chunk_size; int err; @@ -723,7 +723,7 @@ static int handle_block_start(const struct bt_mesh_model *mod, struct bt_mesh_ms static int handle_chunk(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; struct bt_mesh_blob_chunk chunk; size_t expected_size = 0; uint16_t idx; @@ -813,7 +813,7 @@ static int handle_chunk(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; LOG_DBG(""); @@ -849,7 +849,7 @@ const struct bt_mesh_model_op _bt_mesh_blob_srv_op[] = { static int blob_srv_init(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; srv->mod = mod; srv->state.ttl = BT_MESH_TTL_DEFAULT; @@ -865,7 +865,7 @@ static int blob_srv_settings_set(const struct bt_mesh_model *mod, const char *na size_t len_rd, settings_read_cb read_cb, void *cb_arg) { - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; ssize_t len; if (len_rd < offsetof(struct bt_mesh_blob_srv_state, blocks)) { @@ -905,7 +905,7 @@ static int blob_srv_settings_set(const struct bt_mesh_model *mod, const char *na static int blob_srv_start(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; int err = -ENOTSUP; if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { @@ -933,7 +933,7 @@ static int blob_srv_start(const struct bt_mesh_model *mod) static void blob_srv_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_srv *srv = *(mod->user_data); + struct bt_mesh_blob_srv *srv = mod->rt->user_data; phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; diff --git a/subsys/bluetooth/mesh/cfg_cli.c b/subsys/bluetooth/mesh/cfg_cli.c index 2f05fea2f15f178..aa762e9b906a1e1 100644 --- a/subsys/bluetooth/mesh/cfg_cli.c +++ b/subsys/bluetooth/mesh/cfg_cli.c @@ -1094,12 +1094,12 @@ static int cfg_cli_init(const struct bt_mesh_model *model) return -EINVAL; } - if (!*(model->user_data)) { + if (!model->rt->user_data) { LOG_ERR("No Configuration Client context provided"); return -EINVAL; } - cli = *(model->user_data); + cli = model->rt->user_data; cli->model = model; msg_timeout = CONFIG_BT_MESH_CFG_CLI_TIMEOUT; @@ -1108,7 +1108,7 @@ static int cfg_cli_init(const struct bt_mesh_model *model) * and remote keys are allowed to access this model. */ model->keys[0] = BT_MESH_KEY_DEV_ANY; - *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 5920ecd6dc10638..04374977421144b 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -1238,7 +1238,7 @@ static enum bt_mesh_walk mod_sub_list_visitor(const struct bt_mesh_model *mod, v int count = 0; int i; - if (*(mod->elem_idx) != visit->elem_idx) { + if (mod->rt->elem_idx != visit->elem_idx) { return BT_MESH_WALK_CONTINUE; } @@ -1257,7 +1257,7 @@ static enum bt_mesh_walk mod_sub_list_visitor(const struct bt_mesh_model *mod, v count++; } - LOG_DBG("sublist: model %u:%x: %u groups", *(mod->elem_idx), mod->id, count); + LOG_DBG("sublist: model %u:%x: %u groups", mod->rt->elem_idx, mod->id, count); return BT_MESH_WALK_CONTINUE; } @@ -1306,7 +1306,7 @@ static int mod_sub_get(const struct bt_mesh_model *model, net_buf_simple_add_le16(&msg, id); visit_ctx.msg = &msg; - visit_ctx.elem_idx = *(mod->elem_idx); + visit_ctx.elem_idx = mod->rt->elem_idx; bt_mesh_model_extensions_walk(mod, mod_sub_list_visitor, &visit_ctx); send_list: @@ -1365,7 +1365,7 @@ static int mod_sub_get_vnd(const struct bt_mesh_model *model, net_buf_simple_add_le16(&msg, id); visit_ctx.msg = &msg; - visit_ctx.elem_idx = *(mod->elem_idx); + visit_ctx.elem_idx = mod->rt->elem_idx; bt_mesh_model_extensions_walk(mod, mod_sub_list_visitor, &visit_ctx); send_list: @@ -1881,7 +1881,7 @@ static int mod_app_bind(const struct bt_mesh_model *model, } /* Some models only allow device key based access */ - if (*(mod->flags) & BT_MESH_MOD_DEVKEY_ONLY) { + if (mod->rt->flags & BT_MESH_MOD_DEVKEY_ONLY) { LOG_ERR("Client tried to bind AppKey to DevKey based model"); status = STATUS_CANNOT_BIND; goto send_status; @@ -2520,7 +2520,7 @@ static int cfg_srv_init(const struct bt_mesh_model *model) * device-key is allowed to access this model. */ model->keys[0] = BT_MESH_KEY_DEV_LOCAL; - *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } diff --git a/subsys/bluetooth/mesh/dfd_srv.c b/subsys/bluetooth/mesh/dfd_srv.c index 245052b58f8b3a5..54184acd9b88a7c 100644 --- a/subsys/bluetooth/mesh/dfd_srv.c +++ b/subsys/bluetooth/mesh/dfd_srv.c @@ -116,7 +116,7 @@ static int handle_receivers_add(const struct bt_mesh_model *mod, struct bt_mesh_ struct net_buf_simple *buf) { enum bt_mesh_dfd_status status = BT_MESH_DFD_SUCCESS; - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; if (buf->len % 3) { return -EINVAL; @@ -146,7 +146,7 @@ static int handle_receivers_add(const struct bt_mesh_model *mod, struct bt_mesh_ static int handle_receivers_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; receivers_status_rsp(srv, ctx, bt_mesh_dfd_srv_receivers_delete_all(srv)); @@ -156,7 +156,7 @@ static int handle_receivers_delete_all(const struct bt_mesh_model *mod, struct b static int handle_receivers_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; uint16_t first, cnt; uint8_t progress; int i; @@ -226,7 +226,7 @@ static int handle_capabilities_get(const struct bt_mesh_model *mod, struct bt_me net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE - size); #ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; if (srv->oob_schemes.count > 0) { net_buf_simple_add_u8(&rsp, 1); @@ -271,7 +271,7 @@ static void status_rsp(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); @@ -281,7 +281,7 @@ static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *c static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; struct bt_mesh_dfd_start_params params; uint8_t byte; @@ -314,7 +314,7 @@ static int handle_suspend(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; status_rsp(srv, ctx, bt_mesh_dfd_srv_suspend(srv)); @@ -324,7 +324,7 @@ static int handle_suspend(const struct bt_mesh_model *mod, static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; bt_mesh_dfd_srv_cancel(srv, ctx); @@ -334,7 +334,7 @@ static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; status_rsp(srv, ctx, bt_mesh_dfd_srv_apply(srv)); @@ -396,7 +396,7 @@ static void upload_status_rsp(struct bt_mesh_dfd_srv *srv, static int handle_upload_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); @@ -441,7 +441,7 @@ static inline int set_upload_fwid(struct bt_mesh_dfd_srv *srv, struct bt_mesh_ms static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; size_t meta_len, fwid_len, size; const uint8_t *meta, *fwid; uint16_t timeout_base; @@ -563,7 +563,7 @@ static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_m static int handle_upload_start_oob(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; uint8_t uri_len; uint8_t *uri; uint16_t fwid_len; @@ -654,7 +654,7 @@ static int handle_upload_start_oob(const struct bt_mesh_model *mod, struct bt_me static int handle_upload_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; #ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD @@ -693,7 +693,7 @@ static void fw_status_rsp(struct bt_mesh_dfd_srv *srv, static int handle_fw_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; struct bt_mesh_dfu_slot *slot; const uint8_t *fwid; size_t fwid_len; @@ -717,7 +717,7 @@ static int handle_fw_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx static int handle_fw_get_by_index(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; const struct bt_mesh_dfu_slot *slot; uint16_t idx; @@ -738,7 +738,7 @@ static int handle_fw_get_by_index(const struct bt_mesh_model *mod, struct bt_mes static int handle_fw_delete(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; const uint8_t *fwid; size_t fwid_len; @@ -767,7 +767,7 @@ static enum bt_mesh_dfu_iter slot_del_cb(const struct bt_mesh_dfu_slot *slot, static int handle_fw_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; fw_status_rsp(srv, ctx, bt_mesh_dfd_srv_fw_delete_all(srv), 0xffff, NULL, 0); @@ -925,7 +925,7 @@ const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb = { static int dfd_srv_init(const struct bt_mesh_model *mod) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; srv->mod = mod; @@ -938,7 +938,7 @@ static int dfd_srv_init(const struct bt_mesh_model *mod) static void dfd_srv_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_dfd_srv *srv = *(mod->user_data); + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; diff --git a/subsys/bluetooth/mesh/dfu_cli.c b/subsys/bluetooth/mesh/dfu_cli.c index 70b03f4e814dc31..2345ef8e33b5524 100644 --- a/subsys/bluetooth/mesh/dfu_cli.c +++ b/subsys/bluetooth/mesh/dfu_cli.c @@ -702,7 +702,7 @@ static void cancelled(struct bt_mesh_blob_cli *b) static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_cli *cli = *(mod->user_data); + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; enum bt_mesh_dfu_status status; enum bt_mesh_dfu_phase phase; struct bt_mesh_dfu_target *target; @@ -828,7 +828,7 @@ static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_cli *cli = *(mod->user_data); + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; struct bt_mesh_dfu_target *target; enum bt_mesh_dfu_iter it = BT_MESH_DFU_ITER_CONTINUE; uint8_t img_cnt, idx; @@ -927,7 +927,7 @@ static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_ms static int handle_metadata_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_cli *cli = *(mod->user_data); + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; struct bt_mesh_dfu_metadata_status *rsp = cli->req.params; uint8_t hdr, idx; @@ -963,9 +963,9 @@ const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[] = { static int dfu_cli_init(const struct bt_mesh_model *mod) { - struct bt_mesh_dfu_cli *cli = *(mod->user_data); + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; - if (*(mod->elem_idx) != 0) { + if (mod->rt->elem_idx != 0) { LOG_ERR("DFU update client must be instantiated on first elem"); return -EINVAL; } @@ -983,7 +983,7 @@ static int dfu_cli_init(const struct bt_mesh_model *mod) static void dfu_cli_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_dfu_cli *cli = *(mod->user_data); + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; cli->req.type = REQ_NONE; cli->req.addr = BT_MESH_ADDR_UNASSIGNED; diff --git a/subsys/bluetooth/mesh/dfu_srv.c b/subsys/bluetooth/mesh/dfu_srv.c index edd61e6da40b35e..f8e87e29da95072 100644 --- a/subsys/bluetooth/mesh/dfu_srv.c +++ b/subsys/bluetooth/mesh/dfu_srv.c @@ -128,7 +128,7 @@ static void verify(struct bt_mesh_dfu_srv *srv) static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = *(mod->user_data); + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; uint8_t idx, limit; if (srv->update.phase == BT_MESH_DFU_PHASE_APPLYING) { @@ -190,7 +190,7 @@ static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_c static int handle_metadata_check(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = *(mod->user_data); + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; enum bt_mesh_dfu_status status; enum bt_mesh_dfu_effect effect; uint8_t idx; @@ -242,7 +242,7 @@ static void update_status_rsp(struct bt_mesh_dfu_srv *srv, static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = *(mod->user_data); + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; LOG_DBG(""); @@ -265,7 +265,7 @@ static inline bool is_active_update(struct bt_mesh_dfu_srv *srv, uint8_t idx, static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = *(mod->user_data); + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; const struct bt_mesh_blob_io *io; uint16_t timeout_base, meta_checksum; enum bt_mesh_dfu_status status; @@ -374,7 +374,7 @@ static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = *(mod->user_data); + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; if (srv->update.idx == UPDATE_IDX_NONE) { goto rsp; @@ -395,7 +395,7 @@ static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = *(mod->user_data); + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; static const struct bt_mesh_send_cb send_cb = { .start = apply_rsp_sending, .end = apply_rsp_sent, @@ -437,7 +437,7 @@ const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[] = { static int dfu_srv_init(const struct bt_mesh_model *mod) { - struct bt_mesh_dfu_srv *srv = *(mod->user_data); + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; srv->mod = mod; srv->update.idx = UPDATE_IDX_NONE; @@ -459,7 +459,7 @@ static int dfu_srv_settings_set(const struct bt_mesh_model *mod, const char *nam size_t len_rd, settings_read_cb read_cb, void *cb_arg) { - struct bt_mesh_dfu_srv *srv = *(mod->user_data); + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; ssize_t len; if (len_rd < sizeof(srv->update)) { @@ -486,7 +486,7 @@ static int dfu_srv_settings_set(const struct bt_mesh_model *mod, const char *nam static void dfu_srv_reset(const struct bt_mesh_model *mod) { - struct bt_mesh_dfu_srv *srv = *(mod->user_data); + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; srv->update.phase = BT_MESH_DFU_PHASE_IDLE; erase_state(srv); diff --git a/subsys/bluetooth/mesh/health_cli.c b/subsys/bluetooth/mesh/health_cli.c index d34d869e243ec74..16d2a79a53ac0ae 100644 --- a/subsys/bluetooth/mesh/health_cli.c +++ b/subsys/bluetooth/mesh/health_cli.c @@ -40,7 +40,7 @@ static int health_fault_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_cli *cli = *(model->user_data); + struct bt_mesh_health_cli *cli = model->rt->user_data; struct health_fault_param *param; uint8_t test_id; uint16_t cid; @@ -93,7 +93,7 @@ static int health_current_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_cli *cli = *(model->user_data); + struct bt_mesh_health_cli *cli = model->rt->user_data; uint8_t test_id; uint16_t cid; @@ -121,7 +121,7 @@ static int health_period_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_cli *cli = *(model->user_data); + struct bt_mesh_health_cli *cli = model->rt->user_data; struct health_period_param *param; uint8_t divisor; @@ -155,7 +155,7 @@ static int health_attention_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_cli *cli = *(model->user_data); + struct bt_mesh_health_cli *cli = model->rt->user_data; struct health_attention_param *param; uint8_t attention; @@ -404,7 +404,7 @@ void bt_mesh_health_cli_timeout_set(int32_t timeout) static int health_cli_init(const struct bt_mesh_model *model) { - struct bt_mesh_health_cli *cli = *(model->user_data); + struct bt_mesh_health_cli *cli = model->rt->user_data; LOG_DBG("primary %u", bt_mesh_model_in_primary(model)); @@ -425,7 +425,7 @@ static int health_cli_init(const struct bt_mesh_model *model) static void health_cli_reset(const struct bt_mesh_model *model) { - struct bt_mesh_health_cli *cli = *(model->user_data); + struct bt_mesh_health_cli *cli = model->rt->user_data; net_buf_simple_reset(cli->pub.msg); } diff --git a/subsys/bluetooth/mesh/health_srv.c b/subsys/bluetooth/mesh/health_srv.c index 4ae55266ebfbb67..5292967d4699c8f 100644 --- a/subsys/bluetooth/mesh/health_srv.c +++ b/subsys/bluetooth/mesh/health_srv.c @@ -35,7 +35,7 @@ static void health_get_registered(const struct bt_mesh_model *mod, uint16_t company_id, struct net_buf_simple *msg) { - struct bt_mesh_health_srv *srv = *(mod->user_data); + struct bt_mesh_health_srv *srv = mod->rt->user_data; uint8_t *test_id; LOG_DBG("Company ID 0x%04x", company_id); @@ -67,7 +67,7 @@ static void health_get_registered(const struct bt_mesh_model *mod, static size_t health_get_current(const struct bt_mesh_model *mod, struct net_buf_simple *msg) { - struct bt_mesh_health_srv *srv = *(mod->user_data); + struct bt_mesh_health_srv *srv = mod->rt->user_data; const struct bt_mesh_comp *comp; uint8_t *test_id, *company_ptr; uint16_t company_id; @@ -129,7 +129,7 @@ static int health_fault_clear_unrel(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_srv *srv = *(model->user_data); + struct bt_mesh_health_srv *srv = model->rt->user_data; uint16_t company_id; company_id = net_buf_simple_pull_le16(buf); @@ -148,7 +148,7 @@ static int health_fault_clear(const struct bt_mesh_model *model, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX); - struct bt_mesh_health_srv *srv = *(model->user_data); + struct bt_mesh_health_srv *srv = model->rt->user_data; uint16_t company_id; company_id = net_buf_simple_pull_le16(buf); @@ -177,7 +177,7 @@ static int health_fault_test_unrel(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_health_srv *srv = *(model->user_data); + struct bt_mesh_health_srv *srv = model->rt->user_data; uint16_t company_id; uint8_t test_id; @@ -198,7 +198,7 @@ static int health_fault_test(const struct bt_mesh_model *model, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX); - struct bt_mesh_health_srv *srv = *(model->user_data); + struct bt_mesh_health_srv *srv = model->rt->user_data; uint16_t company_id; uint8_t test_id; @@ -233,7 +233,7 @@ static int send_attention_status(const struct bt_mesh_model *model, { /* Needed size: opcode (2 bytes) + msg + MIC */ BT_MESH_MODEL_BUF_DEFINE(msg, OP_ATTENTION_STATUS, 1); - struct bt_mesh_health_srv *srv = *(model->user_data); + struct bt_mesh_health_srv *srv = model->rt->user_data; uint8_t time; time = k_ticks_to_ms_floor32( @@ -420,7 +420,7 @@ static void attention_off(struct k_work *work) static int health_srv_init(const struct bt_mesh_model *model) { - struct bt_mesh_health_srv *srv = *(model->user_data); + struct bt_mesh_health_srv *srv = model->rt->user_data; if (!srv) { LOG_ERR("No Health Server context provided"); @@ -462,7 +462,7 @@ void bt_mesh_attention(const struct bt_mesh_model *model, uint8_t time) model = srv->model; } else { - srv = *(model->user_data); + srv = model->rt->user_data; } if ((time > 0) && srv->cb && srv->cb->attn_on) { diff --git a/subsys/bluetooth/mesh/large_comp_data_cli.c b/subsys/bluetooth/mesh/large_comp_data_cli.c index dc1152f415f1ede..3aa688523f9ba9c 100644 --- a/subsys/bluetooth/mesh/large_comp_data_cli.c +++ b/subsys/bluetooth/mesh/large_comp_data_cli.c @@ -108,9 +108,9 @@ static int large_comp_data_cli_init(const struct bt_mesh_model *model) } model->keys[0] = BT_MESH_KEY_DEV_ANY; - *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; - cli = *(model->user_data); + cli = model->rt->user_data; cli->model = model; msg_timeout = 5000; diff --git a/subsys/bluetooth/mesh/large_comp_data_srv.c b/subsys/bluetooth/mesh/large_comp_data_srv.c index 5d724b9f0837004..f47947b9b92a965 100644 --- a/subsys/bluetooth/mesh/large_comp_data_srv.c +++ b/subsys/bluetooth/mesh/large_comp_data_srv.c @@ -177,7 +177,7 @@ static int large_comp_data_srv_init(const struct bt_mesh_model *model) /* Large Composition Data Server model shall use the device key */ model->keys[0] = BT_MESH_KEY_DEV; - *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; srv.model = model; diff --git a/subsys/bluetooth/mesh/od_priv_proxy_cli.c b/subsys/bluetooth/mesh/od_priv_proxy_cli.c index f2844d2ecc68ba2..bd4e796b8e276b1 100644 --- a/subsys/bluetooth/mesh/od_priv_proxy_cli.c +++ b/subsys/bluetooth/mesh/od_priv_proxy_cli.c @@ -100,10 +100,10 @@ static int on_demand_proxy_cli_init(const struct bt_mesh_model *mod) return -EINVAL; } - cli = *(mod->user_data); + cli = mod->rt->user_data; cli->model = mod; mod->keys[0] = BT_MESH_KEY_DEV_ANY; - *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + mod->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; msg_timeout = CONFIG_BT_MESH_OD_PRIV_PROXY_CLI_TIMEOUT; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); diff --git a/subsys/bluetooth/mesh/od_priv_proxy_srv.c b/subsys/bluetooth/mesh/od_priv_proxy_srv.c index e671a80e9de6662..e54ed88fa0cfa98 100644 --- a/subsys/bluetooth/mesh/od_priv_proxy_srv.c +++ b/subsys/bluetooth/mesh/od_priv_proxy_srv.c @@ -98,7 +98,7 @@ static int od_priv_proxy_srv_init(const struct bt_mesh_model *mod) } mod->keys[0] = BT_MESH_KEY_DEV_LOCAL; - *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + mod->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) { bt_mesh_model_extend(mod, priv_beacon_srv); diff --git a/subsys/bluetooth/mesh/priv_beacon_cli.c b/subsys/bluetooth/mesh/priv_beacon_cli.c index fd48ef0583b35ea..0611aeb77057155 100644 --- a/subsys/bluetooth/mesh/priv_beacon_cli.c +++ b/subsys/bluetooth/mesh/priv_beacon_cli.c @@ -141,11 +141,11 @@ static int priv_beacon_cli_init(const struct bt_mesh_model *model) return -EINVAL; } - cli = *(model->user_data); + cli = model->rt->user_data; cli->model = model; msg_timeout = 2 * MSEC_PER_SEC; model->keys[0] = BT_MESH_KEY_DEV_ANY; - *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); diff --git a/subsys/bluetooth/mesh/rpr_cli.c b/subsys/bluetooth/mesh/rpr_cli.c index 7a1dd493b875dfe..cbb92e75b40cc93 100644 --- a/subsys/bluetooth/mesh/rpr_cli.c +++ b/subsys/bluetooth/mesh/rpr_cli.c @@ -94,7 +94,7 @@ static int handle_extended_scan_report(const struct bt_mesh_model *mod, struct b struct net_buf_simple *buf) { struct bt_mesh_rpr_node srv = RPR_NODE(ctx); - struct bt_mesh_rpr_cli *cli = *(mod->user_data); + struct bt_mesh_rpr_cli *cli = mod->rt->user_data; struct bt_mesh_rpr_unprov dev = { 0 }; enum bt_mesh_rpr_status status; bool found_dev = false; @@ -127,7 +127,7 @@ static int handle_link_report(const struct bt_mesh_model *mod, struct bt_mesh_ms struct net_buf_simple *buf) { struct bt_mesh_rpr_node srv = RPR_NODE(ctx); - struct bt_mesh_rpr_cli *cli = *(mod->user_data); + struct bt_mesh_rpr_cli *cli = mod->rt->user_data; struct bt_mesh_rpr_link link; uint8_t reason = PROV_BEARER_LINK_STATUS_SUCCESS; @@ -164,7 +164,7 @@ static int handle_link_report(const struct bt_mesh_model *mod, struct bt_mesh_ms static int handle_link_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = *(mod->user_data); + struct bt_mesh_rpr_cli *cli = mod->rt->user_data; struct bt_mesh_rpr_node srv = RPR_NODE(ctx); struct bt_mesh_rpr_link *rsp; struct bt_mesh_rpr_link link; @@ -198,7 +198,7 @@ static int handle_link_status(const struct bt_mesh_model *mod, struct bt_mesh_ms static int handle_pdu_outbound_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = *(mod->user_data); + struct bt_mesh_rpr_cli *cli = mod->rt->user_data; struct bt_mesh_rpr_node srv = RPR_NODE(ctx); void *cb_data; uint8_t num; @@ -229,7 +229,7 @@ static int handle_pdu_outbound_report(const struct bt_mesh_model *mod, struct bt static int handle_pdu_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = *(mod->user_data); + struct bt_mesh_rpr_cli *cli = mod->rt->user_data; struct bt_mesh_rpr_node srv = RPR_NODE(ctx); struct pb_remote_ctx cb_ctx = { cli, @@ -260,7 +260,7 @@ static int handle_pdu_report(const struct bt_mesh_model *mod, struct bt_mesh_msg static int handle_scan_caps_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = *(mod->user_data); + struct bt_mesh_rpr_cli *cli = mod->rt->user_data; struct bt_mesh_rpr_node srv = RPR_NODE(ctx); struct bt_mesh_rpr_caps *caps; @@ -284,7 +284,7 @@ static int handle_scan_caps_status(const struct bt_mesh_model *mod, struct bt_me static int handle_scan_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = *(mod->user_data); + struct bt_mesh_rpr_cli *cli = mod->rt->user_data; struct bt_mesh_rpr_node srv = RPR_NODE(ctx); struct bt_mesh_rpr_unprov dev = { 0 }; @@ -316,7 +316,7 @@ static int handle_scan_report(const struct bt_mesh_model *mod, struct bt_mesh_ms static int handle_scan_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_rpr_cli *cli = *(mod->user_data); + struct bt_mesh_rpr_cli *cli = mod->rt->user_data; struct bt_mesh_rpr_scan_status *status; struct bt_mesh_rpr_node srv = RPR_NODE(ctx); @@ -363,13 +363,13 @@ static void link_timeout(struct k_work *work) static int rpr_cli_init(const struct bt_mesh_model *mod) { - if (*(mod->elem_idx)) { + if (mod->rt->elem_idx) { LOG_ERR("Remote provisioning client must be initialized " "on first element"); return -EINVAL; } - struct bt_mesh_rpr_cli *cli = *(mod->user_data); + struct bt_mesh_rpr_cli *cli = mod->rt->user_data; cli->mod = mod; cli->link.time = LINK_TIMEOUT_SECONDS_DEFAULT; @@ -378,7 +378,7 @@ static int rpr_cli_init(const struct bt_mesh_model *mod) bt_mesh_msg_ack_ctx_init(&cli->prov_ack_ctx); k_work_init_delayable(&cli->link.timeout, link_timeout); mod->keys[0] = BT_MESH_KEY_DEV_ANY; - *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + mod->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } diff --git a/subsys/bluetooth/mesh/rpr_srv.c b/subsys/bluetooth/mesh/rpr_srv.c index e008aa0a8b13fcf..9813842a367d0ab 100644 --- a/subsys/bluetooth/mesh/rpr_srv.c +++ b/subsys/bluetooth/mesh/rpr_srv.c @@ -1305,7 +1305,7 @@ static struct bt_le_scan_cb scan_cb = { static int rpr_srv_init(const struct bt_mesh_model *mod) { - if (*(mod->elem_idx) || srv.mod) { + if (mod->rt->elem_idx || srv.mod) { LOG_ERR("Remote provisioning server must be initialized " "on first element"); return -EINVAL; @@ -1320,7 +1320,7 @@ static int rpr_srv_init(const struct bt_mesh_model *mod) k_work_init(&srv.link.report, link_report_send_and_clear); bt_le_scan_cb_register(&scan_cb); mod->keys[0] = BT_MESH_KEY_DEV_LOCAL; - *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + mod->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } diff --git a/subsys/bluetooth/mesh/sar_cfg_cli.c b/subsys/bluetooth/mesh/sar_cfg_cli.c index aaf07451e1d7709..52239c95be464db 100644 --- a/subsys/bluetooth/mesh/sar_cfg_cli.c +++ b/subsys/bluetooth/mesh/sar_cfg_cli.c @@ -94,17 +94,17 @@ static int bt_mesh_sar_cfg_cli_init(const struct bt_mesh_model *model) return -EINVAL; } - if (!*(model->user_data)) { + if (!model->rt->user_data) { LOG_ERR("No SAR Configuration Client context provided"); return -EINVAL; } - cli = *(model->user_data); + cli = model->rt->user_data; cli->model = model; cli->timeout = 2 * MSEC_PER_SEC; model->keys[0] = BT_MESH_KEY_DEV_ANY; - *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); @@ -115,7 +115,7 @@ static void bt_mesh_sar_cfg_cli_reset(const struct bt_mesh_model *model) { struct bt_mesh_sar_cfg_cli *model_cli; - model_cli = *(model->user_data); + model_cli = model->rt->user_data; bt_mesh_msg_ack_ctx_clear(&model_cli->ack_ctx); } diff --git a/subsys/bluetooth/mesh/sar_cfg_srv.c b/subsys/bluetooth/mesh/sar_cfg_srv.c index 59ec36907c59550..2943ce02ddde972 100644 --- a/subsys/bluetooth/mesh/sar_cfg_srv.c +++ b/subsys/bluetooth/mesh/sar_cfg_srv.c @@ -155,7 +155,7 @@ static int sar_cfg_srv_init(const struct bt_mesh_model *model) * device-key is allowed to access this model. */ model->keys[0] = BT_MESH_KEY_DEV_LOCAL; - *(model->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } diff --git a/subsys/bluetooth/mesh/shell/blob.c b/subsys/bluetooth/mesh/shell/blob.c index ed0f4fbd4584e6d..a6888da42704137 100644 --- a/subsys/bluetooth/mesh/shell/blob.c +++ b/subsys/bluetooth/mesh/shell/blob.c @@ -351,7 +351,7 @@ static int cmd_tx(const struct shell *sh, size_t argc, char *argv[]) "pull", blob_cli_xfer.xfer.size, group); - err = bt_mesh_blob_cli_send((struct bt_mesh_blob_cli *)*(mod_cli->user_data), + err = bt_mesh_blob_cli_send((struct bt_mesh_blob_cli *)mod_cli->rt->user_data, &blob_cli_xfer.inputs, &blob_cli_xfer.xfer, bt_mesh_shell_blob_io); if (err) { @@ -421,7 +421,7 @@ static int cmd_caps(const struct shell *sh, size_t argc, char *argv[]) blob_cli_inputs_prepare(group); - err = bt_mesh_blob_cli_caps_get((struct bt_mesh_blob_cli *)*(mod_cli->user_data), + err = bt_mesh_blob_cli_caps_get((struct bt_mesh_blob_cli *)mod_cli->rt->user_data, &blob_cli_xfer.inputs); if (err) { shell_print(sh, "Boundary check start failed (err: %d)", err); @@ -438,7 +438,7 @@ static int cmd_tx_cancel(const struct shell *sh, size_t argc, } shell_print(sh, "Cancelling transfer"); - bt_mesh_blob_cli_cancel((struct bt_mesh_blob_cli *)*(mod_cli->user_data)); + bt_mesh_blob_cli_cancel((struct bt_mesh_blob_cli *)mod_cli->rt->user_data); return 0; } @@ -465,7 +465,7 @@ static int cmd_tx_get(const struct shell *sh, size_t argc, char *argv[]) blob_cli_inputs_prepare(group); - err = bt_mesh_blob_cli_xfer_progress_get((struct bt_mesh_blob_cli *)*(mod_cli->user_data), + err = bt_mesh_blob_cli_xfer_progress_get((struct bt_mesh_blob_cli *)mod_cli->rt->user_data, &blob_cli_xfer.inputs); if (err) { shell_print(sh, "ERR %d", err); @@ -482,7 +482,7 @@ static int cmd_tx_suspend(const struct shell *sh, size_t argc, } shell_print(sh, "Suspending transfer"); - bt_mesh_blob_cli_suspend((struct bt_mesh_blob_cli *)*(mod_cli->user_data)); + bt_mesh_blob_cli_suspend((struct bt_mesh_blob_cli *)mod_cli->rt->user_data); return 0; } @@ -494,7 +494,7 @@ static int cmd_tx_resume(const struct shell *sh, size_t argc, char *argv[]) } shell_print(sh, "Resuming transfer"); - bt_mesh_blob_cli_resume((struct bt_mesh_blob_cli *)*(mod_cli->user_data)); + bt_mesh_blob_cli_resume((struct bt_mesh_blob_cli *)mod_cli->rt->user_data); return 0; } @@ -530,7 +530,7 @@ static int cmd_rx(const struct shell *sh, size_t argc, char *argv[]) } shell_print(sh, "Receive BLOB 0x%x", id); - err = bt_mesh_blob_srv_recv((struct bt_mesh_blob_srv *)*(mod_srv->user_data), + err = bt_mesh_blob_srv_recv((struct bt_mesh_blob_srv *)mod_srv->rt->user_data, id, bt_mesh_shell_blob_io, BT_MESH_TTL_MAX, timeout_base); if (err) { shell_print(sh, "BLOB RX setup failed (%d)", err); @@ -548,7 +548,7 @@ static int cmd_rx_cancel(const struct shell *sh, size_t argc, char *argv[]) } shell_print(sh, "Cancelling BLOB rx"); - err = bt_mesh_blob_srv_cancel((struct bt_mesh_blob_srv *)*(mod_srv->user_data)); + err = bt_mesh_blob_srv_cancel((struct bt_mesh_blob_srv *)mod_srv->rt->user_data); if (err) { shell_print(sh, "BLOB cancel failed (%d)", err); } diff --git a/subsys/bluetooth/mesh/shell/dfd.c b/subsys/bluetooth/mesh/shell/dfd.c index 464a5340342b244..4b3d49702822c08 100644 --- a/subsys/bluetooth/mesh/shell/dfd.c +++ b/subsys/bluetooth/mesh/shell/dfd.c @@ -70,7 +70,7 @@ static int cmd_dfd_receivers_add(const struct shell *sh, size_t argc, char *argv return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; if (bt_mesh_dfu_cli_is_busy(&dfd_srv->dfu)) { print_receivers_status(sh, dfd_srv, @@ -122,7 +122,7 @@ static int cmd_dfd_receivers_delete_all(const struct shell *sh, size_t argc, cha return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_receivers_delete_all( dfd_srv); @@ -142,7 +142,7 @@ static int cmd_dfd_receivers_get(const struct shell *sh, size_t argc, char *argv return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; int err = 0; uint16_t first = shell_strtoul(argv[1], 0, &err); @@ -197,7 +197,7 @@ static int cmd_dfd_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; print_dfd_status(sh, dfd_srv, BT_MESH_DFD_SUCCESS); @@ -210,7 +210,7 @@ static int cmd_dfd_start(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; struct bt_mesh_dfd_start_params params; int err = 0; @@ -267,7 +267,7 @@ static int cmd_dfd_suspend(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_suspend(dfd_srv); @@ -285,7 +285,7 @@ static int cmd_dfd_cancel(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_cancel(dfd_srv, NULL); @@ -303,7 +303,7 @@ static int cmd_dfd_apply(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_apply(dfd_srv); @@ -364,7 +364,7 @@ static int cmd_dfd_fw_delete(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; uint8_t fwid_buf[CONFIG_BT_MESH_DFU_FWID_MAXLEN]; size_t hexlen = strlen(argv[1]); @@ -394,7 +394,7 @@ static int cmd_dfd_fw_delete_all(const struct shell *sh, size_t argc, char *argv return -ENODEV; } - struct bt_mesh_dfd_srv *dfd_srv = *(mod->user_data); + struct bt_mesh_dfd_srv *dfd_srv = mod->rt->user_data; enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_fw_delete_all(dfd_srv); diff --git a/subsys/bluetooth/mesh/shell/dfu.c b/subsys/bluetooth/mesh/shell/dfu.c index 22c60dc17c88b1b..6b7df4a8bd499ef 100644 --- a/subsys/bluetooth/mesh/shell/dfu.c +++ b/subsys/bluetooth/mesh/shell/dfu.c @@ -587,7 +587,7 @@ static int cmd_dfu_target_state(const struct shell *sh, size_t argc, char *argv[ return -ENODEV; } - err = bt_mesh_dfu_cli_status_get((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), + err = bt_mesh_dfu_cli_status_get((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data, &ctx, &rsp); if (err) { shell_print(sh, "Failed getting target status (err: %d)", @@ -654,7 +654,7 @@ static int cmd_dfu_target_imgs(const struct shell *sh, size_t argc, char *argv[] shell_print(sh, "Requesting DFU images in 0x%04x", bt_mesh_shell_target_ctx.dst); - err = bt_mesh_dfu_cli_imgs_get((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), + err = bt_mesh_dfu_cli_imgs_get((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data, &ctx, dfu_img_cb, NULL, img_cnt); if (err) { shell_print(sh, "Request failed (err: %d)", err); @@ -694,7 +694,7 @@ static int cmd_dfu_target_check(const struct shell *sh, size_t argc, char *argv[ return 0; } - err = bt_mesh_dfu_cli_metadata_check((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), + err = bt_mesh_dfu_cli_metadata_check((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data, &ctx, img_idx, slot, &rsp); if (err) { shell_print(sh, "Metadata check failed. err: %d", err); @@ -765,7 +765,7 @@ static int cmd_dfu_send(const struct shell *sh, size_t argc, char *argv[]) dfu_tx.inputs.app_idx = bt_mesh_shell_target_ctx.app_idx; dfu_tx.inputs.ttl = BT_MESH_TTL_DEFAULT; - err = bt_mesh_dfu_cli_send((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), + err = bt_mesh_dfu_cli_send((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data, &dfu_tx.inputs, bt_mesh_shell_blob_io, &xfer); if (err) { shell_print(sh, "Failed (err: %d)", err); @@ -800,7 +800,7 @@ static int cmd_dfu_tx_cancel(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Cancelling DFU"); } - err = bt_mesh_dfu_cli_cancel((struct bt_mesh_dfu_cli *)*(mod_cli->user_data), + err = bt_mesh_dfu_cli_cancel((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data, (argc == 2) ? &ctx : NULL); if (err) { shell_print(sh, "Failed (err: %d)", err); @@ -819,7 +819,7 @@ static int cmd_dfu_apply(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Applying DFU"); - err = bt_mesh_dfu_cli_apply((struct bt_mesh_dfu_cli *)*(mod_cli->user_data)); + err = bt_mesh_dfu_cli_apply((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data); if (err) { shell_print(sh, "Failed (err: %d)", err); } @@ -837,7 +837,7 @@ static int cmd_dfu_confirm(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Confirming DFU"); - err = bt_mesh_dfu_cli_confirm((struct bt_mesh_dfu_cli *)*(mod_cli->user_data)); + err = bt_mesh_dfu_cli_confirm((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data); if (err) { shell_print(sh, "Failed (err: %d)", err); } @@ -855,7 +855,7 @@ static int cmd_dfu_suspend(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Suspending DFU"); - err = bt_mesh_dfu_cli_suspend((struct bt_mesh_dfu_cli *)*(mod_cli->user_data)); + err = bt_mesh_dfu_cli_suspend((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data); if (err) { shell_print(sh, "Failed (err: %d)", err); } @@ -873,7 +873,7 @@ static int cmd_dfu_resume(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Resuming DFU"); - err = bt_mesh_dfu_cli_resume((struct bt_mesh_dfu_cli *)*(mod_cli->user_data)); + err = bt_mesh_dfu_cli_resume((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data); if (err) { shell_print(sh, "Failed (err: %d)", err); } @@ -888,7 +888,7 @@ static int cmd_dfu_tx_progress(const struct shell *sh, size_t argc, char *argv[] } shell_print(sh, "DFU progress: %u %%", - bt_mesh_dfu_cli_progress((struct bt_mesh_dfu_cli *)*(mod_cli->user_data))); + bt_mesh_dfu_cli_progress((struct bt_mesh_dfu_cli *)mod_cli->rt->user_data)); return 0; } @@ -904,7 +904,7 @@ static int cmd_dfu_applied(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - bt_mesh_dfu_srv_applied((struct bt_mesh_dfu_srv *)*(mod_srv->user_data)); + bt_mesh_dfu_srv_applied((struct bt_mesh_dfu_srv *)mod_srv->rt->user_data); return 0; } @@ -914,7 +914,7 @@ static int cmd_dfu_rx_cancel(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - bt_mesh_dfu_srv_cancel((struct bt_mesh_dfu_srv *)*(mod_srv->user_data)); + bt_mesh_dfu_srv_cancel((struct bt_mesh_dfu_srv *)mod_srv->rt->user_data); return 0; } @@ -925,7 +925,7 @@ static int cmd_dfu_rx_progress(const struct shell *sh, size_t argc, char *argv[] } shell_print(sh, "DFU progress: %u %%", - bt_mesh_dfu_srv_progress((struct bt_mesh_dfu_srv *)*(mod_srv->user_data))); + bt_mesh_dfu_srv_progress((struct bt_mesh_dfu_srv *)mod_srv->rt->user_data)); return 0; } diff --git a/subsys/bluetooth/mesh/shell/health.c b/subsys/bluetooth/mesh/shell/health.c index a0ca150ae152e81..21480c6a66e97db 100644 --- a/subsys/bluetooth/mesh/shell/health.c +++ b/subsys/bluetooth/mesh/shell/health.c @@ -40,7 +40,7 @@ static int cmd_fault_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_health_cli *cli = *(mod->user_data); + struct bt_mesh_health_cli *cli = mod->rt->user_data; struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t faults[32]; @@ -74,7 +74,7 @@ static int fault_clear(const struct shell *sh, size_t argc, char *argv[], bool a return -ENODEV; } - struct bt_mesh_health_cli *cli = *(mod->user_data); + struct bt_mesh_health_cli *cli = mod->rt->user_data; struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t test_id; @@ -126,7 +126,7 @@ static int fault_test(const struct shell *sh, size_t argc, char *argv[], bool ac return -ENODEV; } - struct bt_mesh_health_cli *cli = *(mod->user_data); + struct bt_mesh_health_cli *cli = mod->rt->user_data; struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t test_id; @@ -179,7 +179,7 @@ static int cmd_period_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_health_cli *cli = *(mod->user_data); + struct bt_mesh_health_cli *cli = mod->rt->user_data; struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t divisor; @@ -201,7 +201,7 @@ static int period_set(const struct shell *sh, size_t argc, char *argv[], bool ac return -ENODEV; } - struct bt_mesh_health_cli *cli = *(mod->user_data); + struct bt_mesh_health_cli *cli = mod->rt->user_data; struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t divisor; @@ -251,7 +251,7 @@ static int cmd_attention_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - struct bt_mesh_health_cli *cli = *(mod->user_data); + struct bt_mesh_health_cli *cli = mod->rt->user_data; struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t attention; @@ -273,7 +273,7 @@ static int attention_set(const struct shell *sh, size_t argc, char *argv[], bool return -ENODEV; } - struct bt_mesh_health_cli *cli = *(mod->user_data); + struct bt_mesh_health_cli *cli = mod->rt->user_data; struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_APP(bt_mesh_shell_target_ctx.app_idx, bt_mesh_shell_target_ctx.dst); uint8_t attention; diff --git a/subsys/bluetooth/mesh/shell/rpr.c b/subsys/bluetooth/mesh/shell/rpr.c index 1ddb11f497dc8e2..870fc7c5d37ebd3 100644 --- a/subsys/bluetooth/mesh/shell/rpr.c +++ b/subsys/bluetooth/mesh/shell/rpr.c @@ -108,7 +108,7 @@ static int cmd_scan(const struct shell *sh, size_t argc, char *argv[]) hex2bin(argv[2], strlen(argv[2]), uuid, 16); } - err = bt_mesh_rpr_scan_start((struct bt_mesh_rpr_cli *)*(mod->user_data), + err = bt_mesh_rpr_scan_start((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, argc > 2 ? uuid : NULL, timeout, BT_MESH_RPR_SCAN_MAX_DEVS_ANY, &rsp); if (err) { @@ -153,7 +153,7 @@ static int cmd_scan_ext(const struct shell *sh, size_t argc, char *argv[]) return err; } - err = bt_mesh_rpr_scan_start_ext((struct bt_mesh_rpr_cli *)*(mod->user_data), + err = bt_mesh_rpr_scan_start_ext((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, uuid, timeout, ad_types, (argc - 3)); if (err) { @@ -189,7 +189,7 @@ static int cmd_scan_srv(const struct shell *sh, size_t argc, char *argv[]) return err; } - err = bt_mesh_rpr_scan_start_ext((struct bt_mesh_rpr_cli *)*(mod->user_data), + err = bt_mesh_rpr_scan_start_ext((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, NULL, 0, ad_types, (argc - 1)); if (err) { shell_print(sh, "Scan start failed: %d", err); @@ -213,7 +213,7 @@ static int cmd_scan_caps(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - err = bt_mesh_rpr_scan_caps_get((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &caps); + err = bt_mesh_rpr_scan_caps_get((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, &caps); if (err) { shell_print(sh, "Scan capabilities get failed: %d", err); return err; @@ -241,7 +241,7 @@ static int cmd_scan_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - err = bt_mesh_rpr_scan_get((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &rsp); + err = bt_mesh_rpr_scan_get((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, &rsp); if (err) { shell_print(sh, "Scan get failed: %d", err); return err; @@ -269,7 +269,7 @@ static int cmd_scan_stop(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - err = bt_mesh_rpr_scan_stop((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &rsp); + err = bt_mesh_rpr_scan_stop((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, &rsp); if (err || rsp.status) { shell_print(sh, "Scan stop failed: %d %u", err, rsp.status); return err; @@ -294,7 +294,7 @@ static int cmd_link_get(const struct shell *sh, size_t argc, char *argv[]) return -ENODEV; } - err = bt_mesh_rpr_link_get((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &rsp); + err = bt_mesh_rpr_link_get((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, &rsp); if (err) { shell_print(sh, "Link get failed: %d %u", err, rsp.status); return err; @@ -316,7 +316,7 @@ static int cmd_link_close(const struct shell *sh, size_t argc, char *argv[]) }; int err; - err = bt_mesh_rpr_link_close((struct bt_mesh_rpr_cli *)*(mod->user_data), &srv, &rsp); + err = bt_mesh_rpr_link_close((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, &rsp); if (err) { shell_print(sh, "Link close failed: %d %u", err, rsp.status); return err; @@ -355,7 +355,7 @@ static int cmd_provision_remote(const struct shell *sh, size_t argc, char *argv[ return err; } - err = bt_mesh_provision_remote((struct bt_mesh_rpr_cli *)*(mod->user_data), + err = bt_mesh_provision_remote((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, uuid, net_idx, addr); if (err) { shell_print(sh, "Prov remote start failed: %d", err); @@ -396,7 +396,7 @@ static int cmd_reprovision_remote(const struct shell *sh, size_t argc, char *arg return err; } - err = bt_mesh_reprovision_remote((struct bt_mesh_rpr_cli *)*(mod->user_data), + err = bt_mesh_reprovision_remote((struct bt_mesh_rpr_cli *)mod->rt->user_data, &srv, addr, composition_changed); if (err) { shell_print(sh, "Reprovisioning failed: %d", err); diff --git a/subsys/bluetooth/mesh/shell/utils.c b/subsys/bluetooth/mesh/shell/utils.c index 1d8ab79951de769..1ccb0e252120708 100644 --- a/subsys/bluetooth/mesh/shell/utils.c +++ b/subsys/bluetooth/mesh/shell/utils.c @@ -60,7 +60,7 @@ int bt_mesh_shell_mdl_print_all(const struct shell *sh, uint16_t mod_id) if (mod) { shell_print(sh, "Client model instance found at addr 0x%.4X. Element index: %d", - comp->elem[i].addr, *(mod->elem_idx)); + comp->elem[i].addr, mod->rt->elem_idx); } } diff --git a/subsys/bluetooth/mesh/sol_pdu_rpl_cli.c b/subsys/bluetooth/mesh/sol_pdu_rpl_cli.c index 05457eff3387045..dd809b599961c00 100644 --- a/subsys/bluetooth/mesh/sol_pdu_rpl_cli.c +++ b/subsys/bluetooth/mesh/sol_pdu_rpl_cli.c @@ -169,7 +169,7 @@ static int sol_pdu_rpl_cli_init(const struct bt_mesh_model *mod) msg_timeout = CONFIG_BT_MESH_SOL_PDU_RPL_CLI_TIMEOUT; - cli = *(mod->user_data); + cli = mod->rt->user_data; cli->model = mod; bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); return 0; diff --git a/tests/bsim/bluetooth/mesh/src/test_access.c b/tests/bsim/bluetooth/mesh/src/test_access.c index dacc30c741e0704..14ee6b03428c56f 100644 --- a/tests/bsim/bluetooth/mesh/src/test_access.c +++ b/tests/bsim/bluetooth/mesh/src/test_access.c @@ -261,7 +261,7 @@ static int model3_init(const struct bt_mesh_model *model) ASSERT_OK(bt_mesh_model_extend(model, model - 2)); ASSERT_OK(bt_mesh_model_extend(model, model - 1)); - if (*(model->elem_idx) == 1) { + if (model->rt->elem_idx == 1) { ASSERT_OK(bt_mesh_model_extend(model, &models[4])); } diff --git a/tests/bsim/bluetooth/mesh/src/test_lcd.c b/tests/bsim/bluetooth/mesh/src/test_lcd.c index 7e1d9ffca3ce4c4..337edaddc54d1e3 100644 --- a/tests/bsim/bluetooth/mesh/src/test_lcd.c +++ b/tests/bsim/bluetooth/mesh/src/test_lcd.c @@ -31,19 +31,10 @@ LOG_MODULE_REGISTER(test_lcd, LOG_LEVEL_INF); LCD_STATUS_FIELDS_LEN - \ BT_MESH_MIC_SHORT) /* 378 bytes */ -#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS -#define BT_MESH_MODEL_NEXT_UNASSIGNED() \ - .next = (const struct bt_mesh_model *[]){ NULL }, -#else -#define BT_MESH_MODEL_NEXT_UNASSIGNED() -#endif - #define TEST_MODEL_CNT_CB(_dummy_op, _metadata) \ { \ .id = 0x1234, \ - .elem_idx = (uint8_t []) { 0 }, \ - .mod_idx = (uint8_t []) { 0 }, \ - .flags = (uint16_t []) { 0 }, \ + BT_MESH_MODEL_RUNTIME_INIT(NULL) \ .pub = NULL, \ .keys = NULL, \ .keys_cnt = 0, \ @@ -51,8 +42,6 @@ LOG_MODULE_REGISTER(test_lcd, LOG_LEVEL_INF); .groups_cnt = 0, \ .op = _dummy_op, \ .cb = NULL, \ - BT_MESH_MODEL_NEXT_UNASSIGNED() \ - .user_data = (void *[]){ NULL }, \ .metadata = _metadata, \ } diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 80eb9ff38cd2eae..63b8d89416cfa5f 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -171,7 +171,7 @@ static const struct bt_mesh_model_op model_rpr_op1[] = { static int mock_model_init(const struct bt_mesh_model *mod) { mod->keys[0] = BT_MESH_KEY_DEV_LOCAL; - *(mod->flags) |= BT_MESH_MOD_DEVKEY_ONLY; + mod->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; return 0; } From d896213ef4b98a6afba5cdb94834713f554e1b84 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Thu, 16 Nov 2023 12:11:21 +0800 Subject: [PATCH 0536/1049] doc/release: Add incompatible change for bt mesh https://github.com/zephyrproject-rtos/zephyr/issues/57267 Signed-off-by: Lingao Meng --- doc/releases/migration-guide-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 77a0c1b76f758b0..dfd3fdb3cf6b1df 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -76,6 +76,10 @@ Bluetooth cleared on :c:func:`bt_enable`. Callbacks can now be registered before the initial call to :c:func:`bt_enable`, and should no longer be re-registered after a :c:func:`bt_disable` :c:func:`bt_enable` cycle. +* The Bluetooth Mesh ``model`` declaration has been changed to add prefix ``const``. + The ``model->user_data``, ``model->elem_idx`` and ``model->mod_idx`` field has been changed to + the new runtime structure, replaced by ``model->rt->user_data``, ``model->rt->elem_idx`` and + ``model->rt->mod_idx`` separately. LoRaWAN ======= From b911694f9bedd648664245b90c9fce8c21e868de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Sun, 12 Nov 2023 14:30:44 +0700 Subject: [PATCH 0537/1049] dts: pinctrl: kinetis: make slew-rate optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting slew-rate property is not supported on Kinetis KE series and the value will not have effect, so this property should not be required. We are also planning to reuse the Kinetis pin control binding and associated driver for NXP S32K1xx devices, which doesn't support setting the slew-rate rate as well. Signed-off-by: Manuel Argüelles --- dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml b/dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml index ccc36d4f167ed5d..c5b2f5d60207e7e 100644 --- a/dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml +++ b/dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2022, NXP +# Copyright (c) 2022-2023, NXP # SPDX-License-Identifier: Apache-2.0 description: | @@ -63,7 +63,6 @@ child-binding: 0 DSE_0- low drive strength when pin is configured as output 1 DSE_1- high drive strength when pin is configured as output slew-rate: - required: true type: string enum: - "fast" From de4fc8bf75aabf023f1b5831cd92102c1d17e61e Mon Sep 17 00:00:00 2001 From: Nazar Palamar Date: Wed, 8 Nov 2023 22:11:49 +0200 Subject: [PATCH 0538/1049] boards: arm: CY8CPROTO-062-4343W: update bias for i2c Update pin control bias mode for i2c3 pins: &p6_0_scb3_i2c_scl { drive-open-drain; input-enable; }; &p6_1_scb3_i2c_sda { drive-open-drain; input-enable; }; Signed-off-by: Nazar Palamar --- .../cy8cproto_062_4343w-pinctrl.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi index 14202d8fbcdf95a..fcf6655e5d6709a 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi @@ -29,6 +29,17 @@ input-enable; }; +/* Configure pin control bias mode for i2c3 pins */ +&p6_0_scb3_i2c_scl { + drive-open-drain; + input-enable; +}; + +&p6_1_scb3_i2c_sda { + drive-open-drain; + input-enable; +}; + &pinctrl { /* Configure pin control bias mode for SDIO */ p2_5_sdio_clk: p2_5_sdio_clk { From 47ad8f047cd61e9cacbdd394f18ed31472b7aa52 Mon Sep 17 00:00:00 2001 From: Nazar Palamar Date: Wed, 8 Nov 2023 22:15:12 +0200 Subject: [PATCH 0539/1049] dts: binding: i2c: Update description for Infineon CAT1 i2c driver - added example of usage Infineon CAT1 i2c driver - added note that pinctrl nodes need to be configured as open-drain and input-enable. Signed-off-by: Nazar Palamar --- dts/bindings/i2c/infineon,cat1-i2c.yaml | 37 ++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/dts/bindings/i2c/infineon,cat1-i2c.yaml b/dts/bindings/i2c/infineon,cat1-i2c.yaml index fa7ca1b8f4a274d..ef287709b767bf5 100644 --- a/dts/bindings/i2c/infineon,cat1-i2c.yaml +++ b/dts/bindings/i2c/infineon,cat1-i2c.yaml @@ -3,7 +3,42 @@ # # SPDX-License-Identifier: Apache-2.0 -description: Infineon CAT1 I2C +description: | + Infineon CAT1 I2C driver + + This driver configures the SCB as an I2C device. + + Example devicetree configuration with vl53l0x Time-of-Flight (ToF) + ranging sensor connected on the bus: + + i2c3: &scb3 { + compatible = "infineon,cat1-i2c"; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&p6_0_scb3_i2c_scl &p6_1_scb3_i2c_sda>; + pinctrl-names = "default"; + + vl53l0x@29 { + compatible = "st,vl53l0x"; + reg = <0x29>; + }; + }; + + The pinctrl nodes need to be configured as open-drain and + input-enable: + + &p6_0_scb3_i2c_scl { + drive-open-drain; + input-enable; + }; + + &p6_1_scb3_i2c_sda { + drive-open-drain; + input-enable; + }; compatible: "infineon,cat1-i2c" From 3b5fd5fc929bdc958c1acd435726d28c0ecf3f8e Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 10 Oct 2023 14:26:32 +0200 Subject: [PATCH 0540/1049] boards: arm: LPC55Sx6: Enable LinkServer and PyOCD runners. Enable LinkerServer and PyOCD runners for LPC55Sx6 EVKs, where it is supported. It was tested on a real HW. Signed-off-by: Andrej Butok --- boards/arm/lpcxpresso55s06/board.cmake | 3 +++ boards/arm/lpcxpresso55s16/board.cmake | 5 +++++ boards/arm/lpcxpresso55s36/board.cmake | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/boards/arm/lpcxpresso55s06/board.cmake b/boards/arm/lpcxpresso55s06/board.cmake index 32f7be75b332e26..305ed963f21c912 100644 --- a/boards/arm/lpcxpresso55s06/board.cmake +++ b/boards/arm/lpcxpresso55s06/board.cmake @@ -1,9 +1,12 @@ # # Copyright (c) 2022 metraTec +# Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # +board_runner_args(linkserver "--device=LPC55S06:LPCXpresso55S06") board_runner_args(jlink "--device=LPC55S06" "--reset-after-load") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/lpcxpresso55s16/board.cmake b/boards/arm/lpcxpresso55s16/board.cmake index 7daaf7d25c108ff..45ca5dcfe1cf358 100644 --- a/boards/arm/lpcxpresso55s16/board.cmake +++ b/boards/arm/lpcxpresso55s16/board.cmake @@ -1,9 +1,14 @@ # # Copyright (c) 2020 Henrik Brix Andersen +# Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # +board_runner_args(linkserver "--device=LPC55S16:LPCXpresso55S16") board_runner_args(jlink "--device=LPC55S16" "--reset-after-load") +board_runner_args(pyocd "--target=lpc55s16") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/lpcxpresso55s36/board.cmake b/boards/arm/lpcxpresso55s36/board.cmake index 2aceb6ca675c531..b1e16906bd56e30 100644 --- a/boards/arm/lpcxpresso55s36/board.cmake +++ b/boards/arm/lpcxpresso55s36/board.cmake @@ -1,11 +1,13 @@ # -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # # SPDX-License-Identifier: Apache-2.0 # +board_runner_args(linkserver "--device=LPC55S36:LPCXpresso55S36") board_runner_args(jlink "--device=LPC55S36" "--reset-after-load") board_runner_args(pyocd "--target=lpc55s36") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) From faf8bb0696931eccb1ed46baff2e663ab7099e19 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 14 Nov 2023 09:58:43 +0100 Subject: [PATCH 0541/1049] boards nrf5340_bsim doc: IPC and MUTEX peripherals are now supported Update this board docs to reflect that these 2 peripherals are now supported. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf_bsim/doc/nrf5340bsim.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/boards/posix/nrf_bsim/doc/nrf5340bsim.rst b/boards/posix/nrf_bsim/doc/nrf5340bsim.rst index 36dbf1d2adcc3fe..f2ece408e08859f 100644 --- a/boards/posix/nrf_bsim/doc/nrf5340bsim.rst +++ b/boards/posix/nrf_bsim/doc/nrf5340bsim.rst @@ -28,29 +28,26 @@ core on the simulated nRF5340 SOC. These boards include models of some of the nRF5340 SOC peripherals: -* Radio -* Timers * AAR (Accelerated Address Resolver) * AES CCM & AES ECB encryption HW * CLOCK (Clock control) * DPPI (Distributed Programmable Peripheral Interconnect) * EGU (Event Generator Unit) * FICR (Factory Information Configuration Registers) +* IPC (Interprocessor communication) +* MUTEX (Mutual exclusive peripheral) * NVMC (Non-Volatile Memory Controller / Flash) +* RADIO * RNG (Random Number Generator) * RTC (Real Time Counter) * TEMP (Temperature sensor) +* TIMER * UICR (User Information Configuration Registers) and will use the same drivers as the nrf5340dk targets for these. For more information on what is modelled to which level of detail, check the `HW models implementation status`_. -.. note:: - - The IPC and MUTEX peripherals are not yet present in these models. Therefore communication - between the cores using Zephyr's IPC driver is not yet possible. - Note that unlike a real nrf5340 device, the nrf5340bsim boards have unlimited RAM and flash for code. From ceba001bad770694e8915f981daf232aa0eb7d62 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 14 Nov 2023 15:18:13 +0100 Subject: [PATCH 0542/1049] bsim boards doc: Update general bsim boards documentation Polish and correct the documentation to reflect the use of the native_simulator, and the fact that we have now more than one bsim board in tree. Signed-off-by: Alberto Escolar Piedras --- boards/posix/doc/bsim_boards_design.rst | 82 ++-- boards/posix/doc/layering_natsim.svg | 582 ++++++++++++++++++++++++ 2 files changed, 631 insertions(+), 33 deletions(-) create mode 100644 boards/posix/doc/layering_natsim.svg diff --git a/boards/posix/doc/bsim_boards_design.rst b/boards/posix/doc/bsim_boards_design.rst index bb510f583513948..9b6bcfc0bca38a3 100644 --- a/boards/posix/doc/bsim_boards_design.rst +++ b/boards/posix/doc/bsim_boards_design.rst @@ -3,21 +3,27 @@ Bsim boards ########### -This page covers the design, architecture and rationale, of the -:ref:`nrf52_bsim`, :ref:`nrf5340bsim` and other similar bsim boards. -Particular details on the nRF52 and nRF5340 simulation boards, including how to use them, -can be found in their respective documentation. -These boards are postfixed with `_bsim` as they use BabbleSim_ -(shortened bsim). +**Available bsim boards** -These boards use the `native simulator`_ and the :ref:`POSIX architecture` to build -and execute the embedded code natively on Linux. +* :ref:`Simulated nRF52833 (nrf52_bsim)` +* :ref:`Simulated nRF5340 (nrf5340bsim)` -.. contents:: +.. contents:: Table of contents :depth: 2 :backlinks: entry :local: +This page covers the design, architecture and rationale, of the +nrf5x_bsim boards and other similar bsim boards. +These boards are postfixed with `_bsim` as they use BabbleSim_ +(shortened bsim), to simulate the radio environment. +These boards use the `native simulator`_ and the :ref:`POSIX architecture` to build +and execute the embedded code natively on Linux. + +Particular details on the :ref:`nRF52` and :ref:`nRF5340` +simulation boards, including how to use them, +can be found in their respective documentation. + .. _BabbleSim: https://BabbleSim.github.io @@ -55,6 +61,9 @@ without the need for real HW, and in a deterministic/reproducible fashion. Unlike :ref:`native_sim `, bsim boards do not interact directly with any host peripherals, and their execution is independent of the host load, or timing. +These boards are also designed to be used as prototyping and development environments, +which can help developing applications or communication stacks. + .. _bsim_boards_tests: Different types of tests and how the bsim boards relate to them @@ -120,35 +129,37 @@ Layering: Zephyr's arch, soc and board layers The basic architecture layering of these boards is as follows: +- The `native simulator`_ runner is used to execute the code in your host. - The architecture, SOC and board components of Zephyr are replaced with simulation specific ones. - The architecture (arch) is the Zephyr :ref:`POSIX architecture` layer. - The SOC layer is the soc_inf layer. And the board layer is dependent on + The SOC layer is `inf_clock`. And the board layer is dependent on the specific device we are simulating. - The POSIX architecture provides an adaptation from the Zephyr arch API - (which handles mostly the thread context switching) to the Linux kernel. + (which handles mostly the thread context switching) to the native simulator + CPU thread emulation. See :ref:`POSIX arch architecture` -- The soc_inf layer provides the overall CPU "simulation" and the handling of - control between the "CPU simulation" (Zephyr threads) and the HW models thread - ( See `Threading`_ ) +- The SOC `inf_clock` layer provides an adaptation to the native simulator CPU "simulation" + and the handling of control between the "CPU simulation" (Zephyr threads) and the + HW models thread ( See `Threading`_ ). - The board layer provides all SOC/ IC specific content, including - (or linking to) HW models, IRQ handling, busy wait API - (see :ref:`posix_busy_wait`), and Zephyr's printk backend. + selecting the HW models which are built in the native simulator runner context, IRQ handling, + busy wait API (see :ref:`posix_busy_wait`), and Zephyr's printk backend. Note that in a normal Zephyr target interrupt handling and a custom busy wait would be provided by the SOC layer, but abusing Zephyr's layering, and for the - soc_inf layer to be generic, these were delegated to the board. + `inf_clock` layer to be generic, these were delegated to the board. The board layer provides other test specific functionality like bs_tests hooks, trace control, etc, and - by means of the native simulator, provides the :c:func:`main` entry point for the linux + by means of the native simulator, provides the :c:func:`main` entry point for the Linux program, command line argument handling, and the overall time scheduling of the simulated device. - Note that the POSIX arch and soc_inf expect a set of APIs being provided by + Note that the POSIX arch and `inf_clock` soc expect a set of APIs being provided by the board. This includes the busy wait API, a basic tracing API, the interrupt controller and interrupt handling APIs, :c:func:`posix_exit`, - and :c:func:`posix_get_hw_cycle` (see posix_board_if.h and posix_soc_if.h ). + and :c:func:`posix_get_hw_cycle` (see :file:`posix_board_if.h` and :file:`posix_soc_if.h`). -.. figure:: layering.svg +.. figure:: layering_natsim.svg :align: center :alt: Zephyr layering in native & bsim builds :figclass: align-center @@ -161,7 +172,7 @@ Important limitations All native and bsim boards share the same set of :ref:`important limitations which` -are inherited from the POSIX arch and soc_inf design. +are inherited from the POSIX arch and `inf_clock` design. .. _Threading: @@ -228,7 +239,7 @@ can use to exchange data. About using Zephyr APIs ======================= -Note that even though bsim board code is linked with the Zephyr kernel, +Note that even though part of the bsim board code is linked with the Zephyr kernel, one should in general not call Zephyr APIs from the board code itself. In particular, one should not call Zephyr APIs from the original/HW models thread as the Zephyr code would be called from the wrong context, @@ -242,13 +253,14 @@ which relies on the bs_trace API. Instead, for tracing the bs_trace API should be used directly. The same applies to other Zephyr APIs, including the entropy API, etc. -posix_print backend -=================== +posix_print and nsi_print backends +================================== + +The bsim board provides a backend for the ``posix_print`` API which is expected by the posix +ARCH and `inf_clock` code, and for the ``nsi_print`` API expected by the native simulator. -The bsim board provides a backend for the posix_print API which is expected by the posix ARCH -and soc inf (POSIX) code. -It simply routes the printk strings to the bs_trace bsim API. -Any message printed to the posix_print API, which is also the default printk backend, +These simply route this API calls into the ``bs_trace`` bsim API. +Any message printed to these APIs, and by extension by default to Zephyr's ``printk``, will be printed to the console (stdout) together with all other device messages. .. _bsim_boards_bs_tests: @@ -271,12 +283,12 @@ callbacks are assigned to the respective hooks. There is a set of one time hooks at different levels of initialization of the HW and Zephyr OS, a hook to process possible command line arguments, and, a hook that can be used to sniff or capture interrupts. -bs_tests also provides a hook which will be called from the embedded application +`bs_tests` also provides a hook which will be called from the embedded application :c:func:`main`, but this will only work if the main application supports it, that is, if the main app is a version for simulation which calls :c:func:`bst_main` when running in the bsim board. -Apart from these hooks, the bs_tests system provides facilities to build a +Apart from these hooks, the `bs_tests` system provides facilities to build a dedicated test "task". This will be executed in the HW models thread context, but will have access to all SW variables. This task will be driven with a special timer which can be configured to produce either periodic or one time @@ -286,12 +298,16 @@ at specific points in time. This can be combined with Babblesim's tb_defs macros to build quite complex test tasks which can wait for a given amount of time, for conditions to be fulfilled, etc. -Note: When writing the tests with bs_tests one needs to be aware that other +Note when writing the tests with `bs_tests` one needs to be aware that other bs tests will probably be built with the same application, and that therefore the tests should not be registering initialization or callback functions using NATIVE_TASKS or Zephyr's PRE/POST kernel driver initialization APIs as this will execute even if the test is not selected. -Instead the equivalent bs_tests provided hooks should be used. +Instead the equivalent `bs_tests` provided hooks should be used. + +Note also that, for AMP targets like the :ref:`nrf5340bsim `, each embedded MCU has +its own separate `bs_tests` built with that MCU. You can select if and what test is used +for each MCU separatedly with the command line options. Command line argument parsing ============================= diff --git a/boards/posix/doc/layering_natsim.svg b/boards/posix/doc/layering_natsim.svg new file mode 100644 index 000000000000000..535ad934e5e19fd --- /dev/null +++ b/boards/posix/doc/layering_natsim.svg @@ -0,0 +1,582 @@ + + + + + + + + + + + + + Sheet.1 + CPU/SOC + + + + CPU/SOC + Sheet.2 + HW peripherals + + + + HW peripherals + Sheet.3 + Drivers + + + + Drivers + Sheet.4 + Architecture/SOC dependent layer + + + + Architecture/SOC dependent layer + Sheet.5 + Zephyr Kernel + + + + ZephyrKernel + Sheet.6 + Application + + + + Application + Sheet.7 + Host OS Kernel (i.e. Linux) + + + + Host OS Kernel (i.e. Linux) Sheet.7Host OS Kernel (i.e. Linux)Overall scheduler & entry pointCPUemulationSheet.8HW models / host HW API adaptationPOSIX archand SOC + Sheet.9 + Drivers + + + + Drivers + Sheet.11 + Zephyr Kernel + + + + ZephyrKernel + Sheet.12 + Application + + + + Application + Sheet.13 + Normal Zephyr layering + + + + Normal Zephyr layering native simulator runner contextEmbedded CPU SW (Zephyr) context +native_sim & _bsimboards Zephyr layeringHW models /Host APIadaptation From 05c03eb2587af0240e77bb3d15ad9266e0f72eb5 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 14 Nov 2023 16:43:18 +0100 Subject: [PATCH 0543/1049] bluetooth dev doc: Update with nrf5340bsim info Now that we also have this target board, we have some more options. Update the docs to reflect these. Signed-off-by: Alberto Escolar Piedras --- doc/connectivity/bluetooth/bluetooth-dev.rst | 25 +++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/doc/connectivity/bluetooth/bluetooth-dev.rst b/doc/connectivity/bluetooth/bluetooth-dev.rst index 49daefe43b90834..865eb22d049f4d8 100644 --- a/doc/connectivity/bluetooth/bluetooth-dev.rst +++ b/doc/connectivity/bluetooth/bluetooth-dev.rst @@ -34,7 +34,7 @@ There are 4 possible hardware setups to use with Zephyr and Bluetooth: #. Embedded #. QEMU with an external Controller #. :ref:`native_sim ` with an external Controller -#. Simulated nRF52 with BabbleSim +#. Simulated nRF5x with BabbleSim Embedded ======== @@ -137,32 +137,35 @@ Refer to :ref:`bluetooth_qemu_native` for full instructions on how to build and run an application with a physical controller. For the virtual controller refer to :ref:`bluetooth_virtual_posix`. -Simulated nRF52 with BabbleSim +Simulated nRF5x with BabbleSim ============================== .. note:: This is currently only available on GNU/Linux -The :ref:`nrf52_bsim board `, is a simulated target board -which emulates the necessary peripherals of a nrf52 SOC to be able to develop +The :ref:`nrf52_bsim ` and :ref:`nrf5340bsim ` boards, +are simulated target boards +which emulate the necessary peripherals of a nRF52/53 SOC to be able to develop and test BLE applications. -This board, uses: +These boards, use: - * `BabbleSim`_ to simulate the nrf52 modem and the radio environment. - * The POSIX arch to emulate the processor. - * `Models of the nrf52 HW `_ + * `BabbleSim`_ to simulate the nRF5x modem and the radio environment. + * The POSIX arch and native simulator to emulate the processor, and run natively on your host. + * `Models of the nrf5x HW `_ Just like with the :ref:`native_sim ` target, the build result is a normal Linux executable. You can find more information on how to run simulations with one or several -devices in -:ref:`this board's documentation ` +devices in either of :ref:`these boards's documentation `. -Currently, only :ref:`Combined builds +With the :ref:`nrf52_bsim `, only :ref:`Combined builds ` are possible, as this board does not yet have any models of a UART, or USB which could be used for an HCI interface towards another real or simulated device. +With the :ref:`nrf5340bsim `, you can build with either, both controller and host +on its network core, or, with the network core running only the controller, the application +core running the host and your application, and the HCI transport over IPC. Initialization ************** From b9977592a505cb1c29da58132e0ffbb953adf7bf Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 14 Nov 2023 16:44:47 +0100 Subject: [PATCH 0544/1049] doc/develop/test/bsim: Update with nrf5340bsim info Update this page to account for the fact that now we have several bsim boards in tree. Signed-off-by: Alberto Escolar Piedras --- doc/develop/test/bsim.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/develop/test/bsim.rst b/doc/develop/test/bsim.rst index d52bbc6fcfd124f..c785f88c1ee84c9 100644 --- a/doc/develop/test/bsim.rst +++ b/doc/develop/test/bsim.rst @@ -12,7 +12,7 @@ including the BLE stack, 802.15.4, and some of the networking stack. BabbleSim_ is a physical layer simulator, which in combination with the Zephyr :ref:`bsim boards` can be used to simulate a network of BLE and 15.4 devices. -When we build Zephyr targeting an :ref:`nrf52_bsim` board we produce a Linux +When we build Zephyr targeting a :ref:`bsim board` we produce a Linux executable, which includes the application, Zephyr OS, and models of the HW. When there is radio activity, this Linux executable will connect to the BabbleSim Phy simulation @@ -21,8 +21,9 @@ to simulate the radio channel. In the BabbleSim documentation you can find more information on how to `get `_ and `build `_ the simulator. -In the :ref:`nrf52_bsim` board documentation you can find more information about how -to build Zephyr targeting that particular board, and a few examples. +In the :ref:`nrf52_bsim` and :ref:`nrf5340bsim` boards documentation +you can find more information about how to build Zephyr targeting thesee particular boards, +and a few examples. Types of tests ************** @@ -31,7 +32,7 @@ Tests without radio activity: bsim tests with twister ----------------------------------------------------- The :ref:`bsim boards` can be used without radio activity, and in that case, it is not -necessary to connect them to a phyisical layer simulation. Thanks to this, this target boards can +necessary to connect them to a physical layer simulation. Thanks to this, these target boards can be used just like :ref:`native_sim` with :ref:`twister `, to run all standard Zephyr twister tests, but with models of a real SOC HW, and their drivers. @@ -62,8 +63,8 @@ found in the :ref:`bsim boards tests section`. Test coverage and BabbleSim *************************** -As the :ref:`nrf52_bsim` is based on the POSIX architecture, you can easily collect test -coverage information. +As the :ref:`nrf52_bsim` and :ref:`nrf5340bsim` boards are based on the +POSIX architecture, you can easily collect test coverage information. You can use the script :code:`tests/bsim/generate_coverage_report.sh` to generate an html coverage report from tests. From 927445325c78157a9f4b35a5fd8431fd7f390688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 14 Nov 2023 21:16:33 +0700 Subject: [PATCH 0545/1049] soc: nxp_s32: s32ze: include device headers in soc.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To simplify the inclusion of device headers in common code for NXP S32 devices, make sure all SoCs are including their respective device headers. This PR adds the missing headers for S32Z/E. Signed-off-by: Manuel Argüelles --- soc/arm/nxp_s32/s32ze/soc.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/soc/arm/nxp_s32/s32ze/soc.h b/soc/arm/nxp_s32/s32ze/soc.h index 1a3ea6311733855..f7c96aa2ed95a37 100644 --- a/soc/arm/nxp_s32/s32ze/soc.h +++ b/soc/arm/nxp_s32/s32ze/soc.h @@ -10,6 +10,12 @@ /* Do not let CMSIS to handle GIC */ #define __GIC_PRESENT 0 +#if defined(CONFIG_SOC_S32Z27_R52) +#include +#else +#error "SoC not supported" +#endif + /* Aliases for peripheral base addresses */ /* SIUL2 */ From 2c9255fbba64f6d33fe75d0ca1dc3f876eaed1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 14 Nov 2023 21:16:46 +0700 Subject: [PATCH 0546/1049] soc: nxp_s32: include soc.h instead of individual headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SoC header already includes the necessary device headers for all SoC variants supported. Signed-off-by: Manuel Argüelles --- soc/arm/nxp_s32/common/osif.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/soc/arm/nxp_s32/common/osif.c b/soc/arm/nxp_s32/common/osif.c index 52de7a38b7fd1ba..970e127fe132a1e 100644 --- a/soc/arm/nxp_s32/common/osif.c +++ b/soc/arm/nxp_s32/common/osif.c @@ -4,15 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include -#if defined(CONFIG_SOC_S32Z27_R52) -#include -#elif defined(CONFIG_SOC_S32K344) -#include -#endif - /* Required by OsIf timer initialization but not used with Zephyr, so no values configured */ static const OsIf_ConfigType osif_config; const OsIf_ConfigType *const OsIf_apxPredefinedConfig[OSIF_MAX_COREIDX_SUPPORTED] = { From 24c1b42741e2c641f0886c6f6e4f9fc7deec8739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 14 Nov 2023 21:18:18 +0700 Subject: [PATCH 0547/1049] drivers: ethernet: nxp_s32: include soc.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SoC header already includes the necessary device headers for all SoC variants supported. Signed-off-by: Manuel Argüelles --- drivers/ethernet/eth_nxp_s32_netc.c | 2 +- drivers/ethernet/eth_nxp_s32_netc_psi.c | 2 +- drivers/ethernet/eth_nxp_s32_netc_vsi.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ethernet/eth_nxp_s32_netc.c b/drivers/ethernet/eth_nxp_s32_netc.c index c452a4b398ffd29..f5a3994a9c4cb69 100644 --- a/drivers/ethernet/eth_nxp_s32_netc.c +++ b/drivers/ethernet/eth_nxp_s32_netc.c @@ -18,7 +18,7 @@ LOG_MODULE_REGISTER(nxp_s32_eth); #include #include -#include +#include #include #include #include diff --git a/drivers/ethernet/eth_nxp_s32_netc_psi.c b/drivers/ethernet/eth_nxp_s32_netc_psi.c index f35eb73ba283a3f..8a3242be9113cd2 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_psi.c +++ b/drivers/ethernet/eth_nxp_s32_netc_psi.c @@ -18,7 +18,7 @@ LOG_MODULE_REGISTER(nxp_s32_eth_psi); #include #include -#include +#include #include #include #include diff --git a/drivers/ethernet/eth_nxp_s32_netc_vsi.c b/drivers/ethernet/eth_nxp_s32_netc_vsi.c index b262250c226fa12..1a15952981476a5 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_vsi.c +++ b/drivers/ethernet/eth_nxp_s32_netc_vsi.c @@ -18,7 +18,7 @@ LOG_MODULE_REGISTER(nxp_s32_eth_vsi); #include #include -#include +#include #include #include #include From e87ded3f03798b2f2f348984f673489542a127cc Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 13 Nov 2023 16:27:01 +0000 Subject: [PATCH 0548/1049] input: it8xxx2: use the generic keyboard code Split the common keyboard scanning code out of the ITE specific driver and use the generic code instead. Note that this changes few timing defaults, the change is not significant though so I suspect there's no difference in practice. Signed-off-by: Fabio Baltieri --- boards/riscv/it82xx2_evb/it82xx2_evb.dts | 2 + boards/riscv/it8xxx2_evb/it8xxx2_evb.dts | 2 + drivers/input/Kconfig.it8xxx2 | 40 +-- drivers/input/input_ite_it8xxx2_kbd.c | 436 ++++------------------- dts/bindings/input/ite,it8xxx2-kbd.yaml | 8 +- 5 files changed, 90 insertions(+), 398 deletions(-) diff --git a/boards/riscv/it82xx2_evb/it82xx2_evb.dts b/boards/riscv/it82xx2_evb/it82xx2_evb.dts index 3110363d88a8307..1d1bb23eeb68024 100644 --- a/boards/riscv/it82xx2_evb/it82xx2_evb.dts +++ b/boards/riscv/it82xx2_evb/it82xx2_evb.dts @@ -189,6 +189,8 @@ &kso14_default &kso15_default>; pinctrl-names = "default"; + row-size = <8>; + col-size = <16>; kscan_input: kscan-input { compatible = "zephyr,kscan-input"; diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts index 73f7ec1b1defb2d..c111e9092aa15d9 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts @@ -173,6 +173,8 @@ &kso14_default &kso15_default>; pinctrl-names = "default"; + row-size = <8>; + col-size = <16>; kscan_input: kscan-input { compatible = "zephyr,kscan-input"; diff --git a/drivers/input/Kconfig.it8xxx2 b/drivers/input/Kconfig.it8xxx2 index bbd9699decc3d4c..6e729b27c3a927d 100644 --- a/drivers/input/Kconfig.it8xxx2 +++ b/drivers/input/Kconfig.it8xxx2 @@ -1,47 +1,11 @@ # Copyright (c) 2021 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -menuconfig INPUT_ITE_IT8XXX2_KBD +config INPUT_ITE_IT8XXX2_KBD bool "ITE keyboard scanning driver" default y depends on DT_HAS_ITE_IT8XXX2_KBD_ENABLED + select INPUT_KBD_MATRIX select MULTITHREADING help This option enables the ITE keyboard scan driver. - -if INPUT_ITE_IT8XXX2_KBD - -config INPUT_ITE_IT8XXX2_COLUMN_SIZE - int "INPUT_ITE_IT8XXX2_COLUMN_SIZE" - range 16 18 - default 16 - help - Adjust the value to your keyboard columns. The maximum - column size for the ITE family is 18. - -config INPUT_ITE_IT8XXX2_ROW_SIZE - int "INPUT_ITE_IT8XXX2_ROW_SIZE" - default 8 - help - Adjust the value to your keyboard rows. The maximum - row size for the ITE family is 8. - -config INPUT_ITE_IT8XXX2_DEBOUNCE_DOWN - int "INPUT_ITE_IT8XXX2_DEBOUNCE_DOWN" - default 9 - help - Determines the time in msecs for debouncing a key press. - -config INPUT_ITE_IT8XXX2_DEBOUNCE_UP - int "INPUT_ITE_IT8XXX2_DEBOUNCE_UP" - default 30 - help - Determines the time in msecs for debouncing a key release. - -config INPUT_ITE_IT8XXX2_POLL_PERIOD - int "INPUT_ITE_IT8XXX2_POLL_PERIOD" - default 3 - help - Defines the poll period in msecs between matrix scans. - -endif diff --git a/drivers/input/input_ite_it8xxx2_kbd.c b/drivers/input/input_ite_it8xxx2_kbd.c index 560f4fdd7d91a4a..6f16fba1d6e7c2b 100644 --- a/drivers/input/input_ite_it8xxx2_kbd.c +++ b/drivers/input/input_ite_it8xxx2_kbd.c @@ -14,40 +14,30 @@ #include #include #include +#include #include #include #include LOG_MODULE_REGISTER(input_ite_it8xxx2_kbd); -#define KEYBOARD_KSI_PIN_COUNT IT8XXX2_DT_INST_WUCCTRL_LEN(0) -#define KEYBOARD_COLUMN_DRIVE_ALL -2 -#define KEYBOARD_COLUMN_DRIVE_NONE -1 -/* Free run timer counts transform to micro-seconds (clock source is 32768Hz) */ -#define CLOCK_32K_HW_CYCLES_TO_US(X) \ - (uint32_t)((((uint64_t)(X) * 1000000U) / \ - sys_clock_hw_cycles_per_sec())) -/* Milli-second transform to micro-second */ -#define MS_TO_US 1000U -/* Number of tracked scan times */ -#define SCAN_OCURRENCES 30U -/* Thread stack size */ -#define TASK_STACK_SIZE 1024 - -struct input_it8xxx2_kbd_wuc_map_cfg { +#define KEYBOARD_KSI_PIN_COUNT IT8XXX2_DT_INST_WUCCTRL_LEN(0) + +struct it8xxx2_kbd_wuc_map_cfg { /* WUC control device structure */ const struct device *wucs; /* WUC pin mask */ uint8_t mask; }; -struct input_it8xxx2_kbd_config { +struct it8xxx2_kbd_config { + struct input_kbd_matrix_common_config common; /* Keyboard scan controller base address */ struct kscan_it8xxx2_regs *base; /* Keyboard scan input (KSI) wake-up irq */ int irq; /* KSI[7:0] wake-up input source configuration list */ - const struct input_it8xxx2_kbd_wuc_map_cfg *wuc_map_list; + const struct it8xxx2_kbd_wuc_map_cfg *wuc_map_list; /* KSI[7:0]/KSO[17:0] keyboard scan alternate configuration */ const struct pinctrl_dev_config *pcfg; /* KSO16 GPIO cells */ @@ -56,44 +46,26 @@ struct input_it8xxx2_kbd_config { struct gpio_dt_spec kso17_gpios; }; -/* Device data */ -struct input_it8xxx2_kbd_data { - /* Variables in usec units */ - uint32_t deb_time_press; - uint32_t deb_time_rel; - int32_t poll_timeout; - uint32_t poll_period; - uint8_t matrix_stable_state[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE]; - uint8_t matrix_unstable_state[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE]; - uint8_t matrix_previous_state[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE]; - /* Index in to the scan_clock_cycle to indicate start of debouncing */ - uint8_t scan_cycle_idx[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE] - [CONFIG_INPUT_ITE_IT8XXX2_ROW_SIZE]; - /* - * Track previous "elapsed clock cycles" per matrix scan. This - * is used to calculate the debouncing time for every key - */ - uint8_t scan_clk_cycle[SCAN_OCURRENCES]; - struct k_sem poll_lock; - uint8_t scan_cycles_idx; - struct k_thread thread; +struct it8xxx2_kbd_data { + struct input_kbd_matrix_common_data common; /* KSI[7:0] wake-up interrupt status mask */ uint8_t ksi_pin_mask; - - K_KERNEL_STACK_MEMBER(thread_stack, TASK_STACK_SIZE); }; -static void drive_keyboard_column(const struct device *dev, int col) +INPUT_KBD_STRUCT_CHECK(struct it8xxx2_kbd_config, struct it8xxx2_kbd_data); + +static void it8xxx2_kbd_drive_column(const struct device *dev, int col) { - const struct input_it8xxx2_kbd_config *const config = dev->config; + const struct it8xxx2_kbd_config *const config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; struct kscan_it8xxx2_regs *const inst = config->base; int mask; /* Tri-state all outputs */ - if (col == KEYBOARD_COLUMN_DRIVE_NONE) { + if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) { mask = 0x3ffff; /* Assert all outputs */ - } else if (col == KEYBOARD_COLUMN_DRIVE_ALL) { + } else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) { mask = 0; /* Assert a single output */ } else { @@ -103,86 +75,24 @@ static void drive_keyboard_column(const struct device *dev, int col) /* Set KSO[17:0] output data */ inst->KBS_KSOL = (uint8_t) (mask & 0xff); inst->KBS_KSOH1 = (uint8_t) ((mask >> 8) & 0xff); -#if (CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE > 16) - inst->KBS_KSOH2 = (uint8_t) ((mask >> 16) & 0xff); -#endif + if (common->col_size > 16) { + inst->KBS_KSOH2 = (uint8_t) ((mask >> 16) & 0xff); + } } -static uint8_t read_keyboard_row(const struct device *dev) +static int it8xxx2_kbd_read_row(const struct device *dev) { - const struct input_it8xxx2_kbd_config *const config = dev->config; + const struct it8xxx2_kbd_config *const config = dev->config; struct kscan_it8xxx2_regs *const inst = config->base; /* Bits are active-low, so toggle it (return 1 means key pressed) */ return (inst->KBS_KSI ^ 0xff); } -static bool is_matrix_ghosting(const uint8_t *state) -{ - /* - * Matrix keyboard designs are susceptible to ghosting. - * An extra key appears to be pressed when 3 keys - * belonging to the same block are pressed. - * for example, in the following block - * - * . . w . q . - * . . . . . . - * . . . . . . - * . . m . a . - * - * the key m would look as pressed if the user pressed keys - * w, q and a simultaneously. A block can also be formed, - * with not adjacent columns. - */ - for (int c = 0; c < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; c++) { - if (!state[c]) - continue; - - for (int c_n = c + 1; c_n < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; c_n++) { - /* - * We AND the columns to detect a "block". - * this is an indication of ghosting, due to current - * flowing from a key which was never pressed. in our - * case, current flowing is a bit set to 1 as we - * flipped the bits when the matrix was scanned. - * now we OR the columns using z&(z-1) which is - * non-zero only if z has more than one bit set. - */ - uint8_t common_row_bits = state[c] & state[c_n]; - - if (common_row_bits & (common_row_bits - 1)) - return true; - } - } - - return false; -} - -static bool read_keyboard_matrix(const struct device *dev, uint8_t *new_state) -{ - uint8_t row; - uint8_t key_event = 0U; - - for (int col = 0; col < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; col++) { - /* Drive specific column low and others high */ - drive_keyboard_column(dev, col); - /* Allow the matrix to stabilize before reading it */ - k_busy_wait(50U); - row = read_keyboard_row(dev); - new_state[col] = row; - - key_event |= row; - } - - drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_NONE); - - return key_event != 0U ? true : false; -} - -static void keyboard_raw_interrupt(const struct device *dev) +static void it8xxx2_kbd_isr(const struct device *dev) { - const struct input_it8xxx2_kbd_config *const config = dev->config; - struct input_it8xxx2_kbd_data *data = dev->data; + const struct it8xxx2_kbd_config *const config = dev->config; + struct it8xxx2_kbd_data *data = dev->data; /* * W/C wakeup interrupt status of KSI[7:0] pins @@ -196,14 +106,13 @@ static void keyboard_raw_interrupt(const struct device *dev) /* W/C interrupt status of KSI[7:0] pins */ ite_intc_isr_clear(config->irq); - /* Release poll lock semaphore */ - k_sem_give(&data->poll_lock); + input_kbd_matrix_poll_start(dev); } -void keyboard_raw_enable_interrupt(const struct device *dev, int enable) +static void it8xxx2_kbd_set_detect_mode(const struct device *dev, bool enable) { - const struct input_it8xxx2_kbd_config *const config = dev->config; - struct input_it8xxx2_kbd_data *data = dev->data; + const struct it8xxx2_kbd_config *const config = dev->config; + struct it8xxx2_kbd_data *data = dev->data; if (enable) { /* @@ -224,217 +133,33 @@ void keyboard_raw_enable_interrupt(const struct device *dev, int enable) } } -static bool check_key_events(const struct device *dev) +static int it8xxx2_kbd_init(const struct device *dev) { - struct input_it8xxx2_kbd_data *data = dev->data; - uint8_t matrix_new_state[CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE] = {0U}; - bool key_pressed = false; - uint32_t cycles_now = k_cycle_get_32(); - uint8_t row_changed = 0U; - uint8_t deb_col; - - if (++data->scan_cycles_idx >= SCAN_OCURRENCES) { - data->scan_cycles_idx = 0U; - } - - data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now; - - /* Scan the matrix */ - key_pressed = read_keyboard_matrix(dev, matrix_new_state); - - /* Abort if ghosting is detected */ - if (is_matrix_ghosting(matrix_new_state)) { - return false; - } - - /* - * The intent of this loop is to gather information related to key - * changes - */ - for (int c = 0; c < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; c++) { - /* Check if there was an update from the previous scan */ - row_changed = matrix_new_state[c] ^ - data->matrix_previous_state[c]; - - if (!row_changed) - continue; - - for (int r = 0; r < CONFIG_INPUT_ITE_IT8XXX2_ROW_SIZE; r++) { - /* - * Index all they keys that changed for each row - * in order to debounce each key in terms of it - */ - if (row_changed & BIT(r)) - data->scan_cycle_idx[c][r] = - data->scan_cycles_idx; - } - - data->matrix_unstable_state[c] |= row_changed; - data->matrix_previous_state[c] = matrix_new_state[c]; - } - - for (int c = 0; c < CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE; c++) { - deb_col = data->matrix_unstable_state[c]; - - if (!deb_col) - continue; - - /* Debouncing for each row key occurs here */ - for (int r = 0; r < CONFIG_INPUT_ITE_IT8XXX2_ROW_SIZE; r++) { - uint8_t mask = BIT(r); - uint8_t row_bit = matrix_new_state[c] & mask; - - /* Continue if we already debounce a key */ - if (!(deb_col & mask)) - continue; - - /* Convert the clock cycle differences to usec */ - uint32_t debt = CLOCK_32K_HW_CYCLES_TO_US(cycles_now - - data->scan_clk_cycle[data->scan_cycle_idx[c][r]]); - - /* Does the key requires more time to be debounced ? */ - if (debt < (row_bit ? data->deb_time_press : - data->deb_time_rel)) { - /* Need more time to debounce */ - continue; - } - - data->matrix_unstable_state[c] &= ~row_bit; - - /* Check if there was a change in the stable state */ - if ((data->matrix_stable_state[c] & mask) == row_bit) { - /* Key state did not change */ - continue; - } - - /* - * The current row has been debounced, therefore update - * the stable state. Then, proceed to notify the - * application about the keys pressed. - */ - data->matrix_stable_state[c] ^= mask; - - input_report_abs(dev, INPUT_ABS_X, c, false, K_FOREVER); - input_report_abs(dev, INPUT_ABS_Y, r, false, K_FOREVER); - input_report_key(dev, INPUT_BTN_TOUCH, row_bit, true, K_FOREVER); - } - } - - return key_pressed; -} - -/** - * @brief Determine if a timer is expired. - * - * @param start_cycles The starting time of HW cycle. - * @param timeout Pointer to the period time. - * - * @retval true If timer is expired; - * false If timer isn't expired. - */ -static bool poll_expired(uint32_t start_cycles, int32_t *timeout) -{ - uint32_t now_cycles; - uint32_t microsecs_spent; - - now_cycles = k_cycle_get_32(); - microsecs_spent = CLOCK_32K_HW_CYCLES_TO_US(now_cycles - start_cycles); - - /* Update the timeout value */ - *timeout -= microsecs_spent; - - return !(*timeout >= 0); -} - -void polling_task(const struct device *dev, void *dummy2, void *dummy3) -{ - struct input_it8xxx2_kbd_data *data = dev->data; - int32_t local_poll_timeout = data->poll_timeout; - uint32_t current_cycles; - uint32_t cycles_delta; - uint32_t wait_period; - - ARG_UNUSED(dummy2); - ARG_UNUSED(dummy3); - - while (true) { - /* Init all KSO output low */ - drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_ALL); - /* Enable wakeup and interrupt of KSI pins */ - keyboard_raw_enable_interrupt(dev, 1); - /* Wait poll lock semaphore */ - k_sem_take(&data->poll_lock, K_FOREVER); - /* Disable wakeup and interrupt of KSI pins after fired */ - keyboard_raw_enable_interrupt(dev, 0); - - uint32_t start_poll_cycles = k_cycle_get_32(); - - while (true) { - uint32_t start_period_cycles = k_cycle_get_32(); - - if (check_key_events(dev)) { - start_poll_cycles = k_cycle_get_32(); - } else if (poll_expired(start_poll_cycles, - &local_poll_timeout)) { - break; - } - - /* - * Subtract the time invested from the sleep period - * in order to compensate for the time invested - * in debouncing a key - */ - current_cycles = k_cycle_get_32(); - cycles_delta = current_cycles - start_period_cycles; - wait_period = data->poll_period - - CLOCK_32K_HW_CYCLES_TO_US(cycles_delta); - - /* Override wait_period in case it's less than 1000 us */ - if (wait_period < MS_TO_US) { - wait_period = MS_TO_US; - } - - /* - * Wait period results in a larger number when - * current cycles counter wrap. In this case, the - * whole poll period is used - */ - if (wait_period > data->poll_period) { - LOG_DBG("wait_period : %u", wait_period); - wait_period = data->poll_period; - } - - /* Allow other threads to run while we sleep */ - k_usleep(wait_period); - } - } -} - -static int input_it8xxx2_kbd_init(const struct device *dev) -{ - const struct input_it8xxx2_kbd_config *const config = dev->config; - struct input_it8xxx2_kbd_data *data = dev->data; + const struct it8xxx2_kbd_config *const config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; + struct it8xxx2_kbd_data *data = dev->data; struct kscan_it8xxx2_regs *const inst = config->base; int status; /* Disable wakeup and interrupt of KSI pins before configuring */ - keyboard_raw_enable_interrupt(dev, 0); + it8xxx2_kbd_set_detect_mode(dev, false); -#if (CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE > 16) - /* - * For KSO[16] and KSO[17]: - * 1.GPOTRC: - * Bit[x] = 1b: Enable the open-drain mode of KSO pin - * 2.GPCRCx: - * Bit[7:6] = 00b: Select alternate KSO function - * Bit[2] = 1b: Enable the internal pull-up of KSO pin - * - * NOTE: Set input temporarily for gpio_pin_configure(), after that - * pinctrl_apply_state() set to alternate function immediately. - */ - gpio_pin_configure_dt(&config->kso16_gpios, GPIO_INPUT); - gpio_pin_configure_dt(&config->kso17_gpios, GPIO_INPUT); -#endif + if (common->col_size > 16) { + /* + * For KSO[16] and KSO[17]: + * 1.GPOTRC: + * Bit[x] = 1b: Enable the open-drain mode of KSO pin + * 2.GPCRCx: + * Bit[7:6] = 00b: Select alternate KSO function + * Bit[2] = 1b: Enable the internal pull-up of KSO pin + * + * NOTE: Set input temporarily for gpio_pin_configure(), after + * that pinctrl_apply_state() set to alternate function + * immediately. + */ + gpio_pin_configure_dt(&config->kso16_gpios, GPIO_INPUT); + gpio_pin_configure_dt(&config->kso17_gpios, GPIO_INPUT); + } /* * Enable the internal pull-up and kbs mode of the KSI[7:0] pins. * Enable the internal pull-up and kbs mode of the KSO[15:0] pins. @@ -449,9 +174,9 @@ static int input_it8xxx2_kbd_init(const struct device *dev) /* KSO[17:0] pins output low */ inst->KBS_KSOL = 0x00; inst->KBS_KSOH1 = 0x00; -#if (CONFIG_INPUT_ITE_IT8XXX2_COLUMN_SIZE > 16) - inst->KBS_KSOH2 = 0x00; -#endif + if (common->col_size > 16) { + inst->KBS_KSOH2 = 0x00; + } for (int i = 0; i < KEYBOARD_KSI_PIN_COUNT; i++) { /* Select wakeup interrupt falling-edge triggered of KSI[7:0] pins */ @@ -469,10 +194,8 @@ static int input_it8xxx2_kbd_init(const struct device *dev) * We want to clear KSI[7:0] pins status at a time when wakeup * interrupt fire, so gather the KSI[7:0] pin mask value here. */ - if (IS_ENABLED(CONFIG_LOG)) { - if (config->wuc_map_list[i].wucs != config->wuc_map_list[0].wucs) { - LOG_ERR("KSI%d pin isn't in the same wuc node!", i); - } + if (config->wuc_map_list[i].wucs != config->wuc_map_list[0].wucs) { + LOG_ERR("KSI%d pin isn't in the same wuc node!", i); } data->ksi_pin_mask |= config->wuc_map_list[i].mask; } @@ -480,48 +203,43 @@ static int input_it8xxx2_kbd_init(const struct device *dev) /* W/C interrupt status of KSI[7:0] pins */ ite_intc_isr_clear(config->irq); - /* Kconfig.it8xxx2 time figures are transformed from msec to usec */ - data->deb_time_press = - (uint32_t) (CONFIG_INPUT_ITE_IT8XXX2_DEBOUNCE_DOWN * MS_TO_US); - data->deb_time_rel = - (uint32_t) (CONFIG_INPUT_ITE_IT8XXX2_DEBOUNCE_UP * MS_TO_US); - data->poll_period = - (uint32_t) (CONFIG_INPUT_ITE_IT8XXX2_POLL_PERIOD * MS_TO_US); - data->poll_timeout = 100 * MS_TO_US; - - /* Create poll lock semaphore */ - k_sem_init(&data->poll_lock, 0, 1); - irq_connect_dynamic(DT_INST_IRQN(0), 0, - (void (*)(const void *))keyboard_raw_interrupt, + (void (*)(const void *))it8xxx2_kbd_isr, (const void *)dev, 0); - /* Create keyboard scan task */ - k_thread_create(&data->thread, data->thread_stack, - TASK_STACK_SIZE, - (void (*)(void *, void *, void *))polling_task, - (void *)dev, NULL, NULL, - K_PRIO_COOP(4), 0, K_NO_WAIT); - - return 0; + return input_kbd_matrix_common_init(dev); } -static const struct input_it8xxx2_kbd_wuc_map_cfg - input_it8xxx2_kbd_wuc[IT8XXX2_DT_INST_WUCCTRL_LEN(0)] = IT8XXX2_DT_WUC_ITEMS_LIST(0); +static const struct it8xxx2_kbd_wuc_map_cfg + it8xxx2_kbd_wuc[IT8XXX2_DT_INST_WUCCTRL_LEN(0)] = IT8XXX2_DT_WUC_ITEMS_LIST(0); PINCTRL_DT_INST_DEFINE(0); -static const struct input_it8xxx2_kbd_config input_it8xxx2_kbd_cfg = { +INPUT_KBD_MATRIX_DT_INST_DEFINE(0); + +static const struct input_kbd_matrix_api it8xxx2_kbd_api = { + .drive_column = it8xxx2_kbd_drive_column, + .read_row = it8xxx2_kbd_read_row, + .set_detect_mode = it8xxx2_kbd_set_detect_mode, +}; + +static const struct it8xxx2_kbd_config it8xxx2_kbd_cfg_0 = { + .common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(0, &it8xxx2_kbd_api), .base = (struct kscan_it8xxx2_regs *)DT_INST_REG_ADDR_BY_IDX(0, 0), .irq = DT_INST_IRQN(0), - .wuc_map_list = input_it8xxx2_kbd_wuc, + .wuc_map_list = it8xxx2_kbd_wuc, .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), .kso16_gpios = GPIO_DT_SPEC_INST_GET(0, kso16_gpios), .kso17_gpios = GPIO_DT_SPEC_INST_GET(0, kso17_gpios), }; -static struct input_it8xxx2_kbd_data input_it8xxx2_kbd_kbd_data; +static struct it8xxx2_kbd_data it8xxx2_kbd_data_0; -DEVICE_DT_INST_DEFINE(0, &input_it8xxx2_kbd_init, NULL, - &input_it8xxx2_kbd_kbd_data, &input_it8xxx2_kbd_cfg, +DEVICE_DT_INST_DEFINE(0, &it8xxx2_kbd_init, NULL, + &it8xxx2_kbd_data_0, &it8xxx2_kbd_cfg_0, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, + "only one ite,it8xxx2-kbd compatible node can be supported"); +BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, row_size), 1, 8), "invalid row-size"); +BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, col_size), 16, 18), "invalid col-size"); diff --git a/dts/bindings/input/ite,it8xxx2-kbd.yaml b/dts/bindings/input/ite,it8xxx2-kbd.yaml index 1aec1e1e7a9a1b7..d809f41fbbc971f 100644 --- a/dts/bindings/input/ite,it8xxx2-kbd.yaml +++ b/dts/bindings/input/ite,it8xxx2-kbd.yaml @@ -5,7 +5,7 @@ description: ITE it8xxx2 keyboard matrix controller compatible: "ite,it8xxx2-kbd" -include: [kscan.yaml, pinctrl-device.yaml] +include: [kbd-matrix-common.yaml, pinctrl-device.yaml] properties: reg: @@ -40,3 +40,9 @@ properties: pinctrl-names: required: true + + row-size: + required: true + + col-size: + required: true From 11857e350907875772bda13485675048b724a54e Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Tue, 14 Nov 2023 15:04:44 +0000 Subject: [PATCH 0549/1049] MAINTAINERS: Update maintainers/codeowners for Intel Agilex boards Corrected/Updated proper github account names for maintainers and codeowners file. Signed-off-by: Girisha Dengi --- CODEOWNERS | 2 +- MAINTAINERS.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 54f2b65933ad982..8872e7381c5498e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -144,7 +144,7 @@ /boards/arm64/fvp_baser_aemv8r/ @povergoing /boards/arm64/fvp_base_revc_2xaemv8a/ @carlocaione /boards/arm64/intel_socfpga_agilex_socdk/ @siclim @ngboonkhai -/boards/arm64/intel_socfpga_agilex5_socdk/ @chongteikheng +/boards/arm64/intel_socfpga_agilex5_socdk/ @teikheng @gdengi /boards/arm64/rcar_*/ @lorc @xakep-amatop # All cmake related files /doc/develop/tools/coccinelle.rst @himanshujha199640 @JuliaLawall diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 7562f3587c7a1b5..32a1d1efb54b01d 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2634,7 +2634,7 @@ Intel Platforms (Agilex): - gdengi collaborators: - nbalabak - - chongteikheng + - teikheng files: - boards/arm64/intel_*/ - soc/arm64/intel_*/ From 256adeebd934b80358c78d6fb6600fed09f25fa4 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 16 Nov 2023 18:20:05 +0100 Subject: [PATCH 0550/1049] Revert "drivers: watchdog: wdt_nrfx: Implement disable API" This reverts commit 415b6fc945fd3748d2c8c5191abbc484fe551cad. This does not even compile as it attempts to do assignment to a read-only object (config->config.behaviour). Signed-off-by: Henrik Brix Andersen --- drivers/watchdog/wdt_nrfx.c | 41 ++++++++++++------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index 5d2e036a2136d6b..8d61f11d6fbe5ad 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -28,32 +28,29 @@ static int wdt_nrf_setup(const struct device *dev, uint8_t options) { const struct wdt_nrfx_config *config = dev->config; struct wdt_nrfx_data *data = dev->data; - nrfx_err_t err_code; + uint32_t behaviour; /* Activate all available options. Run in all cases. */ - config->config.behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK | -#if NRF_WDT_HAS_STOP - NRF_WDT_BEHAVIOUR_STOP_ENABLE_MASK | -#endif - NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; + behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK | NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; /* Deactivate running in sleep mode. */ if (options & WDT_OPT_PAUSE_IN_SLEEP) { - config->config.behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK; + behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK; } /* Deactivate running when debugger is attached. */ if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { - config->config.behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; + behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; } - config->config.reload_value = data->m_timeout; - - err_code = nrfx_wdt_reconfigure(&config->wdt, &config->config); - - if (err_code != NRFX_SUCCESS) { - return -EBUSY; - } + nrf_wdt_behaviour_set(config->wdt.p_reg, behaviour); + /* The watchdog timer is driven by the LFCLK clock running at 32768 Hz. + * The timeout value given in milliseconds needs to be converted here + * to watchdog ticks.*/ + nrf_wdt_reload_value_set( + config->wdt.p_reg, + (uint32_t)(((uint64_t)data->m_timeout * 32768U) + / 1000)); nrfx_wdt_enable(&config->wdt); @@ -62,21 +59,9 @@ static int wdt_nrf_setup(const struct device *dev, uint8_t options) static int wdt_nrf_disable(const struct device *dev) { -#if NRFX_WDT_HAS_STOP - const struct wdt_nrfx_config *config = dev->config; - nrfx_err_t err_code; - - err_code = nrfx_wdt_stop(&config->wdt); - - if (err_code != NRFX_SUCCESS) { - return -ENOTSUP; - } - - return 0; -#else + /* Started watchdog cannot be stopped on nRF devices. */ ARG_UNUSED(dev); return -EPERM; -#endif } static int wdt_nrf_install_timeout(const struct device *dev, From 21366fea1979f76fce9f9c84cc4c3eb25630f90f Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 16 Nov 2023 21:50:08 +0000 Subject: [PATCH 0551/1049] ci: do not mark coverity issues as stale Coverity issues need to be resolved and closed by owners, not by the bot. Other wise we will continue scanning them and reporting them over and over. Signed-off-by: Anas Nashif --- .github/workflows/stale_issue.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale_issue.yml b/.github/workflows/stale_issue.yml index d93aa1f381d128f..8dc313701258c05 100644 --- a/.github/workflows/stale_issue.yml +++ b/.github/workflows/stale_issue.yml @@ -24,5 +24,5 @@ jobs: stale-issue-label: 'Stale' stale-pr-label: 'Stale' exempt-pr-labels: 'Blocked,In progress' - exempt-issue-labels: 'In progress,Enhancement,Feature,Feature Request,RFC,Meta,Process' + exempt-issue-labels: 'In progress,Enhancement,Feature,Feature Request,RFC,Meta,Process,Coverity' operations-per-run: 400 From 37637373264d707705afbdb72162251904337b76 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 1 Nov 2023 15:26:14 -0700 Subject: [PATCH 0552/1049] smbus: Remove syscalls with callbacks Remove syscalls that allows user threads to set callbacks that will be invoked by the kernel. Userspace is not trusted we can't allow a user thread set callbacks that will be invoked by the kernel and run with supervisor privileges. Signed-off-by: Flavio Ceolin --- drivers/smbus/smbus_handlers.c | 18 ------------------ include/zephyr/drivers/smbus.h | 14 ++++---------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/drivers/smbus/smbus_handlers.c b/drivers/smbus/smbus_handlers.c index 4762ccf1e90c905..b9c45e76cf76bf2 100644 --- a/drivers/smbus/smbus_handlers.c +++ b/drivers/smbus/smbus_handlers.c @@ -144,15 +144,6 @@ static inline int z_vrfy_smbus_block_pcall(const struct device *dev, } #include -static inline int z_vrfy_smbus_smbalert_set_cb(const struct device *dev, - struct smbus_callback *cb) -{ - K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - - return z_impl_smbus_smbalert_set_cb(dev, cb); -} -#include - static inline int z_vrfy_smbus_smbalert_remove_cb(const struct device *dev, struct smbus_callback *cb) { @@ -162,15 +153,6 @@ static inline int z_vrfy_smbus_smbalert_remove_cb(const struct device *dev, } #include -static inline int z_vrfy_smbus_host_notify_set_cb(const struct device *dev, - struct smbus_callback *cb) -{ - K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - - return z_impl_smbus_host_notify_set_cb(dev, cb); -} -#include - static inline int z_vrfy_smbus_host_notify_remove_cb(const struct device *dev, struct smbus_callback *cb) { diff --git a/include/zephyr/drivers/smbus.h b/include/zephyr/drivers/smbus.h index ccb67a14d4a89e7..c4995febb7b606c 100644 --- a/include/zephyr/drivers/smbus.h +++ b/include/zephyr/drivers/smbus.h @@ -611,11 +611,8 @@ static inline int z_impl_smbus_get_config(const struct device *dev, * @retval -ENOSYS If function smbus_smbalert_set_cb() is not implemented * by the driver. */ -__syscall int smbus_smbalert_set_cb(const struct device *dev, - struct smbus_callback *cb); - -static inline int z_impl_smbus_smbalert_set_cb(const struct device *dev, - struct smbus_callback *cb) +static inline int smbus_smbalert_set_cb(const struct device *dev, + struct smbus_callback *cb) { const struct smbus_driver_api *api = (const struct smbus_driver_api *)dev->api; @@ -665,11 +662,8 @@ static inline int z_impl_smbus_smbalert_remove_cb(const struct device *dev, * @retval -ENOSYS If function smbus_host_notify_set_cb() is not implemented * by the driver. */ -__syscall int smbus_host_notify_set_cb(const struct device *dev, - struct smbus_callback *cb); - -static inline int z_impl_smbus_host_notify_set_cb(const struct device *dev, - struct smbus_callback *cb) +static inline int smbus_host_notify_set_cb(const struct device *dev, + struct smbus_callback *cb) { const struct smbus_driver_api *api = (const struct smbus_driver_api *)dev->api; From eb323be088d80773ef85360190578aea19361863 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 2 Nov 2023 18:44:53 -0700 Subject: [PATCH 0553/1049] tests: smbus: Fix user mode usage APIs that set callback don't have syscalls and their tests have to run in supervisor mode. Signed-off-by: Flavio Ceolin --- tests/drivers/smbus/smbus_api/src/test_smbus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers/smbus/smbus_api/src/test_smbus.c b/tests/drivers/smbus/smbus_api/src/test_smbus.c index 5642bd664a6d0d0..5d1dd9ca49ad7d7 100644 --- a/tests/drivers/smbus/smbus_api/src/test_smbus.c +++ b/tests/drivers/smbus/smbus_api/src/test_smbus.c @@ -45,7 +45,7 @@ ZTEST_USER(test_smbus_general, test_smbus_basic_api) * The test is run in userspace only if CONFIG_USERSPACE option is * enabled, otherwise it is the same as ZTEST() */ -ZTEST_USER(test_smbus_general, test_smbus_smbalert_api) +ZTEST(test_smbus_general, test_smbus_smbalert_api) { const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(smbus0)); void *dummy; /* For the dummy function pointer use this */ @@ -90,7 +90,7 @@ ZTEST_USER(test_smbus_general, test_smbus_smbalert_api) * The test is run in userspace only if CONFIG_USERSPACE option is * enabled, otherwise it is the same as ZTEST() */ -ZTEST_USER(test_smbus_general, test_smbus_host_notify_api) +ZTEST(test_smbus_general, test_smbus_host_notify_api) { const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(smbus0)); void *dummy; /* For the dummy function pointer use this */ From 3441fee460d9ea90262d3d89a0d4e79e314772cc Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Tue, 7 Nov 2023 16:12:10 +0100 Subject: [PATCH 0554/1049] drivers: spi: Implement workaround for unreliable busy flag For some STM32 MCUs the busy flag of SPI is unreliable. This is a known issue of the device and described in the device errata. As a fix implement a configurable timeout which ensures that a call to spi_transceive will eventually return. Fixes #64927 Signed-off-by: Benedikt Schmidt --- drivers/spi/Kconfig.stm32 | 17 +++++++++++++++++ drivers/spi/spi_ll_stm32.c | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/spi/Kconfig.stm32 b/drivers/spi/Kconfig.stm32 index 8baa58801926db7..6a53f30cbc49db8 100644 --- a/drivers/spi/Kconfig.stm32 +++ b/drivers/spi/Kconfig.stm32 @@ -32,5 +32,22 @@ config SPI_STM32_USE_HW_SS help Use Slave Select pin instead of software Slave Select. +config SPI_STM32F7_ERRATA_BUSY + bool + default y + depends on SOC_STM32F745XX || SOC_STM32F746XX || \ + SOC_STM32F750XX || SOC_STM32F756XX + help + Handles erratum "BSY bit may stay high at the end of a data + transfer in Slave mode". + Seen in Errata Sheet 0290 §2.11.2 + +if SPI_STM32F7_ERRATA_BUSY + +config SPI_STM32_BUSY_FLAG_TIMEOUT + int "timeout in us for the STM32 busy flag workaround" + default 10000 + +endif # SPI_STM32F7_ERRATA_BUSY endif # SPI_STM32 diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index e62a763a3f998a0..0241dbde2543a34 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -902,9 +902,15 @@ static int transceive_dma(const struct device *dev, } #endif +#ifdef CONFIG_SPI_STM32F7_ERRATA_BUSY + WAIT_FOR(ll_func_spi_dma_busy(spi) != 0, + CONFIG_SPI_STM32_BUSY_FLAG_TIMEOUT, + k_yield()); +#else /* wait until spi is no more busy (spi TX fifo is really empty) */ while (ll_func_spi_dma_busy(spi) == 0) { } +#endif #if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) /* toggle the DMA transfer request */ From 100836ee9e38bd16281b3a42d318621476d143f3 Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Wed, 15 Nov 2023 08:30:52 -0300 Subject: [PATCH 0555/1049] zbus: fix warning messages when mixing C and C++ files After some further investigation, I could find the current solution to enable zbus channels (by using ZBUS_CHAN_DECLARE) to be used in C++ files, which generates a warning when we mix C and C++ code. This fixes the issue by using an approach to add the extern keyword only when the file is being compiled with a C++ compiler. Signed-off-by: Rodrigo Peixoto --- include/zephyr/zbus/zbus.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/zephyr/zbus/zbus.h b/include/zephyr/zbus/zbus.h index 8b2aa05175b38ff..285338d4732023b 100644 --- a/include/zephyr/zbus/zbus.h +++ b/include/zephyr/zbus/zbus.h @@ -148,6 +148,12 @@ struct zbus_channel_observation { const struct zbus_observer *const obs; }; +#ifdef __cplusplus +#define _ZBUS_CPP_EXTERN extern +#else +#define _ZBUS_CPP_EXTERN +#endif /* __cplusplus */ + #if defined(CONFIG_ZBUS_ASSERT_MOCK) #define _ZBUS_ASSERT(_cond, _fmt, ...) \ do { \ @@ -304,8 +310,7 @@ struct zbus_channel_observation { static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \ .observers_start_idx = -1, .observers_end_idx = -1}; \ static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \ - IF_ENABLED(CONFIG_CPP, (extern)) \ - const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \ + _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \ ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \ .message = &_CONCAT(_zbus_message_, _name), \ .message_size = sizeof(_type), .user_data = _user_data, .validator = (_validator), \ From 8cfede8f2e2063028635efd9bc3efd08cf483b6e Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Wed, 15 Nov 2023 13:40:38 +0200 Subject: [PATCH 0556/1049] net: lwm2m: Support DTLS Connection Identifier DTLS Connection Identifier support requires DTLS stack that supports it. MbedTLS support in Zephyr is already ported in, also some offloaded sockets support it. Signed-off-by: Seppo Takalo --- doc/connectivity/networking/api/lwm2m.rst | 5 +++++ samples/net/lwm2m_client/overlay-dtls.conf | 3 +++ subsys/net/lib/lwm2m/Kconfig | 7 +++++++ subsys/net/lib/lwm2m/lwm2m_engine.c | 12 ++++++++++++ 4 files changed, 27 insertions(+) diff --git a/doc/connectivity/networking/api/lwm2m.rst b/doc/connectivity/networking/api/lwm2m.rst index 8a36adf88601ac3..3baa4516c5d5c8a 100644 --- a/doc/connectivity/networking/api/lwm2m.rst +++ b/doc/connectivity/networking/api/lwm2m.rst @@ -404,6 +404,11 @@ NoSec In all modes, Server URI resource (ID 0) must contain the full URI for the target server. When DNS names are used, the DNS resolver must be enabled. +When DTLS is used, following options are recommended to reduce DTLS handshake traffic when connection is re-established: + +* :kconfig:option:`CONFIG_LWM2M_DTLS_CID` enables DTLS Connection Identifier support. When server supports it, this completely removes the handshake when device resumes operation after long idle period. Greatly helps when NAT mappings have timed out. +* :kconfig:option:`CONFIG_LWM2M_TLS_SESSION_CACHING` uses session cache when before falling back to full DTLS handshake. Reduces few packets from handshake, when session is still cached on server side. Most significant effect is to avoid full registration. + LwM2M stack provides callbacks in the :c:struct:`lwm2m_ctx` structure. They are used to feed keys from the LwM2M security object into the TLS credential subsystem. By default, these callbacks can be left as NULL pointers, in which case default callbacks are used. diff --git a/samples/net/lwm2m_client/overlay-dtls.conf b/samples/net/lwm2m_client/overlay-dtls.conf index d9cf838ddc51939..930230d8ba4b2be 100644 --- a/samples/net/lwm2m_client/overlay-dtls.conf +++ b/samples/net/lwm2m_client/overlay-dtls.conf @@ -1,9 +1,12 @@ +# Enable DTLS with Connection Identifier CONFIG_LWM2M_DTLS_SUPPORT=y +CONFIG_LWM2M_DTLS_CID=y CONFIG_LWM2M_PEER_PORT=5684 # Select Zephyr mbedtls CONFIG_MBEDTLS=y CONFIG_MBEDTLS_TLS_VERSION_1_2=y +CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID=y # Special MbedTLS changes CONFIG_MBEDTLS_ENABLE_HEAP=y diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 1f5b83f47d0790e..dd3c0c45618f0d4 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -115,6 +115,13 @@ config LWM2M_TLS_SESSION_CACHING help Enabling this only when feature is supported in TLS library. +config LWM2M_DTLS_CID + bool "DTLS Connection Identifier support" + default y if MBEDTLS_SSL_DTLS_CONNECTION_ID + help + Request TLS stack to enable DTLS Connection identifier. This requires stack that support it + and actual effect depends on the target server as well. + config LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP bool "Bootstrap support" help diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index befc8826e0c6491..8fceecf93351c94 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -987,6 +987,18 @@ int lwm2m_set_default_sockopt(struct lwm2m_ctx *ctx) return ret; } } + if (IS_ENABLED(CONFIG_LWM2M_DTLS_CID)) { + /* Enable CID */ + int cid = TLS_DTLS_CID_ENABLED; + + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_DTLS_CID, &cid, + sizeof(cid)); + if (ret) { + ret = -errno; + LOG_ERR("Failed to enable TLS_DTLS_CID: %d", ret); + /* Not fatal, continue. */ + } + } if (ctx->hostname_verify && (ctx->desthostname != NULL)) { /** store character at len position */ From 22d470e6a5c50513ac184a8ba84d8c62a279fd3d Mon Sep 17 00:00:00 2001 From: Ibe Van de Veire Date: Wed, 15 Nov 2023 14:40:35 +0100 Subject: [PATCH 0557/1049] drivers: eth_mcux: Add net_if_mcast_cb for IPv4 Added ability to receive mcast callbacks for both IPv4 and IPv6 instead of only IPv6. Signed-off-by: Ibe Van de Veire --- drivers/ethernet/eth_mcux.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/eth_mcux.c index b4e244ae30471d4..f9ab95db9aa34cd 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/eth_mcux.c @@ -1163,7 +1163,6 @@ static int eth_init(const struct device *dev) return 0; } -#if defined(CONFIG_NET_IPV6) static void net_if_mcast_cb(struct net_if *iface, const struct net_addr *addr, bool is_joined) @@ -1172,30 +1171,29 @@ static void net_if_mcast_cb(struct net_if *iface, struct eth_context *context = dev->data; struct net_eth_addr mac_addr; - if (addr->family != AF_INET6) { + if (IS_ENABLED(CONFIG_NET_IPV4) && addr->family == AF_INET) { + net_eth_ipv4_mcast_to_mac_addr(&addr->in_addr, &mac_addr); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && addr->family == AF_INET6) { + net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr); + } else { return; } - net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr); - if (is_joined) { ENET_AddMulticastGroup(context->base, mac_addr.addr); } else { ENET_LeaveMulticastGroup(context->base, mac_addr.addr); } } -#endif /* CONFIG_NET_IPV6 */ static void eth_iface_init(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); struct eth_context *context = dev->data; -#if defined(CONFIG_NET_IPV6) static struct net_if_mcast_monitor mon; net_if_mcast_mon_register(&mon, iface, net_if_mcast_cb); -#endif /* CONFIG_NET_IPV6 */ net_if_set_link_addr(iface, context->mac_addr, sizeof(context->mac_addr), From ebd70f959f1642c99416f625cff76925f55e1802 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 15 Nov 2023 14:29:55 +0100 Subject: [PATCH 0558/1049] flash host fuse access: Fix for native_sim For native_sim we need to have the fuse library linked with the native simulator runner, not with the embedded code. Let's fix it. Signed-off-by: Alberto Escolar Piedras --- subsys/fs/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/subsys/fs/CMakeLists.txt b/subsys/fs/CMakeLists.txt index 0c1bce7425f16d3..e6c66d304ceee87 100644 --- a/subsys/fs/CMakeLists.txt +++ b/subsys/fs/CMakeLists.txt @@ -31,7 +31,11 @@ if(CONFIG_FUSE_FS_ACCESS) find_package(PkgConfig REQUIRED) pkg_search_module(FUSE REQUIRED fuse) zephyr_include_directories(${FUSE_INCLUDE_DIR}) - zephyr_link_libraries(${FUSE_LIBRARIES}) + if (CONFIG_NATIVE_LIBRARY) + target_link_options(native_simulator INTERFACE "-l${FUSE_LIBRARIES}") + else() + zephyr_link_libraries(${FUSE_LIBRARIES}) + endif() zephyr_library_compile_definitions(_FILE_OFFSET_BITS=64) zephyr_library_sources(fuse_fs_access.c) endif() From 65fd7d42467225c3c9df013fb710587a62bbf874 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 10 Nov 2023 11:42:39 +0100 Subject: [PATCH 0559/1049] samples shell/fs docs: Enable for native_sim Instead of always enabling fuse for native_posix, let's give users instructions on how to enable it while building. In the documentation: replace the references to native_posix with native_sim, improve the links, mention the flash simulator, and provide a separate subsection for FUSE access. Add a separate test for the sample with fuse access enabled and be sure it is possible to run both this and the basic one with native_sim (was filtered out before for native_posix) Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 4 ++ samples/subsys/shell/fs/README.rst | 39 +++++++++++++++---- .../subsys/shell/fs/boards/native_posix.conf | 1 - .../shell/fs/boards/native_posix_64.conf | 1 - samples/subsys/shell/fs/sample.yaml | 21 ++++++---- 5 files changed, 49 insertions(+), 17 deletions(-) delete mode 100644 samples/subsys/shell/fs/boards/native_posix.conf delete mode 100644 samples/subsys/shell/fs/boards/native_posix_64.conf diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 5cd060930e4e2b5..5d4ab7b8b8c99f3 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -428,6 +428,8 @@ The following peripherals are currently provided with this board: The flash content can be accessed from the host system, as explained in the `Host based flash access`_ section. +.. _native_ptty_uart: + PTTY UART ========= @@ -550,6 +552,8 @@ development by integrating more seamlessly with the host operating system: data to a file in the host filesystem. More information can be found in :ref:`Common Tracing Format ` +.. _native_fuse_flash: + Host based flash access *********************** diff --git a/samples/subsys/shell/fs/README.rst b/samples/subsys/shell/fs/README.rst index d8bdecae6cda221..f3d860832255a49 100644 --- a/samples/subsys/shell/fs/README.rst +++ b/samples/subsys/shell/fs/README.rst @@ -17,12 +17,38 @@ A board with LittleFS file system support and UART console Building ******** -Native Posix -============ +native_sim +========== + +You can build this sample for :ref:`native_sim ` with: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/shell/fs + :board: native_sim + :goals: build + :compact: + +Which by default will use the flash simulator. The flash simulator will use a file, +:file:`flash.bin`, in the current directory to keep the flash content. +You have several options to control this. You can check them with: + +.. code-block:: console + + zephyr/zephyr.exe -help + +Check the :ref:`native_sim UART documentation ` for information on how to connect +to the UART. + +With FUSE access in the host filesystem +--------------------------------------- + +If you enable the :ref:`host FUSE filsystem access ` +you will also have the flash filesystem mounted and accessible from your Linux host filesystem. Before starting a build, make sure that the i386 pkgconfig directory is in your search path and that a 32-bit version of libfuse is installed. For more -background information on this requirement see :ref:`native_posix`. +background information on this requirement check +:ref:`the native_sim documentation `. .. code-block:: console @@ -30,12 +56,11 @@ background information on this requirement see :ref:`native_posix`. .. zephyr-app-commands:: :zephyr-app: samples/subsys/shell/fs - :board: native_posix + :board: native_sim + :gen-args: -DCONFIG_FUSE_FS_ACCESS=y :goals: build :compact: -See :ref:`native_posix` on how to connect to the UART. - Reel Board ========== @@ -198,7 +223,7 @@ Remove a file or directory Flash Host Access ================= -For the Native POSIX board the flash partitions can be accessed from the host +For the :ref:`native sim board ` the flash partitions can be accessed from the host Linux system. By default the flash partitions are accessible through the directory *flash* diff --git a/samples/subsys/shell/fs/boards/native_posix.conf b/samples/subsys/shell/fs/boards/native_posix.conf deleted file mode 100644 index 80357cdf245772e..000000000000000 --- a/samples/subsys/shell/fs/boards/native_posix.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_FUSE_FS_ACCESS=y diff --git a/samples/subsys/shell/fs/boards/native_posix_64.conf b/samples/subsys/shell/fs/boards/native_posix_64.conf deleted file mode 100644 index 80357cdf245772e..000000000000000 --- a/samples/subsys/shell/fs/boards/native_posix_64.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_FUSE_FS_ACCESS=y diff --git a/samples/subsys/shell/fs/sample.yaml b/samples/subsys/shell/fs/sample.yaml index e66f984e929d9ac..2f30aad68bbb5be 100644 --- a/samples/subsys/shell/fs/sample.yaml +++ b/samples/subsys/shell/fs/sample.yaml @@ -1,25 +1,30 @@ sample: description: FS shell sample name: FS shell +common: + tags: + - shell + - filesystem + harness: keyboard tests: sample.filesystem.shell: - tags: - - shell - - filesystem - harness: keyboard platform_allow: - reel_board - mimxrt1060_evk - mr_canhubk3 + - native_sim integration_platforms: - reel_board - + sample.filesystem.shell.fuse: + platform_allow: + - native_sim + extra_configs: + - CONFIG_FUSE_FS_ACCESS=y + # This test cannot be run in CI as we lack the fuse library + skip: true sample.filesystem.shell.flash_load: tags: - - shell - - filesystem - flash_load - harness: keyboard platform_allow: nrf52dk_nrf52832 extra_args: CONF_FILE=prj_flash_load.conf integration_platforms: From e2927426d109f624d262e0b7104d3a690599a3d3 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 15 Nov 2023 15:08:43 +0100 Subject: [PATCH 0560/1049] samples shell_module: Replace native_posix w native_sim Replace native_posix with native_sim as the default integration platform. Signed-off-by: Alberto Escolar Piedras --- samples/subsys/shell/shell_module/sample.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/subsys/shell/shell_module/sample.yaml b/samples/subsys/shell/shell_module/sample.yaml index 7aac79eac903513..95ac36bc6b33e9b 100644 --- a/samples/subsys/shell/shell_module/sample.yaml +++ b/samples/subsys/shell/shell_module/sample.yaml @@ -7,7 +7,7 @@ tests: harness: keyboard min_ram: 40 integration_platforms: - - native_posix + - native_sim - intel_socfpga_agilex5_socdk sample.shell.shell_module.usb: depends_on: usb_device @@ -20,14 +20,14 @@ tests: - OVERLAY_CONFIG="overlay-usb.conf" - DTC_OVERLAY_FILE="usb.overlay" integration_platforms: - - native_posix + - native_sim sample.shell.shell_module.minimal: filter: CONFIG_SERIAL and dt_chosen_enabled("zephyr,shell-uart") tags: shell harness: keyboard extra_args: CONF_FILE="prj_minimal.conf" integration_platforms: - - native_posix + - native_sim sample.shell.shell_module.getopt: integration_platforms: - qemu_x86 @@ -51,7 +51,7 @@ tests: min_ram: 40 extra_args: CONF_FILE="prj_login.conf" integration_platforms: - - native_posix + - native_sim sample.shell.shell_module.robot: harness: robot harness_config: From 78eebda134fa06dfae2f23dd759f68527a1f6ef9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 15 Nov 2023 15:10:31 +0100 Subject: [PATCH 0561/1049] samples shell/devmem_load: Replace native_posix w native_sim In the docs replace references to native_posix with native_sim Switch the default test platform to native_sim from native_posix Signed-off-by: Alberto Escolar Piedras --- samples/subsys/shell/devmem_load/README.md | 2 +- samples/subsys/shell/devmem_load/sample.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/subsys/shell/devmem_load/README.md b/samples/subsys/shell/devmem_load/README.md index e4c457bf6a9612f..98b4059dcaf615e 100644 --- a/samples/subsys/shell/devmem_load/README.md +++ b/samples/subsys/shell/devmem_load/README.md @@ -20,7 +20,7 @@ west flash Building for boards without UART interrupt support: ```bash -west build -b native_posix -- -DOVERLAY_CONFIG=prj_poll.conf samples/subsys/shell/devmem_load +west build -b native_sim -- -DOVERLAY_CONFIG=prj_poll.conf samples/subsys/shell/devmem_load ``` ## Running After connecting to the UART console you should see the following output: diff --git a/samples/subsys/shell/devmem_load/sample.yaml b/samples/subsys/shell/devmem_load/sample.yaml index eca1e1f65cd3a4e..2d59490a0eb23bd 100644 --- a/samples/subsys/shell/devmem_load/sample.yaml +++ b/samples/subsys/shell/devmem_load/sample.yaml @@ -9,7 +9,7 @@ common: tests: sample.devmem_load.polled: integration_platforms: - - native_posix + - native_sim extra_args: OVERLAY_CONFIG="prj_poll.conf" sample.devmem_load.uart.interrupt: integration_platforms: From 958cd4ff53982175a74041abda01694fdc381c92 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 6 Nov 2023 23:31:44 +0000 Subject: [PATCH 0562/1049] input: kbd_matrix,npcx: drop explicit LOG_LEVEL define Use the LOG_MODULE_REGISTER argument instead. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 3 +-- drivers/input/input_npcx_kbd.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index f4c49d29d51c782..9c73296ec8a599b 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -13,8 +13,7 @@ #include #include -#define LOG_LEVEL CONFIG_INPUT_LOG_LEVEL -LOG_MODULE_REGISTER(input_kbd_matrix); +LOG_MODULE_REGISTER(input_kbd_matrix, CONFIG_INPUT_LOG_LEVEL); #define INPUT_KBD_MATRIX_ROW_MASK UINT8_MAX diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index e703bd65f3ffeaa..64cde93bda9e4fd 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -18,8 +18,7 @@ #include #include -#define LOG_LEVEL CONFIG_INPUT_LOG_LEVEL -LOG_MODULE_REGISTER(input_npcx_kbd); +LOG_MODULE_REGISTER(input_npcx_kbd, CONFIG_INPUT_LOG_LEVEL); #define ROW_SIZE DT_INST_PROP(0, row_size) From c639ab8e5709b95654f6b85cdbe599b852c892d4 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 11:03:06 +0000 Subject: [PATCH 0563/1049] input: kbd_matrix: clean debug logs Tweak a couple of debug log entries. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 9c73296ec8a599b..16c0d8b0a318cdc 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -197,7 +197,8 @@ static bool input_kbd_matrix_check_key_events(const struct device *dev) key_pressed = input_kbd_matrix_scan(dev); for (int c = 0; c < cfg->col_size; c++) { - LOG_DBG("U%x, P%x, N%x", + LOG_DBG("c=%2d u=%02x p=%02x n=%02x", + c, cfg->matrix_unstable_state[c], cfg->matrix_previous_state[c], cfg->matrix_new_state[c]); @@ -273,7 +274,7 @@ static void input_kbd_matrix_polling_thread(void *arg1, void *unused2, void *unu api->set_detect_mode(dev, true); k_sem_take(&data->poll_lock, K_FOREVER); - LOG_DBG("Start KB scan"); + LOG_DBG("scan start"); /* Disable interrupt of KSI pins and start polling */ api->set_detect_mode(dev, false); From 2cf9d32b29288110b94a518a1bbd4cb554094456 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 11:04:37 +0000 Subject: [PATCH 0564/1049] input: kbd_matrix: use CLAMP instead of two ifs Replace the wait_period_us clamping functions using a single CLAMP, reposition the debug log as well. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 16c0d8b0a318cdc..2518df1291f9ed8 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -12,6 +12,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(input_kbd_matrix, CONFIG_INPUT_LOG_LEVEL); @@ -239,20 +240,10 @@ static void input_kbd_matrix_poll(const struct device *dev) cycles_diff = current_cycles - start_period_cycles; wait_period_us = cfg->poll_period_us - k_cyc_to_us_floor32(cycles_diff); - /* Wait for at least 1ms */ - if (wait_period_us < USEC_PER_MSEC) { - wait_period_us = USEC_PER_MSEC; - } + wait_period_us = CLAMP(wait_period_us, + USEC_PER_MSEC, cfg->poll_period_us); - /* - * Wait period results in a larger number when current cycles - * counter wrap. In this case, the whole poll period is used - */ - if (wait_period_us > cfg->poll_period_us) { - LOG_DBG("wait_period_us: %u", wait_period_us); - - wait_period_us = cfg->poll_period_us; - } + LOG_DBG("wait_period_us: %d", wait_period_us); /* Allow other threads to run while we sleep */ k_usleep(wait_period_us); From eaac842b82013ecb764b5b5f4c901eb704d7d824 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 11:05:39 +0000 Subject: [PATCH 0565/1049] input: kbd_matrix: move scan_cycles_idx increment Move the scan_cycles_idx increment in input_kbd_matrix_update_state as it's only used there, use a modulo operation rather than the if to handle the index wrapping condition. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 2518df1291f9ed8..0b44677f2be9a9e 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -182,18 +182,15 @@ static void input_kbd_matrix_update_state(const struct device *dev) input_report_key(dev, INPUT_BTN_TOUCH, row_bit, true, K_FOREVER); } } + + data->scan_cycles_idx = (data->scan_cycles_idx + 1) % INPUT_KBD_MATRIX_SCAN_OCURRENCES; } static bool input_kbd_matrix_check_key_events(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; - struct input_kbd_matrix_common_data *data = dev->data; bool key_pressed; - if (++data->scan_cycles_idx >= INPUT_KBD_MATRIX_SCAN_OCURRENCES) { - data->scan_cycles_idx = 0U; - } - /* Scan the matrix */ key_pressed = input_kbd_matrix_scan(dev); From 716281b5c9084421df79d4c99c8abe20cd99704e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 11:07:57 +0000 Subject: [PATCH 0566/1049] input: kbd_matrix: move few assignment off the declaration area Move a couple of automatic variable assignment off the declaration block, leaves only structure aliases there, makes it a bit easier to read. Signed-off-by: Fabio Baltieri --- drivers/input/input_kbd_matrix.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 0b44677f2be9a9e..6005a76b3b332ed 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -98,10 +98,12 @@ static void input_kbd_matrix_update_state(const struct device *dev) const struct input_kbd_matrix_common_config *cfg = dev->config; struct input_kbd_matrix_common_data *data = dev->data; uint8_t *matrix_new_state = cfg->matrix_new_state; - uint32_t cycles_now = k_cycle_get_32(); + uint32_t cycles_now; uint8_t row_changed; uint8_t deb_col; + cycles_now = k_cycle_get_32(); + data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now; /* @@ -215,11 +217,13 @@ static bool input_kbd_matrix_check_key_events(const struct device *dev) static void input_kbd_matrix_poll(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; - k_timepoint_t poll_time_end = sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); + k_timepoint_t poll_time_end; uint32_t current_cycles; uint32_t cycles_diff; uint32_t wait_period_us; + poll_time_end = sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); + while (true) { uint32_t start_period_cycles = k_cycle_get_32(); From 3452f9fa4ef4afc32a5a9306a2dc34c7669e72db Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 15:27:11 +0000 Subject: [PATCH 0567/1049] input: it8xxx2_kbd: drop unnecessary include Drop the atomic.h included, this does not use any atomic anymore. Signed-off-by: Fabio Baltieri --- drivers/input/input_ite_it8xxx2_kbd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/input_ite_it8xxx2_kbd.c b/drivers/input/input_ite_it8xxx2_kbd.c index 6f16fba1d6e7c2b..8d688d42db1531f 100644 --- a/drivers/input/input_ite_it8xxx2_kbd.c +++ b/drivers/input/input_ite_it8xxx2_kbd.c @@ -16,7 +16,6 @@ #include #include #include -#include #include LOG_MODULE_REGISTER(input_ite_it8xxx2_kbd); From bf2f06587642302bf38eef87bb3ffd07ba1eeef9 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Wed, 15 Nov 2023 16:16:24 +0100 Subject: [PATCH 0568/1049] Bluetooth: Host: Remove ifdef around `sc_indicate` Instead, `sc_indicate` is defined as a no-op when if would previously not be defined. Signed-off-by: Aleksander Wasaznik --- subsys/bluetooth/host/gatt.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 11c292f159eea5f..103229ea24543ee 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -854,9 +854,7 @@ static void db_hash_gen(void) atomic_set_bit(gatt_sc.flags, DB_HASH_VALID); } -#if defined(CONFIG_BT_SETTINGS) static void sc_indicate(uint16_t start, uint16_t end); -#endif static void do_db_hash(void) { @@ -1515,10 +1513,10 @@ void bt_gatt_init(void) #endif /* CONFIG_BT_SETTINGS && CONFIG_BT_SMP */ } -#if defined(CONFIG_BT_GATT_DYNAMIC_DB) || \ - (defined(CONFIG_BT_GATT_CACHING) && defined(CONFIG_BT_SETTINGS)) static void sc_indicate(uint16_t start, uint16_t end) { +#if defined(CONFIG_BT_GATT_DYNAMIC_DB) || \ + (defined(CONFIG_BT_GATT_CACHING) && defined(CONFIG_BT_SETTINGS)) LOG_DBG("start 0x%04x end 0x%04x", start, end); if (!atomic_test_and_set_bit(gatt_sc.flags, SC_RANGE_CHANGED)) { @@ -1539,8 +1537,8 @@ static void sc_indicate(uint16_t start, uint16_t end) /* Reschedule since the range has changed */ sc_work_submit(SC_TIMEOUT); -} #endif /* BT_GATT_DYNAMIC_DB || (BT_GATT_CACHING && BT_SETTINGS) */ +} void bt_gatt_cb_register(struct bt_gatt_cb *cb) { @@ -5757,14 +5755,12 @@ void bt_gatt_encrypt_change(struct bt_conn *conn) bt_gatt_foreach_attr(0x0001, 0xffff, update_ccc, &data); -#if defined(CONFIG_BT_SETTINGS) && defined(CONFIG_BT_GATT_SERVICE_CHANGED) if (!bt_gatt_change_aware(conn, false)) { /* Send a Service Changed indication if the current peer is * marked as change-unaware. */ sc_indicate(0x0001, 0xffff); } -#endif /* CONFIG_BT_SETTINGS && CONFIG_BT_GATT_SERVICE_CHANGED */ } bool bt_gatt_change_aware(struct bt_conn *conn, bool req) From fef999c06f892418d8238700335ea27f6d3b418f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 9 Nov 2023 13:56:06 +0100 Subject: [PATCH 0569/1049] llext: (cosmetic) remove "inline" in llext.c Let the compiler decide which functions to inline. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index fcaa2317c419df0..f7b0885ece5b532 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -213,7 +213,7 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext) return 0; } -static inline enum llext_section llext_sect_from_mem(enum llext_mem m) +static enum llext_section llext_sect_from_mem(enum llext_mem m) { enum llext_section s; @@ -370,7 +370,7 @@ static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) return 0; } -static inline int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) +static int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) { int ret = 0; size_t syms_size = ldr->sym_cnt * sizeof(struct llext_symbol); @@ -384,7 +384,7 @@ static inline int llext_allocate_symtab(struct llext_loader *ldr, struct llext * return ret; } -static inline int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) +static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) { size_t ent_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_entsize; size_t syms_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_size; From 60aef84cad218c60cb58f17ce800cb7c137a6565 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 9 Nov 2023 14:06:03 +0100 Subject: [PATCH 0570/1049] llext: (cosmetic) use a local variable Simplify llext_copy_symbols() by using a local variable to store a pointer. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index f7b0885ece5b532..772abb386a6fc4e 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -374,11 +374,11 @@ static int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) { int ret = 0; size_t syms_size = ldr->sym_cnt * sizeof(struct llext_symbol); + struct llext_symtable *sym_tab = &ext->sym_tab; - ext->sym_tab.syms = k_heap_alloc(&llext_heap, syms_size, - K_NO_WAIT); - ext->sym_tab.sym_cnt = ldr->sym_cnt; - memset(ext->sym_tab.syms, 0, ldr->sym_cnt * sizeof(struct llext_symbol)); + sym_tab->syms = k_heap_alloc(&llext_heap, syms_size, K_NO_WAIT); + sym_tab->sym_cnt = ldr->sym_cnt; + memset(sym_tab->syms, 0, ldr->sym_cnt * sizeof(struct llext_symbol)); ext->mem_size += syms_size; return ret; @@ -389,6 +389,7 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) size_t ent_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_entsize; size_t syms_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_size; int sym_cnt = syms_size / sizeof(elf_sym_t); + struct llext_symtable *sym_tab = &ext->sym_tab; elf_sym_t sym; int i, j, ret; size_t pos; @@ -418,12 +419,14 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) if (stt == STT_FUNC && stb == STB_GLOBAL && sect != SHN_UNDEF) { const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name); - ext->sym_tab.syms[j].name = name; - ext->sym_tab.syms[j].addr = + __ASSERT(j <= sym_tab->sym_cnt, "Miscalculated symbol number %u\n", j); + + sym_tab->syms[j].name = name; + sym_tab->syms[j].addr = (void *)((uintptr_t)ext->mem[ldr->sect_map[sym.st_shndx]] + sym.st_value); LOG_DBG("function symbol %d name %s addr %p", - j, name, ext->sym_tab.syms[j].addr); + j, name, sym_tab->syms[j].addr); j++; } } From db43d35f617a581b6c2952847a82a504e750eb87 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 9 Nov 2023 15:11:26 +0100 Subject: [PATCH 0571/1049] llext: (cosmetic) remove an unused variable op_code in llext_link() is unused, remove it. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 772abb386a6fc4e..428c142454dedab 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -517,7 +517,7 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) rel.r_offset, name, ELF_ST_TYPE(sym.st_info), ELF_ST_BIND(sym.st_info), sym.st_shndx); - uintptr_t link_addr, op_loc, op_code; + uintptr_t link_addr, op_loc; op_loc = loc + rel.r_offset; @@ -530,11 +530,6 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) "symbol table %s, offset %d, link section %d", name, rel.r_offset, shdr.sh_link); return -ENODATA; - } else { - op_code = (uintptr_t)(loc + rel.r_offset); - - LOG_INF("found symbol %s at 0x%lx, updating op code 0x%lx", - name, link_addr, op_code); } } else if (ELF_ST_TYPE(sym.st_info) == STT_SECTION) { /* Current relocation location holds an offset into the section */ From fb92636056fa4e4a15ec914b1030f4fbc7639d8c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 9 Nov 2023 13:04:21 +0100 Subject: [PATCH 0572/1049] llext: remove a symbol count copy The symbol count in struct llext_loader is redundant, we already have one in struct llext_symtable, accessible via struct llext. Remove the redundant copy. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/loader.h | 1 - subsys/llext/llext.c | 11 ++++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/include/zephyr/llext/loader.h b/include/zephyr/llext/loader.h index 915a6278a443a58..5bcfb1e908b6967 100644 --- a/include/zephyr/llext/loader.h +++ b/include/zephyr/llext/loader.h @@ -92,7 +92,6 @@ struct llext_loader { elf_shdr_t sects[LLEXT_SECT_COUNT]; uint32_t *sect_map; uint32_t sect_cnt; - uint32_t sym_cnt; /** @endcond */ }; diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 428c142454dedab..02ed0e17ed7c297 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -360,7 +360,7 @@ static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) if (stt == STT_FUNC && stb == STB_GLOBAL) { LOG_DBG("function symbol %d, name %s, type tag %d, bind %d, sect %d", i, name, stt, stb, sect); - ldr->sym_cnt++; + ext->sym_tab.sym_cnt++; } else { LOG_DBG("unhandled symbol %d, name %s, type tag %d, bind %d, sect %d", i, name, stt, stb, sect); @@ -372,16 +372,14 @@ static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) static int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) { - int ret = 0; - size_t syms_size = ldr->sym_cnt * sizeof(struct llext_symbol); struct llext_symtable *sym_tab = &ext->sym_tab; + size_t syms_size = sym_tab->sym_cnt * sizeof(struct llext_symbol); sym_tab->syms = k_heap_alloc(&llext_heap, syms_size, K_NO_WAIT); - sym_tab->sym_cnt = ldr->sym_cnt; - memset(sym_tab->syms, 0, ldr->sym_cnt * sizeof(struct llext_symbol)); + memset(sym_tab->syms, 0, syms_size); ext->mem_size += syms_size; - return ret; + return 0; } static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) @@ -570,7 +568,6 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) memset(ldr->sects, 0, sizeof(ldr->sects)); ldr->sect_cnt = 0; - ldr->sym_cnt = 0; size_t sect_map_sz = ldr->hdr.e_shnum * sizeof(uint32_t); From eb3071ebe8512e287f6e9294955784c4f7547178 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 9 Nov 2023 13:48:16 +0100 Subject: [PATCH 0573/1049] llext: check for an allocation failure Add a missing allocation failure check in llext_export_symbols(). Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 02ed0e17ed7c297..6c85a6330725e12 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -376,6 +376,9 @@ static int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext) size_t syms_size = sym_tab->sym_cnt * sizeof(struct llext_symbol); sym_tab->syms = k_heap_alloc(&llext_heap, syms_size, K_NO_WAIT); + if (!sym_tab->syms) { + return -ENOMEM; + } memset(sym_tab->syms, 0, syms_size); ext->mem_size += syms_size; From 21cea07b8c97674032b1457f8430e80a5d4bcdc4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 14 Nov 2023 12:51:27 +0100 Subject: [PATCH 0574/1049] llext: fix a confusion between section indices A common pattern is used throughout llext.c: ext->mem[ldr->sect_map[sym.st_shndx]] where ldr->sect_map[sym.st_shndx] actually contains indices from enum llext_section but ext->mem[] is indexed, using enum llext_mem values. Fix this by changing ldr->sect_map[] to actually contain enum llext_mem values. Signed-off-by: Guennadi Liakhovetski --- include/zephyr/llext/llext.h | 1 + include/zephyr/llext/loader.h | 4 +++- subsys/llext/llext.c | 25 +++++++++++++++++-------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index e0ceece0cf83d3f..a4458a054687fde 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -33,6 +33,7 @@ enum llext_mem { LLEXT_MEM_DATA, LLEXT_MEM_RODATA, LLEXT_MEM_BSS, + LLEXT_MEM_SYMTAB, LLEXT_MEM_STRTAB, LLEXT_MEM_SHSTRTAB, diff --git a/include/zephyr/llext/loader.h b/include/zephyr/llext/loader.h index 5bcfb1e908b6967..3cc53da7d88224c 100644 --- a/include/zephyr/llext/loader.h +++ b/include/zephyr/llext/loader.h @@ -42,6 +42,8 @@ enum llext_section { LLEXT_SECT_COUNT, }; +enum llext_mem; + /** * @brief Linkable loadable extension loader context */ @@ -90,7 +92,7 @@ struct llext_loader { /** @cond ignore */ elf_ehdr_t hdr; elf_shdr_t sects[LLEXT_SECT_COUNT]; - uint32_t *sect_map; + enum llext_mem *sect_map; uint32_t sect_cnt; /** @endcond */ }; diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 6c85a6330725e12..84c38765d95b543 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -128,18 +128,18 @@ static int llext_find_tables(struct llext_loader *ldr) case SHT_DYNSYM: LOG_DBG("symtab at %d", i); ldr->sects[LLEXT_SECT_SYMTAB] = shdr; - ldr->sect_map[i] = LLEXT_SECT_SYMTAB; + ldr->sect_map[i] = LLEXT_MEM_SYMTAB; sect_cnt++; break; case SHT_STRTAB: if (ldr->hdr.e_shstrndx == i) { LOG_DBG("shstrtab at %d", i); ldr->sects[LLEXT_SECT_SHSTRTAB] = shdr; - ldr->sect_map[i] = LLEXT_SECT_SHSTRTAB; + ldr->sect_map[i] = LLEXT_MEM_SHSTRTAB; } else { LOG_DBG("strtab at %d", i); ldr->sects[LLEXT_SECT_STRTAB] = shdr; - ldr->sect_map[i] = LLEXT_SECT_STRTAB; + ldr->sect_map[i] = LLEXT_MEM_STRTAB; } sect_cnt++; break; @@ -192,22 +192,27 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext) LOG_DBG("section %d name %s", i, name); enum llext_section sect_idx; + enum llext_mem mem_idx; if (strcmp(name, ".text") == 0) { sect_idx = LLEXT_SECT_TEXT; + mem_idx = LLEXT_MEM_TEXT; } else if (strcmp(name, ".data") == 0) { sect_idx = LLEXT_SECT_DATA; + mem_idx = LLEXT_MEM_DATA; } else if (strcmp(name, ".rodata") == 0) { sect_idx = LLEXT_SECT_RODATA; + mem_idx = LLEXT_MEM_RODATA; } else if (strcmp(name, ".bss") == 0) { sect_idx = LLEXT_SECT_BSS; + mem_idx = LLEXT_MEM_BSS; } else { LOG_DBG("Not copied section %s", name); continue; } ldr->sects[sect_idx] = shdr; - ldr->sect_map[i] = sect_idx; + ldr->sect_map[i] = mem_idx; } return 0; @@ -230,6 +235,9 @@ static enum llext_section llext_sect_from_mem(enum llext_mem m) case LLEXT_MEM_TEXT: s = LLEXT_SECT_TEXT; break; + case LLEXT_MEM_SYMTAB: + s = LLEXT_SECT_SYMTAB; + break; case LLEXT_MEM_STRTAB: s = LLEXT_SECT_STRTAB; break; @@ -415,17 +423,18 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) uint32_t stt = ELF_ST_TYPE(sym.st_info); uint32_t stb = ELF_ST_BIND(sym.st_info); - uint32_t sect = sym.st_shndx; + unsigned int sect = sym.st_shndx; if (stt == STT_FUNC && stb == STB_GLOBAL && sect != SHN_UNDEF) { + enum llext_mem mem = ldr->sect_map[sect]; + enum llext_section sect_idx = llext_sect_from_mem(mem); const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name); __ASSERT(j <= sym_tab->sym_cnt, "Miscalculated symbol number %u\n", j); sym_tab->syms[j].name = name; - sym_tab->syms[j].addr = - (void *)((uintptr_t)ext->mem[ldr->sect_map[sym.st_shndx]] - + sym.st_value); + sym_tab->syms[j].addr = (void *)((uintptr_t)ext->mem[mem] + + sym.st_value); LOG_DBG("function symbol %d name %s addr %p", j, name, sym_tab->syms[j].addr); j++; From e0ea44cbfa6003c29a1dff785c3d629fda0324cd Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Sep 2023 13:56:54 +0200 Subject: [PATCH 0575/1049] llext: fix symbol address calculation for ET_DYN Symbopl tables of ELF objects of type ET_REL contain offsets instead of addresses as for ET_DYN. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 84c38765d95b543..3d99c8af4fae54c 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -433,8 +433,10 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) __ASSERT(j <= sym_tab->sym_cnt, "Miscalculated symbol number %u\n", j); sym_tab->syms[j].name = name; - sym_tab->syms[j].addr = (void *)((uintptr_t)ext->mem[mem] - + sym.st_value); + sym_tab->syms[j].addr = (void *)((uintptr_t)ext->mem[mem] + + sym.st_value - + (ldr->hdr.e_type == ET_REL ? 0 : + ldr->sects[sect_idx].sh_addr)); LOG_DBG("function symbol %d name %s addr %p", j, name, sym_tab->syms[j].addr); j++; From 530e845f927caa7c2f19aa172f2dbafbf1c731a7 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 16 Nov 2023 09:00:43 +0100 Subject: [PATCH 0576/1049] Revert "Bluetooth: att: don't re-use the ATT buffer for confirmations" This reverts commit 4cd0748a407b118145916393a954231ee11abb1e. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/att.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index cb8c17983cb0d01..aa7cab49f07e3b6 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -677,12 +677,10 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t switch (att_op_get_type(op)) { case ATT_RESPONSE: - /* Use a timeout only when responding */ - timeout = BT_ATT_TIMEOUT; - re_use = true; - break; case ATT_CONFIRMATION: + /* Use a timeout only when responding/confirming */ timeout = BT_ATT_TIMEOUT; + re_use = true; break; default: timeout = K_FOREVER; @@ -710,7 +708,7 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t * This is better than an assert as an assert would * allow a peer to DoS us. */ - LOG_ERR("already processing a REQ/RSP on chan %p", chan); + LOG_ERR("already processing a transaction on chan %p", chan); return NULL; } From bd9c35b4966bf56d908c3416ab2c192781f37ed8 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 16 Nov 2023 09:01:35 +0100 Subject: [PATCH 0577/1049] Revert "Bluetooth: att: re-use REQ buf for RSP" This reverts commit aa7954bd4725bbd46e974a03c0d0312b7e9a483f. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/att.c | 65 +++++---------------------- subsys/bluetooth/host/buf.c | 5 +-- subsys/bluetooth/host/conn_internal.h | 11 +++++ subsys/bluetooth/host/hci_core.c | 28 +++++------- 4 files changed, 36 insertions(+), 73 deletions(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index aa7cab49f07e3b6..031396fa34d3fdb 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -103,7 +103,6 @@ struct bt_att_chan { ATOMIC_DEFINE(flags, ATT_NUM_FLAGS); struct bt_att_req *req; struct k_fifo tx_queue; - struct net_buf *rsp_buf; struct bt_att_tx_meta_data rsp_meta; struct k_work_delayable timeout_work; sys_snode_t node; @@ -667,7 +666,7 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t struct net_buf *buf; struct bt_att_tx_meta_data *data; k_timeout_t timeout; - bool re_use = false; + bool is_rsp = false; if (len + sizeof(op) > bt_att_mtu(chan)) { LOG_WRN("ATT MTU exceeded, max %u, wanted %zu", bt_att_mtu(chan), @@ -680,23 +679,19 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t case ATT_CONFIRMATION: /* Use a timeout only when responding/confirming */ timeout = BT_ATT_TIMEOUT; - re_use = true; + is_rsp = true; break; default: timeout = K_FOREVER; } - if (IS_ENABLED(CONFIG_BT_GATT_READ_MULTIPLE) && - (op == BT_ATT_OP_READ_MULT_RSP || - op == BT_ATT_OP_READ_MULT_VL_RSP)) { - /* We can't re-use the REQ buffer (see below) for these two - * opcodes, as the handler will read from it _after_ allocating - * the RSP buffer. - */ - re_use = false; + buf = bt_l2cap_create_pdu_timeout(NULL, 0, timeout); + if (!buf) { + LOG_ERR("Unable to allocate buffer for op 0x%02x", op); + return NULL; } - if (re_use) { + if (is_rsp) { /* There can only ever be one transaction at a time on a * bearer/channel. Use a dedicated channel meta-data to ensure * we can always queue an (error) RSP for each REQ. The ATT @@ -713,27 +708,8 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t return NULL; } data = &chan->rsp_meta; - - /* Re-use REQ buf to avoid dropping the REQ and timing out. - * This only works if the bearer used to RX REQs is the same as - * for sending the RSP. That should always be the case - * (per-spec). - */ - __ASSERT_NO_MSG(chan->rsp_buf); - buf = net_buf_ref(chan->rsp_buf); - - net_buf_reset(buf); - net_buf_reserve(buf, BT_L2CAP_BUF_SIZE(0)); - - LOG_DBG("re-using REQ buf %p for RSP", buf); + LOG_INF("alloc rsp meta"); } else { - LOG_DBG("alloc buf & meta from global pools"); - buf = bt_l2cap_create_pdu_timeout(NULL, 0, timeout); - if (!buf) { - LOG_ERR("Unable to allocate buffer for op 0x%02x", op); - return NULL; - } - data = tx_meta_data_alloc(timeout); if (!data) { LOG_WRN("Unable to allocate ATT TX meta"); @@ -817,7 +793,6 @@ static void send_err_rsp(struct bt_att_chan *chan, uint8_t req, uint16_t handle, buf = bt_att_chan_create_pdu(chan, BT_ATT_OP_ERROR_RSP, sizeof(*rsp)); if (!buf) { - LOG_ERR("unable to allocate buf for error response"); return; } @@ -2916,20 +2891,6 @@ static int bt_att_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) } } - /* Thread-local variable, shouldn't be used by anything else */ - __ASSERT_NO_MSG(!att_chan->rsp_buf); - - /* Mark buffer free for re-use by the opcode handler. - * - * This allows ATT to always be able to send a RSP (or err RSP) - * to the peer, regardless of the TX buffer usage by other stack - * users (e.g. GATT notifications, L2CAP using global pool, SMP, - * etc..), avoiding an ATT timeout due to resource usage. - * - * The ref is taken by `bt_att_chan_create_pdu`. - */ - att_chan->rsp_buf = net_buf_ref(buf); - if (!handler) { LOG_WRN("Unhandled ATT code 0x%02x", hdr->code); if (att_op_get_type(hdr->code) != ATT_COMMAND && @@ -2937,19 +2898,19 @@ static int bt_att_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) send_err_rsp(att_chan, hdr->code, 0, BT_ATT_ERR_NOT_SUPPORTED); } - goto exit; + return 0; } if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) { if (handler->type == ATT_REQUEST && atomic_test_and_set_bit(att_chan->flags, ATT_PENDING_RSP)) { LOG_WRN("Ignoring unexpected request"); - goto exit; + return 0; } else if (handler->type == ATT_INDICATION && atomic_test_and_set_bit(att_chan->flags, ATT_PENDING_CFM)) { LOG_WRN("Ignoring unexpected indication"); - goto exit; + return 0; } } @@ -2965,10 +2926,6 @@ static int bt_att_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) send_err_rsp(att_chan, hdr->code, 0, err); } -exit: - net_buf_unref(att_chan->rsp_buf); - att_chan->rsp_buf = NULL; - return 0; } diff --git a/subsys/bluetooth/host/buf.c b/subsys/bluetooth/host/buf.c index ff9620766fecb0b..50b567d31b76a01 100644 --- a/subsys/bluetooth/host/buf.c +++ b/subsys/bluetooth/host/buf.c @@ -43,15 +43,14 @@ NET_BUF_POOL_FIXED_DEFINE(discardable_pool, CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT, #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) NET_BUF_POOL_DEFINE(acl_in_pool, CONFIG_BT_BUF_ACL_RX_COUNT, BT_BUF_ACL_SIZE(CONFIG_BT_BUF_ACL_RX_SIZE), - MAX(sizeof(struct bt_buf_data), CONFIG_BT_CONN_TX_USER_DATA_SIZE), - bt_hci_host_num_completed_packets); + sizeof(struct acl_data), bt_hci_host_num_completed_packets); NET_BUF_POOL_FIXED_DEFINE(evt_pool, CONFIG_BT_BUF_EVT_RX_COUNT, BT_BUF_EVT_RX_SIZE, 8, NULL); #else NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, - BT_BUF_RX_SIZE, CONFIG_BT_CONN_TX_USER_DATA_SIZE, + BT_BUF_RX_SIZE, 8, NULL); #endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index e3fd60da34e701c..7741e259a618103 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -146,6 +146,17 @@ struct bt_conn_tx { uint32_t pending_no_cb; }; +struct acl_data { + /* Extend the bt_buf user data */ + struct bt_buf_data buf_data; + + /* Index into the bt_conn storage array */ + uint8_t index; + + /** ACL connection handle */ + uint16_t handle; +}; + struct bt_conn { uint16_t handle; enum bt_conn_type type; diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 51f9ac8d2115d1a..de4fb637b4922ee 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -111,16 +111,8 @@ struct cmd_data { static struct cmd_data cmd_data[CONFIG_BT_BUF_CMD_TX_COUNT]; -#if defined(CONFIG_BT_CONN) -struct acl_data { - uint16_t acl_handle; -}; - -static struct acl_data acl_data[CONFIG_BT_BUF_ACL_RX_COUNT]; -#endif - #define cmd(buf) (&cmd_data[net_buf_id(buf)]) -#define acl(buf) (&acl_data[net_buf_id(buf)]) +#define acl(buf) ((struct acl_data *)net_buf_user_data(buf)) void bt_hci_cmd_state_set_init(struct net_buf *buf, struct bt_hci_cmd_state_set *state, @@ -209,9 +201,10 @@ void bt_hci_host_num_completed_packets(struct net_buf *buf) { struct bt_hci_cp_host_num_completed_packets *cp; - uint16_t handle = acl(buf)->acl_handle; + uint16_t handle = acl(buf)->handle; struct bt_hci_handle_count *hc; struct bt_conn *conn; + uint8_t index = acl(buf)->index; net_buf_destroy(buf); @@ -220,9 +213,9 @@ void bt_hci_host_num_completed_packets(struct net_buf *buf) return; } - conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ALL); + conn = bt_conn_lookup_index(index); if (!conn) { - LOG_WRN("Unable to look up conn with ACL handle %u", handle); + LOG_WRN("Unable to look up conn with index 0x%02x", index); return; } @@ -519,9 +512,10 @@ static void hci_acl(struct net_buf *buf) handle = sys_le16_to_cpu(hdr->handle); flags = bt_acl_flags(handle); - acl(buf)->acl_handle = bt_acl_handle(handle); + acl(buf)->handle = bt_acl_handle(handle); + acl(buf)->index = BT_CONN_INDEX_INVALID; - LOG_DBG("handle %u len %u flags %u", acl(buf)->acl_handle, len, flags); + LOG_DBG("handle %u len %u flags %u", acl(buf)->handle, len, flags); if (buf->len != len) { LOG_ERR("ACL data length mismatch (%u != %u)", buf->len, len); @@ -529,13 +523,15 @@ static void hci_acl(struct net_buf *buf) return; } - conn = bt_conn_lookup_handle(acl(buf)->acl_handle, BT_CONN_TYPE_ALL); + conn = bt_conn_lookup_handle(acl(buf)->handle, BT_CONN_TYPE_ALL); if (!conn) { - LOG_ERR("Unable to find conn for handle %u", acl(buf)->acl_handle); + LOG_ERR("Unable to find conn for handle %u", acl(buf)->handle); net_buf_unref(buf); return; } + acl(buf)->index = bt_conn_index(conn); + bt_conn_recv(conn, buf, flags); bt_conn_unref(conn); } From dfd762427066dfc7b5a140ec27e34b5c7d0f890a Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 16 Nov 2023 09:03:53 +0100 Subject: [PATCH 0578/1049] Revert "Bluetooth: att: use a dedicated metadata struct for RSP PDUs" This reverts commit 14858d96d87d33ebb593d61380f4607e14107287. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/att.c | 72 ++++++++++--------------------------- 1 file changed, 18 insertions(+), 54 deletions(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 031396fa34d3fdb..130b4ab0853aa86 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -83,18 +83,6 @@ enum { ATT_NUM_FLAGS, }; -struct bt_att_tx_meta_data { - struct bt_att_chan *att_chan; - uint16_t attr_count; - bt_gatt_complete_func_t func; - void *user_data; - enum bt_att_chan_opt chan_opt; -}; - -struct bt_att_tx_meta { - struct bt_att_tx_meta_data *data; -}; - /* ATT channel specific data */ struct bt_att_chan { /* Connection this channel is associated with */ @@ -103,7 +91,6 @@ struct bt_att_chan { ATOMIC_DEFINE(flags, ATT_NUM_FLAGS); struct bt_att_req *req; struct k_fifo tx_queue; - struct bt_att_tx_meta_data rsp_meta; struct k_work_delayable timeout_work; sys_snode_t node; }; @@ -172,6 +159,18 @@ static struct bt_att_req cancel; */ static k_tid_t att_handle_rsp_thread; +struct bt_att_tx_meta_data { + struct bt_att_chan *att_chan; + uint16_t attr_count; + bt_gatt_complete_func_t func; + void *user_data; + enum bt_att_chan_opt chan_opt; +}; + +struct bt_att_tx_meta { + struct bt_att_tx_meta_data *data; +}; + #define bt_att_tx_meta_data(buf) (((struct bt_att_tx_meta *)net_buf_user_data(buf))->data) static struct bt_att_tx_meta_data tx_meta_data[CONFIG_BT_CONN_TX_MAX]; @@ -193,22 +192,9 @@ static struct bt_att_tx_meta_data *tx_meta_data_alloc(k_timeout_t timeout) static inline void tx_meta_data_free(struct bt_att_tx_meta_data *data) { __ASSERT_NO_MSG(data); - bool alloc_from_global = PART_OF_ARRAY(tx_meta_data, data); - - if (data == &data->att_chan->rsp_meta) { - /* "Free-ness" is kept by remote: There can only ever be one - * transaction per-bearer. - */ - __ASSERT_NO_MSG(!alloc_from_global); - } else { - __ASSERT_NO_MSG(alloc_from_global); - } (void)memset(data, 0, sizeof(*data)); - - if (alloc_from_global) { - k_fifo_put(&free_att_tx_meta_data, data); - } + k_fifo_put(&free_att_tx_meta_data, data); } static int bt_att_chan_send(struct bt_att_chan *chan, struct net_buf *buf); @@ -666,7 +652,6 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t struct net_buf *buf; struct bt_att_tx_meta_data *data; k_timeout_t timeout; - bool is_rsp = false; if (len + sizeof(op) > bt_att_mtu(chan)) { LOG_WRN("ATT MTU exceeded, max %u, wanted %zu", bt_att_mtu(chan), @@ -679,7 +664,6 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t case ATT_CONFIRMATION: /* Use a timeout only when responding/confirming */ timeout = BT_ATT_TIMEOUT; - is_rsp = true; break; default: timeout = K_FOREVER; @@ -691,31 +675,11 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t return NULL; } - if (is_rsp) { - /* There can only ever be one transaction at a time on a - * bearer/channel. Use a dedicated channel meta-data to ensure - * we can always queue an (error) RSP for each REQ. The ATT - * module can then reschedule the RSP if it is not able to send - * it immediately. - */ - if (chan->rsp_meta.att_chan) { - /* Returning a NULL here will trigger an ATT timeout. - * This is better than an assert as an assert would - * allow a peer to DoS us. - */ - LOG_ERR("already processing a transaction on chan %p", chan); - - return NULL; - } - data = &chan->rsp_meta; - LOG_INF("alloc rsp meta"); - } else { - data = tx_meta_data_alloc(timeout); - if (!data) { - LOG_WRN("Unable to allocate ATT TX meta"); - net_buf_unref(buf); - return NULL; - } + data = tx_meta_data_alloc(timeout); + if (!data) { + LOG_WRN("Unable to allocate ATT TX meta"); + net_buf_unref(buf); + return NULL; } if (IS_ENABLED(CONFIG_BT_EATT)) { From 3b96c2421ee4b374cac813c6f2144711bc2982db Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Thu, 16 Nov 2023 11:16:24 +0100 Subject: [PATCH 0579/1049] MAINTAINERS: add the PLIC interrupt controller driver to the RISC-V area This commit adds the RISC-V Platform-Level Interrupt Controller driver to the RISC-V area of maintenance. Signed-off-by: Filip Kokosinski --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 32a1d1efb54b01d..aa4fbaadced7287 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2290,6 +2290,7 @@ RISCV arch: - soc/riscv/ - tests/arch/riscv/ - doc/hardware/arch/risc-v.rst + - drivers/interrupt_controller/intc_plic.c labels: - "area: RISCV" From 190f0dde266c222fd822030f4bc52b0e3d1a25dd Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 16:35:41 +0000 Subject: [PATCH 0580/1049] doc: migration-guide: annotate various entry with the PR numbers Add a PR number reference to various migration guide entries. Signed-off-by: Fabio Baltieri --- doc/releases/migration-guide-3.6.rst | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index dfd3fdb3cf6b1df..ddf42b6dc3ab4a8 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -26,7 +26,7 @@ Optional Modules The following modules have been made optional and are not downloaded with `west update` by default anymore: -* ``canopennode`` +* ``canopennode`` (:github:`64139`) To enable them again use the ``west config manifest.project-filter -- +`` command, or ``west config manifest.group-filter -- +optional`` to @@ -53,6 +53,8 @@ Device Drivers and Device Tree }; }; + (:github:`62994`) + Power Management ================ @@ -61,7 +63,7 @@ Bootloader * MCUboot's deprecated ``CONFIG_ZEPHYR_TRY_MASS_ERASE`` Kconfig option has been removed. If an erase is needed when flashing MCUboot, this should now be provided directly to the ``west`` - command e.g. ``west flash --erase``. + command e.g. ``west flash --erase``. (:github:`64703`) Bluetooth ========= @@ -71,15 +73,15 @@ Bluetooth :kconfig:option:`CONFIG_BT_HCI_IPC`, and the ``zephyr,bt-hci-rpmsg-ipc`` Devicetree chosen is now ``zephyr,bt-hci-ipc``. The existing sample has also been renamed, from ``samples/bluetooth/hci_rpmsg`` to - ``samples/bluetooth/hci_ipc``. + ``samples/bluetooth/hci_ipc``. (:github:`64391`) * The BT GATT callback list, appended to by :c:func:`bt_gatt_cb_register`, is no longer cleared on :c:func:`bt_enable`. Callbacks can now be registered before the initial call to :c:func:`bt_enable`, and should no longer be re-registered after a :c:func:`bt_disable` - :c:func:`bt_enable` cycle. + :c:func:`bt_enable` cycle. (:github:`63693`) * The Bluetooth Mesh ``model`` declaration has been changed to add prefix ``const``. The ``model->user_data``, ``model->elem_idx`` and ``model->mod_idx`` field has been changed to the new runtime structure, replaced by ``model->rt->user_data``, ``model->rt->elem_idx`` and - ``model->rt->mod_idx`` separately. + ``model->rt->mod_idx`` separately. (:github:`65152`) LoRaWAN ======= @@ -88,6 +90,7 @@ LoRaWAN renamed from ``lorawan_set_battery_level_callback`` to :c:func:`lorawan_register_battery_level_callback` and the return type is now ``void``. This is more consistent with similar functions for downlink and data rate changed callbacks. + (:github:`65103`) Networking ========== @@ -96,18 +99,19 @@ Networking :c:func:`coap_remove_observer` now returns a result if the observer was removed. This change is used by the newly introduced :ref:`coap_server_interface` subsystem. Also, the ``request`` argument for :c:func:`coap_well_known_core_get` is made ``const``. + (:github:`64265`) Other Subsystems ================ * MCUmgr applications that make use of serial transports (shell or UART) must now select :kconfig:option:`CONFIG_CRC`, this was previously erroneously selected if MCUmgr was enabled, - when for non-serial transports it was not needed. + when for non-serial transports it was not needed. (:github:`64078`) * Touchscreen drivers :dtcompatible:`focaltech,ft5336` and :dtcompatible:`goodix,gt911` were using the incorrect polarity for the respective ``reset-gpios``. This has been fixed so those signals now have to - be flagged as :c:macro:`GPIO_ACTIVE_LOW` in the devicetree. + be flagged as :c:macro:`GPIO_ACTIVE_LOW` in the devicetree. (:github:`64800`) Recommended Changes ******************* From f25e2201a4ca248348d3948dc1210ac7dbbe740d Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 15 Nov 2023 14:20:03 +0000 Subject: [PATCH 0581/1049] tests: fix various test identifiers Fix a few inconsistent test identifiers. Signed-off-by: Anas Nashif --- samples/subsys/sensing/simple/sample.yaml | 2 +- samples/subsys/task_wdt/sample.yaml | 7 ++++--- tests/arch/arc/arc_dsp_sharing/testcase.yaml | 4 ++-- tests/arch/arm/arm_hardfault_validation/testcase.yaml | 2 +- tests/arch/arm/arm_interrupt/testcase.yaml | 6 +++--- tests/arch/arm/arm_runtime_nmi/testcase.yaml | 2 +- tests/drivers/build_all/can/testcase.yaml | 6 +++--- tests/drivers/build_all/fpga/testcase.yaml | 2 +- tests/drivers/ethernet/eth_ivshmem_queue/testcase.yaml | 2 +- tests/drivers/virtualization/ivshmem/plain/testcase.yaml | 2 +- tests/net/conn_mgr_conn/testcase.yaml | 2 +- tests/net/conn_mgr_monitor/testcase.yaml | 4 ++-- 12 files changed, 21 insertions(+), 20 deletions(-) diff --git a/samples/subsys/sensing/simple/sample.yaml b/samples/subsys/sensing/simple/sample.yaml index e8b33b417d96b4b..de2508c0d49af31 100644 --- a/samples/subsys/sensing/simple/sample.yaml +++ b/samples/subsys/sensing/simple/sample.yaml @@ -11,7 +11,7 @@ common: regex: - "sensing subsystem run successfully" tests: - sample.subsys.sensing.simple: + sample.sensing.simple: platform_allow: - native_sim tags: sensing diff --git a/samples/subsys/task_wdt/sample.yaml b/samples/subsys/task_wdt/sample.yaml index 1c9c300a8782122..334d6e3a24f7cb0 100644 --- a/samples/subsys/task_wdt/sample.yaml +++ b/samples/subsys/task_wdt/sample.yaml @@ -1,8 +1,9 @@ sample: name: Task Watchdog Subsytem Sample common: - tags: subsys harness: console + tags: + - task_wdt harness_config: type: multi_line ordered: true @@ -19,10 +20,10 @@ common: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 tests: - sample.subsys.task_wdt: + sample.task_wdt: integration_platforms: - nucleo_g474re - sample.subsys.task_wdt.no_hw_fallback: + sample.task_wdt.no_hw_fallback: extra_args: CONF_FILE="prj_no_hw_fallback.conf" platform_allow: - mr_canhubk3 diff --git a/tests/arch/arc/arc_dsp_sharing/testcase.yaml b/tests/arch/arc/arc_dsp_sharing/testcase.yaml index 09ac8efa78980f8..21cb221e059be06 100644 --- a/tests/arch/arc/arc_dsp_sharing/testcase.yaml +++ b/tests/arch/arc/arc_dsp_sharing/testcase.yaml @@ -1,8 +1,8 @@ tests: - dsp_sharing.test_load_store: + arch.arc.dsp_sharing.test_load_store: filter: CONFIG_ISA_ARCV2 and CONFIG_ARC_HAS_DSP platform_allow: nsim_em11d - dsp_sharing.test_calculation: + arch.arc.dsp_sharing.test_calculation: filter: CONFIG_ISA_ARCV2 and CONFIG_ARC_HAS_DSP toolchain_allow: arcmwdt platform_allow: nsim_em11d diff --git a/tests/arch/arm/arm_hardfault_validation/testcase.yaml b/tests/arch/arm/arm_hardfault_validation/testcase.yaml index 3294ff9c3052c35..f65fbfdb32a44a1 100644 --- a/tests/arch/arm/arm_hardfault_validation/testcase.yaml +++ b/tests/arch/arm/arm_hardfault_validation/testcase.yaml @@ -1,5 +1,5 @@ tests: - arch.interrupt.arm.hardfault_validation: + arch.arm.interrupt.hardfault_validation: filter: not CONFIG_TRUSTED_EXECUTION_NONSECURE and CONFIG_ARMV7_M_ARMV8_M_MAINLINE arch_allow: arm tags: arm diff --git a/tests/arch/arm/arm_interrupt/testcase.yaml b/tests/arch/arm/arm_interrupt/testcase.yaml index 9c92b9476312192..4895e2a90ccf1e2 100644 --- a/tests/arch/arm/arm_interrupt/testcase.yaml +++ b/tests/arch/arm/arm_interrupt/testcase.yaml @@ -7,16 +7,16 @@ common: ignore_faults: true arch_allow: arm tests: - arch.interrupt.arm: + arch.arm.interrupt: filter: not CONFIG_TRUSTED_EXECUTION_NONSECURE - arch.interrupt.no_optimizations: + arch.arm.interrupt.no_optimizations: filter: not CONFIG_TRUSTED_EXECUTION_NONSECURE extra_configs: - CONFIG_NO_OPTIMIZATIONS=y - CONFIG_ZTEST_WARN_NO_OPTIMIZATIONS=n - CONFIG_IDLE_STACK_SIZE=512 - CONFIG_MAIN_STACK_SIZE=2048 - arch.interrupt.extra_exception_info: + arch.arm.interrupt.extra_exception_info: filter: not CONFIG_TRUSTED_EXECUTION_NONSECURE extra_configs: - CONFIG_EXTRA_EXCEPTION_INFO=y diff --git a/tests/arch/arm/arm_runtime_nmi/testcase.yaml b/tests/arch/arm/arm_runtime_nmi/testcase.yaml index 34e95fe6f741c17..55706b0fedd30cc 100644 --- a/tests/arch/arm/arm_runtime_nmi/testcase.yaml +++ b/tests/arch/arm/arm_runtime_nmi/testcase.yaml @@ -1,5 +1,5 @@ tests: - arch.interrupt.arm.nmi: + arch.arm.interrupt.nmi: filter: CONFIG_ARMV6_M_ARMV8_M_BASELINE or CONFIG_ARMV7_M_ARMV8_M_MAINLINE and not CONFIG_BUILD_WITH_TFM arch_allow: arm diff --git a/tests/drivers/build_all/can/testcase.yaml b/tests/drivers/build_all/can/testcase.yaml index 749da969f761bd9..c276b24c65208d7 100644 --- a/tests/drivers/build_all/can/testcase.yaml +++ b/tests/drivers/build_all/can/testcase.yaml @@ -4,18 +4,18 @@ common: - drivers - can tests: - drivers.build_all.can.mcp2515: + drivers.can.build_all.mcp2515: depends_on: - arduino_spi - arduino_gpio extra_args: SHIELD=dfrobot_can_bus_v2_0 platform_allow: frdm_k64f - drivers.build_all.can.tcan4x5x: + drivers.can.build_all.tcan4x5x: depends_on: - arduino_spi - arduino_gpio extra_args: SHIELD=tcan4550evm platform_allow: frdm_k64f - drivers.build_all.can.mcp251xfd: + drivers.can.build_all.mcp251xfd: extra_args: SHIELD=mikroe_mcp2518fd_click platform_allow: lpcxpresso55s28 diff --git a/tests/drivers/build_all/fpga/testcase.yaml b/tests/drivers/build_all/fpga/testcase.yaml index 75821c7a1a76f8b..33cccf76dde4e59 100644 --- a/tests/drivers/build_all/fpga/testcase.yaml +++ b/tests/drivers/build_all/fpga/testcase.yaml @@ -5,5 +5,5 @@ common: platform_allow: native_posix build_only: true tests: - fpga.build: + drivers.fpga.build: tags: fpga diff --git a/tests/drivers/ethernet/eth_ivshmem_queue/testcase.yaml b/tests/drivers/ethernet/eth_ivshmem_queue/testcase.yaml index c4512d95326e9f4..9411b3d83ff18d2 100644 --- a/tests/drivers/ethernet/eth_ivshmem_queue/testcase.yaml +++ b/tests/drivers/ethernet/eth_ivshmem_queue/testcase.yaml @@ -1,3 +1,3 @@ tests: - net.eth_ivshmem_queue: + net.ethernet.eth_ivshmem_queue: platform_allow: qemu_cortex_a53 diff --git a/tests/drivers/virtualization/ivshmem/plain/testcase.yaml b/tests/drivers/virtualization/ivshmem/plain/testcase.yaml index 37208f9367ffa43..26330e1b1333cd7 100644 --- a/tests/drivers/virtualization/ivshmem/plain/testcase.yaml +++ b/tests/drivers/virtualization/ivshmem/plain/testcase.yaml @@ -1,5 +1,5 @@ tests: - virtualization.ivshmem: + drivers.virtualization.ivshmem: arch_allow: - x86 - arm64 diff --git a/tests/net/conn_mgr_conn/testcase.yaml b/tests/net/conn_mgr_conn/testcase.yaml index 07bb325cb0aa253..ff78e1dc721d7ed 100644 --- a/tests/net/conn_mgr_conn/testcase.yaml +++ b/tests/net/conn_mgr_conn/testcase.yaml @@ -2,7 +2,7 @@ common: min_ram: 16 depends_on: netif tests: - net.conn_mgr_conn: + net.conn_mgr.conn: tags: - net - iface diff --git a/tests/net/conn_mgr_monitor/testcase.yaml b/tests/net/conn_mgr_monitor/testcase.yaml index 64ce1efacec044b..ac6b5ad3c612782 100644 --- a/tests/net/conn_mgr_monitor/testcase.yaml +++ b/tests/net/conn_mgr_monitor/testcase.yaml @@ -3,9 +3,9 @@ common: depends_on: netif tags: net iface tests: - net.conn_mgr_nodad: + net.conn_mgr.nodad: extra_configs: - CONFIG_NET_IPV6_DAD=n - net.conn_mgr_dad: + net.conn_mgr.dad: extra_configs: - CONFIG_NET_IPV6_DAD=y From 968916572c01165115abb370241d315ab3fbb106 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 16 Nov 2023 10:56:03 +0100 Subject: [PATCH 0582/1049] drivers: watchdog: wdt_nrfx: Remove config field from config structure The field config of `nrfx_wdt_config_t` type is redundant in device config structure. Instead of that local variable is used in the setup function. Signed-off-by: Adam Wojasinski --- drivers/watchdog/wdt_nrfx.c | 44 ++++++++++++++----------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index 8d61f11d6fbe5ad..ff5fd0179f88113 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -20,37 +20,32 @@ struct wdt_nrfx_data { }; struct wdt_nrfx_config { - nrfx_wdt_t wdt; - nrfx_wdt_config_t config; + nrfx_wdt_t wdt; }; static int wdt_nrf_setup(const struct device *dev, uint8_t options) { const struct wdt_nrfx_config *config = dev->config; - struct wdt_nrfx_data *data = dev->data; - uint32_t behaviour; + const struct wdt_nrfx_data *data = dev->data; + nrfx_err_t err_code; - /* Activate all available options. Run in all cases. */ - behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK | NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; + nrfx_wdt_config_t wdt_config = { + .reload_value = data->m_timeout + }; - /* Deactivate running in sleep mode. */ - if (options & WDT_OPT_PAUSE_IN_SLEEP) { - behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK; + if (!(options & WDT_OPT_PAUSE_IN_SLEEP)) { + wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK; } - /* Deactivate running when debugger is attached. */ - if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { - behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; + if (!(options & WDT_OPT_PAUSE_HALTED_BY_DBG)) { + wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; } - nrf_wdt_behaviour_set(config->wdt.p_reg, behaviour); - /* The watchdog timer is driven by the LFCLK clock running at 32768 Hz. - * The timeout value given in milliseconds needs to be converted here - * to watchdog ticks.*/ - nrf_wdt_reload_value_set( - config->wdt.p_reg, - (uint32_t)(((uint64_t)data->m_timeout * 32768U) - / 1000)); + err_code = nrfx_wdt_reconfigure(&config->wdt, &wdt_config); + + if (err_code != NRFX_SUCCESS) { + return -EBUSY; + } nrfx_wdt_enable(&config->wdt); @@ -162,8 +157,8 @@ static void wdt_event_handler(const struct device *dev, uint32_t requests) IRQ_CONNECT(DT_IRQN(WDT(idx)), DT_IRQ(WDT(idx), priority), \ nrfx_isr, nrfx_wdt_##idx##_irq_handler, 0); \ err_code = nrfx_wdt_init(&config->wdt, \ - &config->config, \ - wdt_##idx##_event_handler); \ + NULL, \ + wdt_##idx##_event_handler); \ if (err_code != NRFX_SUCCESS) { \ return -EBUSY; \ } \ @@ -175,11 +170,6 @@ static void wdt_event_handler(const struct device *dev, uint32_t requests) }; \ static const struct wdt_nrfx_config wdt_##idx##z_config = { \ .wdt = NRFX_WDT_INSTANCE(idx), \ - .config = { \ - .behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK | \ - NRF_WDT_BEHAVIOUR_RUN_HALT_MASK, \ - .reload_value = 2000, \ - } \ }; \ DEVICE_DT_DEFINE(WDT(idx), \ wdt_##idx##_init, \ From 599bcb1e5d470e4fafce7418ff6516f0573f6d03 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 22 Sep 2023 09:08:17 +0200 Subject: [PATCH 0583/1049] drivers: watchdog: wdt_nrfx: Implement disable API nRF5340 SoC has `TASK_STOP` this patch implements disabling watchdog for that SoC and enables allowing WDT to STOP in WDT setup. Signed-off-by: Adam Wojasinski --- drivers/watchdog/wdt_nrfx.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index ff5fd0179f88113..98fcb713b818349 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -33,6 +33,10 @@ static int wdt_nrf_setup(const struct device *dev, uint8_t options) .reload_value = data->m_timeout }; +#if NRF_WDT_HAS_STOP + wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_STOP_ENABLE_MASK; +#endif + if (!(options & WDT_OPT_PAUSE_IN_SLEEP)) { wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK; } @@ -54,9 +58,21 @@ static int wdt_nrf_setup(const struct device *dev, uint8_t options) static int wdt_nrf_disable(const struct device *dev) { - /* Started watchdog cannot be stopped on nRF devices. */ +#if NRFX_WDT_HAS_STOP + const struct wdt_nrfx_config *config = dev->config; + nrfx_err_t err_code; + + err_code = nrfx_wdt_stop(&config->wdt); + + if (err_code != NRFX_SUCCESS) { + return -ENOTSUP; + } + + return 0; +#else ARG_UNUSED(dev); return -EPERM; +#endif } static int wdt_nrf_install_timeout(const struct device *dev, From 31ee2e678d2be4f47918c073f615129ed37bbfb3 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 15 Nov 2023 17:36:10 +0200 Subject: [PATCH 0584/1049] net: context: Allow binding to different interfaces Allow user to bind to different network interface. This is useful if binding a multicast address to a certain network interface. Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_context.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index ef9fc640f08164a..9cdcaadc8221cd7 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -121,7 +121,8 @@ static inline bool is_in_tcp_time_wait_state(struct net_context *context) #endif } -static int check_used_port(enum net_ip_protocol proto, +static int check_used_port(struct net_if *iface, + enum net_ip_protocol proto, uint16_t local_port, const struct sockaddr *local_addr, bool reuseaddr_set, @@ -140,6 +141,12 @@ static int check_used_port(enum net_ip_protocol proto, continue; } + if (net_context_is_bound_to_iface(&contexts[i])) { + if (iface != NULL && iface != net_context_get_iface(&contexts[i])) { + continue; + } + } + if (IS_ENABLED(CONFIG_NET_IPV6) && local_addr->sa_family == AF_INET6) { if (net_sin6_ptr(&contexts[i].local)->sin6_addr == NULL || @@ -271,7 +278,7 @@ static uint16_t find_available_port(struct net_context *context, do { local_port = sys_rand32_get() | 0x8000; - } while (check_used_port(net_context_get_proto(context), + } while (check_used_port(NULL, net_context_get_proto(context), htons(local_port), addr, false, false) == -EEXIST); return htons(local_port); @@ -285,7 +292,7 @@ bool net_context_port_in_use(enum net_ip_protocol proto, uint16_t local_port, const struct sockaddr *local_addr) { - return check_used_port(proto, htons(local_port), local_addr, false, false) != 0; + return check_used_port(NULL, proto, htons(local_port), local_addr, false, false) != 0; } #if defined(CONFIG_NET_CONTEXT_CHECK) @@ -742,7 +749,8 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, ret = 0; if (addr6->sin6_port) { - ret = check_used_port(context->proto, + ret = check_used_port(iface, + context->proto, addr6->sin6_port, addr, net_context_is_reuseaddr_set(context), @@ -750,6 +758,8 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, if (ret != 0) { NET_ERR("Port %d is in use!", ntohs(addr6->sin6_port)); + NET_DBG("Interface %d (%p)", + iface ? net_if_get_by_iface(iface) : 0, iface); ret = -EADDRINUSE; goto unlock_ipv6; } else { @@ -839,7 +849,8 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, ret = 0; if (addr4->sin_port) { - ret = check_used_port(context->proto, + ret = check_used_port(iface, + context->proto, addr4->sin_port, addr, net_context_is_reuseaddr_set(context), @@ -848,6 +859,8 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, NET_ERR("Port %d is in use!", ntohs(addr4->sin_port)); ret = -EADDRINUSE; + NET_DBG("Interface %d (%p)", + iface ? net_if_get_by_iface(iface) : 0, iface); goto unlock_ipv4; } else { net_sin_ptr(&context->local)->sin_port = From 8157b487342cb5502101d51d62c06ebc923421d4 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 15 Nov 2023 17:39:14 +0200 Subject: [PATCH 0585/1049] net: context: Add function to bound to a network interface Helper function that marks the net_context to bound to a network interface. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_context.h | 17 +++++++++++++++++ subsys/net/lib/sockets/sockets.c | 3 +-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index 6c0453a3d2b5715..ea116a24846c530 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -672,6 +672,23 @@ static inline void net_context_set_iface(struct net_context *context, context->iface = net_if_get_by_iface(iface); } +/** + * @brief Bind network interface to this context. + * + * @details This function binds network interface to this context. + * + * @param context Network context. + * @param iface Network interface. + */ +static inline void net_context_bind_iface(struct net_context *context, + struct net_if *iface) +{ + NET_ASSERT(iface); + + context->flags |= NET_CONTEXT_BOUND_TO_IFACE; + net_context_set_iface(context, iface); +} + static inline uint8_t net_context_get_ipv4_ttl(struct net_context *context) { return context->ipv4_ttl; diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 9dadc452a26bb59..b10b9136272c22d 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -2421,8 +2421,7 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, } } - net_context_set_iface(ctx, iface); - ctx->flags |= NET_CONTEXT_BOUND_TO_IFACE; + net_context_bind_iface(ctx, iface); return 0; } From 3f891ced3a718171162b0e93b4d7d1dbbeb73b21 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 15 Nov 2023 17:40:22 +0200 Subject: [PATCH 0586/1049] net: conn: Check also network interface for duplicates When verifying if there are duplicate connections, check also network interface. Signed-off-by: Jukka Rissanen --- subsys/net/ip/connection.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index 35ef208a609ef65..e32747bc38f4c85 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -154,7 +154,8 @@ static void conn_set_unused(struct net_conn *conn) } /* Check if we already have identical connection handler installed. */ -static struct net_conn *conn_find_handler(uint16_t proto, uint8_t family, +static struct net_conn *conn_find_handler(struct net_if *iface, + uint16_t proto, uint8_t family, const struct sockaddr *remote_addr, const struct sockaddr *local_addr, uint16_t remote_port, @@ -252,6 +253,13 @@ static struct net_conn *conn_find_handler(uint16_t proto, uint8_t family, continue; } + if (conn->context != NULL && iface != NULL && + net_context_is_bound_to_iface(conn->context)) { + if (iface != net_context_get_iface(conn->context)) { + continue; + } + } + k_mutex_unlock(&conn_lock); return conn; } @@ -273,7 +281,8 @@ int net_conn_register(uint16_t proto, uint8_t family, struct net_conn *conn; uint8_t flags = 0U; - conn = conn_find_handler(proto, family, remote_addr, local_addr, + conn = conn_find_handler(context != NULL ? net_context_get_iface(context) : NULL, + proto, family, remote_addr, local_addr, remote_port, local_port, context != NULL ? net_context_is_reuseport_set(context) : From dd2a222086bcd6a633d4247ab066da3a659b699f Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 15 Nov 2023 17:42:21 +0200 Subject: [PATCH 0587/1049] net: if: Add helper to calculate number of interfaces Add a helper macro that can be used at runtime to return the number of network interfaces in the system. Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_if.h | 14 ++++++++++++++ subsys/net/ip/net_if.c | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index ab056d05e151e6f..788c33163918fbb 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -3022,6 +3022,20 @@ struct net_if_api { #define NET_DEVICE_DT_INST_OFFLOAD_DEFINE(inst, ...) \ NET_DEVICE_DT_OFFLOAD_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) +/** + * @brief Count the number of network interfaces. + * + * @param[out] _dst Pointer to location where result is written. + */ +#define NET_IFACE_COUNT(_dst) \ + do { \ + extern struct net_if _net_if_list_start[]; \ + extern struct net_if _net_if_list_end[]; \ + *(_dst) = ((uintptr_t)_net_if_list_end - \ + (uintptr_t)_net_if_list_start) / \ + sizeof(struct net_if); \ + } while (0) + #ifdef __cplusplus } #endif diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index dbf20af3cc0a0a9..00c9c74495d8f19 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -4876,6 +4876,16 @@ void net_if_init(void) goto out; } +#if defined(CONFIG_ASSERT) + /* Do extra check that verifies that interface count is properly + * done. + */ + int count_if; + + NET_IFACE_COUNT(&count_if); + NET_ASSERT(count_if == if_count); +#endif + iface_ipv6_init(if_count); iface_ipv4_init(if_count); iface_router_init(); From 5049a049dba231c7b99642fe32bb699b8f1b3cc9 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 15 Nov 2023 17:44:10 +0200 Subject: [PATCH 0588/1049] net: mdns: Create a listener to all available network interfaces Instead of just listening first network interface in the system, install a multicast listener to all available network interfaces. Fixes #18748 Signed-off-by: Jukka Rissanen --- subsys/net/lib/dns/mdns_responder.c | 97 ++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 23 deletions(-) diff --git a/subsys/net/lib/dns/mdns_responder.c b/subsys/net/lib/dns/mdns_responder.c index 4a61992e5063351..5a724faf136af49 100644 --- a/subsys/net/lib/dns/mdns_responder.c +++ b/subsys/net/lib/dns/mdns_responder.c @@ -38,11 +38,17 @@ LOG_MODULE_REGISTER(net_mdns_responder, CONFIG_MDNS_RESPONDER_LOG_LEVEL); #define MDNS_TTL CONFIG_MDNS_RESPONDER_TTL /* In seconds */ #if defined(CONFIG_NET_IPV4) -static struct net_context *ipv4; +#define MAX_IPV4_IFACE_COUNT CONFIG_NET_IF_MAX_IPV4_COUNT +static struct net_context *ipv4[MAX_IPV4_IFACE_COUNT]; static struct sockaddr_in local_addr4; +#else +#define MAX_IPV4_IFACE_COUNT 0 #endif #if defined(CONFIG_NET_IPV6) -static struct net_context *ipv6; +#define MAX_IPV6_IFACE_COUNT CONFIG_NET_IF_MAX_IPV6_COUNT +static struct net_context *ipv6[MAX_IPV6_IFACE_COUNT]; +#else +#define MAX_IPV6_IFACE_COUNT 0 #endif static struct net_mgmt_event_callback mgmt_cb; @@ -645,55 +651,100 @@ static void setup_ipv4_addr(struct sockaddr_in *local_addr) static int init_listener(void) { - int ret, ok = 0; + int ret, ok = 0, i; + struct net_if *iface; + int iface_count; + + NET_IFACE_COUNT(&iface_count); + NET_DBG("Setting mDNS listener to %d interface%s", iface_count, + iface_count > 1 ? "s" : ""); + + if ((iface_count > MAX_IPV6_IFACE_COUNT && MAX_IPV6_IFACE_COUNT > 0) || + (iface_count > MAX_IPV4_IFACE_COUNT && MAX_IPV4_IFACE_COUNT > 0)) { + NET_WARN("You have %d interfaces configured but there " + "are %d network interfaces in the system.", + MAX(MAX_IPV6_IFACE_COUNT, + MAX_IPV6_IFACE_COUNT), iface_count); + } #if defined(CONFIG_NET_IPV6) - do { - static struct sockaddr_in6 local_addr; + struct sockaddr_in6 local_addr6; + struct net_context *v6; - setup_ipv6_addr(&local_addr); + setup_ipv6_addr(&local_addr6); - ipv6 = get_ctx(AF_INET6); + for (i = 0; i < MAX_IPV6_IFACE_COUNT; i++) { + v6 = get_ctx(AF_INET6); + if (v6 == NULL) { + NET_ERR("Cannot get %s context out of %d. Max contexts is %d", + "IPv6", MAX_IPV6_IFACE_COUNT, CONFIG_NET_MAX_CONTEXTS); + continue; + } - ret = bind_ctx(ipv6, (struct sockaddr *)&local_addr, - sizeof(local_addr)); + iface = net_if_get_by_index(i + 1); + if (iface == NULL) { + net_context_unref(v6); + continue; + } + + net_context_bind_iface(v6, iface); + + ret = bind_ctx(v6, (struct sockaddr *)&local_addr6, + sizeof(local_addr6)); if (ret < 0) { - net_context_put(ipv6); + net_context_put(v6); goto ipv6_out; } - ret = net_context_recv(ipv6, recv_cb, K_NO_WAIT, ipv6); + ret = net_context_recv(v6, recv_cb, K_NO_WAIT, v6); if (ret < 0) { - NET_WARN("Cannot receive IPv6 mDNS data (%d)", ret); - net_context_put(ipv6); + NET_WARN("Cannot receive %s mDNS data (%d)", "IPv6", ret); + net_context_put(v6); } else { + ipv6[i] = v6; ok++; } - } while (0); + } ipv6_out: #endif /* CONFIG_NET_IPV6 */ #if defined(CONFIG_NET_IPV4) - do { - setup_ipv4_addr(&local_addr4); + struct net_context *v4; - ipv4 = get_ctx(AF_INET); + setup_ipv4_addr(&local_addr4); - ret = bind_ctx(ipv4, (struct sockaddr *)&local_addr4, + for (i = 0; i < MAX_IPV4_IFACE_COUNT; i++) { + v4 = get_ctx(AF_INET); + if (v4 == NULL) { + NET_ERR("Cannot get %s context out of %d. Max contexts is %d", + "IPv4", MAX_IPV4_IFACE_COUNT, CONFIG_NET_MAX_CONTEXTS); + continue; + } + + iface = net_if_get_by_index(i + 1); + if (iface == NULL) { + net_context_unref(v4); + continue; + } + + net_context_bind_iface(v4, iface); + + ret = bind_ctx(v4, (struct sockaddr *)&local_addr4, sizeof(local_addr4)); if (ret < 0) { - net_context_put(ipv4); + net_context_put(v4); goto ipv4_out; } - ret = net_context_recv(ipv4, recv_cb, K_NO_WAIT, ipv4); + ret = net_context_recv(v4, recv_cb, K_NO_WAIT, v4); if (ret < 0) { - NET_WARN("Cannot receive IPv4 mDNS data (%d)", ret); - net_context_put(ipv4); + NET_WARN("Cannot receive %s mDNS data (%d)", "IPv4", ret); + net_context_put(v4); } else { + ipv4[i] = v4; ok++; } - } while (0); + } ipv4_out: #endif /* CONFIG_NET_IPV4 */ From 9246d98a6a2533177a06e91eca76fec93c7df1a3 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 15 Nov 2023 17:47:06 +0200 Subject: [PATCH 0589/1049] samples: net: mdns_responder: Add VLAN support Add virtual LAN support to the sample so that it is easier to test the multiple mDNS listener feature implemented in previous commit. Signed-off-by: Jukka Rissanen --- samples/net/mdns_responder/CMakeLists.txt | 5 +- samples/net/mdns_responder/Kconfig | 56 ++++++++ samples/net/mdns_responder/overlay-e1000.conf | 6 + samples/net/mdns_responder/overlay-vlan.conf | 34 +++++ samples/net/mdns_responder/src/main.c | 10 ++ samples/net/mdns_responder/src/vlan.c | 135 ++++++++++++++++++ 6 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 samples/net/mdns_responder/Kconfig create mode 100644 samples/net/mdns_responder/overlay-e1000.conf create mode 100644 samples/net/mdns_responder/overlay-vlan.conf create mode 100644 samples/net/mdns_responder/src/vlan.c diff --git a/samples/net/mdns_responder/CMakeLists.txt b/samples/net/mdns_responder/CMakeLists.txt index 21efc955050f04b..5c4e88178a9227e 100644 --- a/samples/net/mdns_responder/CMakeLists.txt +++ b/samples/net/mdns_responder/CMakeLists.txt @@ -4,7 +4,8 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(mdns_responder) -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) +target_sources(app PRIVATE src/main.c) +target_sources(app PRIVATE src/service.c) +target_sources_ifdef(CONFIG_NET_VLAN app PRIVATE src/vlan.c) include(${ZEPHYR_BASE}/samples/net/common/common.cmake) diff --git a/samples/net/mdns_responder/Kconfig b/samples/net/mdns_responder/Kconfig new file mode 100644 index 000000000000000..53cc3d2153d4894 --- /dev/null +++ b/samples/net/mdns_responder/Kconfig @@ -0,0 +1,56 @@ +# Private config options for mDNS responder sample app + +# Copyright (c) 2023 NordicNordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Networking mDNS responder sample application" + +config NET_SAMPLE_IFACE2_MY_IPV6_ADDR + string "My IPv6 address for second interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE2_MY_IPV4_ADDR + string "My IPv4 address for second interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE2_MY_IPV4_NETMASK + string "My IPv4 netmask for second interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE2_VLAN_TAG + int "VLAN tag for second interface" + default 100 + range 0 4094 + depends on NET_VLAN + help + Set VLAN (virtual LAN) tag (id) that is used in the sample + application. + +config NET_SAMPLE_IFACE3_MY_IPV6_ADDR + string "My IPv6 address for third interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE3_MY_IPV4_ADDR + string "My IPv4 address for third interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE3_MY_IPV4_NETMASK + string "My IPv4 netmask for third interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE3_VLAN_TAG + int "VLAN tag for third interface" + default 200 + range 0 4094 + depends on NET_VLAN + help + Set VLAN (virtual LAN) tag (id) that is used in the sample + application. + +source "Kconfig.zephyr" diff --git a/samples/net/mdns_responder/overlay-e1000.conf b/samples/net/mdns_responder/overlay-e1000.conf new file mode 100644 index 000000000000000..d2880bd3587a31e --- /dev/null +++ b/samples/net/mdns_responder/overlay-e1000.conf @@ -0,0 +1,6 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_QEMU_ETHERNET=y + +CONFIG_PCIE=y + +#CONFIG_ETHERNET_LOG_LEVEL_DBG=y diff --git a/samples/net/mdns_responder/overlay-vlan.conf b/samples/net/mdns_responder/overlay-vlan.conf new file mode 100644 index 000000000000000..5dfe0f9b8f72a98 --- /dev/null +++ b/samples/net/mdns_responder/overlay-vlan.conf @@ -0,0 +1,34 @@ +CONFIG_NET_VLAN=y + +# We have one non-vlan interface and two VLAN interfaces +CONFIG_NET_VLAN_COUNT=3 + +# There will be three network interfaces. + +# First ethernet interface will use these settings +CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" + +# Second ethernet interface will have these settings +CONFIG_NET_SAMPLE_IFACE2_MY_IPV6_ADDR="2001:db8:100::1" +# TEST-NET-2 from RFC 5737 +CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_ADDR="198.51.100.1" +CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_NETMASK="255.255.255.0" +# VLAN tag for the second interface +CONFIG_NET_SAMPLE_IFACE2_VLAN_TAG=100 + +# Settings for the third network interface +CONFIG_NET_SAMPLE_IFACE3_MY_IPV6_ADDR="2001:db8:200::1" +# TEST-NET-3 from RFC 5737 +CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_ADDR="203.0.113.1" +CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_NETMASK="255.255.255.0" +# VLAN tag for the second interface +CONFIG_NET_SAMPLE_IFACE3_VLAN_TAG=200 + +# Each interface needs at least 2 context. So if we have three +# interfaces we need minimum 6 context but allocate more so that +# we do not run out of them. +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_MAX_CONN=10 diff --git a/samples/net/mdns_responder/src/main.c b/samples/net/mdns_responder/src/main.c index 6a4ec48a4ab8869..112f9e93931676d 100644 --- a/samples/net/mdns_responder/src/main.c +++ b/samples/net/mdns_responder/src/main.c @@ -14,6 +14,15 @@ LOG_MODULE_REGISTER(net_mdns_responder_sample, LOG_LEVEL_DBG); extern void service(void); +#if defined(CONFIG_NET_VLAN) +int init_vlan(void); +#else +static inline int init_vlan(void) +{ + return 0; +} +#endif /* CONFIG_NET_VLAN */ + /* * Note that mDNS support requires no application interaction with zephyr, * beyond optional runtime hostname configuration calls and setting @@ -26,6 +35,7 @@ extern void service(void); int main(void) { LOG_INF("Waiting mDNS queries..."); + init_vlan(); service(); return 0; } diff --git a/samples/net/mdns_responder/src/vlan.c b/samples/net/mdns_responder/src/vlan.c new file mode 100644 index 000000000000000..534662c3c6497ac --- /dev/null +++ b/samples/net/mdns_responder/src/vlan.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_mdns_responder_sample, LOG_LEVEL_DBG); + +#include + +#include + +/* User data for the interface callback */ +struct ud { + struct net_if *first; + struct net_if *second; + struct net_if *third; +}; + +static void iface_cb(struct net_if *iface, void *user_data_param) +{ + struct ud *user_data = user_data_param; + + if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) { + return; + } + + if (!user_data->first) { + user_data->first = iface; + return; + } + + if (!user_data->second) { + user_data->second = iface; + return; + } + + if (!user_data->third) { + user_data->third = iface; + return; + } +} + +static int setup_iface(struct net_if *iface, const char *ipv6_addr, + const char *ipv4_addr, const char *netmask, + uint16_t vlan_tag) +{ + struct net_if_addr *ifaddr; + struct in_addr addr4; + struct in6_addr addr6; + int ret; + + ret = net_eth_vlan_enable(iface, vlan_tag); + if (ret < 0) { + LOG_ERR("Cannot enable VLAN for tag %d (%d)", vlan_tag, ret); + } + + if (IS_ENABLED(CONFIG_NET_IPV6)) { + if (net_addr_pton(AF_INET6, ipv6_addr, &addr6)) { + LOG_ERR("Invalid address: %s", ipv6_addr); + return -EINVAL; + } + + ifaddr = net_if_ipv6_addr_add(iface, &addr6, + NET_ADDR_MANUAL, 0); + if (!ifaddr) { + LOG_ERR("Cannot add %s to interface %p", + ipv6_addr, iface); + return -EINVAL; + } + } + + if (IS_ENABLED(CONFIG_NET_IPV4)) { + if (net_addr_pton(AF_INET, ipv4_addr, &addr4)) { + LOG_ERR("Invalid address: %s", ipv4_addr); + return -EINVAL; + } + + ifaddr = net_if_ipv4_addr_add(iface, &addr4, + NET_ADDR_MANUAL, 0); + if (!ifaddr) { + LOG_ERR("Cannot add %s to interface %p", + ipv4_addr, iface); + return -EINVAL; + } + + if (netmask && netmask[0]) { + if (net_addr_pton(AF_INET, netmask, &addr4)) { + LOG_ERR("Invalid netmask: %s", ipv4_addr); + return -EINVAL; + } + + net_if_ipv4_set_netmask(iface, &addr4); + } + } + + LOG_DBG("Interface %p VLAN tag %d setup done.", iface, vlan_tag); + + return 0; +} + +int init_vlan(void) +{ + struct ud user_data; + int ret; + + memset(&user_data, 0, sizeof(user_data)); + + net_if_foreach(iface_cb, &user_data); + + /* This sample has two VLANs. For the second one we need to manually + * create IP address for this test. But first the VLAN needs to be + * added to the interface so that IPv6 DAD can work properly. + */ + ret = setup_iface(user_data.second, + CONFIG_NET_SAMPLE_IFACE2_MY_IPV6_ADDR, + CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_ADDR, + CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_NETMASK, + CONFIG_NET_SAMPLE_IFACE2_VLAN_TAG); + if (ret < 0) { + return ret; + } + + ret = setup_iface(user_data.third, + CONFIG_NET_SAMPLE_IFACE3_MY_IPV6_ADDR, + CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_ADDR, + CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_NETMASK, + CONFIG_NET_SAMPLE_IFACE3_VLAN_TAG); + if (ret < 0) { + return ret; + } + + return 0; +} From 5209666539bcd4dea30faaf39f700339e075d14d Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 16 Nov 2023 21:40:56 +0200 Subject: [PATCH 0590/1049] net: mdns: Fix compile error when using clang No issues with gcc but clang gives this error for the *v4 variable few lines below. .../lib/dns/mdns_responder.c:712:2: error: expected expression struct net_context *v4; Signed-off-by: Jukka Rissanen --- subsys/net/lib/dns/mdns_responder.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subsys/net/lib/dns/mdns_responder.c b/subsys/net/lib/dns/mdns_responder.c index 5a724faf136af49..04acbabbecd17cc 100644 --- a/subsys/net/lib/dns/mdns_responder.c +++ b/subsys/net/lib/dns/mdns_responder.c @@ -706,6 +706,9 @@ static int init_listener(void) } } ipv6_out: + ; /* Added ";" to avoid clang compile error because of + * the "struct net_context *v4" after it. + */ #endif /* CONFIG_NET_IPV6 */ #if defined(CONFIG_NET_IPV4) From 7a83724e0f18d7f2400517407150f9e9a1ecd6e6 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sun, 22 Oct 2023 10:44:38 +1100 Subject: [PATCH 0591/1049] boards: nrf52840dk_nrf52840: add gpio reserved ranges and line names Add gpio-reserved-ranges and gpio-line-names properties. Signed-off-by: Nick Ward --- boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts index 96006ec4722aa69..dcee7b0db5fd48e 100644 --- a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts +++ b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts @@ -149,10 +149,18 @@ &gpio0 { status = "okay"; + gpio-reserved-ranges = <0 11>, <17 7>, <26 6>; + gpio-line-names = "", "", "", "", "", "", "", "", + "", "", "", "BUTTON1", "BUTTON2", "LED1", "LED2", "LED3", + "LED4", "", "", "", "", "", "", "", + "BUTTON3", "BUTTON4", "", "", "", "", "", ""; }; &gpio1 { status = "okay"; + gpio-reserved-ranges = <0 1>, <9 1>, <12 4>; + gpio-line-names = "", "D0", "D1", "D2", "D3", "D4", "D5", "D6", + "D7", "", "D8", "D9", "", "", "", ""; }; &uart0 { From 0df794e31656ae2360f241487bbff84076134f66 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sun, 22 Oct 2023 11:34:30 +1100 Subject: [PATCH 0592/1049] drivers: gpio: shell: improve tab complete/suggestion support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implements this enhancement: https://github.com/zephyrproject-rtos/zephyr/issues/63018 The forms of the gpio commands are now: gpio conf device pin ol0 gpio set device pin 1 gpio get device pin gpio blink device pin Device name and pin subcommands now are suggested/completed when tab is used. Pin names are suggested with numbers and line names if available from the gpio controller’s Devicetree node. GPIO pin command is now limited to pins that are not assigned as reserved. Signed-off-by: Nick Ward --- drivers/gpio/gpio_shell.c | 488 +++++++++++++++++++++++++++++--------- 1 file changed, 371 insertions(+), 117 deletions(-) diff --git a/drivers/gpio/gpio_shell.c b/drivers/gpio/gpio_shell.c index b444288953b0df5..e7dea06538f168b 100644 --- a/drivers/gpio/gpio_shell.c +++ b/drivers/gpio/gpio_shell.c @@ -1,187 +1,441 @@ /* * Copyright (c) 2018 Intel Corporation * Copyright (c) 2021 Dennis Ruffer + * Copyright (c) 2023 Nick Ward * * SPDX-License-Identifier: Apache-2.0 - * - * Use "device list" command for GPIO port names */ -#include +#include #include -#include -#include + #include -#include -#include -#include -#include -#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#define ARGV_DEV 1 +#define ARGV_PIN 2 +#define ARGV_CONF 3 +#define ARGV_VALUE 3 -LOG_MODULE_REGISTER(gpio_shell); +#define NGPIOS_UNKNOWN -1 +#define PIN_NOT_FOUND UINT8_MAX -struct args_index { - uint8_t port; - uint8_t index; - uint8_t mode; - uint8_t value; +/* Pin syntax maximum length */ +#define PIN_SYNTAX_MAX 32 +#define PIN_NUM_MAX 4 + +struct gpio_ctrl { + const struct device *dev; + int8_t ngpios; + gpio_port_pins_t reserved_mask; + const char **line_names; + uint8_t line_names_len; + const union shell_cmd_entry *subcmd; }; -static const struct args_index args_indx = { - .port = 1, - .index = 2, - .mode = 3, - .value = 3, +struct sh_gpio { + const struct device *dev; + gpio_pin_t pin; }; -static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv) +/* + * Find idx-th pin reference from the set of non reserved + * pin numbers and provided line names. + */ +static void port_pin_get(gpio_port_pins_t reserved_mask, const char **line_names, + uint8_t line_names_len, size_t idx, struct shell_static_entry *entry) { - uint8_t index = 0U; - int type = GPIO_OUTPUT; - const struct device *dev; + static char pin_syntax[PIN_SYNTAX_MAX]; + static char pin_num[PIN_NUM_MAX]; + const char *name; + gpio_pin_t pin; + bool reserved; + + entry->handler = NULL; + + /* Find allowed numeric pin reference */ + for (pin = 0; pin < GPIO_MAX_PINS_PER_PORT; pin++) { + reserved = ((BIT64(pin) & reserved_mask) != 0); + if (!reserved) { + if (idx == 0) { + break; + } + idx--; + } + } - if (isdigit((unsigned char)argv[args_indx.index][0]) != 0 && - isalpha((unsigned char)argv[args_indx.mode][0]) != 0) { - index = (uint8_t)atoi(argv[args_indx.index]); - if (!strcmp(argv[args_indx.mode], "in")) { - type = GPIO_INPUT; - } else if (!strcmp(argv[args_indx.mode], "inu")) { - type = GPIO_INPUT | GPIO_PULL_UP; - } else if (!strcmp(argv[args_indx.mode], "ind")) { - type = GPIO_INPUT | GPIO_PULL_DOWN; - } else if (!strcmp(argv[args_indx.mode], "out")) { - type = GPIO_OUTPUT; + if (pin < GPIO_MAX_PINS_PER_PORT) { + sprintf(pin_num, "%u", pin); + if ((pin < line_names_len) && (strlen(line_names[pin]) > 0)) { + /* pin can be specified by line name */ + name = line_names[pin]; + for (int i = 0; i < (sizeof(pin_syntax) - 1); i++) { + /* + * For line-name tab completion to work replace any + * space characters with '_'. + */ + pin_syntax[i] = (name[i] != ' ') ? name[i] : '_'; + if (name[i] == '\0') { + break; + } + } + pin_syntax[sizeof(pin_syntax) - 1] = '\0'; + entry->syntax = pin_syntax; + entry->help = pin_num; } else { - return 0; + /* fallback to pin specified by pin number */ + entry->syntax = pin_num; + entry->help = NULL; } } else { - shell_error(sh, "Wrong parameters for conf"); - return -ENOTSUP; + /* No more pins */ + entry->syntax = NULL; + entry->help = NULL; } +} - dev = device_get_binding(argv[args_indx.port]); +#define GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, ngpios), \ + (GPIO_DT_RESERVED_RANGES_NGPIOS(node_id, DT_PROP(node_id, ngpios))), \ + (GPIO_MAX_PINS_PER_PORT)) - if (dev != NULL) { - index = (uint8_t)atoi(argv[args_indx.index]); - shell_print(sh, "Configuring %s pin %d", - argv[args_indx.port], index); - gpio_pin_configure(dev, index, type); +#define GPIO_CTRL_PIN_GET_FN(node_id) \ + static const char *node_id##line_names[] = DT_PROP_OR(node_id, gpio_line_names, {NULL}); \ + \ + static void node_id##cmd_gpio_pin_get(size_t idx, struct shell_static_entry *entry); \ + \ + SHELL_DYNAMIC_CMD_CREATE(node_id##sub_gpio_pin, node_id##cmd_gpio_pin_get); \ + \ + static void node_id##cmd_gpio_pin_get(size_t idx, struct shell_static_entry *entry) \ + { \ + gpio_port_pins_t reserved_mask = GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id); \ + uint8_t line_names_len = DT_PROP_LEN_OR(node_id, gpio_line_names, 0); \ + \ + port_pin_get(reserved_mask, node_id##line_names, line_names_len, idx, entry); \ + entry->subcmd = NULL; \ } - return 0; +#define IS_GPIO_CTRL_PIN_GET(node_id) \ + COND_CODE_1(DT_PROP(node_id, gpio_controller), (GPIO_CTRL_PIN_GET_FN(node_id)), ()) + +DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_PIN_GET) + +#define GPIO_CTRL_LIST_ENTRY(node_id) \ + { \ + .dev = DEVICE_DT_GET(node_id), \ + .ngpios = DT_PROP_OR(node_id, ngpios, NGPIOS_UNKNOWN), \ + .reserved_mask = GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id), \ + .line_names = node_id##line_names, \ + .line_names_len = DT_PROP_LEN_OR(node_id, gpio_line_names, 0), \ + .subcmd = &node_id##sub_gpio_pin, \ + }, + +#define IS_GPIO_CTRL_LIST(node_id) \ + COND_CODE_1(DT_PROP(node_id, gpio_controller), (GPIO_CTRL_LIST_ENTRY(node_id)), ()) + +static const struct gpio_ctrl gpio_list[] = {DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_LIST)}; + +static const struct gpio_ctrl *get_gpio_ctrl(char *name) +{ + const struct device *dev = device_get_binding(name); + size_t i; + + for (i = 0; i < ARRAY_SIZE(gpio_list); i++) { + if (gpio_list[i].dev == dev) { + return &gpio_list[i]; + } + } + return NULL; } -static int cmd_gpio_get(const struct shell *sh, - size_t argc, char **argv) +int line_cmp(const char *input, const char *line_name) { - const struct device *dev; - uint8_t index = 0U; - int rc; + int i = 0; - if (isdigit((unsigned char)argv[args_indx.index][0]) != 0) { - index = (uint8_t)atoi(argv[args_indx.index]); - } else { - shell_error(sh, "Wrong parameters for get"); + while (true) { + if ((input[i] == '_') && (line_name[i] == ' ')) { + /* Allow input underscore to match line_name space */ + } else if (input[i] != line_name[i]) { + return (input[i] > line_name[i]) ? 1 : -1; + } else if (line_name[i] == '\0') { + return 0; + } + i++; + } +} + +static int get_gpio_pin(const struct shell *sh, const struct gpio_ctrl *ctrl, char *line_name) +{ + gpio_pin_t pin = PIN_NOT_FOUND; + gpio_pin_t i; + int result; + + for (i = 0; i < ctrl->ngpios; i++) { + result = line_cmp(line_name, ctrl->line_names[i]); + if (result == 0) { + if ((BIT64(i) & ctrl->reserved_mask) != 0) { + shell_error(sh, "Reserved pin"); + return -EACCES; + } else if (pin == PIN_NOT_FOUND) { + pin = i; + } else { + shell_error(sh, "Line name ambiguous"); + return -EFAULT; + } + } + } + + if (pin == PIN_NOT_FOUND) { + shell_error(sh, "Line name not found: '%s'", line_name); + return -ENOENT; + } + + return pin; +} + +static int get_sh_gpio(const struct shell *sh, char **argv, struct sh_gpio *gpio) +{ + const struct gpio_ctrl *ctrl; + int ret = 0; + int pin; + + ctrl = get_gpio_ctrl(argv[ARGV_DEV]); + if (ctrl == NULL) { + shell_error(sh, "unknown gpio controller: %s", argv[ARGV_DEV]); return -EINVAL; } + gpio->dev = ctrl->dev; + pin = shell_strtoul(argv[ARGV_PIN], 0, &ret); + if (ret != 0) { + pin = get_gpio_pin(sh, ctrl, argv[ARGV_PIN]); + if (pin < 0) { + return pin; + } + } else if ((BIT64(pin) & ctrl->reserved_mask) != 0) { + shell_error(sh, "Reserved pin"); + return -EACCES; + } + gpio->pin = pin; + + return 0; +} + +static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv, void *data) +{ + gpio_flags_t flags = 0; + struct sh_gpio gpio; + int ret = 0; + + ret = get_sh_gpio(sh, argv, &gpio); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } - dev = device_get_binding(argv[args_indx.port]); + for (int i = 0; i < strlen(argv[ARGV_CONF]); i++) { + switch (argv[ARGV_CONF][i]) { + case 'i': + flags |= GPIO_INPUT; + break; + case 'o': + flags |= GPIO_OUTPUT; + break; + case 'u': + flags |= GPIO_PULL_UP; + break; + case 'd': + flags |= GPIO_PULL_DOWN; + break; + case 'h': + flags |= GPIO_ACTIVE_HIGH; + break; + case 'l': + flags |= GPIO_ACTIVE_LOW; + break; + case '0': + flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_LOW; + break; + case '1': + flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_HIGH; + break; + default: + shell_error(sh, "Unknown: '%c'", argv[ARGV_CONF][i]); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + } - if (dev != NULL) { - index = (uint8_t)atoi(argv[2]); - shell_print(sh, "Reading %s pin %d", - argv[args_indx.port], index); - rc = gpio_pin_get(dev, index); - if (rc >= 0) { - shell_print(sh, "Value %d", rc); - } else { - shell_error(sh, "Error %d reading value", rc); - return -EIO; + if (((flags & GPIO_INPUT) != 0) == ((flags & GPIO_OUTPUT) != 0)) { + shell_error(sh, "must be either input or output"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + if (((flags & GPIO_PULL_UP) != 0) && ((flags & GPIO_PULL_DOWN) != 0)) { + shell_error(sh, "cannot be pull up and pull down"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + if (((flags & GPIO_ACTIVE_LOW) != 0) && ((flags & GPIO_ACTIVE_HIGH) != 0)) { + shell_error(sh, "cannot be active low and active high"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + if ((flags & GPIO_OUTPUT) != 0) { + /* Default to active high if not specified */ + if ((flags & (GPIO_ACTIVE_LOW | GPIO_ACTIVE_HIGH)) == 0) { + flags |= GPIO_ACTIVE_HIGH; } + /* Default to initialisation to logic 0 if not specified */ + if ((flags & GPIO_OUTPUT_INIT_LOGICAL) == 0) { + flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_LOW; + } + } + + if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT_INIT_LOGICAL) != 0)) { + shell_error(sh, "an input cannot be initialised to a logic level"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + if (((flags & GPIO_OUTPUT_INIT_LOW) != 0) && ((flags & GPIO_OUTPUT_INIT_HIGH) != 0)) { + shell_error(sh, "cannot initialise to logic 0 and logic 1"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + ret = gpio_pin_configure(gpio.dev, gpio.pin, flags); + if (ret != 0) { + shell_error(sh, "error: %d", ret); + return ret; } return 0; } -static int cmd_gpio_set(const struct shell *sh, - size_t argc, char **argv) +static int cmd_gpio_get(const struct shell *sh, size_t argc, char **argv) { - const struct device *dev; - uint8_t index = 0U; - uint8_t value = 0U; + struct sh_gpio gpio; + int value; + int ret; - if (isdigit((unsigned char)argv[args_indx.index][0]) != 0 && - isdigit((unsigned char)argv[args_indx.value][0]) != 0) { - index = (uint8_t)atoi(argv[args_indx.index]); - value = (uint8_t)atoi(argv[args_indx.value]); - } else { - shell_print(sh, "Wrong parameters for set"); - return -EINVAL; + ret = get_sh_gpio(sh, argv, &gpio); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; } - dev = device_get_binding(argv[args_indx.port]); - if (dev != NULL) { - index = (uint8_t)atoi(argv[2]); - shell_print(sh, "Writing to %s pin %d", - argv[args_indx.port], index); - gpio_pin_set(dev, index, value); + value = gpio_pin_get(gpio.dev, gpio.pin); + if (value >= 0) { + shell_print(sh, "%u", value); + } else { + shell_error(sh, "error: %d", value); + return value; } return 0; } +static int cmd_gpio_set(const struct shell *sh, size_t argc, char **argv) +{ + struct sh_gpio gpio; + unsigned long value; + int ret = 0; + + ret = get_sh_gpio(sh, argv, &gpio); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + value = shell_strtoul(argv[ARGV_VALUE], 0, &ret); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + ret = gpio_pin_set(gpio.dev, gpio.pin, value != 0); + if (ret != 0) { + shell_error(sh, "error: %d", ret); + return ret; + } + + return 0; +} /* 500 msec = 1/2 sec */ #define SLEEP_TIME_MS 500 -static int cmd_gpio_blink(const struct shell *sh, - size_t argc, char **argv) +static int cmd_gpio_blink(const struct shell *sh, size_t argc, char **argv) { - const struct device *dev; - uint8_t index = 0U; - uint8_t value = 0U; + struct sh_gpio gpio; size_t count = 0; + int value = 0; char data; + int ret; - if (isdigit((unsigned char)argv[args_indx.index][0]) != 0) { - index = (uint8_t)atoi(argv[args_indx.index]); - } else { - shell_error(sh, "Wrong parameters for blink"); - return -EINVAL; + ret = get_sh_gpio(sh, argv, &gpio); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; } - dev = device_get_binding(argv[args_indx.port]); - if (dev != NULL) { - index = (uint8_t)atoi(argv[2]); - shell_fprintf(sh, SHELL_NORMAL, "Blinking port %s index %d.", argv[1], index); - shell_fprintf(sh, SHELL_NORMAL, " Hit any key to exit"); + shell_fprintf(sh, SHELL_NORMAL, "Blinking port %s pin %u.", argv[ARGV_DEV], gpio.pin); + shell_fprintf(sh, SHELL_NORMAL, " Hit any key to exit"); - /* dummy read to clear any pending input */ - (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); + /* dummy read to clear any pending input */ + (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); - while (true) { - (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); - if (count != 0) { - break; - } - gpio_pin_set(dev, index, value); - value = !value; - k_msleep(SLEEP_TIME_MS); + while (true) { + (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); + if (count != 0) { + break; } - - shell_fprintf(sh, SHELL_NORMAL, "\n"); + gpio_pin_set(gpio.dev, gpio.pin, value); + value = !value; + k_msleep(SLEEP_TIME_MS); } + shell_fprintf(sh, SHELL_NORMAL, "\n"); + return 0; } +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + if (idx >= ARRAY_SIZE(gpio_list)) { + entry->syntax = NULL; + return; + } + + entry->syntax = gpio_list[idx].dev->name; + entry->handler = NULL; + entry->help = "Device"; + entry->subcmd = gpio_list[idx].subcmd; +} + +SHELL_DYNAMIC_CMD_CREATE(sub_gpio_dev, device_name_get); + SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio, - SHELL_CMD_ARG(conf, NULL, "Configure GPIO", cmd_gpio_conf, 4, 0), - SHELL_CMD_ARG(get, NULL, "Get GPIO value", cmd_gpio_get, 3, 0), - SHELL_CMD_ARG(set, NULL, "Set GPIO", cmd_gpio_set, 4, 0), - SHELL_CMD_ARG(blink, NULL, "Blink GPIO", cmd_gpio_blink, 3, 0), - SHELL_SUBCMD_SET_END /* Array terminated. */ - ); + SHELL_CMD_ARG(conf, &sub_gpio_dev, + "Configure GPIO pin\n" + "Usage: gpio conf [u|d][h|l][0|1]>\n" + " - input|output\n" + "[u|d] - pull up|pull down, otherwise open\n" + "[h|l] - active high|active low, otherwise defaults to active high\n" + "[0|1] - initialise to logic 0|logic 1, otherwise defaults to logic 0", + cmd_gpio_conf, 4, 0), + SHELL_CMD_ARG(get, &sub_gpio_dev, + "Get GPIO pin value\n" + "Usage: gpio get ", cmd_gpio_get, 3, 0), + SHELL_CMD_ARG(set, &sub_gpio_dev, + "Set GPIO pin value\n" + "Usage: gpio set ", cmd_gpio_set, 4, 0), + SHELL_CMD_ARG(blink, &sub_gpio_dev, + "Blink GPIO pin\n" + "Usage: gpio blink ", cmd_gpio_blink, 3, 0), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); SHELL_CMD_REGISTER(gpio, &sub_gpio, "GPIO commands", NULL); From 695a0ac503a7d5ee2bbeb4f8a1a1af8d1ad007e1 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sun, 22 Oct 2023 15:37:53 +1100 Subject: [PATCH 0593/1049] drivers: gpio: shell: add info command Usage: gpio info [device] The new command prints gpio controller information for a specific device if specified or if no device is specified it prints out all controller information ordered by line name. Also added Kconfig option so this command can be removed if resources need to be conserved. Signed-off-by: Nick Ward --- drivers/gpio/Kconfig | 9 +++ drivers/gpio/gpio_shell.c | 147 +++++++++++++++++++++++++++++++++++++- 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7ae1a8d0d939f7e..51e86b026bb8408 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -20,6 +20,15 @@ config GPIO_SHELL help Enable GPIO Shell for testing. +config GPIO_SHELL_INFO_CMD + bool "GPIO Shell info command" + default y + depends on GPIO_SHELL + help + Enable GPIO Shell information command. + This command provides a shell user extra information about gpio + controller reserved pins and line names. + config GPIO_INIT_PRIORITY int "GPIO init priority" default KERNEL_INIT_PRIORITY_DEFAULT diff --git a/drivers/gpio/gpio_shell.c b/drivers/gpio/gpio_shell.c index e7dea06538f168b..6f867b65b8b639e 100644 --- a/drivers/gpio/gpio_shell.c +++ b/drivers/gpio/gpio_shell.c @@ -36,7 +36,6 @@ struct sh_gpio { const struct device *dev; gpio_pin_t pin; }; - /* * Find idx-th pin reference from the set of non reserved * pin numbers and provided line names. @@ -417,6 +416,149 @@ static void device_name_get(size_t idx, struct shell_static_entry *entry) SHELL_DYNAMIC_CMD_CREATE(sub_gpio_dev, device_name_get); +struct pin_info { + const struct device *dev; + bool reserved; + gpio_pin_t pin; + const char *line_name; +}; + +struct pin_order_user_data { + const struct shell *sh; + struct pin_info prev; + struct pin_info next; +}; + +typedef void (*pin_foreach_func_t)(const struct pin_info *info, void *user_data); + +static void print_gpio_ctrl_info(const struct shell *sh, const struct gpio_ctrl *ctrl) +{ + gpio_pin_t pin; + bool reserved; + + shell_print(sh, " ngpios: %u", ctrl->ngpios); + shell_print(sh, " Reserved pin mask: 0x%08X", ctrl->reserved_mask); + + shell_print(sh, ""); + + shell_print(sh, " Reserved Pin Line Name"); + for (pin = 0; pin < GPIO_MAX_PINS_PER_PORT; pin++) { + if ((pin >= ctrl->ngpios) && (pin >= ctrl->line_names_len)) { + /* Out of info */ + break; + } + reserved = (BIT64(pin) & ctrl->reserved_mask) != 0; + shell_print(sh, " %c %2u %s", reserved ? '*' : ' ', + pin, ctrl->line_names[pin]); + } +} + +static void foreach_pin(pin_foreach_func_t func, void *user_data) +{ + gpio_port_pins_t reserved_mask; + struct pin_info info; + gpio_pin_t pin; + size_t i; + + for (i = 0; i < ARRAY_SIZE(gpio_list); i++) { + for (pin = 0; pin < gpio_list[i].ngpios; pin++) { + info.dev = gpio_list[i].dev; + reserved_mask = gpio_list[i].reserved_mask; + info.reserved = (BIT64(pin) & reserved_mask) != 0; + info.pin = pin; + if (pin < gpio_list[i].line_names_len) { + info.line_name = gpio_list[i].line_names[pin]; + } else { + info.line_name = ""; + } + func(&info, user_data); + } + } +} + +static int pin_cmp(const struct pin_info *a, const struct pin_info *b) +{ + int result = strcmp(a->line_name, b->line_name); + + if (result != 0) { + return result; + } + result = strcmp(a->dev->name, b->dev->name); + if (result != 0) { + return result; + } + result = (int)a->pin - (int)b->pin; + + return result; +} + +static void pin_get_next(const struct pin_info *info, void *user_data) +{ + struct pin_order_user_data *data = user_data; + int result; + + if (data->prev.line_name != NULL) { + result = pin_cmp(info, &data->prev); + } else { + result = 1; + } + if (result > 0) { + if (data->next.line_name == NULL) { + data->next = *info; + return; + } + result = pin_cmp(info, &data->next); + if (result < 0) { + data->next = *info; + } + } +} + +static void pin_ordered(const struct pin_info *info, void *user_data) +{ + struct pin_order_user_data *data = user_data; + + ARG_UNUSED(info); + + foreach_pin(pin_get_next, data); + + shell_print(data->sh, " %-12s %-8c %-16s %2u", + data->next.line_name, + data->next.reserved ? '*' : ' ', + data->next.dev->name, + data->next.pin); + + data->prev = data->next; + data->next.line_name = NULL; +} + +static void print_ordered_info(const struct shell *sh) +{ + struct pin_order_user_data data = {0}; + + data.sh = sh; + + shell_print(sh, " %-12s %-8s %-16s %-3s", + "Line", "Reserved", "Device", "Pin"); + + foreach_pin(pin_ordered, &data); +} + +static int cmd_gpio_info(const struct shell *sh, size_t argc, char **argv) +{ + const struct gpio_ctrl *ctrl = get_gpio_ctrl(argv[ARGV_DEV]); + + if (ctrl == NULL) { + /* No device specified */ + print_ordered_info(sh); + return 0; + } + + print_gpio_ctrl_info(sh, ctrl); + + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio, SHELL_CMD_ARG(conf, &sub_gpio_dev, "Configure GPIO pin\n" @@ -435,6 +577,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio, SHELL_CMD_ARG(blink, &sub_gpio_dev, "Blink GPIO pin\n" "Usage: gpio blink ", cmd_gpio_blink, 3, 0), + SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_INFO_CMD, info, &sub_gpio_dev, + "GPIO Information\n" + "Usage: gpio info [device]", cmd_gpio_info, 1, 1), SHELL_SUBCMD_SET_END /* Array terminated. */ ); From 45509fdc0ed30d4590b65661d7d1da385c28095a Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sun, 22 Oct 2023 18:00:35 +1100 Subject: [PATCH 0594/1049] drivers: gpio: shell: make blink command optional Adds CONFIG_GPIO_SHELL_BLINK_CMD symbol. Saves around 300 bytes when command is disabled. Signed-off-by: Nick Ward --- drivers/gpio/Kconfig | 9 +++++++++ drivers/gpio/gpio_shell.c | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 51e86b026bb8408..07c3d6b47da9e1c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -29,6 +29,15 @@ config GPIO_SHELL_INFO_CMD This command provides a shell user extra information about gpio controller reserved pins and line names. +config GPIO_SHELL_BLINK_CMD + bool "GPIO Shell blink command" + default y + depends on GPIO_SHELL + help + Enable GPIO Shell blink command. + This command provides a shell user the ability to 'blink' a pin + at 1Hz. + config GPIO_INIT_PRIORITY int "GPIO init priority" default KERNEL_INIT_PRIORITY_DEFAULT diff --git a/drivers/gpio/gpio_shell.c b/drivers/gpio/gpio_shell.c index 6f867b65b8b639e..ec5c0263702b10d 100644 --- a/drivers/gpio/gpio_shell.c +++ b/drivers/gpio/gpio_shell.c @@ -574,7 +574,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio, SHELL_CMD_ARG(set, &sub_gpio_dev, "Set GPIO pin value\n" "Usage: gpio set ", cmd_gpio_set, 4, 0), - SHELL_CMD_ARG(blink, &sub_gpio_dev, + SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_BLINK_CMD, blink, &sub_gpio_dev, "Blink GPIO pin\n" "Usage: gpio blink ", cmd_gpio_blink, 3, 0), SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_INFO_CMD, info, &sub_gpio_dev, From 738a1517b191850cc897fd14f47b1764246014a2 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sun, 22 Oct 2023 18:20:04 +1100 Subject: [PATCH 0595/1049] drivers: gpio: shell: optimise blink command Use gpio toggle api instead of manually toggling. Remove redundant text. Print error and break from blinking if it occurs. Only print 'how to exit' text if first toggle is successful. Saves roughly 40 bytes. Signed-off-by: Nick Ward --- drivers/gpio/gpio_shell.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio_shell.c b/drivers/gpio/gpio_shell.c index ec5c0263702b10d..2c37a8ffcbfeaa4 100644 --- a/drivers/gpio/gpio_shell.c +++ b/drivers/gpio/gpio_shell.c @@ -368,9 +368,9 @@ static int cmd_gpio_set(const struct shell *sh, size_t argc, char **argv) static int cmd_gpio_blink(const struct shell *sh, size_t argc, char **argv) { + bool msg_one_shot = true; struct sh_gpio gpio; - size_t count = 0; - int value = 0; + size_t count; char data; int ret; @@ -380,9 +380,6 @@ static int cmd_gpio_blink(const struct shell *sh, size_t argc, char **argv) return SHELL_CMD_HELP_PRINTED; } - shell_fprintf(sh, SHELL_NORMAL, "Blinking port %s pin %u.", argv[ARGV_DEV], gpio.pin); - shell_fprintf(sh, SHELL_NORMAL, " Hit any key to exit"); - /* dummy read to clear any pending input */ (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); @@ -391,13 +388,17 @@ static int cmd_gpio_blink(const struct shell *sh, size_t argc, char **argv) if (count != 0) { break; } - gpio_pin_set(gpio.dev, gpio.pin, value); - value = !value; + ret = gpio_pin_toggle(gpio.dev, gpio.pin); + if (ret != 0) { + shell_error(sh, "%d", ret); + break; + } else if (msg_one_shot) { + msg_one_shot = false; + shell_print(sh, "Hit any key to exit"); + } k_msleep(SLEEP_TIME_MS); } - shell_fprintf(sh, SHELL_NORMAL, "\n"); - return 0; } From cd9f307e7169b5164b005895c37885e31210ba86 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Mon, 23 Oct 2023 22:40:02 +1100 Subject: [PATCH 0596/1049] drivers: gpio: shell: add vendor specific flags argument Allow the optional setting of vendor specific flags in the conf command. Signed-off-by: Nick Ward --- drivers/gpio/gpio_shell.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio_shell.c b/drivers/gpio/gpio_shell.c index 2c37a8ffcbfeaa4..48d7e95f7a75254 100644 --- a/drivers/gpio/gpio_shell.c +++ b/drivers/gpio/gpio_shell.c @@ -15,6 +15,7 @@ #define ARGV_PIN 2 #define ARGV_CONF 3 #define ARGV_VALUE 3 +#define ARGV_VENDOR_SPECIFIC 4 #define NGPIOS_UNKNOWN -1 #define PIN_NOT_FOUND UINT8_MAX @@ -221,6 +222,7 @@ static int get_sh_gpio(const struct shell *sh, char **argv, struct sh_gpio *gpio static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv, void *data) { gpio_flags_t flags = 0; + gpio_flags_t vendor_specific; struct sh_gpio gpio; int ret = 0; @@ -304,6 +306,22 @@ static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv, void return SHELL_CMD_HELP_PRINTED; } + if (argc == 5) { + vendor_specific = shell_strtoul(argv[ARGV_VENDOR_SPECIFIC], 0, &ret); + if ((ret == 0) && ((vendor_specific & ~(0xFF00U)) == 0)) { + flags |= vendor_specific; + } else { + /* + * See include/zephyr/dt-bindings/gpio/ for the + * available flags for your vendor. + */ + shell_error(sh, "vendor specific flags must be within " + "the mask 0xFF00"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + } + ret = gpio_pin_configure(gpio.dev, gpio.pin, flags); if (ret != 0) { shell_error(sh, "error: %d", ret); @@ -563,12 +581,14 @@ static int cmd_gpio_info(const struct shell *sh, size_t argc, char **argv) SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio, SHELL_CMD_ARG(conf, &sub_gpio_dev, "Configure GPIO pin\n" - "Usage: gpio conf [u|d][h|l][0|1]>\n" + "Usage: gpio conf [u|d][h|l][0|1]> [vendor specific]\n" " - input|output\n" "[u|d] - pull up|pull down, otherwise open\n" "[h|l] - active high|active low, otherwise defaults to active high\n" - "[0|1] - initialise to logic 0|logic 1, otherwise defaults to logic 0", - cmd_gpio_conf, 4, 0), + "[0|1] - initialise to logic 0|logic 1, otherwise defaults to logic 0\n" + "[vendor specific] - configuration flags within the mask 0xFF00\n" + " see include/zephyr/dt-bindings/gpio/", + cmd_gpio_conf, 4, 1), SHELL_CMD_ARG(get, &sub_gpio_dev, "Get GPIO pin value\n" "Usage: gpio get ", cmd_gpio_get, 3, 0), From 19d250e1dcaa2e764c258a416891582db13ec87c Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Mon, 13 Nov 2023 13:36:44 +0100 Subject: [PATCH 0597/1049] sysbuild: create sysbuild_cache function Create dedicated function, sysbuild_cache(), for handling sysbuild's image specific cache file. This provides a cleaner handling of said cache file, and provides a mechanism for updating the cache file at later sysbuild CMake stages. Signed-off-by: Torsten Rasmussen --- .../cmake/modules/sysbuild_extensions.cmake | 124 ++++++++++++------ 1 file changed, 82 insertions(+), 42 deletions(-) diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index a3838415eee2041..9250c209c50a0b9 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -107,6 +107,87 @@ function(sysbuild_get variable) endif() endfunction() +# Usage: +# sysbuild_cache(CREATE APPLICATION [CMAKE_RERUN]) +# +# This function works on the sysbuild cache for sysbuild managed applications. +# +# Arguments: +# CREATE : Create or update existing sysbuild cache file for the application. +# The sysbuild cache is only updated if it contain changes. +# APPLICATION : Name of the application. +# CMAKE_RERUN : Force a CMake rerun for the application during next build +# invocation if the sysbuild cache has changed. It is +# advised to always use this flag. Not using this flag can +# reduce build time, but only do so if application is +# guranteed to be up-to-date. +# +function(sysbuild_cache) + cmake_parse_arguments(SB_CACHE "CREATE;CMAKE_RERUN" "APPLICATION" "" ${ARGN}) + zephyr_check_arguments_required(sysbuild_cache SB_CACHE APPLICATION) + zephyr_check_flags_required(sysbuild_cache SB_CACHE CREATE) + + get_target_property(${SB_CACHE_APPLICATION}_MAIN_APP ${SB_CACHE_APPLICATION} MAIN_APP) + get_cmake_property(sysbuild_cache CACHE_VARIABLES) + + foreach(var_name ${sysbuild_cache}) + if(NOT "${var_name}" MATCHES "^(CMAKE_.*|BOARD)$") + # Perform a dummy read to prevent a false warning about unused variables + # being emitted due to a cmake bug: https://gitlab.kitware.com/cmake/cmake/-/issues/24555 + set(unused_tmp_var ${${var_name}}) + + # We don't want to pass internal CMake variables. + # Required CMake variable to be passed, like CMAKE_BUILD_TYPE must be + # passed using `-D` on command invocation. + get_property(var_type CACHE ${var_name} PROPERTY TYPE) + set(cache_entry "${var_name}:${var_type}=$CACHE{${var_name}}") + string(REPLACE ";" "\;" cache_entry "${cache_entry}") + list(APPEND sysbuild_cache_strings "${cache_entry}\n") + endif() + endforeach() + if(DEFINED BOARD_REVISION) + list(APPEND sysbuild_cache_strings "BOARD:STRING=${BOARD}@${BOARD_REVISION}\n") + else() + list(APPEND sysbuild_cache_strings "BOARD:STRING=${BOARD}\n") + endif() + list(APPEND sysbuild_cache_strings "SYSBUILD_NAME:STRING=${SB_CACHE_APPLICATION}\n") + + if(${SB_CACHE_APPLICATION}_MAIN_APP) + list(APPEND sysbuild_cache_strings "SYSBUILD_MAIN_APP:BOOL=True\n") + endif() + + if(${SB_CACHE_APPLICATION}_BOARD AND NOT DEFINED CACHE{${SB_CACHE_APPLICATION}_BOARD}) + # Only set image specific board if provided. + # The sysbuild BOARD is exported through sysbuild cache, and will be used + # unless _BOARD is defined. + list(APPEND sysbuild_cache_strings + "${SB_CACHE_APPLICATION}_BOARD:STRING=${${SB_CACHE_APPLICATION}_BOARD}\n" + ) + endif() + + get_target_property(${SB_CACHE_APPLICATION}_CACHE_FILE ${SB_CACHE_APPLICATION} CACHE_FILE) + file(WRITE ${${SB_CACHE_APPLICATION}_CACHE_FILE}.tmp ${sysbuild_cache_strings}) + if(SB_CACHE_CMAKE_RERUN) + execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files + ${${SB_CACHE_APPLICATION}_CACHE_FILE}.tmp + ${${SB_CACHE_APPLICATION}_CACHE_FILE} + RESULT_VARIABLE compare_res + ) + if(NOT compare_res EQUAL 0) + zephyr_file_copy(${${SB_CACHE_APPLICATION}_CACHE_FILE}.tmp + ${${SB_CACHE_APPLICATION}_CACHE_FILE} + ) + ExternalProject_Get_Property(${SB_CACHE_APPLICATION} BINARY_DIR) + file(TOUCH_NOCREATE ${BINARY_DIR}/CMakeCache.txt) + endif() + else() + zephyr_file_copy(${${SB_CACHE_APPLICATION}_CACHE_FILE}.tmp + ${${SB_CACHE_APPLICATION}_CACHE_FILE} ONLY_IF_DIFFERENT + ) + endif() + +endfunction() + # Usage: # ExternalZephyrProject_Add(APPLICATION # SOURCE_DIR

@@ -372,9 +453,7 @@ function(ExternalZephyrProject_Cmake) ) ExternalProject_Get_Property(${ZCMAKE_APPLICATION} SOURCE_DIR BINARY_DIR CMAKE_ARGS) - get_target_property(${ZCMAKE_APPLICATION}_CACHE_FILE ${ZCMAKE_APPLICATION} CACHE_FILE) get_target_property(${ZCMAKE_APPLICATION}_BOARD ${ZCMAKE_APPLICATION} BOARD) - get_target_property(${ZCMAKE_APPLICATION}_MAIN_APP ${ZCMAKE_APPLICATION} MAIN_APP) get_property(${ZCMAKE_APPLICATION}_CONF_SCRIPT TARGET ${ZCMAKE_APPLICATION} PROPERTY IMAGE_CONF_SCRIPT @@ -390,46 +469,7 @@ function(ExternalZephyrProject_Cmake) endif() endforeach() - get_cmake_property(sysbuild_cache CACHE_VARIABLES) - foreach(var_name ${sysbuild_cache}) - if(NOT "${var_name}" MATCHES "^(CMAKE_.*|BOARD)$") - # Perform a dummy read to prevent a false warning about unused variables - # being emitted due to a cmake bug: https://gitlab.kitware.com/cmake/cmake/-/issues/24555 - set(unused_tmp_var ${${var_name}}) - - # We don't want to pass internal CMake variables. - # Required CMake variable to be passed, like CMAKE_BUILD_TYPE must be - # passed using `-D` on command invocation. - get_property(var_type CACHE ${var_name} PROPERTY TYPE) - set(cache_entry "${var_name}:${var_type}=$CACHE{${var_name}}") - string(REPLACE ";" "\;" cache_entry "${cache_entry}") - list(APPEND sysbuild_cache_strings "${cache_entry}\n") - endif() - endforeach() - if(DEFINED BOARD_REVISION) - list(APPEND sysbuild_cache_strings "BOARD:STRING=${BOARD}@${BOARD_REVISION}\n") - else() - list(APPEND sysbuild_cache_strings "BOARD:STRING=${BOARD}\n") - endif() - list(APPEND sysbuild_cache_strings "SYSBUILD_NAME:STRING=${ZCMAKE_APPLICATION}\n") - - if(${ZCMAKE_APPLICATION}_MAIN_APP) - list(APPEND sysbuild_cache_strings "SYSBUILD_MAIN_APP:BOOL=True\n") - endif() - - if(${ZCMAKE_APPLICATION}_BOARD AND NOT DEFINED CACHE{${ZCMAKE_APPLICATION}_BOARD}) - # Only set image specific board if provided. - # The sysbuild BOARD is exported through sysbuild cache, and will be used - # unless _BOARD is defined. - list(APPEND sysbuild_cache_strings - "${ZCMAKE_APPLICATION}_BOARD:STRING=${${ZCMAKE_APPLICATION}_BOARD}\n" - ) - endif() - - file(WRITE ${${ZCMAKE_APPLICATION}_CACHE_FILE}.tmp ${sysbuild_cache_strings}) - zephyr_file_copy(${${ZCMAKE_APPLICATION}_CACHE_FILE}.tmp - ${${ZCMAKE_APPLICATION}_CACHE_FILE} ONLY_IF_DIFFERENT - ) + sysbuild_cache(CREATE APPLICATION ${ZCMAKE_APPLICATION}) foreach(script ${${ZCMAKE_APPLICATION}_CONF_SCRIPT}) include(${script}) From bc08e801c6b1416dcbbc679f5e25f801d438a531 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 14 Nov 2023 15:23:55 +0100 Subject: [PATCH 0598/1049] native_sim build: Fix for APPLICATION_BINARY_DIR!=CMAKE_BINARY_DIR In some cases, the APPLICATION_BINARY_DIR does not match the CMAKE_BINARY_DIR, in those cases the native simulator build would not find the zephyr elf file. Fix it by using the correct variable. Signed-off-by: Alberto Escolar Piedras --- CMakeLists.txt | 2 +- boards/posix/common/natsim_config.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c29fa6885a4b57a..164d82fde0e8ad9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1762,7 +1762,7 @@ if(CONFIG_BUILD_OUTPUT_EXE) COMMENT "Building native simulator runner, and linking final executable" COMMAND ${MAKE} -f ${ZEPHYR_BASE}/scripts/native_simulator/Makefile all --warn-undefined-variables - -r NSI_CONFIG_FILE=${CMAKE_BINARY_DIR}/zephyr/NSI/nsi_config + -r NSI_CONFIG_FILE=${APPLICATION_BINARY_DIR}/zephyr/NSI/nsi_config # nsi_config is created by the board cmake file DEPENDS ${logical_target_for_zephyr_elf} BYPRODUCTS ${KERNEL_EXE_NAME} diff --git a/boards/posix/common/natsim_config.cmake b/boards/posix/common/natsim_config.cmake index 576e4b9b6376e09..2ab155af1056fea 100644 --- a/boards/posix/common/natsim_config.cmake +++ b/boards/posix/common/natsim_config.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -set(zephyr_build_path ${CMAKE_BINARY_DIR}/zephyr) +set(zephyr_build_path ${APPLICATION_BINARY_DIR}/zephyr) get_property(CCACHE GLOBAL PROPERTY RULE_LAUNCH_COMPILE) target_link_options(native_simulator INTERFACE From 2dce408bc3237e8b5a7e8cd026a6dfc2a929b97a Mon Sep 17 00:00:00 2001 From: Josuah Demangeon Date: Thu, 12 Oct 2023 12:58:40 +0200 Subject: [PATCH 0599/1049] drivers: serial: uart_liteuart: fix interrupt-driven mode Interrupt-driven mode was not working, and disabled by default. When it was forced on, the behavior was to only have a few bytes: as many as min(CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE, 9). After the hardware FIFO was filled by software and emptied by hardware, no interrupt occured, and enqueuing more data did never happen. By letting the events enabled for TX (only), then interrupts are still generated after the first transfer, and the software can then add the subsequent transfers until all data is print: the UART works. It does not generate endless interrupts either, which was tested by adding litex_write8('%', UART_RXTX_ADDR) in liteuart_uart_irq_handler() to log all interrupts events, and when there is nothing to print, no interrupt is fired. It was tested with the Zephyr shell. Fixes #63794 Signed-off-by: Josuah Demangeon --- drivers/serial/uart_liteuart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/uart_liteuart.c b/drivers/serial/uart_liteuart.c index 073d565770efe93..d23b68b7c5ca3f3 100644 --- a/drivers/serial/uart_liteuart.c +++ b/drivers/serial/uart_liteuart.c @@ -273,8 +273,8 @@ static void liteuart_uart_irq_handler(const struct device *dev) data->callback(dev, data->cb_data); } - /* clear events */ - litex_write8(UART_EV_TX | UART_EV_RX, UART_EV_PENDING_ADDR); + /* Clear RX events, TX events still needed to enqueue the next transfer */ + litex_write8(UART_EV_RX, UART_EV_PENDING_ADDR); irq_unlock(key); } From ce3ba0dfd2620e3566face861d2c22ff5765e137 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 17 Nov 2023 09:47:18 +0000 Subject: [PATCH 0600/1049] modules: openthread: platform: radio: Rename missed type Fixes an issue whereby a rename of a variable type has been forgotten in an instance, which now uses the correct type name Signed-off-by: Jamie McCrae --- modules/openthread/platform/radio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 9c5de3c9d69f71c..98eab182aade44d 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -1431,7 +1431,7 @@ otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics a header_ie_len = set_vendor_ie_header_lm(aLinkMetrics.mLqi, aLinkMetrics.mLinkMargin, aLinkMetrics.mRssi, header_ie_buf); - config.ack_ie.header_ie = (struct ieee802154_ie_header *)header_ie_buf; + config.ack_ie.header_ie = (struct ieee802154_header_ie *)header_ie_buf; result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config); return result ? OT_ERROR_FAILED : OT_ERROR_NONE; From 4c92419546abf0d9193009a2b622f93d572d4b6b Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Fri, 22 Sep 2023 17:23:29 -0700 Subject: [PATCH 0601/1049] drivers: sensor: hs300x: Add driver for Renesas HS300x sensors Adds support for Renesas HS3001 and HS3003 temperature/humidity sensors connected via an I2C bus. Signed-off-by: Ian Morris --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/hs300x/CMakeLists.txt | 5 + drivers/sensor/hs300x/Kconfig | 12 ++ drivers/sensor/hs300x/hs300x.c | 160 ++++++++++++++++++++++++ dts/bindings/sensor/renesas,hs300x.yaml | 10 ++ tests/drivers/build_all/sensor/i2c.dtsi | 5 + 7 files changed, 194 insertions(+) create mode 100644 drivers/sensor/hs300x/CMakeLists.txt create mode 100644 drivers/sensor/hs300x/Kconfig create mode 100644 drivers/sensor/hs300x/hs300x.c create mode 100644 dts/bindings/sensor/renesas,hs300x.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index ff1cf9ec4eb449c..2fa37289ac21f42 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -47,6 +47,7 @@ add_subdirectory_ifdef(CONFIG_HAS_STMEMSC stmemsc) add_subdirectory_ifdef(CONFIG_HM330X hm330x) add_subdirectory_ifdef(CONFIG_HMC5883L hmc5883l) add_subdirectory_ifdef(CONFIG_HP206C hp206c) +add_subdirectory_ifdef(CONFIG_HS300X hs300x) add_subdirectory_ifdef(CONFIG_HTS221 hts221) add_subdirectory_ifdef(CONFIG_I3G4250D i3g4250d) add_subdirectory_ifdef(CONFIG_ICM42605 icm42605) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 55ef3ffec513643..25af39bde4c78ff 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -119,6 +119,7 @@ source "drivers/sensor/grow_r502a/Kconfig" source "drivers/sensor/hm330x/Kconfig" source "drivers/sensor/hmc5883l/Kconfig" source "drivers/sensor/hp206c/Kconfig" +source "drivers/sensor/hs300x/Kconfig" source "drivers/sensor/hts221/Kconfig" source "drivers/sensor/i3g4250d/Kconfig" source "drivers/sensor/icm42605/Kconfig" diff --git a/drivers/sensor/hs300x/CMakeLists.txt b/drivers/sensor/hs300x/CMakeLists.txt new file mode 100644 index 000000000000000..f937e6bb6f11b3e --- /dev/null +++ b/drivers/sensor/hs300x/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(hs300x.c) diff --git a/drivers/sensor/hs300x/Kconfig b/drivers/sensor/hs300x/Kconfig new file mode 100644 index 000000000000000..53060cb5c217efd --- /dev/null +++ b/drivers/sensor/hs300x/Kconfig @@ -0,0 +1,12 @@ +# Renesas HS300x temperature and humidity sensor configuration options + +# Copyright (c) 2023 Ian Morris +# SPDX-License-Identifier: Apache-2.0 + +config HS300X + bool "HS300x Temperature and Humidity Sensor" + default y + depends on DT_HAS_RENESAS_HS300X_ENABLED + select I2C + help + Enable driver for HS300x temperature and humidity sensors. diff --git a/drivers/sensor/hs300x/hs300x.c b/drivers/sensor/hs300x/hs300x.c new file mode 100644 index 000000000000000..9faabbb1e352092 --- /dev/null +++ b/drivers/sensor/hs300x/hs300x.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2023 Ian Morris + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_hs300x + +#include +#include +#include +#include +#include +#include +#include + +#define HS300X_STATUS_MASK (BIT(0) | BIT(1)) + +LOG_MODULE_REGISTER(HS300X, CONFIG_SENSOR_LOG_LEVEL); + +struct hs300x_config { + struct i2c_dt_spec bus; +}; + +struct hs300x_data { + int16_t t_sample; + uint16_t rh_sample; +}; + +static int hs300x_read_sample(const struct device *dev, uint16_t *t_sample, uint16_t *rh_sample) +{ + const struct hs300x_config *cfg = dev->config; + uint8_t rx_buf[4]; + int rc; + + rc = i2c_read_dt(&cfg->bus, rx_buf, sizeof(rx_buf)); + if (rc < 0) { + LOG_ERR("Failed to read data from device."); + return rc; + } + + if ((rx_buf[3] & HS300X_STATUS_MASK) != 0) { + LOG_ERR("Stale data"); + return -EIO; + } + + *rh_sample = sys_get_be16(rx_buf); + *t_sample = sys_get_be16(&rx_buf[2]); + + /* Remove status bits (only present in temperature value)*/ + *t_sample >>= 2; + + return 0; +} + +static int hs300x_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct hs300x_data *data = dev->data; + const struct hs300x_config *cfg = dev->config; + int rc; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP && + chan != SENSOR_CHAN_HUMIDITY) { + return -ENOTSUP; + } + + /* + * Initiate a measurement simply by sending 7-bit address followed + * by an eighth bit set to 0 (write) and NO data. + */ + rc = i2c_write_dt(&cfg->bus, NULL, 0); + if (rc < 0) { + LOG_ERR("Failed to start measurement."); + return rc; + } + + /* + * According to datasheet maximum time to make temperature and humidity + * measurements is 33ms, add a little safety margin... + */ + k_msleep(50); + + rc = hs300x_read_sample(dev, &data->t_sample, &data->rh_sample); + if (rc < 0) { + LOG_ERR("Failed to fetch data."); + return rc; + } + + return 0; +} + +static void hs300x_temp_convert(struct sensor_value *val, int16_t raw) +{ + int32_t micro_c; + + /* + * Convert to micro Celsius. See datasheet "Calculating Humidity and + * Temperature Output" section for more details on processing sample data. + */ + micro_c = (((int64_t)raw * 165000000) / 16383) - 40000000; + + val->val1 = micro_c / 1000000; + val->val2 = micro_c % 1000000; +} + +static void hs300x_rh_convert(struct sensor_value *val, uint16_t raw) +{ + int32_t micro_rh; + + /* + * Convert to micro %RH. See datasheet "Calculating Humidity and + * Temperature Output" section for more details on processing sample data. + */ + micro_rh = ((uint64_t)raw * 100000000) / 16383; + + val->val1 = micro_rh / 1000000; + val->val2 = micro_rh % 1000000; +} + +static int hs300x_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + const struct hs300x_data *data = dev->data; + + if (chan == SENSOR_CHAN_AMBIENT_TEMP) { + hs300x_temp_convert(val, data->t_sample); + } else if (chan == SENSOR_CHAN_HUMIDITY) { + hs300x_rh_convert(val, data->rh_sample); + } else { + return -ENOTSUP; + } + + return 0; +} + +static int hs300x_init(const struct device *dev) +{ + const struct hs300x_config *cfg = dev->config; + + if (!i2c_is_ready_dt(&cfg->bus)) { + LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name); + return -ENODEV; + } + + return 0; +} + +static const struct sensor_driver_api hs300x_driver_api = {.sample_fetch = hs300x_sample_fetch, + .channel_get = hs300x_channel_get}; + +#define DEFINE_HS300X(n) \ + static struct hs300x_data hs300x_data_##n; \ + \ + static const struct hs300x_config hs300x_config_##n = {.bus = I2C_DT_SPEC_INST_GET(n)}; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, hs300x_init, NULL, &hs300x_data_##n, &hs300x_config_##n, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &hs300x_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_HS300X) diff --git a/dts/bindings/sensor/renesas,hs300x.yaml b/dts/bindings/sensor/renesas,hs300x.yaml new file mode 100644 index 000000000000000..cd24b67da74db1c --- /dev/null +++ b/dts/bindings/sensor/renesas,hs300x.yaml @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023 Ian Morris +# +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas HS300x humidity and temperature sensor + +compatible: "renesas,hs300x" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index ebafddab96c6e9c..ce22576c48a35d1 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -807,3 +807,8 @@ test_i2c_lps22df: lps22df@79 { drdy-gpios = <&test_gpio 0 0>; status = "okay"; }; + +test_i2c_hs300x: hs300x@79 { + compatible = "renesas,hs300x"; + reg = <0x79>; +}; From dfc747d53a07b1219c7a962ca64a8edadf05f5f2 Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Fri, 22 Sep 2023 17:38:07 -0700 Subject: [PATCH 0602/1049] samples: sensor: dht_polling: Add generic dht sample application This simple application periodically prints the temperature and humidity measured by one or more digital humidity/temperature sensors. Signed-off-by: Ian Morris --- samples/sensor/dht_polling/CMakeLists.txt | 9 +++ samples/sensor/dht_polling/README.rst | 49 +++++++++++++++ .../dht_polling/boards/nucleo_f401re.overlay | 22 +++++++ samples/sensor/dht_polling/prj.conf | 2 + samples/sensor/dht_polling/sample.yaml | 20 ++++++ samples/sensor/dht_polling/src/main.c | 62 +++++++++++++++++++ 6 files changed, 164 insertions(+) create mode 100644 samples/sensor/dht_polling/CMakeLists.txt create mode 100644 samples/sensor/dht_polling/README.rst create mode 100644 samples/sensor/dht_polling/boards/nucleo_f401re.overlay create mode 100644 samples/sensor/dht_polling/prj.conf create mode 100644 samples/sensor/dht_polling/sample.yaml create mode 100644 samples/sensor/dht_polling/src/main.c diff --git a/samples/sensor/dht_polling/CMakeLists.txt b/samples/sensor/dht_polling/CMakeLists.txt new file mode 100644 index 000000000000000..31b4352da9d70f1 --- /dev/null +++ b/samples/sensor/dht_polling/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Ian Morris +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(dht_polling) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/dht_polling/README.rst b/samples/sensor/dht_polling/README.rst new file mode 100644 index 000000000000000..09550b255d00b47 --- /dev/null +++ b/samples/sensor/dht_polling/README.rst @@ -0,0 +1,49 @@ +.. _dht_polling: + +Generic Digital Humidity Temperature sensor polling sample +########################################################## + +Overview +******** + +This sample application demonstrates how to use digital humidity temperature +sensors. + +Building and Running +******************** + +This sample supports up to 10 humidity/temperature sensors. Each sensor needs to +be aliased as ``dhtN`` where ``N`` goes from ``0`` to ``9``. For example: + +.. code-block:: devicetree + + / { + aliases { + dht0 = &hs300x; + }; + }; + +Make sure the aliases are in devicetree, then build and run with: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/dht_polling + :board: + :goals: build flash + :compact: + +Sample Output +============= + +.. code-block:: console + + hs300x@44: temp is 25.31 °C humidity is 30.39 %RH + hs300x@44: temp is 25.51 °C humidity is 30.44 %RH + hs300x@44: temp is 25.51 °C humidity is 30.37 %RH + hs300x@44: temp is 25.51 °C humidity is 30.39 %RH + hs300x@44: temp is 25.31 °C humidity is 30.37 %RH + hs300x@44: temp is 25.31 °C humidity is 30.35 %RH + hs300x@44: temp is 25.51 °C humidity is 30.37 %RH + hs300x@44: temp is 25.51 °C humidity is 30.37 %RH + hs300x@44: temp is 25.51 °C humidity is 30.39 %RH + hs300x@44: temp is 25.51 °C humidity is 30.44 %RH + hs300x@44: temp is 25.51 °C humidity is 30.53 %RH diff --git a/samples/sensor/dht_polling/boards/nucleo_f401re.overlay b/samples/sensor/dht_polling/boards/nucleo_f401re.overlay new file mode 100644 index 000000000000000..cb381b5ba3a0f0c --- /dev/null +++ b/samples/sensor/dht_polling/boards/nucleo_f401re.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Ian Morris + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + dht0 = &hs300x; + }; +}; + + &i2c1 { + status = "okay"; + + hs300x: hs300x@44 { + compatible = "renesas,hs300x"; + reg = <0x44>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/samples/sensor/dht_polling/prj.conf b/samples/sensor/dht_polling/prj.conf new file mode 100644 index 000000000000000..7d668be1f0b1957 --- /dev/null +++ b/samples/sensor/dht_polling/prj.conf @@ -0,0 +1,2 @@ +CONFIG_STDOUT_CONSOLE=y +CONFIG_SENSOR=y diff --git a/samples/sensor/dht_polling/sample.yaml b/samples/sensor/dht_polling/sample.yaml new file mode 100644 index 000000000000000..8177e636d21670f --- /dev/null +++ b/samples/sensor/dht_polling/sample.yaml @@ -0,0 +1,20 @@ +# +# Copyright (c) 2023 Ian Morris +# +# SPDX-License-Identifier: Apache-2.0 +# + +sample: + description: Digital Humidity Temperature polling sample + name: DHT polling sample +tests: + sample.sensor.dht_polling: + tags: sensors + filter: dt_alias_exists("dht0") + integration_platforms: + - nucleo_f401re + harness: console + harness_config: + type: one_line + regex: + - "[0-9A-Za-z_,+-.]*@[0-9A-Fa-f]*: temp is (.*) °C humidity is (.*) %RH" diff --git a/samples/sensor/dht_polling/src/main.c b/samples/sensor/dht_polling/src/main.c new file mode 100644 index 000000000000000..8ff26b5ab9b0acf --- /dev/null +++ b/samples/sensor/dht_polling/src/main.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Ian Morris + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#define DHT_ALIAS(i) DT_ALIAS(_CONCAT(dht, i)) +#define DHT_DEVICE(i, _) \ + IF_ENABLED(DT_NODE_EXISTS(DHT_ALIAS(i)), (DEVICE_DT_GET(DHT_ALIAS(i)),)) + +/* Support up to 10 temperature/humidity sensors */ +static const struct device *const sensors[] = {LISTIFY(10, DHT_DEVICE, ())}; + +int main(void) +{ + int rc; + + for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) { + if (!device_is_ready(sensors[i])) { + printk("sensor: device %s not ready.\n", sensors[i]->name); + return 0; + } + } + + while (1) { + for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) { + struct device *dev = (struct device *)sensors[i]; + + rc = sensor_sample_fetch(dev); + if (rc < 0) { + printk("%s: sensor_sample_fetch() failed: %d\n", dev->name, rc); + return rc; + } + + struct sensor_value temp; + struct sensor_value hum; + + rc = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp); + if (rc == 0) { + rc = sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &hum); + } + if (rc != 0) { + printf("get failed: %d\n", rc); + break; + } + + printk("%16s: temp is %d.%02d °C humidity is %d.%02d %%RH\n", + dev->name, temp.val1, temp.val2 / 10000, + hum.val1, hum.val2 / 10000); + } + k_msleep(1000); + } + return 0; +} From 4cfd4b5379ee200e76358e17e90aabe0a55f5365 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Mon, 30 Oct 2023 15:14:12 +0800 Subject: [PATCH 0603/1049] driver: timer: npcx: fix announce/set timer timeout tick The timer driver doesn't annouce/set the timeout at the tick boundary but at the absolute next expiration time. It will cause the accumatlation of the tick drift and cannot pass the kernel/timer/timer_behavior test suite. This commit fixes the tick drift problem by annouce the time at the tick bouandry. Fixes #59594 Signed-off-by: Jun Lin --- drivers/timer/npcx_itim_timer.c | 38 ++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/timer/npcx_itim_timer.c b/drivers/timer/npcx_itim_timer.c index a54db566d9eba25..fba2bc2b3c11348 100644 --- a/drivers/timer/npcx_itim_timer.c +++ b/drivers/timer/npcx_itim_timer.c @@ -58,6 +58,7 @@ LOG_MODULE_REGISTER(itim, LOG_LEVEL_ERR); #define NPCX_ITIM_CLK_SEL_DELAY 92 /* Delay for clock selection (Unit:us) */ /* Timeout for enabling ITIM module: 100us (Unit:cycles) */ #define NPCX_ITIM_EN_TIMEOUT_CYCLES (100 * SYS_CYCLES_PER_USEC) +#define SYS_CYC_PER_EVT_CYC (sys_clock_hw_cycles_per_sec() / EVT_CYCLES_PER_SEC) /* Instance of system and event timers */ static struct itim64_reg *const sys_tmr = (struct itim64_reg *) @@ -70,6 +71,9 @@ static const struct npcx_clk_cfg itim_clk_cfg[] = NPCX_DT_CLK_CFG_ITEMS_LIST(0); static struct k_spinlock lock; /* Announced cycles in system timer before executing sys_clock_announce() */ static uint64_t cyc_sys_announced; +static uint64_t last_ticks; +static uint32_t last_elapsed; + /* Current target cycles of time-out signal in event timer */ static uint32_t cyc_evt_timeout; /* Total cycles of system timer stopped in "sleep/deep sleep" mode */ @@ -136,18 +140,33 @@ static inline void npcx_itim_evt_disable(void) /* ITIM local functions */ static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks) { + k_spinlock_key_t key = k_spin_lock(&lock); + /* * Get desired cycles of event timer from the requested ticks which * round up to next tick boundary. */ + if (ticks == K_TICKS_FOREVER) { cyc_evt_timeout = NPCX_ITIM32_MAX_CNT; } else { + uint64_t next_cycs; + uint64_t curr = npcx_itim_get_sys_cyc64(); + uint32_t dcycles; + if (ticks <= 0) { ticks = 1; } - cyc_evt_timeout = MIN(EVT_CYCLES_FROM_TICKS(ticks), - NPCX_ITIM32_MAX_CNT); + + next_cycs = (last_ticks + last_elapsed + ticks) * SYS_CYCLES_PER_TICK; + if (unlikely(next_cycs <= curr)) { + cyc_evt_timeout = 1; + } else { + dcycles = next_cycs - curr; + cyc_evt_timeout = + CLAMP((dcycles / SYS_CYC_PER_EVT_CYC), 1, NPCX_ITIM32_MAX_CNT); + } + } LOG_DBG("ticks %x, cyc_evt_timeout %x", ticks, cyc_evt_timeout); @@ -159,9 +178,9 @@ static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks) /* Upload counter of event timer */ evt_tmr->ITCNT32 = MAX(cyc_evt_timeout - 1, 1); + k_spin_unlock(&lock, key); /* Enable event timer and start ticking */ return npcx_itim_evt_enable(); - } static void npcx_itim_evt_isr(const struct device *dev) @@ -175,11 +194,12 @@ static void npcx_itim_evt_isr(const struct device *dev) if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { k_spinlock_key_t key = k_spin_lock(&lock); - uint32_t delta_ticks = (uint32_t)((npcx_itim_get_sys_cyc64() - - cyc_sys_announced) / SYS_CYCLES_PER_TICK); + uint64_t curr = npcx_itim_get_sys_cyc64(); + uint32_t delta_ticks = (uint32_t)((curr - cyc_sys_announced) / SYS_CYCLES_PER_TICK); - /* Store announced cycles of system timer */ - cyc_sys_announced = npcx_itim_get_sys_cyc64(); + cyc_sys_announced += delta_ticks * SYS_CYCLES_PER_TICK; + last_ticks += delta_ticks; + last_elapsed = 0; k_spin_unlock(&lock, key); /* Informs kernel that specified number of ticks have elapsed */ @@ -252,11 +272,13 @@ uint32_t sys_clock_elapsed(void) k_spinlock_key_t key = k_spin_lock(&lock); uint64_t delta_cycle = npcx_itim_get_sys_cyc64() - cyc_sys_announced; + uint32_t delta_ticks = (uint32_t)delta_cycle / SYS_CYCLES_PER_TICK; + last_elapsed = delta_ticks; k_spin_unlock(&lock, key); /* Return how many ticks elapsed since last sys_clock_announce() call */ - return (uint32_t)(delta_cycle / SYS_CYCLES_PER_TICK); + return delta_ticks; } uint32_t sys_clock_cycle_get_32(void) From 317d0702221d281fb498ac763baacd882b23f746 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Thu, 2 Nov 2023 11:06:15 +0800 Subject: [PATCH 0604/1049] tests: timer_behavior: increase stdev tolerance for npcx timer Change the stdev tolerance stdev from 10 to 33 when npcx timer is used. This is because the clock source of npcx event timer, which is used to generate the timeout interrupt, is running at 32.768 KHz. (i.e. 1 count = ~30.5 us.) The conversion from the absolute system timer to the event timer count might have -30.5 ~ 30.5 deviation. The tolerance setting is under the assumption that test sampes are evenly located at 1030.5 and 969.5 for the worst case. Fixes #59594 Signed-off-by: Jun Lin --- tests/kernel/timer/timer_behavior/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/kernel/timer/timer_behavior/Kconfig b/tests/kernel/timer/timer_behavior/Kconfig index 9e5d80532f1702c..ba5f18e969e0364 100644 --- a/tests/kernel/timer/timer_behavior/Kconfig +++ b/tests/kernel/timer/timer_behavior/Kconfig @@ -23,6 +23,7 @@ config TIMER_TEST_PERIOD config TIMER_TEST_MAX_STDDEV int "Maximum standard deviation in microseconds allowed" + default 33 if NPCX_ITIM_TIMER default 10 config TIMER_TEST_MAX_DRIFT From da3d9197a650977a08dbb2ba409feca6b00f5996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 16 Nov 2023 23:45:19 +0700 Subject: [PATCH 0605/1049] include: arm: nxp_mpu: remove redundant HAL include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The inclusion of `fsl_common.h` solely for defining `NXP_MPU_BASE` is redundant, as this symbol is not used. Consequently, this unnecessary inclusion leads to the pervasive inclusion of HAL headers through kernel headers. The needed HAL definitions are already included into the NXP MPU driver implementation via the SoC header. Signed-off-by: Manuel Argüelles --- include/zephyr/arch/arm/mpu/nxp_mpu.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/zephyr/arch/arm/mpu/nxp_mpu.h b/include/zephyr/arch/arm/mpu/nxp_mpu.h index 2b40050afa4c672..d1f5882bfeda60e 100644 --- a/include/zephyr/arch/arm/mpu/nxp_mpu.h +++ b/include/zephyr/arch/arm/mpu/nxp_mpu.h @@ -8,10 +8,6 @@ #ifndef _ASMLANGUAGE -#include - -#define NXP_MPU_BASE SYSMPU_BASE - #define NXP_MPU_REGION_NUMBER 12 /* Bus Master User Mode Access */ From 92fb8b223825bb3d8714017743c453a225eb6dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 16 Nov 2023 21:13:31 +0700 Subject: [PATCH 0606/1049] arm: nxp_mpu: enable module's clock only when needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NXP SYSMPU is used in other SoCs besides the Kinetis series. For devices like S32K1xx, its bus interface clock lacks of clock gating and it's driven by the system clock. Hence, only enable the module clock for the Kinetis series. Signed-off-by: Manuel Argüelles --- arch/arm/core/mpu/nxp_mpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/core/mpu/nxp_mpu.c b/arch/arm/core/mpu/nxp_mpu.c index f3d3bd715aefa8c..39d7cde6f8f52c4 100644 --- a/arch/arm/core/mpu/nxp_mpu.c +++ b/arch/arm/core/mpu/nxp_mpu.c @@ -37,8 +37,10 @@ static uint8_t static_regions_num; /* Global MPU configuration at system initialization. */ static void mpu_init(void) { +#if defined(CONFIG_SOC_FAMILY_KINETIS) /* Enable clock for the Memory Protection Unit (MPU). */ CLOCK_EnableClock(kCLOCK_Sysmpu0); +#endif } /** From 21d885535e7da4fe658056205b06493a687cf66f Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 17 Nov 2023 11:29:45 -0500 Subject: [PATCH 0607/1049] MAINTAINERS: declare myself as a RISC-V collaborator ... given that 62.5% of the code in arch/riscv/core/* is mine. Signed-off-by: Nicolas Pitre --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index aa4fbaadced7287..f03d141e4756b4d 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2281,6 +2281,7 @@ RISCV arch: - katsuster - edersondisouza - carlocaione + - npitre files: - arch/riscv/ - boards/riscv/ From b485cd717bea008f66cc3452f65f2b45bd1cc1ab Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 17 Nov 2023 10:31:14 -0800 Subject: [PATCH 0608/1049] xtensa: remove unused z_mp_entry declaration z_mp_entry has been removed from Xtensa architecture. So there is no need for a function declaration. Remove it. Signed-off-by: Daniel Leung --- arch/xtensa/core/crt1.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/xtensa/core/crt1.S b/arch/xtensa/core/crt1.S index 1f9cc148ab5a9f7..0fa3ad230995c41 100644 --- a/arch/xtensa/core/crt1.S +++ b/arch/xtensa/core/crt1.S @@ -23,7 +23,6 @@ .global __start .type z_cstart, @function -.type z_mp_entry, @function #ifdef CONFIG_XTENSA_MMU .type z_xtensa_mmu_init, @function From 0d1fa268bb598033de961d9a0130d9cb2c16bebd Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sun, 11 Jun 2023 17:07:42 -0400 Subject: [PATCH 0609/1049] drivers: clock_control: Add PWM clock device Adds a clock control device for a PWM node, allowing the PWM to be controlled using the clock control API. It is a similar idea to the device driver in linux: linux/Documentation/devicetree/bindings/clock/pwm-clock.yaml Signed-off-by: Andriy Gelman --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.pwm | 18 ++ drivers/clock_control/clock_control_pwm.c | 159 ++++++++++++++++++ dts/bindings/clock/pwm-clock.yaml | 54 ++++++ .../clock_control/pwm_clock/CMakeLists.txt | 7 + .../pwm_clock/boards/sam_v71_xult.overlay | 25 +++ .../pwm_clock/boards/xmc45_relax_kit.overlay | 26 +++ .../pwm_clock/boards/xmc47_relax_kit.overlay | 26 +++ .../test-clock-control-clock-pwm.yaml | 10 ++ .../drivers/clock_control/pwm_clock/prj.conf | 2 + .../clock_control/pwm_clock/src/main.c | 74 ++++++++ .../clock_control/pwm_clock/testcase.yaml | 7 + 13 files changed, 411 insertions(+) create mode 100644 drivers/clock_control/Kconfig.pwm create mode 100644 drivers/clock_control/clock_control_pwm.c create mode 100644 dts/bindings/clock/pwm-clock.yaml create mode 100644 tests/drivers/clock_control/pwm_clock/CMakeLists.txt create mode 100644 tests/drivers/clock_control/pwm_clock/boards/sam_v71_xult.overlay create mode 100644 tests/drivers/clock_control/pwm_clock/boards/xmc45_relax_kit.overlay create mode 100644 tests/drivers/clock_control/pwm_clock/boards/xmc47_relax_kit.overlay create mode 100644 tests/drivers/clock_control/pwm_clock/dts/bindings/test-clock-control-clock-pwm.yaml create mode 100644 tests/drivers/clock_control/pwm_clock/prj.conf create mode 100644 tests/drivers/clock_control/pwm_clock/src/main.c create mode 100644 tests/drivers/clock_control/pwm_clock/testcase.yaml diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 0f7a1c4dd4ab9f8..a1f553fc1348084 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -28,6 +28,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NUMAKER_SCC clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NXP_S32 clock_control_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RA clock_control_ra.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AMBIQ clock_control_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_PWM clock_control_pwm.c) if(CONFIG_CLOCK_CONTROL_STM32_CUBE) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index a380b9a9c12abcb..37cbb2e28956587 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -84,4 +84,6 @@ source "drivers/clock_control/Kconfig.ra" source "drivers/clock_control/Kconfig.ambiq" +source "drivers/clock_control/Kconfig.pwm" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.pwm b/drivers/clock_control/Kconfig.pwm new file mode 100644 index 000000000000000..eed5a91c17bb190 --- /dev/null +++ b/drivers/clock_control/Kconfig.pwm @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_PWM + bool "Generic PWM clock" + default y + depends on DT_HAS_PWM_CLOCK_ENABLED + select PWM + help + Enable generic PWM clock. + +config CLOCK_CONTROL_PWM_INIT_PRIORITY + int "Initialization priority of the pwm clock device" + default 51 + depends on CLOCK_CONTROL_PWM + help + Initialization priority of the PWM clock device. Must be + lower priority than PWM. diff --git a/drivers/clock_control/clock_control_pwm.c b/drivers/clock_control/clock_control_pwm.c new file mode 100644 index 000000000000000..1936e3ab6cce25e --- /dev/null +++ b/drivers/clock_control/clock_control_pwm.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT pwm_clock + +#include + +#include +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL +#include +LOG_MODULE_REGISTER(clock_control_pwm); + +BUILD_ASSERT(CONFIG_CLOCK_CONTROL_PWM_INIT_PRIORITY > CONFIG_PWM_INIT_PRIORITY, + "PWM must have a higher priority than PWM clock control"); + +#define NUM_PWM_CLOCKS 1 + +struct clock_control_pwm_config { + const struct pwm_dt_spec pwm_dt; + const uint16_t pwm_on_delay; +}; + +struct clock_control_pwm_data { + uint32_t clock_frequency; + bool is_enabled; +}; + +static int clock_control_pwm_on(const struct device *dev, clock_control_subsys_t sys) +{ + struct clock_control_pwm_data *data = dev->data; + const struct clock_control_pwm_config *config = dev->config; + const struct pwm_dt_spec *spec; + int id = (int)sys; + int ret; + + if (id >= NUM_PWM_CLOCKS) { + return -EINVAL; + } + + spec = &config->pwm_dt; + if (data->clock_frequency == 0) { + ret = pwm_set_dt(spec, spec->period, spec->period / 2); + } else { + uint64_t cycles_per_sec; + uint32_t period_cycles; + + ret = pwm_get_cycles_per_sec(spec->dev, spec->channel, &cycles_per_sec); + if (ret) { + return ret; + } + + if (cycles_per_sec % data->clock_frequency > 0) { + LOG_WRN("Target clock frequency cannot be expressed in PWM clock ticks"); + } + + period_cycles = cycles_per_sec / data->clock_frequency; + ret = pwm_set_cycles(spec->dev, spec->channel, period_cycles, period_cycles / 2, + spec->flags); + } + + if (ret) { + return ret; + } + + k_busy_wait(config->pwm_on_delay); + + data->is_enabled = true; + + return 0; +} + +static int clock_control_pwm_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + struct clock_control_pwm_data *data = dev->data; + const struct clock_control_pwm_config *config = dev->config; + int id = (int)sys; + + if (id >= NUM_PWM_CLOCKS) { + return -EINVAL; + } + + if (data->clock_frequency > 0) { + *rate = data->clock_frequency; + } else { + *rate = NSEC_PER_SEC / config->pwm_dt.period; + } + + return 0; +} + +static int clock_control_pwm_set_rate(const struct device *dev, clock_control_subsys_rate_t sys, + clock_control_subsys_rate_t rate) +{ + struct clock_control_pwm_data *data = dev->data; + uint32_t rate_hz = (uint32_t)rate; + int id = (int)sys; + + if (id >= NUM_PWM_CLOCKS) { + return -EINVAL; + } + + if (data->clock_frequency == rate_hz && data->is_enabled) { + return -EALREADY; + } + + data->clock_frequency = rate_hz; + + return clock_control_pwm_on(dev, sys); +} + +static int clock_control_pwm_init(const struct device *dev) +{ + const struct clock_control_pwm_config *config = dev->config; + + if (!device_is_ready(config->pwm_dt.dev)) { + return -ENODEV; + } + + return 0; +} + +static struct clock_control_driver_api clock_control_pwm_api = { + .on = clock_control_pwm_on, + .get_rate = clock_control_pwm_get_rate, + .set_rate = clock_control_pwm_set_rate, +}; + +#define PWM_CLOCK_INIT(i) \ + \ + BUILD_ASSERT(DT_INST_PROP_LEN(i, pwms) <= 1, \ + "One PWM per clock control node is supported"); \ + \ + BUILD_ASSERT(DT_INST_PROP(i, pwm_on_delay) <= UINT16_MAX, \ + "Maximum pwm-on-delay is 65535 usec"); \ + \ + static const struct clock_control_pwm_config clock_control_pwm_config_##i = { \ + .pwm_dt = PWM_DT_SPEC_INST_GET(i), \ + .pwm_on_delay = DT_INST_PROP(i, pwm_on_delay), \ + }; \ + \ + static struct clock_control_pwm_data clock_control_pwm_data_##i = { \ + .clock_frequency = DT_INST_PROP_OR(i, clock_frequency, 0), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(i, clock_control_pwm_init, NULL, &clock_control_pwm_data_##i, \ + &clock_control_pwm_config_##i, POST_KERNEL, \ + CONFIG_CLOCK_CONTROL_PWM_INIT_PRIORITY, &clock_control_pwm_api); + +DT_INST_FOREACH_STATUS_OKAY(PWM_CLOCK_INIT) diff --git a/dts/bindings/clock/pwm-clock.yaml b/dts/bindings/clock/pwm-clock.yaml new file mode 100644 index 000000000000000..5e19a245809cf73 --- /dev/null +++ b/dts/bindings/clock/pwm-clock.yaml @@ -0,0 +1,54 @@ +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 + +description: | + An external clock signal driven by a PWM pin. + + The devicetree must define a clock node: + + pwmclock: pwmclock { + status = "okay"; + compatible = "pwm-clock"; + #clock-cells = <1>; + pwms = <&pwm_ccu40 2 PWM_HZ(1000000) PWM_POLARITY_NORMAL>; + }; + + This will create a device node with a clock-controller + API. Internally the device node will use PWM API to start the + clock signals at 1MHz. Note that the PWM_HZ() macro converts the + frequency to time (nanoseconds units). This may result in rounding + errors if the clock frequency is not an integer number of nanoseconds. + The clock frequency can be explicitly set using the clock-frequency + property. + + The PWM node may need to be properly configured to generate + the target period (i.e. using prescaler options). See the documention + for the target PWM driver. + +compatible: "pwm-clock" + +include: [clock-controller.yaml, base.yaml] + +properties: + pwms: + type: phandle-array + required: true + + clock-frequency: + type: int + description: | + Exact output frequency, in case the PWM period is not exact + but was rounded to nanoseconds. This property is optional. + + pwm-on-delay: + type: int + default: 0 + description: + Optional blocking delay in micro seconds to make sure that the PWM + clock has started after returning from clock_control_on(). + + "#clock-cells": + const: 1 + +clock-cells: + - id diff --git a/tests/drivers/clock_control/pwm_clock/CMakeLists.txt b/tests/drivers/clock_control/pwm_clock/CMakeLists.txt new file mode 100644 index 000000000000000..c6217f1aabf9327 --- /dev/null +++ b/tests/drivers/clock_control/pwm_clock/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(pwm_clock) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/drivers/clock_control/pwm_clock/boards/sam_v71_xult.overlay b/tests/drivers/clock_control/pwm_clock/boards/sam_v71_xult.overlay new file mode 100644 index 000000000000000..f744dc9f0e5e5ca --- /dev/null +++ b/tests/drivers/clock_control/pwm_clock/boards/sam_v71_xult.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + pwmclock: pwmclock { + status = "okay"; + compatible = "pwm-clock"; + #clock-cells = <1>; + clock-frequency = <1000000>; + pwms = <&pwm0 0 PWM_KHZ(1000) PWM_POLARITY_NORMAL>; + }; + + samplenode: samplenode { + status = "okay"; + compatible = "test-clock-control-pwm-clock"; + clocks = <&pwmclock 0>; + }; +}; + +&pwm0 { + prescaler = <1>; +}; diff --git a/tests/drivers/clock_control/pwm_clock/boards/xmc45_relax_kit.overlay b/tests/drivers/clock_control/pwm_clock/boards/xmc45_relax_kit.overlay new file mode 100644 index 000000000000000..16218f42596761f --- /dev/null +++ b/tests/drivers/clock_control/pwm_clock/boards/xmc45_relax_kit.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + pwmclock: pwmclock { + status = "okay"; + compatible = "pwm-clock"; + #clock-cells = <1>; + clock-frequency = <1000000>; + pwms = <&pwm_ccu40 2 PWM_KHZ(1000) PWM_POLARITY_NORMAL>; + }; + + samplenode: samplenode { + status = "okay"; + compatible = "test-clock-control-pwm-clock"; + clocks = <&pwmclock 0>; + }; +}; + +&pwm_ccu40 { + status = "okay"; + slice-prescaler = <0 0 0 0>; +}; diff --git a/tests/drivers/clock_control/pwm_clock/boards/xmc47_relax_kit.overlay b/tests/drivers/clock_control/pwm_clock/boards/xmc47_relax_kit.overlay new file mode 100644 index 000000000000000..880430e4c680906 --- /dev/null +++ b/tests/drivers/clock_control/pwm_clock/boards/xmc47_relax_kit.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + pwmclock: pwmclock { + status = "okay"; + compatible = "pwm-clock"; + #clock-cells = <1>; + clock-frequency = <1000000>; + pwms = <&pwm_ccu80 0 PWM_KHZ(1000) PWM_POLARITY_NORMAL>; + }; + + samplenode: samplenode { + status = "okay"; + compatible = "test-clock-control-pwm-clock"; + clocks = <&pwmclock 0>; + }; +}; + +&pwm_ccu80 { + status = "okay"; + slice-prescaler = <0 0 0 0>; +}; diff --git a/tests/drivers/clock_control/pwm_clock/dts/bindings/test-clock-control-clock-pwm.yaml b/tests/drivers/clock_control/pwm_clock/dts/bindings/test-clock-control-clock-pwm.yaml new file mode 100644 index 000000000000000..078e3bc39cdc0af --- /dev/null +++ b/tests/drivers/clock_control/pwm_clock/dts/bindings/test-clock-control-clock-pwm.yaml @@ -0,0 +1,10 @@ +description: Example binding for a node using a PWM clock + +compatible: "test-clock-control-pwm-clock" + +include: base.yaml + +properties: + clocks: + required: true + description: Clock phandle array diff --git a/tests/drivers/clock_control/pwm_clock/prj.conf b/tests/drivers/clock_control/pwm_clock/prj.conf new file mode 100644 index 000000000000000..903dc40185bc572 --- /dev/null +++ b/tests/drivers/clock_control/pwm_clock/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_CLOCK_CONTROL=y diff --git a/tests/drivers/clock_control/pwm_clock/src/main.c b/tests/drivers/clock_control/pwm_clock/src/main.c new file mode 100644 index 000000000000000..87fa860147327df --- /dev/null +++ b/tests/drivers/clock_control/pwm_clock/src/main.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023 Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define NODELABEL DT_NODELABEL(samplenode) +static const struct device *clk_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(NODELABEL)); + +static void *pwm_clock_setup(void) +{ + int ret; + uint32_t clock_rate; + uint32_t clock_rate_dt = DT_PROP_BY_PHANDLE(NODELABEL, clocks, clock_frequency); + + zassert_equal(device_is_ready(clk_dev), true, "%s: PWM clock device is not ready", + clk_dev->name); + + ret = clock_control_get_rate(clk_dev, 0, &clock_rate); + zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_get_rate", + clk_dev->name, ret); + + zassert_equal(clock_rate_dt, clock_rate, + "%s: devicetree clock rate mismatch. Expected %dHz Fetched %dHz", + clk_dev->name, clock_rate_dt, clock_rate); + + ret = clock_control_on(clk_dev, 0); + zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_on", clk_dev->name, ret); + + return NULL; +} + +ZTEST(pwm_clock, test_clock_control_get_rate) +{ + int ret; + uint32_t clock_rate; + + ret = clock_control_get_rate(clk_dev, 0, &clock_rate); + zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_get_rate", + clk_dev->name, ret); +} + +ZTEST(pwm_clock, test_clock_control_set_rate) +{ + int ret; + uint32_t clock_rate, clock_rate_new; + + ret = clock_control_get_rate(clk_dev, 0, &clock_rate); + zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_get_rate", + clk_dev->name, ret); + + clock_rate /= 2; + + ret = clock_control_set_rate(clk_dev, 0, (clock_control_subsys_rate_t)clock_rate); + zassert_equal(0, ret, "%s: unexpected err (%d) from clock_control_set_rate", + clk_dev->name, ret); + + ret = clock_control_get_rate(clk_dev, 0, &clock_rate_new); + zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_get_rate", + clk_dev->name, ret); + + zassert_equal(clock_rate, clock_rate_new, + "%s: Clock rate mismatch. Expected %dHz Fetched %dHz", clk_dev->name, + clock_rate, clock_rate_new); +} + +ZTEST_SUITE(pwm_clock, NULL, pwm_clock_setup, NULL, NULL, NULL); diff --git a/tests/drivers/clock_control/pwm_clock/testcase.yaml b/tests/drivers/clock_control/pwm_clock/testcase.yaml new file mode 100644 index 000000000000000..0789fcf07227917 --- /dev/null +++ b/tests/drivers/clock_control/pwm_clock/testcase.yaml @@ -0,0 +1,7 @@ +tests: + drivers.clock.pwm_clock: + filter: dt_compat_enabled("pwm-clock") and dt_compat_enabled("test-clock-control-pwm-clock") + tags: + - drivers + - clock + - pwm From 524ed5dbc1610d47bf0a45e3d080fa113b6f9a60 Mon Sep 17 00:00:00 2001 From: Flavia Caforio Date: Wed, 8 Nov 2023 17:48:58 +0100 Subject: [PATCH 0610/1049] drivers: counter: nrf_timer: Add event clear to set_top_value At present, if you want to set a periodic timer again with set_top_value, the last triggered event is not cleared. This could result in an old event being served at the next interrupt activation. The solution proposed in this patch adds the nrf_timer_event_clear function into set_top_value to prevent this from happening in the above case. Signed-off-by: Flavia Caforio --- drivers/counter/counter_nrfx_timer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/counter/counter_nrfx_timer.c b/drivers/counter/counter_nrfx_timer.c index df5b617525739b1..caf2c5852e4d6d1 100644 --- a/drivers/counter/counter_nrfx_timer.c +++ b/drivers/counter/counter_nrfx_timer.c @@ -253,6 +253,7 @@ static int set_top_value(const struct device *dev, nrf_timer_int_disable(timer, COUNTER_TOP_INT_MASK); nrf_timer_cc_set(timer, TOP_CH, cfg->ticks); + nrf_timer_event_clear(timer, COUNTER_TOP_EVT); nrf_timer_shorts_enable(timer, COUNTER_OVERFLOW_SHORT); data->top_cb = cfg->callback; From c972ef1a0f82d254c9a8ff2437b73ebe368ba9c4 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 13 Nov 2023 15:12:45 -0800 Subject: [PATCH 0611/1049] kernel: mm: move kernel mm functions under kernel includes This moves the k_* memory management functions from sys/ into kernel/ includes, as there are kernel public APIs. The z_* functions are further separated into the kernel internal header directory. Also made a quick change to doxygen to group sys_mem_* into the OS Memory Management group so they will appear in doc. Signed-off-by: Daniel Leung --- MAINTAINERS.yml | 2 + arch/arm/core/mmu/arm_mmu.c | 6 +- arch/x86/core/efi.c | 2 +- arch/x86/core/ia32/crt0.S | 2 +- arch/x86/core/ia32/fatal.c | 2 +- arch/x86/core/ia32/userspace.S | 2 +- arch/x86/core/intel64/locore.S | 2 +- arch/x86/core/intel64/userspace.S | 2 +- arch/x86/core/x86_mmu.c | 2 +- arch/x86/include/x86_mmu.h | 2 +- arch/xtensa/core/mem_manage.c | 2 +- arch/xtensa/core/xtensa_mmu.c | 2 +- boards/x86/qemu_x86/qemu_x86_tiny.ld | 2 +- drivers/ethernet/eth_dwmac_mmu.c | 2 +- drivers/mm/mm_drv_intel_adsp.h | 2 +- drivers/mm/mm_drv_intel_adsp_tlb.c | 2 +- drivers/pcie/host/msi.c | 2 +- include/zephyr/arch/arm64/arm_mem.h | 2 +- include/zephyr/arch/x86/ia32/linker.ld | 2 +- include/zephyr/arch/x86/memory.ld | 2 +- include/zephyr/kernel/internal/mm.h | 214 ++++++ include/zephyr/kernel/mm.h | 528 ++++++++++++++ include/zephyr/kernel/thread.h | 2 +- include/zephyr/linker/linker-tool-gcc.h | 2 +- include/zephyr/sys/device_mmio.h | 2 +- include/zephyr/sys/mem_manage.h | 683 +----------------- kernel/CMakeLists.txt | 1 + kernel/include/mmu.h | 2 +- kernel/paging/statistics.c | 2 +- lib/libc/common/source/stdlib/malloc.c | 2 +- lib/libc/newlib/libc-hooks.c | 2 +- lib/libc/picolibc/libc-hooks.c | 2 +- tests/kernel/fatal/exception/src/main.c | 2 +- .../mem_heap/shared_multi_heap/src/main.c | 2 +- .../mem_protect/demand_paging/src/main.c | 2 +- tests/kernel/mem_protect/mem_map/src/main.c | 2 +- 36 files changed, 780 insertions(+), 714 deletions(-) create mode 100644 include/zephyr/kernel/internal/mm.h create mode 100644 include/zephyr/kernel/mm.h diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index f03d141e4756b4d..02ff92cb9f8a9f5 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3136,6 +3136,8 @@ Userspace: - scripts/build/gen_relocate_app.py - include/zephyr/sys/kobject.h - include/zephyr/sys/mem_manage.h + - include/zephyr/kernel/mm.h + - include/zephyr/kernel/internal/mm.h labels: - "area: Userspace" diff --git a/arch/arm/core/mmu/arm_mmu.c b/arch/arm/core/mmu/arm_mmu.c index 5281d265cd0efb9..77c79fdfc3d07db 100644 --- a/arch/arm/core/mmu/arm_mmu.c +++ b/arch/arm/core/mmu/arm_mmu.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -861,7 +861,7 @@ int z_arm_mmu_init(void) * @param phys 32-bit physical address. * @param size Size (in bytes) of the memory area to map. * @param flags Memory attributes & permissions. Comp. K_MEM_... - * flags in sys/mem_manage.h. + * flags in kernel/mm.h. * @retval 0 on success, -EINVAL if an invalid parameter is detected. */ static int __arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) @@ -939,7 +939,7 @@ static int __arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flag * @param phys 32-bit physical address. * @param size Size (in bytes) of the memory area to map. * @param flags Memory attributes & permissions. Comp. K_MEM_... - * flags in sys/mem_manage.h. + * flags in kernel/mm.h. */ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) { diff --git a/arch/x86/core/efi.c b/arch/x86/core/efi.c index 00bcff8d47c4bef..425b0dcde86f2fb 100644 --- a/arch/x86/core/efi.c +++ b/arch/x86/core/efi.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include "../zefi/efi.h" /* ZEFI not on include path */ #include #include diff --git a/arch/x86/core/ia32/crt0.S b/arch/x86/core/ia32/crt0.S index d42a99d5f5683cd..75a5402a4b23e4a 100644 --- a/arch/x86/core/ia32/crt0.S +++ b/arch/x86/core/ia32/crt0.S @@ -21,7 +21,7 @@ #include #include #include -#include +#include /* exports (private APIs) */ diff --git a/arch/x86/core/ia32/fatal.c b/arch/x86/core/ia32/fatal.c index 9c9ab5f3a63b6ab..38cf180e0bcd025 100644 --- a/arch/x86/core/ia32/fatal.c +++ b/arch/x86/core/ia32/fatal.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); diff --git a/arch/x86/core/ia32/userspace.S b/arch/x86/core/ia32/userspace.S index adba32c78b2d25b..bf21a0cc1a22746 100644 --- a/arch/x86/core/ia32/userspace.S +++ b/arch/x86/core/ia32/userspace.S @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include /* Exports */ diff --git a/arch/x86/core/intel64/locore.S b/arch/x86/core/intel64/locore.S index f69545cc64ac7e7..dd541921742a78e 100644 --- a/arch/x86/core/intel64/locore.S +++ b/arch/x86/core/intel64/locore.S @@ -13,7 +13,7 @@ #include #include #include -#include +#include /* * Definitions/macros for enabling paging diff --git a/arch/x86/core/intel64/userspace.S b/arch/x86/core/intel64/userspace.S index 747c6183c3ccbce..ab09381c7af9cc7 100644 --- a/arch/x86/core/intel64/userspace.S +++ b/arch/x86/core/intel64/userspace.S @@ -8,7 +8,7 @@ #include #include #include -#include +#include #ifdef CONFIG_X86_KPTI /* Copy interrupt return stack context to the trampoline stack, switch back diff --git a/arch/x86/core/x86_mmu.c b/arch/x86/core/x86_mmu.c index 119179b72ae8efa..71aafe5cad9b978 100644 --- a/arch/x86/core/x86_mmu.c +++ b/arch/x86/core/x86_mmu.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/include/x86_mmu.h b/arch/x86/include/x86_mmu.h index 14c5b053c6513c1..b5b319a64e41a90 100644 --- a/arch/x86/include/x86_mmu.h +++ b/arch/x86/include/x86_mmu.h @@ -14,7 +14,7 @@ #include #include -#include +#include #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) #define XD_SUPPORTED diff --git a/arch/xtensa/core/mem_manage.c b/arch/xtensa/core/mem_manage.c index ee2d162c835d1a0..e43bf4b75d6dfba 100644 --- a/arch/xtensa/core/mem_manage.c +++ b/arch/xtensa/core/mem_manage.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include __weak bool sys_mm_is_phys_addr_in_range(uintptr_t phys) { diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index c84d01b8337abbb..e50c51a3848f55b 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/boards/x86/qemu_x86/qemu_x86_tiny.ld b/boards/x86/qemu_x86/qemu_x86_tiny.ld index c53e2a7b409804f..44e8ff853583cf5 100644 --- a/boards/x86/qemu_x86/qemu_x86_tiny.ld +++ b/boards/x86/qemu_x86/qemu_x86_tiny.ld @@ -10,7 +10,7 @@ #include #include #include -#include +#include /* Bounds of physical RAM from DTS */ diff --git a/drivers/ethernet/eth_dwmac_mmu.c b/drivers/ethernet/eth_dwmac_mmu.c index 38e8a99c4356e6e..b78fbbc035d6bbb 100644 --- a/drivers/ethernet/eth_dwmac_mmu.c +++ b/drivers/ethernet/eth_dwmac_mmu.c @@ -15,7 +15,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define DT_DRV_COMPAT snps_designware_ethernet #include -#include +#include #include #include #include diff --git a/drivers/mm/mm_drv_intel_adsp.h b/drivers/mm/mm_drv_intel_adsp.h index b62e7ceb27db499..8de9ccc42cab62a 100644 --- a/drivers/mm/mm_drv_intel_adsp.h +++ b/drivers/mm/mm_drv_intel_adsp.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mm/mm_drv_intel_adsp_tlb.c b/drivers/mm/mm_drv_intel_adsp_tlb.c index 26d69371a2d78dd..315496be8e0041f 100644 --- a/drivers/mm/mm_drv_intel_adsp_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_tlb.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pcie/host/msi.c b/drivers/pcie/host/msi.c index fc04fdccfa13f39..f78f5b171a61a6a 100644 --- a/drivers/pcie/host/msi.c +++ b/drivers/pcie/host/msi.c @@ -38,7 +38,7 @@ static uint32_t pcie_msi_base(pcie_bdf_t bdf, bool *msi) #ifdef CONFIG_PCIE_MSI_MULTI_VECTOR -#include +#include __weak uint8_t arch_pcie_msi_vectors_allocate(unsigned int priority, msi_vector_t *vectors, diff --git a/include/zephyr/arch/arm64/arm_mem.h b/include/zephyr/arch/arm64/arm_mem.h index 23569f6c345fc7c..110f85a24caa60b 100644 --- a/include/zephyr/arch/arm64/arm_mem.h +++ b/include/zephyr/arch/arm64/arm_mem.h @@ -8,7 +8,7 @@ /* * Define ARM specific memory flags used by z_phys_map() - * followed public definitions in include/sys/mem_manage.h. + * followed public definitions in include/kernel/mm.h. */ /* For ARM64, K_MEM_CACHE_NONE is nGnRnE. */ #define K_MEM_ARM_DEVICE_nGnRnE K_MEM_CACHE_NONE diff --git a/include/zephyr/arch/x86/ia32/linker.ld b/include/zephyr/arch/x86/ia32/linker.ld index 4d3ebe03f850acd..a0e2f5c6732ebde 100644 --- a/include/zephyr/arch/x86/ia32/linker.ld +++ b/include/zephyr/arch/x86/ia32/linker.ld @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include diff --git a/include/zephyr/arch/x86/memory.ld b/include/zephyr/arch/x86/memory.ld index 8cc19fd6484ca72..72b400dd079cc7b 100644 --- a/include/zephyr/arch/x86/memory.ld +++ b/include/zephyr/arch/x86/memory.ld @@ -29,7 +29,7 @@ #include #include -#include +#include /* Bounds of physical RAM from DTS */ #define PHYS_RAM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_sram)) diff --git a/include/zephyr/kernel/internal/mm.h b/include/zephyr/kernel/internal/mm.h new file mode 100644 index 000000000000000..c859e9392349a13 --- /dev/null +++ b/include/zephyr/kernel/internal/mm.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_KERNEL_INTERNAL_MM_H +#define ZEPHYR_INCLUDE_KERNEL_INTERNAL_MM_H + +#include +#include + +/** + * @defgroup kernel_mm_internal_apis Kernel Memory Management Internal APIs + * @ingroup internal_api + * @{ + */ + +/* + * This is the offset to subtract from a virtual address mapped in the + * kernel's permanent mapping of RAM, to obtain its physical address. + * + * virt_addr = phys_addr + Z_MEM_VM_OFFSET + * + * This only works for virtual addresses within the interval + * [CONFIG_KERNEL_VM_BASE, CONFIG_KERNEL_VM_BASE + (CONFIG_SRAM_SIZE * 1024)). + * + * These macros are intended for assembly, linker code, and static initializers. + * Use with care. + * + * Note that when demand paging is active, these will only work with page + * frames that are pinned to their virtual mapping at boot. + * + * TODO: This will likely need to move to an arch API or need additional + * constraints defined. + */ +#ifdef CONFIG_MMU +#define Z_MEM_VM_OFFSET ((CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_OFFSET) - \ + (CONFIG_SRAM_BASE_ADDRESS + CONFIG_SRAM_OFFSET)) +#else +#define Z_MEM_VM_OFFSET 0 +#endif + +#define Z_MEM_PHYS_ADDR(virt) ((virt) - Z_MEM_VM_OFFSET) +#define Z_MEM_VIRT_ADDR(phys) ((phys) + Z_MEM_VM_OFFSET) + +#if Z_MEM_VM_OFFSET != 0 +#define Z_VM_KERNEL 1 +#ifdef CONFIG_XIP +#error "XIP and a virtual memory kernel are not allowed" +#endif +#endif + +#ifndef _ASMLANGUAGE +#include +#include +#include +#include + +/* Just like Z_MEM_PHYS_ADDR() but with type safety and assertions */ +static inline uintptr_t z_mem_phys_addr(void *virt) +{ + uintptr_t addr = (uintptr_t)virt; + +#if defined(CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK) + __ASSERT(sys_mm_is_virt_addr_in_range(virt), + "address %p not in permanent mappings", virt); +#elif defined(CONFIG_MMU) + __ASSERT( +#if CONFIG_KERNEL_VM_BASE != 0 + (addr >= CONFIG_KERNEL_VM_BASE) && +#endif +#if (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE) != 0 + (addr < (CONFIG_KERNEL_VM_BASE + + (CONFIG_KERNEL_VM_SIZE))), +#else + false, +#endif + "address %p not in permanent mappings", virt); +#else + /* Should be identity-mapped */ + __ASSERT( +#if CONFIG_SRAM_BASE_ADDRESS != 0 + (addr >= CONFIG_SRAM_BASE_ADDRESS) && +#endif +#if (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)) != 0 + (addr < (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024UL))), +#else + false, +#endif + "physical address 0x%lx not in RAM", + (unsigned long)addr); +#endif /* CONFIG_MMU */ + + /* TODO add assertion that this page is pinned to boot mapping, + * the above checks won't be sufficient with demand paging + */ + + return Z_MEM_PHYS_ADDR(addr); +} + +/* Just like Z_MEM_VIRT_ADDR() but with type safety and assertions */ +static inline void *z_mem_virt_addr(uintptr_t phys) +{ +#if defined(CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK) + __ASSERT(sys_mm_is_phys_addr_in_range(phys), + "physical address 0x%lx not in RAM", (unsigned long)phys); +#else + __ASSERT( +#if CONFIG_SRAM_BASE_ADDRESS != 0 + (phys >= CONFIG_SRAM_BASE_ADDRESS) && +#endif +#if (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)) != 0 + (phys < (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024UL))), +#else + false, +#endif + "physical address 0x%lx not in RAM", (unsigned long)phys); +#endif + + /* TODO add assertion that this page frame is pinned to boot mapping, + * the above check won't be sufficient with demand paging + */ + + return (void *)Z_MEM_VIRT_ADDR(phys); +} + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Map a physical memory region into the kernel's virtual address space + * + * This function is intended for mapping memory-mapped I/O regions into + * the virtual address space. Given a physical address and a size, return a + * linear address representing the base of where the physical region is mapped + * in the virtual address space for the Zephyr kernel. + * + * This function alters the active page tables in the area reserved + * for the kernel. This function will choose the virtual address + * and return it to the caller. + * + * Portable code should never assume that phys_addr and linear_addr will + * be equal. + * + * Caching and access properties are controlled by the 'flags' parameter. + * Unused bits in 'flags' are reserved for future expansion. + * A caching mode must be selected. By default, the region is read-only + * with user access and code execution forbidden. This policy is changed + * by passing K_MEM_CACHE_* and K_MEM_PERM_* macros into the 'flags' parameter. + * + * If there is insufficient virtual address space for the mapping this will + * generate a kernel panic. + * + * This API is only available if CONFIG_MMU is enabled. + * + * It is highly discouraged to use this function to map system RAM page + * frames. It may conflict with anonymous memory mappings and demand paging + * and produce undefined behavior. Do not use this for RAM unless you know + * exactly what you are doing. If you need a chunk of memory, use k_mem_map(). + * If you need a contiguous buffer of physical memory, statically declare it + * and pin it at build time, it will be mapped when the system boots. + * + * This API is part of infrastructure still under development and may + * change. + * + * @param virt [out] Output virtual address storage location + * @param phys Physical address base of the memory region + * @param size Size of the memory region + * @param flags Caching mode and access flags, see K_MAP_* macros + */ +void z_phys_map(uint8_t **virt_ptr, uintptr_t phys, size_t size, + uint32_t flags); + +/** + * Unmap a virtual memory region from kernel's virtual address space. + * + * This function is intended to be used by drivers and early boot routines + * where temporary memory mappings need to be made. This allows these + * memory mappings to be discarded once they are no longer needed. + * + * This function alters the active page tables in the area reserved + * for the kernel. + * + * This will align the input parameters to page boundaries so that + * this can be used with the virtual address as returned by + * z_phys_map(). + * + * This API is only available if CONFIG_MMU is enabled. + * + * It is highly discouraged to use this function to unmap memory mappings. + * It may conflict with anonymous memory mappings and demand paging and + * produce undefined behavior. Do not use this unless you know exactly + * what you are doing. + * + * This API is part of infrastructure still under development and may + * change. + * + * @param virt Starting address of the virtual address region to be unmapped. + * @param size Size of the virtual address region + */ +void z_phys_unmap(uint8_t *virt, size_t size); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* !_ASMLANGUAGE */ +#endif /* ZEPHYR_INCLUDE_KERNEL_INTERNAL_MM_H */ diff --git a/include/zephyr/kernel/mm.h b/include/zephyr/kernel/mm.h new file mode 100644 index 000000000000000..b277449ea3e3024 --- /dev/null +++ b/include/zephyr/kernel/mm.h @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_KERNEL_MM_H +#define ZEPHYR_INCLUDE_KERNEL_MM_H + +#include +#include +#if defined(CONFIG_ARM_MMU) && defined(CONFIG_ARM64) +#include +#endif + +#include + +/** + * @brief Kernel Memory Management + * @defgroup kernel_memory_management Kernel Memory Management + * @ingroup kernel_apis + * @{ + * @} + */ + +/* + * Caching mode definitions. These are mutually exclusive. + */ + +/** No caching. Most drivers want this. */ +#define K_MEM_CACHE_NONE 2 + +/** Write-through caching. Used by certain drivers. */ +#define K_MEM_CACHE_WT 1 + +/** Full write-back caching. Any RAM mapped wants this. */ +#define K_MEM_CACHE_WB 0 + +/* + * ARM64 Specific flags are defined in arch/arm64/arm_mem.h, + * pay attention to be not conflicted when updating these flags. + */ + +/** Reserved bits for cache modes in k_map() flags argument */ +#define K_MEM_CACHE_MASK (BIT(3) - 1) + +/* + * Region permission attributes. Default is read-only, no user, no exec + */ + +/** Region will have read/write access (and not read-only) */ +#define K_MEM_PERM_RW BIT(3) + +/** Region will be executable (normally forbidden) */ +#define K_MEM_PERM_EXEC BIT(4) + +/** Region will be accessible to user mode (normally supervisor-only) */ +#define K_MEM_PERM_USER BIT(5) + +/* + * Region mapping behaviour attributes + */ + +/** Region will be mapped to 1:1 virtual and physical address */ +#define K_MEM_DIRECT_MAP BIT(6) + +#ifndef _ASMLANGUAGE +#include +#include +#include + +struct k_mem_paging_stats_t { +#ifdef CONFIG_DEMAND_PAGING_STATS + struct { + /** Number of page faults */ + unsigned long cnt; + + /** Number of page faults with IRQ locked */ + unsigned long irq_locked; + + /** Number of page faults with IRQ unlocked */ + unsigned long irq_unlocked; + +#ifndef CONFIG_DEMAND_PAGING_ALLOW_IRQ + /** Number of page faults while in ISR */ + unsigned long in_isr; +#endif + } pagefaults; + + struct { + /** Number of clean pages selected for eviction */ + unsigned long clean; + + /** Number of dirty pages selected for eviction */ + unsigned long dirty; + } eviction; +#endif /* CONFIG_DEMAND_PAGING_STATS */ +}; + +struct k_mem_paging_histogram_t { +#ifdef CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM + /* Counts for each bin in timing histogram */ + unsigned long counts[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; + + /* Bounds for the bins in timing histogram, + * excluding the first and last (hence, NUM_SLOTS - 1). + */ + unsigned long bounds[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; +#endif /* CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * k_mem_map() control flags + */ + +/** + * @brief The mapped region is not guaranteed to be zeroed. + * + * This may improve performance. The associated page frames may contain + * indeterminate data, zeroes, or even sensitive information. + * + * This may not be used with K_MEM_PERM_USER as there are no circumstances + * where this is safe. + */ +#define K_MEM_MAP_UNINIT BIT(16) + +/** + * Region will be pinned in memory and never paged + * + * Such memory is guaranteed to never produce a page fault due to page-outs + * or copy-on-write once the mapping call has returned. Physical page frames + * will be pre-fetched as necessary and pinned. + */ +#define K_MEM_MAP_LOCK BIT(17) + +/** + * Return the amount of free memory available + * + * The returned value will reflect how many free RAM page frames are available. + * If demand paging is enabled, it may still be possible to allocate more. + * + * The information reported by this function may go stale immediately if + * concurrent memory mappings or page-ins take place. + * + * @return Free physical RAM, in bytes + */ +size_t k_mem_free_get(void); + +/** + * Map anonymous memory into Zephyr's address space + * + * This function effectively increases the data space available to Zephyr. + * The kernel will choose a base virtual address and return it to the caller. + * The memory will have access permissions for all contexts set per the + * provided flags argument. + * + * If user thread access control needs to be managed in any way, do not enable + * K_MEM_PERM_USER flags here; instead manage the region's permissions + * with memory domain APIs after the mapping has been established. Setting + * K_MEM_PERM_USER here will allow all user threads to access this memory + * which is usually undesirable. + * + * Unless K_MEM_MAP_UNINIT is used, the returned memory will be zeroed. + * + * The mapped region is not guaranteed to be physically contiguous in memory. + * Physically contiguous buffers should be allocated statically and pinned + * at build time. + * + * Pages mapped in this way have write-back cache settings. + * + * The returned virtual memory pointer will be page-aligned. The size + * parameter, and any base address for re-mapping purposes must be page- + * aligned. + * + * Note that the allocation includes two guard pages immediately before + * and after the requested region. The total size of the allocation will be + * the requested size plus the size of these two guard pages. + * + * Many K_MEM_MAP_* flags have been implemented to alter the behavior of this + * function, with details in the documentation for these flags. + * + * @param size Size of the memory mapping. This must be page-aligned. + * @param flags K_MEM_PERM_*, K_MEM_MAP_* control flags. + * @return The mapped memory location, or NULL if insufficient virtual address + * space, insufficient physical memory to establish the mapping, + * or insufficient memory for paging structures. + */ +void *k_mem_map(size_t size, uint32_t flags); + +/** + * Un-map mapped memory + * + * This removes a memory mapping for the provided page-aligned region. + * Associated page frames will be free and the kernel may re-use the associated + * virtual address region. Any paged out data pages may be discarded. + * + * Calling this function on a region which was not mapped to begin with is + * undefined behavior. + * + * @param addr Page-aligned memory region base virtual address + * @param size Page-aligned memory region size + */ +void k_mem_unmap(void *addr, size_t size); + +/** + * Given an arbitrary region, provide a aligned region that covers it + * + * The returned region will have both its base address and size aligned + * to the provided alignment value. + * + * @param aligned_addr [out] Aligned address + * @param aligned_size [out] Aligned region size + * @param addr Region base address + * @param size Region size + * @param align What to align the address and size to + * @retval offset between aligned_addr and addr + */ +size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size, + uintptr_t addr, size_t size, size_t align); + +/** + * @defgroup demand_paging Demand Paging + * @ingroup kernel_memory_management + */ +/** + * @defgroup mem-demand-paging Demand Paging APIs + * @ingroup demand_paging + * @{ + */ + +/** + * Evict a page-aligned virtual memory region to the backing store + * + * Useful if it is known that a memory region will not be used for some time. + * All the data pages within the specified region will be evicted to the + * backing store if they weren't already, with their associated page frames + * marked as available for mappings or page-ins. + * + * None of the associated page frames mapped to the provided region should + * be pinned. + * + * Note that there are no guarantees how long these pages will be evicted, + * they could take page faults immediately. + * + * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be + * called by ISRs as the backing store may be in-use. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + * @retval 0 Success + * @retval -ENOMEM Insufficient space in backing store to satisfy request. + * The region may be partially paged out. + */ +int k_mem_page_out(void *addr, size_t size); + +/** + * Load a virtual data region into memory + * + * After the function completes, all the page frames associated with this + * function will be paged in. However, they are not guaranteed to stay there. + * This is useful if the region is known to be used soon. + * + * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be + * called by ISRs as the backing store may be in-use. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + */ +void k_mem_page_in(void *addr, size_t size); + +/** + * Pin an aligned virtual data region, paging in as necessary + * + * After the function completes, all the page frames associated with this + * region will be resident in memory and pinned such that they stay that way. + * This is a stronger version of z_mem_page_in(). + * + * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be + * called by ISRs as the backing store may be in-use. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + */ +void k_mem_pin(void *addr, size_t size); + +/** + * Un-pin an aligned virtual data region + * + * After the function completes, all the page frames associated with this + * region will be no longer marked as pinned. This does not evict the region, + * follow this with z_mem_page_out() if you need that. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + */ +void k_mem_unpin(void *addr, size_t size); + +/** + * Get the paging statistics since system startup + * + * This populates the paging statistics struct being passed in + * as argument. + * + * @param[in,out] stats Paging statistics struct to be filled. + */ +__syscall void k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats); + +struct k_thread; +/** + * Get the paging statistics since system startup for a thread + * + * This populates the paging statistics struct being passed in + * as argument for a particular thread. + * + * @param[in] thread Thread + * @param[in,out] stats Paging statistics struct to be filled. + */ +__syscall +void k_mem_paging_thread_stats_get(struct k_thread *thread, + struct k_mem_paging_stats_t *stats); + +/** + * Get the eviction timing histogram + * + * This populates the timing histogram struct being passed in + * as argument. + * + * @param[in,out] hist Timing histogram struct to be filled. + */ +__syscall void k_mem_paging_histogram_eviction_get( + struct k_mem_paging_histogram_t *hist); + +/** + * Get the backing store page-in timing histogram + * + * This populates the timing histogram struct being passed in + * as argument. + * + * @param[in,out] hist Timing histogram struct to be filled. + */ +__syscall void k_mem_paging_histogram_backing_store_page_in_get( + struct k_mem_paging_histogram_t *hist); + +/** + * Get the backing store page-out timing histogram + * + * This populates the timing histogram struct being passed in + * as argument. + * + * @param[in,out] hist Timing histogram struct to be filled. + */ +__syscall void k_mem_paging_histogram_backing_store_page_out_get( + struct k_mem_paging_histogram_t *hist); + +#include + +/** @} */ + +/** + * Eviction algorithm APIs + * + * @defgroup mem-demand-paging-eviction Eviction Algorithm APIs + * @ingroup demand_paging + * @{ + */ + +/** + * Select a page frame for eviction + * + * The kernel will invoke this to choose a page frame to evict if there + * are no free page frames. + * + * This function will never be called before the initial + * k_mem_paging_eviction_init(). + * + * This function is invoked with interrupts locked. + * + * @param [out] dirty Whether the page to evict is dirty + * @return The page frame to evict + */ +struct z_page_frame *k_mem_paging_eviction_select(bool *dirty); + +/** + * Initialization function + * + * Called at POST_KERNEL to perform any necessary initialization tasks for the + * eviction algorithm. k_mem_paging_eviction_select() is guaranteed to never be + * called until this has returned, and this will only be called once. + */ +void k_mem_paging_eviction_init(void); + +/** @} */ + +/** + * Backing store APIs + * + * @defgroup mem-demand-paging-backing-store Backing Store APIs + * @ingroup demand_paging + * @{ + */ + +/** + * Reserve or fetch a storage location for a data page loaded into a page frame + * + * The returned location token must be unique to the mapped virtual address. + * This location will be used in the backing store to page out data page + * contents for later retrieval. The location value must be page-aligned. + * + * This function may be called multiple times on the same data page. If its + * page frame has its Z_PAGE_FRAME_BACKED bit set, it is expected to return + * the previous backing store location for the data page containing a cached + * clean copy. This clean copy may be updated on page-out, or used to + * discard clean pages without needing to write out their contents. + * + * If the backing store is full, some other backing store location which caches + * a loaded data page may be selected, in which case its associated page frame + * will have the Z_PAGE_FRAME_BACKED bit cleared (as it is no longer cached). + * + * pf->addr will indicate the virtual address the page is currently mapped to. + * Large, sparse backing stores which can contain the entire address space + * may simply generate location tokens purely as a function of pf->addr with no + * other management necessary. + * + * This function distinguishes whether it was called on behalf of a page + * fault. A free backing store location must always be reserved in order for + * page faults to succeed. If the page_fault parameter is not set, this + * function should return -ENOMEM even if one location is available. + * + * This function is invoked with interrupts locked. + * + * @param pf Virtual address to obtain a storage location + * @param [out] location storage location token + * @param page_fault Whether this request was for a page fault + * @return 0 Success + * @return -ENOMEM Backing store is full + */ +int k_mem_paging_backing_store_location_get(struct z_page_frame *pf, + uintptr_t *location, + bool page_fault); + +/** + * Free a backing store location + * + * Any stored data may be discarded, and the location token associated with + * this address may be re-used for some other data page. + * + * This function is invoked with interrupts locked. + * + * @param location Location token to free + */ +void k_mem_paging_backing_store_location_free(uintptr_t location); + +/** + * Copy a data page from Z_SCRATCH_PAGE to the specified location + * + * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write + * to the intended source page frame for the calling context. + * + * Calls to this and k_mem_paging_backing_store_page_in() will always be + * serialized, but interrupts may be enabled. + * + * @param location Location token for the data page, for later retrieval + */ +void k_mem_paging_backing_store_page_out(uintptr_t location); + +/** + * Copy a data page from the provided location to Z_SCRATCH_PAGE. + * + * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write + * to the intended destination page frame for the calling context. + * + * Calls to this and k_mem_paging_backing_store_page_out() will always be + * serialized, but interrupts may be enabled. + * + * @param location Location token for the data page + */ +void k_mem_paging_backing_store_page_in(uintptr_t location); + +/** + * Update internal accounting after a page-in + * + * This is invoked after k_mem_paging_backing_store_page_in() and interrupts + * have been* re-locked, making it safe to access the z_page_frame data. + * The location value will be the same passed to + * k_mem_paging_backing_store_page_in(). + * + * The primary use-case for this is to update custom fields for the backing + * store in the page frame, to reflect where the data should be evicted to + * if it is paged out again. This may be a no-op in some implementations. + * + * If the backing store caches paged-in data pages, this is the appropriate + * time to set the Z_PAGE_FRAME_BACKED bit. The kernel only skips paging + * out clean data pages if they are noted as clean in the page tables and the + * Z_PAGE_FRAME_BACKED bit is set in their associated page frame. + * + * @param pf Page frame that was loaded in + * @param location Location of where the loaded data page was retrieved + */ +void k_mem_paging_backing_store_page_finalize(struct z_page_frame *pf, + uintptr_t location); + +/** + * Backing store initialization function. + * + * The implementation may expect to receive page in/out calls as soon as this + * returns, but not before that. Called at POST_KERNEL. + * + * This function is expected to do two things: + * - Initialize any internal data structures and accounting for the backing + * store. + * - If the backing store already contains all or some loaded kernel data pages + * at boot time, Z_PAGE_FRAME_BACKED should be appropriately set for their + * associated page frames, and any internal accounting set up appropriately. + */ +void k_mem_paging_backing_store_init(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_ASMLANGUAGE */ +#endif /* ZEPHYR_INCLUDE_KERNEL_MM_H */ diff --git a/include/zephyr/kernel/thread.h b/include/zephyr/kernel/thread.h index 20d88bba2501fbb..b152dfb909aef30 100644 --- a/include/zephyr/kernel/thread.h +++ b/include/zephyr/kernel/thread.h @@ -8,7 +8,7 @@ #define ZEPHYR_INCLUDE_KERNEL_THREAD_H_ #ifdef CONFIG_DEMAND_PAGING_THREAD_STATS -#include +#include #endif #include diff --git a/include/zephyr/linker/linker-tool-gcc.h b/include/zephyr/linker/linker-tool-gcc.h index e5364b5a3d93c6e..ab8a3ad7f9aaa95 100644 --- a/include/zephyr/linker/linker-tool-gcc.h +++ b/include/zephyr/linker/linker-tool-gcc.h @@ -15,7 +15,7 @@ #ifndef ZEPHYR_INCLUDE_LINKER_LINKER_TOOL_GCC_H_ #define ZEPHYR_INCLUDE_LINKER_LINKER_TOOL_GCC_H_ -#include +#include #if defined(CONFIG_ARM) #if defined(CONFIG_BIG_ENDIAN) diff --git a/include/zephyr/sys/device_mmio.h b/include/zephyr/sys/device_mmio.h index 4aee3c3013121e8..c50a12782eef22a 100644 --- a/include/zephyr/sys/device_mmio.h +++ b/include/zephyr/sys/device_mmio.h @@ -45,7 +45,7 @@ #ifndef _ASMLANGUAGE #include #include -#include +#include #include #ifdef DEVICE_MMIO_IS_IN_RAM diff --git a/include/zephyr/sys/mem_manage.h b/include/zephyr/sys/mem_manage.h index 2e150110f7d592e..850a1376eafaea5 100644 --- a/include/zephyr/sys/mem_manage.h +++ b/include/zephyr/sys/mem_manage.h @@ -7,141 +7,18 @@ #ifndef ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H #define ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H -#include -#include -#if defined(CONFIG_ARM_MMU) && defined(CONFIG_ARM64) -#include -#endif +#include /** * @brief Memory Management * @defgroup memory_management Memory Management * @ingroup os_services * @{ - * @} */ -/* - * Caching mode definitions. These are mutually exclusive. - */ - -/** No caching. Most drivers want this. */ -#define K_MEM_CACHE_NONE 2 - -/** Write-through caching. Used by certain drivers. */ -#define K_MEM_CACHE_WT 1 - -/** Full write-back caching. Any RAM mapped wants this. */ -#define K_MEM_CACHE_WB 0 - -/* - * ARM64 Specific flags are defined in arch/arm64/arm_mem.h, - * pay attention to be not conflicted when updating these flags. - */ - -/** Reserved bits for cache modes in k_map() flags argument */ -#define K_MEM_CACHE_MASK (BIT(3) - 1) - -/* - * Region permission attributes. Default is read-only, no user, no exec - */ - -/** Region will have read/write access (and not read-only) */ -#define K_MEM_PERM_RW BIT(3) - -/** Region will be executable (normally forbidden) */ -#define K_MEM_PERM_EXEC BIT(4) - -/** Region will be accessible to user mode (normally supervisor-only) */ -#define K_MEM_PERM_USER BIT(5) - -/* - * Region mapping behaviour attributes - */ - -/** Region will be mapped to 1:1 virtual and physical address */ -#define K_MEM_DIRECT_MAP BIT(6) - -/* - * This is the offset to subtract from a virtual address mapped in the - * kernel's permanent mapping of RAM, to obtain its physical address. - * - * virt_addr = phys_addr + Z_MEM_VM_OFFSET - * - * This only works for virtual addresses within the interval - * [CONFIG_KERNEL_VM_BASE, CONFIG_KERNEL_VM_BASE + (CONFIG_SRAM_SIZE * 1024)). - * - * These macros are intended for assembly, linker code, and static initializers. - * Use with care. - * - * Note that when demand paging is active, these will only work with page - * frames that are pinned to their virtual mapping at boot. - * - * TODO: This will likely need to move to an arch API or need additional - * constraints defined. - */ -#ifdef CONFIG_MMU -#define Z_MEM_VM_OFFSET ((CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_OFFSET) - \ - (CONFIG_SRAM_BASE_ADDRESS + CONFIG_SRAM_OFFSET)) -#else -#define Z_MEM_VM_OFFSET 0 -#endif - -#define Z_MEM_PHYS_ADDR(virt) ((virt) - Z_MEM_VM_OFFSET) -#define Z_MEM_VIRT_ADDR(phys) ((phys) + Z_MEM_VM_OFFSET) - -#if Z_MEM_VM_OFFSET != 0 -#define Z_VM_KERNEL 1 -#ifdef CONFIG_XIP -#error "XIP and a virtual memory kernel are not allowed" -#endif -#endif - #ifndef _ASMLANGUAGE +#include #include -#include -#include -#include - -struct k_mem_paging_stats_t { -#ifdef CONFIG_DEMAND_PAGING_STATS - struct { - /** Number of page faults */ - unsigned long cnt; - - /** Number of page faults with IRQ locked */ - unsigned long irq_locked; - - /** Number of page faults with IRQ unlocked */ - unsigned long irq_unlocked; - -#ifndef CONFIG_DEMAND_PAGING_ALLOW_IRQ - /** Number of page faults while in ISR */ - unsigned long in_isr; -#endif - } pagefaults; - - struct { - /** Number of clean pages selected for eviction */ - unsigned long clean; - - /** Number of dirty pages selected for eviction */ - unsigned long dirty; - } eviction; -#endif /* CONFIG_DEMAND_PAGING_STATS */ -}; - -struct k_mem_paging_histogram_t { -#ifdef CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM - /* Counts for each bin in timing histogram */ - unsigned long counts[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; - - /* Bounds for the bins in timing histogram, - * excluding the first and last (hence, NUM_SLOTS - 1). - */ - unsigned long bounds[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; -#endif /* CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM */ -}; /** * @brief Check if a physical address is within range of physical memory. @@ -181,563 +58,7 @@ bool sys_mm_is_phys_addr_in_range(uintptr_t phys); */ bool sys_mm_is_virt_addr_in_range(void *virt); -/* Just like Z_MEM_PHYS_ADDR() but with type safety and assertions */ -static inline uintptr_t z_mem_phys_addr(void *virt) -{ - uintptr_t addr = (uintptr_t)virt; - -#if defined(CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK) - __ASSERT(sys_mm_is_virt_addr_in_range(virt), - "address %p not in permanent mappings", virt); -#elif defined(CONFIG_MMU) - __ASSERT( -#if CONFIG_KERNEL_VM_BASE != 0 - (addr >= CONFIG_KERNEL_VM_BASE) && -#endif -#if (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE) != 0 - (addr < (CONFIG_KERNEL_VM_BASE + - (CONFIG_KERNEL_VM_SIZE))), -#else - false, -#endif - "address %p not in permanent mappings", virt); -#else - /* Should be identity-mapped */ - __ASSERT( -#if CONFIG_SRAM_BASE_ADDRESS != 0 - (addr >= CONFIG_SRAM_BASE_ADDRESS) && -#endif -#if (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)) != 0 - (addr < (CONFIG_SRAM_BASE_ADDRESS + - (CONFIG_SRAM_SIZE * 1024UL))), -#else - false, -#endif - "physical address 0x%lx not in RAM", - (unsigned long)addr); -#endif /* CONFIG_MMU */ - - /* TODO add assertion that this page is pinned to boot mapping, - * the above checks won't be sufficient with demand paging - */ - - return Z_MEM_PHYS_ADDR(addr); -} - -/* Just like Z_MEM_VIRT_ADDR() but with type safety and assertions */ -static inline void *z_mem_virt_addr(uintptr_t phys) -{ -#if defined(CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK) - __ASSERT(sys_mm_is_phys_addr_in_range(phys), - "physical address 0x%lx not in RAM", (unsigned long)phys); -#else - __ASSERT( -#if CONFIG_SRAM_BASE_ADDRESS != 0 - (phys >= CONFIG_SRAM_BASE_ADDRESS) && -#endif -#if (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)) != 0 - (phys < (CONFIG_SRAM_BASE_ADDRESS + - (CONFIG_SRAM_SIZE * 1024UL))), -#else - false, -#endif - "physical address 0x%lx not in RAM", (unsigned long)phys); -#endif - - /* TODO add assertion that this page frame is pinned to boot mapping, - * the above check won't be sufficient with demand paging - */ - - return (void *)Z_MEM_VIRT_ADDR(phys); -} - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Map a physical memory region into the kernel's virtual address space - * - * This function is intended for mapping memory-mapped I/O regions into - * the virtual address space. Given a physical address and a size, return a - * linear address representing the base of where the physical region is mapped - * in the virtual address space for the Zephyr kernel. - * - * This function alters the active page tables in the area reserved - * for the kernel. This function will choose the virtual address - * and return it to the caller. - * - * Portable code should never assume that phys_addr and linear_addr will - * be equal. - * - * Caching and access properties are controlled by the 'flags' parameter. - * Unused bits in 'flags' are reserved for future expansion. - * A caching mode must be selected. By default, the region is read-only - * with user access and code execution forbidden. This policy is changed - * by passing K_MEM_CACHE_* and K_MEM_PERM_* macros into the 'flags' parameter. - * - * If there is insufficient virtual address space for the mapping this will - * generate a kernel panic. - * - * This API is only available if CONFIG_MMU is enabled. - * - * It is highly discouraged to use this function to map system RAM page - * frames. It may conflict with anonymous memory mappings and demand paging - * and produce undefined behavior. Do not use this for RAM unless you know - * exactly what you are doing. If you need a chunk of memory, use k_mem_map(). - * If you need a contiguous buffer of physical memory, statically declare it - * and pin it at build time, it will be mapped when the system boots. - * - * This API is part of infrastructure still under development and may - * change. - * - * @param virt [out] Output virtual address storage location - * @param phys Physical address base of the memory region - * @param size Size of the memory region - * @param flags Caching mode and access flags, see K_MAP_* macros - */ -void z_phys_map(uint8_t **virt_ptr, uintptr_t phys, size_t size, - uint32_t flags); - -/** - * Unmap a virtual memory region from kernel's virtual address space. - * - * This function is intended to be used by drivers and early boot routines - * where temporary memory mappings need to be made. This allows these - * memory mappings to be discarded once they are no longer needed. - * - * This function alters the active page tables in the area reserved - * for the kernel. - * - * This will align the input parameters to page boundaries so that - * this can be used with the virtual address as returned by - * z_phys_map(). - * - * This API is only available if CONFIG_MMU is enabled. - * - * It is highly discouraged to use this function to unmap memory mappings. - * It may conflict with anonymous memory mappings and demand paging and - * produce undefined behavior. Do not use this unless you know exactly - * what you are doing. - * - * This API is part of infrastructure still under development and may - * change. - * - * @param virt Starting address of the virtual address region to be unmapped. - * @param size Size of the virtual address region - */ -void z_phys_unmap(uint8_t *virt, size_t size); - -/* - * k_mem_map() control flags - */ - -/** - * @brief The mapped region is not guaranteed to be zeroed. - * - * This may improve performance. The associated page frames may contain - * indeterminate data, zeroes, or even sensitive information. - * - * This may not be used with K_MEM_PERM_USER as there are no circumstances - * where this is safe. - */ -#define K_MEM_MAP_UNINIT BIT(16) - -/** - * Region will be pinned in memory and never paged - * - * Such memory is guaranteed to never produce a page fault due to page-outs - * or copy-on-write once the mapping call has returned. Physical page frames - * will be pre-fetched as necessary and pinned. - */ -#define K_MEM_MAP_LOCK BIT(17) - -/** - * Return the amount of free memory available - * - * The returned value will reflect how many free RAM page frames are available. - * If demand paging is enabled, it may still be possible to allocate more. - * - * The information reported by this function may go stale immediately if - * concurrent memory mappings or page-ins take place. - * - * @return Free physical RAM, in bytes - */ -size_t k_mem_free_get(void); - -/** - * Map anonymous memory into Zephyr's address space - * - * This function effectively increases the data space available to Zephyr. - * The kernel will choose a base virtual address and return it to the caller. - * The memory will have access permissions for all contexts set per the - * provided flags argument. - * - * If user thread access control needs to be managed in any way, do not enable - * K_MEM_PERM_USER flags here; instead manage the region's permissions - * with memory domain APIs after the mapping has been established. Setting - * K_MEM_PERM_USER here will allow all user threads to access this memory - * which is usually undesirable. - * - * Unless K_MEM_MAP_UNINIT is used, the returned memory will be zeroed. - * - * The mapped region is not guaranteed to be physically contiguous in memory. - * Physically contiguous buffers should be allocated statically and pinned - * at build time. - * - * Pages mapped in this way have write-back cache settings. - * - * The returned virtual memory pointer will be page-aligned. The size - * parameter, and any base address for re-mapping purposes must be page- - * aligned. - * - * Note that the allocation includes two guard pages immediately before - * and after the requested region. The total size of the allocation will be - * the requested size plus the size of these two guard pages. - * - * Many K_MEM_MAP_* flags have been implemented to alter the behavior of this - * function, with details in the documentation for these flags. - * - * @param size Size of the memory mapping. This must be page-aligned. - * @param flags K_MEM_PERM_*, K_MEM_MAP_* control flags. - * @return The mapped memory location, or NULL if insufficient virtual address - * space, insufficient physical memory to establish the mapping, - * or insufficient memory for paging structures. - */ -void *k_mem_map(size_t size, uint32_t flags); - -/** - * Un-map mapped memory - * - * This removes a memory mapping for the provided page-aligned region. - * Associated page frames will be free and the kernel may re-use the associated - * virtual address region. Any paged out data pages may be discarded. - * - * Calling this function on a region which was not mapped to begin with is - * undefined behavior. - * - * @param addr Page-aligned memory region base virtual address - * @param size Page-aligned memory region size - */ -void k_mem_unmap(void *addr, size_t size); - -/** - * Given an arbitrary region, provide a aligned region that covers it - * - * The returned region will have both its base address and size aligned - * to the provided alignment value. - * - * @param aligned_addr [out] Aligned address - * @param aligned_size [out] Aligned region size - * @param addr Region base address - * @param size Region size - * @param align What to align the address and size to - * @retval offset between aligned_addr and addr - */ -size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size, - uintptr_t addr, size_t size, size_t align); - -/** - * @defgroup demand_paging Demand Paging - * @ingroup memory_management - */ -/** - * @defgroup mem-demand-paging Demand Paging APIs - * @ingroup demand_paging - * @{ - */ - -/** - * Evict a page-aligned virtual memory region to the backing store - * - * Useful if it is known that a memory region will not be used for some time. - * All the data pages within the specified region will be evicted to the - * backing store if they weren't already, with their associated page frames - * marked as available for mappings or page-ins. - * - * None of the associated page frames mapped to the provided region should - * be pinned. - * - * Note that there are no guarantees how long these pages will be evicted, - * they could take page faults immediately. - * - * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be - * called by ISRs as the backing store may be in-use. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - * @retval 0 Success - * @retval -ENOMEM Insufficient space in backing store to satisfy request. - * The region may be partially paged out. - */ -int k_mem_page_out(void *addr, size_t size); - -/** - * Load a virtual data region into memory - * - * After the function completes, all the page frames associated with this - * function will be paged in. However, they are not guaranteed to stay there. - * This is useful if the region is known to be used soon. - * - * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be - * called by ISRs as the backing store may be in-use. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - */ -void k_mem_page_in(void *addr, size_t size); - -/** - * Pin an aligned virtual data region, paging in as necessary - * - * After the function completes, all the page frames associated with this - * region will be resident in memory and pinned such that they stay that way. - * This is a stronger version of z_mem_page_in(). - * - * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be - * called by ISRs as the backing store may be in-use. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - */ -void k_mem_pin(void *addr, size_t size); - -/** - * Un-pin an aligned virtual data region - * - * After the function completes, all the page frames associated with this - * region will be no longer marked as pinned. This does not evict the region, - * follow this with z_mem_page_out() if you need that. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - */ -void k_mem_unpin(void *addr, size_t size); - -/** - * Get the paging statistics since system startup - * - * This populates the paging statistics struct being passed in - * as argument. - * - * @param[in,out] stats Paging statistics struct to be filled. - */ -__syscall void k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats); - -struct k_thread; -/** - * Get the paging statistics since system startup for a thread - * - * This populates the paging statistics struct being passed in - * as argument for a particular thread. - * - * @param[in] thread Thread - * @param[in,out] stats Paging statistics struct to be filled. - */ -__syscall -void k_mem_paging_thread_stats_get(struct k_thread *thread, - struct k_mem_paging_stats_t *stats); - -/** - * Get the eviction timing histogram - * - * This populates the timing histogram struct being passed in - * as argument. - * - * @param[in,out] hist Timing histogram struct to be filled. - */ -__syscall void k_mem_paging_histogram_eviction_get( - struct k_mem_paging_histogram_t *hist); - -/** - * Get the backing store page-in timing histogram - * - * This populates the timing histogram struct being passed in - * as argument. - * - * @param[in,out] hist Timing histogram struct to be filled. - */ -__syscall void k_mem_paging_histogram_backing_store_page_in_get( - struct k_mem_paging_histogram_t *hist); - -/** - * Get the backing store page-out timing histogram - * - * This populates the timing histogram struct being passed in - * as argument. - * - * @param[in,out] hist Timing histogram struct to be filled. - */ -__syscall void k_mem_paging_histogram_backing_store_page_out_get( - struct k_mem_paging_histogram_t *hist); - -#include - -/** @} */ - -/** - * Eviction algorithm APIs - * - * @defgroup mem-demand-paging-eviction Eviction Algorithm APIs - * @ingroup demand_paging - * @{ - */ - -/** - * Select a page frame for eviction - * - * The kernel will invoke this to choose a page frame to evict if there - * are no free page frames. - * - * This function will never be called before the initial - * k_mem_paging_eviction_init(). - * - * This function is invoked with interrupts locked. - * - * @param [out] dirty Whether the page to evict is dirty - * @return The page frame to evict - */ -struct z_page_frame *k_mem_paging_eviction_select(bool *dirty); - -/** - * Initialization function - * - * Called at POST_KERNEL to perform any necessary initialization tasks for the - * eviction algorithm. k_mem_paging_eviction_select() is guaranteed to never be - * called until this has returned, and this will only be called once. - */ -void k_mem_paging_eviction_init(void); - -/** @} */ - -/** - * Backing store APIs - * - * @defgroup mem-demand-paging-backing-store Backing Store APIs - * @ingroup demand_paging - * @{ - */ - -/** - * Reserve or fetch a storage location for a data page loaded into a page frame - * - * The returned location token must be unique to the mapped virtual address. - * This location will be used in the backing store to page out data page - * contents for later retrieval. The location value must be page-aligned. - * - * This function may be called multiple times on the same data page. If its - * page frame has its Z_PAGE_FRAME_BACKED bit set, it is expected to return - * the previous backing store location for the data page containing a cached - * clean copy. This clean copy may be updated on page-out, or used to - * discard clean pages without needing to write out their contents. - * - * If the backing store is full, some other backing store location which caches - * a loaded data page may be selected, in which case its associated page frame - * will have the Z_PAGE_FRAME_BACKED bit cleared (as it is no longer cached). - * - * pf->addr will indicate the virtual address the page is currently mapped to. - * Large, sparse backing stores which can contain the entire address space - * may simply generate location tokens purely as a function of pf->addr with no - * other management necessary. - * - * This function distinguishes whether it was called on behalf of a page - * fault. A free backing store location must always be reserved in order for - * page faults to succeed. If the page_fault parameter is not set, this - * function should return -ENOMEM even if one location is available. - * - * This function is invoked with interrupts locked. - * - * @param pf Virtual address to obtain a storage location - * @param [out] location storage location token - * @param page_fault Whether this request was for a page fault - * @return 0 Success - * @return -ENOMEM Backing store is full - */ -int k_mem_paging_backing_store_location_get(struct z_page_frame *pf, - uintptr_t *location, - bool page_fault); - -/** - * Free a backing store location - * - * Any stored data may be discarded, and the location token associated with - * this address may be re-used for some other data page. - * - * This function is invoked with interrupts locked. - * - * @param location Location token to free - */ -void k_mem_paging_backing_store_location_free(uintptr_t location); - -/** - * Copy a data page from Z_SCRATCH_PAGE to the specified location - * - * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write - * to the intended source page frame for the calling context. - * - * Calls to this and k_mem_paging_backing_store_page_in() will always be - * serialized, but interrupts may be enabled. - * - * @param location Location token for the data page, for later retrieval - */ -void k_mem_paging_backing_store_page_out(uintptr_t location); - -/** - * Copy a data page from the provided location to Z_SCRATCH_PAGE. - * - * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write - * to the intended destination page frame for the calling context. - * - * Calls to this and k_mem_paging_backing_store_page_out() will always be - * serialized, but interrupts may be enabled. - * - * @param location Location token for the data page - */ -void k_mem_paging_backing_store_page_in(uintptr_t location); - -/** - * Update internal accounting after a page-in - * - * This is invoked after k_mem_paging_backing_store_page_in() and interrupts - * have been* re-locked, making it safe to access the z_page_frame data. - * The location value will be the same passed to - * k_mem_paging_backing_store_page_in(). - * - * The primary use-case for this is to update custom fields for the backing - * store in the page frame, to reflect where the data should be evicted to - * if it is paged out again. This may be a no-op in some implementations. - * - * If the backing store caches paged-in data pages, this is the appropriate - * time to set the Z_PAGE_FRAME_BACKED bit. The kernel only skips paging - * out clean data pages if they are noted as clean in the page tables and the - * Z_PAGE_FRAME_BACKED bit is set in their associated page frame. - * - * @param pf Page frame that was loaded in - * @param location Location of where the loaded data page was retrieved - */ -void k_mem_paging_backing_store_page_finalize(struct z_page_frame *pf, - uintptr_t location); - -/** - * Backing store initialization function. - * - * The implementation may expect to receive page in/out calls as soon as this - * returns, but not before that. Called at POST_KERNEL. - * - * This function is expected to do two things: - * - Initialize any internal data structures and accounting for the backing - * store. - * - If the backing store already contains all or some loaded kernel data pages - * at boot time, Z_PAGE_FRAME_BACKED should be appropriately set for their - * associated page frames, and any internal accounting set up appropriately. - */ -void k_mem_paging_backing_store_init(void); - /** @} */ -#ifdef __cplusplus -} -#endif - #endif /* !_ASMLANGUAGE */ #endif /* ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H */ diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index e628cfec6693c6d..367b83ab04a6575 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_syscall_header_ifdef( zephyr_syscall_header_ifdef( CONFIG_MMU + ${ZEPHYR_BASE}/include/zephyr/kernel/mm.h ${ZEPHYR_BASE}/include/zephyr/sys/mem_manage.h ) diff --git a/kernel/include/mmu.h b/kernel/include/mmu.h index f51c0adeda0d688..cd290100e40cc66 100644 --- a/kernel/include/mmu.h +++ b/kernel/include/mmu.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include /* diff --git a/kernel/paging/statistics.c b/kernel/paging/statistics.c index b2f343c9fcb5956..e8972738135db68 100644 --- a/kernel/paging/statistics.c +++ b/kernel/paging/statistics.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include extern struct k_mem_paging_stats_t paging_stats; diff --git a/lib/libc/common/source/stdlib/malloc.c b/lib/libc/common/source/stdlib/malloc.c index 6762c38e92720bf..e3a5db6f7d53c76 100644 --- a/lib/libc/common/source/stdlib/malloc.c +++ b/lib/libc/common/source/stdlib/malloc.c @@ -18,7 +18,7 @@ #include #include #ifdef CONFIG_MMU -#include +#include #endif #define LOG_LEVEL CONFIG_KERNEL_LOG_LEVEL diff --git a/lib/libc/newlib/libc-hooks.c b/lib/libc/newlib/libc-hooks.c index 88a83742a50b1c3..7e066a2817f5b3b 100644 --- a/lib/libc/newlib/libc-hooks.c +++ b/lib/libc/newlib/libc-hooks.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #define LIBC_BSS K_APP_BMEM(z_libc_partition) diff --git a/lib/libc/picolibc/libc-hooks.c b/lib/libc/picolibc/libc-hooks.c index ab90ab8b047b451..d00b53d1e8ad222 100644 --- a/lib/libc/picolibc/libc-hooks.c +++ b/lib/libc/picolibc/libc-hooks.c @@ -20,7 +20,7 @@ #include #include #ifdef CONFIG_MMU -#include +#include #endif #define LIBC_BSS K_APP_BMEM(z_libc_partition) diff --git a/tests/kernel/fatal/exception/src/main.c b/tests/kernel/fatal/exception/src/main.c index 79c793ebf11e0ff..ea4ffaa7c34bbe5 100644 --- a/tests/kernel/fatal/exception/src/main.c +++ b/tests/kernel/fatal/exception/src/main.c @@ -13,7 +13,7 @@ #include #if defined(CONFIG_USERSPACE) -#include +#include #include #include "test_syscalls.h" #endif diff --git a/tests/kernel/mem_heap/shared_multi_heap/src/main.c b/tests/kernel/mem_heap/shared_multi_heap/src/main.c index bee594c56f3df15..a9883ecc1c95df7 100644 --- a/tests/kernel/mem_heap/shared_multi_heap/src/main.c +++ b/tests/kernel/mem_heap/shared_multi_heap/src/main.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/tests/kernel/mem_protect/demand_paging/src/main.c b/tests/kernel/mem_protect/demand_paging/src/main.c index ed90e0fbe97b490..a453c06a573a0db 100644 --- a/tests/kernel/mem_protect/demand_paging/src/main.c +++ b/tests/kernel/mem_protect/demand_paging/src/main.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include diff --git a/tests/kernel/mem_protect/mem_map/src/main.c b/tests/kernel/mem_protect/mem_map/src/main.c index 6db32356440b144..45ca0aa1cf37ecc 100644 --- a/tests/kernel/mem_protect/mem_map/src/main.c +++ b/tests/kernel/mem_protect/mem_map/src/main.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include From f12d49d7efa88e0ac116f7c79646dc2ecc0135fa Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 13 Nov 2023 17:59:14 -0800 Subject: [PATCH 0612/1049] kernel: mm: separate demand paging headers into its own file This separates demand paging related headers into its own file instead of being stuffed inside the main kernel memory management header file. Signed-off-by: Daniel Leung --- MAINTAINERS.yml | 1 + include/zephyr/kernel/mm.h | 339 +-------------------- include/zephyr/kernel/mm/demand_paging.h | 369 +++++++++++++++++++++++ kernel/CMakeLists.txt | 5 + 4 files changed, 376 insertions(+), 338 deletions(-) create mode 100644 include/zephyr/kernel/mm/demand_paging.h diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 02ff92cb9f8a9f5..b57181967501c33 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3138,6 +3138,7 @@ Userspace: - include/zephyr/sys/mem_manage.h - include/zephyr/kernel/mm.h - include/zephyr/kernel/internal/mm.h + - include/zephyr/kernel/mm/demand_paging.h labels: - "area: Userspace" diff --git a/include/zephyr/kernel/mm.h b/include/zephyr/kernel/mm.h index b277449ea3e3024..1056857c4fd852b 100644 --- a/include/zephyr/kernel/mm.h +++ b/include/zephyr/kernel/mm.h @@ -14,6 +14,7 @@ #endif #include +#include /** * @brief Kernel Memory Management @@ -69,46 +70,6 @@ #include #include -struct k_mem_paging_stats_t { -#ifdef CONFIG_DEMAND_PAGING_STATS - struct { - /** Number of page faults */ - unsigned long cnt; - - /** Number of page faults with IRQ locked */ - unsigned long irq_locked; - - /** Number of page faults with IRQ unlocked */ - unsigned long irq_unlocked; - -#ifndef CONFIG_DEMAND_PAGING_ALLOW_IRQ - /** Number of page faults while in ISR */ - unsigned long in_isr; -#endif - } pagefaults; - - struct { - /** Number of clean pages selected for eviction */ - unsigned long clean; - - /** Number of dirty pages selected for eviction */ - unsigned long dirty; - } eviction; -#endif /* CONFIG_DEMAND_PAGING_STATS */ -}; - -struct k_mem_paging_histogram_t { -#ifdef CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM - /* Counts for each bin in timing histogram */ - unsigned long counts[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; - - /* Bounds for the bins in timing histogram, - * excluding the first and last (hence, NUM_SLOTS - 1). - */ - unsigned long bounds[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; -#endif /* CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM */ -}; - #ifdef __cplusplus extern "C" { #endif @@ -222,304 +183,6 @@ void k_mem_unmap(void *addr, size_t size); size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size, uintptr_t addr, size_t size, size_t align); -/** - * @defgroup demand_paging Demand Paging - * @ingroup kernel_memory_management - */ -/** - * @defgroup mem-demand-paging Demand Paging APIs - * @ingroup demand_paging - * @{ - */ - -/** - * Evict a page-aligned virtual memory region to the backing store - * - * Useful if it is known that a memory region will not be used for some time. - * All the data pages within the specified region will be evicted to the - * backing store if they weren't already, with their associated page frames - * marked as available for mappings or page-ins. - * - * None of the associated page frames mapped to the provided region should - * be pinned. - * - * Note that there are no guarantees how long these pages will be evicted, - * they could take page faults immediately. - * - * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be - * called by ISRs as the backing store may be in-use. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - * @retval 0 Success - * @retval -ENOMEM Insufficient space in backing store to satisfy request. - * The region may be partially paged out. - */ -int k_mem_page_out(void *addr, size_t size); - -/** - * Load a virtual data region into memory - * - * After the function completes, all the page frames associated with this - * function will be paged in. However, they are not guaranteed to stay there. - * This is useful if the region is known to be used soon. - * - * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be - * called by ISRs as the backing store may be in-use. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - */ -void k_mem_page_in(void *addr, size_t size); - -/** - * Pin an aligned virtual data region, paging in as necessary - * - * After the function completes, all the page frames associated with this - * region will be resident in memory and pinned such that they stay that way. - * This is a stronger version of z_mem_page_in(). - * - * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be - * called by ISRs as the backing store may be in-use. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - */ -void k_mem_pin(void *addr, size_t size); - -/** - * Un-pin an aligned virtual data region - * - * After the function completes, all the page frames associated with this - * region will be no longer marked as pinned. This does not evict the region, - * follow this with z_mem_page_out() if you need that. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - */ -void k_mem_unpin(void *addr, size_t size); - -/** - * Get the paging statistics since system startup - * - * This populates the paging statistics struct being passed in - * as argument. - * - * @param[in,out] stats Paging statistics struct to be filled. - */ -__syscall void k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats); - -struct k_thread; -/** - * Get the paging statistics since system startup for a thread - * - * This populates the paging statistics struct being passed in - * as argument for a particular thread. - * - * @param[in] thread Thread - * @param[in,out] stats Paging statistics struct to be filled. - */ -__syscall -void k_mem_paging_thread_stats_get(struct k_thread *thread, - struct k_mem_paging_stats_t *stats); - -/** - * Get the eviction timing histogram - * - * This populates the timing histogram struct being passed in - * as argument. - * - * @param[in,out] hist Timing histogram struct to be filled. - */ -__syscall void k_mem_paging_histogram_eviction_get( - struct k_mem_paging_histogram_t *hist); - -/** - * Get the backing store page-in timing histogram - * - * This populates the timing histogram struct being passed in - * as argument. - * - * @param[in,out] hist Timing histogram struct to be filled. - */ -__syscall void k_mem_paging_histogram_backing_store_page_in_get( - struct k_mem_paging_histogram_t *hist); - -/** - * Get the backing store page-out timing histogram - * - * This populates the timing histogram struct being passed in - * as argument. - * - * @param[in,out] hist Timing histogram struct to be filled. - */ -__syscall void k_mem_paging_histogram_backing_store_page_out_get( - struct k_mem_paging_histogram_t *hist); - -#include - -/** @} */ - -/** - * Eviction algorithm APIs - * - * @defgroup mem-demand-paging-eviction Eviction Algorithm APIs - * @ingroup demand_paging - * @{ - */ - -/** - * Select a page frame for eviction - * - * The kernel will invoke this to choose a page frame to evict if there - * are no free page frames. - * - * This function will never be called before the initial - * k_mem_paging_eviction_init(). - * - * This function is invoked with interrupts locked. - * - * @param [out] dirty Whether the page to evict is dirty - * @return The page frame to evict - */ -struct z_page_frame *k_mem_paging_eviction_select(bool *dirty); - -/** - * Initialization function - * - * Called at POST_KERNEL to perform any necessary initialization tasks for the - * eviction algorithm. k_mem_paging_eviction_select() is guaranteed to never be - * called until this has returned, and this will only be called once. - */ -void k_mem_paging_eviction_init(void); - -/** @} */ - -/** - * Backing store APIs - * - * @defgroup mem-demand-paging-backing-store Backing Store APIs - * @ingroup demand_paging - * @{ - */ - -/** - * Reserve or fetch a storage location for a data page loaded into a page frame - * - * The returned location token must be unique to the mapped virtual address. - * This location will be used in the backing store to page out data page - * contents for later retrieval. The location value must be page-aligned. - * - * This function may be called multiple times on the same data page. If its - * page frame has its Z_PAGE_FRAME_BACKED bit set, it is expected to return - * the previous backing store location for the data page containing a cached - * clean copy. This clean copy may be updated on page-out, or used to - * discard clean pages without needing to write out their contents. - * - * If the backing store is full, some other backing store location which caches - * a loaded data page may be selected, in which case its associated page frame - * will have the Z_PAGE_FRAME_BACKED bit cleared (as it is no longer cached). - * - * pf->addr will indicate the virtual address the page is currently mapped to. - * Large, sparse backing stores which can contain the entire address space - * may simply generate location tokens purely as a function of pf->addr with no - * other management necessary. - * - * This function distinguishes whether it was called on behalf of a page - * fault. A free backing store location must always be reserved in order for - * page faults to succeed. If the page_fault parameter is not set, this - * function should return -ENOMEM even if one location is available. - * - * This function is invoked with interrupts locked. - * - * @param pf Virtual address to obtain a storage location - * @param [out] location storage location token - * @param page_fault Whether this request was for a page fault - * @return 0 Success - * @return -ENOMEM Backing store is full - */ -int k_mem_paging_backing_store_location_get(struct z_page_frame *pf, - uintptr_t *location, - bool page_fault); - -/** - * Free a backing store location - * - * Any stored data may be discarded, and the location token associated with - * this address may be re-used for some other data page. - * - * This function is invoked with interrupts locked. - * - * @param location Location token to free - */ -void k_mem_paging_backing_store_location_free(uintptr_t location); - -/** - * Copy a data page from Z_SCRATCH_PAGE to the specified location - * - * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write - * to the intended source page frame for the calling context. - * - * Calls to this and k_mem_paging_backing_store_page_in() will always be - * serialized, but interrupts may be enabled. - * - * @param location Location token for the data page, for later retrieval - */ -void k_mem_paging_backing_store_page_out(uintptr_t location); - -/** - * Copy a data page from the provided location to Z_SCRATCH_PAGE. - * - * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write - * to the intended destination page frame for the calling context. - * - * Calls to this and k_mem_paging_backing_store_page_out() will always be - * serialized, but interrupts may be enabled. - * - * @param location Location token for the data page - */ -void k_mem_paging_backing_store_page_in(uintptr_t location); - -/** - * Update internal accounting after a page-in - * - * This is invoked after k_mem_paging_backing_store_page_in() and interrupts - * have been* re-locked, making it safe to access the z_page_frame data. - * The location value will be the same passed to - * k_mem_paging_backing_store_page_in(). - * - * The primary use-case for this is to update custom fields for the backing - * store in the page frame, to reflect where the data should be evicted to - * if it is paged out again. This may be a no-op in some implementations. - * - * If the backing store caches paged-in data pages, this is the appropriate - * time to set the Z_PAGE_FRAME_BACKED bit. The kernel only skips paging - * out clean data pages if they are noted as clean in the page tables and the - * Z_PAGE_FRAME_BACKED bit is set in their associated page frame. - * - * @param pf Page frame that was loaded in - * @param location Location of where the loaded data page was retrieved - */ -void k_mem_paging_backing_store_page_finalize(struct z_page_frame *pf, - uintptr_t location); - -/** - * Backing store initialization function. - * - * The implementation may expect to receive page in/out calls as soon as this - * returns, but not before that. Called at POST_KERNEL. - * - * This function is expected to do two things: - * - Initialize any internal data structures and accounting for the backing - * store. - * - If the backing store already contains all or some loaded kernel data pages - * at boot time, Z_PAGE_FRAME_BACKED should be appropriately set for their - * associated page frames, and any internal accounting set up appropriately. - */ -void k_mem_paging_backing_store_init(void); - -/** @} */ - #ifdef __cplusplus } #endif diff --git a/include/zephyr/kernel/mm/demand_paging.h b/include/zephyr/kernel/mm/demand_paging.h new file mode 100644 index 000000000000000..fb20a2c734f0a7a --- /dev/null +++ b/include/zephyr/kernel/mm/demand_paging.h @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_KERNEL_MM_DEMAND_PAGING_H +#define ZEPHYR_INCLUDE_KERNEL_MM_DEMAND_PAGING_H + +#include + +#include +#include + +/** + * @defgroup demand_paging Demand Paging + * @ingroup kernel_memory_management + */ + +/** + * @defgroup mem-demand-paging Demand Paging APIs + * @ingroup demand_paging + * @{ + */ + +#ifndef _ASMLANGUAGE +#include +#include +#include +#include + +struct k_mem_paging_stats_t { +#ifdef CONFIG_DEMAND_PAGING_STATS + struct { + /** Number of page faults */ + unsigned long cnt; + + /** Number of page faults with IRQ locked */ + unsigned long irq_locked; + + /** Number of page faults with IRQ unlocked */ + unsigned long irq_unlocked; + +#ifndef CONFIG_DEMAND_PAGING_ALLOW_IRQ + /** Number of page faults while in ISR */ + unsigned long in_isr; +#endif + } pagefaults; + + struct { + /** Number of clean pages selected for eviction */ + unsigned long clean; + + /** Number of dirty pages selected for eviction */ + unsigned long dirty; + } eviction; +#endif /* CONFIG_DEMAND_PAGING_STATS */ +}; + +struct k_mem_paging_histogram_t { +#ifdef CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM + /* Counts for each bin in timing histogram */ + unsigned long counts[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; + + /* Bounds for the bins in timing histogram, + * excluding the first and last (hence, NUM_SLOTS - 1). + */ + unsigned long bounds[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; +#endif /* CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Evict a page-aligned virtual memory region to the backing store + * + * Useful if it is known that a memory region will not be used for some time. + * All the data pages within the specified region will be evicted to the + * backing store if they weren't already, with their associated page frames + * marked as available for mappings or page-ins. + * + * None of the associated page frames mapped to the provided region should + * be pinned. + * + * Note that there are no guarantees how long these pages will be evicted, + * they could take page faults immediately. + * + * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be + * called by ISRs as the backing store may be in-use. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + * @retval 0 Success + * @retval -ENOMEM Insufficient space in backing store to satisfy request. + * The region may be partially paged out. + */ +int k_mem_page_out(void *addr, size_t size); + +/** + * Load a virtual data region into memory + * + * After the function completes, all the page frames associated with this + * function will be paged in. However, they are not guaranteed to stay there. + * This is useful if the region is known to be used soon. + * + * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be + * called by ISRs as the backing store may be in-use. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + */ +void k_mem_page_in(void *addr, size_t size); + +/** + * Pin an aligned virtual data region, paging in as necessary + * + * After the function completes, all the page frames associated with this + * region will be resident in memory and pinned such that they stay that way. + * This is a stronger version of z_mem_page_in(). + * + * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be + * called by ISRs as the backing store may be in-use. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + */ +void k_mem_pin(void *addr, size_t size); + +/** + * Un-pin an aligned virtual data region + * + * After the function completes, all the page frames associated with this + * region will be no longer marked as pinned. This does not evict the region, + * follow this with z_mem_page_out() if you need that. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + */ +void k_mem_unpin(void *addr, size_t size); + +/** + * Get the paging statistics since system startup + * + * This populates the paging statistics struct being passed in + * as argument. + * + * @param[in,out] stats Paging statistics struct to be filled. + */ +__syscall void k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats); + +struct k_thread; +/** + * Get the paging statistics since system startup for a thread + * + * This populates the paging statistics struct being passed in + * as argument for a particular thread. + * + * @param[in] thread Thread + * @param[in,out] stats Paging statistics struct to be filled. + */ +__syscall +void k_mem_paging_thread_stats_get(struct k_thread *thread, + struct k_mem_paging_stats_t *stats); + +/** + * Get the eviction timing histogram + * + * This populates the timing histogram struct being passed in + * as argument. + * + * @param[in,out] hist Timing histogram struct to be filled. + */ +__syscall void k_mem_paging_histogram_eviction_get( + struct k_mem_paging_histogram_t *hist); + +/** + * Get the backing store page-in timing histogram + * + * This populates the timing histogram struct being passed in + * as argument. + * + * @param[in,out] hist Timing histogram struct to be filled. + */ +__syscall void k_mem_paging_histogram_backing_store_page_in_get( + struct k_mem_paging_histogram_t *hist); + +/** + * Get the backing store page-out timing histogram + * + * This populates the timing histogram struct being passed in + * as argument. + * + * @param[in,out] hist Timing histogram struct to be filled. + */ +__syscall void k_mem_paging_histogram_backing_store_page_out_get( + struct k_mem_paging_histogram_t *hist); + +#include + +/** @} */ + +/** + * Eviction algorithm APIs + * + * @defgroup mem-demand-paging-eviction Eviction Algorithm APIs + * @ingroup demand_paging + * @{ + */ + +/** + * Select a page frame for eviction + * + * The kernel will invoke this to choose a page frame to evict if there + * are no free page frames. + * + * This function will never be called before the initial + * k_mem_paging_eviction_init(). + * + * This function is invoked with interrupts locked. + * + * @param [out] dirty Whether the page to evict is dirty + * @return The page frame to evict + */ +struct z_page_frame *k_mem_paging_eviction_select(bool *dirty); + +/** + * Initialization function + * + * Called at POST_KERNEL to perform any necessary initialization tasks for the + * eviction algorithm. k_mem_paging_eviction_select() is guaranteed to never be + * called until this has returned, and this will only be called once. + */ +void k_mem_paging_eviction_init(void); + +/** @} */ + +/** + * Backing store APIs + * + * @defgroup mem-demand-paging-backing-store Backing Store APIs + * @ingroup demand_paging + * @{ + */ + +/** + * Reserve or fetch a storage location for a data page loaded into a page frame + * + * The returned location token must be unique to the mapped virtual address. + * This location will be used in the backing store to page out data page + * contents for later retrieval. The location value must be page-aligned. + * + * This function may be called multiple times on the same data page. If its + * page frame has its Z_PAGE_FRAME_BACKED bit set, it is expected to return + * the previous backing store location for the data page containing a cached + * clean copy. This clean copy may be updated on page-out, or used to + * discard clean pages without needing to write out their contents. + * + * If the backing store is full, some other backing store location which caches + * a loaded data page may be selected, in which case its associated page frame + * will have the Z_PAGE_FRAME_BACKED bit cleared (as it is no longer cached). + * + * pf->addr will indicate the virtual address the page is currently mapped to. + * Large, sparse backing stores which can contain the entire address space + * may simply generate location tokens purely as a function of pf->addr with no + * other management necessary. + * + * This function distinguishes whether it was called on behalf of a page + * fault. A free backing store location must always be reserved in order for + * page faults to succeed. If the page_fault parameter is not set, this + * function should return -ENOMEM even if one location is available. + * + * This function is invoked with interrupts locked. + * + * @param pf Virtual address to obtain a storage location + * @param [out] location storage location token + * @param page_fault Whether this request was for a page fault + * @return 0 Success + * @return -ENOMEM Backing store is full + */ +int k_mem_paging_backing_store_location_get(struct z_page_frame *pf, + uintptr_t *location, + bool page_fault); + +/** + * Free a backing store location + * + * Any stored data may be discarded, and the location token associated with + * this address may be re-used for some other data page. + * + * This function is invoked with interrupts locked. + * + * @param location Location token to free + */ +void k_mem_paging_backing_store_location_free(uintptr_t location); + +/** + * Copy a data page from Z_SCRATCH_PAGE to the specified location + * + * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write + * to the intended source page frame for the calling context. + * + * Calls to this and k_mem_paging_backing_store_page_in() will always be + * serialized, but interrupts may be enabled. + * + * @param location Location token for the data page, for later retrieval + */ +void k_mem_paging_backing_store_page_out(uintptr_t location); + +/** + * Copy a data page from the provided location to Z_SCRATCH_PAGE. + * + * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write + * to the intended destination page frame for the calling context. + * + * Calls to this and k_mem_paging_backing_store_page_out() will always be + * serialized, but interrupts may be enabled. + * + * @param location Location token for the data page + */ +void k_mem_paging_backing_store_page_in(uintptr_t location); + +/** + * Update internal accounting after a page-in + * + * This is invoked after k_mem_paging_backing_store_page_in() and interrupts + * have been* re-locked, making it safe to access the z_page_frame data. + * The location value will be the same passed to + * k_mem_paging_backing_store_page_in(). + * + * The primary use-case for this is to update custom fields for the backing + * store in the page frame, to reflect where the data should be evicted to + * if it is paged out again. This may be a no-op in some implementations. + * + * If the backing store caches paged-in data pages, this is the appropriate + * time to set the Z_PAGE_FRAME_BACKED bit. The kernel only skips paging + * out clean data pages if they are noted as clean in the page tables and the + * Z_PAGE_FRAME_BACKED bit is set in their associated page frame. + * + * @param pf Page frame that was loaded in + * @param location Location of where the loaded data page was retrieved + */ +void k_mem_paging_backing_store_page_finalize(struct z_page_frame *pf, + uintptr_t location); + +/** + * Backing store initialization function. + * + * The implementation may expect to receive page in/out calls as soon as this + * returns, but not before that. Called at POST_KERNEL. + * + * This function is expected to do two things: + * - Initialize any internal data structures and accounting for the backing + * store. + * - If the backing store already contains all or some loaded kernel data pages + * at boot time, Z_PAGE_FRAME_BACKED should be appropriately set for their + * associated page frames, and any internal accounting set up appropriately. + */ +void k_mem_paging_backing_store_init(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_ASMLANGUAGE */ +#endif /* ZEPHYR_INCLUDE_KERNEL_MM_DEMAND_PAGING_H */ diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 367b83ab04a6575..bec410968cc3c41 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -25,6 +25,11 @@ zephyr_syscall_header_ifdef( ${ZEPHYR_BASE}/include/zephyr/sys/mem_manage.h ) +zephyr_syscall_header_ifdef( + CONFIG_DEMAND_PAGING + ${ZEPHYR_BASE}/include/zephyr/kernel/mm/demand_paging.h +) + # If a pre-built static library containing kernel code exists in # this directory, libkernel.a, link it with the application code # instead of building from source. From f52f76fd6b96472478663d498dce3562b93641e6 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 13 Nov 2023 15:49:44 -0800 Subject: [PATCH 0613/1049] doc: kernel/mm: some doxygen works () Some kernel memory management functions were previously not in any group. So put them under the kernel memory management group, and now they appear in API doc. () Group things together when appropriate. () Add doc if none exists before. Signed-off-by: Daniel Leung --- include/zephyr/kernel/mm.h | 39 ++++++++++++++++++------ include/zephyr/kernel/mm/demand_paging.h | 12 ++++++-- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/include/zephyr/kernel/mm.h b/include/zephyr/kernel/mm.h index 1056857c4fd852b..392dc4b7cdec21f 100644 --- a/include/zephyr/kernel/mm.h +++ b/include/zephyr/kernel/mm.h @@ -21,11 +21,14 @@ * @defgroup kernel_memory_management Kernel Memory Management * @ingroup kernel_apis * @{ - * @} */ -/* - * Caching mode definitions. These are mutually exclusive. +/** + * @name Caching mode definitions. + * + * These are mutually exclusive. + * + * @{ */ /** No caching. Most drivers want this. */ @@ -45,8 +48,14 @@ /** Reserved bits for cache modes in k_map() flags argument */ #define K_MEM_CACHE_MASK (BIT(3) - 1) -/* - * Region permission attributes. Default is read-only, no user, no exec +/** @} */ + +/** + * @name Region permission attributes. + * + * Default is read-only, no user, no exec + * + * @{ */ /** Region will have read/write access (and not read-only) */ @@ -58,13 +67,19 @@ /** Region will be accessible to user mode (normally supervisor-only) */ #define K_MEM_PERM_USER BIT(5) -/* - * Region mapping behaviour attributes +/** @} */ + +/** + * @name Region mapping behaviour attributes + * + * @{ */ /** Region will be mapped to 1:1 virtual and physical address */ #define K_MEM_DIRECT_MAP BIT(6) +/** @} */ + #ifndef _ASMLANGUAGE #include #include @@ -74,8 +89,10 @@ extern "C" { #endif -/* - * k_mem_map() control flags +/** + * @name k_mem_map() control flags + * + * @{ */ /** @@ -98,6 +115,8 @@ extern "C" { */ #define K_MEM_MAP_LOCK BIT(17) +/** @} */ + /** * Return the amount of free memory available * @@ -187,5 +206,7 @@ size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size, } #endif +/** @} */ + #endif /* !_ASMLANGUAGE */ #endif /* ZEPHYR_INCLUDE_KERNEL_MM_H */ diff --git a/include/zephyr/kernel/mm/demand_paging.h b/include/zephyr/kernel/mm/demand_paging.h index fb20a2c734f0a7a..10412d3a7668a98 100644 --- a/include/zephyr/kernel/mm/demand_paging.h +++ b/include/zephyr/kernel/mm/demand_paging.h @@ -29,8 +29,11 @@ #include #include +/** + * Paging Statistics. + */ struct k_mem_paging_stats_t { -#ifdef CONFIG_DEMAND_PAGING_STATS +#if defined(CONFIG_DEMAND_PAGING_STATS) || defined(__DOXYGEN__) struct { /** Number of page faults */ unsigned long cnt; @@ -41,7 +44,7 @@ struct k_mem_paging_stats_t { /** Number of page faults with IRQ unlocked */ unsigned long irq_unlocked; -#ifndef CONFIG_DEMAND_PAGING_ALLOW_IRQ +#if !defined(CONFIG_DEMAND_PAGING_ALLOW_IRQ) || defined(__DOXYGEN__) /** Number of page faults while in ISR */ unsigned long in_isr; #endif @@ -57,8 +60,11 @@ struct k_mem_paging_stats_t { #endif /* CONFIG_DEMAND_PAGING_STATS */ }; +/** + * Paging Statistics Histograms. + */ struct k_mem_paging_histogram_t { -#ifdef CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM +#if defined(CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM) || defined(__DOXYGEN__) /* Counts for each bin in timing histogram */ unsigned long counts[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; From 58152eb93803c06da250a1a2778cdbfa45776bb2 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 15 Nov 2023 09:35:06 +0100 Subject: [PATCH 0614/1049] cmake: modules: Add zephyr_library_add_dependencies extension Add a CMake zephyr library extension for add_dependencies, similar to the target_ functions. This avoids using ${ZEPHYR_CURRENT_LIBRARY} directly. Signed-off-by: Pieter De Gendt --- cmake/modules/extensions.cmake | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 061ed7747c1eafa..6bdd55433ebc478 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -528,6 +528,10 @@ function(zephyr_library_cc_option) endforeach() endfunction() +function(zephyr_library_add_dependencies) + add_dependencies(${ZEPHYR_CURRENT_LIBRARY} ${ARGN}) +endfunction() + # Add the existing CMake library 'library' to the global list of # Zephyr CMake libraries. This is done automatically by the # constructor but must be called explicitly on CMake libraries that do @@ -1819,6 +1823,12 @@ function(zephyr_linker_sources_ifdef feature_toggle) endif() endfunction() +function(zephyr_library_add_dependencies_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_library_add_dependencies(${ARGN}) + endif() +endfunction() + macro(list_append_ifdef feature_toggle list) if(${${feature_toggle}}) list(APPEND ${list} ${ARGN}) @@ -1965,6 +1975,12 @@ function(zephyr_linker_sources_ifndef feature_toggle) endif() endfunction() +function(zephyr_library_add_dependencies_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_library_add_dependencies(${ARGN}) + endif() +endfunction() + macro(list_append_ifndef feature_toggle list) if(NOT ${feature_toggle}) list(APPEND ${list} ${ARGN}) From 8f8a77abc9f99aee430ce58501a391d2c7203667 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 17 Nov 2023 09:33:44 +0100 Subject: [PATCH 0615/1049] modules: hal_rpi_pico: Use zephyr_library_add_dependencies Replace usage of add_dependencies(${ZEPHYR_CURRENT_LIBRARY} ...) Signed-off-by: Pieter De Gendt --- modules/hal_rpi_pico/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hal_rpi_pico/CMakeLists.txt b/modules/hal_rpi_pico/CMakeLists.txt index 3ae107449aeff11..3281528d73f1a4c 100644 --- a/modules/hal_rpi_pico/CMakeLists.txt +++ b/modules/hal_rpi_pico/CMakeLists.txt @@ -42,7 +42,7 @@ if(CONFIG_HAS_RPI_PICO) BUILD_ALWAYS TRUE ) - add_dependencies(${ZEPHYR_CURRENT_LIBRARY} second_stage_bootloader) + zephyr_library_add_dependencies(second_stage_bootloader) zephyr_library_sources(${rp2_bootloader_asm}) endif() From 015659322187b7ac9df9f27eace5ff2a72e8ddeb Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Fri, 17 Nov 2023 09:34:53 +0100 Subject: [PATCH 0616/1049] bindesc: Use zephyr_library_add_dependencies Replace usage of add_dependencies(${ZEPHYR_CURRENT_LIBRARY} ...) Signed-off-by: Pieter De Gendt --- subsys/bindesc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bindesc/CMakeLists.txt b/subsys/bindesc/CMakeLists.txt index 7419a78e5a9b73b..9dcb467208d923c 100644 --- a/subsys/bindesc/CMakeLists.txt +++ b/subsys/bindesc/CMakeLists.txt @@ -66,7 +66,7 @@ if(CONFIG_BINDESC_DEFINE_BUILD_TIME) bindesc_time_force_rebuild COMMAND ${CMAKE_COMMAND} ${CMAKE_BINARY_DIR} ) - add_dependencies(${ZEPHYR_CURRENT_LIBRARY} bindesc_time_force_rebuild) + zephyr_library_add_dependencies(bindesc_time_force_rebuild) endif() endif() From d7d11ef09f37449026436252c211d82f7513ee9e Mon Sep 17 00:00:00 2001 From: Natalia Pluta Date: Mon, 14 Aug 2023 11:36:56 +0200 Subject: [PATCH 0617/1049] soc: arm: nordic_nrf: Add Kconfig symbols for QDEC instances Add QDEC instances 20, 21, 130, 131 Signed-off-by: Natalia Pluta --- soc/arm/nordic_nrf/Kconfig.peripherals | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/arm/nordic_nrf/Kconfig.peripherals index d62238f1c8bc7a5..285b92d3dda6371 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/arm/nordic_nrf/Kconfig.peripherals @@ -129,6 +129,18 @@ config HAS_HW_NRF_QDEC0 config HAS_HW_NRF_QDEC1 def_bool $(dt_nodelabel_enabled_with_compat,qdec1,$(DT_COMPAT_NORDIC_NRF_QDEC)) +config HAS_HW_NRF_QDEC20 + def_bool $(dt_nodelabel_enabled_with_compat,qdec20,$(DT_COMPAT_NORDIC_NRF_QDEC)) + +config HAS_HW_NRF_QDEC21 + def_bool $(dt_nodelabel_enabled_with_compat,qdec21,$(DT_COMPAT_NORDIC_NRF_QDEC)) + +config HAS_HW_NRF_QDEC130 + def_bool $(dt_nodelabel_enabled_with_compat,qdec130,$(DT_COMPAT_NORDIC_NRF_QDEC)) + +config HAS_HW_NRF_QDEC131 + def_bool $(dt_nodelabel_enabled_with_compat,qdec131,$(DT_COMPAT_NORDIC_NRF_QDEC)) + config HAS_HW_NRF_QSPI def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_QSPI)) From f5658254e8aac7b8def932b9c1b43999731434d2 Mon Sep 17 00:00:00 2001 From: Natalia Pluta Date: Mon, 14 Aug 2023 11:29:24 +0200 Subject: [PATCH 0618/1049] modules: hal_nordic: Add QDEC Kconfig symbols and translation to nrfx Add Kconfig symbols for QDEC instances (20, 21, 130, 131) and translation symbols used in nrfx drivers. Signed-off-by: Natalia Pluta --- modules/hal_nordic/nrfx/Kconfig | 20 ++++++++++++++++++++ modules/hal_nordic/nrfx/nrfx_config.h | 12 ++++++++++++ 2 files changed, 32 insertions(+) diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index 78d9671b3c43b40..53a77e601752778 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -154,6 +154,26 @@ config NRFX_QDEC1 depends on $(dt_nodelabel_has_compat,qdec1,$(DT_COMPAT_NORDIC_NRF_QDEC)) select NRFX_QDEC +config NRFX_QDEC20 + bool "QDEC20 driver instance" + depends on $(dt_nodelabel_has_compat,qdec20,$(DT_COMPAT_NORDIC_NRF_QDEC)) + select NRFX_QDEC + +config NRFX_QDEC21 + bool "QDEC21 driver instance" + depends on $(dt_nodelabel_has_compat,qdec21,$(DT_COMPAT_NORDIC_NRF_QDEC)) + select NRFX_QDEC + +config NRFX_QDEC130 + bool "QDEC130 driver instance" + depends on $(dt_nodelabel_has_compat,qdec130,$(DT_COMPAT_NORDIC_NRF_QDEC)) + select NRFX_QDEC + +config NRFX_QDEC131 + bool "QDEC131 driver instance" + depends on $(dt_nodelabel_has_compat,qdec131,$(DT_COMPAT_NORDIC_NRF_QDEC)) + select NRFX_QDEC + config NRFX_QSPI bool "QSPI driver" depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_QSPI)) diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index 04be67a7b435cb4..f799c4207d550c5 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -244,6 +244,18 @@ #ifdef CONFIG_NRFX_QDEC1 #define NRFX_QDEC1_ENABLED 1 #endif +#ifdef CONFIG_NRFX_QDEC20 +#define NRFX_QDEC20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_QDEC21 +#define NRFX_QDEC21_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_QDEC130 +#define NRFX_QDEC130_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_QDEC131 +#define NRFX_QDEC131_ENABLED 1 +#endif #ifdef CONFIG_NRFX_QSPI #define NRFX_QSPI_ENABLED 1 From 8b2c5120aa1239bb09cddc451f0989fa8c2b5adf Mon Sep 17 00:00:00 2001 From: Natalia Pluta Date: Wed, 28 Jun 2023 11:41:07 +0200 Subject: [PATCH 0619/1049] drivers: sensor: qdec_nrfx: Add support for new QDEC instances Introducing support for new QDEC instances in the driver. Signed-off-by: Natalia Pluta --- drivers/sensor/qdec_nrfx/Kconfig | 4 ++++ drivers/sensor/qdec_nrfx/qdec_nrfx.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/sensor/qdec_nrfx/Kconfig b/drivers/sensor/qdec_nrfx/Kconfig index 64d91d6ba6f8cd4..71c3ab1d5b0d78c 100644 --- a/drivers/sensor/qdec_nrfx/Kconfig +++ b/drivers/sensor/qdec_nrfx/Kconfig @@ -7,6 +7,10 @@ config QDEC_NRFX depends on DT_HAS_NORDIC_NRF_QDEC_ENABLED select NRFX_QDEC0 if HAS_HW_NRF_QDEC0 select NRFX_QDEC1 if HAS_HW_NRF_QDEC1 + select NRFX_QDEC20 if HAS_HW_NRF_QDEC20 + select NRFX_QDEC21 if HAS_HW_NRF_QDEC21 + select NRFX_QDEC130 if HAS_HW_NRF_QDEC130 + select NRFX_QDEC131 if HAS_HW_NRF_QDEC131 select PINCTRL help Enable support for nrfx QDEC driver for nRF MCU series. diff --git a/drivers/sensor/qdec_nrfx/qdec_nrfx.c b/drivers/sensor/qdec_nrfx/qdec_nrfx.c index b11ce70fb9c342b..10035e0a1036595 100644 --- a/drivers/sensor/qdec_nrfx/qdec_nrfx.c +++ b/drivers/sensor/qdec_nrfx/qdec_nrfx.c @@ -299,3 +299,19 @@ SENSOR_NRFX_QDEC_DEVICE(0); #ifdef CONFIG_HAS_HW_NRF_QDEC1 SENSOR_NRFX_QDEC_DEVICE(1); #endif + +#ifdef CONFIG_HAS_HW_NRF_QDEC20 +SENSOR_NRFX_QDEC_DEVICE(20); +#endif + +#ifdef CONFIG_HAS_HW_NRF_QDEC21 +SENSOR_NRFX_QDEC_DEVICE(21); +#endif + +#ifdef CONFIG_HAS_HW_NRF_QDEC130 +SENSOR_NRFX_QDEC_DEVICE(130); +#endif + +#ifdef CONFIG_HAS_HW_NRF_QDEC131 +SENSOR_NRFX_QDEC_DEVICE(131); +#endif From 43a0839c6c6bc9b06c00c6175d048e7d9c28aad2 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 3 Oct 2023 11:10:34 +0300 Subject: [PATCH 0620/1049] drivers: dma: Add SOF host DMA driver This commit introduces the SOF host DMA driver. This driver is used by NXP platforms in the context of SOF's host component to copy data from the host memory to the firmware (local) memory. This is possible because NXP platforms can access the host memory directly w/o an actual DMA engine. Signed-off-by: Laurentiu Mihalcea --- drivers/dma/CMakeLists.txt | 1 + drivers/dma/Kconfig | 3 + drivers/dma/Kconfig.nxp_sof_host_dma | 34 +++ drivers/dma/dma_nxp_sof_host_dma.c | 284 +++++++++++++++++++++++++ dts/bindings/dma/nxp,sof-host-dma.yaml | 12 ++ 5 files changed, 334 insertions(+) create mode 100644 drivers/dma/Kconfig.nxp_sof_host_dma create mode 100644 drivers/dma/dma_nxp_sof_host_dma.c create mode 100644 dts/bindings/dma/nxp,sof-host-dma.yaml diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 271ddf19ff08962..e65c3726622724f 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -37,3 +37,4 @@ zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_SMARTDMA dma_mcux_smartdma.c) zephyr_library_sources_ifdef(CONFIG_DMA_ANDES_ATCDMAC300 dma_andes_atcdmac300.c) zephyr_library_sources_ifdef(CONFIG_DMA_SEDI dma_sedi.c) zephyr_library_sources_ifdef(CONFIG_DMA_SMARTBOND dma_smartbond.c) +zephyr_library_sources_ifdef(CONFIG_DMA_NXP_SOF_HOST_DMA dma_nxp_sof_host_dma.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 5a2ce5bdceda1a7..e24386558cddbc6 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -69,4 +69,7 @@ source "drivers/dma/Kconfig.andes_atcdmac300" source "drivers/dma/Kconfig.sedi" source "drivers/dma/Kconfig.smartbond" + +source "drivers/dma/Kconfig.nxp_sof_host_dma" + endif # DMA diff --git a/drivers/dma/Kconfig.nxp_sof_host_dma b/drivers/dma/Kconfig.nxp_sof_host_dma new file mode 100644 index 000000000000000..f909612f3aa302c --- /dev/null +++ b/drivers/dma/Kconfig.nxp_sof_host_dma @@ -0,0 +1,34 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config DMA_NXP_SOF_HOST_DMA + bool "NXP DMA driver used by SOF's host component" + default y + depends on DT_HAS_NXP_SOF_HOST_DMA_ENABLED + help + Enable NXP's DMA driver used by + SOF (Sound Open Firmware) host + component. Specifically, this driver + is used by the SOF host component to + perform transfers between the host + memory and firmware (local) memory, which + can be accessed without an actual + DMA engine. + +if DMA_NXP_SOF_HOST_DMA + +config DMA_NXP_SOF_HOST_DMA_ALIGN + int "Alignment (in bytes) required for memory regions passed to this driver" + default 8 + help + Use this to set the alignment (in bytes) + which shall be used by entities employing + this driver to adjust a memory region's size + and base address. Since this driver doesn't + actually have any hardware to back it up this + configuration doesn't make much sense as there's + no alignment restrictions imposed by memcpy. + Nevertheless, this is needed because this driver + needs to act as if it controls a DMA engine. + +endif # DMA_NXP_SOF_HOST_DMA diff --git a/drivers/dma/dma_nxp_sof_host_dma.c b/drivers/dma/dma_nxp_sof_host_dma.c new file mode 100644 index 000000000000000..6c03d84418ca6c9 --- /dev/null +++ b/drivers/dma/dma_nxp_sof_host_dma.c @@ -0,0 +1,284 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* used for driver binding */ +#define DT_DRV_COMPAT nxp_sof_host_dma + +/* macros used to parse DTS properties */ +#define IDENTITY_VARGS(V, ...) IDENTITY(V) + +#define _SOF_HOST_DMA_CHANNEL_INDEX_ARRAY(inst)\ + LISTIFY(DT_INST_PROP_OR(inst, dma_channels, 0), IDENTITY_VARGS, (,)) + +#define _SOF_HOST_DMA_CHANNEL_DECLARE(idx) {} + +#define SOF_HOST_DMA_CHANNELS_DECLARE(inst)\ + FOR_EACH(_SOF_HOST_DMA_CHANNEL_DECLARE,\ + (,), _SOF_HOST_DMA_CHANNEL_INDEX_ARRAY(inst)) + +LOG_MODULE_REGISTER(nxp_sof_host_dma); + +/* note: This driver doesn't attempt to provide + * a generic software-based DMA engine implementation. + * As its name suggests, its only usage is in SOF + * (Sound Open Firmware) for NXP plaforms which are + * able to access the host memory directly from the + * core on which the firmware is running. + */ + +enum channel_state { + CHAN_STATE_INIT = 0, + CHAN_STATE_CONFIGURED, +}; + +struct sof_host_dma_channel { + uint32_t src; + uint32_t dest; + uint32_t size; + uint32_t direction; + enum channel_state state; +}; + +struct sof_host_dma_data { + /* this needs to be first */ + struct dma_context ctx; + atomic_t channel_flags; + struct sof_host_dma_channel *channels; +}; + +static int channel_change_state(struct sof_host_dma_channel *chan, + enum channel_state next) +{ + enum channel_state prev = chan->state; + + /* validate transition */ + switch (prev) { + case CHAN_STATE_INIT: + case CHAN_STATE_CONFIGURED: + if (next != CHAN_STATE_CONFIGURED) { + return -EPERM; + } + break; + default: + LOG_ERR("invalid channel previous state: %d", prev); + return -EINVAL; + } + + chan->state = next; + + return 0; +} + +static int sof_host_dma_reload(const struct device *dev, uint32_t chan_id, + uint32_t src, uint32_t dst, size_t size) +{ + ARG_UNUSED(src); + ARG_UNUSED(dst); + ARG_UNUSED(size); + + struct sof_host_dma_data *data; + struct sof_host_dma_channel *chan; + int ret; + + data = dev->data; + + if (chan_id >= data->ctx.dma_channels) { + LOG_ERR("channel %d is not a valid channel ID", chan_id); + return -EINVAL; + } + + /* fetch channel data */ + chan = &data->channels[chan_id]; + + /* validate state */ + if (chan->state != CHAN_STATE_CONFIGURED) { + LOG_ERR("attempting to reload unconfigured DMA channel %d", chan_id); + return -EINVAL; + } + + if (chan->direction == HOST_TO_MEMORY) { + /* the host may have modified the region we're about to copy + * to local memory. In this case, the data cache holds stale + * data so invalidate it to force a read from the main memory. + */ + ret = sys_cache_data_invd_range(UINT_TO_POINTER(chan->src), + chan->size); + if (ret < 0) { + LOG_ERR("failed to invalidate data cache range"); + return ret; + } + } + + memcpy(UINT_TO_POINTER(chan->dest), UINT_TO_POINTER(chan->src), chan->size); + + if (chan->direction == MEMORY_TO_HOST) { + /* force range to main memory so that host doesn't read any + * stale data. + */ + ret = sys_cache_data_flush_range(UINT_TO_POINTER(chan->dest), + chan->size); + if (ret < 0) { + LOG_ERR("failed to flush data cache range"); + return ret; + } + } + + return 0; +} + + +static int sof_host_dma_config(const struct device *dev, uint32_t chan_id, + struct dma_config *config) +{ + struct sof_host_dma_data *data; + struct sof_host_dma_channel *chan; + int ret; + + data = dev->data; + + if (chan_id >= data->ctx.dma_channels) { + LOG_ERR("channel %d is not a valid channel ID", chan_id); + return -EINVAL; + } + + /* fetch channel data */ + chan = &data->channels[chan_id]; + + /* attempt a state transition */ + ret = channel_change_state(chan, CHAN_STATE_CONFIGURED); + if (ret < 0) { + LOG_ERR("failed to change channel %d's state to CONFIGURED", chan_id); + return ret; + } + + /* SG configurations are not currently supported */ + if (config->block_count != 1) { + LOG_ERR("invalid number of blocks: %d", config->block_count); + return -EINVAL; + } + + if (!config->head_block->source_address) { + LOG_ERR("got NULL source address"); + return -EINVAL; + } + + if (!config->head_block->dest_address) { + LOG_ERR("got NULL destination address"); + return -EINVAL; + } + + if (!config->head_block->block_size) { + LOG_ERR("got 0 bytes to copy"); + return -EINVAL; + } + + /* for now, only H2M and M2H transfers are supported */ + if (config->channel_direction != HOST_TO_MEMORY && + config->channel_direction != MEMORY_TO_HOST) { + LOG_ERR("invalid channel direction: %d", + config->channel_direction); + return -EINVAL; + } + + /* latch onto the passed configuration */ + chan->src = config->head_block->source_address; + chan->dest = config->head_block->dest_address; + chan->size = config->head_block->block_size; + chan->direction = config->channel_direction; + + LOG_DBG("configured channel %d with SRC 0x%x DST 0x%x SIZE 0x%x", + chan_id, chan->src, chan->dest, chan->size); + + return 0; +} + +static int sof_host_dma_start(const struct device *dev, uint32_t chan_id) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_stop(const struct device *dev, uint32_t chan_id) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_suspend(const struct device *dev, uint32_t chan_id) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_resume(const struct device *dev, uint32_t chan_id) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_get_status(const struct device *dev, + uint32_t chan_id, struct dma_status *stat) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_get_attribute(const struct device *dev, uint32_t type, uint32_t *val) +{ + switch (type) { + case DMA_ATTR_COPY_ALIGNMENT: + case DMA_ATTR_BUFFER_SIZE_ALIGNMENT: + case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: + *val = CONFIG_DMA_NXP_SOF_HOST_DMA_ALIGN; + break; + default: + LOG_ERR("invalid attribute type: %d", type); + return -EINVAL; + } + + return 0; +} + +static const struct dma_driver_api sof_host_dma_api = { + .reload = sof_host_dma_reload, + .config = sof_host_dma_config, + .start = sof_host_dma_start, + .stop = sof_host_dma_stop, + .suspend = sof_host_dma_suspend, + .resume = sof_host_dma_resume, + .get_status = sof_host_dma_get_status, + .get_attribute = sof_host_dma_get_attribute, +}; + +static int sof_host_dma_init(const struct device *dev) +{ + struct sof_host_dma_data *data = dev->data; + + data->channel_flags = ATOMIC_INIT(0); + data->ctx.atomic = &data->channel_flags; + + return 0; +} + +static struct sof_host_dma_channel channels[] = { + SOF_HOST_DMA_CHANNELS_DECLARE(0), +}; + +static struct sof_host_dma_data sof_host_dma_data = { + .ctx.magic = DMA_MAGIC, + .ctx.dma_channels = ARRAY_SIZE(channels), + .channels = channels, +}; + +/* assumption: only 1 SOF_HOST_DMA instance */ +DEVICE_DT_INST_DEFINE(0, sof_host_dma_init, NULL, + &sof_host_dma_data, NULL, + PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, + &sof_host_dma_api); diff --git a/dts/bindings/dma/nxp,sof-host-dma.yaml b/dts/bindings/dma/nxp,sof-host-dma.yaml new file mode 100644 index 000000000000000..ebb03c46d8bf0fc --- /dev/null +++ b/dts/bindings/dma/nxp,sof-host-dma.yaml @@ -0,0 +1,12 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP SOF host DMA node + +compatible: "nxp,sof-host-dma" + +include: [base.yaml, dma-controller.yaml] + +properties: + dma-channels: + required: true From 3ef34ff6d1c60df8a620b8e9e453b1f8ee931a32 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Thu, 16 Nov 2023 16:17:50 +0100 Subject: [PATCH 0621/1049] drivers: intc: plic: Make function names and types consistent `get_claim_complete_offset` and `get_threshold_priority_offset` actually return addresses directly. Rename them to `_addr` for consistency within the driver. Also change their return type to `mem_addr_t`. Signed-off-by: Piotr Wojnarowski --- drivers/interrupt_controller/intc_plic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 41ee75823b044ca..fa11faca91e8b3d 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -71,14 +71,14 @@ static inline uint32_t get_plic_enabled_size(const struct device *dev) return local_irq_to_reg_offset(config->num_irqs) + 1; } -static inline uint32_t get_claim_complete_offset(const struct device *dev) +static inline mem_addr_t get_claim_complete_addr(const struct device *dev) { const struct plic_config *config = dev->config; return config->reg + PLIC_REG_REGS_CLAIM_COMPLETE_OFFSET; } -static inline uint32_t get_threshold_priority_offset(const struct device *dev) +static inline mem_addr_t get_threshold_priority_addr(const struct device *dev) { const struct plic_config *config = dev->config; @@ -240,7 +240,7 @@ const struct device *riscv_plic_get_dev(void) static void plic_irq_handler(const struct device *dev) { const struct plic_config *config = dev->config; - mem_addr_t claim_complete_addr = get_claim_complete_offset(dev); + mem_addr_t claim_complete_addr = get_claim_complete_addr(dev); struct _isr_table_entry *ite; int edge_irq; @@ -305,7 +305,7 @@ static int plic_init(const struct device *dev) const struct plic_config *config = dev->config; mem_addr_t en_addr = config->irq_en; mem_addr_t prio_addr = config->prio; - mem_addr_t thres_prio_addr = get_threshold_priority_offset(dev); + mem_addr_t thres_prio_addr = get_threshold_priority_addr(dev); /* Ensure that all interrupts are disabled initially */ for (uint32_t i = 0; i < get_plic_enabled_size(dev); i++) { From 3afe238926affaed74f6fab4fc964d1e68fc4eef Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Thu, 16 Nov 2023 16:18:11 +0100 Subject: [PATCH 0622/1049] drivers: intc: plic: Fix memory-mapped register offset calculation Previously, the PLIC's registers were accessed through uint32_t *, so all calculated offsets were effectively multiplied by sizeof(uint32_t). Do the same manuallly now that we have mem_addr_t/sys_read32. Signed-off-by: Piotr Wojnarowski --- drivers/interrupt_controller/intc_plic.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index fa11faca91e8b3d..20422f23433ded4 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -59,16 +59,21 @@ struct plic_config { static uint32_t save_irq; static const struct device *save_dev; -static inline uint32_t local_irq_to_reg_offset(uint32_t local_irq) +static inline uint32_t local_irq_to_reg_index(uint32_t local_irq) { return local_irq >> LOG2(PLIC_REG_SIZE); } +static inline uint32_t local_irq_to_reg_offset(uint32_t local_irq) +{ + return local_irq_to_reg_index(local_irq) * sizeof(uint32_t); +} + static inline uint32_t get_plic_enabled_size(const struct device *dev) { const struct plic_config *config = dev->config; - return local_irq_to_reg_offset(config->num_irqs) + 1; + return local_irq_to_reg_index(config->num_irqs) + 1; } static inline mem_addr_t get_claim_complete_addr(const struct device *dev) From 6670dbe8348b6eb50be1c28cb9712bfd5908ffe3 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Fri, 17 Nov 2023 15:36:44 +0100 Subject: [PATCH 0623/1049] tests: drivers: intc_plic: Add tests for register index and offset Add a test to verify that the regression from ffb8f31bffd39b3a21e99e31deb7555d0585d81c is fixed. Signed-off-by: Piotr Wojnarowski --- drivers/interrupt_controller/intc_plic.c | 10 ++++-- .../intc_plic/CMakeLists.txt | 8 +++++ .../interrupt_controller/intc_plic/Kconfig | 10 ++++++ .../interrupt_controller/intc_plic/prj.conf | 1 + .../interrupt_controller/intc_plic/src/main.c | 31 +++++++++++++++++++ .../intc_plic/testcase.yaml | 7 +++++ 6 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 tests/drivers/interrupt_controller/intc_plic/CMakeLists.txt create mode 100644 tests/drivers/interrupt_controller/intc_plic/Kconfig create mode 100644 tests/drivers/interrupt_controller/intc_plic/prj.conf create mode 100644 tests/drivers/interrupt_controller/intc_plic/src/main.c create mode 100644 tests/drivers/interrupt_controller/intc_plic/testcase.yaml diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 20422f23433ded4..51ce17693969335 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -45,6 +45,12 @@ #define PLIC_REG_SIZE 32 #define PLIC_REG_MASK BIT_MASK(LOG2(PLIC_REG_SIZE)) +#ifdef CONFIG_TEST_INTC_PLIC +#define INTC_PLIC_STATIC +#else +#define INTC_PLIC_STATIC static inline +#endif + typedef void (*riscv_plic_irq_config_func_t)(void); struct plic_config { mem_addr_t prio; @@ -59,12 +65,12 @@ struct plic_config { static uint32_t save_irq; static const struct device *save_dev; -static inline uint32_t local_irq_to_reg_index(uint32_t local_irq) +INTC_PLIC_STATIC uint32_t local_irq_to_reg_index(uint32_t local_irq) { return local_irq >> LOG2(PLIC_REG_SIZE); } -static inline uint32_t local_irq_to_reg_offset(uint32_t local_irq) +INTC_PLIC_STATIC uint32_t local_irq_to_reg_offset(uint32_t local_irq) { return local_irq_to_reg_index(local_irq) * sizeof(uint32_t); } diff --git a/tests/drivers/interrupt_controller/intc_plic/CMakeLists.txt b/tests/drivers/interrupt_controller/intc_plic/CMakeLists.txt new file mode 100644 index 000000000000000..59fd0a3bb2f73db --- /dev/null +++ b/tests/drivers/interrupt_controller/intc_plic/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(intc_plic) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/interrupt_controller/intc_plic/Kconfig b/tests/drivers/interrupt_controller/intc_plic/Kconfig new file mode 100644 index 000000000000000..53ccc57348211ac --- /dev/null +++ b/tests/drivers/interrupt_controller/intc_plic/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config TEST_INTC_PLIC + bool + default y + help + Declare some intc_plic.c functions in the global scope for verification. + +source "Kconfig" diff --git a/tests/drivers/interrupt_controller/intc_plic/prj.conf b/tests/drivers/interrupt_controller/intc_plic/prj.conf new file mode 100644 index 000000000000000..9467c2926896dd7 --- /dev/null +++ b/tests/drivers/interrupt_controller/intc_plic/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/tests/drivers/interrupt_controller/intc_plic/src/main.c b/tests/drivers/interrupt_controller/intc_plic/src/main.c new file mode 100644 index 000000000000000..631e0e8915a3735 --- /dev/null +++ b/tests/drivers/interrupt_controller/intc_plic/src/main.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +uint32_t local_irq_to_reg_index(uint32_t local_irq); +uint32_t local_irq_to_reg_offset(uint32_t local_irq); + +ZTEST_SUITE(intc_plic, NULL, NULL, NULL, NULL, NULL); + +/* Test calculating the register index from a local IRQ number */ +ZTEST(intc_plic, test_local_irq_to_reg_index) +{ + zassert_equal(0, local_irq_to_reg_index(0x1f)); + zassert_equal(1, local_irq_to_reg_index(0x20)); + zassert_equal(1, local_irq_to_reg_index(0x3f)); + zassert_equal(2, local_irq_to_reg_index(0x40)); +} + +/* Test calculating the register offset from a local IRQ number */ +ZTEST(intc_plic, test_local_irq_to_reg_offset) +{ + zassert_equal(0, local_irq_to_reg_offset(0x1f)); + zassert_equal(4, local_irq_to_reg_offset(0x20)); + zassert_equal(4, local_irq_to_reg_offset(0x3f)); + zassert_equal(8, local_irq_to_reg_offset(0x40)); +} diff --git a/tests/drivers/interrupt_controller/intc_plic/testcase.yaml b/tests/drivers/interrupt_controller/intc_plic/testcase.yaml new file mode 100644 index 000000000000000..11c1f74fa39a32b --- /dev/null +++ b/tests/drivers/interrupt_controller/intc_plic/testcase.yaml @@ -0,0 +1,7 @@ +tests: + drivers.interrupt_controller.intc_plic: + tags: + - drivers + - interrupt + - plic + platform_allow: qemu_riscv64 From 07ae06f8feb8d66b63d9df630aedc0149b917aba Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Thu, 16 Nov 2023 12:46:47 +0200 Subject: [PATCH 0624/1049] mgmt: mcumgr: Doxygen tags update Added a missing defgroup and ingroup for mcmumgr client and smp client. Signed-off-by: Juha Heiskanen --- .../zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h | 11 +++++++++++ .../zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h | 11 +++++++++++ include/zephyr/mgmt/mcumgr/smp/smp_client.h | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h index 8cede40d64e1f93..61e12afb16492ac 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h @@ -11,6 +11,13 @@ #include #include +/** + * @brief MCUmgr Image management client API + * @defgroup mcumgr_img_mgmt_client MCUmgr img_mgmt_client API + * @ingroup mcumgr + * @{ + */ + #ifdef __cplusplus extern "C" { #endif @@ -186,6 +193,10 @@ int img_mgmt_client_state_read(struct img_mgmt_client *client, struct mcumgr_ima int img_mgmt_client_erase(struct img_mgmt_client *client, uint32_t slot); +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h index 12e8abde246c18c..0b12ccdb6840bee 100644 --- a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h +++ b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h @@ -10,6 +10,13 @@ #include #include +/** + * @brief MCUmgr OS management client API + * @defgroup mcumgr_os_mgmt_client MCUmgr os_mgmt_client API + * @ingroup mcumgr + * @{ + */ + #ifdef __cplusplus extern "C" { #endif @@ -54,6 +61,10 @@ int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string); */ int os_mgmt_client_reset(struct os_mgmt_client *client); +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/mcumgr/smp/smp_client.h b/include/zephyr/mgmt/mcumgr/smp/smp_client.h index 88b2af701b09f4d..2e0eee2cfe66645 100644 --- a/include/zephyr/mgmt/mcumgr/smp/smp_client.h +++ b/include/zephyr/mgmt/mcumgr/smp/smp_client.h @@ -13,6 +13,13 @@ #include #include +/** + * @brief MCUmgr SMP client API + * @defgroup mcumgr_smp_client SMP client API + * @ingroup mcumgr + * @{ + */ + /** * @brief SMP client object */ @@ -102,6 +109,10 @@ void smp_client_buf_free(struct net_buf *nb); int smp_client_send_cmd(struct smp_client_object *smp_client, struct net_buf *nb, smp_client_res_fn cb, void *user_data, int timeout_in_sec); +/** + * @} + */ + #ifdef __cplusplus } #endif From 1d6d24b6effa22bd750b2704801910cd57692395 Mon Sep 17 00:00:00 2001 From: Benjamin Lindqvist Date: Thu, 16 Nov 2023 11:14:07 +0100 Subject: [PATCH 0625/1049] net: lwm2m: don't load credentials on plaintext context Since lwm2m_load_tls_credentials(ctx) will assume that the ctx has a valid security object assigned to it, it should not be called at all when ctx.use_dtls == false. This solves a major bug where LwM2M comms are DTLS encrypted but FOTA is allowed to be plain-text. Signed-off-by: Benjamin Lindqvist --- subsys/net/lib/lwm2m/lwm2m_engine.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 8fceecf93351c94..45d3822bdbb2152 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1073,13 +1073,15 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx) int ret; #if defined(CONFIG_LWM2M_DTLS_SUPPORT) - if (client_ctx->load_credentials) { - ret = client_ctx->load_credentials(client_ctx); - } else { - ret = lwm2m_load_tls_credentials(client_ctx); - } - if (ret < 0) { - return ret; + if (client_ctx->use_dtls) { + if (client_ctx->load_credentials) { + ret = client_ctx->load_credentials(client_ctx); + } else { + ret = lwm2m_load_tls_credentials(client_ctx); + } + if (ret < 0) { + return ret; + } } #endif /* CONFIG_LWM2M_DTLS_SUPPORT */ From 95bf611ac663ea84f4e9dec5f2f0d9bd590d4f17 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 12:58:30 +0100 Subject: [PATCH 0626/1049] tests/drivers sbs_gauge: Switch from native_posix to native_sim Switch from native_posix to native_sim as native test platform Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/sensor/sbs_gauge/testcase.yaml | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/drivers/sensor/sbs_gauge/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/sensor/sbs_gauge/boards/native_posix.overlay b/tests/drivers/sensor/sbs_gauge/boards/native_sim.overlay similarity index 100% rename from tests/drivers/sensor/sbs_gauge/boards/native_posix.overlay rename to tests/drivers/sensor/sbs_gauge/boards/native_sim.overlay diff --git a/tests/drivers/sensor/sbs_gauge/testcase.yaml b/tests/drivers/sensor/sbs_gauge/testcase.yaml index b19fffaab4297dc..e585ed6f8071f27 100644 --- a/tests/drivers/sensor/sbs_gauge/testcase.yaml +++ b/tests/drivers/sensor/sbs_gauge/testcase.yaml @@ -15,10 +15,10 @@ tests: - sensors filter: dt_compat_enabled("sbs,sbs-gauge") platform_allow: - - native_posix + - native_sim - qemu_cortex_a9 - qemu_arc_hs integration_platforms: - - native_posix + - native_sim extra_configs: - CONFIG_EMUL=y From 3175a81da59082a175159221fa1a2a761d8d1d89 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:00:14 +0100 Subject: [PATCH 0627/1049] tests/drivers adltc2990: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/sensor/adltc2990/testcase.yaml | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) rename tests/drivers/sensor/adltc2990/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/sensor/adltc2990/boards/native_posix.overlay b/tests/drivers/sensor/adltc2990/boards/native_sim.overlay similarity index 100% rename from tests/drivers/sensor/adltc2990/boards/native_posix.overlay rename to tests/drivers/sensor/adltc2990/boards/native_sim.overlay diff --git a/tests/drivers/sensor/adltc2990/testcase.yaml b/tests/drivers/sensor/adltc2990/testcase.yaml index 09b0519416dadcb..2bf6dcfe5c84ecf 100644 --- a/tests/drivers/sensor/adltc2990/testcase.yaml +++ b/tests/drivers/sensor/adltc2990/testcase.yaml @@ -7,4 +7,5 @@ tests: - drivers - sensor - subsys - platform_allow: native_posix + platform_allow: + - native_sim From 5dbb71cc6f50be52a4bafd49b158723eaa8e1792 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:02:37 +0100 Subject: [PATCH 0628/1049] tests/drivers icm42688: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/sensor/icm42688/testcase.yaml | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) rename tests/drivers/sensor/icm42688/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/sensor/icm42688/boards/native_posix.overlay b/tests/drivers/sensor/icm42688/boards/native_sim.overlay similarity index 100% rename from tests/drivers/sensor/icm42688/boards/native_posix.overlay rename to tests/drivers/sensor/icm42688/boards/native_sim.overlay diff --git a/tests/drivers/sensor/icm42688/testcase.yaml b/tests/drivers/sensor/icm42688/testcase.yaml index f8f5929078c6311..6f886cb6191df1d 100644 --- a/tests/drivers/sensor/icm42688/testcase.yaml +++ b/tests/drivers/sensor/icm42688/testcase.yaml @@ -7,4 +7,5 @@ tests: - drivers - sensor - subsys - platform_allow: native_posix + platform_allow: + - native_sim From 75006ad9af52829e59a39b97b06251db7b002fd1 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:04:30 +0100 Subject: [PATCH 0629/1049] tests/drivers akm09918c: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/sensor/akm09918c/testcase.yaml | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) rename tests/drivers/sensor/akm09918c/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/sensor/akm09918c/boards/native_posix.overlay b/tests/drivers/sensor/akm09918c/boards/native_sim.overlay similarity index 100% rename from tests/drivers/sensor/akm09918c/boards/native_posix.overlay rename to tests/drivers/sensor/akm09918c/boards/native_sim.overlay diff --git a/tests/drivers/sensor/akm09918c/testcase.yaml b/tests/drivers/sensor/akm09918c/testcase.yaml index 4ccafdfbec94bfd..bc5167fda4b38c7 100644 --- a/tests/drivers/sensor/akm09918c/testcase.yaml +++ b/tests/drivers/sensor/akm09918c/testcase.yaml @@ -7,4 +7,5 @@ tests: - drivers - sensor - subsys - platform_allow: native_posix + platform_allow: + - native_sim From 5327ba38e5fb6e3cd6a6f1341fdfedf052457f33 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:05:42 +0100 Subject: [PATCH 0630/1049] tests/drivers ina230: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- .../ina230/boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/sensor/ina230/testcase.yaml | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) rename tests/drivers/sensor/ina230/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/sensor/ina230/boards/native_posix.overlay b/tests/drivers/sensor/ina230/boards/native_sim.overlay similarity index 100% rename from tests/drivers/sensor/ina230/boards/native_posix.overlay rename to tests/drivers/sensor/ina230/boards/native_sim.overlay diff --git a/tests/drivers/sensor/ina230/testcase.yaml b/tests/drivers/sensor/ina230/testcase.yaml index a0f962e4a6c33c7..9ead4ab22b11c0a 100644 --- a/tests/drivers/sensor/ina230/testcase.yaml +++ b/tests/drivers/sensor/ina230/testcase.yaml @@ -7,4 +7,5 @@ tests: - drivers - sensor - subsys - platform_allow: native_posix + platform_allow: + - native_sim From 1846fa6f2c563c159e5062347702daaf1c5b1457 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:07:41 +0100 Subject: [PATCH 0631/1049] tests/drivers ina237: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- .../ina237/boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/sensor/ina237/testcase.yaml | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) rename tests/drivers/sensor/ina237/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/sensor/ina237/boards/native_posix.overlay b/tests/drivers/sensor/ina237/boards/native_sim.overlay similarity index 100% rename from tests/drivers/sensor/ina237/boards/native_posix.overlay rename to tests/drivers/sensor/ina237/boards/native_sim.overlay diff --git a/tests/drivers/sensor/ina237/testcase.yaml b/tests/drivers/sensor/ina237/testcase.yaml index afad2c5726c7e17..3c9f97d76046f47 100644 --- a/tests/drivers/sensor/ina237/testcase.yaml +++ b/tests/drivers/sensor/ina237/testcase.yaml @@ -7,4 +7,5 @@ tests: - drivers - sensor - subsys - platform_allow: native_posix + platform_allow: + - native_sim From b85aef003cde55b8d0c27c01afe6a28a91ccacc7 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:09:50 +0100 Subject: [PATCH 0632/1049] tests/drivers/build_all/sensor: Enable for native_sim And switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/drivers/build_all/sensor/testcase.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/drivers/build_all/sensor/testcase.yaml b/tests/drivers/build_all/sensor/testcase.yaml index eeca799df9462d9..2bf581e58dae391 100644 --- a/tests/drivers/build_all/sensor/testcase.yaml +++ b/tests/drivers/build_all/sensor/testcase.yaml @@ -2,7 +2,11 @@ common: tags: - drivers - sensors - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim build_only: true tests: sensors.build.sensorhub: From 7d5772d2d66c85eb3234adb92378473468ffd469 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:12:23 +0100 Subject: [PATCH 0633/1049] tests/drivers/pinctrl/api: Enable for native_sim Enable for native_sim. and switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/drivers/pinctrl/api/testcase.yaml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/drivers/pinctrl/api/testcase.yaml b/tests/drivers/pinctrl/api/testcase.yaml index dc23dadafe985bd..90a6f48a496d7c4 100644 --- a/tests/drivers/pinctrl/api/testcase.yaml +++ b/tests/drivers/pinctrl/api/testcase.yaml @@ -1,23 +1,21 @@ # Copyright (c) 2021 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 +common: + platform_allow: + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - native_sim tests: drivers.pinctrl.api: tags: - drivers - pinctrl - platform_allow: - - native_posix - - native_posix_64 - integration_platforms: - - native_posix drivers.pinctrl.api_reg: tags: - drivers - pinctrl - platform_allow: - - native_posix - - native_posix_64 extra_args: CONF_FILE="prj.conf;reg.conf" - integration_platforms: - - native_posix From be8f4e104b00814b0ecafb50cac255aa2e15fd67 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:15:01 +0100 Subject: [PATCH 0634/1049] tests/drivers espi: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- .../espi/boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/espi/testcase.yaml | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename tests/drivers/espi/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/espi/boards/native_posix.overlay b/tests/drivers/espi/boards/native_sim.overlay similarity index 100% rename from tests/drivers/espi/boards/native_posix.overlay rename to tests/drivers/espi/boards/native_sim.overlay diff --git a/tests/drivers/espi/testcase.yaml b/tests/drivers/espi/testcase.yaml index 89f1c45c2bc4e84..d8d55bb2e3357aa 100644 --- a/tests/drivers/espi/testcase.yaml +++ b/tests/drivers/espi/testcase.yaml @@ -8,6 +8,7 @@ tests: - espi filter: dt_compat_enabled("zephyr,espi-emul-controller") harness: ztest - platform_allow: native_posix + platform_allow: + - native_sim integration_platforms: - - native_posix + - native_sim From 64cb9a4540d2c3eb5156253a3551e653cb6ce0dd Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:16:21 +0100 Subject: [PATCH 0635/1049] tests/drivers/regulator/api: Enable for native_sim Enable for native_sim. and switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/drivers/regulator/api/testcase.yaml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/drivers/regulator/api/testcase.yaml b/tests/drivers/regulator/api/testcase.yaml index 95a27f73d646420..6aa48cc3aa22836 100644 --- a/tests/drivers/regulator/api/testcase.yaml +++ b/tests/drivers/regulator/api/testcase.yaml @@ -1,24 +1,22 @@ # Copyright (c) 2022 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 +common: + platform_allow: + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - native_sim tests: drivers.regulator.api: tags: - drivers - regulator - platform_allow: - - native_posix - - native_posix_64 - integration_platforms: - - native_posix drivers.regulator.api.nothreadsaferefcnt: tags: - drivers - regulator - platform_allow: - - native_posix - - native_posix_64 - integration_platforms: - - native_posix extra_configs: - CONFIG_REGULATOR_THREAD_SAFE_REFCNT=n From c6f5dbe8a75effc6689f9288ba28375905fcd253 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:24:55 +0100 Subject: [PATCH 0636/1049] tests fuel_gauge/bq27z746: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- .../bq27z746/boards/{native_posix.conf => native_sim.conf} | 0 .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/fuel_gauge/bq27z746/testcase.yaml | 3 ++- 3 files changed, 2 insertions(+), 1 deletion(-) rename tests/drivers/fuel_gauge/bq27z746/boards/{native_posix.conf => native_sim.conf} (100%) rename tests/drivers/fuel_gauge/bq27z746/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/fuel_gauge/bq27z746/boards/native_posix.conf b/tests/drivers/fuel_gauge/bq27z746/boards/native_sim.conf similarity index 100% rename from tests/drivers/fuel_gauge/bq27z746/boards/native_posix.conf rename to tests/drivers/fuel_gauge/bq27z746/boards/native_sim.conf diff --git a/tests/drivers/fuel_gauge/bq27z746/boards/native_posix.overlay b/tests/drivers/fuel_gauge/bq27z746/boards/native_sim.overlay similarity index 100% rename from tests/drivers/fuel_gauge/bq27z746/boards/native_posix.overlay rename to tests/drivers/fuel_gauge/bq27z746/boards/native_sim.overlay diff --git a/tests/drivers/fuel_gauge/bq27z746/testcase.yaml b/tests/drivers/fuel_gauge/bq27z746/testcase.yaml index 21f149d4da2b1c3..3bf2755af760b64 100644 --- a/tests/drivers/fuel_gauge/bq27z746/testcase.yaml +++ b/tests/drivers/fuel_gauge/bq27z746/testcase.yaml @@ -3,4 +3,5 @@ tests: tags: - fuel_gauge filter: dt_compat_enabled("ti,bq27z746") - platform_allow: native_posix + platform_allow: + - native_sim From 3ff73f22a434d5d8b96695acf4236e6968d2e927 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:26:05 +0100 Subject: [PATCH 0637/1049] tests fuel_gauge/max17048: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- .../max17048/boards/{native_posix.conf => native_sim.conf} | 0 .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/fuel_gauge/max17048/testcase.yaml | 3 ++- 3 files changed, 2 insertions(+), 1 deletion(-) rename tests/drivers/fuel_gauge/max17048/boards/{native_posix.conf => native_sim.conf} (100%) rename tests/drivers/fuel_gauge/max17048/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/fuel_gauge/max17048/boards/native_posix.conf b/tests/drivers/fuel_gauge/max17048/boards/native_sim.conf similarity index 100% rename from tests/drivers/fuel_gauge/max17048/boards/native_posix.conf rename to tests/drivers/fuel_gauge/max17048/boards/native_sim.conf diff --git a/tests/drivers/fuel_gauge/max17048/boards/native_posix.overlay b/tests/drivers/fuel_gauge/max17048/boards/native_sim.overlay similarity index 100% rename from tests/drivers/fuel_gauge/max17048/boards/native_posix.overlay rename to tests/drivers/fuel_gauge/max17048/boards/native_sim.overlay diff --git a/tests/drivers/fuel_gauge/max17048/testcase.yaml b/tests/drivers/fuel_gauge/max17048/testcase.yaml index 33c8def41957b94..3f187d27cd70784 100644 --- a/tests/drivers/fuel_gauge/max17048/testcase.yaml +++ b/tests/drivers/fuel_gauge/max17048/testcase.yaml @@ -3,4 +3,5 @@ tests: tags: - fuel_gauge filter: dt_compat_enabled("maxim,max17048") - platform_allow: native_posix + platform_allow: + - native_sim From e13acd2f29dd5d4de4b8dcab88ff38f628c35af1 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:27:02 +0100 Subject: [PATCH 0638/1049] tests fuel_gauge/sbs_gauge: Enable for native_sim Enable for native_sim Signed-off-by: Alberto Escolar Piedras --- tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml b/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml index 66e3dde18dfe621..97d25b26a050b8d 100644 --- a/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml +++ b/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml @@ -5,7 +5,7 @@ tests: - fuel_gauge filter: > dt_compat_enabled("sbs,sbs-gauge-new-api") and - (CONFIG_QEMU_TARGET or CONFIG_BOARD_NATIVE_POSIX) + (CONFIG_QEMU_TARGET or CONFIG_BOARD_NATIVE_SIM) extra_args: - CONF_FILE="prj.conf;boards/emulated_board.conf" - DTC_OVERLAY_FILE="boards/emulated_board.overlay" @@ -26,7 +26,7 @@ tests: - fuel_gauge filter: > dt_compat_enabled("sbs,sbs-gauge-new-api") and - (CONFIG_QEMU_TARGET or CONFIG_BOARD_NATIVE_POSIX) + (CONFIG_QEMU_TARGET or CONFIG_BOARD_NATIVE_SIM) platform_allow: - hifive_unmatched - qemu_cortex_a53 @@ -52,4 +52,5 @@ tests: - CONFIG_USERSPACE=y platform_allow: - native_posix + - native_sim - qemu_x86 From ef346c2505cffea0029f31dece886946fe9db2ec Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:36:53 +0100 Subject: [PATCH 0639/1049] tests input/gpio_keys: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 .../{native_posix_64.overlay => native_sim_64.overlay} | 2 +- tests/drivers/input/gpio_keys/testcase.yaml | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) rename tests/drivers/input/gpio_keys/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/input/gpio_keys/boards/{native_posix_64.overlay => native_sim_64.overlay} (70%) diff --git a/tests/drivers/input/gpio_keys/boards/native_posix.overlay b/tests/drivers/input/gpio_keys/boards/native_sim.overlay similarity index 100% rename from tests/drivers/input/gpio_keys/boards/native_posix.overlay rename to tests/drivers/input/gpio_keys/boards/native_sim.overlay diff --git a/tests/drivers/input/gpio_keys/boards/native_posix_64.overlay b/tests/drivers/input/gpio_keys/boards/native_sim_64.overlay similarity index 70% rename from tests/drivers/input/gpio_keys/boards/native_posix_64.overlay rename to tests/drivers/input/gpio_keys/boards/native_sim_64.overlay index 166e6f02e82d5b0..a906fce7488c3fc 100644 --- a/tests/drivers/input/gpio_keys/boards/native_posix_64.overlay +++ b/tests/drivers/input/gpio_keys/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/input/gpio_keys/testcase.yaml b/tests/drivers/input/gpio_keys/testcase.yaml index b8fd702d96af826..be4cb2b17e949b4 100644 --- a/tests/drivers/input/gpio_keys/testcase.yaml +++ b/tests/drivers/input/gpio_keys/testcase.yaml @@ -6,7 +6,7 @@ tests: - drivers - input platform_allow: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim From 6bba2d955b967eb8daf10d017eb0b3508bb86d08 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:48:22 +0100 Subject: [PATCH 0640/1049] tests/net/traffic_class: Enable for native_sim Enable these tests in native_sim and switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/net/traffic_class/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/net/traffic_class/testcase.yaml b/tests/net/traffic_class/testcase.yaml index b8a56acbb273239..a69fe29edcb4360 100644 --- a/tests/net/traffic_class/testcase.yaml +++ b/tests/net/traffic_class/testcase.yaml @@ -2,8 +2,10 @@ common: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix_64 + - native_sim_64 tags: - net - traffic_class From 18d27f0a290c85c3edb134c2f74454b94ed21ce2 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:50:41 +0100 Subject: [PATCH 0641/1049] tests ieee802154: Enable for native_sim Enable these tests for native_sim and switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/net/ieee802154/6lo_fragment/testcase.yaml | 4 +++- tests/net/ieee802154/custom_l2/testcase.yaml | 4 +++- tests/net/ieee802154/l2/testcase.yaml | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/net/ieee802154/6lo_fragment/testcase.yaml b/tests/net/ieee802154/6lo_fragment/testcase.yaml index 547a34c3a628e6c..dad5d24d7b291fc 100644 --- a/tests/net/ieee802154/6lo_fragment/testcase.yaml +++ b/tests/net/ieee802154/6lo_fragment/testcase.yaml @@ -3,8 +3,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - net - ieee802154 diff --git a/tests/net/ieee802154/custom_l2/testcase.yaml b/tests/net/ieee802154/custom_l2/testcase.yaml index 4a289e924d83c37..97c58a16ba108d3 100644 --- a/tests/net/ieee802154/custom_l2/testcase.yaml +++ b/tests/net/ieee802154/custom_l2/testcase.yaml @@ -3,8 +3,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - net - ieee802154 diff --git a/tests/net/ieee802154/l2/testcase.yaml b/tests/net/ieee802154/l2/testcase.yaml index 2be38d93d243e64..795bd13304c2256 100644 --- a/tests/net/ieee802154/l2/testcase.yaml +++ b/tests/net/ieee802154/l2/testcase.yaml @@ -2,8 +2,10 @@ common: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - net - ieee802154 From eae99c1035051599058ddf3f00eb0ea473024790 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:52:30 +0100 Subject: [PATCH 0642/1049] tests net/ptp/clock: Enable for native_sim Enable these tests for native_sim and switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/net/ptp/clock/testcase.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/net/ptp/clock/testcase.yaml b/tests/net/ptp/clock/testcase.yaml index d37134a9301281a..1d72469533700c7 100644 --- a/tests/net/ptp/clock/testcase.yaml +++ b/tests/net/ptp/clock/testcase.yaml @@ -5,8 +5,9 @@ common: - frdm_k64f - sam_e70_xplained - native_posix + - native_sim integration_platforms: - - native_posix + - native_sim tests: net.ptp.clock: min_ram: 32 From c64f33a6486293d1d9f97cb18933477c12eaab17 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:56:05 +0100 Subject: [PATCH 0643/1049] tests/net lwm2m_rd_client: Switch from native_posix to native_sim Switch these tests from native_posix to native_sim Signed-off-by: Alberto Escolar Piedras --- .../net/lib/lwm2m/lwm2m_rd_client/boards/native_posix.conf | 1 - tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_sim.conf | 1 + tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c | 6 +++--- tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_posix.conf create mode 100644 tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_sim.conf diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_posix.conf b/tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_posix.conf deleted file mode 100644 index eb56d825c96d1a0..000000000000000 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_posix.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_sim.conf b/tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_sim.conf new file mode 100644 index 000000000000000..0843e94acbdbdea --- /dev/null +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_sim.conf @@ -0,0 +1 @@ +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c index 03d0dce7f49441c..931f6f15904ee76 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c @@ -9,8 +9,8 @@ #include #include #include -#if defined(CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME) -#include "timer_model.h" +#if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME) +#include "nsi_timer_model.h" #endif #include @@ -141,7 +141,7 @@ static void lwm2m_observe_cb(enum lwm2m_observe_event event, struct lwm2m_obj_pa static void my_suite_before(void *data) { -#if defined(CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME) +#if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME) /* It is enough that some slow-down is happening on sleeps, it does not have to be * real time */ diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml index 80c5bee1131319b..df49b3c7342d856 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml @@ -5,7 +5,7 @@ common: - lwm2m - net platform_allow: - - native_posix + - native_sim tests: net.lwm2m.lwm2m_rd_client: extra_args: EXTRA_CFLAGS="" From f7b8ded41ae26bdf4ea8f9409ed0e77123b188cf Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 13:59:16 +0100 Subject: [PATCH 0644/1049] tests/net/lib/coap_client/: Enable for native_sim Enable this test for native_sim Signed-off-by: Alberto Escolar Piedras --- tests/net/lib/coap_client/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/net/lib/coap_client/testcase.yaml b/tests/net/lib/coap_client/testcase.yaml index 923e1380f010a86..18e64f08df52f8c 100644 --- a/tests/net/lib/coap_client/testcase.yaml +++ b/tests/net/lib/coap_client/testcase.yaml @@ -2,5 +2,7 @@ common: depends_on: netif tests: net.coap.client: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: coap net From 0de923e2b0ef25e5c2a2a2138b729438763ee233 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 14:05:20 +0100 Subject: [PATCH 0645/1049] tests/net/lib/lwm2m/interop: Switch from native_posix to native_sim Switch support of native_posix to native_sim Signed-off-by: Alberto Escolar Piedras --- .../interop/boards/{native_posix.conf => native_sim.conf} | 2 +- tests/net/lib/lwm2m/interop/testcase.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename tests/net/lib/lwm2m/interop/boards/{native_posix.conf => native_sim.conf} (82%) diff --git a/tests/net/lib/lwm2m/interop/boards/native_posix.conf b/tests/net/lib/lwm2m/interop/boards/native_sim.conf similarity index 82% rename from tests/net/lib/lwm2m/interop/boards/native_posix.conf rename to tests/net/lib/lwm2m/interop/boards/native_sim.conf index 422e2c1bde471fe..2dc86f3d484dbac 100644 --- a/tests/net/lib/lwm2m/interop/boards/native_posix.conf +++ b/tests/net/lib/lwm2m/interop/boards/native_sim.conf @@ -3,6 +3,6 @@ CONFIG_DNS_SERVER_IP_ADDRESSES=y CONFIG_DNS_SERVER1="192.0.2.2" CONFIG_LWM2M_DNS_SUPPORT=y CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" -CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y CONFIG_NATIVE_UART_0_ON_STDINOUT=y CONFIG_ASAN=y diff --git a/tests/net/lib/lwm2m/interop/testcase.yaml b/tests/net/lib/lwm2m/interop/testcase.yaml index 42bd53814bf70d0..06390472269436b 100644 --- a/tests/net/lib/lwm2m/interop/testcase.yaml +++ b/tests/net/lib/lwm2m/interop/testcase.yaml @@ -7,9 +7,9 @@ tests: pytest_dut_scope: module pytest_args: [] integration_platforms: - - native_posix + - native_sim platform_allow: - - native_posix + - native_sim - qemu_cortex_m3 - qemu_x86 tags: From 640b926b0afaebc477d2dc1e4099c9154402b790 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 14:07:16 +0100 Subject: [PATCH 0646/1049] tests/net/lib lwm2m_engine: Switch from native_posix to native_sim Switch support of native_posix to native_sim Signed-off-by: Alberto Escolar Piedras --- tests/net/lib/lwm2m/lwm2m_engine/boards/native_posix.conf | 1 - tests/net/lib/lwm2m/lwm2m_engine/boards/native_sim.conf | 1 + tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 tests/net/lib/lwm2m/lwm2m_engine/boards/native_posix.conf create mode 100644 tests/net/lib/lwm2m/lwm2m_engine/boards/native_sim.conf diff --git a/tests/net/lib/lwm2m/lwm2m_engine/boards/native_posix.conf b/tests/net/lib/lwm2m/lwm2m_engine/boards/native_posix.conf deleted file mode 100644 index eb56d825c96d1a0..000000000000000 --- a/tests/net/lib/lwm2m/lwm2m_engine/boards/native_posix.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y diff --git a/tests/net/lib/lwm2m/lwm2m_engine/boards/native_sim.conf b/tests/net/lib/lwm2m/lwm2m_engine/boards/native_sim.conf new file mode 100644 index 000000000000000..0843e94acbdbdea --- /dev/null +++ b/tests/net/lib/lwm2m/lwm2m_engine/boards/native_sim.conf @@ -0,0 +1 @@ +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml index a7f628405ebf739..2f765ac0dc1b0da 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim From a86e0a8da9eec1bb0acb7e49cac0c1b63a9a7383 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 14:08:11 +0100 Subject: [PATCH 0647/1049] tests/net/lib/lwm2m/*: Switch integation_platforms to native_sim Switch integation_platforms from native_posix to native_sim Signed-off-by: Alberto Escolar Piedras --- tests/net/lib/lwm2m/block_transfer/testcase.yaml | 2 +- tests/net/lib/lwm2m/content_json/testcase.yaml | 2 +- tests/net/lib/lwm2m/content_link_format/testcase.yaml | 2 +- tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml | 2 +- tests/net/lib/lwm2m/content_plain_text/testcase.yaml | 2 +- tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml | 2 +- tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml | 2 +- tests/net/lib/lwm2m/engine/testcase.yaml | 2 +- tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/net/lib/lwm2m/block_transfer/testcase.yaml b/tests/net/lib/lwm2m/block_transfer/testcase.yaml index 66f145fd18fbcd0..4ad71f29ef037f7 100644 --- a/tests/net/lib/lwm2m/block_transfer/testcase.yaml +++ b/tests/net/lib/lwm2m/block_transfer/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim diff --git a/tests/net/lib/lwm2m/content_json/testcase.yaml b/tests/net/lib/lwm2m/content_json/testcase.yaml index a283ce908ef66cb..f933ec6d684bc26 100644 --- a/tests/net/lib/lwm2m/content_json/testcase.yaml +++ b/tests/net/lib/lwm2m/content_json/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim diff --git a/tests/net/lib/lwm2m/content_link_format/testcase.yaml b/tests/net/lib/lwm2m/content_link_format/testcase.yaml index 5448cf68fd059b1..0b7d965d0f0eec2 100644 --- a/tests/net/lib/lwm2m/content_link_format/testcase.yaml +++ b/tests/net/lib/lwm2m/content_link_format/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim diff --git a/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml b/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml index 2bf877f735370df..dee42fcc5035d74 100644 --- a/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml +++ b/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim diff --git a/tests/net/lib/lwm2m/content_plain_text/testcase.yaml b/tests/net/lib/lwm2m/content_plain_text/testcase.yaml index bd70dd790b303de..96fc17267941168 100644 --- a/tests/net/lib/lwm2m/content_plain_text/testcase.yaml +++ b/tests/net/lib/lwm2m/content_plain_text/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim diff --git a/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml b/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml index 9fc90f109bc06e1..4580a2538caa238 100644 --- a/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml +++ b/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim diff --git a/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml b/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml index 55cd89a9f51b2a0..1bca0ca15ebe46a 100644 --- a/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml +++ b/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim diff --git a/tests/net/lib/lwm2m/engine/testcase.yaml b/tests/net/lib/lwm2m/engine/testcase.yaml index 3263441b418d4c1..b13ecef47534802 100644 --- a/tests/net/lib/lwm2m/engine/testcase.yaml +++ b/tests/net/lib/lwm2m/engine/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim diff --git a/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml index ca0f06f58b57832..a994dd72ad8f001 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml @@ -6,4 +6,4 @@ tests: - lwm2m - net integration_platforms: - - native_posix + - native_sim From 0a81ea5406c95f13980e97b7531dc4804fea200e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 14:16:33 +0100 Subject: [PATCH 0648/1049] tests/net/socket/can: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/net/socket/can/testcase.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/net/socket/can/testcase.yaml b/tests/net/socket/can/testcase.yaml index 251c541c0c297e9..6d5a2a495da6a48 100644 --- a/tests/net/socket/can/testcase.yaml +++ b/tests/net/socket/can/testcase.yaml @@ -1,8 +1,8 @@ tests: net.socket.can: integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: - net - can From 8991e0176c96d2d1a7890af68485f6fc7f738e2e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 14:17:05 +0100 Subject: [PATCH 0649/1049] tests/net/lib/coap_server: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/net/lib/coap_server/common/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/net/lib/coap_server/common/testcase.yaml b/tests/net/lib/coap_server/common/testcase.yaml index c36e9646270542a..513d3c4a0e41a0e 100644 --- a/tests/net/lib/coap_server/common/testcase.yaml +++ b/tests/net/lib/coap_server/common/testcase.yaml @@ -5,7 +5,7 @@ common: - coap - server integration_platforms: - - native_posix + - native_sim tests: net.coap.server.common: {} From c5e0f6c0ffabb64479866618744b0f10bb5c9389 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 14:17:22 +0100 Subject: [PATCH 0650/1049] tests/net/lib/http_server: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/net/lib/http_server/common/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/net/lib/http_server/common/testcase.yaml b/tests/net/lib/http_server/common/testcase.yaml index 951f5d7c582ad71..b86f2dc0c95741d 100644 --- a/tests/net/lib/http_server/common/testcase.yaml +++ b/tests/net/lib/http_server/common/testcase.yaml @@ -5,7 +5,7 @@ common: - http - server integration_platforms: - - native_posix + - native_sim tests: net.http.server.common: {} From f345378db1f8852753811c0bac8ae7858e55b331 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Thu, 16 Nov 2023 15:03:07 +0100 Subject: [PATCH 0651/1049] doc: application: Fix application build comment Fix the application build comment to make it valid for both ninja and make build tools. It generated the wrong "ninja" comment for "make". Signed-off-by: Andrej Butok --- doc/_extensions/zephyr/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_extensions/zephyr/application.py b/doc/_extensions/zephyr/application.py index e24d1bf76475dfa..969e3290a5927a6 100644 --- a/doc/_extensions/zephyr/application.py +++ b/doc/_extensions/zephyr/application.py @@ -415,7 +415,7 @@ def _generate_cmake(self, **kwargs): cmake_args, source_dir)) if not compact: content.extend(['', - '# Now run ninja on the generated build system:']) + '# Now run the build tool on the generated build system:']) if 'build' in goals: content.append('{}{}{}'.format(generator, tool_build_dir, From c0c895273917a156e2cd9e743c607aeea820650e Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 16 Nov 2023 15:09:40 +0100 Subject: [PATCH 0652/1049] shell: do not enable subsystem/driver shell modules by default Do not enable subsystem/driver shell modules by default and stop abusing CONFIG_SHELL_MINIMAL, which is internal to the shell subsystem, to decide when to enable a driver shell. The list of shell modules has grown considerably through the years. Enabling CONFIG_SHELL for doing e.g. an interactive debug session leads to a large number of shell modules also being enabled unless explicitly disabled, which again leads to non-negligible increases in RAM/ROM usage. This commit attempts to establish a policy of subsystem/driver shell modules being disabled by default, requiring the user/application to explicitly enable only those needed. Signed-off-by: Henrik Brix Andersen --- drivers/adc/Kconfig | 1 - drivers/audio/Kconfig | 1 - drivers/can/Kconfig | 1 - drivers/clock_control/Kconfig.nrf | 1 - drivers/dac/Kconfig | 1 - drivers/edac/Kconfig | 1 - drivers/eeprom/Kconfig | 1 - drivers/flash/Kconfig | 1 - drivers/hwinfo/Kconfig | 1 - drivers/i2c/Kconfig | 1 - drivers/lora/Kconfig | 1 - drivers/mdio/Kconfig | 1 - drivers/pcie/host/Kconfig | 1 - drivers/pm_cpu_ops/Kconfig | 1 - drivers/pwm/Kconfig | 1 - drivers/regulator/Kconfig | 1 - drivers/sensor/Kconfig | 1 - drivers/smbus/Kconfig | 1 - drivers/w1/Kconfig | 1 - drivers/watchdog/Kconfig.shell | 1 - lib/acpi/Kconfig | 1 - samples/drivers/smbus/prj.conf | 1 + samples/shields/npm1300_ek/prj.conf | 1 + samples/shields/npm6001_ek/prj.conf | 1 + subsys/debug/coredump/Kconfig | 1 - subsys/dfu/Kconfig | 1 - subsys/logging/Kconfig.misc | 1 - subsys/net/l2/openthread/Kconfig | 1 - subsys/stats/Kconfig | 1 - subsys/usb/device_next/Kconfig | 1 - subsys/usb/host/Kconfig | 1 - 31 files changed, 3 insertions(+), 28 deletions(-) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index b52183c2b476bc5..6dd41582bd0396c 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -17,7 +17,6 @@ if ADC config ADC_SHELL bool "ADC Shell" - default y depends on SHELL help Enable ADC Shell for testing. diff --git a/drivers/audio/Kconfig b/drivers/audio/Kconfig index 308bbb3172a8ab6..a9d113316760cab 100644 --- a/drivers/audio/Kconfig +++ b/drivers/audio/Kconfig @@ -27,7 +27,6 @@ config AUDIO_CODEC_INIT_PRIORITY config AUDIO_CODEC_SHELL bool "Audio Codec shell" - default y depends on SHELL help Enable the Audio Codec shell with Audio Codec related commands. diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index f12bbebf6fa5c6d..ed0818d3508a18d 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -25,7 +25,6 @@ config CAN_INIT_PRIORITY config CAN_SHELL bool "CAN shell" - default y depends on SHELL select POLL help diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index 64e31b1ad162e00..453aac5b5d074b4 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -25,7 +25,6 @@ if CLOCK_CONTROL_NRF config CLOCK_CONTROL_NRF_SHELL bool "Shell commands" depends on SHELL - default y if SHELL choice CLOCK_CONTROL_NRF_SOURCE prompt "32KHz clock source" diff --git a/drivers/dac/Kconfig b/drivers/dac/Kconfig index 553d9f05355d9d9..3735a11aa2aa6b0 100644 --- a/drivers/dac/Kconfig +++ b/drivers/dac/Kconfig @@ -19,7 +19,6 @@ source "subsys/logging/Kconfig.template.log_config" config DAC_SHELL bool "DAC shell" - default y depends on SHELL help Enable DAC related shell commands. diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 45e499a749a6217..e5029ce470f889e 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -19,7 +19,6 @@ config EDAC_ERROR_INJECT config EDAC_SHELL bool "EDAC Shell" depends on SHELL - default y if SHELL help Enable EDAC shell for debugging EDAC. diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig index 745d274ff1e3a97..29405f4ed65fb0a 100644 --- a/drivers/eeprom/Kconfig +++ b/drivers/eeprom/Kconfig @@ -24,7 +24,6 @@ config EEPROM_INIT_PRIORITY config EEPROM_SHELL bool "EEPROM shell" - default y depends on SHELL help Enable the EEPROM shell with EEPROM related commands. diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 5b47c75c20e6541..698190e7780af23 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -53,7 +53,6 @@ config FLASH_SHELL bool "Flash shell" depends on SHELL && FLASH_PAGE_LAYOUT select MPU_ALLOW_FLASH_WRITE if ARM_MPU - default y help Enable the flash shell with flash related commands such as test, write, read and erase. diff --git a/drivers/hwinfo/Kconfig b/drivers/hwinfo/Kconfig index 6971315b6b89a60..7c4cc7f08051e9e 100644 --- a/drivers/hwinfo/Kconfig +++ b/drivers/hwinfo/Kconfig @@ -16,7 +16,6 @@ source "subsys/logging/Kconfig.template.log_config" config HWINFO_SHELL bool "HWINFO Shell" - default y depends on SHELL help Enable hwinfo Shell for testing. diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 2523877c8513da1..233879167c6cbce 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -15,7 +15,6 @@ if I2C config I2C_SHELL bool "I2C Shell" - default y depends on SHELL help Enable I2C Shell. diff --git a/drivers/lora/Kconfig b/drivers/lora/Kconfig index ddc1e50e62509a1..585f122c3d6fd41 100644 --- a/drivers/lora/Kconfig +++ b/drivers/lora/Kconfig @@ -21,7 +21,6 @@ source "subsys/logging/Kconfig.template.log_config" config LORA_SHELL bool "LoRa Shell" - default y depends on SHELL help Enable LoRa Shell for testing. diff --git a/drivers/mdio/Kconfig b/drivers/mdio/Kconfig index ddca38359fa6550..b3831b2c2d7ec38 100644 --- a/drivers/mdio/Kconfig +++ b/drivers/mdio/Kconfig @@ -15,7 +15,6 @@ if MDIO config MDIO_SHELL bool "MDIO Shell" - default y depends on SHELL help Enable MDIO Shell. diff --git a/drivers/pcie/host/Kconfig b/drivers/pcie/host/Kconfig index 2dcb9bba61290c2..515ef89ce280da2 100644 --- a/drivers/pcie/host/Kconfig +++ b/drivers/pcie/host/Kconfig @@ -82,7 +82,6 @@ config PCIE_PRT config PCIE_SHELL bool "PCIe/new PCI Shell" - default y depends on SHELL help Enable commands for debugging PCI(e) using the built-in shell. diff --git a/drivers/pm_cpu_ops/Kconfig b/drivers/pm_cpu_ops/Kconfig index c38c6779fa1cad5..43d549f59bde558 100644 --- a/drivers/pm_cpu_ops/Kconfig +++ b/drivers/pm_cpu_ops/Kconfig @@ -32,7 +32,6 @@ config PM_CPU_OPS_PSCI config PSCI_SHELL bool "Support for PSCI interface shell commands" - default y depends on SHELL && PM_CPU_OPS_PSCI help Say Y here if you need to enable PSCI interface shell commands diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index ff9856d9d57dfed..8942ebd89b08cd1 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -22,7 +22,6 @@ config PWM_INIT_PRIORITY config PWM_SHELL bool "PWM shell" - default y depends on SHELL help Enable the PWM related shell commands. diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index ebf13261cbf395e..c35ae389669ff14 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -17,7 +17,6 @@ config REGULATOR_THREAD_SAFE_REFCNT config REGULATOR_SHELL bool "Regulator shell" - default y depends on SHELL help Enable regulator shell framework, for interacting with regulators via diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 25af39bde4c78ff..08d04774dcd92b9 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -32,7 +32,6 @@ config SENSOR_SHELL depends on SHELL select CBPRINTF_FP_SUPPORT select SENSOR_ASYNC_API - default y if !SHELL_MINIMAL help This shell provides access to basic sensor data. diff --git a/drivers/smbus/Kconfig b/drivers/smbus/Kconfig index b80e1df2dd91f49..88eff8b0030b8e5 100644 --- a/drivers/smbus/Kconfig +++ b/drivers/smbus/Kconfig @@ -12,7 +12,6 @@ if SMBUS config SMBUS_SHELL bool "SMBus Shell" - default y depends on SHELL help Enable SMBus Shell. diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index 2fabe874b6d0446..a63a57419811e36 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -26,7 +26,6 @@ config W1_INIT_PRIORITY config W1_SHELL bool "1-Wire Shell" depends on SHELL - default y if !SHELL_MINIMAL help Enable 1-Wire Shell for testing. diff --git a/drivers/watchdog/Kconfig.shell b/drivers/watchdog/Kconfig.shell index 5f5a97a6bda1310..11503277e935ce8 100644 --- a/drivers/watchdog/Kconfig.shell +++ b/drivers/watchdog/Kconfig.shell @@ -3,7 +3,6 @@ config WDT_SHELL bool "Watchdog (WDT) shell" - default y depends on SHELL help Enable WDT shell. diff --git a/lib/acpi/Kconfig b/lib/acpi/Kconfig index 6c29b77875d74b0..42b35725c70365e 100644 --- a/lib/acpi/Kconfig +++ b/lib/acpi/Kconfig @@ -32,7 +32,6 @@ endif # PCIE_PRT config ACPI_SHELL bool "ACPI command Shell" - default y depends on SHELL help Enable commands for debugging ACPI using the built-in shell. diff --git a/samples/drivers/smbus/prj.conf b/samples/drivers/smbus/prj.conf index a02baae7ec92afd..8ed31bb9e29d06a 100644 --- a/samples/drivers/smbus/prj.conf +++ b/samples/drivers/smbus/prj.conf @@ -1,4 +1,5 @@ CONFIG_SMBUS=y +CONFIG_SMBUS_SHELL=y CONFIG_SMBUS_INTEL_PCH=y CONFIG_SMBUS_LOG_LEVEL_DBG=y CONFIG_USERSPACE=y diff --git a/samples/shields/npm1300_ek/prj.conf b/samples/shields/npm1300_ek/prj.conf index 7b134995827eea6..c8421d9bf0c00ef 100644 --- a/samples/shields/npm1300_ek/prj.conf +++ b/samples/shields/npm1300_ek/prj.conf @@ -5,5 +5,6 @@ CONFIG_SHELL=y CONFIG_LOG=y CONFIG_GPIO=y CONFIG_REGULATOR=y +CONFIG_REGULATOR_SHELL=y CONFIG_SENSOR=y CONFIG_LED=y diff --git a/samples/shields/npm6001_ek/prj.conf b/samples/shields/npm6001_ek/prj.conf index bfacbe8b14bf8be..94da7cfdaef63f3 100644 --- a/samples/shields/npm6001_ek/prj.conf +++ b/samples/shields/npm6001_ek/prj.conf @@ -7,4 +7,5 @@ CONFIG_GETOPT=y CONFIG_GETOPT_LONG=y CONFIG_GPIO=y CONFIG_REGULATOR=y +CONFIG_REGULATOR_SHELL=y CONFIG_WATCHDOG=y diff --git a/subsys/debug/coredump/Kconfig b/subsys/debug/coredump/Kconfig index 7b7de2227849e16..63126a283723590 100644 --- a/subsys/debug/coredump/Kconfig +++ b/subsys/debug/coredump/Kconfig @@ -71,7 +71,6 @@ endchoice config DEBUG_COREDUMP_SHELL bool "Coredump shell" - default y depends on SHELL help This shell provides access to coredump and its backends. diff --git a/subsys/dfu/Kconfig b/subsys/dfu/Kconfig index 121fa3964f6d316..e320185dfef2757 100644 --- a/subsys/dfu/Kconfig +++ b/subsys/dfu/Kconfig @@ -33,7 +33,6 @@ endchoice config MCUBOOT_SHELL bool "MCUboot shell" - default y depends on MCUBOOT_IMG_MANAGER depends on SHELL help diff --git a/subsys/logging/Kconfig.misc b/subsys/logging/Kconfig.misc index 0dc5831e5282c62..ce34bdae0a03d33 100644 --- a/subsys/logging/Kconfig.misc +++ b/subsys/logging/Kconfig.misc @@ -15,7 +15,6 @@ config LOG_CMDS bool "Shell commands" depends on SHELL depends on !LOG_FRONTEND_ONLY && !LOG_MODE_MINIMAL - default y if SHELL config LOG_TEST_CLEAR_MESSAGE_SPACE bool "Clear message after allocation" diff --git a/subsys/net/l2/openthread/Kconfig b/subsys/net/l2/openthread/Kconfig index 70c7d642674a065..98113975797fe37 100644 --- a/subsys/net/l2/openthread/Kconfig +++ b/subsys/net/l2/openthread/Kconfig @@ -151,7 +151,6 @@ endmenu # "Zephyr optimizations" config OPENTHREAD_SHELL bool "OpenThread shell" depends on SHELL - default y config MBEDTLS_PROMPTLESS bool diff --git a/subsys/stats/Kconfig b/subsys/stats/Kconfig index 1c6d138e1dfb837..417d5db021330c2 100644 --- a/subsys/stats/Kconfig +++ b/subsys/stats/Kconfig @@ -20,7 +20,6 @@ config STATS_NAMES config STATS_SHELL bool "Statistics Shell Command" - default y depends on STATS && SHELL imply STATS_NAMES help diff --git a/subsys/usb/device_next/Kconfig b/subsys/usb/device_next/Kconfig index d6ccd4d7bd679b3..90a774a9e369da9 100644 --- a/subsys/usb/device_next/Kconfig +++ b/subsys/usb/device_next/Kconfig @@ -18,7 +18,6 @@ source "subsys/logging/Kconfig.template.log_config" config USBD_SHELL bool "USB device shell" - default y depends on SHELL help Enable USB device shell. diff --git a/subsys/usb/host/Kconfig b/subsys/usb/host/Kconfig index bdedc6a4aa4de4f..e3055e0026c7613 100644 --- a/subsys/usb/host/Kconfig +++ b/subsys/usb/host/Kconfig @@ -17,7 +17,6 @@ source "subsys/logging/Kconfig.template.log_config" config USBH_SHELL bool "USB host shell" - default y depends on SHELL help Shell commands for USB host support. From 62f2ae1c5ed9a07c7cc307fe72d7eb91343e2863 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 16 Nov 2023 15:20:53 +0100 Subject: [PATCH 0653/1049] docs: releases: migration: 3.6: change in defaults for shell modules Mention the change in the default value for subsystem/driver shell module Kconfigs. Signed-off-by: Henrik Brix Andersen --- doc/releases/migration-guide-3.6.rst | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index ddf42b6dc3ab4a8..bff8df1770393bf 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -58,6 +58,41 @@ Device Drivers and Device Tree Power Management ================ +Shell +===== + +* The following subsystem and driver shell modules are now disabled by default. Each required shell + module must now be explicitly enabled via Kconfig (:github:`65307`): + + * :kconfig:option:`CONFIG_ACPI_SHELL` + * :kconfig:option:`CONFIG_ADC_SHELL` + * :kconfig:option:`CONFIG_AUDIO_CODEC_SHELL` + * :kconfig:option:`CONFIG_CAN_SHELL` + * :kconfig:option:`CONFIG_CLOCK_CONTROL_NRF_SHELL` + * :kconfig:option:`CONFIG_DAC_SHELL` + * :kconfig:option:`CONFIG_DEBUG_COREDUMP_SHELL` + * :kconfig:option:`CONFIG_EDAC_SHELL` + * :kconfig:option:`CONFIG_EEPROM_SHELL` + * :kconfig:option:`CONFIG_FLASH_SHELL` + * :kconfig:option:`CONFIG_HWINFO_SHELL` + * :kconfig:option:`CONFIG_I2C_SHELL` + * :kconfig:option:`CONFIG_LOG_CMDS` + * :kconfig:option:`CONFIG_LORA_SHELL` + * :kconfig:option:`CONFIG_MCUBOOT_SHELL` + * :kconfig:option:`CONFIG_MDIO_SHELL` + * :kconfig:option:`CONFIG_OPENTHREAD_SHELL` + * :kconfig:option:`CONFIG_PCIE_SHELL` + * :kconfig:option:`CONFIG_PSCI_SHELL` + * :kconfig:option:`CONFIG_PWM_SHELL` + * :kconfig:option:`CONFIG_REGULATOR_SHELL` + * :kconfig:option:`CONFIG_SENSOR_SHELL` + * :kconfig:option:`CONFIG_SMBUS_SHELL` + * :kconfig:option:`CONFIG_STATS_SHELL` + * :kconfig:option:`CONFIG_USBD_SHELL` + * :kconfig:option:`CONFIG_USBH_SHELL` + * :kconfig:option:`CONFIG_W1_SHELL` + * :kconfig:option:`CONFIG_WDT_SHELL` + Bootloader ========== From 92340883067910b6bfe5b52ab4a6d24b623ddb84 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 15:30:24 +0000 Subject: [PATCH 0654/1049] samples: kscan_touch: drop the kscan_touch sample All in-tree touchscreen drivers have been migrated over to input, the compatibility node has been removed from those boards as well, this sample can be dropped now. Signed-off-by: Fabio Baltieri --- MAINTAINERS.yml | 1 - doc/_scripts/redirects.py | 1 + samples/drivers/kscan_touch/CMakeLists.txt | 8 ----- samples/drivers/kscan_touch/README.rst | 27 -------------- samples/drivers/kscan_touch/prj.conf | 3 -- samples/drivers/kscan_touch/sample.yaml | 14 -------- samples/drivers/kscan_touch/src/main.c | 41 ---------------------- 7 files changed, 1 insertion(+), 94 deletions(-) delete mode 100644 samples/drivers/kscan_touch/CMakeLists.txt delete mode 100644 samples/drivers/kscan_touch/README.rst delete mode 100644 samples/drivers/kscan_touch/prj.conf delete mode 100644 samples/drivers/kscan_touch/sample.yaml delete mode 100644 samples/drivers/kscan_touch/src/main.c diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index b57181967501c33..97d0ec0222faa7e 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1215,7 +1215,6 @@ Release Notes: - include/zephyr/drivers/kscan.h - samples/drivers/espi/ - samples/drivers/kscan/ - - samples/drivers/kscan_touch/ - tests/drivers/kscan/ - tests/drivers/espi/ - dts/bindings/kscan/ diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 8c9120e9899a612..0180d1f5373faf3 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -163,5 +163,6 @@ ('reference/usermode/overview', 'kernel/usermode/overview'), ('reference/usermode/syscalls', 'kernel/usermode/syscalls'), ('reference/util/index', 'kernel/util/index'), + ('samples/drivers/kscan_touch', 'samples/subsys/input/input'), ('samples/net/cloud/google_iot_mqtt', 'samples/net/cloud'), ] diff --git a/samples/drivers/kscan_touch/CMakeLists.txt b/samples/drivers/kscan_touch/CMakeLists.txt deleted file mode 100644 index 1c5812ccffb1de2..000000000000000 --- a/samples/drivers/kscan_touch/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(kscan) - -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) diff --git a/samples/drivers/kscan_touch/README.rst b/samples/drivers/kscan_touch/README.rst deleted file mode 100644 index 52ad2aa7095d315..000000000000000 --- a/samples/drivers/kscan_touch/README.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. zephyr:code-sample:: kscan-touch - :name: KSCAN touch panel - :relevant-api: kscan_interface - - Use the KSCAN API to interface with a touch panel. - -Overview -******** - -This sample demonstrates how to interface with a touch panel. When touches are -detected a log message is output on the console. - -Building and Running -******************** - -The sample can be built and executed on boards with a touch panel for example -stm32f746g_disco or mimxrt1060_evk. The boards dts file should contain an alias -to kscan0 - -Sample output -============= - -.. code-block:: console - - KSCAN test for touch panels. - Note: You are expected to see several callbacks - as you touch the screen. diff --git a/samples/drivers/kscan_touch/prj.conf b/samples/drivers/kscan_touch/prj.conf deleted file mode 100644 index b25816644e92d1b..000000000000000 --- a/samples/drivers/kscan_touch/prj.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_STDOUT_CONSOLE=y -CONFIG_PRINTK=y -CONFIG_KSCAN=y diff --git a/samples/drivers/kscan_touch/sample.yaml b/samples/drivers/kscan_touch/sample.yaml deleted file mode 100644 index b555e9f9901f33c..000000000000000 --- a/samples/drivers/kscan_touch/sample.yaml +++ /dev/null @@ -1,14 +0,0 @@ -sample: - name: KSCAN touch driver api sample -tests: - sample.drivers.kscan_touch: - tags: - - drivers - - kscan_touch - harness: console - harness_config: - type: multi_line - ordered: true - regex: - - "kb data(.*)" - depends_on: kscan:touch diff --git a/samples/drivers/kscan_touch/src/main.c b/samples/drivers/kscan_touch/src/main.c deleted file mode 100644 index cfec920f732d5f3..000000000000000 --- a/samples/drivers/kscan_touch/src/main.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2020 Mark Olsson - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include - -#define LOG_LEVEL LOG_LEVEL_DBG -#include - -LOG_MODULE_REGISTER(main); - -const struct device *const kscan_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_keyboard_scan)); - -static void k_callback(const struct device *dev, uint32_t row, uint32_t col, - bool pressed) -{ - ARG_UNUSED(dev); - if (pressed) { - printk("row = %u col = %u\n", row, col); - } -} - -int main(void) -{ - printk("Kscan touch panel sample application\n"); - - if (!device_is_ready(kscan_dev)) { - LOG_ERR("kscan device %s not ready", kscan_dev->name); - return 0; - } - - kscan_config(kscan_dev, k_callback); - kscan_enable_callback(kscan_dev); - return 0; -} From 9f70cd557bf87cd84a9b19196bcc783e0f595416 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 16 Nov 2023 17:50:00 +0000 Subject: [PATCH 0655/1049] x86: Fix build when optimizations are disabled When building without optimizations and with only one core the linker does not throw away arch_start_cpu and we get an undefined reference to x86_ap_start Signed-off-by: Flavio Ceolin --- arch/x86/core/intel64/cpu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/core/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index a522e87de3a9758..204264cbdf9fe25 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -141,6 +141,7 @@ struct x86_cpuboot x86_cpuboot[] = { void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, arch_cpustart_t fn, void *arg) { +#if CONFIG_MP_MAX_NUM_CPUS > 1 uint8_t vector = ((unsigned long) x86_ap_start) >> 12; uint8_t apic_id; @@ -166,6 +167,13 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, while (x86_cpuboot[cpu_num].ready == 0) { } +#else + ARG_UNUSED(cpu_num); + ARG_UNUSED(stack); + ARG_UNUSED(sz); + ARG_UNUSED(fn); + ARG_UNUSED(arg); +#endif } /* Per-CPU initialization, C domain. On the first CPU, z_x86_prep_c is the From 7d9c0b9db5cdda0d0941176cc8161bda69d91f59 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 16 Nov 2023 13:23:59 -0500 Subject: [PATCH 0656/1049] lib/os/cbprintf: Picolibc doesn't support several cbprintf options * Picolibc doesn't provide the %a-only mode. * On advice from security experts, who report numerous vulnerabilities caused by %n in printf specifiers, picolibc never supports this feature. * Picolibc doesn't use cbprintf for C-library compatible functions, instead it provides aliases for the *printfcb functions using stdio names. Signed-off-by: Keith Packard --- lib/os/Kconfig.cbprintf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/os/Kconfig.cbprintf b/lib/os/Kconfig.cbprintf index 0180c745dc38d1f..93ffa90ca5d7f58 100644 --- a/lib/os/Kconfig.cbprintf +++ b/lib/os/Kconfig.cbprintf @@ -90,6 +90,7 @@ config CBPRINTF_FP_A_SUPPORT config CBPRINTF_FP_ALWAYS_A bool "Select %a format for all floating point specifications" select CBPRINTF_FP_A_SUPPORT + depends on !PICOLIBC help The %a format for floats requires significantly less code than the standard decimal representations (%f, %e, %g). Selecting this @@ -103,10 +104,12 @@ config CBPRINTF_FP_ALWAYS_A config CBPRINTF_N_SPECIFIER bool "Support %n specifications" depends on CBPRINTF_COMPLETE + depends on !PICOLIBC default y help If selected %n can be used to determine the number of characters emitted. If enabled there is a small increase in code size. + Picolibc does not support this feature for security reasons. # 180: 18% / 138 B (180 / 80) [NANO] config CBPRINTF_LIBC_SUBSTS @@ -120,6 +123,9 @@ config CBPRINTF_LIBC_SUBSTS When used with CBPRINTF_NANO this increases the implementation code size by a small amount. + When used with picolibc, this option generates cbprintf-compatible + functions using stdio, effectively inverting the sense above. + module = CBPRINTF_PACKAGE module-str = cbprintf_package source "subsys/logging/Kconfig.template.log_config" From 9369c6f8e1b651f0cda01e8162a02aae291db462 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Thu, 16 Nov 2023 17:02:15 -0600 Subject: [PATCH 0657/1049] rtio: Make coverity happy Coverity reported (rightfully) a possible divide by zero when trying to allocate from a pool. Return -ENOMEM in such scenarios as it means there is no memory to allocate from. Signed-off-by: Tom Burdick --- include/zephyr/rtio/rtio.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/zephyr/rtio/rtio.h b/include/zephyr/rtio/rtio.h index 8ad07281ceef329..fe0f5b72c97bf0b 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -674,6 +674,13 @@ static inline int rtio_block_pool_alloc(struct rtio *r, size_t min_sz, const uint32_t block_size = rtio_mempool_block_size(r); uint32_t bytes = max_sz; + /* Not every context has a block pool and the block size may return 0 in + * that case + */ + if (block_size == 0) { + return -ENOMEM; + } + do { size_t num_blks = DIV_ROUND_UP(bytes, block_size); int rc = sys_mem_blocks_alloc_contiguous(r->block_pool, num_blks, (void **)buf); From 5f1c2f199b63c03ea780acbfbfecdd168f399b4f Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Fri, 17 Nov 2023 09:36:34 +0800 Subject: [PATCH 0658/1049] Bluetooth: Mesh: Make element as rodata the reason is that the Mesh Profile clearly stipulates that Mesh nodes cannot change their own element definitions. Signed-off-by: Lingao Meng --- include/zephyr/bluetooth/mesh/access.h | 26 ++++--- include/zephyr/bluetooth/mesh/health_srv.h | 2 +- samples/bluetooth/mesh/src/main.c | 2 +- samples/bluetooth/mesh_demo/src/main.c | 4 +- samples/bluetooth/mesh_provisioner/src/main.c | 2 +- samples/boards/nrf/mesh/onoff-app/src/main.c | 8 +-- .../src/mesh/device_composition.c | 4 +- .../boards/reel_board/mesh_badge/src/mesh.c | 16 ++--- subsys/bluetooth/mesh/access.c | 70 +++++++++---------- subsys/bluetooth/mesh/access.h | 6 +- subsys/bluetooth/mesh/cfg_srv.c | 40 +++++------ subsys/bluetooth/mesh/health_srv.c | 2 +- subsys/bluetooth/mesh/main.c | 6 +- subsys/bluetooth/mesh/op_agg_cli.c | 2 +- subsys/bluetooth/mesh/shell/shell.c | 6 +- subsys/bluetooth/mesh/shell/utils.c | 2 +- tests/bluetooth/mesh/basic/src/main.c | 2 +- tests/bluetooth/mesh_shell/src/main.c | 2 +- tests/bluetooth/tester/src/btp_mesh.c | 4 +- tests/bsim/bluetooth/mesh/src/mesh_test.c | 2 +- tests/bsim/bluetooth/mesh/src/test_access.c | 2 +- tests/bsim/bluetooth/mesh/src/test_beacon.c | 2 +- tests/bsim/bluetooth/mesh/src/test_blob.c | 8 +-- tests/bsim/bluetooth/mesh/src/test_cdp1.c | 2 +- tests/bsim/bluetooth/mesh/src/test_dfu.c | 16 ++--- tests/bsim/bluetooth/mesh/src/test_lcd.c | 4 +- tests/bsim/bluetooth/mesh/src/test_op_agg.c | 2 +- .../bsim/bluetooth/mesh/src/test_provision.c | 10 +-- tests/bsim/bluetooth/mesh/src/test_sar.c | 2 +- 29 files changed, 130 insertions(+), 126 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index 45042b87d9b8d93..7ae53a7d9ea8177 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -145,19 +145,23 @@ extern "C" { * @param _mods Array of models. * @param _vnd_mods Array of vendor models. */ -#define BT_MESH_ELEM(_loc, _mods, _vnd_mods) \ -{ \ - .loc = (_loc), \ - .model_count = ARRAY_SIZE(_mods), \ - .vnd_model_count = ARRAY_SIZE(_vnd_mods), \ - .models = (_mods), \ - .vnd_models = (_vnd_mods), \ +#define BT_MESH_ELEM(_loc, _mods, _vnd_mods) \ +{ \ + .rt = &(struct bt_mesh_elem_rt_ctx) { 0 }, \ + .loc = (_loc), \ + .model_count = ARRAY_SIZE(_mods), \ + .vnd_model_count = ARRAY_SIZE(_vnd_mods), \ + .models = (_mods), \ + .vnd_models = (_vnd_mods), \ } /** Abstraction that describes a Mesh Element */ struct bt_mesh_elem { - /** Unicast Address. Set at runtime during provisioning. */ - uint16_t addr; + /** Mesh Element runtime information */ + struct bt_mesh_elem_rt_ctx { + /** Unicast Address. Set at runtime during provisioning. */ + uint16_t addr; + } * const rt; /** Location Descriptor (GATT Bluetooth Namespace Descriptors) */ const uint16_t loc; @@ -1001,7 +1005,7 @@ static inline bool bt_mesh_model_pub_is_retransmission(const struct bt_mesh_mode * * @return Pointer to the element that the given model belongs to. */ -struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod); +const struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod); /** @brief Find a SIG model. * @@ -1147,7 +1151,7 @@ struct bt_mesh_comp { uint16_t vid; /**< Version ID */ size_t elem_count; /**< The number of elements in this device. */ - struct bt_mesh_elem *elem; /**< List of elements. */ + const struct bt_mesh_elem *elem; /**< List of elements. */ }; /** Composition data page 2 record. */ diff --git a/include/zephyr/bluetooth/mesh/health_srv.h b/include/zephyr/bluetooth/mesh/health_srv.h index bb1e48004b93648..3eef7e459f70b82 100644 --- a/include/zephyr/bluetooth/mesh/health_srv.h +++ b/include/zephyr/bluetooth/mesh/health_srv.h @@ -219,7 +219,7 @@ struct bt_mesh_health_srv { * * @return 0 on success, or (negative) error code otherwise. */ -int bt_mesh_health_srv_fault_update(struct bt_mesh_elem *elem); +int bt_mesh_health_srv_fault_update(const struct bt_mesh_elem *elem); /** @cond INTERNAL_HIDDEN */ extern const struct bt_mesh_model_op bt_mesh_health_srv_op[]; diff --git a/samples/bluetooth/mesh/src/main.c b/samples/bluetooth/mesh/src/main.c index 5555edef9bbbee3..b220b354fd5c17b 100644 --- a/samples/bluetooth/mesh/src/main.c +++ b/samples/bluetooth/mesh/src/main.c @@ -257,7 +257,7 @@ static const struct bt_mesh_model models[] = { NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, models, BT_MESH_MODEL_NONE), }; diff --git a/samples/bluetooth/mesh_demo/src/main.c b/samples/bluetooth/mesh_demo/src/main.c index 08d6a1aae9b59bf..b405fd062164f8b 100644 --- a/samples/bluetooth/mesh_demo/src/main.c +++ b/samples/bluetooth/mesh_demo/src/main.c @@ -86,7 +86,7 @@ static int vnd_button_pressed(const struct bt_mesh_model *model, { printk("src 0x%04x\n", ctx->addr); - if (ctx->addr == bt_mesh_model_elem(model)->addr) { + if (ctx->addr == bt_mesh_model_elem(model)->rt->addr) { return 0; } @@ -105,7 +105,7 @@ static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(BT_COMP_ID_LF, MOD_LF, vnd_ops, NULL, NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vnd_models), }; diff --git a/samples/bluetooth/mesh_provisioner/src/main.c b/samples/bluetooth/mesh_provisioner/src/main.c index 057087a2e8afa09..472dc020d438ee6 100644 --- a/samples/bluetooth/mesh_provisioner/src/main.c +++ b/samples/bluetooth/mesh_provisioner/src/main.c @@ -59,7 +59,7 @@ static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_HEALTH_CLI(&health_cli), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE), }; diff --git a/samples/boards/nrf/mesh/onoff-app/src/main.c b/samples/boards/nrf/mesh/onoff-app/src/main.c index 71b787fe4979ca0..f0755cb70ab626f 100644 --- a/samples/boards/nrf/mesh/onoff-app/src/main.c +++ b/samples/boards/nrf/mesh/onoff-app/src/main.c @@ -236,7 +236,7 @@ const struct bt_mesh_model *mod_srv_sw[] = { * Root and Secondary Element Declarations */ -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE), BT_MESH_ELEM(0, secondary_0_models, BT_MESH_MODEL_NONE), BT_MESH_ELEM(0, secondary_1_models, BT_MESH_MODEL_NONE), @@ -289,7 +289,7 @@ static int gen_onoff_get(const struct bt_mesh_model *model, struct led_onoff_state *onoff_state = model->rt->user_data; printk("addr 0x%04x onoff 0x%02x\n", - bt_mesh_model_elem(model)->addr, onoff_state->current); + bt_mesh_model_elem(model)->rt->addr, onoff_state->current); bt_mesh_model_msg_init(&msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); net_buf_simple_add_u8(&msg, onoff_state->current); @@ -310,7 +310,7 @@ static int gen_onoff_set_unack(const struct bt_mesh_model *model, onoff_state->current = net_buf_simple_pull_u8(buf); printk("addr 0x%02x state 0x%02x\n", - bt_mesh_model_elem(model)->addr, onoff_state->current); + bt_mesh_model_elem(model)->rt->addr, onoff_state->current); gpio_pin_set_dt(&onoff_state->led_device, onoff_state->current); @@ -361,7 +361,7 @@ static int gen_onoff_status(const struct bt_mesh_model *model, state = net_buf_simple_pull_u8(buf); printk("Node 0x%04x OnOff status from 0x%04x with state 0x%02x\n", - bt_mesh_model_elem(model)->addr, ctx->addr, state); + bt_mesh_model_elem(model)->rt->addr, ctx->addr, state); return 0; } diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c index 775c793bb377ef3..1c59ef8fbd75247 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c @@ -63,7 +63,7 @@ struct vendor_state vnd_user_data; /* Definitions of models user data (End) */ -static struct bt_mesh_elem elements[]; +static const struct bt_mesh_elem elements[]; /* message handlers (Start) */ @@ -3190,7 +3190,7 @@ const struct bt_mesh_model s0_models[] = { NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vnd_models), BT_MESH_ELEM(0, s0_models, BT_MESH_MODEL_NONE), }; diff --git a/samples/boards/reel_board/mesh_badge/src/mesh.c b/samples/boards/reel_board/mesh_badge/src/mesh.c index 61af8cc0b6d3a5e..0b9aff947b0cd8d 100644 --- a/samples/boards/reel_board/mesh_badge/src/mesh.c +++ b/samples/boards/reel_board/mesh_badge/src/mesh.c @@ -187,7 +187,7 @@ static int gen_onoff_get(const struct bt_mesh_model *model, struct led_onoff_state *state = model->rt->user_data; printk("addr 0x%04x onoff 0x%02x\n", - bt_mesh_model_elem(model)->addr, state->current); + bt_mesh_model_elem(model)->rt->addr, state->current); bt_mesh_model_msg_init(&msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); net_buf_simple_add_u8(&msg, state->current); @@ -229,7 +229,7 @@ static int gen_onoff_set_unack(const struct bt_mesh_model *model, state->last_msg_timestamp = now; printk("addr 0x%02x state 0x%02x\n", - bt_mesh_model_elem(model)->addr, state->current); + bt_mesh_model_elem(model)->rt->addr, state->current); if (set_led_state(state->dev_id, onoff)) { printk("Failed to set led state\n"); @@ -404,7 +404,7 @@ static int vnd_hello(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx * printk("Hello message from 0x%04x\n", ctx->addr); - if (ctx->addr == bt_mesh_model_elem(model)->addr) { + if (ctx->addr == bt_mesh_model_elem(model)->rt->addr) { printk("Ignoring message from self\n"); return 0; } @@ -431,7 +431,7 @@ static int vnd_baduser(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx printk("\"Bad user\" message from 0x%04x\n", ctx->addr); - if (ctx->addr == bt_mesh_model_elem(model)->addr) { + if (ctx->addr == bt_mesh_model_elem(model)->rt->addr) { printk("Ignoring message from self\n"); return 0; } @@ -455,7 +455,7 @@ static int vnd_heartbeat(const struct bt_mesh_model *model, uint8_t init_ttl, hops; /* Ignore messages from self */ - if (ctx->addr == bt_mesh_model_elem(model)->addr) { + if (ctx->addr == bt_mesh_model_elem(model)->rt->addr) { return 0; } @@ -495,7 +495,7 @@ static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(BT_COMP_ID_LF, MOD_LF, vnd_ops, &vnd_pub, NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vnd_models), }; @@ -638,12 +638,12 @@ void mesh_start(void) bool mesh_is_initialized(void) { - return elements[0].addr != BT_MESH_ADDR_UNASSIGNED; + return elements[0].rt->addr != BT_MESH_ADDR_UNASSIGNED; } uint16_t mesh_get_addr(void) { - return elements[0].addr; + return elements[0].rt->addr; } int mesh_init(void) diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 4b6a45ae5c83f4f..dcf7f0f783b9945 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -115,7 +115,7 @@ static const struct { }; void bt_mesh_model_foreach(void (*func)(const struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, + const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data), void *user_data) @@ -123,7 +123,7 @@ void bt_mesh_model_foreach(void (*func)(const struct bt_mesh_model *mod, int i, j; for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; + const struct bt_mesh_elem *elem = &dev_comp->elem[i]; for (j = 0; j < elem->model_count; j++) { const struct bt_mesh_model *model = &elem->models[j]; @@ -181,7 +181,7 @@ static void data_buf_add_mem_offset(struct net_buf_simple *buf, uint8_t *data, s *offset = 0; } -static void comp_add_model(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void comp_add_model(const struct bt_mesh_model *mod, const struct bt_mesh_elem *elem, bool vnd, void *user_data) { struct comp_foreach_model_arg *arg = user_data; @@ -197,7 +197,7 @@ static void comp_add_model(const struct bt_mesh_model *mod, struct bt_mesh_elem #if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) static size_t metadata_model_size(const struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, bool vnd) + const struct bt_mesh_elem *elem, bool vnd) { const struct bt_mesh_models_metadata_entry *entry; size_t size = 0; @@ -231,7 +231,7 @@ size_t bt_mesh_metadata_page_0_size(void) comp = bt_mesh_comp_get(); for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; + const struct bt_mesh_elem *elem = &dev_comp->elem[i]; size += sizeof(elem->model_count) + sizeof(elem->vnd_model_count); @@ -253,7 +253,7 @@ size_t bt_mesh_metadata_page_0_size(void) } static int metadata_add_model(const struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, bool vnd, + const struct bt_mesh_elem *elem, bool vnd, void *user_data) { const struct bt_mesh_models_metadata_entry *entry; @@ -310,7 +310,7 @@ int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset) comp = bt_mesh_comp_get(); for (i = 0; i < comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; + const struct bt_mesh_elem *elem = &dev_comp->elem[i]; /* Check that the buffer has available tailroom for metadata item counts */ if (net_buf_simple_tailroom(buf) < (((offset == 0) ? 2 : (offset == 1) ? 1 : 0) @@ -360,7 +360,7 @@ int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset) } #endif -static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem, +static int comp_add_elem(struct net_buf_simple *buf, const struct bt_mesh_elem *elem, size_t *offset) { struct comp_foreach_model_arg arg = { @@ -382,7 +382,7 @@ static int comp_add_elem(struct net_buf_simple *buf, struct bt_mesh_elem *elem, * the element shall not be reported. */ LOG_DBG("Element 0x%04x didn't fit in the Data field", - elem->addr); + elem->rt->addr); return 0; } @@ -577,7 +577,7 @@ static size_t mod_items_size(const struct bt_mesh_model *mod, uint8_t sig_offset return temp_size; } -static size_t page1_elem_size(struct bt_mesh_elem *elem) +static size_t page1_elem_size(const struct bt_mesh_elem *elem) { size_t temp_size = 2; @@ -618,7 +618,7 @@ static int bt_mesh_comp_data_get_page_1(struct net_buf_simple *buf, size_t offse * the element shall not be reported. */ LOG_DBG("Element 0x%04x didn't fit in the Data field", - comp->elem[i].addr); + comp->elem[i].rt->addr); return 0; } @@ -821,7 +821,7 @@ static int publish_transmit(const struct bt_mesh_model *mod) struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_PUB(pub); struct bt_mesh_net_tx tx = { .ctx = &ctx, - .src = bt_mesh_model_elem(mod)->addr, + .src = bt_mesh_model_elem(mod)->rt->addr, .friend_cred = pub->cred, }; @@ -899,14 +899,14 @@ static void mod_publish(struct k_work *work) } } -struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod) +const struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod) { return &dev_comp->elem[mod->rt->elem_idx]; } const struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx) { - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; if (elem_idx >= dev_comp->elem_count) { LOG_ERR("Invalid element index %u", elem_idx); @@ -956,7 +956,7 @@ static int bt_mesh_vnd_mod_msg_cid_check(const struct bt_mesh_model *mod) } #endif -static void mod_init(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void mod_init(const struct bt_mesh_model *mod, const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { int i; @@ -1057,12 +1057,12 @@ void bt_mesh_comp_provision(uint16_t addr) LOG_DBG("addr 0x%04x elem_count %zu", addr, dev_comp->elem_count); for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; + const struct bt_mesh_elem *elem = &dev_comp->elem[i]; - elem->addr = addr++; + elem->rt->addr = addr++; - LOG_DBG("addr 0x%04x mod_count %u vnd_mod_count %u", elem->addr, elem->model_count, - elem->vnd_model_count); + LOG_DBG("addr 0x%04x mod_count %u vnd_mod_count %u", elem->rt->addr, + elem->model_count, elem->vnd_model_count); } } @@ -1073,9 +1073,9 @@ void bt_mesh_comp_unprovision(void) dev_primary_addr = BT_MESH_ADDR_UNASSIGNED; for (int i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; + const struct bt_mesh_elem *elem = &dev_comp->elem[i]; - elem->addr = BT_MESH_ADDR_UNASSIGNED; + elem->rt->addr = BT_MESH_ADDR_UNASSIGNED; } } @@ -1197,7 +1197,7 @@ const uint8_t **bt_mesh_model_find_uuid(const struct bt_mesh_model **mod, const #endif } -static const struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem, +static const struct bt_mesh_model *bt_mesh_elem_find_group(const struct bt_mesh_elem *elem, uint16_t group_addr) { const struct bt_mesh_model *model; @@ -1225,7 +1225,7 @@ static const struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem * return NULL; } -struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) +const struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) { uint16_t index; @@ -1233,7 +1233,7 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) return NULL; } - index = addr - dev_comp->elem[0].addr; + index = addr - dev_comp->elem[0].rt->addr; if (index >= dev_comp->elem_count) { return NULL; } @@ -1254,7 +1254,7 @@ bool bt_mesh_has_addr(uint16_t addr) } for (index = 0; index < dev_comp->elem_count; index++) { - struct bt_mesh_elem *elem = &dev_comp->elem[index]; + const struct bt_mesh_elem *elem = &dev_comp->elem[index]; if (bt_mesh_elem_find_group(elem, addr)) { return true; @@ -1315,7 +1315,7 @@ bool bt_mesh_model_has_key(const struct bt_mesh_model *mod, uint16_t key) static bool model_has_dst(const struct bt_mesh_model *mod, uint16_t dst, const uint8_t *uuid) { if (BT_MESH_ADDR_IS_UNICAST(dst)) { - return (dev_comp->elem[mod->rt->elem_idx].addr == dst); + return (dev_comp->elem[mod->rt->elem_idx].rt->addr == dst); } else if (BT_MESH_ADDR_IS_VIRTUAL(dst)) { return !!bt_mesh_model_find_uuid(&mod, uuid); } else if (BT_MESH_ADDR_IS_GROUP(dst) || @@ -1330,7 +1330,7 @@ static bool model_has_dst(const struct bt_mesh_model *mod, uint16_t dst, const u return mod->rt->elem_idx == 0; } -static const struct bt_mesh_model_op *find_op(struct bt_mesh_elem *elem, +static const struct bt_mesh_model_op *find_op(const struct bt_mesh_elem *elem, uint32_t opcode, const struct bt_mesh_model **model) { uint8_t i; @@ -1415,7 +1415,7 @@ static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode) } static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, - struct bt_mesh_elem *elem, uint32_t opcode) + const struct bt_mesh_elem *elem, uint32_t opcode) { const struct bt_mesh_model_op *op; const struct bt_mesh_model *model; @@ -1424,7 +1424,7 @@ static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple op = find_op(elem, opcode, &model); if (!op) { - LOG_ERR("No OpCode 0x%08x for elem 0x%02x", opcode, elem->addr); + LOG_ERR("No OpCode 0x%08x for elem 0x%02x", opcode, elem->rt->addr); return ACCESS_STATUS_WRONG_OPCODE; } @@ -1479,19 +1479,19 @@ int bt_mesh_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) LOG_DBG("OpCode 0x%08x", opcode); if (BT_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) { - index = ctx->recv_dst - dev_comp->elem[0].addr; + index = ctx->recv_dst - dev_comp->elem[0].rt->addr; if (index >= dev_comp->elem_count) { LOG_ERR("Invalid address 0x%02x", ctx->recv_dst); err = ACCESS_STATUS_INVALID_ADDRESS; } else { - struct bt_mesh_elem *elem = &dev_comp->elem[index]; + const struct bt_mesh_elem *elem = &dev_comp->elem[index]; err = element_model_recv(ctx, buf, elem, opcode); } } else { for (index = 0; index < dev_comp->elem_count; index++) { - struct bt_mesh_elem *elem = &dev_comp->elem[index]; + const struct bt_mesh_elem *elem = &dev_comp->elem[index]; (void)element_model_recv(ctx, buf, elem, opcode); } @@ -1519,7 +1519,7 @@ int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx return -EINVAL; } - return bt_mesh_access_send(ctx, msg, bt_mesh_model_elem(model)->addr, cb, cb_data); + return bt_mesh_access_send(ctx, msg, bt_mesh_model_elem(model)->rt->addr, cb, cb_data); } int bt_mesh_model_publish(const struct bt_mesh_model *model) @@ -2171,7 +2171,7 @@ static void store_pending_mod_pub(const struct bt_mesh_model *mod, bool vnd) } static void store_pending_mod(const struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, bool vnd, + const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { if (!mod->rt->flags) { @@ -2553,7 +2553,7 @@ int bt_mesh_models_metadata_change_prepare(void) #endif } -static void commit_mod(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void commit_mod(const struct bt_mesh_model *mod, const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { if (mod->pub && mod->pub->update && diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index 663f99c84d23881..b7ce1abd0ea3cd3 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -20,7 +20,7 @@ enum { BT_MESH_MOD_DATA_PENDING = BIT(5), }; -void bt_mesh_elem_register(struct bt_mesh_elem *elem, uint8_t count); +void bt_mesh_elem_register(const struct bt_mesh_elem *elem, uint8_t count); uint8_t bt_mesh_elem_count(void); size_t bt_mesh_comp_page_size(uint8_t page); @@ -29,7 +29,7 @@ size_t bt_mesh_metadata_page_0_size(void); int bt_mesh_metadata_get_page_0(struct net_buf_simple *buf, size_t offset); /* Find local element based on unicast address */ -struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); +const struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); bool bt_mesh_has_addr(uint16_t addr); bool bt_mesh_model_has_key(const struct bt_mesh_model *mod, uint16_t key); @@ -43,7 +43,7 @@ uint16_t *bt_mesh_model_find_group(const struct bt_mesh_model **mod, uint16_t ad const uint8_t **bt_mesh_model_find_uuid(const struct bt_mesh_model **mod, const uint8_t *uuid); void bt_mesh_model_foreach(void (*func)(const struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, + const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data), void *user_data); diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 04374977421144b..fa6bb48703a18d5 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -86,7 +86,7 @@ static int dev_comp_data_get(const struct bt_mesh_model *model, return err; } -static const struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, +static const struct bt_mesh_model *get_model(const struct bt_mesh_elem *elem, struct net_buf_simple *buf, bool *vnd) { if (buf->len < 4) { @@ -94,7 +94,7 @@ static const struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, id = net_buf_simple_pull_le16(buf); - LOG_DBG("ID 0x%04x addr 0x%04x", id, elem->addr); + LOG_DBG("ID 0x%04x addr 0x%04x", id, elem->rt->addr); *vnd = false; @@ -105,7 +105,7 @@ static const struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, company = net_buf_simple_pull_le16(buf); id = net_buf_simple_pull_le16(buf); - LOG_DBG("Company 0x%04x ID 0x%04x addr 0x%04x", company, id, elem->addr); + LOG_DBG("Company 0x%04x ID 0x%04x addr 0x%04x", company, id, elem->rt->addr); *vnd = true; @@ -336,7 +336,7 @@ static int app_key_update(const struct bt_mesh_model *model, } static void mod_app_key_del(const struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, bool vnd, bool primary, + const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { uint16_t *app_idx = user_data; @@ -696,7 +696,7 @@ static int mod_pub_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx { uint16_t elem_addr, pub_addr = 0U; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; @@ -749,7 +749,7 @@ static int mod_pub_set(const struct bt_mesh_model *model, uint8_t retransmit, status, pub_ttl, pub_period, cred_flag; uint16_t elem_addr, pub_addr, pub_app_idx; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint8_t *mod_id; bool vnd; @@ -847,7 +847,7 @@ static int mod_pub_va_set(const struct bt_mesh_model *model, uint16_t elem_addr, pub_app_idx; uint16_t pub_addr = 0U; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; const uint8_t *uuid; uint8_t *mod_id; bool vnd; @@ -949,7 +949,7 @@ static int mod_sub_add(const struct bt_mesh_model *model, { uint16_t elem_addr, sub_addr; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint8_t *mod_id; uint8_t status; uint16_t *entry; @@ -1027,7 +1027,7 @@ static int mod_sub_del(const struct bt_mesh_model *model, { uint16_t elem_addr, sub_addr; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint8_t *mod_id; uint16_t *match; uint8_t status; @@ -1109,7 +1109,7 @@ static int mod_sub_overwrite(const struct bt_mesh_model *model, { uint16_t elem_addr, sub_addr; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint8_t *mod_id; uint8_t status; bool vnd; @@ -1179,7 +1179,7 @@ static int mod_sub_del_all(const struct bt_mesh_model *model, struct net_buf_simple *buf) { const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint16_t elem_addr; uint8_t *mod_id; uint8_t status; @@ -1269,7 +1269,7 @@ static int mod_sub_get(const struct bt_mesh_model *model, NET_BUF_SIMPLE_DEFINE(msg, BT_MESH_TX_SDU_MAX); struct mod_sub_list_ctx visit_ctx; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint16_t addr, id; addr = net_buf_simple_pull_le16(buf); @@ -1324,7 +1324,7 @@ static int mod_sub_get_vnd(const struct bt_mesh_model *model, NET_BUF_SIMPLE_DEFINE(msg, BT_MESH_TX_SDU_MAX); struct mod_sub_list_ctx visit_ctx; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint16_t company, addr, id; addr = net_buf_simple_pull_le16(buf); @@ -1383,7 +1383,7 @@ static int mod_sub_va_add(const struct bt_mesh_model *model, const struct bt_mesh_va *va; uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; const uint8_t *uuid; uint8_t *mod_id; uint16_t *group_entry; @@ -1485,7 +1485,7 @@ static int mod_sub_va_del(const struct bt_mesh_model *model, const struct bt_mesh_va *va; uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; const uint8_t *uuid; uint8_t *mod_id; const uint8_t **label_match; @@ -1569,7 +1569,7 @@ static int mod_sub_va_overwrite(const struct bt_mesh_model *model, const struct bt_mesh_va *va; uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; const uint8_t *uuid; uint8_t *mod_id; uint8_t status; @@ -1848,7 +1848,7 @@ static int mod_app_bind(const struct bt_mesh_model *model, BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_APP_STATUS, 9); uint16_t elem_addr, key_app_idx; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; @@ -1912,7 +1912,7 @@ static int mod_app_unbind(const struct bt_mesh_model *model, BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_APP_STATUS, 9); uint16_t elem_addr, key_app_idx; const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; @@ -1974,7 +1974,7 @@ static int mod_app_get(const struct bt_mesh_model *model, BT_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST, 9 + KEY_LIST_LEN))); const struct bt_mesh_model *mod; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; uint8_t *mod_id, status; uint16_t elem_addr; bool vnd; @@ -2529,7 +2529,7 @@ const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb = { .init = cfg_srv_init, }; -static void mod_reset(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void mod_reset(const struct bt_mesh_model *mod, const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { size_t clear_count; diff --git a/subsys/bluetooth/mesh/health_srv.c b/subsys/bluetooth/mesh/health_srv.c index 5292967d4699c8f..8611e1004f63372 100644 --- a/subsys/bluetooth/mesh/health_srv.c +++ b/subsys/bluetooth/mesh/health_srv.c @@ -384,7 +384,7 @@ static int health_pub_update(const struct bt_mesh_model *mod) return 0; } -int bt_mesh_health_srv_fault_update(struct bt_mesh_elem *elem) +int bt_mesh_health_srv_fault_update(const struct bt_mesh_elem *elem) { const struct bt_mesh_model *mod; diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 3aedf19af487f8f..2c78ea227de145a 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -419,7 +419,7 @@ bool bt_mesh_is_provisioned(void) return atomic_test_bit(bt_mesh.flags, BT_MESH_VALID); } -static void model_suspend(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void model_suspend(const struct bt_mesh_model *mod, const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { if (mod->pub && mod->pub->update) { @@ -463,7 +463,7 @@ int bt_mesh_suspend(void) return 0; } -static void model_resume(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void model_resume(const struct bt_mesh_model *mod, const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { if (mod->pub && mod->pub->update) { @@ -552,7 +552,7 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, return 0; } -static void model_start(const struct bt_mesh_model *mod, struct bt_mesh_elem *elem, +static void model_start(const struct bt_mesh_model *mod, const struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { if (mod->cb && mod->cb->start) { diff --git a/subsys/bluetooth/mesh/op_agg_cli.c b/subsys/bluetooth/mesh/op_agg_cli.c index b74b8245cfd56da..1e44ba36f54f22d 100644 --- a/subsys/bluetooth/mesh/op_agg_cli.c +++ b/subsys/bluetooth/mesh/op_agg_cli.c @@ -205,7 +205,7 @@ void bt_mesh_op_agg_cli_timeout_set(int32_t timeout) int bt_mesh_op_agg_cli_send(const struct bt_mesh_model *model, struct net_buf_simple *msg) { - uint16_t src = bt_mesh_model_elem(model)->addr; + uint16_t src = bt_mesh_model_elem(model)->rt->addr; if (net_buf_simple_tailroom(&srcs) < 2) { return -ENOMEM; diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index 3a28829877b6720..a169bb164222755 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -1070,7 +1070,7 @@ static int cmd_rpl_clear(const struct shell *sh, size_t argc, char *argv[]) } #if defined(CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE) -static struct bt_mesh_elem *primary_element(void) +static const struct bt_mesh_elem *primary_element(void) { const struct bt_mesh_comp *comp = bt_mesh_comp_get(); @@ -1085,7 +1085,7 @@ static int cmd_add_fault(const struct shell *sh, size_t argc, char *argv[]) { uint8_t fault_id; uint8_t i; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; int err = 0; elem = primary_element(); @@ -1138,7 +1138,7 @@ static int cmd_del_fault(const struct shell *sh, size_t argc, char *argv[]) { uint8_t fault_id; uint8_t i; - struct bt_mesh_elem *elem; + const struct bt_mesh_elem *elem; int err = 0; elem = primary_element(); diff --git a/subsys/bluetooth/mesh/shell/utils.c b/subsys/bluetooth/mesh/shell/utils.c index 1ccb0e252120708..7ae09f943caf11f 100644 --- a/subsys/bluetooth/mesh/shell/utils.c +++ b/subsys/bluetooth/mesh/shell/utils.c @@ -60,7 +60,7 @@ int bt_mesh_shell_mdl_print_all(const struct shell *sh, uint16_t mod_id) if (mod) { shell_print(sh, "Client model instance found at addr 0x%.4X. Element index: %d", - comp->elem[i].addr, mod->rt->elem_idx); + comp->elem[i].rt->addr, mod->rt->elem_idx); } } diff --git a/tests/bluetooth/mesh/basic/src/main.c b/tests/bluetooth/mesh/basic/src/main.c index 34f94d486c3f70c..d48a012bb2aa47e 100644 --- a/tests/bluetooth/mesh/basic/src/main.c +++ b/tests/bluetooth/mesh/basic/src/main.c @@ -114,7 +114,7 @@ static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(BT_COMP_ID_LF, 0x4321, vnd_ops, &vnd_pub2, NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vnd_models), }; diff --git a/tests/bluetooth/mesh_shell/src/main.c b/tests/bluetooth/mesh_shell/src/main.c index b562e428d11ed0c..f5dbdc41b40558f 100644 --- a/tests/bluetooth/mesh_shell/src/main.c +++ b/tests/bluetooth/mesh_shell/src/main.c @@ -107,7 +107,7 @@ static const struct bt_mesh_model root_models[] = { #endif }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE), }; diff --git a/tests/bluetooth/tester/src/btp_mesh.c b/tests/bluetooth/tester/src/btp_mesh.c index 36e627abe8c2d24..96ce410eed8cfb0 100644 --- a/tests/bluetooth/tester/src/btp_mesh.c +++ b/tests/bluetooth/tester/src/btp_mesh.c @@ -1096,7 +1096,7 @@ static const struct bt_mesh_model vnd_models[] = { NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vnd_models), }; @@ -1739,7 +1739,7 @@ static uint8_t model_send(const void *cmd, uint16_t cmd_len, /* Lookup source address */ for (int i = 0; i < ARRAY_SIZE(model_bound); i++) { - if (bt_mesh_model_elem(model_bound[i].model)->addr == src) { + if (bt_mesh_model_elem(model_bound[i].model)->rt->addr == src) { model = model_bound[i].model; ctx.app_idx = model_bound[i].appkey_idx; diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.c b/tests/bsim/bluetooth/mesh/src/mesh_test.c index ea209d9609c7255..5dce0c8dc9d3b8a 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.c +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.c @@ -204,7 +204,7 @@ static const struct bt_mesh_model vnd_models[] = { const struct bt_mesh_model *test_vnd_model = &vnd_models[0]; -static struct bt_mesh_elem elems[] = { +static const struct bt_mesh_elem elems[] = { BT_MESH_ELEM(0, models, vnd_models), }; diff --git a/tests/bsim/bluetooth/mesh/src/test_access.c b/tests/bsim/bluetooth/mesh/src/test_access.c index 14ee6b03428c56f..b8b10fd7634c1eb 100644 --- a/tests/bsim/bluetooth/mesh/src/test_access.c +++ b/tests/bsim/bluetooth/mesh/src/test_access.c @@ -225,7 +225,7 @@ static const struct bt_mesh_model models_ne[] = { static const struct bt_mesh_model vnd_models[] = {}; -static struct bt_mesh_elem elems[] = { +static const struct bt_mesh_elem elems[] = { BT_MESH_ELEM(0, models, vnd_models), BT_MESH_ELEM(1, models_ne, vnd_models), }; diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index b80d777ba01a8c1..ef1ce8b9f74dc80 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -79,7 +79,7 @@ static struct bt_mesh_priv_beacon_cli priv_beacon_cli; static const struct bt_mesh_comp prb_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), diff --git a/tests/bsim/bluetooth/mesh/src/test_blob.c b/tests/bsim/bluetooth/mesh/src/test_blob.c index f9661fa0be03024..4258ff77c625dc8 100644 --- a/tests/bsim/bluetooth/mesh/src/test_blob.c +++ b/tests/bsim/bluetooth/mesh/src/test_blob.c @@ -233,7 +233,7 @@ static struct bt_mesh_sar_cfg_cli sar_cfg_cli; static const struct bt_mesh_comp srv_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -247,7 +247,7 @@ static const struct bt_mesh_comp srv_comp = { static const struct bt_mesh_comp cli_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -275,7 +275,7 @@ static const struct bt_mesh_model_op model_op1[] = { static const struct bt_mesh_comp none_rsp_srv_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -1328,7 +1328,7 @@ static const struct bt_mesh_model_op model_op2[] = { */ static const struct bt_mesh_comp srv_broken_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), diff --git a/tests/bsim/bluetooth/mesh/src/test_cdp1.c b/tests/bsim/bluetooth/mesh/src/test_cdp1.c index 03b71dce970811f..35befdea95b17c1 100644 --- a/tests/bsim/bluetooth/mesh/src/test_cdp1.c +++ b/tests/bsim/bluetooth/mesh/src/test_cdp1.c @@ -81,7 +81,7 @@ static const struct bt_mesh_model models_vnd1[] = { &test_model_vnd1_cb), }; -static struct bt_mesh_elem elems[] = { +static const struct bt_mesh_elem elems[] = { BT_MESH_ELEM(0, models_1, models_vnd1), BT_MESH_ELEM(1, models_2, BT_MESH_MODEL_NONE), BT_MESH_ELEM(2, models_3, BT_MESH_MODEL_NONE), diff --git a/tests/bsim/bluetooth/mesh/src/test_dfu.c b/tests/bsim/bluetooth/mesh/src/test_dfu.c index 83037ea6e73ad83..06f7248a6adfcec 100644 --- a/tests/bsim/bluetooth/mesh/src/test_dfu.c +++ b/tests/bsim/bluetooth/mesh/src/test_dfu.c @@ -290,7 +290,7 @@ static struct bt_mesh_dfu_srv dfu_srv = BT_MESH_DFU_SRV_INIT(&dfu_handlers, dfu_ static const struct bt_mesh_comp dist_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -304,7 +304,7 @@ static const struct bt_mesh_comp dist_comp = { static const struct bt_mesh_comp dist_comp_self_update = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -325,7 +325,7 @@ static const struct bt_mesh_model_op model_dummy_op[] = { static const struct bt_mesh_comp target_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -941,7 +941,7 @@ static struct bt_mesh_dfu_cli dfu_cli = BT_MESH_DFU_CLI_INIT(&dfu_cli_cb); static const struct bt_mesh_comp cli_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -1326,7 +1326,7 @@ static const struct bt_mesh_model_op model_caps_op1[] = { static const struct bt_mesh_comp srv_caps_broken_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -1357,7 +1357,7 @@ static const struct bt_mesh_model_op model_caps_op2[] = { static const struct bt_mesh_comp broken_target_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -1389,7 +1389,7 @@ static const struct bt_mesh_model_op model_update_get_op1[] = { static const struct bt_mesh_comp srv_update_get_broken_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -1422,7 +1422,7 @@ static const struct bt_mesh_model_op model_update_apply_op1[] = { static const struct bt_mesh_comp srv_update_apply_broken_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), diff --git a/tests/bsim/bluetooth/mesh/src/test_lcd.c b/tests/bsim/bluetooth/mesh/src/test_lcd.c index 337edaddc54d1e3..e1c7adde7308b98 100644 --- a/tests/bsim/bluetooth/mesh/src/test_lcd.c +++ b/tests/bsim/bluetooth/mesh/src/test_lcd.c @@ -107,7 +107,7 @@ static struct bt_mesh_cfg_cli cfg_cli; static struct bt_mesh_large_comp_data_cli lcd_cli; /* Creates enough composition data to send a max SDU comp status message + 1 byte */ -static struct bt_mesh_elem elements_1[] = { +static const struct bt_mesh_elem elements_1[] = { BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), @@ -118,7 +118,7 @@ static struct bt_mesh_elem elements_1[] = { }; /* Creates enough metadata to send a max SDU metadata status message + 1 byte */ -static struct bt_mesh_elem elements_2[] = { +static const struct bt_mesh_elem elements_2[] = { BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), diff --git a/tests/bsim/bluetooth/mesh/src/test_op_agg.c b/tests/bsim/bluetooth/mesh/src/test_op_agg.c index 8735bdf524d3442..fe15219246fd739 100644 --- a/tests/bsim/bluetooth/mesh/src/test_op_agg.c +++ b/tests/bsim/bluetooth/mesh/src/test_op_agg.c @@ -119,7 +119,7 @@ const struct bt_mesh_model_op _dummy_vnd_mod_op[] = { BT_MESH_MODEL_OP_END, }; -static struct bt_mesh_elem elements[] = {BT_MESH_ELEM( +static const struct bt_mesh_elem elements[] = {BT_MESH_ELEM( 0, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_OP_AGG_SRV, BT_MESH_MODEL_OP_AGG_CLI), diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 63b8d89416cfa5f..f2c98778a3b563e 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -118,7 +118,7 @@ static struct bt_mesh_rpr_cli rpr_cli = { static const struct bt_mesh_comp rpr_cli_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&(struct bt_mesh_cfg_cli){}), @@ -130,7 +130,7 @@ static const struct bt_mesh_comp rpr_cli_comp = { static const struct bt_mesh_comp rpr_srv_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_RPR_SRV), @@ -141,7 +141,7 @@ static const struct bt_mesh_comp rpr_srv_comp = { static const struct bt_mesh_comp rpr_cli_srv_comp = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&(struct bt_mesh_cfg_cli){}), @@ -182,7 +182,7 @@ const struct bt_mesh_model_cb mock_model_cb = { static const struct bt_mesh_comp rpr_srv_comp_unresponsive = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CB(IMPOSTER_MODEL_ID, @@ -221,7 +221,7 @@ static const struct bt_mesh_comp2 comp_p2_2 = {.record_cnt = 2, .record = comp_r static const struct bt_mesh_comp rpr_srv_comp_2_elem = { .elem = - (struct bt_mesh_elem[]){ + (const struct bt_mesh_elem[]){ BT_MESH_ELEM(1, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_RPR_SRV), diff --git a/tests/bsim/bluetooth/mesh/src/test_sar.c b/tests/bsim/bluetooth/mesh/src/test_sar.c index 7214366247dd39d..61c7946235d7229 100644 --- a/tests/bsim/bluetooth/mesh/src/test_sar.c +++ b/tests/bsim/bluetooth/mesh/src/test_sar.c @@ -131,7 +131,7 @@ static const struct bt_mesh_model_op _dummy_vnd_mod_op[] = { uint16_t dummy_keys[CONFIG_BT_MESH_MODEL_KEY_COUNT] = { 0 }; -static struct bt_mesh_elem elements[] = {BT_MESH_ELEM( +static const struct bt_mesh_elem elements[] = {BT_MESH_ELEM( 0, MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), From 7fcc3f0696edd251aaa927d533fb9d54839e6dea Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Fri, 17 Nov 2023 10:15:50 +0800 Subject: [PATCH 0659/1049] doc/migartion: Add migration guide for element The Bluetooth Mesh ``element`` declaration has been changed to add prefix ``const``. The ``elem->addr``field has been changed to the new runtime structure, replaced by ``elem->rt->addr``. Signed-off-by: Lingao Meng --- doc/releases/migration-guide-3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index bff8df1770393bf..5728d339984cbb0 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -117,6 +117,9 @@ Bluetooth The ``model->user_data``, ``model->elem_idx`` and ``model->mod_idx`` field has been changed to the new runtime structure, replaced by ``model->rt->user_data``, ``model->rt->elem_idx`` and ``model->rt->mod_idx`` separately. (:github:`65152`) +* The Bluetooth Mesh ``element`` declaration has been changed to add prefix ``const``. + The ``elem->addr`` field has been changed to the new runtime structure, replaced by + ``elem->rt->addr``. (:github:`65388`) LoRaWAN ======= From 1c280c5327697bacc4ad43bd37ce9025835e2b5a Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Fri, 17 Nov 2023 17:18:55 +0800 Subject: [PATCH 0660/1049] Bluetooth: Mesh: Add missing struct name Add name for inner-struct. Signed-off-by: Lingao Meng --- include/zephyr/bluetooth/mesh/access.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index 7ae53a7d9ea8177..817fba918eff3bb 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -30,13 +30,8 @@ #define BT_MESH_MODEL_UUIDS_UNASSIGNED() #endif -#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS -#define BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ - .rt = (void *)(void *[]){ NULL, NULL, (_user_data) }, -#else #define BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ - .rt = (void *)(void *[]){ NULL, (_user_data) }, -#endif + .rt = &(struct bt_mesh_model_rt_ctx){ .user_data = (_user_data) }, /** * @brief Access layer @@ -890,7 +885,7 @@ struct bt_mesh_model { }; /* Model runtime information */ - struct { + struct bt_mesh_model_rt_ctx { uint8_t elem_idx; /* Belongs to Nth element */ uint8_t mod_idx; /* Is the Nth model in the element */ uint16_t flags; /* Model flags for internal bookkeeping */ From 8861bc0671ec3ba780f9c7cacbdaa329ddee5203 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Fri, 17 Nov 2023 09:13:49 +0100 Subject: [PATCH 0661/1049] modules: lvgl: Force fullsize render buffer on full refresh Changes the default of `LV_Z_VDB_SIZE` to 100 percent if `LV_Z_FULL_REFRESH` is set. Reason is that LVGL will reset the full refresh flag if the buffer is not equal to the screen size. Signed-off-by: Fabian Blatz --- modules/lvgl/Kconfig.memory | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/lvgl/Kconfig.memory b/modules/lvgl/Kconfig.memory index efd74540466789a..fc59eccb2e3849c 100644 --- a/modules/lvgl/Kconfig.memory +++ b/modules/lvgl/Kconfig.memory @@ -40,6 +40,7 @@ config LV_Z_MEM_POOL_SIZE config LV_Z_VDB_SIZE int "Rendering buffer size" + default 100 if LV_Z_FULL_REFRESH default 10 range 1 100 help From 79c677c0ef37e81298ce9afe795989f5c21d9c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 10:30:06 +0100 Subject: [PATCH 0662/1049] net: lib: coap: Fix NULL pointer dereference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As reported by Coverity, cpkt was being used before checking it's not NULL. Fixes #65372 / CID: 323075 Signed-off-by: Benjamin Cabé --- subsys/net/lib/coap/coap.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 3ecc077aa64f450..9fe62730b472fd0 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -658,10 +658,10 @@ static int remove_middle_option(struct coap_packet *cpkt, } int coap_packet_remove_option(struct coap_packet *cpkt, uint16_t code) { - uint16_t offset = cpkt->hdr_len; + uint16_t offset = 0; uint16_t opt_delta = 0; uint16_t opt_len = 0; - uint16_t previous_offset = cpkt->hdr_len; + uint16_t previous_offset = 0; uint16_t previous_code = 0; struct coap_option option; int r; @@ -678,6 +678,9 @@ int coap_packet_remove_option(struct coap_packet *cpkt, uint16_t code) return 0; } + offset = cpkt->hdr_len; + previous_offset = cpkt->hdr_len; + /* Find the requested option */ while (offset < cpkt->hdr_len + cpkt->opt_len) { r = parse_option(cpkt->data, offset, &offset, cpkt->hdr_len + cpkt->opt_len, From e702ecc8fb18adc0507ac7f9315ab32054a04751 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 17 Nov 2023 10:10:48 +0100 Subject: [PATCH 0663/1049] net: dhcpv6: Verify net_pkt_skip() return value Verify the return value of net_pkt_skip() function, in case the parser ignores the unrecognized options, so that in case the option was malformed and the actual provided option length exceeds the packet length, it is recognize (net_pkt_skip() should fail then). Signed-off-by: Robert Lubos --- subsys/net/ip/dhcpv6.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/subsys/net/ip/dhcpv6.c b/subsys/net/ip/dhcpv6.c index 3d464c92954e3e1..5e596a95e5b2b43 100644 --- a/subsys/net/ip/dhcpv6.c +++ b/subsys/net/ip/dhcpv6.c @@ -892,8 +892,13 @@ static int dhcpv6_parse_option_iaaddr(struct net_pkt *pkt, uint16_t length, break; default: - net_pkt_skip(pkt, sublen); NET_DBG("Unexpected option %d length %d", code, sublen); + + ret = net_pkt_skip(pkt, sublen); + if (ret < 0) { + return ret; + } + break; } @@ -980,8 +985,13 @@ static int dhcpv6_parse_option_ia_na(struct net_pkt *pkt, uint16_t length, break; default: - net_pkt_skip(pkt, sublen); NET_DBG("Unexpected option %d length %d", code, sublen); + + ret = net_pkt_skip(pkt, sublen); + if (ret < 0) { + return ret; + } + break; } @@ -1058,8 +1068,13 @@ static int dhcpv6_parse_option_iaprefix(struct net_pkt *pkt, uint16_t length, break; default: - net_pkt_skip(pkt, sublen); NET_DBG("Unexpected option %d length %d", code, sublen); + + ret = net_pkt_skip(pkt, sublen); + if (ret < 0) { + return ret; + } + break; } @@ -1145,8 +1160,13 @@ static int dhcpv6_parse_option_ia_pd(struct net_pkt *pkt, uint16_t length, break; default: - net_pkt_skip(pkt, sublen); NET_DBG("Unexpected option %d length %d", code, sublen); + + ret = net_pkt_skip(pkt, sublen); + if (ret < 0) { + return ret; + } + break; } @@ -1161,6 +1181,7 @@ static int dhcpv6_find_option(struct net_pkt *pkt, enum dhcpv6_option_code opt_c { uint16_t length; uint16_t code; + int ret; while (net_pkt_read_be16(pkt, &code) == 0) { if (net_pkt_read_be16(pkt, &length) < 0) { @@ -1172,7 +1193,10 @@ static int dhcpv6_find_option(struct net_pkt *pkt, enum dhcpv6_option_code opt_c return 0; } - net_pkt_skip(pkt, length); + ret = net_pkt_skip(pkt, length); + if (ret < 0) { + return ret; + } } return -ENOENT; From f3b85ad92c69d87a7b87ee2c214aab447f33d3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 10:59:21 +0100 Subject: [PATCH 0664/1049] drivers: modem: fix for possible non-null terminated string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix handling of strncpy in cgnsinf parsing function to avoid potentially getting a non-null terminated string. Fixes #58573 / CID: 248403 Signed-off-by: Benjamin Cabé --- drivers/modem/simcom-sim7080.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/modem/simcom-sim7080.c b/drivers/modem/simcom-sim7080.c index b6a159e519da4c3..f0b31a1d1b686c7 100644 --- a/drivers/modem/simcom-sim7080.c +++ b/drivers/modem/simcom-sim7080.c @@ -1466,7 +1466,7 @@ static int parse_cgnsinf(char *gps_buf) gnss_data.run_status = 1; gnss_data.fix_status = 1; - strncpy(gnss_data.utc, utc, sizeof(gnss_data.utc)); + strncpy(gnss_data.utc, utc, sizeof(gnss_data.utc) - 1); ret = gnss_split_on_dot(lat, &number, &fraction); if (ret != 0) { From 6a5d082cc5aaeb486ddfd89c36736e6624cd7949 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Fri, 17 Nov 2023 09:33:16 +0100 Subject: [PATCH 0665/1049] Bluetooth: Mesh: Ignore return value of settings_delete This suppresses warning from Coverity. Coverity-CID: 330638 Fixes #65330 Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/dfu_slot.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/mesh/dfu_slot.c b/subsys/bluetooth/mesh/dfu_slot.c index 097d5abcc82238b..c11c16d44fcf677 100644 --- a/subsys/bluetooth/mesh/dfu_slot.c +++ b/subsys/bluetooth/mesh/dfu_slot.c @@ -95,9 +95,9 @@ static void slot_erase(struct slot *slot_to_erase) uint16_t idx = ARRAY_INDEX(slots, slot_to_erase); char buf[SLOT_ENTRY_BUFLEN]; - settings_delete(slot_entry_encode(idx, buf, PROP_HEADER)); - settings_delete(slot_entry_encode(idx, buf, PROP_FWID)); - settings_delete(slot_entry_encode(idx, buf, PROP_METADATA)); + (void)settings_delete(slot_entry_encode(idx, buf, PROP_HEADER)); + (void)settings_delete(slot_entry_encode(idx, buf, PROP_FWID)); + (void)settings_delete(slot_entry_encode(idx, buf, PROP_METADATA)); } static void slot_index_defrag(void) From b15611eb28cf4e187453cdd5eaf911d4abbf65df Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Fri, 17 Nov 2023 09:40:25 +0100 Subject: [PATCH 0666/1049] Bluetooth: Mesh: Check return value of bt_conn_get_info Coverity-CID: 323094 Fixes #65366 Coverity-CID: 323081 Fixes #65370 Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/gatt_cli.c | 9 +++++---- subsys/bluetooth/mesh/pb_gatt_srv.c | 14 ++++++++------ subsys/bluetooth/mesh/proxy_srv.c | 14 ++++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/subsys/bluetooth/mesh/gatt_cli.c b/subsys/bluetooth/mesh/gatt_cli.c index 59407458de24630..bff9b567011d209 100644 --- a/subsys/bluetooth/mesh/gatt_cli.c +++ b/subsys/bluetooth/mesh/gatt_cli.c @@ -176,8 +176,8 @@ static void gatt_connected(struct bt_conn *conn, uint8_t conn_err) struct bt_conn_info info; int err; - bt_conn_get_info(conn, &info); - if (info.role != BT_CONN_ROLE_CENTRAL || + err = bt_conn_get_info(conn, &info); + if (err || info.role != BT_CONN_ROLE_CENTRAL || !server->gatt) { return; } @@ -214,9 +214,10 @@ static void gatt_disconnected(struct bt_conn *conn, uint8_t reason) { struct bt_conn_info info; struct bt_mesh_gatt_server *server = get_server(conn); + int err; - bt_conn_get_info(conn, &info); - if (info.role != BT_CONN_ROLE_CENTRAL || + err = bt_conn_get_info(conn, &info); + if (err || info.role != BT_CONN_ROLE_CENTRAL || !server->gatt) { return; } diff --git a/subsys/bluetooth/mesh/pb_gatt_srv.c b/subsys/bluetooth/mesh/pb_gatt_srv.c index d5ad2f9711d101a..f6d9298fc78221c 100644 --- a/subsys/bluetooth/mesh/pb_gatt_srv.c +++ b/subsys/bluetooth/mesh/pb_gatt_srv.c @@ -94,27 +94,29 @@ static ssize_t gatt_recv(struct bt_conn *conn, return bt_mesh_proxy_msg_recv(conn, buf, len); } -static void gatt_connected(struct bt_conn *conn, uint8_t err) +static void gatt_connected(struct bt_conn *conn, uint8_t conn_err) { struct bt_conn_info info; + int err; - bt_conn_get_info(conn, &info); - if (info.role != BT_CONN_ROLE_PERIPHERAL || !service_registered || + err = bt_conn_get_info(conn, &info); + if (err || info.role != BT_CONN_ROLE_PERIPHERAL || !service_registered || bt_mesh_is_provisioned() || info.id != BT_ID_DEFAULT || cli) { return; } cli = bt_mesh_proxy_role_setup(conn, gatt_send, proxy_msg_recv); - LOG_DBG("conn %p err 0x%02x", (void *)conn, err); + LOG_DBG("conn %p err 0x%02x", (void *)conn, conn_err); } static void gatt_disconnected(struct bt_conn *conn, uint8_t reason) { struct bt_conn_info info; + int err; - bt_conn_get_info(conn, &info); - if (info.role != BT_CONN_ROLE_PERIPHERAL || !service_registered || + err = bt_conn_get_info(conn, &info); + if (err || info.role != BT_CONN_ROLE_PERIPHERAL || !service_registered || info.id != BT_ID_DEFAULT || !cli || cli->conn != conn) { return; } diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 2943afdca93c4dc..3a2bad0851ec23d 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -1057,18 +1057,19 @@ static void solicitation_reset(struct bt_mesh_subnet *sub) #endif } -static void gatt_connected(struct bt_conn *conn, uint8_t err) +static void gatt_connected(struct bt_conn *conn, uint8_t conn_err) { struct bt_mesh_proxy_client *client; struct bt_conn_info info; + int err; - bt_conn_get_info(conn, &info); - if (info.role != BT_CONN_ROLE_PERIPHERAL || !service_registered || + err = bt_conn_get_info(conn, &info); + if (err || info.role != BT_CONN_ROLE_PERIPHERAL || !service_registered || info.id != BT_ID_DEFAULT) { return; } - LOG_DBG("conn %p err 0x%02x", (void *)conn, err); + LOG_DBG("conn %p err 0x%02x", (void *)conn, conn_err); client = find_client(conn); @@ -1107,9 +1108,10 @@ static void gatt_disconnected(struct bt_conn *conn, uint8_t reason) { struct bt_conn_info info; struct bt_mesh_proxy_client *client; + int err; - bt_conn_get_info(conn, &info); - if (info.role != BT_CONN_ROLE_PERIPHERAL || info.id != BT_ID_DEFAULT) { + err = bt_conn_get_info(conn, &info); + if (err || info.role != BT_CONN_ROLE_PERIPHERAL || info.id != BT_ID_DEFAULT) { return; } From 3bc17d1d18d778ee90ebd98a8001c5384502bb28 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Fri, 17 Nov 2023 10:27:22 +0100 Subject: [PATCH 0667/1049] Bluetooth: Mesh: Fix async behavior of Private Beacon Client API The Private Beacon Client API requires a response argument to allow to call the API in the asynchronous manner (https://github.com/zephyrproject-rtos/zephyr/pull/56426). Because the removal of the EXPERIMENTAL tag for this API was not released yet, it should be OK to change this API. The EXPERIMENTAL tag has been removed here: https://github.com/zephyrproject-rtos/zephyr/pull/64866 Coverity-CID: 330039 Coverity-CID: 330029 Coverity-CID: 329977 Fixes #65336 Fixes #65338 Fixes #65354 Signed-off-by: Pavel Vasilyev --- .../zephyr/bluetooth/mesh/priv_beacon_cli.h | 31 ++++++++++++++----- subsys/bluetooth/mesh/priv_beacon_cli.c | 29 +++++++++-------- subsys/bluetooth/mesh/shell/priv_beacon.c | 6 ++-- tests/bluetooth/tester/src/btp_mesh.c | 6 ++-- tests/bsim/bluetooth/mesh/src/test_beacon.c | 14 ++++----- .../bluetooth/mesh/src/test_persistence.c | 6 ++-- 6 files changed, 56 insertions(+), 36 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/priv_beacon_cli.h b/include/zephyr/bluetooth/mesh/priv_beacon_cli.h index 24fba6f67be68e8..ac77b45839fddfb 100644 --- a/include/zephyr/bluetooth/mesh/priv_beacon_cli.h +++ b/include/zephyr/bluetooth/mesh/priv_beacon_cli.h @@ -101,14 +101,20 @@ struct bt_mesh_priv_beacon_cli { /** @brief Set the target's Private Beacon state. * + * This method can be used asynchronously by setting @p rsp as NULL. + * This way the method will not wait for response and will return + * immediately after sending the command. + * @param net_idx Network index to encrypt with. * @param addr Target node address. - * @param val New Private Beacon value. Returns response status on success. + * @param val New Private Beacon value. + * @param rsp If set, returns response status on success. * * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr, - struct bt_mesh_priv_beacon *val); + struct bt_mesh_priv_beacon *val, + struct bt_mesh_priv_beacon *rsp); /** @brief Get the target's Private Beacon state. * @@ -122,16 +128,20 @@ int bt_mesh_priv_beacon_cli_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val); /** @brief Set the target's Private GATT Proxy state. + * + * This method can be used asynchronously by setting @p rsp as NULL. + * This way the method will not wait for response and will return + * immediately after sending the command. * * @param net_idx Network index to encrypt with. * @param addr Target node address. - * @param val New Private GATT Proxy value. Returns response status on - * success. + * @param val New Private GATT Proxy value. + * @param rsp If set, returns response status on success. * * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx, uint16_t addr, - uint8_t *val); + uint8_t val, uint8_t *rsp); /** @brief Get the target's Private GATT Proxy state. * @@ -145,16 +155,21 @@ int bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *val); /** @brief Set the target's Private Node Identity state. + * + * This method can be used asynchronously by setting @p rsp as NULL. + * This way the method will not wait for response and will return + * immediately after sending the command. * * @param net_idx Network index to encrypt with. * @param addr Target node address. - * @param val New Private Node Identity value. Returns response status on - * success. + * @param val New Private Node Identity value. + * @param rsp If set, returns response status on success. * * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx, uint16_t addr, - struct bt_mesh_priv_node_id *val); + struct bt_mesh_priv_node_id *val, + struct bt_mesh_priv_node_id *rsp); /** @brief Get the target's Private Node Identity state. * diff --git a/subsys/bluetooth/mesh/priv_beacon_cli.c b/subsys/bluetooth/mesh/priv_beacon_cli.c index 0611aeb77057155..7d679f0e3227810 100644 --- a/subsys/bluetooth/mesh/priv_beacon_cli.c +++ b/subsys/bluetooth/mesh/priv_beacon_cli.c @@ -156,13 +156,14 @@ const struct bt_mesh_model_cb bt_mesh_priv_beacon_cli_cb = { .init = priv_beacon_cli_init, }; -int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val) +int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val, + struct bt_mesh_priv_beacon *rsp) { struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr); const struct bt_mesh_msg_rsp_ctx rsp_ctx = { .ack = &cli->ack_ctx, .op = OP_PRIV_BEACON_STATUS, - .user_data = val, + .user_data = rsp, .timeout = msg_timeout, }; @@ -174,7 +175,7 @@ int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr, struct bt_mesh_ net_buf_simple_add_u8(&buf, val->rand_interval); } - return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL); + return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, rsp ? &rsp_ctx : NULL); } int bt_mesh_priv_beacon_cli_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val) @@ -193,27 +194,28 @@ int bt_mesh_priv_beacon_cli_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_ return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL); } -int bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx, uint16_t addr, uint8_t *val) +int bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx, uint16_t addr, uint8_t val, + uint8_t *rsp) { struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr); const struct bt_mesh_msg_rsp_ctx rsp_ctx = { .ack = &cli->ack_ctx, .op = OP_PRIV_GATT_PROXY_STATUS, - .user_data = val, + .user_data = rsp, .timeout = msg_timeout, }; - if (!val || (*val != BT_MESH_GATT_PROXY_DISABLED && - *val != BT_MESH_GATT_PROXY_ENABLED)) { + if ((val != BT_MESH_GATT_PROXY_DISABLED && + val != BT_MESH_GATT_PROXY_ENABLED)) { return -EINVAL; } BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_SET, 1); bt_mesh_model_msg_init(&buf, OP_PRIV_GATT_PROXY_SET); - net_buf_simple_add_u8(&buf, *val); + net_buf_simple_add_u8(&buf, val); - return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL); + return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, rsp ? &rsp_ctx : NULL); } int bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *val) @@ -233,17 +235,18 @@ int bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint } int bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx, uint16_t addr, - struct bt_mesh_priv_node_id *val) + struct bt_mesh_priv_node_id *val, + struct bt_mesh_priv_node_id *rsp) { struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr); const struct bt_mesh_msg_rsp_ctx rsp_ctx = { .ack = &cli->ack_ctx, .op = OP_PRIV_NODE_ID_STATUS, - .user_data = val, + .user_data = rsp, .timeout = msg_timeout, }; - if (!val || val->net_idx > 0xfff || + if (val->net_idx > 0xfff || (val->state != BT_MESH_NODE_IDENTITY_STOPPED && val->state != BT_MESH_NODE_IDENTITY_RUNNING)) { return -EINVAL; @@ -255,7 +258,7 @@ int bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx, uint16_t addr, net_buf_simple_add_le16(&buf, val->net_idx); net_buf_simple_add_u8(&buf, val->state); - return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL); + return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, rsp ? &rsp_ctx : NULL); } int bt_mesh_priv_beacon_cli_node_id_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, diff --git a/subsys/bluetooth/mesh/shell/priv_beacon.c b/subsys/bluetooth/mesh/shell/priv_beacon.c index 296d96b114ea1ca..71b0da91e503f59 100644 --- a/subsys/bluetooth/mesh/shell/priv_beacon.c +++ b/subsys/bluetooth/mesh/shell/priv_beacon.c @@ -48,7 +48,7 @@ static int cmd_priv_beacon_set(const struct shell *sh, size_t argc, char *argv[] err = bt_mesh_priv_beacon_cli_set(bt_mesh_shell_target_ctx.net_idx, bt_mesh_shell_target_ctx.dst, - &val); + &val, &val); if (err) { shell_error(sh, "Failed to send Private Beacon Set (err %d)", err); return 0; @@ -86,7 +86,7 @@ static int cmd_priv_gatt_proxy_set(const struct shell *sh, size_t argc, char *ar } err = bt_mesh_priv_beacon_cli_gatt_proxy_set(bt_mesh_shell_target_ctx.net_idx, - bt_mesh_shell_target_ctx.dst, &state); + bt_mesh_shell_target_ctx.dst, state, &state); if (err) { shell_error(sh, "Failed to send Private GATT Proxy Set (err %d)", err); return 0; @@ -130,7 +130,7 @@ static int cmd_priv_node_id_set(const struct shell *sh, size_t argc, char *argv[ } err = bt_mesh_priv_beacon_cli_node_id_set(bt_mesh_shell_target_ctx.net_idx, - bt_mesh_shell_target_ctx.dst, &val); + bt_mesh_shell_target_ctx.dst, &val, &val); if (err) { shell_error(sh, "Failed to send Private Node Identity Set (err %d)", err); return 0; diff --git a/tests/bluetooth/tester/src/btp_mesh.c b/tests/bluetooth/tester/src/btp_mesh.c index 96ce410eed8cfb0..ab5fcf515bd1baa 100644 --- a/tests/bluetooth/tester/src/btp_mesh.c +++ b/tests/bluetooth/tester/src/btp_mesh.c @@ -820,7 +820,7 @@ static uint8_t priv_beacon_set(const void *cmd, uint16_t cmd_len, val.enabled = cp->enabled; val.rand_interval = cp->rand_interval; - err = bt_mesh_priv_beacon_cli_set(net.net_idx, cp->dst, &val); + err = bt_mesh_priv_beacon_cli_set(net.net_idx, cp->dst, &val, &val); if (err) { LOG_ERR("Failed to send Private Beacon Set (err %d)", err); return BTP_STATUS_FAILED; @@ -857,7 +857,7 @@ static uint8_t priv_gatt_proxy_set(const void *cmd, uint16_t cmd_len, state = cp->state; - err = bt_mesh_priv_beacon_cli_gatt_proxy_set(net.net_idx, cp->dst, &state); + err = bt_mesh_priv_beacon_cli_gatt_proxy_set(net.net_idx, cp->dst, state, &state); if (err) { LOG_ERR("Failed to send Private GATT Proxy Set (err %d)", err); return BTP_STATUS_FAILED; @@ -896,7 +896,7 @@ static uint8_t priv_node_id_set(const void *cmd, uint16_t cmd_len, val.net_idx = cp->net_idx; val.state = cp->state; - err = bt_mesh_priv_beacon_cli_node_id_set(net.net_idx, cp->dst, &val); + err = bt_mesh_priv_beacon_cli_node_id_set(net.net_idx, cp->dst, &val, &val); if (err) { LOG_ERR("Failed to send Private Node Identity Set (err %d)", err); return BTP_STATUS_FAILED; diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index ef1ce8b9f74dc80..e93c2301e46d21d 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -1131,7 +1131,7 @@ static void tx_priv_setup(void) FAIL("Beacon set failed (err %d, status %u)", err, status); } - err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val); + err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); if (err) { FAIL("Failed to enable Private Beacon (err=%d)", err); } @@ -1169,7 +1169,7 @@ static void test_tx_priv_adv(void) val.enabled = 1; val.rand_interval = 1; - err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val); + err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); if (err) { FAIL("Failed to enable Private Beacon (err=%d)", err); } @@ -1178,7 +1178,7 @@ static void test_tx_priv_adv(void) val.rand_interval = 0; - err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val); + err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); if (err) { FAIL("Failed to enable Private Beacon (err=%d)", err); } @@ -1187,7 +1187,7 @@ static void test_tx_priv_adv(void) val.rand_interval = 0; - err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val); + err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); if (err) { FAIL("Failed to enable Private Beacon (err=%d)", err); } @@ -1196,7 +1196,7 @@ static void test_tx_priv_adv(void) val.rand_interval = 3; - err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val); + err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); if (err) { FAIL("Failed to enable Private Beacon (err=%d)", err); } @@ -1328,7 +1328,7 @@ static void test_rx_priv_invalid(void) FAIL("Beacon set failed (err %d, status %u)", err, status); } - err = bt_mesh_priv_beacon_cli_set(0, rx_cfg.addr, &val); + err = bt_mesh_priv_beacon_cli_set(0, rx_cfg.addr, &val, &val); if (err) { FAIL("Failed to enable Private Beacon (err=%d)", err); } @@ -1361,7 +1361,7 @@ static void toggle_priv_beacon(uint16_t addr, uint8_t enabled) val.enabled = enabled; val.rand_interval = 1; - err = bt_mesh_priv_beacon_cli_set(0, addr, &val); + err = bt_mesh_priv_beacon_cli_set(0, addr, &val, &val); if (err) { FAIL("Failed to enable Private Beacon (err=%d)", err); } diff --git a/tests/bsim/bluetooth/mesh/src/test_persistence.c b/tests/bsim/bluetooth/mesh/src/test_persistence.c index df3eaa19989cc1e..4bf1f9faa936b3c 100644 --- a/tests/bsim/bluetooth/mesh/src/test_persistence.c +++ b/tests/bsim/bluetooth/mesh/src/test_persistence.c @@ -953,14 +953,16 @@ static void test_cfg_save(void) .rand_interval = current_stack_cfg->priv_beacon_int, }; - err = bt_mesh_priv_beacon_cli_set(test_netkey_idx, TEST_ADDR, &priv_beacon_state); + err = bt_mesh_priv_beacon_cli_set(test_netkey_idx, TEST_ADDR, &priv_beacon_state, + &priv_beacon_state); if (err) { FAIL("Failed to enable Private Beacon (err %d)", err); } uint8_t priv_beacon_gatt = current_stack_cfg->priv_beacon_gatt; - err = bt_mesh_priv_beacon_cli_gatt_proxy_set(test_netkey_idx, TEST_ADDR, &priv_beacon_gatt); + err = bt_mesh_priv_beacon_cli_gatt_proxy_set(test_netkey_idx, TEST_ADDR, priv_beacon_gatt, + &priv_beacon_gatt); if (err) { FAIL("Failed to enable Private Beacon GATT proxy (err %d)", err); } From 07848a4456b035b08a41218dcb98f3f7db359a2e Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Fri, 17 Nov 2023 11:14:48 +0100 Subject: [PATCH 0668/1049] Bluetooth: Mesh: Fix integer overflow Fix potential integer overflow by casting one of operands to int64_t. Coverity-CID: 329961 Fixes #65356 Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/proxy_srv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 3a2bad0851ec23d..571144ceaedd08f 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -697,7 +697,8 @@ static void gatt_proxy_solicited(struct bt_mesh_subnet *sub) int32_t remaining; if (sub->priv_net_id_sent > 0) { - timeout = sub->priv_net_id_sent + MSEC_PER_SEC * bt_mesh_od_priv_proxy_get(); + timeout = sub->priv_net_id_sent + + MSEC_PER_SEC * (int64_t) bt_mesh_od_priv_proxy_get(); remaining = MIN(timeout - now, INT32_MAX); } else { remaining = MSEC_PER_SEC * bt_mesh_od_priv_proxy_get(); From 4f1823c61636a69964b6d0c3305e9874ee52264a Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 17 Nov 2023 09:59:55 +0100 Subject: [PATCH 0669/1049] soc: arm: nordic_nrf: Add Kconfig symbol for new I2S instance Add I2S 20 instance Signed-off-by: Adam Wojasinski --- soc/arm/nordic_nrf/Kconfig.peripherals | 3 +++ 1 file changed, 3 insertions(+) diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/arm/nordic_nrf/Kconfig.peripherals index 285b92d3dda6371..3aacc35a08a0806 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/arm/nordic_nrf/Kconfig.peripherals @@ -75,6 +75,9 @@ config HAS_HW_NRF_GPIOTE config HAS_HW_NRF_I2S0 def_bool $(dt_nodelabel_enabled_with_compat,i2s0,$(DT_COMPAT_NORDIC_NRF_I2S)) +config HAS_HW_NRF_I2S20 + def_bool $(dt_nodelabel_enabled_with_compat,i2s20,$(DT_COMPAT_NORDIC_NRF_I2S)) + config HAS_HW_NRF_IPC def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_IPC)) From cac170d2b9c49943347b8288175bd5784b2b5bd7 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 17 Nov 2023 10:16:23 +0100 Subject: [PATCH 0670/1049] modules: hal_nordic: Add I2S Kconfig symbols and translation to nrfx Add Kconfig symbols for I2S 20 instance and translation symbols used in nrfx drivers. Signed-off-by: Adam Wojasinski --- modules/hal_nordic/nrfx/Kconfig | 5 +++++ modules/hal_nordic/nrfx/nrfx_config.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index 53a77e601752778..5dcda73c9be97f0 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -82,6 +82,11 @@ config NRFX_I2S0 depends on $(dt_nodelabel_has_compat,i2s0,$(DT_COMPAT_NORDIC_NRF_I2S)) select NRFX_I2S +config NRFX_I2S20 + bool "I2S20 driver instance" + depends on $(dt_nodelabel_has_compat,i2s20,$(DT_COMPAT_NORDIC_NRF_I2S)) + select NRFX_I2S + config NRFX_IPC bool "IPC driver" depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_IPC)) diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index f799c4207d550c5..aaf3175100422b7 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -141,6 +141,9 @@ #ifdef CONFIG_NRFX_I2S0 #define NRFX_I2S0_ENABLED 1 #endif +#ifdef CONFIG_NRFX_I2S20 +#define NRFX_I2S20_ENABLED 1 +#endif #ifdef CONFIG_NRFX_IPC #define NRFX_IPC_ENABLED 1 From dd36592aa47208903123c92808fd9078c11e25f2 Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Thu, 24 Aug 2023 15:50:55 +0200 Subject: [PATCH 0671/1049] drivers: i2s: i2s_nrfx: Add support for new instance Add support for new I2S 20 instance. Signed-off-by: Adam Kondraciuk --- drivers/i2s/Kconfig.nrfx | 1 + drivers/i2s/i2s_nrfx.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/i2s/Kconfig.nrfx b/drivers/i2s/Kconfig.nrfx index 1cb023a2b2ea540..b36f3eb9c641eea 100644 --- a/drivers/i2s/Kconfig.nrfx +++ b/drivers/i2s/Kconfig.nrfx @@ -6,6 +6,7 @@ menuconfig I2S_NRFX default y depends on DT_HAS_NORDIC_NRF_I2S_ENABLED select NRFX_I2S0 if HAS_HW_NRF_I2S0 + select NRFX_I2S20 if HAS_HW_NRF_I2S20 select PINCTRL help Enable support for nrfx I2S driver for nRF MCU series. diff --git a/drivers/i2s/i2s_nrfx.c b/drivers/i2s/i2s_nrfx.c index 57910c464ab7f83..e1b3684c4f77b23 100644 --- a/drivers/i2s/i2s_nrfx.c +++ b/drivers/i2s/i2s_nrfx.c @@ -955,5 +955,10 @@ static const struct i2s_driver_api i2s_nrf_drv_api = { POST_KERNEL, CONFIG_I2S_INIT_PRIORITY, \ &i2s_nrf_drv_api); -/* Existing SoCs only have one I2S instance. */ +#ifdef CONFIG_HAS_HW_NRF_I2S0 I2S_NRFX_DEVICE(0); +#endif + +#ifdef CONFIG_HAS_HW_NRF_I2S20 +I2S_NRFX_DEVICE(20); +#endif From ec50e5393c98156729870167cb18645b13845d9f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 17 Nov 2023 11:48:01 +0100 Subject: [PATCH 0672/1049] net: lwm2m: shell: Add error check for string to float conversion The result of string to float conversion in LwM2M shell write command was not verified, which could result in incorrect data being written to the resource. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_shell.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_shell.c b/subsys/net/lib/lwm2m/lwm2m_shell.c index a4807d517f2baad..a4cedf8cd6258fe 100644 --- a/subsys/net/lib/lwm2m/lwm2m_shell.c +++ b/subsys/net/lib/lwm2m/lwm2m_shell.c @@ -328,8 +328,10 @@ static int cmd_write(const struct shell *sh, size_t argc, char **argv) } else if (strcmp(dtype, "-f") == 0) { double new = 0; - lwm2m_atof(value, &new); /* Convert string -> float */ - ret = lwm2m_set_f64(&path, new); + ret = lwm2m_atof(value, &new); /* Convert string -> float */ + if (ret == 0) { + ret = lwm2m_set_f64(&path, new); + } } else { /* All the types using stdlib funcs*/ char *e; From 7f7d019b25b0d663142f44cc335e66d36095692c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 17 Nov 2023 12:02:13 +0100 Subject: [PATCH 0673/1049] net: lwm2m: Add error checks for option encoding in BS registration Add missing error checks when encoding CoAP options for Bootstrap Register message Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index ca539fcded6820f..d9f2e229edd9e17 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -770,16 +770,20 @@ static int sm_send_bootstrap_registration(void) goto cleanup; } - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, - "bs", strlen("bs")); + ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, + "bs", strlen("bs")); + if (ret < 0) { + goto cleanup; + } snprintk(query_buffer, sizeof(query_buffer) - 1, "ep=%s", client.ep_name); - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, - query_buffer, strlen(query_buffer)); + ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, + query_buffer, strlen(query_buffer)); + if (ret < 0) { + goto cleanup; + } if (IS_ENABLED(CONFIG_LWM2M_VERSION_1_1)) { int pct = LWM2M_FORMAT_OMA_TLV; From a3362d969dfc62f52b91afa50bf06a1a54e0a1a6 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 17 Nov 2023 12:05:27 +0100 Subject: [PATCH 0674/1049] net: lwm2m: Explicitly initialize path_list_size variable To get rid of compiler warning about potential use of uninitialized variable. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_observation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_observation.c b/subsys/net/lib/lwm2m/lwm2m_observation.c index 7933ebd8fd31481..9ee1fa6eda18d0f 100644 --- a/subsys/net/lib/lwm2m/lwm2m_observation.c +++ b/subsys/net/lib/lwm2m/lwm2m_observation.c @@ -529,7 +529,7 @@ struct observe_node *engine_observe_node_discover(sys_slist_t *observe_node_list const uint8_t *token, uint8_t tkl) { struct observe_node *obs; - int obs_list_size, path_list_size; + int obs_list_size, path_list_size = 0; if (lwm2m_path_list) { path_list_size = engine_path_list_size(lwm2m_path_list); From 69e6b3a56371bf7a9f1cae679e84d5b9faf49ee6 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 17 Nov 2023 12:40:46 +0100 Subject: [PATCH 0675/1049] net: tftp: Log transmit error There's not really much to do when the transmission of the error reply fails, but we can at least log the failure. Signed-off-by: Robert Lubos --- subsys/net/lib/tftp/tftp_client.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/tftp/tftp_client.c b/subsys/net/lib/tftp/tftp_client.c index fc3cd2b70d9f796..12f3d9e03467308 100644 --- a/subsys/net/lib/tftp/tftp_client.c +++ b/subsys/net/lib/tftp/tftp_client.c @@ -293,7 +293,10 @@ int tftp_get(struct tftpc *client, const char *remote_file, const char *mode) if (client->callback == NULL) { LOG_ERR("No callback defined."); - send_err(sock, client, TFTP_ERROR_DISK_FULL, NULL); + if (send_err(sock, client, TFTP_ERROR_DISK_FULL, NULL) < 0) { + LOG_ERR("Failed to send error response, err: %d", + -errno); + } ret = TFTPC_BUFFER_OVERFLOW; goto get_end; } From 59544d58efdcb31e3318cc28d3b0621562f0af2e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 17 Nov 2023 12:44:52 +0100 Subject: [PATCH 0676/1049] net: tftp: Verify connect return value Verify that connect() succeeded before reporting success. Signed-off-by: Robert Lubos --- subsys/net/lib/tftp/tftp_client.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/tftp/tftp_client.c b/subsys/net/lib/tftp/tftp_client.c index 12f3d9e03467308..776135866a3a04e 100644 --- a/subsys/net/lib/tftp/tftp_client.c +++ b/subsys/net/lib/tftp/tftp_client.c @@ -222,7 +222,11 @@ static int send_request(int sock, struct tftpc *client, } /* Limit communication to the specific address:port */ - connect(sock, &from_addr, from_addr_len); + if (connect(sock, &from_addr, from_addr_len) < 0) { + ret = -errno; + LOG_ERR("connect failed, err %d", ret); + break; + } break; From f0247131bffbaf0417fa35a1d1a0a6f720f8272e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 17 Nov 2023 12:53:38 +0100 Subject: [PATCH 0677/1049] net: tftp: Ensure the error message fits into transmit buffer Make sure that the error message does not overflow the transmit buffer when copying the error message string. Signed-off-by: Robert Lubos --- subsys/net/lib/tftp/tftp_client.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/tftp/tftp_client.c b/subsys/net/lib/tftp/tftp_client.c index 776135866a3a04e..c6f9a371d6b0e5f 100644 --- a/subsys/net/lib/tftp/tftp_client.c +++ b/subsys/net/lib/tftp/tftp_client.c @@ -155,8 +155,14 @@ static inline int send_err(int sock, struct tftpc *client, int err_code, char *e /* Copy the Error String. */ if (err_msg != NULL) { - strcpy(client->tftp_buf + req_size, err_msg); - req_size += strlen(err_msg); + size_t copy_len = strlen(err_msg); + + if (copy_len > sizeof(client->tftp_buf) - req_size) { + copy_len = sizeof(client->tftp_buf) - req_size; + } + + memcpy(client->tftp_buf + req_size, err_msg, copy_len); + req_size += copy_len; } /* Send Error to server. */ From e72baabe910934564b4bac2c4a8ec59867b84701 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 10:56:20 +0100 Subject: [PATCH 0678/1049] dt-bindings: sensor: lsm6dsv16x: add macros for DT properties setting Add macros for setting in a clear way lsm6dsv16x DT properties. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,lsm6dsv16x-common.yaml | 188 ++++++++++-------- .../zephyr/dt-bindings/sensor/lsm6dsv16x.h | 58 ++++++ tests/drivers/build_all/sensor/i2c.dtsi | 6 + 3 files changed, 173 insertions(+), 79 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/lsm6dsv16x.h diff --git a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml index 619669bf545e309..99167a6506dadbd 100644 --- a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml +++ b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml @@ -1,6 +1,23 @@ # Copyright (c) 2023 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in + a .dts or .dtsi file you may include st_lsm6dsv16x.h and use the macros + defined there. + + Example: + #include + + lsm6dsv16x: lsm6dsv16x@0 { + ... + + accel-range = ; + accel-odr = ; + gyro-range = ; + gyro-odr = ; + }; + include: sensor-device.yaml properties: @@ -41,11 +58,13 @@ properties: default: 0 description: | Range in g. Default is power-up configuration. - enum: - - 0 # 2g (0.061 mg/LSB) - - 1 # 4g (0.122 mg/LSB) - - 2 # 8g (0.244 mg/LSB) - - 3 # 16g (0.488 mg/LSB) + + - 0 # LSM6DSV16X_DT_FS_2G (0.061 mg/LSB) + - 1 # LSM6DSV16X_DT_FS_4G (0.122 mg/LSB) + - 2 # LSM6DSV16X_DT_FS_8G (0.244 mg/LSB) + - 3 # LSM6DSV16X_DT_FS_16G (0.488 mg/LSB) + + enum: [0, 1, 2, 3] accel-odr: type: int @@ -56,53 +75,59 @@ properties: module. Please note that this values will not change the operating mode, which will remain High Performance (device default) Default is power-up configuration. - enum: - - 0x00 # Power-Down - - 0x01 # 1Hz875 - - 0x02 # 7Hz5 - - 0x03 # 15Hz - - 0x04 # 30Hz - - 0x05 # 60Hz - - 0x06 # 120Hz - - 0x07 # 240Hz - - 0x08 # 480Hz - - 0x09 # 960Hz - - 0x0a # 1920Hz - - 0x0b # 3840Hz - - 0x0c # 7680Hz - - 0x13 # 15Hz625 (High Accuracy 1) - - 0x14 # 31Hz25 (High Accuracy 1) - - 0x15 # 62Hz5 (High Accuracy 1) - - 0x16 # 125Hz (High Accuracy 1) - - 0x17 # 250Hz (High Accuracy 1) - - 0x18 # 500Hz (High Accuracy 1) - - 0x19 # 1000Hz (High Accuracy 1) - - 0x1a # 2000Hz (High Accuracy 1) - - 0x1b # 4000Hz (High Accuracy 1) - - 0x1c # 8000Hz (High Accuracy 1) - - 0x23 # 12Hz5 (High Accuracy 2) - - 0x24 # 25Hz (High Accuracy 2) - - 0x25 # 50Hz (High Accuracy 2) - - 0x26 # 100Hz (High Accuracy 2) - - 0x27 # 200Hz (High Accuracy 2) - - 0x28 # 400Hz (High Accuracy 2) - - 0x29 # 800Hz (High Accuracy 2) - - 0x2a # 1600Hz (High Accuracy 2) - - 0x2b # 3200Hz (High Accuracy 2) - - 0x2c # 6400Hz (High Accuracy 2) + + - 0x00 # LSM6DSV16X_DT_ODR_OFF + - 0x01 # LSM6DSV16X_DT_ODR_AT_1Hz875 + - 0x02 # LSM6DSV16X_DT_ODR_AT_7Hz5 + - 0x03 # LSM6DSV16X_DT_ODR_AT_15Hz + - 0x04 # LSM6DSV16X_DT_ODR_AT_30Hz + - 0x05 # LSM6DSV16X_DT_ODR_AT_60Hz + - 0x06 # LSM6DSV16X_DT_ODR_AT_120Hz + - 0x07 # LSM6DSV16X_DT_ODR_AT_240Hz + - 0x08 # LSM6DSV16X_DT_ODR_AT_480Hz + - 0x09 # LSM6DSV16X_DT_ODR_AT_960Hz + - 0x0a # LSM6DSV16X_DT_ODR_AT_1920Hz + - 0x0b # LSM6DSV16X_DT_ODR_AT_3840Hz + - 0x0c # LSM6DSV16X_DT_ODR_AT_7680Hz + - 0x13 # LSM6DSV16X_DT_ODR_HA01_AT_15Hz625 + - 0x14 # LSM6DSV16X_DT_ODR_HA01_AT_31Hz25 + - 0x15 # LSM6DSV16X_DT_ODR_HA01_AT_62Hz5 + - 0x16 # LSM6DSV16X_DT_ODR_HA01_AT_125Hz + - 0x17 # LSM6DSV16X_DT_ODR_HA01_AT_250Hz + - 0x18 # LSM6DSV16X_DT_ODR_HA01_AT_500Hz + - 0x19 # LSM6DSV16X_DT_ODR_HA01_AT_1000Hz + - 0x1a # LSM6DSV16X_DT_ODR_HA01_AT_2000Hz + - 0x1b # LSM6DSV16X_DT_ODR_HA01_AT_4000Hz + - 0x1c # LSM6DSV16X_DT_ODR_HA01_AT_8000Hz + - 0x23 # LSM6DSV16X_DT_ODR_HA02_AT_12Hz5 + - 0x24 # LSM6DSV16X_DT_ODR_HA02_AT_25Hz + - 0x25 # LSM6DSV16X_DT_ODR_HA02_AT_50Hz + - 0x26 # LSM6DSV16X_DT_ODR_HA02_AT_100Hz + - 0x27 # LSM6DSV16X_DT_ODR_HA02_AT_200Hz + - 0x28 # LSM6DSV16X_DT_ODR_HA02_AT_400Hz + - 0x29 # LSM6DSV16X_DT_ODR_HA02_AT_800Hz + - 0x2a # LSM6DSV16X_DT_ODR_HA02_AT_1600Hz + - 0x2b # LSM6DSV16X_DT_ODR_HA02_AT_3200Hz + - 0x2c # LSM6DSV16X_DT_ODR_HA02_AT_6400Hz + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c] gyro-range: type: int default: 0 description: | Range in dps. Default is power-up configuration. - enum: - - 0 # 125 dps (4.375 mdps/LSB) - - 1 # 250 dps (8.75 mdps/LSB) - - 2 # 500 dps (17.50 mdps/LSB) - - 3 # 1000 dps (35 mdps/LSB) - - 4 # 2000 dps (70 mdps/LSB) - - 5 # 4000 dps (140 mdps/LSB) + + - 0x0 # LSM6DSV16X_DT_FS_125DPS (4.375 mdps/LSB) + - 0x1 # LSM6DSV16X_DT_FS_250DPS (8.75 mdps/LSB) + - 0x2 # LSM6DSV16X_DT_FS_500DPS (17.50 mdps/LSB) + - 0x3 # LSM6DSV16X_DT_FS_1000DPS (35 mdps/LSB) + - 0x4 # LSM6DSV16X_DT_FS_2000DPS (70 mdps/LSB) + - 0xc # LSM6DSV16X_DT_FS_4000DPS (140 mdps/LSB) + + enum: [0x0, 0x1, 0x2, 0x3, 0x4, 0xc] gyro-odr: type: int @@ -115,39 +140,44 @@ properties: DT are the only way to specifiy the odr accuracy even at runtime with SENSOR_ATTR_SAMPLING_FREQUENCY. Default is power-up configuration. - enum: - - 0x00 # Power-Down - - 0x02 # 7Hz5 - - 0x03 # 15Hz - - 0x04 # 30Hz - - 0x05 # 60Hz - - 0x06 # 120Hz - - 0x07 # 240Hz - - 0x08 # 480Hz - - 0x09 # 960Hz - - 0x0a # 1920Hz - - 0x0b # 3840Hz - - 0x0c # 7680Hz - - 0x13 # 15Hz625 (High Accuracy 1) - - 0x14 # 31Hz25 (High Accuracy 1) - - 0x15 # 62Hz5 (High Accuracy 1) - - 0x16 # 125Hz (High Accuracy 1) - - 0x17 # 250Hz (High Accuracy 1) - - 0x18 # 500Hz (High Accuracy 1) - - 0x19 # 1000Hz (High Accuracy 1) - - 0x1a # 2000Hz (High Accuracy 1) - - 0x1b # 4000Hz (High Accuracy 1) - - 0x1c # 8000Hz (High Accuracy 1) - - 0x23 # 12Hz5 (High Accuracy 2) - - 0x24 # 25Hz (High Accuracy 2) - - 0x25 # 50Hz (High Accuracy 2) - - 0x26 # 100Hz (High Accuracy 2) - - 0x27 # 200Hz (High Accuracy 2) - - 0x28 # 400Hz (High Accuracy 2) - - 0x29 # 800Hz (High Accuracy 2) - - 0x2a # 1600Hz (High Accuracy 2) - - 0x2b # 3200Hz (High Accuracy 2) - - 0x2c # 6400Hz (High Accuracy 2) + + - 0x00 # LSM6DSV16X_DT_ODR_OFF + - 0x01 # LSM6DSV16X_DT_ODR_AT_1Hz875 + - 0x02 # LSM6DSV16X_DT_ODR_AT_7Hz5 + - 0x03 # LSM6DSV16X_DT_ODR_AT_15Hz + - 0x04 # LSM6DSV16X_DT_ODR_AT_30Hz + - 0x05 # LSM6DSV16X_DT_ODR_AT_60Hz + - 0x06 # LSM6DSV16X_DT_ODR_AT_120Hz + - 0x07 # LSM6DSV16X_DT_ODR_AT_240Hz + - 0x08 # LSM6DSV16X_DT_ODR_AT_480Hz + - 0x09 # LSM6DSV16X_DT_ODR_AT_960Hz + - 0x0a # LSM6DSV16X_DT_ODR_AT_1920Hz + - 0x0b # LSM6DSV16X_DT_ODR_AT_3840Hz + - 0x0c # LSM6DSV16X_DT_ODR_AT_7680Hz + - 0x13 # LSM6DSV16X_DT_ODR_HA01_AT_15Hz625 + - 0x14 # LSM6DSV16X_DT_ODR_HA01_AT_31Hz25 + - 0x15 # LSM6DSV16X_DT_ODR_HA01_AT_62Hz5 + - 0x16 # LSM6DSV16X_DT_ODR_HA01_AT_125Hz + - 0x17 # LSM6DSV16X_DT_ODR_HA01_AT_250Hz + - 0x18 # LSM6DSV16X_DT_ODR_HA01_AT_500Hz + - 0x19 # LSM6DSV16X_DT_ODR_HA01_AT_1000Hz + - 0x1a # LSM6DSV16X_DT_ODR_HA01_AT_2000Hz + - 0x1b # LSM6DSV16X_DT_ODR_HA01_AT_4000Hz + - 0x1c # LSM6DSV16X_DT_ODR_HA01_AT_8000Hz + - 0x23 # LSM6DSV16X_DT_ODR_HA02_AT_12Hz5 + - 0x24 # LSM6DSV16X_DT_ODR_HA02_AT_25Hz + - 0x25 # LSM6DSV16X_DT_ODR_HA02_AT_50Hz + - 0x26 # LSM6DSV16X_DT_ODR_HA02_AT_100Hz + - 0x27 # LSM6DSV16X_DT_ODR_HA02_AT_200Hz + - 0x28 # LSM6DSV16X_DT_ODR_HA02_AT_400Hz + - 0x29 # LSM6DSV16X_DT_ODR_HA02_AT_800Hz + - 0x2a # LSM6DSV16X_DT_ODR_HA02_AT_1600Hz + - 0x2b # LSM6DSV16X_DT_ODR_HA02_AT_3200Hz + - 0x2c # LSM6DSV16X_DT_ODR_HA02_AT_6400Hz + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c] drdy-pulsed: type: boolean diff --git a/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h b/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h new file mode 100644 index 000000000000000..533dd5e3febb085 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSV16X_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSV16X_H_ + +/* Accel range */ +#define LSM6DSV16X_DT_FS_2G 0 +#define LSM6DSV16X_DT_FS_4G 1 +#define LSM6DSV16X_DT_FS_8G 2 +#define LSM6DSV16X_DT_FS_16G 3 + +/* Gyro range */ +#define LSM6DSV16X_DT_FS_125DPS 0x0 +#define LSM6DSV16X_DT_FS_250DPS 0x1 +#define LSM6DSV16X_DT_FS_500DPS 0x2 +#define LSM6DSV16X_DT_FS_1000DPS 0x3 +#define LSM6DSV16X_DT_FS_2000DPS 0x4 +#define LSM6DSV16X_DT_FS_4000DPS 0xc + +/* Accel and Gyro Data rates */ +#define LSM6DSV16X_DT_ODR_OFF 0x0 +#define LSM6DSV16X_DT_ODR_AT_1Hz875 0x1 +#define LSM6DSV16X_DT_ODR_AT_7Hz5 0x2 +#define LSM6DSV16X_DT_ODR_AT_15Hz 0x3 +#define LSM6DSV16X_DT_ODR_AT_30Hz 0x4 +#define LSM6DSV16X_DT_ODR_AT_60Hz 0x5 +#define LSM6DSV16X_DT_ODR_AT_120Hz 0x6 +#define LSM6DSV16X_DT_ODR_AT_240Hz 0x7 +#define LSM6DSV16X_DT_ODR_AT_480Hz 0x8 +#define LSM6DSV16X_DT_ODR_AT_960Hz 0x9 +#define LSM6DSV16X_DT_ODR_AT_1920Hz 0xA +#define LSM6DSV16X_DT_ODR_AT_3840Hz 0xB +#define LSM6DSV16X_DT_ODR_AT_7680Hz 0xC +#define LSM6DSV16X_DT_ODR_HA01_AT_15Hz625 0x13 +#define LSM6DSV16X_DT_ODR_HA01_AT_31Hz25 0x14 +#define LSM6DSV16X_DT_ODR_HA01_AT_62Hz5 0x15 +#define LSM6DSV16X_DT_ODR_HA01_AT_125Hz 0x16 +#define LSM6DSV16X_DT_ODR_HA01_AT_250Hz 0x17 +#define LSM6DSV16X_DT_ODR_HA01_AT_500Hz 0x18 +#define LSM6DSV16X_DT_ODR_HA01_AT_1000Hz 0x19 +#define LSM6DSV16X_DT_ODR_HA01_AT_2000Hz 0x1A +#define LSM6DSV16X_DT_ODR_HA01_AT_4000Hz 0x1B +#define LSM6DSV16X_DT_ODR_HA01_AT_8000Hz 0x1C +#define LSM6DSV16X_DT_ODR_HA02_AT_12Hz5 0x23 +#define LSM6DSV16X_DT_ODR_HA02_AT_25Hz 0x24 +#define LSM6DSV16X_DT_ODR_HA02_AT_50Hz 0x25 +#define LSM6DSV16X_DT_ODR_HA02_AT_100Hz 0x26 +#define LSM6DSV16X_DT_ODR_HA02_AT_200Hz 0x27 +#define LSM6DSV16X_DT_ODR_HA02_AT_400Hz 0x28 +#define LSM6DSV16X_DT_ODR_HA02_AT_800Hz 0x29 +#define LSM6DSV16X_DT_ODR_HA02_AT_1600Hz 0x2A +#define LSM6DSV16X_DT_ODR_HA02_AT_3200Hz 0x2B +#define LSM6DSV16X_DT_ODR_HA02_AT_6400Hz 0x2C + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSV16X_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index ce22576c48a35d1..6dfad3e8a4f1d62 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -6,6 +6,8 @@ * Application overlay for i2c devices */ +#include + /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * ***************************************/ @@ -697,6 +699,10 @@ test_i2c_lsm6dsv16x: lsm6dsv16x@69 { reg = <0x69>; int1-gpios = <&test_gpio 0 0>; int2-gpios = <&test_gpio 0 0>; + accel-range = ; + accel-odr = ; + gyro-range = ; + gyro-odr = ; }; test_i2c_mcp9600: mcp9600@6a { From 0c3057edf471dad786f0071cf4e6e118237eb7ea Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 10:59:11 +0100 Subject: [PATCH 0679/1049] dt-bindings: sensor: lsm6dso: add macros for DT properties setting Add macros for setting in a clear way lsm6dso DT properties. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,lsm6dso-common.yaml | 116 +++++++++++++------- include/zephyr/dt-bindings/sensor/lsm6dso.h | 45 ++++++++ tests/drivers/build_all/sensor/i2c.dtsi | 7 ++ 3 files changed, 126 insertions(+), 42 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/lsm6dso.h diff --git a/dts/bindings/sensor/st,lsm6dso-common.yaml b/dts/bindings/sensor/st,lsm6dso-common.yaml index e8de1e9a75df113..0b4b17df720b6a4 100644 --- a/dts/bindings/sensor/st,lsm6dso-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso-common.yaml @@ -1,6 +1,25 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the accel-pm, accel-range, accel-odr, gyro-pm, gyro-range, + gyro-odr properties in a .dts or .dtsi file you may include st_lsm6dso.h + and use the macros defined there. + + Example: + #include + + lsm6dso: lsm6dso@0 { + ... + + accel-pm = ; + accel-range = ; + accel-odr = ; + gyro-pm = ; + gyro-range = ; + gyro-odr = ; + }; + include: sensor-device.yaml properties: @@ -33,21 +52,25 @@ properties: description: | Specify the accelerometer power mode. Default is power-up configuration. - enum: - - 0 # High Performance mode (default) - - 1 # Low/Normal Power mode - - 2 # Ultra Low Power mode + + - 0 # LSM6DSO_DT_XL_HP_MODE + - 1 # LSM6DSO_DT_XL_LP_NORMAL_MODE + - 2 # LSM6DSO_DT_XL_ULP_MODE + + enum: [0, 1, 2] accel-range: type: int default: 0 description: | Range in g. Default is power-up configuration. - enum: - - 0 # 2g (0.061 mg/LSB) (LSM6DSO32 will be double these values) - - 1 # 16g (0.488 mg/LSB) - - 2 # 4g (0.122 mg/LSB) - - 3 # 8g (0.244 mg/LSB) + + - 0 # LSM6DSO_DT_FS_2G (0.061 mg/LSB) (LSM6DSO32 will be double these values) + - 1 # LSM6DSO_DT_FS_16G (0.488 mg/LSB) + - 2 # LSM6DSO_DT_FS_4G (0.122 mg/LSB) + - 3 # LSM6DSO_DT_FS_8G (0.244 mg/LSB) + + enum: [0, 1, 2, 3] accel-odr: type: int @@ -55,18 +78,21 @@ properties: description: | Specify the default accelerometer output data rate expressed in samples per second (Hz). Default is power-up configuration. - enum: - - 0 # Power-Down - - 1 # 12.5Hz - - 2 # 26Hz - - 3 # 52Hz - - 4 # 104Hz - - 5 # 208Hz - - 6 # 417Hz - - 7 # 833Hz - - 8 # 1667Hz - - 9 # 3333Hz - - 10 # 6667Hz + + - 0 # LSM6DSO_DT_ODR_OFF + - 1 # LSM6DSO_DT_ODR_12Hz5 + - 2 # LSM6DSO_DT_ODR_26H + - 3 # LSM6DSO_DT_ODR_52Hz + - 4 # LSM6DSO_DT_ODR_104Hz + - 5 # LSM6DSO_DT_ODR_208Hz + - 6 # LSM6DSO_DT_ODR_417Hz + - 7 # LSM6DSO_DT_ODR_833Hz + - 8 # LSM6DSO_DT_ODR_1667Hz + - 9 # LSM6DSO_DT_ODR_3333Hz + - 10 # LSM6DSO_DT_ODR_6667Hz + - 11 # LSM6DSO_DT_ODR_1Hz6 + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] gyro-pm: type: int @@ -74,21 +100,25 @@ properties: description: | Specify the gyrometer power mode. Default is power-up configuration. - enum: - - 0 # High Performance mode (default) - - 1 # Low/Normal Power mode + + - 0 # LSM6DSO_DT_GY_HP_MODE + - 1 # LSM6DSO_DT_GY_NORMAL_MODE + + enum: [0, 1] gyro-range: type: int default: 0 description: | Range in dps. Default is power-up configuration. - enum: - - 0 # 250 dps (8.75 mdps/LSB) - - 1 # 125 dps (4.375 mdps/LSB) - - 2 # 500 dps (17.50 mdps/LSB) - - 4 # 1000 dps (35 mdps/LSB) - - 6 # 2000 dps (70 mdps/LSB) + + - 0 # LSM6DSO_DT_FS_250DPS (8.75 mdps/LSB) + - 1 # LSM6DSO_DT_FS_125DPS (4.375 mdps/LSB) + - 2 # LSM6DSO_DT_FS_500DPS (17.50 mdps/LSB) + - 4 # LSM6DSO_DT_FS_1000DPS (35 mdps/LSB) + - 6 # LSM6DSO_DT_FS_2000DPS (70 mdps/LSB) + + enum: [0, 1, 2, 4, 6] gyro-odr: type: int @@ -96,18 +126,20 @@ properties: description: | Specify the default gyro output data rate expressed in samples per second (Hz). Default is power-up configuration. - enum: - - 0 # Power-Down - - 1 # 12.5Hz - - 2 # 26Hz - - 3 # 52Hz - - 4 # 104Hz - - 5 # 208Hz - - 6 # 417Hz - - 7 # 833Hz - - 8 # 1667Hz - - 9 # 3333Hz - - 10 # 6667Hz + + - 0 # LSM6DSO_DT_ODR_OFF + - 1 # LSM6DSO_DT_ODR_12Hz5 + - 2 # LSM6DSO_DT_ODR_26H + - 3 # LSM6DSO_DT_ODR_52Hz + - 4 # LSM6DSO_DT_ODR_104Hz + - 5 # LSM6DSO_DT_ODR_208Hz + - 6 # LSM6DSO_DT_ODR_417Hz + - 7 # LSM6DSO_DT_ODR_833Hz + - 8 # LSM6DSO_DT_ODR_1667Hz + - 9 # LSM6DSO_DT_ODR_3333Hz + - 10 # LSM6DSO_DT_ODR_6667Hz + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] drdy-pulsed: type: boolean diff --git a/include/zephyr/dt-bindings/sensor/lsm6dso.h b/include/zephyr/dt-bindings/sensor/lsm6dso.h new file mode 100644 index 000000000000000..7d3775bae3d3e4f --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lsm6dso.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO_H_ + +/* Accel power-modes */ +#define LSM6DSO_DT_XL_HP_MODE 0 +#define LSM6DSO_DT_XL_LP_NORMAL_MODE 1 +#define LSM6DSO_DT_XL_ULP_MODE 2 + +/* Gyro power-modes */ +#define LSM6DSO_DT_GY_HP_MODE 0 +#define LSM6DSO_DT_GY_NORMAL_MODE 1 + +/* Accel range */ +#define LSM6DSO_DT_FS_2G 0 +#define LSM6DSO_DT_FS_16G 1 +#define LSM6DSO_DT_FS_4G 2 +#define LSM6DSO_DT_FS_8G 3 + +/* Gyro range */ +#define LSM6DSO_DT_FS_250DPS 0 +#define LSM6DSO_DT_FS_125DPS 1 +#define LSM6DSO_DT_FS_500DPS 2 +#define LSM6DSO_DT_FS_1000DPS 4 +#define LSM6DSO_DT_FS_2000DPS 6 + +/* Accel and Gyro Data rates */ +#define LSM6DSO_DT_ODR_OFF 0x0 +#define LSM6DSO_DT_ODR_12Hz5 0x1 +#define LSM6DSO_DT_ODR_26H 0x2 +#define LSM6DSO_DT_ODR_52Hz 0x3 +#define LSM6DSO_DT_ODR_104Hz 0x4 +#define LSM6DSO_DT_ODR_208Hz 0x5 +#define LSM6DSO_DT_ODR_417Hz 0x6 +#define LSM6DSO_DT_ODR_833Hz 0x7 +#define LSM6DSO_DT_ODR_1667Hz 0x8 +#define LSM6DSO_DT_ODR_3333Hz 0x9 +#define LSM6DSO_DT_ODR_6667Hz 0xa +#define LSM6DSO_DT_ODR_1Hz6 0xb + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 6dfad3e8a4f1d62..2441a3cb9b9a767 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -7,6 +7,7 @@ */ #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -364,6 +365,12 @@ test_i2c_lsm6dso: lsm6dso@39 { compatible = "st,lsm6dso"; reg = <0x39>; irq-gpios = <&test_gpio 0 0>; + accel-pm = ; + accel-range = ; + accel-odr = ; + gyro-pm = ; + gyro-range = ; + gyro-odr = ; }; test_i2c_lsm9ds0_gyro: lsm9ds0-gyro@3a { From 1fbd157c6156c4c5e28a50e7e60b05333a2c6a0a Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 11:19:33 +0100 Subject: [PATCH 0680/1049] dt-bindings: sensor: lsm6dso16is: add macros for DT properties setting Add macros for setting in a clear way lsm6dso16is DT properties. Signed-off-by: Armando Visconti --- .../sensor/st,lsm6dso16is-common.yaml | 139 +++++++++++------- .../zephyr/dt-bindings/sensor/lsm6dso16is.h | 46 ++++++ tests/drivers/build_all/sensor/i2c.dtsi | 5 + 3 files changed, 134 insertions(+), 56 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/lsm6dso16is.h diff --git a/dts/bindings/sensor/st,lsm6dso16is-common.yaml b/dts/bindings/sensor/st,lsm6dso16is-common.yaml index 16304b5692c0b4f..49f7fd187fb67b0 100644 --- a/dts/bindings/sensor/st,lsm6dso16is-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso16is-common.yaml @@ -1,6 +1,23 @@ # Copyright (c) 2023 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in + a .dts or .dtsi file you may include st_lsm6dso16is.h and use the macros + defined there. + + Example: + #include + + lsm6dso16is: lsm6dso16is@0 { + ... + + accel-range = ; + accel-odr = ; + gyro-range = ; + gyro-odr = ; + }; + include: sensor-device.yaml properties: @@ -32,11 +49,13 @@ properties: default: 0 description: | Range in g. Default is power-up configuration. - enum: - - 0 # 2g (0.061 mg/LSB) - - 1 # 16g (0.488 mg/LSB) - - 2 # 4g (0.122 mg/LSB) - - 3 # 8g (0.244 mg/LSB) + + - 0 # LSM6DSO16IS_DT_FS_2G (0.061 mg/LSB) + - 1 # LSM6DSO16IS_DT_FS_16G (0.488 mg/LSB) + - 2 # LSM6DSO16IS_DT_FS_4G (0.122 mg/LSB) + - 3 # LSM6DSO16IS_DT_FS_8G (0.244 mg/LSB) + + enum: [0, 1, 2, 3] accel-odr: type: int @@ -46,41 +65,46 @@ properties: The values are taken in accordance to lsm6dso16is_xl_data_rate_t enumerative in hal/st module. Default is power-up configuration. - enum: - - 0x00 # Power-Down - - 0x01 # 12.5Hz High Performance - - 0x02 # 26Hz High Performance - - 0x03 # 52Hz High Performance - - 0x04 # 104Hz High Performance - - 0x05 # 208Hz High Performance - - 0x06 # 417Hz High Performance - - 0x07 # 833Hz High Performance - - 0x08 # 1667Hz High Performance - - 0x09 # 3333Hz High Performance - - 0x0a # 6667Hz High Performance - - 0x11 # 12.5Hz Low Power - - 0x12 # 26Hz Low Power - - 0x13 # 52Hz Low Power - - 0x14 # 104Hz Low Power - - 0x15 # 208Hz Low Power - - 0x16 # 417Hz Low Power - - 0x17 # 833Hz Low Power - - 0x18 # 1667Hz Low Power - - 0x19 # 3333Hz Low Power - - 0x1a # 6667Hz Low Power - - 0x1b # 1Hz6 Low Power + + - 0x00 # LSM6DSO16IS_DT_ODR_OFF + - 0x01 # LSM6DSO16IS_DT_ODR_12Hz5_HP + - 0x02 # LSM6DSO16IS_DT_ODR_26H_HP + - 0x03 # LSM6DSO16IS_DT_ODR_52Hz_HP + - 0x04 # LSM6DSO16IS_DT_ODR_104Hz_HP + - 0x05 # LSM6DSO16IS_DT_ODR_208Hz_HP + - 0x06 # LSM6DSO16IS_DT_ODR_416Hz_HP + - 0x07 # LSM6DSO16IS_DT_ODR_833Hz_HP + - 0x08 # LSM6DSO16IS_DT_ODR_1667Hz_HP + - 0x09 # LSM6DSO16IS_DT_ODR_3333Hz_HP + - 0x0a # LSM6DSO16IS_DT_ODR_6667Hz_HP + - 0x11 # LSM6DSO16IS_DT_ODR_12Hz5_LP + - 0x12 # LSM6DSO16IS_DT_ODR_26H_LP + - 0x13 # LSM6DSO16IS_DT_ODR_52Hz_LP + - 0x14 # LSM6DSO16IS_DT_ODR_104Hz_LP + - 0x15 # LSM6DSO16IS_DT_ODR_208Hz_LP + - 0x16 # LSM6DSO16IS_DT_ODR_416Hz_LP + - 0x17 # LSM6DSO16IS_DT_ODR_833Hz_LP + - 0x18 # LSM6DSO16IS_DT_ODR_1667Hz_LP + - 0x19 # LSM6DSO16IS_DT_ODR_3333Hz_LP + - 0x1a # LSM6DSO16IS_DT_ODR_6667Hz_LP + - 0x1b # LSM6DSO16IS_DT_ODR_1Hz6_LP + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b] gyro-range: type: int default: 0 description: | Range in dps. Default is power-up configuration. - enum: - - 0 # 250 dps (8.75 mdps/LSB) - - 1 # 125 dps (4.375 mdps/LSB) - - 2 # 500 dps (17.50 mdps/LSB) - - 4 # 1000 dps (35 mdps/LSB) - - 6 # 2000 dps (70 mdps/LSB) + + - 0x0 # LSM6DSO16IS_DT_FS_250DPS (8.75 mdps/LSB) + - 0x1 # LSM6DSO16IS_DT_FS_500DPS (17.50 mdps/LSB) + - 0x2 # LSM6DSO16IS_DT_FS_1000DPS (35 mdps/LSB) + - 0x3 # LSM6DSO16IS_DT_FS_2000DPS (70 mdps/LSB) + - 0x10 # LSM6DSO16IS_DT_FS_125DPS (4.375 mdps/LSB) + + enum: [0x0, 0x1, 0x2, 0x3, 0x10] gyro-odr: type: int @@ -90,28 +114,31 @@ properties: The values are taken in accordance to lsm6dso16is_gy_data_rate_t enumerative in hal/st module. Default is power-up configuration. - enum: - - 0x00 # Power-Down - - 0x01 # 12.5Hz High Performance - - 0x02 # 26Hz High Performance - - 0x03 # 52Hz High Performance - - 0x04 # 104Hz High Performance - - 0x05 # 208Hz High Performance - - 0x06 # 417Hz High Performance - - 0x07 # 833Hz High Performance - - 0x08 # 1667Hz High Performance - - 0x09 # 3333Hz High Performance - - 0x0a # 6667Hz High Performance - - 0x11 # 12.5Hz Low Power - - 0x12 # 26Hz Low Power - - 0x13 # 52Hz Low Power - - 0x14 # 104Hz Low Power - - 0x15 # 208Hz Low Power - - 0x16 # 417Hz Low Power - - 0x17 # 833Hz Low Power - - 0x18 # 1667Hz Low Power - - 0x19 # 3333Hz Low Power - - 0x1a # 6667Hz Low Power + + - 0x00 # LSM6DSO16IS_DT_ODR_OFF + - 0x01 # LSM6DSO16IS_DT_ODR_12Hz5_HP + - 0x02 # LSM6DSO16IS_DT_ODR_26H_HP + - 0x03 # LSM6DSO16IS_DT_ODR_52Hz_HP + - 0x04 # LSM6DSO16IS_DT_ODR_104Hz_HP + - 0x05 # LSM6DSO16IS_DT_ODR_208Hz_HP + - 0x06 # LSM6DSO16IS_DT_ODR_416Hz_HP + - 0x07 # LSM6DSO16IS_DT_ODR_833Hz_HP + - 0x08 # LSM6DSO16IS_DT_ODR_1667Hz_HP + - 0x09 # LSM6DSO16IS_DT_ODR_3333Hz_HP + - 0x0a # LSM6DSO16IS_DT_ODR_6667Hz_HP + - 0x11 # LSM6DSO16IS_DT_ODR_12Hz5_LP + - 0x12 # LSM6DSO16IS_DT_ODR_26H_LP + - 0x13 # LSM6DSO16IS_DT_ODR_52Hz_LP + - 0x14 # LSM6DSO16IS_DT_ODR_104Hz_LP + - 0x15 # LSM6DSO16IS_DT_ODR_208Hz_LP + - 0x16 # LSM6DSO16IS_DT_ODR_416Hz_LP + - 0x17 # LSM6DSO16IS_DT_ODR_833Hz_LP + - 0x18 # LSM6DSO16IS_DT_ODR_1667Hz_LP + - 0x19 # LSM6DSO16IS_DT_ODR_3333Hz_LP + - 0x1a # LSM6DSO16IS_DT_ODR_6667Hz_LP + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a] drdy-pulsed: type: boolean diff --git a/include/zephyr/dt-bindings/sensor/lsm6dso16is.h b/include/zephyr/dt-bindings/sensor/lsm6dso16is.h new file mode 100644 index 000000000000000..385f41145cf12bf --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lsm6dso16is.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO16IS_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO16IS_H_ + +/* Accel range */ +#define LSM6DSO16IS_DT_FS_2G 0 +#define LSM6DSO16IS_DT_FS_16G 1 +#define LSM6DSO16IS_DT_FS_4G 2 +#define LSM6DSO16IS_DT_FS_8G 3 + +/* Gyro range */ +#define LSM6DSO16IS_DT_FS_250DPS 0x0 +#define LSM6DSO16IS_DT_FS_500DPS 0x1 +#define LSM6DSO16IS_DT_FS_1000DPS 0x2 +#define LSM6DSO16IS_DT_FS_2000DPS 0x3 +#define LSM6DSO16IS_DT_FS_125DPS 0x10 + +/* Accel and Gyro Data rates */ +#define LSM6DSO16IS_DT_ODR_OFF 0x0 +#define LSM6DSO16IS_DT_ODR_12Hz5_HP 0x1 +#define LSM6DSO16IS_DT_ODR_26H_HP 0x2 +#define LSM6DSO16IS_DT_ODR_52Hz_HP 0x3 +#define LSM6DSO16IS_DT_ODR_104Hz_HP 0x4 +#define LSM6DSO16IS_DT_ODR_208Hz_HP 0x5 +#define LSM6DSO16IS_DT_ODR_416Hz_HP 0x6 +#define LSM6DSO16IS_DT_ODR_833Hz_HP 0x7 +#define LSM6DSO16IS_DT_ODR_1667Hz_HP 0x8 +#define LSM6DSO16IS_DT_ODR_3333Hz_HP 0x9 +#define LSM6DSO16IS_DT_ODR_6667Hz_HP 0xa +#define LSM6DSO16IS_DT_ODR_12Hz5_LP 0x11 +#define LSM6DSO16IS_DT_ODR_26H_LP 0x12 +#define LSM6DSO16IS_DT_ODR_52Hz_LP 0x13 +#define LSM6DSO16IS_DT_ODR_104Hz_LP 0x14 +#define LSM6DSO16IS_DT_ODR_208Hz_LP 0x15 +#define LSM6DSO16IS_DT_ODR_416Hz_LP 0x16 +#define LSM6DSO16IS_DT_ODR_833Hz_LP 0x17 +#define LSM6DSO16IS_DT_ODR_1667Hz_LP 0x18 +#define LSM6DSO16IS_DT_ODR_3333Hz_LP 0x19 +#define LSM6DSO16IS_DT_ODR_6667Hz_LP 0x1a +#define LSM6DSO16IS_DT_ODR_1Hz6_LP 0x1b + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO16IS_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 2441a3cb9b9a767..6c00025d8dd29b8 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -8,6 +8,7 @@ #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -699,6 +700,10 @@ test_i2c_lsm6dso16is: lsm6dso16is@68 { compatible = "st,lsm6dso16is"; reg = <0x68>; irq-gpios = <&test_gpio 0 0>; + accel-range = ; + accel-odr = ; + gyro-range = ; + gyro-odr = ; }; test_i2c_lsm6dsv16x: lsm6dsv16x@69 { From b0f22dbafdc4b7eb6dd5a25dbca7b8918c40101f Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 11:21:36 +0100 Subject: [PATCH 0681/1049] dt-bindings: sensor: lps22hh: add macros for DT properties setting Add macros for setting in a clear way lps22hh DT properties. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,lps22hh-common.yaml | 33 +++++++++++++++------ include/zephyr/dt-bindings/sensor/lps22hh.h | 19 ++++++++++++ tests/drivers/build_all/sensor/i2c.dtsi | 2 ++ 3 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/lps22hh.h diff --git a/dts/bindings/sensor/st,lps22hh-common.yaml b/dts/bindings/sensor/st,lps22hh-common.yaml index a704eac46aea2df..eeeffe25f9687e6 100644 --- a/dts/bindings/sensor/st,lps22hh-common.yaml +++ b/dts/bindings/sensor/st,lps22hh-common.yaml @@ -1,6 +1,19 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the odr property in a .dts or .dtsi file you may include + st_lps22hh.h and use the macros defined there. + + Example: + #include + + lps22hh: lps22hh@0 { + ... + + odr = ; + }; + include: sensor-device.yaml properties: @@ -19,12 +32,14 @@ properties: description: | Specify the default output data rate expressed in samples per second (Hz). The default is the power-on reset value. - enum: - - 0 # Power-Down - - 1 # 1Hz - - 2 # 10Hz - - 3 # 25Hz - - 4 # 50Hz - - 5 # 75Hz - - 6 # 100Hz - - 7 # 200Hz + + - 0 # LPS22HH_DT_ODR_POWER_DOWN + - 1 # LPS22HH_DT_ODR_1HZ + - 2 # LPS22HH_DT_ODR_10HZ + - 3 # LPS22HH_DT_ODR_25HZ + - 4 # LPS22HH_DT_ODR_50HZ + - 5 # LPS22HH_DT_ODR_75HZ + - 6 # LPS22HH_DT_ODR_100HZ + - 7 # LPS22HH_DT_ODR_200HZ + + enum: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/include/zephyr/dt-bindings/sensor/lps22hh.h b/include/zephyr/dt-bindings/sensor/lps22hh.h new file mode 100644 index 000000000000000..728f872bc37589c --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lps22hh.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22HH_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22HH_H_ + +/* Data rate */ +#define LPS22HH_DT_ODR_POWER_DOWN 0 +#define LPS22HH_DT_ODR_1HZ 1 +#define LPS22HH_DT_ODR_10HZ 2 +#define LPS22HH_DT_ODR_25HZ 3 +#define LPS22HH_DT_ODR_50HZ 4 +#define LPS22HH_DT_ODR_75HZ 5 +#define LPS22HH_DT_ODR_100HZ 6 +#define LPS22HH_DT_ODR_200HZ 7 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22HH_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 6c00025d8dd29b8..b8bbc74b8860062 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -323,6 +324,7 @@ test_i2c_lps22hh: lps22hh@32 { compatible = "st,lps22hh"; reg = <0x32>; drdy-gpios = <&test_gpio 0 0>; + odr = ; }; test_i2c_lps25hb_press: lps25hb-press@33 { From a6cfa0bc15bf5578cd07e0aec169b9c48c71b13b Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 11:23:14 +0100 Subject: [PATCH 0682/1049] dt-bindings: sensor: lps22df: add macros for DT properties setting Add macros for setting in a clear way lps22df DT properties. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,lps22df-common.yaml | 84 ++++++++++----------- include/zephyr/dt-bindings/sensor/lps22df.h | 35 +++++++++ tests/drivers/build_all/sensor/i2c.dtsi | 4 + 3 files changed, 80 insertions(+), 43 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/lps22df.h diff --git a/dts/bindings/sensor/st,lps22df-common.yaml b/dts/bindings/sensor/st,lps22df-common.yaml index 7a1f21573b2ba86..cc3f11c106fb388 100644 --- a/dts/bindings/sensor/st,lps22df-common.yaml +++ b/dts/bindings/sensor/st,lps22df-common.yaml @@ -1,6 +1,21 @@ # Copyright (c) 2023 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the odr, lpf, avg properties in a .dts or .dtsi file + you may include st_lps22df.h and use the macros defined there. + + Example: + #include + + lps22df@5d { + ... + + odr = ; + lpf = ; + avg = ; + }; + include: sensor-device.yaml properties: @@ -26,25 +41,17 @@ properties: Specify the output data rate expressed in samples per second (Hz). The default is the power-on reset value. - 0 = Power-Down - 1 = 1Hz - 2 = 4Hz - 3 = 10Hz - 4 = 25Hz - 5 = 50Hz - 6 = 75Hz - 7 = 100Hz - 8 = 200Hz - enum: - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 + - 0 # LPS22DF_DT_ODR_POWER_DOWN + - 1 # LPS22DF_DT_ODR_1HZ + - 2 # LPS22DF_DT_ODR_4HZ + - 3 # LPS22DF_DT_ODR_10HZ + - 4 # LPS22DF_DT_ODR_25HZ + - 5 # LPS22DF_DT_ODR_50HZ + - 6 # LPS22DF_DT_ODR_75HZ + - 7 # LPS22DF_DT_ODR_100HZ + - 8 # LPS22DF_DT_ODR_200HZ + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8] lpf: type: int @@ -53,13 +60,11 @@ properties: Specify the low pass filter value to be applied to pressure data. The default is the power-on reset value. - 0 = Low Pass Filter disabled - 1 = Low Pass Filter set to ODR/4 - 3 = Low Pass Filter set to ODR/9 - enum: - - 0 - - 1 - - 3 + - 0 # LPS22DF_DT_LP_FILTER_OFF + - 1 # LPS22DF_DT_LP_FILTER_ODR_4 + - 3 # LPS22DF_DT_LP_FILTER_ODR_9 + + enum: [0, 1, 3] avg: type: int @@ -69,20 +74,13 @@ properties: to pressure and temperature data. The default is the power-on reset value. - 0 = Average of 4 data samples - 1 = Average of 8 data samples - 2 = Average of 16 data samples - 3 = Average of 32 data samples - 4 = Average of 64 data samples - 5 = Average of 128 data samples - 6 = Average of 256 data samples - 7 = Average of 512 data samples - enum: - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 + - 0 # LPS22DF_DT_AVG_4_SAMPLES + - 1 # LPS22DF_DT_AVG_8_SAMPLES + - 2 # LPS22DF_DT_AVG_16_SAMPLES + - 3 # LPS22DF_DT_AVG_32_SAMPLES + - 4 # LPS22DF_DT_AVG_64_SAMPLES + - 5 # LPS22DF_DT_AVG_128_SAMPLES + - 6 # LPS22DF_DT_AVG_256_SAMPLES + - 7 # LPS22DF_DT_AVG_512_SAMPLES + + enum: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/include/zephyr/dt-bindings/sensor/lps22df.h b/include/zephyr/dt-bindings/sensor/lps22df.h new file mode 100644 index 000000000000000..95668ae63903eb5 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lps22df.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ + +/* Data rate */ +#define LPS22DF_DT_ODR_POWER_DOWN 0 +#define LPS22DF_DT_ODR_1HZ 1 +#define LPS22DF_DT_ODR_4HZ 2 +#define LPS22DF_DT_ODR_10HZ 3 +#define LPS22DF_DT_ODR_25HZ 4 +#define LPS22DF_DT_ODR_50HZ 5 +#define LPS22DF_DT_ODR_75HZ 6 +#define LPS22DF_DT_ODR_100HZ 7 +#define LPS22DF_DT_ODR_200HZ 8 + +/* Low Pass filter */ +#define LPS22DF_DT_LP_FILTER_OFF 0 +#define LPS22DF_DT_LP_FILTER_ODR_4 1 +#define LPS22DF_DT_LP_FILTER_ODR_9 3 + +/* Average (number of samples) filter */ +#define LPS22DF_DT_AVG_4_SAMPLES 0 +#define LPS22DF_DT_AVG_8_SAMPLES 1 +#define LPS22DF_DT_AVG_16_SAMPLES 2 +#define LPS22DF_DT_AVG_32_SAMPLES 3 +#define LPS22DF_DT_AVG_64_SAMPLES 4 +#define LPS22DF_DT_AVG_128_SAMPLES 5 +#define LPS22DF_DT_AVG_256_SAMPLES 6 +#define LPS22DF_DT_AVG_512_SAMPLES 7 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index b8bbc74b8860062..ca8eefd5e681db1 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -826,6 +827,9 @@ test_i2c_lps22df: lps22df@79 { reg = <0x79>; drdy-gpios = <&test_gpio 0 0>; status = "okay"; + odr = ; + lpf = ; + avg = ; }; test_i2c_hs300x: hs300x@79 { From 2fe89c1076f8096ecec0c8db0ec599e0df3eff3d Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 11:26:04 +0100 Subject: [PATCH 0683/1049] dt-bindings: sensor: lis2ds12: add macros for DT properties setting Add macros for setting in a clear way lis2ds12 DT properties. Signed-off-by: Armando Visconti --- drivers/sensor/lis2ds12/lis2ds12.c | 6 ++- dts/bindings/sensor/st,lis2ds12-common.yaml | 56 +++++++++++++------- include/zephyr/dt-bindings/sensor/lis2ds12.h | 29 ++++++++++ tests/drivers/build_all/sensor/i2c.dtsi | 3 ++ 4 files changed, 73 insertions(+), 21 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/lis2ds12.h diff --git a/drivers/sensor/lis2ds12/lis2ds12.c b/drivers/sensor/lis2ds12/lis2ds12.c index ae7fa9eb81f643e..c9634b2179f5ca5 100644 --- a/drivers/sensor/lis2ds12/lis2ds12.c +++ b/drivers/sensor/lis2ds12/lis2ds12.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "lis2ds12.h" @@ -40,8 +41,9 @@ static int lis2ds12_set_odr(const struct device *dev, uint8_t odr) * 12,5Hz <= odr <= 800Hz are available in LP and HR mode only * odr == 1Hz is available in LP mode only */ - if ((odr >= 9 && cfg->pm != 3) || (odr < 9 && cfg->pm == 3) || - (odr == 1 && cfg->pm != 1)) { + if ((odr >= LIS2DS12_DT_ODR_1600Hz && cfg->pm != LIS2DS12_DT_HIGH_FREQUENCY) || + (odr < LIS2DS12_DT_ODR_1600Hz && cfg->pm == LIS2DS12_DT_HIGH_FREQUENCY) || + (odr == LIS2DS12_DT_ODR_1Hz_LP && cfg->pm != LIS2DS12_DT_LOW_POWER)) { LOG_ERR("%s: bad odr and pm combination", dev->name); return -ENOTSUP; } diff --git a/dts/bindings/sensor/st,lis2ds12-common.yaml b/dts/bindings/sensor/st,lis2ds12-common.yaml index 4a5926c42ad21a7..4ac18b40a553c0e 100644 --- a/dts/bindings/sensor/st,lis2ds12-common.yaml +++ b/dts/bindings/sensor/st,lis2ds12-common.yaml @@ -1,6 +1,20 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the odr and power-mode properties in a .dts or .dtsi file you may include + st_lis2ds12.h and use the macros defined there. + + Example: + #include + + lis2ds12: lis2ds12@0 { + ... + + power-mode = ; + odr = ; + }; + include: sensor-device.yaml properties: @@ -19,23 +33,25 @@ properties: description: | Range in g. Default is power-up configuration. - enum: - 16 # 16g (0.488 mg/LSB) - 8 # 8g (0.244 mg/LSB) - 4 # 4g (0.122 mg/LSB) - 2 # 2g (0.061 mg/LSB) + enum: [16, 8, 4, 2] + power-mode: type: int default: 0 description: | Specify the sensor power mode. Default is power-down mode - enum: - - 0 # Power Down (PD) - - 1 # Low Power (LP) - - 2 # High Resolution (HR) - - 3 # High Frequency (HF) + - 0 # LIS2DS12_DT_POWER_DOWN + - 1 # LIS2DS12_DT_LOW_POWER + - 2 # LIS2DS12_DT_HIGH_RESOLUTION + - 3 # LIS2DS12_DT_HIGH_FREQUENCY + + enum: [0, 1, 2, 3] odr: type: int @@ -43,16 +59,18 @@ properties: description: | Specify the default output data rate expressed in samples per second (Hz). Default is power-down mode - enum: - - 0 # Power-Down - - 1 # 1Hz (available in LP mode only) - - 2 # 12.5Hz (available in LP and HR mode) - - 3 # 25Hz (available in LP and HR mode) - - 4 # 50Hz (available in LP and HR mode) - - 5 # 100Hz (available in LP and HR mode) - - 6 # 200Hz (available in LP and HR mode) - - 7 # 400Hz (available in LP and HR mode) - - 8 # 800Hz (available in LP and HR mode) - - 9 # 1600Hz (available in HF mode only) - - 10 # 3200Hz (available in HF mode only) - - 11 # 6400Hz (available in HF mode only) + + - 0 # LIS2DS12_DT_ODR_OFF + - 1 # LIS2DS12_DT_ODR_1Hz_LP + - 2 # LIS2DS12_DT_ODR_12Hz5 + - 3 # LIS2DS12_DT_ODR_25Hz + - 4 # LIS2DS12_DT_ODR_50Hz + - 5 # LIS2DS12_DT_ODR_100Hz + - 6 # LIS2DS12_DT_ODR_200Hz + - 7 # LIS2DS12_DT_ODR_400Hz + - 8 # LIS2DS12_DT_ODR_800Hz + - 9 # LIS2DS12_DT_ODR_1600Hz + - 10 # LIS2DS12_DT_ODR_3200Hz_HF + - 11 # LIS2DS12_DT_ODR_6400Hz_HF + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] diff --git a/include/zephyr/dt-bindings/sensor/lis2ds12.h b/include/zephyr/dt-bindings/sensor/lis2ds12.h new file mode 100644 index 000000000000000..04d808bfa72d792 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2ds12.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DS12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DS12_H_ + +/* power-modes */ +#define LIS2DS12_DT_POWER_DOWN 0 +#define LIS2DS12_DT_LOW_POWER 1 +#define LIS2DS12_DT_HIGH_RESOLUTION 2 +#define LIS2DS12_DT_HIGH_FREQUENCY 3 + +/* Data rate */ +#define LIS2DS12_DT_ODR_OFF 0 +#define LIS2DS12_DT_ODR_1Hz_LP 1 /* available in LP mode only */ +#define LIS2DS12_DT_ODR_12Hz5 2 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_25Hz 3 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_50Hz 4 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_100Hz 5 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_200Hz 6 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_400Hz 7 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_800Hz 8 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_1600Hz 9 /* available in HF mode only */ +#define LIS2DS12_DT_ODR_3200Hz_HF 10 /* available in HF mode only */ +#define LIS2DS12_DT_ODR_6400Hz_HF 11 /* available in HF mode only */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DS12_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index ca8eefd5e681db1..85313f211f298ba 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -11,6 +11,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -289,6 +290,8 @@ test_i2c_lis2ds12: lis2ds12@2c { compatible = "st,lis2ds12"; reg = <0x2c>; irq-gpios = <&test_gpio 0 0>; + power-mode = ; + odr = ; }; test_i2c_lis2dw12: lis2dw12@2d { From 0b46f387f4a48bb9ff969e2ebd46d118dd0a23f9 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 11:28:05 +0100 Subject: [PATCH 0684/1049] dt-bindings: sensor: lis2dw12: add macros for DT properties setting Add macros for setting in a clear way lis2dw12 DT properties. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,lis2dw12-common.yaml | 119 ++++++++----------- include/zephyr/dt-bindings/sensor/lis2dw12.h | 42 +++++++ tests/drivers/build_all/sensor/i2c.dtsi | 6 + 3 files changed, 100 insertions(+), 67 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/lis2dw12.h diff --git a/dts/bindings/sensor/st,lis2dw12-common.yaml b/dts/bindings/sensor/st,lis2dw12-common.yaml index 364e4320849a61d..0c9f8dcee678935 100644 --- a/dts/bindings/sensor/st,lis2dw12-common.yaml +++ b/dts/bindings/sensor/st,lis2dw12-common.yaml @@ -1,6 +1,23 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the odr property in a .dts or .dtsi file you may include + st_lis2dw12.h and use the macros defined there. + + Example: + #include + + lis2dw12: lis2dw12@0 { + ... + + wakeup-duration = ; + ff-threshold = ; + tap-mode = ; + power-mode = ; + bw-filt = ; + }; + include: sensor-device.yaml properties: @@ -16,9 +33,8 @@ properties: int-pin: type: int default: 1 - enum: - - 1 - - 2 + enum: [1, 2] + description: | Select DRDY pin number (1 or 2). @@ -41,11 +57,7 @@ properties: 4 # 4g (0.488 mg/LSB) 2 # 2g (0.244 mg/LSB) - enum: - - 16 - - 8 - - 4 - - 2 + enum: [16, 8, 4, 2] odr: type: int @@ -56,17 +68,7 @@ properties: If 0 selected as the odr, the accelerometer initializes into power off state. - enum: - - 0 - - 1 - - 12 - - 25 - - 50 - - 100 - - 200 - - 400 - - 800 - - 1600 + enum: [0, 1, 12, 25, 50, 100, 200, 400, 800, 1600] bw-filt: type: int @@ -74,16 +76,12 @@ properties: description: | Digital filtering cutoff bandwidth. Default is power-up configuration. - 3 # ODR/20 (HP/LP) - 2 # ODR/10 (HP/LP) - 1 # ODR/ 4 (HP/LP) - 0 # ODR/ 2 (up to ODR = 800 Hz, 400 Hz when ODR = 1600 Hz) + - 0 # LIS2DW12_DT_FILTER_BW_ODR_DIV_2 + - 1 # LIS2DW12_DT_FILTER_BW_ODR_DIV_4 + - 2 # LIS2DW12_DT_FILTER_BW_ODR_DIV_10 + - 3 # LIS2DW12_DT_FILTER_BW_ODR_DIV_20 - enum: - - 3 - - 2 - - 1 - - 0 + enum: [0, 1, 2, 3] power-mode: type: int @@ -91,18 +89,13 @@ properties: description: | Specify the sensor power mode. Default is power-up configuration. - 0 # Low Power M1 - 1 # Low Power M2 - 2 # Low Power M3 - 3 # Low Power M4 - 4 # High Performance + - 0 # LIS2DW12_DT_LP_M1 + - 1 # LIS2DW12_DT_LP_M2 + - 2 # LIS2DW12_DT_LP_M3 + - 3 # LIS2DW12_DT_LP_M4 + - 4 # LIS2DW12_DT_HP_MODE - enum: - - 0 - - 1 - - 2 - - 3 - - 4 + enum: [0, 1, 2, 3, 4] # tap and tap-tap configuration section # All default values are selected to match the power-up values. @@ -114,12 +107,10 @@ properties: description: | Tap mode. Default is power-up configuration. - 0 # Only Single Tap - 1 # Single and Double Tap + - 0 # LIS2DW12_DT_SINGLE_TAP + - 1 # LIS2DW12_DT_SINGLE_DOUBLE_TAP - enum: - - 0 - - 1 + enum: [0, 1] tap-threshold: type: array @@ -228,24 +219,17 @@ properties: than the freefall threshold value for the freefall duration long, then a freefall trigger occurs. This value is 3 bits long. Default value chosen 3 (312 mg) refer to ST DT0100 design tip document. - 0 # ~156mg - 1 # ~219mg - 2 # ~250mg - 3 # ~312mg - 4 # ~344mg - 5 # ~406mg - 6 # ~469mg - 7 # ~500mg - - enum: - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 + + - 0 # LIS2DW12_DT_FF_THRESHOLD_156_mg + - 1 # LIS2DW12_DT_FF_THRESHOLD_219_mg + - 2 # LIS2DW12_DT_FF_THRESHOLD_250_mg + - 3 # LIS2DW12_DT_FF_THRESHOLD_312_mg + - 4 # LIS2DW12_DT_FF_THRESHOLD_344_mg + - 5 # LIS2DW12_DT_FF_THRESHOLD_406_mg + - 6 # LIS2DW12_DT_FF_THRESHOLD_469_mg + - 7 # LIS2DW12_DT_FF_THRESHOLD_500_mg + + enum: [0, 1, 2, 3, 4, 5, 6, 7] wakeup-duration: type: int @@ -257,8 +241,9 @@ properties: then a wakeup trigger occurs. This value is 2 bits long in the register and 1 LSB = 1 * 1/ODR. - enum: - - 0 - - 1 - - 2 - - 3 + - 0 # LIS2DW12_DT_WAKEUP_1_ODR + - 1 # LIS2DW12_DT_WAKEUP_2_ODR + - 2 # LIS2DW12_DT_WAKEUP_3_ODR + - 3 # LIS2DW12_DT_WAKEUP_4_ODR + + enum: [0, 1, 2, 3] diff --git a/include/zephyr/dt-bindings/sensor/lis2dw12.h b/include/zephyr/dt-bindings/sensor/lis2dw12.h new file mode 100644 index 000000000000000..9e5892ec0a52dd2 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2dw12.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DW12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DW12_H_ + +/* power-modes */ +#define LIS2DW12_DT_LP_M1 0 +#define LIS2DW12_DT_LP_M2 1 +#define LIS2DW12_DT_LP_M3 2 +#define LIS2DW12_DT_LP_M4 3 +#define LIS2DW12_DT_HP_MODE 4 + +/* Filter bandwidth */ +#define LIS2DW12_DT_FILTER_BW_ODR_DIV_2 0 +#define LIS2DW12_DT_FILTER_BW_ODR_DIV_4 1 +#define LIS2DW12_DT_FILTER_BW_ODR_DIV_10 2 +#define LIS2DW12_DT_FILTER_BW_ODR_DIV_20 3 + +/* Tap mode */ +#define LIS2DW12_DT_SINGLE_TAP 0 +#define LIS2DW12_DT_SINGLE_DOUBLE_TAP 1 + +/* Free-Fall threshold */ +#define LIS2DW12_DT_FF_THRESHOLD_156_mg 0 +#define LIS2DW12_DT_FF_THRESHOLD_219_mg 1 +#define LIS2DW12_DT_FF_THRESHOLD_250_mg 2 +#define LIS2DW12_DT_FF_THRESHOLD_312_mg 3 +#define LIS2DW12_DT_FF_THRESHOLD_344_mg 4 +#define LIS2DW12_DT_FF_THRESHOLD_406_mg 5 +#define LIS2DW12_DT_FF_THRESHOLD_469_mg 6 +#define LIS2DW12_DT_FF_THRESHOLD_500_mg 7 + +/* wakeup duration */ +#define LIS2DW12_DT_WAKEUP_1_ODR 0 +#define LIS2DW12_DT_WAKEUP_2_ODR 1 +#define LIS2DW12_DT_WAKEUP_3_ODR 2 +#define LIS2DW12_DT_WAKEUP_4_ODR 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DW12_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 85313f211f298ba..2f6866771622a1b 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -12,6 +12,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -298,6 +299,11 @@ test_i2c_lis2dw12: lis2dw12@2d { compatible = "st,lis2dw12"; reg = <0x2d>; irq-gpios = <&test_gpio 0 0>; + wakeup-duration = ; + ff-threshold = ; + tap-mode = ; + power-mode = ; + bw-filt = ; }; test_i2c_lis2mdl: lis2mdl@2e { From 0d68d9e493efe784c227a1eb1cd38178de27d836 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 11:29:40 +0100 Subject: [PATCH 0685/1049] dt-bindings: sensor: ism330dhcx: add macros for DT properties setting Add macros for setting in a clear way ism330dhcx DT properties. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,ism330dhcx-common.yaml | 128 ++++++++---------- .../zephyr/dt-bindings/sensor/ism330dhcx.h | 23 ++++ tests/drivers/build_all/sensor/i2c.dtsi | 3 + 3 files changed, 81 insertions(+), 73 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/ism330dhcx.h diff --git a/dts/bindings/sensor/st,ism330dhcx-common.yaml b/dts/bindings/sensor/st,ism330dhcx-common.yaml index 93d9be0890ef87f..f00f37c17006691 100644 --- a/dts/bindings/sensor/st,ism330dhcx-common.yaml +++ b/dts/bindings/sensor/st,ism330dhcx-common.yaml @@ -1,6 +1,20 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the accel-odr and gyro-odr properties in a .dts or .dtsi file you may include + st_ism330dhcx.h and use the macros defined there. + + Example: + #include + + ism330dhcx: ism330dhcx@0 { + ... + + accel-odr = ; + gyro-odr = ; + }; + include: sensor-device.yaml properties: @@ -27,9 +41,7 @@ properties: (INT1 or INT2) the drdy line is attached to. This property is not mandatory and if not present it defaults to 1 which is the configuration at power-up. - enum: - - 1 - - 2 + enum: [1, 2] accel-odr: type: int @@ -38,30 +50,20 @@ properties: Specify the default accelerometer output data rate expressed in samples per second (Hz). Default is power-up configuration. - Selection - 0 Power-Down - 1 12.5Hz - 2 26Hz - 3 52Hz - 4 104Hz - 5 208Hz - 6 416Hz - 7 833Hz - 8 1660Hz - 9 3330Hz - 10 6660Hz - enum: - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9 - - 10 + - 0 # ISM330DHCX_DT_ODR_OFF + - 1 # ISM330DHCX_DT_ODR_12Hz5 + - 2 # ISM330DHCX_DT_ODR_26H + - 3 # ISM330DHCX_DT_ODR_52Hz + - 4 # ISM330DHCX_DT_ODR_104Hz + - 5 # ISM330DHCX_DT_ODR_208Hz + - 6 # ISM330DHCX_DT_ODR_416Hz + - 7 # ISM330DHCX_DT_ODR_833Hz + - 8 # ISM330DHCX_DT_ODR_1666Hz + - 9 # ISM330DHCX_DT_ODR_3332Hz + - 10 # ISM330DHCX_DT_ODR_6667Hz + - 11 # ISM330DHCX_DT_ODR_1Hz6 + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] accel-range: type: int @@ -69,16 +71,12 @@ properties: description: | Range in g. Default is power-up configuration. - Selection - 16 16g (0.488 mg/LSB) - 8 8g (0.244 mg/LSB) - 4 4g (0.122 mg/LSB) - 2 2g (0.061 mg/LSB) - enum: - - 16 - - 8 - - 4 - - 2 + - 16 # 16g (0.488 mg/LSB) + - 8 # 8g (0.244 mg/LSB) + - 4 # 4g (0.122 mg/LSB) + - 2 # 2g (0.061 mg/LSB) + + enum: [16, 8, 4, 2] gyro-odr: type: int @@ -87,30 +85,19 @@ properties: Specify the default gyro output data rate expressed in samples per second (Hz). Default is power-up configuration. - Selection - 0 Power-Down - 1 12.5Hz - 2 26Hz - 3 52Hz - 4 104Hz - 5 208Hz - 6 416Hz - 7 833Hz - 8 1660Hz - 9 3330Hz - 10 6660Hz - enum: - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9 - - 10 + - 0 # ISM330DHCX_DT_ODR_OFF + - 1 # ISM330DHCX_DT_ODR_12Hz5 + - 2 # ISM330DHCX_DT_ODR_26H + - 3 # ISM330DHCX_DT_ODR_52Hz + - 4 # ISM330DHCX_DT_ODR_104Hz + - 5 # ISM330DHCX_DT_ODR_208Hz + - 6 # ISM330DHCX_DT_ODR_416Hz + - 7 # ISM330DHCX_DT_ODR_833Hz + - 8 # ISM330DHCX_DT_ODR_1666Hz + - 9 # ISM330DHCX_DT_ODR_3332Hz + - 10 # ISM330DHCX_DT_ODR_6667Hz + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] gyro-range: type: int @@ -118,15 +105,10 @@ properties: description: | Range in dps. Default is power-up configuration. - Selection - 125 +/- 125dps - 250 +/- 250dps - 500 +/- 500dps - 1000 +/- 1000dps - 2000 +/- 2000dps - enum: - - 125 - - 250 - - 500 - - 1000 - - 2000 + - 125 # +/- 125dps + - 250 # +/- 250dps + - 500 # +/- 500dps + - 1000 # +/- 1000dps + - 2000 # +/- 2000dps + + enum: [125, 250, 500, 1000, 2000] diff --git a/include/zephyr/dt-bindings/sensor/ism330dhcx.h b/include/zephyr/dt-bindings/sensor/ism330dhcx.h new file mode 100644 index 000000000000000..7d857eb165a662b --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/ism330dhcx.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_ISM330DHCX_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_ISM330DHCX_H_ + +/* Accel and Gyro Data rates */ +#define ISM330DHCX_DT_ODR_OFF 0x0 +#define ISM330DHCX_DT_ODR_12Hz5 0x1 +#define ISM330DHCX_DT_ODR_26H 0x2 +#define ISM330DHCX_DT_ODR_52Hz 0x3 +#define ISM330DHCX_DT_ODR_104Hz 0x4 +#define ISM330DHCX_DT_ODR_208Hz 0x5 +#define ISM330DHCX_DT_ODR_416Hz 0x6 +#define ISM330DHCX_DT_ODR_833Hz 0x7 +#define ISM330DHCX_DT_ODR_1666Hz 0x8 +#define ISM330DHCX_DT_ODR_3332Hz 0x9 +#define ISM330DHCX_DT_ODR_6667Hz 0xa +#define ISM330DHCX_DT_ODR_1Hz6 0xb + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_ISM330DHCX_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 2f6866771622a1b..b054a0b2defc469 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -13,6 +13,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -271,6 +272,8 @@ test_i2c_ism330dhcx: ism330dhcx@29 { compatible = "st,ism330dhcx"; reg = <0x29>; drdy-gpios = <&test_gpio 0 0>; + accel-odr = ; + gyro-odr = ; }; test_i2c_lis2dh: lis2dh@2a { From 6e09f91fec00c0bcdfc8ea4a9be5529c6453d3ec Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 11:31:10 +0100 Subject: [PATCH 0686/1049] dt-bindings: sensor: iis2dlpc: add macros for DT properties setting Add macros for setting in a clear way iis2dlpc DT properties. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,iis2dlpc-common.yaml | 59 ++++++++++++++------ include/zephyr/dt-bindings/sensor/iis2dlpc.h | 42 ++++++++++++++ tests/drivers/build_all/sensor/i2c.dtsi | 3 + 3 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/iis2dlpc.h diff --git a/dts/bindings/sensor/st,iis2dlpc-common.yaml b/dts/bindings/sensor/st,iis2dlpc-common.yaml index 36c258df4b12a5e..997b0b189f03c28 100644 --- a/dts/bindings/sensor/st,iis2dlpc-common.yaml +++ b/dts/bindings/sensor/st,iis2dlpc-common.yaml @@ -1,6 +1,20 @@ # Copyright (c) 2018 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the odr property in a .dts or .dtsi file you may include + st_iis2dlpc.h and use the macros defined there. + + Example: + #include + + iis2dlpc: iis2dlpc@0 { + ... + + tap-mode = ; + power-mode = ; + }; + include: sensor-device.yaml properties: @@ -16,36 +30,44 @@ properties: drdy-int: type: int default: 1 - enum: - - 1 # drdy is generated from INT1 - - 2 # drdy is generated from INT2 - description: Select DRDY pin number (1 or 2). + enum: [1, 2] + description: | + Select DRDY pin number (1 or 2). This number represents which of the two interrupt pins (INT1 or INT2) the drdy line is attached to. This property is not mandatory and if not present it defaults to 1 which is the configuration at power-up. + - 1 # drdy is generated from INT1 + - 2 # drdy is generated from INT2 + range: type: int default: 2 - description: Range in g. Default is power-up configuration. - enum: + description: | + Range in g. Default is power-up configuration. + - 16 # 16g (1.952 mg/LSB) - 8 # 8g (0.976 mg/LSB) - 4 # 4g (0.488 mg/LSB) - 2 # 2g (0.244 mg/LSB) + enum: [16, 8, 4, 2] + power-mode: type: int default: 0 - description: Specify the sensor power mode. Default is power-up configuration. - enum: - - 0 # Low Power M1 - - 1 # Low Power M2 - - 2 # Low Power M3 - - 3 # Low Power M4 - - 4 # High Performance + description: | + Specify the sensor power mode. Default is power-up configuration. + + - 0 # IIS2DLPC_DT_LP_M1 + - 1 # IIS2DLPC_DT_LP_M2 + - 2 # IIS2DLPC_DT_LP_M3 + - 3 # IIS2DLPC_DT_LP_M4 + - 4 # IIS2DLPC_DT_HP_MODE + + enum: [0, 1, 2, 3, 4] # tap and tap-tap configuration section # All default values are selected to match the power-up values. @@ -54,10 +76,13 @@ properties: tap-mode: type: int default: 0 - description: Tap mode. Default is power-up configuration. - enum: - - 0 # Only Single Tap - - 1 # Single and Double Tap + description: | + Tap mode. Default is power-up configuration. + + - 0 # IIS2DLPC_DT_SINGLE_TAP + - 1 # IIS2DLPC_DT_SINGLE_DOUBLE_TAP + + enum: [0, 1] tap-threshold: type: array diff --git a/include/zephyr/dt-bindings/sensor/iis2dlpc.h b/include/zephyr/dt-bindings/sensor/iis2dlpc.h new file mode 100644 index 000000000000000..abf6df1cc443606 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/iis2dlpc.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2DLPC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2DLPC_H_ + +/* power-modes */ +#define IIS2DLPC_DT_LP_M1 0 +#define IIS2DLPC_DT_LP_M2 1 +#define IIS2DLPC_DT_LP_M3 2 +#define IIS2DLPC_DT_LP_M4 3 +#define IIS2DLPC_DT_HP_MODE 4 + +/* Filter bandwidth */ +#define IIS2DLPC_DT_FILTER_BW_ODR_DIV_2 0 +#define IIS2DLPC_DT_FILTER_BW_ODR_DIV_4 1 +#define IIS2DLPC_DT_FILTER_BW_ODR_DIV_10 2 +#define IIS2DLPC_DT_FILTER_BW_ODR_DIV_20 3 + +/* Tap mode */ +#define IIS2DLPC_DT_SINGLE_TAP 0 +#define IIS2DLPC_DT_SINGLE_DOUBLE_TAP 1 + +/* Free-Fall threshold */ +#define IIS2DLPC_DT_FF_THRESHOLD_156_mg 0 +#define IIS2DLPC_DT_FF_THRESHOLD_219_mg 1 +#define IIS2DLPC_DT_FF_THRESHOLD_250_mg 2 +#define IIS2DLPC_DT_FF_THRESHOLD_312_mg 3 +#define IIS2DLPC_DT_FF_THRESHOLD_344_mg 4 +#define IIS2DLPC_DT_FF_THRESHOLD_406_mg 5 +#define IIS2DLPC_DT_FF_THRESHOLD_469_mg 6 +#define IIS2DLPC_DT_FF_THRESHOLD_500_mg 7 + +/* wakeup duration */ +#define IIS2DLPC_DT_WAKEUP_1_ODR 0 +#define IIS2DLPC_DT_WAKEUP_2_ODR 1 +#define IIS2DLPC_DT_WAKEUP_3_ODR 2 +#define IIS2DLPC_DT_WAKEUP_4_ODR 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2DLPC_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index b054a0b2defc469..a10717f8e373640 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -14,6 +14,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -260,6 +261,8 @@ test_i2c_iis2dlpc: iis2dlpc@27 { compatible = "st,iis2dlpc"; reg = <0x27>; drdy-gpios = <&test_gpio 0 0>; + tap-mode = ; + power-mode = ; }; test_i2c_iis2mdc: iis2mdc@28 { From 273475804e2152b7697f318abb55cd2e135e5742 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 12:21:55 +0100 Subject: [PATCH 0687/1049] dt-bindings: sensor: lis2dh: add macros for DT properties setting Add macros for setting in a clear way lis2dh DT properties. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,lis2dh-common.yaml | 72 ++++++++++++---------- include/zephyr/dt-bindings/sensor/lis2dh.h | 22 +++++++ tests/drivers/build_all/sensor/i2c.dtsi | 4 ++ 3 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/lis2dh.h diff --git a/dts/bindings/sensor/st,lis2dh-common.yaml b/dts/bindings/sensor/st,lis2dh-common.yaml index 7ba07fc4b12a728..351fa0dc97fda79 100644 --- a/dts/bindings/sensor/st,lis2dh-common.yaml +++ b/dts/bindings/sensor/st,lis2dh-common.yaml @@ -1,6 +1,21 @@ # Copyright (c) 2018 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the int1-gpio-config/int2-gpio-config and anym-mode properties + in a .dts or .dtsi file you may include st_lis2dh.h and use the macros defined there. + + Example: + #include + + lis2dh: lis2dh@0 { + ... + + int1-gpio-config = ; + int2-gpio-config = ; + anym-mode = ; + }; + include: sensor-device.yaml properties: @@ -16,20 +31,16 @@ properties: description: | Select the interrupt configuration for INT1 gpio. - 0 = GPIO_INT_EDGE - 1 = GPIO_INT_EDGE_RISING - 2 = GPIO_INT_EDGE_FALLING - 3 = GPIO_INT_LEVEL_HIGH - 4 = GPIO_INT_LEVEL_LOW - The default of 0 is the most common situation to avoid multiple interrupts to be triggered by same event. - enum: - - 0 - - 1 - - 2 - - 3 - - 4 + + - 0 # LIS2DH_DT_GPIO_INT_EDGE + - 1 # LIS2DH_DT_GPIO_INT_EDGE_RISING + - 2 # LIS2DH_DT_GPIO_INT_EDGE_FALLING + - 3 # LIS2DH_DT_GPIO_INT_LEVEL_HIGH + - 4 # LIS2DH_DT_GPIO_INT_LEVEL_LOW + + enum: [0, 1, 2, 3, 4] int2-gpio-config: type: int @@ -37,20 +48,16 @@ properties: description: | Select the interrupt configuration for INT2 gpio. - 0 = GPIO_INT_EDGE - 1 = GPIO_INT_EDGE_RISING - 2 = GPIO_INT_EDGE_FALLING - 3 = GPIO_INT_LEVEL_HIGH - 4 = GPIO_INT_LEVEL_LOW - The default of 0 is the most common situation to avoid multiple interrupts to be triggered by same event. - enum: - - 0 - - 1 - - 2 - - 3 - - 4 + + - 0 # LIS2DH_DT_GPIO_INT_EDGE + - 1 # LIS2DH_DT_GPIO_INT_EDGE_RISING + - 2 # LIS2DH_DT_GPIO_INT_EDGE_FALLING + - 3 # LIS2DH_DT_GPIO_INT_LEVEL_HIGH + - 4 # LIS2DH_DT_GPIO_INT_LEVEL_LOW + + enum: [0, 1, 2, 3, 4] disconnect-sdo-sa0-pull-up: type: boolean @@ -78,14 +85,11 @@ properties: description: | Select the interrupt mode for any movement. - 0 = OR combination of interrupt events - 1 = 6D movement recognition - 2 = AND combination of interrupt events - 3 = 6D position recognition - The default of 0 is the power-on-reset value. - enum: - - 0 - - 1 - - 2 - - 3 + + - 0 # LIS2DH_DT_ANYM_OR_COMBINATION + - 1 # LIS2DH_DT_ANYM_6D_MOVEMENT + - 2 # LIS2DH_DT_ANYM_AND_COMBINATION + - 3 # LIS2DH_DT_ANYM_6D_POSITION + + enum: [0, 1, 2, 3] diff --git a/include/zephyr/dt-bindings/sensor/lis2dh.h b/include/zephyr/dt-bindings/sensor/lis2dh.h new file mode 100644 index 000000000000000..a697f34cc802465 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2dh.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DH_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DH_H_ + +/* GPIO interrupt configuration */ +#define LIS2DH_DT_GPIO_INT_EDGE 0 +#define LIS2DH_DT_GPIO_INT_EDGE_RISING 1 +#define LIS2DH_DT_GPIO_INT_EDGE_FALLING 2 +#define LIS2DH_DT_GPIO_INT_LEVEL_HIGH 3 +#define LIS2DH_DT_GPIO_INT_LEVEL_LOW 4 + +/* Any Motion mode */ +#define LIS2DH_DT_ANYM_OR_COMBINATION 0 +#define LIS2DH_DT_ANYM_6D_MOVEMENT 1 +#define LIS2DH_DT_ANYM_AND_COMBINATION 2 +#define LIS2DH_DT_ANYM_6D_POSITION 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DH_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index a10717f8e373640..b858e9bbb2fc312 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -15,6 +15,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -284,6 +285,9 @@ test_i2c_lis2dh: lis2dh@2a { reg = <0x2a>; irq-gpios = <&test_gpio 0 0>; /* disconnect-sdo-sa0-pull-up; */ + int1-gpio-config = ; + int2-gpio-config = ; + anym-mode = ; }; test_i2c_lis2dh12: lis2dh12@2b { From 194ee015f92b7d069c16cc8badf95225712b6b59 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 12:41:22 +0100 Subject: [PATCH 0688/1049] dt-bindings: sensor: iis2iclx: add macros for DT property setting Add macros for setting in a clear way iis2iclx DT properties. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,iis2iclx-common.yaml | 67 +++++++++++++------- include/zephyr/dt-bindings/sensor/iis2iclx.h | 25 ++++++++ tests/drivers/build_all/sensor/i2c.dtsi | 3 + 3 files changed, 71 insertions(+), 24 deletions(-) create mode 100644 include/zephyr/dt-bindings/sensor/iis2iclx.h diff --git a/dts/bindings/sensor/st,iis2iclx-common.yaml b/dts/bindings/sensor/st,iis2iclx-common.yaml index 9551c274ae10e5e..0a312824c989d4a 100644 --- a/dts/bindings/sensor/st,iis2iclx-common.yaml +++ b/dts/bindings/sensor/st,iis2iclx-common.yaml @@ -1,12 +1,27 @@ # Copyright (c) 2020 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the range, odr properties in a .dts or .dtsi file you may + include st_iis2iclx.h and use the macros defined there. + + Example: + #include + + iis2iclx: iis2iclx@0 { + ... + + range = ; + odr = ; + }; + include: sensor-device.yaml properties: drdy-gpios: type: phandle-array - description: DRDY pin + description: | + DRDY pin This pin defaults to active high when produced by the sensor. The property value should ensure the flags properly describe @@ -15,41 +30,45 @@ properties: int-pin: type: int default: 1 - enum: - - 1 # drdy is generated from INT1 - - 2 # drdy is generated from INT2 - description: Select DRDY pin number (1 or 2). + enum: [1, 2] + description: | + Select DRDY pin number (1 or 2). This number represents which of the two interrupt pins (INT1 or INT2) the drdy line is attached to. This property is not mandatory and if not present it defaults to 1 which is the configuration at power-up. + - 1 # drdy is generated from INT1 + - 2 # drdy is generated from INT2 + range: type: int default: 3 - description: Range in g. Default is power-up configuration. - enum: - - 0 # 500mg (0.015 mg/LSB) - - 1 # 3g (0.122 mg/LSB) - - 2 # 1g (0.031 mg/LSB) - - 3 # 2g (0.061 mg/LSB) + description: | + Range in g. Default is power-up configuration. + + - 0 # IIS2ICLX_DT_FS_500mG (0.015 mg/LSB) + - 1 # IIS2ICLX_DT_FS_3G (0.122 mg/LSB) + - 2 # IIS2ICLX_DT_FS_1G (0.031 mg/LSB) + - 3 # IIS2ICLX_DT_FS_2G (0.061 mg/LSB) + + enum: [0, 1, 2, 3] odr: type: int default: 0 - description: + description: | Specify the default accelerometer output data rate expressed in samples per second (Hz). Default is power-up configuration. - enum: - - 0 # Power-Down - - 1 # 12.5Hz - - 2 # 26Hz - - 3 # 52Hz - - 4 # 104Hz - - 5 # 208Hz - - 6 # 416Hz - - 7 # 833Hz - - 8 # 1660Hz - - 9 # 3330Hz - - 10 # 6660Hz + + - 0 # IIS2ICLX_DT_ODR_OFF + - 1 # IIS2ICLX_DT_ODR_12Hz5 + - 2 # IIS2ICLX_DT_ODR_26H + - 3 # IIS2ICLX_DT_ODR_52Hz + - 4 # IIS2ICLX_DT_ODR_104Hz + - 5 # IIS2ICLX_DT_ODR_208Hz + - 6 # IIS2ICLX_DT_ODR_416Hz + - 7 # IIS2ICLX_DT_ODR_833Hz + + enum: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/include/zephyr/dt-bindings/sensor/iis2iclx.h b/include/zephyr/dt-bindings/sensor/iis2iclx.h new file mode 100644 index 000000000000000..544486e0984dc3e --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/iis2iclx.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2ICLX_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2ICLX_H_ + +/* Accel range */ +#define IIS2ICLX_DT_FS_500mG 0 +#define IIS2ICLX_DT_FS_3G 1 +#define IIS2ICLX_DT_FS_1G 2 +#define IIS2ICLX_DT_FS_2G 3 + +/* Accel Data rates */ +#define IIS2ICLX_DT_ODR_OFF 0x0 +#define IIS2ICLX_DT_ODR_12Hz5 0x1 +#define IIS2ICLX_DT_ODR_26H 0x2 +#define IIS2ICLX_DT_ODR_52Hz 0x3 +#define IIS2ICLX_DT_ODR_104Hz 0x4 +#define IIS2ICLX_DT_ODR_208Hz 0x5 +#define IIS2ICLX_DT_ODR_416Hz 0x6 +#define IIS2ICLX_DT_ODR_833Hz 0x7 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2ICLX_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index b858e9bbb2fc312..6ad5ac8703e7e66 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -16,6 +16,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -504,6 +505,8 @@ test_i2c_iis2iclx: iis2iclx@4c { reg = <0x4c>; drdy-gpios = <&test_gpio 0 0>; int-pin = <1>; + range = ; + odr = ; }; test_i2c_wsen_hids: wsen_hids@4d { From 237891973bcc95bd4bdfb7f2a5acc32250f29add Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 17 Nov 2023 17:35:27 +0100 Subject: [PATCH 0689/1049] doc: migration-guide-3.6.rst: recommend use of DT macros for ST sensors Recommend use of DT macros for ST sensors as described in #65410. Signed-off-by: Armando Visconti --- doc/releases/migration-guide-3.6.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index 5728d339984cbb0..c4b93e5f150718e 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -153,3 +153,7 @@ Other Subsystems Recommended Changes ******************* + +* New macros available for ST sensor DT properties setting. These macros have a self-explanatory + name that helps in recognizing what the property setting means (e.g. LSM6DSV16X_DT_ODR_AT_60Hz). + (:github:`65410`) From 8a75a4b9dbba7442c21a579f1a5f3cdf6e5d74bb Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 17 Nov 2023 14:09:50 +0100 Subject: [PATCH 0690/1049] net: shell: Fix array indexing with dynamic iface command Network interface numbering starts from 1, therefore when accessing help/index array, the interface index should not be used directly, but rather decremented by 1, to avoid out-of-bound access on those arrays. Signed-off-by: Robert Lubos --- subsys/net/lib/shell/iface_dynamic.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/net/lib/shell/iface_dynamic.h b/subsys/net/lib/shell/iface_dynamic.h index df62ad1eb36a536..d10e25e1c1b970c 100644 --- a/subsys/net/lib/shell/iface_dynamic.h +++ b/subsys/net/lib/shell/iface_dynamic.h @@ -32,9 +32,9 @@ static char *set_iface_index_buffer(size_t idx) return NULL; } - snprintk(iface_index_buffer[idx], MAX_IFACE_STR_LEN, "%d", (uint8_t)idx); + snprintk(iface_index_buffer[idx - 1], MAX_IFACE_STR_LEN, "%d", (uint8_t)idx); - return iface_index_buffer[idx]; + return iface_index_buffer[idx - 1]; } static char *set_iface_index_help(size_t idx) @@ -56,14 +56,14 @@ static char *set_iface_index_help(size_t idx) net_if_get_name(iface, name, CONFIG_NET_INTERFACE_NAME_LEN); name[CONFIG_NET_INTERFACE_NAME_LEN] = '\0'; - snprintk(iface_help_buffer[idx], MAX_IFACE_HELP_STR_LEN, + snprintk(iface_help_buffer[idx - 1], MAX_IFACE_HELP_STR_LEN, "%s [%s] (%p)", name, iface2str(iface, NULL), iface); #else - snprintk(iface_help_buffer[idx], MAX_IFACE_HELP_STR_LEN, + snprintk(iface_help_buffer[idx - 1], MAX_IFACE_HELP_STR_LEN, "[%s] (%p)", iface2str(iface, NULL), iface); #endif - return iface_help_buffer[idx]; + return iface_help_buffer[idx - 1]; } static void iface_index_get(size_t idx, struct shell_static_entry *entry) From 0aa6f3f3ffda64af4733c13b3d8c234deaac283c Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sat, 18 Nov 2023 11:41:58 +0100 Subject: [PATCH 0691/1049] modem: cmux: Fix coverity issues Possible NULL pointer dereferences where discovered by static code analysis, they are addressed in this commit. Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/modem_cmux.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index 19df0509d6c9b8c..9c95e124fc270d6 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -805,6 +805,10 @@ static void modem_cmux_connect_handler(struct k_work *item) struct k_work_delayable *dwork = k_work_delayable_from_work(item); struct modem_cmux *cmux = CONTAINER_OF(dwork, struct modem_cmux, connect_work); + if (cmux == NULL) { + return; + } + cmux->state = MODEM_CMUX_STATE_CONNECTING; struct modem_cmux_frame frame = { @@ -914,6 +918,10 @@ static void modem_cmux_dlci_open_handler(struct k_work *item) struct k_work_delayable *dwork = k_work_delayable_from_work(item); struct modem_cmux_dlci *dlci = CONTAINER_OF(dwork, struct modem_cmux_dlci, open_work); + if (dlci == NULL) { + return; + } + dlci->state = MODEM_CMUX_DLCI_STATE_OPENING; struct modem_cmux_frame frame = { @@ -935,6 +943,10 @@ static void modem_cmux_dlci_close_handler(struct k_work *item) struct modem_cmux_dlci *dlci = CONTAINER_OF(dwork, struct modem_cmux_dlci, close_work); struct modem_cmux *cmux = dlci->cmux; + if (cmux == NULL) { + return; + } + dlci->state = MODEM_CMUX_DLCI_STATE_CLOSING; struct modem_cmux_frame frame = { From 8c607bf401775424b3af6f4194ba38522bb2b3ed Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Fri, 13 Oct 2023 15:20:35 -0400 Subject: [PATCH 0692/1049] drivers: can: mcp251xfd: Increase max filters and change filter usage type The mcp251xfd supports upto 32 filters. Also store the filter usage in uint32_t instead of uint64_t. Signed-off-by: Andriy Gelman --- drivers/can/Kconfig.mcp251xfd | 2 +- drivers/can/can_mcp251xfd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/can/Kconfig.mcp251xfd b/drivers/can/Kconfig.mcp251xfd index 8e6cb5ad91c3e06..128becf8e95b6e8 100644 --- a/drivers/can/Kconfig.mcp251xfd +++ b/drivers/can/Kconfig.mcp251xfd @@ -54,7 +54,7 @@ config CAN_MCP251XFD_READ_CRC_RETRIES config CAN_MAX_FILTER int "Maximum number of concurrent active filters" default 5 - range 1 31 + range 1 32 help Maximum number of filters supported by the can_add_rx_callback() API call. diff --git a/drivers/can/can_mcp251xfd.h b/drivers/can/can_mcp251xfd.h index f0414103bedf3b1..b87c6ae53dd30ae 100644 --- a/drivers/can/can_mcp251xfd.h +++ b/drivers/can/can_mcp251xfd.h @@ -496,7 +496,7 @@ struct mcp251xfd_data { struct mcp251xfd_mailbox mailbox[CONFIG_CAN_MCP251XFD_MAX_TX_QUEUE]; /* Filter Data */ - uint64_t filter_usage; + uint32_t filter_usage; struct can_filter filter[CONFIG_CAN_MAX_FILTER]; can_rx_callback_t rx_cb[CONFIG_CAN_MAX_FILTER]; void *cb_arg[CONFIG_CAN_MAX_FILTER]; From 1282194ac549fea1990ea0a028af4ecc870093fc Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Fri, 13 Oct 2023 15:33:01 -0400 Subject: [PATCH 0693/1049] drivers: can: mcp251xfd: Skip payload in spi transfer when RTR flag is set There's no need to transfer the payload bytes when the RTR flag set. Signed-off-by: Andriy Gelman --- drivers/can/can_mcp251xfd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index 3f94ed52319bac2..7b788ec2b6c3ffb 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -191,8 +191,10 @@ static int mcp251xfd_fifo_write(const struct device *dev, int mailbox_idx, txobj = mcp251xfd_get_spi_buf_ptr(dev); mcp251xfd_canframe_to_txobj(msg, mailbox_idx, txobj); - tx_len = MCP251XFD_OBJ_HEADER_SIZE + - ROUND_UP(can_dlc_to_bytes(msg->dlc), MCP251XFD_RAM_ALIGNMENT); + tx_len = MCP251XFD_OBJ_HEADER_SIZE; + if ((msg->flags & CAN_FRAME_RTR) == 0) { + tx_len += ROUND_UP(can_dlc_to_bytes(msg->dlc), MCP251XFD_RAM_ALIGNMENT); + } ret = mcp251xfd_write(dev, address, tx_len); if (ret < 0) { From 85a1124d5d30a43634870004ca7c42db726c9157 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Thu, 9 Nov 2023 18:50:28 +0200 Subject: [PATCH 0694/1049] soc: xtensa: imx8m: Remove unused file Remove platform.h since is no longer used for SOF. Move memory.h to include folder and modify the linker to reflect this. Signed-off-by: Iuliana Prodan --- .../nxp_adsp/imx8m/include/{soc => }/memory.h | 0 .../nxp_adsp/imx8m/include/soc/platform.h | 21 ------------------- soc/xtensa/nxp_adsp/imx8m/linker.ld | 4 ++-- 3 files changed, 2 insertions(+), 23 deletions(-) rename soc/xtensa/nxp_adsp/imx8m/include/{soc => }/memory.h (100%) delete mode 100644 soc/xtensa/nxp_adsp/imx8m/include/soc/platform.h diff --git a/soc/xtensa/nxp_adsp/imx8m/include/soc/memory.h b/soc/xtensa/nxp_adsp/imx8m/include/memory.h similarity index 100% rename from soc/xtensa/nxp_adsp/imx8m/include/soc/memory.h rename to soc/xtensa/nxp_adsp/imx8m/include/memory.h diff --git a/soc/xtensa/nxp_adsp/imx8m/include/soc/platform.h b/soc/xtensa/nxp_adsp/imx8m/include/soc/platform.h deleted file mode 100644 index 2af652c0cc875d6..000000000000000 --- a/soc/xtensa/nxp_adsp/imx8m/include/soc/platform.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2021 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __PLATFORM_PLATFORM_H__ -#define __PLATFORM_PLATFORM_H__ - -#define PLATFORM_PRIMARY_CORE_ID 0 - -#define MAX_CORE_COUNT 1 - -#if PLATFORM_CORE_COUNT > MAX_CORE_COUNT -#error "Invalid core count - exceeding core limit" -/* IPC Interrupt */ -#define PLATFORM_IPC_INTERRUPT IRQ_NUM_MU -#define PLATFORM_IPC_INTERRUPT_NAME NULL -#endif - -#endif /* __PLATFORM_PLATFORM_H__ */ diff --git a/soc/xtensa/nxp_adsp/imx8m/linker.ld b/soc/xtensa/nxp_adsp/imx8m/linker.ld index aab0a0b6548fc1e..235e5a6f2644c78 100644 --- a/soc/xtensa/nxp_adsp/imx8m/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8m/linker.ld @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 NXP + * Copyright 2021, 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,7 @@ OUTPUT_ARCH(xtensa) #include #include -#include +#include #include #include From afc3606116b319dd27ef75f8f6ebc679a4a62d8f Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Thu, 9 Nov 2023 19:06:23 +0200 Subject: [PATCH 0695/1049] soc: xtensa: imx8m: Remove unused definitions Remove unused macro definitions. While here, use Zephyr's convention for include guard. Signed-off-by: Iuliana Prodan --- soc/xtensa/nxp_adsp/imx8m/include/memory.h | 63 +++------------------- 1 file changed, 7 insertions(+), 56 deletions(-) diff --git a/soc/xtensa/nxp_adsp/imx8m/include/memory.h b/soc/xtensa/nxp_adsp/imx8m/include/memory.h index e93617addb50cd6..e882f49a43512d4 100644 --- a/soc/xtensa/nxp_adsp/imx8m/include/memory.h +++ b/soc/xtensa/nxp_adsp/imx8m/include/memory.h @@ -1,11 +1,11 @@ /* - * Copyright (c) 2021 NXP + * Copyright 2021, 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __INC_MEMORY_H -#define __INC_MEMORY_H +#ifndef ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ +#define ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ #define PLATFORM_CORE_COUNT 1 @@ -163,56 +163,7 @@ #define SRAM_TRACE_OFFSET (SRAM_STREAM_OFFSET + SRAM_STREAM_SIZE) #define SOF_MAILBOX_SIZE (SRAM_INBOX_SIZE + SRAM_OUTBOX_SIZE \ - + SRAM_DEBUG_SIZE + SRAM_EXCEPT_SIZE \ - + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) - -/* Heap section sizes for module pool */ -#define HEAP_RT_COUNT8 0 -#define HEAP_RT_COUNT16 48 -#define HEAP_RT_COUNT32 48 -#define HEAP_RT_COUNT64 32 -#define HEAP_RT_COUNT128 32 -#define HEAP_RT_COUNT256 32 -#define HEAP_RT_COUNT512 4 -#define HEAP_RT_COUNT1024 4 -#define HEAP_RT_COUNT2048 4 -#define HEAP_RT_COUNT4096 4 - -/* Heap section sizes for system runtime heap */ -#define HEAP_SYS_RT_COUNT64 128 -#define HEAP_SYS_RT_COUNT512 16 -#define HEAP_SYS_RT_COUNT1024 8 - -/* Heap configuration */ -#define HEAP_SYSTEM_BASE SDRAM1_BASE + SOF_MAILBOX_SIZE -#define HEAP_SYSTEM_SIZE 0xe000 -#define HEAP_SYSTEM_0_BASE HEAP_SYSTEM_BASE - -#define HEAP_SYS_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) -#define HEAP_SYS_RUNTIME_SIZE \ - (HEAP_SYS_RT_COUNT64 * 64 + HEAP_SYS_RT_COUNT512 * 512 + \ - HEAP_SYS_RT_COUNT1024 * 1024) - -#define HEAP_RUNTIME_BASE (HEAP_SYS_RUNTIME_BASE + HEAP_SYS_RUNTIME_SIZE) -#define HEAP_RUNTIME_SIZE \ - (HEAP_RT_COUNT8 * 8 + HEAP_RT_COUNT16 * 16 + \ - HEAP_RT_COUNT32 * 32 + HEAP_RT_COUNT64 * 64 + \ - HEAP_RT_COUNT128 * 128 + HEAP_RT_COUNT256 * 256 + \ - HEAP_RT_COUNT512 * 512 + HEAP_RT_COUNT1024 * 1024 + \ - HEAP_RT_COUNT2048 * 2048 + HEAP_RT_COUNT4096 * 4096) - -#define HEAP_BUFFER_BASE (HEAP_RUNTIME_BASE + HEAP_RUNTIME_SIZE) -#define HEAP_BUFFER_SIZE \ - (SDRAM1_SIZE - SOF_MAILBOX_SIZE - HEAP_RUNTIME_SIZE - SOF_STACK_TOTAL_SIZE -\ - HEAP_SYS_RUNTIME_SIZE - HEAP_SYSTEM_SIZE) - -/* Stack configuration */ -#define SOF_STACK_SIZE 0x1000 -#define SOF_STACK_TOTAL_SIZE SOF_STACK_SIZE -#define SOF_STACK_BASE (SDRAM1_BASE + SDRAM1_SIZE) -#define SOF_STACK_END (SOF_STACK_BASE - SOF_STACK_TOTAL_SIZE) - -/* Host page size */ -#define HOST_PAGE_SIZE 4096 - -#endif /* __INC_MEMORY_H */ + + SRAM_DEBUG_SIZE + SRAM_EXCEPT_SIZE \ + + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) + +#endif /* ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ */ From edc0b7f3527834b0a8bdb2716fb088d7146f1c4a Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Thu, 9 Nov 2023 19:17:41 +0200 Subject: [PATCH 0696/1049] board: xtensa: imx8m: Remove unnecessary configs Remove unnecessary configs. Some were moved to Kconfig.series from soc/. Signed-off-by: Iuliana Prodan --- .../xtensa/nxp_adsp_imx8m/Kconfig.defconfig | 12 +----------- .../nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig | 19 +++++-------------- .../nxp_adsp/imx8m/Kconfig.defconfig.series | 11 +++++++---- soc/xtensa/nxp_adsp/imx8m/Kconfig.series | 2 ++ 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/boards/xtensa/nxp_adsp_imx8m/Kconfig.defconfig b/boards/xtensa/nxp_adsp_imx8m/Kconfig.defconfig index 628c8bfd0b42255..344449dd74436b6 100644 --- a/boards/xtensa/nxp_adsp_imx8m/Kconfig.defconfig +++ b/boards/xtensa/nxp_adsp_imx8m/Kconfig.defconfig @@ -1,4 +1,4 @@ -# Copyright (c) 2021 NXP +# Copyright 2021, 2023 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -7,14 +7,4 @@ if BOARD_NXP_ADSP_IMX8M config BOARD default "nxp_adsp_imx8m" -config DUMMY_DMA - bool - default y - depends on DMA - -config IMX_SDMA - bool - default y - depends on DMA - endif # BOARD_NXP_ADSP_IMX8M diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig index f3b4ca76cbe9a51..72ccd09f55a47cb 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig @@ -1,27 +1,18 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_MAIN_STACK_SIZE=3072 - CONFIG_SOC_SERIES_NXP_IMX8M=y CONFIG_SOC_MIMX8M_ADSP=y CONFIG_BOARD_NXP_ADSP_IMX8M=y -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_XTENSA_RESET_VECTOR=y - -CONFIG_XTENSA_USE_CORE_CRT1=y - -CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY=y +# size of stack for initialization and main thread +CONFIG_MAIN_STACK_SIZE=3072 -CONFIG_MULTI_LEVEL_INTERRUPTS=n -CONFIG_2ND_LEVEL_INTERRUPTS=n +# enable logger +CONFIG_LOG=y +# no need for a "raw" binary zephyr/zephyr.bin in the build directory CONFIG_BUILD_OUTPUT_BIN=n -CONFIG_DCACHE_LINE_SIZE=128 - # enable uart driver CONFIG_SERIAL=y diff --git a/soc/xtensa/nxp_adsp/imx8m/Kconfig.defconfig.series b/soc/xtensa/nxp_adsp/imx8m/Kconfig.defconfig.series index d0fc446b4b0f043..2d00a5e93d96f14 100644 --- a/soc/xtensa/nxp_adsp/imx8m/Kconfig.defconfig.series +++ b/soc/xtensa/nxp_adsp/imx8m/Kconfig.defconfig.series @@ -11,7 +11,7 @@ config SOC_TOOLCHAIN_NAME string default "nxp_imx8m_adsp" -# if SOC_MIMX8M_ADSP +if SOC_MIMX8M_ADSP config SOC string @@ -23,12 +23,15 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config SYS_CLOCK_TICKS_PER_SEC default 50000 +config DCACHE_LINE_SIZE + default 128 + config DYNAMIC_INTERRUPTS default y -config LOG - default y +config GEN_IRQ_VECTOR_TABLE + default n -# endif # SOC_MIMX8M_ADSP +endif # SOC_MIMX8M_ADSP endif # SOC_SERIES_NXP_IMX8M diff --git a/soc/xtensa/nxp_adsp/imx8m/Kconfig.series b/soc/xtensa/nxp_adsp/imx8m/Kconfig.series index eda7d03ae5e2a85..3847f52d2dad1b8 100644 --- a/soc/xtensa/nxp_adsp/imx8m/Kconfig.series +++ b/soc/xtensa/nxp_adsp/imx8m/Kconfig.series @@ -9,5 +9,7 @@ config SOC_SERIES_NXP_IMX8M select XTENSA_RESET_VECTOR select XTENSA_USE_CORE_CRT1 select ATOMIC_OPERATIONS_BUILTIN + select GEN_ISR_TABLES + select XTENSA_SMALL_VECTOR_TABLE_ENTRY help Enable support for NXP i.MX8M Audio DSP From 7c55eb5dfa10f01e4464abb4264770e65a291093 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Sat, 11 Nov 2023 01:00:00 +0200 Subject: [PATCH 0697/1049] board: xtensa: imx8m: Remove unnecessary keyword Remove /omit-if-no-ref/ since it doesn't apply here. This is used for pre-generated nodes. Signed-off-by: Iuliana Prodan --- boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts index bc5b663f57d4546..6a0d7508deb2a72 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 NXP + * Copyright 2021, 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,7 +22,7 @@ }; &pinctrl { - /omit-if-no-ref/ uart4_default: uart4_default { + uart4_default: uart4_default { group0 { pinmux = <&iomuxc_uart4_rxd_uart_rx_uart4_rx>, <&iomuxc_uart4_txd_uart_tx_uart4_tx>; From 24f2d2e136dbd48c5bd4e39b26b5941e3bd8c694 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Sat, 11 Nov 2023 01:09:46 +0200 Subject: [PATCH 0698/1049] nxp_adsp: linker: Rename text area variables Use Zephyr's convention for text region start and end. Signed-off-by: Iuliana Prodan --- soc/xtensa/nxp_adsp/imx8/linker.ld | 4 ++-- soc/xtensa/nxp_adsp/imx8m/linker.ld | 4 ++-- soc/xtensa/nxp_adsp/rt5xx/linker.ld | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/soc/xtensa/nxp_adsp/imx8/linker.ld b/soc/xtensa/nxp_adsp/imx8/linker.ld index 7e5829c8d137f89..52d3a46b2381a95 100644 --- a/soc/xtensa/nxp_adsp/imx8/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8/linker.ld @@ -346,7 +346,7 @@ SECTIONS .text : ALIGN(4) { _stext = .; - _text_start = ABSOLUTE(.); + __text_region_start = ABSOLUTE(.); KEEP (*(.ResetVector.text)) *(.ResetVector.literal) *(.entry.text) @@ -356,7 +356,7 @@ SECTIONS *(.fini.literal) KEEP(*(.fini)) *(.gnu.version) - _text_end = ABSOLUTE(.); + __text_region_end = ABSOLUTE(.); _etext = .; } >sdram0 :sdram0_phdr diff --git a/soc/xtensa/nxp_adsp/imx8m/linker.ld b/soc/xtensa/nxp_adsp/imx8m/linker.ld index 235e5a6f2644c78..7df19644ce9594a 100644 --- a/soc/xtensa/nxp_adsp/imx8m/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8m/linker.ld @@ -352,7 +352,7 @@ SECTIONS .text : ALIGN(4) { _stext = .; - _text_start = ABSOLUTE(.); + __text_region_start = ABSOLUTE(.); KEEP (*(.ResetVector.text)) *(.ResetVector.literal) *(.entry.text) @@ -362,7 +362,7 @@ SECTIONS *(.fini.literal) KEEP(*(.fini)) *(.gnu.version) - _text_end = ABSOLUTE(.); + __text_region_end = ABSOLUTE(.); _etext = .; } >sdram0 :sdram0_phdr diff --git a/soc/xtensa/nxp_adsp/rt5xx/linker.ld b/soc/xtensa/nxp_adsp/rt5xx/linker.ld index 582c4a7fbf8bb82..adc8b87fb621361 100644 --- a/soc/xtensa/nxp_adsp/rt5xx/linker.ld +++ b/soc/xtensa/nxp_adsp/rt5xx/linker.ld @@ -307,7 +307,7 @@ SECTIONS .text : ALIGN(4) { _stext = .; - _text_start = ABSOLUTE(.); + __text_region_start = ABSOLUTE(.); KEEP (*(.ResetVector.text)) *(.ResetVector.literal) *(.entry.text) @@ -317,7 +317,7 @@ SECTIONS *(.fini.literal) KEEP(*(.fini)) *(.gnu.version) - _text_end = ABSOLUTE(.); + __text_region_end = ABSOLUTE(.); _etext = .; } >iram_text_start :iram_text_start_phdr From 23c49e554a75c27e6b3fd01cb42aff5bcda27091 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Sat, 11 Nov 2023 01:18:02 +0200 Subject: [PATCH 0699/1049] nxp_adsp: linker: Update linker scripts for C++ build When linking, in crtbegin.o for C++ exception support, we pull in the .tm_clone_table section. Update the linker scripts to handle this, otherwise we get a "warning: orphan section `.tm_clone_table'". Signed-off-by: Iuliana Prodan --- soc/xtensa/nxp_adsp/imx8m/linker.ld | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/soc/xtensa/nxp_adsp/imx8m/linker.ld b/soc/xtensa/nxp_adsp/imx8m/linker.ld index 7df19644ce9594a..feee4b288c7ea9d 100644 --- a/soc/xtensa/nxp_adsp/imx8m/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8m/linker.ld @@ -415,6 +415,11 @@ SECTIONS #include + /* Used for C++ build */ + .tm_clone_table : { + *(.tm_clone_table) + } >sdram0 :sdram0_phdr + .bss (NOLOAD) : ALIGN(8) { . = ALIGN (8); From 9cac089f8c51b3c47b1b42bd0b99766f69b296db Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Sat, 11 Nov 2023 01:31:10 +0200 Subject: [PATCH 0700/1049] nxp_adsp: linker: Fix _heap_sentry reference Add _heap_sentry value to fix build errors for newlib, like: "undefined reference to `_heap_sentry'" Signed-off-by: Iuliana Prodan --- soc/xtensa/nxp_adsp/imx8m/linker.ld | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soc/xtensa/nxp_adsp/imx8m/linker.ld b/soc/xtensa/nxp_adsp/imx8m/linker.ld index feee4b288c7ea9d..b9d9303e96ba874 100644 --- a/soc/xtensa/nxp_adsp/imx8m/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8m/linker.ld @@ -453,6 +453,8 @@ SECTIONS _end = ALIGN (8); PROVIDE(end = ALIGN (8)); + /* Mostly unused, though newlib likes them */ + _heap_sentry = .; __stack = SDRAM1_BASE + SDRAM1_SIZE; .comment 0 : { *(.comment) } .debug 0 : { *(.debug) } From 9af682587489263d1b55c7ce1c82fa52e6d45313 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Tue, 14 Nov 2023 00:56:35 +0200 Subject: [PATCH 0701/1049] nxp_adsp: linker: Add snippets to linker script The xtensa/nxp_adsp_imx8m linker script is missing the necessary include statements for linker snippets. So we need to add them. This fixes compile warnings like: orphan section `.unstable_id' from `modules/chre/lib..__modules__lib__chre__platform__zephyr.a (version.cc.obj)' being placed in section `.unstable_id'. Signed-off-by: Iuliana Prodan --- soc/xtensa/nxp_adsp/imx8m/linker.ld | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soc/xtensa/nxp_adsp/imx8m/linker.ld b/soc/xtensa/nxp_adsp/imx8m/linker.ld index b9d9303e96ba874..9687b604d6c5435 100644 --- a/soc/xtensa/nxp_adsp/imx8m/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8m/linker.ld @@ -527,4 +527,6 @@ SECTIONS KEEP (*(.fw_metadata)) . = ALIGN(_EXT_MAN_ALIGN_); } >fw_metadata_seg :metadata_entries_phdr + + #include } From aba55686f5f376053eb279adffc5f1294c2be5a6 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Sat, 11 Nov 2023 01:42:07 +0200 Subject: [PATCH 0702/1049] dts: nxp_adsp_imx8m: Add interrupt to fix compilation Add dummy interrupt id until we can support UART interuppt on i.MX8MP in order to fix compilation warnings. Signed-off-by: Iuliana Prodan --- dts/xtensa/nxp/nxp_imx8m.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dts/xtensa/nxp/nxp_imx8m.dtsi b/dts/xtensa/nxp/nxp_imx8m.dtsi index f354c8303ea65d2..21a094c04616827 100644 --- a/dts/xtensa/nxp/nxp_imx8m.dtsi +++ b/dts/xtensa/nxp/nxp_imx8m.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 NXP + * Copyright 2021, 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -64,6 +64,10 @@ uart4: uart@30a60000 { compatible = "nxp,imx-iuart"; reg = <0x30a60000 0x10000>; + /* TODO: This INTID is just a dummy + * until we can support UART interrupts + */ + interrupts = <29 0>; clocks = <&ccm IMX_CCM_UART4_CLK 0x6c 24>; status = "disabled"; }; From 8446c5877779b69c42bd14262f7b5a6604b94e61 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Sat, 11 Nov 2023 01:45:28 +0200 Subject: [PATCH 0703/1049] board: xtensa: imx8m: Enable more tests Update yaml to run more tests. Signed-off-by: Iuliana Prodan --- boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml index 675db668f136e13..b5b62df24f8e6c1 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml @@ -3,11 +3,13 @@ name: NXP i.MX8M Plus EVK Audio DSP type: mcu arch: xtensa toolchain: + - xcc + - xt-clang - zephyr -testing: - only_tags: - - kernel - - sof - - ipm supported: - uart +testing: + ignore_tags: + - net + - bluetooth + - mcumgr From 5879803d155f03f75b954774438390d3221c02c7 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Sat, 11 Nov 2023 01:47:16 +0200 Subject: [PATCH 0704/1049] board: xtensa: nxp: Add vendor Add vendor for NXP boards. Signed-off-by: Iuliana Prodan --- boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.yaml | 1 + boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml | 1 + boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.yaml | 1 + boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.yaml | 1 + 4 files changed, 4 insertions(+) diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.yaml b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.yaml index 60aa04828228558..b2ab9b227a9dc94 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.yaml +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.yaml @@ -8,3 +8,4 @@ testing: only_tags: - kernel - sof +vendor: nxp diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml index b5b62df24f8e6c1..ef0bbdfe0ff04ff 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml @@ -13,3 +13,4 @@ testing: - net - bluetooth - mcumgr +vendor: nxp diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.yaml b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.yaml index 3277fffc7d662fd..a343b8843c8dccd 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.yaml +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.yaml @@ -8,3 +8,4 @@ testing: only_tags: - kernel - sof +vendor: nxp diff --git a/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.yaml b/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.yaml index ca3e0c21252430f..09f61405d94bab1 100644 --- a/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.yaml +++ b/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.yaml @@ -7,3 +7,4 @@ toolchain: testing: only_tags: - kernel +vendor: nxp From 17b39baa6168758c1fe32e3902676f550274a4e3 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Fri, 15 Sep 2023 17:10:57 +0200 Subject: [PATCH 0705/1049] bluetooth: tester: Add support for BASS Support for BAP/BASS and BASS test cases. Signed-off-by: Magdalena Kasenberg --- tests/bluetooth/tester/overlay-le-audio.conf | 9 + tests/bluetooth/tester/src/btp/btp_ascs.h | 2 +- tests/bluetooth/tester/src/btp/btp_bap.h | 119 ++- tests/bluetooth/tester/src/btp/btp_gap.h | 3 +- tests/bluetooth/tester/src/btp/btp_pacs.h | 2 +- tests/bluetooth/tester/src/btp_bap.c | 761 +++++++++++++++++-- tests/bluetooth/tester/src/btp_core.c | 21 +- tests/bluetooth/tester/src/btp_gap.c | 20 +- 8 files changed, 858 insertions(+), 79 deletions(-) diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index 530558c1308c09c..4a7fc4e606cb093 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -31,6 +31,7 @@ CONFIG_BT_BAP_BROADCAST_SOURCE=y CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2 CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=2 CONFIG_BT_ISO_TX_BUF_COUNT=4 +CONFIG_BT_BAP_BROADCAST_ASSISTANT=y # Broadcast Sink CONFIG_BT_BAP_SCAN_DELEGATOR=y @@ -38,6 +39,14 @@ CONFIG_BT_BAP_BROADCAST_SINK=y CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=2 CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=2 +# BASS +CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER=y +CONFIG_BT_BAP_SCAN_DELEGATOR_MAX_METADATA_LEN=255 +CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y +# BASS notifications need higher MTU +CONFIG_BT_L2CAP_TX_MTU=255 +CONFIG_BT_BUF_ACL_RX_SIZE=255 + # ASCS CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=2 diff --git a/tests/bluetooth/tester/src/btp/btp_ascs.h b/tests/bluetooth/tester/src/btp/btp_ascs.h index f14cb5de3d4ff65..739e8c7d824fd68 100644 --- a/tests/bluetooth/tester/src/btp/btp_ascs.h +++ b/tests/bluetooth/tester/src/btp/btp_ascs.h @@ -1,4 +1,4 @@ -/* btp_bap.h - Bluetooth tester headers */ +/* btp_ascs.h - Bluetooth tester headers */ /* * Copyright (c) 2023 Codecoup diff --git a/tests/bluetooth/tester/src/btp/btp_bap.h b/tests/bluetooth/tester/src/btp/btp_bap.h index ede3448f2cf2d04..d094d5363905098 100644 --- a/tests/bluetooth/tester/src/btp/btp_bap.h +++ b/tests/bluetooth/tester/src/btp/btp_bap.h @@ -6,6 +6,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + /* BAP commands */ #define BTP_BAP_READ_SUPPORTED_COMMANDS 0x01 struct btp_bap_read_supported_commands_rp { @@ -50,32 +52,32 @@ struct btp_bap_broadcast_source_setup_cmd { } __packed; struct btp_bap_broadcast_source_setup_rp { uint32_t gap_settings; - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; } __packed; #define BTP_BAP_BROADCAST_SOURCE_RELEASE 0x05 struct btp_bap_broadcast_source_release_cmd { - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; } __packed; #define BTP_BAP_BROADCAST_ADV_START 0x06 struct btp_bap_broadcast_adv_start_cmd { - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; } __packed; #define BTP_BAP_BROADCAST_ADV_STOP 0x07 struct btp_bap_broadcast_adv_stop_cmd { - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; } __packed; #define BTP_BAP_BROADCAST_SOURCE_START 0x08 struct btp_bap_broadcast_source_start_cmd { - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; } __packed; #define BTP_BAP_BROADCAST_SOURCE_STOP 0x09 struct btp_bap_broadcast_source_stop_cmd { - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; } __packed; #define BTP_BAP_BROADCAST_SINK_SETUP 0x0a @@ -97,16 +99,81 @@ struct btp_bap_broadcast_scan_stop_cmd { #define BTP_BAP_BROADCAST_SINK_SYNC 0x0e struct btp_bap_broadcast_sink_sync_cmd { bt_addr_le_t address; - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; uint8_t advertiser_sid; uint16_t skip; uint16_t sync_timeout; + uint8_t past_avail; + uint8_t src_id; } __packed; #define BTP_BAP_BROADCAST_SINK_STOP 0x0f struct btp_bap_broadcast_sink_stop_cmd { bt_addr_le_t address; - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; +} __packed; + +#define BTP_BAP_BROADCAST_SINK_BIS_SYNC 0x10 +struct btp_bap_broadcast_sink_bis_sync_cmd { + bt_addr_le_t address; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; + uint32_t requested_bis_sync; +} __packed; + +#define BTP_BAP_DISCOVER_SCAN_DELEGATORS 0x11 +struct btp_bap_discover_scan_delegators_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_BAP_BROADCAST_ASSISTANT_SCAN_START 0x12 +struct btp_bap_broadcast_assistant_scan_start_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_BAP_BROADCAST_ASSISTANT_SCAN_STOP 0x13 +struct btp_bap_broadcast_assistant_scan_stop_cmd { + bt_addr_le_t address; +} __packed; + +#define BTP_BAP_ADD_BROADCAST_SRC 0x14 +struct btp_bap_add_broadcast_src_cmd { + bt_addr_le_t address; + bt_addr_le_t broadcaster_address; + uint8_t advertiser_sid; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; + uint8_t padv_sync; + uint16_t padv_interval; + uint8_t num_subgroups; + uint8_t subgroups[0]; +} __packed; + +#define BTP_BAP_REMOVE_BROADCAST_SRC 0x15 +struct btp_bap_remove_broadcast_src_cmd { + bt_addr_le_t address; + uint8_t src_id; +} __packed; + +#define BTP_BAP_MODIFY_BROADCAST_SRC 0x16 +struct btp_bap_modify_broadcast_src_cmd { + bt_addr_le_t address; + uint8_t src_id; + uint8_t padv_sync; + uint16_t padv_interval; + uint8_t num_subgroups; + uint8_t subgroups[0]; +} __packed; + +#define BTP_BAP_SET_BROADCAST_CODE 0x17 +struct btp_bap_set_broadcast_code_cmd { + bt_addr_le_t address; + uint8_t src_id; + uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; +} __packed; + +#define BTP_BAP_SEND_PAST 0x18 +struct btp_bap_send_past_cmd { + bt_addr_le_t address; + uint8_t src_id; } __packed; /* BAP events */ @@ -145,7 +212,7 @@ struct btp_bap_stream_received_ev { #define BTP_BAP_EV_BAA_FOUND 0x84 struct btp_bap_baa_found_ev { bt_addr_le_t address; - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; uint8_t advertiser_sid; uint16_t padv_interval; } __packed; @@ -153,7 +220,7 @@ struct btp_bap_baa_found_ev { #define BTP_BAP_EV_BIS_FOUND 0x85 struct btp_bap_bis_found_ev { bt_addr_le_t address; - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; uint8_t presentation_delay[3]; uint8_t subgroup_id; uint8_t bis_id; @@ -167,15 +234,43 @@ struct btp_bap_bis_found_ev { #define BTP_BAP_EV_BIS_SYNCED 0x86 struct btp_bap_bis_syned_ev { bt_addr_le_t address; - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; uint8_t bis_id; } __packed; #define BTP_BAP_EV_BIS_STREAM_RECEIVED 0x87 struct btp_bap_bis_stream_received_ev { bt_addr_le_t address; - uint8_t broadcast_id[3]; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; uint8_t bis_id; uint8_t data_len; uint8_t data[]; } __packed; + +#define BTP_BAP_EV_SCAN_DELEGATOR_FOUND 0x88 +struct btp_bap_scan_delegator_found_ev { + bt_addr_le_t address; +} __packed; + +#define BTP_BAP_EV_BROADCAST_RECEIVE_STATE 0x89 +struct btp_bap_broadcast_receive_state_ev { + bt_addr_le_t address; + uint8_t src_id; + bt_addr_le_t broadcaster_address; + uint8_t advertiser_sid; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; + uint8_t pa_sync_state; + uint8_t big_encryption; + uint8_t num_subgroups; + uint8_t subgroups[0]; +} __packed; + +#define BTP_BAP_EV_PA_SYNC_REQ 0x8a +struct btp_bap_pa_sync_req_ev { + bt_addr_le_t address; + uint8_t src_id; + uint8_t advertiser_sid; + uint8_t broadcast_id[BT_AUDIO_BROADCAST_ID_SIZE]; + uint8_t past_avail; + uint16_t pa_interval; +} __packed; diff --git a/tests/bluetooth/tester/src/btp/btp_gap.h b/tests/bluetooth/tester/src/btp/btp_gap.h index 960d810e0255c57..a727ffce4e46ef3 100644 --- a/tests/bluetooth/tester/src/btp/btp_gap.h +++ b/tests/bluetooth/tester/src/btp/btp_gap.h @@ -456,5 +456,6 @@ int tester_gap_padv_configure(const struct bt_le_per_adv_param *param); int tester_gap_padv_set_data(struct bt_data *per_ad, uint8_t ad_len); int tester_gap_padv_start(void); int tester_gap_padv_stop(void); -int tester_padv_create_sync(struct bt_le_per_adv_sync_param *create_params); +int tester_gap_padv_create_sync(struct bt_le_per_adv_sync_param *create_params); +int tester_gap_padv_stop_sync(void); #endif /* defined(CONFIG_BT_EXT_ADV) */ diff --git a/tests/bluetooth/tester/src/btp/btp_pacs.h b/tests/bluetooth/tester/src/btp/btp_pacs.h index 91f9596e8690808..7403feee7627524 100644 --- a/tests/bluetooth/tester/src/btp/btp_pacs.h +++ b/tests/bluetooth/tester/src/btp/btp_pacs.h @@ -1,4 +1,4 @@ -/* btp_bap.h - Bluetooth tester headers */ +/* btp_pacs.h - Bluetooth tester headers */ /* * Copyright (c) 2023 Codecoup diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index a35950b9cc5dd6d..d6149d2c3ac570a 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "bap_endpoint.h" #include @@ -118,7 +119,15 @@ static struct bt_bap_stream *sink_streams[MAX_STREAMS_COUNT]; /* A mask for the maximum BIS we can sync to. +1 since the BIS indexes start from 1. */ static const uint32_t bis_index_mask = BIT_MASK(MAX_STREAMS_COUNT + 1); static uint32_t bis_index_bitfield; +static uint32_t requested_bis_sync; #define INVALID_BROADCAST_ID (BT_AUDIO_BROADCAST_ID_MAX + 1) +#define SYNC_RETRY_COUNT 6 /* similar to retries for connections */ +#define PA_SYNC_SKIP 5 +/* Sample assumes that we only have a single Scan Delegator receive state */ +static const struct bt_bap_scan_delegator_recv_state *sink_recv_state; +static const struct bt_bap_scan_delegator_recv_state *broadcast_recv_state; +static uint8_t sink_broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; +static struct bt_bap_scan_delegator_subgroup delegator_subgroups[BROADCAST_SNK_SUBGROUP_CNT]; static bool print_cb(struct bt_data *data, void *user_data) { @@ -237,10 +246,8 @@ static void btp_send_ascs_operation_completed_ev(struct bt_conn *conn, uint8_t a uint8_t opcode, uint8_t status) { struct btp_ascs_operation_completed_ev ev; - struct bt_conn_info info; - (void)bt_conn_get_info(conn, &info); - bt_addr_le_copy(&ev.address, info.le.dst); + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); ev.ase_id = ase_id; ev.opcode = opcode; ev.status = status; @@ -252,10 +259,8 @@ static void btp_send_ascs_operation_completed_ev(struct bt_conn *conn, uint8_t a static void btp_send_ascs_ase_state_changed_ev(struct bt_conn *conn, uint8_t ase_id, uint8_t state) { struct btp_ascs_ase_state_changed_ev ev; - struct bt_conn_info info; - (void)bt_conn_get_info(conn, &info); - bt_addr_le_copy(&ev.address, info.le.dst); + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); ev.ase_id = ase_id; ev.state = state; @@ -487,18 +492,15 @@ static void btp_send_stream_received_ev(struct bt_conn *conn, struct bt_bap_ep * uint8_t data_len, uint8_t *data) { struct btp_bap_stream_received_ev *ev; - struct bt_conn_info info; LOG_DBG("Stream received, ep %d, dir %d, len %d", ep->status.id, ep->dir, data_len); - (void)bt_conn_get_info(conn, &info); - net_buf_simple_init(rx_ev_buf, 0); ev = net_buf_simple_add(rx_ev_buf, sizeof(*ev)); - bt_addr_le_copy(&ev->address, info.le.dst); + bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn)); ev->ase_id = ep->status.id; ev->data_len = data_len; @@ -680,6 +682,7 @@ static void stream_started(struct bt_bap_stream *stream) } if (a_stream->broadcast) { + a_stream->bis_synced = true; btp_send_bis_syced_ev(&broadcaster_addr, broadcaster_broadcast_id, a_stream->bis_id); } else { @@ -701,6 +704,8 @@ static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason) if (!a_stream->broadcast) { btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, BT_ASCS_STOP_OP, BTP_STATUS_SUCCESS); + } else { + a_stream->bis_synced = false; } } @@ -747,10 +752,8 @@ static struct bt_bap_stream_ops stream_ops = { static void btp_send_discovery_completed_ev(struct bt_conn *conn, uint8_t status) { struct btp_bap_discovery_completed_ev ev; - struct bt_conn_info info; - (void) bt_conn_get_info(conn, &info); - bt_addr_le_copy(&ev.address, info.le.dst); + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); ev.status = status; tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_DISCOVERY_COMPLETED, &ev, sizeof(ev)); @@ -807,11 +810,9 @@ static void btp_send_pac_codec_found_ev(struct bt_conn *conn, enum bt_audio_dir dir) { struct btp_bap_codec_cap_found_ev ev; - struct bt_conn_info info; const uint8_t *data; - (void)bt_conn_get_info(conn, &info); - bt_addr_le_copy(&ev.address, info.le.dst); + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); ev.dir = dir; ev.coding_format = codec_cap->id; @@ -838,10 +839,8 @@ static void btp_send_pac_codec_found_ev(struct bt_conn *conn, static void btp_send_ase_found_ev(struct bt_conn *conn, struct bt_bap_ep *ep) { struct btp_ascs_ase_found_ev ev; - struct bt_conn_info info; - (void)bt_conn_get_info(conn, &info); - bt_addr_le_copy(&ev.address, info.le.dst); + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); ev.ase_id = ep->status.id; ev.dir = ep->dir; @@ -1418,6 +1417,8 @@ static uint8_t broadcast_source_stop(const void *cmd, uint16_t cmd_len, static int broadcast_sink_reset(void) { bis_index_bitfield = 0U; + sink_recv_state = NULL; + (void)memset(sink_broadcast_code, 0, sizeof(sink_broadcast_code)); (void)memset(&broadcaster_addr, 0, sizeof(broadcaster_addr)); (void)memset(broadcaster, 0, sizeof(*broadcaster)); broadcaster_broadcast_id = INVALID_BROADCAST_ID; @@ -1433,18 +1434,20 @@ static void btp_send_baa_found_ev(const bt_addr_le_t *address, uint32_t broadcas bt_addr_le_copy(&ev.address, address); sys_put_le24(broadcast_id, ev.broadcast_id); ev.advertiser_sid = sid; - ev.padv_interval = interval; + ev.padv_interval = sys_cpu_to_le16(interval); tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BAA_FOUND, &ev, sizeof(ev)); } -static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) +static bool baa_check(struct bt_data *data, void *user_data) { const struct bt_le_scan_recv_info *info = user_data; char le_addr[BT_ADDR_LE_STR_LEN]; struct bt_uuid_16 adv_uuid; uint32_t broadcast_id; + /* Parse the scanned Broadcast Audio Announcement */ + if (data->type != BT_DATA_SVC_DATA16) { return true; } @@ -1465,8 +1468,8 @@ static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); - LOG_DBG("Found broadcaster with ID 0x%06X and addr %s and sid 0x%02X", broadcast_id, - le_addr, info->sid); + LOG_DBG("Found BAA with ID 0x%06X, addr %s, sid 0x%02X, interval 0x%04X", + broadcast_id, le_addr, info->sid, info->interval); btp_send_baa_found_ev(info->addr, broadcast_id, info->sid, info->interval); @@ -1478,7 +1481,7 @@ static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct { /* If 0 there is no periodic advertising. */ if (info->interval != 0U) { - bt_data_parse(ad, scan_check_and_sync_broadcast, (void *)info); + bt_data_parse(ad, baa_check, (void *)info); } } @@ -1526,8 +1529,7 @@ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap return; } - LOG_DBG("Received BASE with %u subgroups from broadcast sink %p", base->subgroup_count, - sink); + LOG_DBG("Received BASE: broadcast sink %p subgroups %u", sink, base->subgroup_count); for (size_t i = 0U; i < base->subgroup_count; i++) { for (size_t j = 0U; j < base->subgroups[i].bis_count; j++) { @@ -1546,15 +1548,29 @@ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap } bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; + LOG_DBG("bis_index_bitfield 0x%08x", bis_index_bitfield); } static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted) { int err; + uint32_t index_bitfield; - LOG_DBG(""); + LOG_DBG("PA found, encrypted %d, requested_bis_sync %d", encrypted, requested_bis_sync); + + if (encrypted) { + /* Wait for Set Broadcast Code and start sync at broadcast_code_cb */ + return; + } - err = bt_bap_broadcast_sink_sync(broadcast_sink, bis_index_bitfield, sink_streams, NULL); + if (!requested_bis_sync) { + /* No sync with any BIS was requested yet */ + return; + } + + index_bitfield = bis_index_bitfield & requested_bis_sync; + err = bt_bap_broadcast_sink_sync(broadcast_sink, index_bitfield, sink_streams, + sink_broadcast_code); if (err != 0) { LOG_DBG("Unable to sync to broadcast source: %d", err); } @@ -1565,21 +1581,36 @@ static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = { .syncable = syncable_cb, }; +static void pa_timer_handler(struct k_work *work) +{ + if (broadcast_recv_state != NULL) { + enum bt_bap_pa_state pa_state; + + if (broadcast_recv_state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ) { + pa_state = BT_BAP_PA_STATE_NO_PAST; + } else { + pa_state = BT_BAP_PA_STATE_FAILED; + } + + bt_bap_scan_delegator_set_pa_state(broadcast_recv_state->src_id, + pa_state); + } + + LOG_DBG("PA timeout"); +} + +static K_WORK_DELAYABLE_DEFINE(pa_timer, pa_timer_handler); + static void bap_pa_sync_synced_cb(struct bt_le_per_adv_sync *sync, struct bt_le_per_adv_sync_synced_info *info) { int err; - struct bt_le_per_adv_sync *pa_sync; - LOG_DBG(""); + LOG_DBG("Sync info: service_data 0x%04X", info->service_data); - pa_sync = tester_gap_padv_get(); + k_work_cancel_delayable(&pa_timer); - if (sync != pa_sync) { - return; - } - - err = bt_bap_broadcast_sink_create(pa_sync, broadcaster_broadcast_id, &broadcast_sink); + err = bt_bap_broadcast_sink_create(sync, broadcaster_broadcast_id, &broadcast_sink); if (err != 0) { LOG_DBG("Failed to create broadcast sink: ID 0x%06X, err %d", broadcaster_broadcast_id, err); @@ -1590,6 +1621,203 @@ static struct bt_le_per_adv_sync_cb bap_pa_sync_cb = { .synced = bap_pa_sync_synced_cb, }; +static void btp_send_pas_sync_req_ev(struct bt_conn *conn, uint8_t src_id, + uint8_t advertiser_sid, uint32_t broadcast_id, + bool past_avail, uint16_t pa_interval) +{ + struct btp_bap_pa_sync_req_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + ev.src_id = src_id; + ev.advertiser_sid = advertiser_sid; + sys_put_le24(broadcast_id, ev.broadcast_id); + ev.past_avail = past_avail; + ev.pa_interval = sys_cpu_to_le16(pa_interval); + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_PA_SYNC_REQ, &ev, sizeof(ev)); +} + +static void btp_send_scan_delegator_found_ev(struct bt_conn *conn) +{ + struct btp_bap_scan_delegator_found_ev ev; + + bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn)); + + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_SCAN_DELEGATOR_FOUND, &ev, sizeof(ev)); +} + +static void btp_send_broadcast_receive_state_ev(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *state) +{ + struct btp_bap_broadcast_receive_state_ev *ev; + size_t len; + uint8_t *ptr; + + tester_rsp_buffer_lock(); + tester_rsp_buffer_allocate(sizeof(*ev) + BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS * + sizeof(struct bt_bap_scan_delegator_subgroup), (uint8_t **)&ev); + + if (conn) { + bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn)); + } else { + (void)memset(&ev->address, 0, sizeof(ev->address)); + } + + ev->src_id = state->src_id; + bt_addr_le_copy(&ev->broadcaster_address, &state->addr); + ev->advertiser_sid = state->adv_sid; + sys_put_le24(state->broadcast_id, ev->broadcast_id); + ev->pa_sync_state = state->pa_sync_state; + ev->big_encryption = state->encrypt_state; + ev->num_subgroups = state->num_subgroups; + + ptr = ev->subgroups; + for (uint8_t i = 0; i < ev->num_subgroups; i++) { + const struct bt_bap_scan_delegator_subgroup *subgroup = &state->subgroups[i]; + + sys_put_le32(subgroup->bis_sync >> 1, ptr); + ptr += sizeof(subgroup->bis_sync); + *ptr = subgroup->metadata_len; + ptr += sizeof(subgroup->metadata_len); + memcpy(ptr, subgroup->metadata, subgroup->metadata_len); + ptr += subgroup->metadata_len; + } + + len = sizeof(*ev) + ptr - ev->subgroups; + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_BROADCAST_RECEIVE_STATE, ev, len); + + tester_rsp_buffer_free(); + tester_rsp_buffer_unlock(); +} + +static int pa_sync_past(struct bt_conn *conn, uint16_t sync_timeout) +{ + struct bt_le_per_adv_sync_transfer_param param = { 0 }; + int err; + + param.skip = PA_SYNC_SKIP; + param.timeout = sync_timeout; + + err = bt_le_per_adv_sync_transfer_subscribe(conn, ¶m); + if (err != 0) { + LOG_DBG("Could not do PAST subscribe: %d", err); + } else { + LOG_DBG("Syncing with PAST: %d", err); + (void)k_work_reschedule(&pa_timer, K_MSEC(param.timeout * 10)); + } + + return err; +} + +static int pa_sync_req_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state, + bool past_avail, uint16_t pa_interval) +{ + LOG_DBG("sync state %d ", recv_state->pa_sync_state); + + sink_recv_state = recv_state; + broadcast_recv_state = recv_state; + + btp_send_pas_sync_req_ev(conn, recv_state->src_id, recv_state->adv_sid, + recv_state->broadcast_id, past_avail, pa_interval); + + return 0; +} + +static int pa_sync_term_req_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state) +{ + LOG_DBG(""); + + sink_recv_state = recv_state; + + tester_gap_padv_stop_sync(); + + return 0; +} + +static void broadcast_code_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state, + const uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]) +{ + int err; + uint32_t index_bitfield; + + LOG_DBG("Broadcast code received for %p", recv_state); + + sink_recv_state = recv_state; + + (void)memcpy(sink_broadcast_code, broadcast_code, BT_AUDIO_BROADCAST_CODE_SIZE); + + if (!requested_bis_sync) { + return; + } + + index_bitfield = bis_index_bitfield & requested_bis_sync; + err = bt_bap_broadcast_sink_sync(broadcast_sink, index_bitfield, sink_streams, + sink_broadcast_code); + if (err != 0) { + LOG_DBG("Unable to sync to broadcast source: %d", err); + } +} + +static int bis_sync_req_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state, + const uint32_t bis_sync_req[BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS]) +{ + bool bis_synced = false; + + LOG_DBG("BIS sync request received for %p: 0x%08x", recv_state, bis_sync_req[0]); + + for (int i = 0; i < MAX_STREAMS_COUNT; i++) { + if (broadcaster->streams[i].bis_synced) { + bis_synced = true; + break; + } + } + + /* We only care about a single subgroup in this sample */ + if (bis_synced) { + /* If the BIS sync request is received while we are already + * synced, it means that the requested BIS sync has changed. + */ + int err; + + /* The stream stopped callback will be called as part of this, + * and we do not need to wait for any events from the + * controller. Thus, when this returns, the `bis_synced` + * is back to false. + */ + err = bt_bap_broadcast_sink_stop(broadcast_sink); + if (err != 0) { + LOG_DBG("Failed to stop Broadcast Sink: %d", err); + + return err; + } + } + + requested_bis_sync = bis_sync_req[0]; + broadcaster_broadcast_id = recv_state->broadcast_id; + + return 0; +} + +static void recv_state_updated_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state) +{ + LOG_DBG("Receive state with ID %u updated", recv_state->src_id); + + btp_send_broadcast_receive_state_ev(conn, recv_state); +} + +static struct bt_bap_scan_delegator_cb scan_delegator_cbs = { + .recv_state_updated = recv_state_updated_cb, + .pa_sync_req = pa_sync_req_cb, + .pa_sync_term_req = pa_sync_term_req_cb, + .broadcast_code = broadcast_code_cb, + .bis_sync_req = bis_sync_req_cb, +}; + static uint8_t broadcast_sink_setup(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { @@ -1608,8 +1836,14 @@ static uint8_t broadcast_sink_setup(const void *cmd, uint16_t cmd_len, sink_streams[i]->ops = &stream_ops; } + /* For Scan Delegator role */ + bt_bap_scan_delegator_register_cb(&scan_delegator_cbs); + + /* For Broadcast Sink role */ bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs); bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb); + + /* For Broadcast Sink or Broadcast Assistant role */ bt_le_scan_cb_register(&bap_scan_cb); return BTP_STATUS_SUCCESS; @@ -1668,35 +1902,36 @@ static uint8_t broadcast_sink_sync(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { int err; + struct bt_conn *conn; const struct btp_bap_broadcast_sink_sync_cmd *cp = cmd; struct bt_le_per_adv_sync_param create_params = {0}; LOG_DBG(""); - /* Sink Sync steps: - * 1. bt_le_per_adv_sync_create() - * 2. bap_pa_sync_synced_cb() - * 3. bt_bap_broadcast_sink_create() - * 4. - base_recv_cb() - * - syncable_cb() - * - broadcast_code_cb() <- only with scan delegator - * - bis_sync_req_cb() <- only for scan delegator - * 5. bt_bap_broadcast_sink_sync() - * 6. stream_started() - * 7. stream_recv_cb() - * 8. bap_pa_sync_terminated_cb() - * 9. stream_stopped_cb() - */ - broadcaster_broadcast_id = sys_get_le24(cp->broadcast_id); bt_addr_le_copy(&broadcaster_addr, &cp->address); - bt_addr_le_copy(&create_params.addr, &cp->address); - create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE; - create_params.sid = cp->advertiser_sid; - create_params.skip = cp->skip; - create_params.timeout = cp->sync_timeout; - err = tester_padv_create_sync(&create_params); + if (IS_ENABLED(CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER) && cp->past_avail) { + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_scan_delegator_set_pa_state(cp->src_id, BT_BAP_PA_STATE_INFO_REQ); + if (err != 0) { + LOG_DBG("Failed to set INFO_REQ state: %d", err); + } + + err = pa_sync_past(conn, cp->sync_timeout); + } else { + bt_addr_le_copy(&create_params.addr, &cp->address); + create_params.options = 0; + create_params.sid = cp->advertiser_sid; + create_params.skip = cp->skip; + create_params.timeout = cp->sync_timeout; + err = tester_gap_padv_create_sync(&create_params); + } + if (err != 0) { return BTP_STATUS_FAILED; } @@ -1711,6 +1946,8 @@ static uint8_t broadcast_sink_stop(const void *cmd, uint16_t cmd_len, LOG_DBG(""); + requested_bis_sync = 0; + err = bt_bap_broadcast_sink_stop(broadcast_sink); if (err != 0) { LOG_DBG("Unable to sync to broadcast source: %d", err); @@ -1718,6 +1955,368 @@ static uint8_t broadcast_sink_stop(const void *cmd, uint16_t cmd_len, return BTP_STATUS_FAILED; } + err = tester_gap_padv_stop_sync(); + if (err != 0) { + LOG_DBG("Failed to stop PA sync, %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t broadcast_sink_bis_sync(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const struct btp_bap_broadcast_sink_bis_sync_cmd *cp = cmd; + + LOG_DBG(""); + + if (cp->requested_bis_sync == BT_BAP_BIS_SYNC_NO_PREF) { + requested_bis_sync = sys_le32_to_cpu(cp->requested_bis_sync); + } else { + /* For semantic purposes Zephyr API uses BIS Index bitfield + * where BIT(1) means BIS Index 1 + */ + requested_bis_sync = sys_le32_to_cpu(cp->requested_bis_sync) << 1; + } + + err = bt_bap_broadcast_sink_sync(broadcast_sink, requested_bis_sync, sink_streams, + sink_broadcast_code); + if (err != 0) { + LOG_DBG("Unable to sync to BISes, req_bis_sync %d, err %d", requested_bis_sync, + err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err, + uint8_t recv_state_count) +{ + LOG_DBG("err %d", err); + + if (err != 0) { + LOG_DBG("BASS discover failed (%d)", err); + } else { + LOG_DBG("BASS discover done with %u recv states", recv_state_count); + + btp_send_scan_delegator_found_ev(conn); + } +} + +static void bap_broadcast_assistant_scan_cb(const struct bt_le_scan_recv_info *info, + uint32_t broadcast_id) +{ + char le_addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + LOG_DBG("[DEVICE]: %s, broadcast_id 0x%06X, interval (ms) %u), SID 0x%x, RSSI %i", le_addr, + broadcast_id, BT_GAP_PER_ADV_INTERVAL_TO_MS(info->interval), info->sid, info->rssi); +} + +static void bap_broadcast_assistant_recv_state_cb(struct bt_conn *conn, int err, + const struct bt_bap_scan_delegator_recv_state *state) +{ + LOG_DBG("err: %d", err); + + if (err != 0 || state == NULL) { + return; + } + + btp_send_broadcast_receive_state_ev(conn, state); +} + +static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, int err, + uint8_t src_id) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_scan_start_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_scan_stop_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_mod_src_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_broadcast_code_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static void bap_broadcast_assistant_rem_src_cb(struct bt_conn *conn, int err) +{ + LOG_DBG("err: %d", err); +} + +static struct bt_bap_broadcast_assistant_cb broadcast_assistant_cb = { + .discover = bap_broadcast_assistant_discover_cb, + .scan = bap_broadcast_assistant_scan_cb, + .recv_state = bap_broadcast_assistant_recv_state_cb, + .recv_state_removed = bap_broadcast_assistant_recv_state_removed_cb, + .scan_start = bap_broadcast_assistant_scan_start_cb, + .scan_stop = bap_broadcast_assistant_scan_stop_cb, + .add_src = bap_broadcast_assistant_add_src_cb, + .mod_src = bap_broadcast_assistant_mod_src_cb, + .broadcast_code = bap_broadcast_assistant_broadcast_code_cb, + .rem_src = bap_broadcast_assistant_rem_src_cb, +}; + +static uint8_t broadcast_discover_scan_delegators(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_discover_scan_delegators_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_discover(conn); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t broadcast_assistant_scan_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_broadcast_assistant_scan_start_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_scan_start(conn, true); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t broadcast_assistant_scan_stop(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_broadcast_assistant_scan_stop_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_scan_stop(conn); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t broadcast_assistant_add_src(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const uint8_t *ptr; + struct bt_conn *conn; + const struct btp_bap_add_broadcast_src_cmd *cp = cmd; + struct bt_bap_broadcast_assistant_add_src_param param = { 0 }; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + memset(delegator_subgroups, 0, sizeof(delegator_subgroups)); + bt_addr_le_copy(¶m.addr, &cp->broadcaster_address); + param.adv_sid = cp->advertiser_sid; + param.pa_sync = cp->padv_sync > 0 ? true : false; + param.broadcast_id = sys_get_le24(cp->broadcast_id); + param.pa_interval = sys_le16_to_cpu(cp->padv_interval); + param.num_subgroups = MIN(cp->num_subgroups, BROADCAST_SNK_SUBGROUP_CNT); + param.subgroups = delegator_subgroups; + + ptr = cp->subgroups; + for (uint8_t i = 0; i < param.num_subgroups; i++) { + struct bt_bap_scan_delegator_subgroup *subgroup = &delegator_subgroups[i]; + + subgroup->bis_sync = sys_get_le32(ptr); + ptr += sizeof(subgroup->bis_sync); + subgroup->metadata_len = *ptr; + ptr += sizeof(subgroup->metadata_len); + memcpy(subgroup->metadata, ptr, subgroup->metadata_len); + ptr += subgroup->metadata_len; + } + + err = bt_bap_broadcast_assistant_add_src(conn, ¶m); + if (err != 0) { + LOG_DBG("err %d", err); + + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t broadcast_assistant_remove_src(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_remove_broadcast_src_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_rem_src(conn, cp->src_id); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t broadcast_assistant_modify_src(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + const uint8_t *ptr; + struct bt_conn *conn; + const struct btp_bap_modify_broadcast_src_cmd *cp = cmd; + struct bt_bap_broadcast_assistant_mod_src_param param = { 0 }; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + memset(delegator_subgroups, 0, sizeof(delegator_subgroups)); + param.src_id = cp->src_id; + param.pa_sync = cp->padv_sync > 0 ? true : false; + param.pa_interval = sys_le16_to_cpu(cp->padv_interval); + param.num_subgroups = MIN(cp->num_subgroups, BROADCAST_SNK_SUBGROUP_CNT); + param.subgroups = delegator_subgroups; + + ptr = cp->subgroups; + for (uint8_t i = 0; i < param.num_subgroups; i++) { + struct bt_bap_scan_delegator_subgroup *subgroup = &delegator_subgroups[i]; + + subgroup->bis_sync = sys_get_le32(ptr); + ptr += sizeof(subgroup->bis_sync); + subgroup->metadata_len = *ptr; + ptr += sizeof(subgroup->metadata_len); + memcpy(subgroup->metadata, ptr, subgroup->metadata_len); + ptr += subgroup->metadata_len; + } + + err = bt_bap_broadcast_assistant_mod_src(conn, ¶m); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t broadcast_assistant_set_broadcast_code(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + struct bt_conn *conn; + const struct btp_bap_set_broadcast_code_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + err = bt_bap_broadcast_assistant_set_broadcast_code(conn, cp->src_id, cp->broadcast_code); + if (err != 0) { + LOG_DBG("err %d", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t broadcast_assistant_send_past(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + uint16_t service_data; + struct bt_conn *conn; + struct bt_le_per_adv_sync *pa_sync; + const struct btp_bap_send_past_cmd *cp = cmd; + + LOG_DBG(""); + + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); + if (!conn) { + return BTP_STATUS_FAILED; + } + + pa_sync = tester_gap_padv_get(); + if (!pa_sync) { + LOG_DBG("Could not send PAST to Scan Delegator"); + + return BTP_STATUS_FAILED; + } + + LOG_DBG("Sending PAST"); + + /* If octet 0 is set to 0, it means AdvA in PAST matches AdvA in ADV_EXT_IND. + * Octet 1 shall be set to Source_ID. + */ + service_data = cp->src_id << 8; + + err = bt_le_per_adv_sync_transfer(pa_sync, conn, service_data); + if (err != 0) { + LOG_DBG("Could not transfer periodic adv sync: %d", err); + + return BTP_STATUS_FAILED; + } + return BTP_STATUS_SUCCESS; } @@ -2698,6 +3297,51 @@ static const struct btp_handler bap_handlers[] = { .expect_len = sizeof(struct btp_bap_broadcast_sink_stop_cmd), .func = broadcast_sink_stop, }, + { + .opcode = BTP_BAP_BROADCAST_SINK_BIS_SYNC, + .expect_len = sizeof(struct btp_bap_broadcast_sink_bis_sync_cmd), + .func = broadcast_sink_bis_sync, + }, + { + .opcode = BTP_BAP_DISCOVER_SCAN_DELEGATORS, + .expect_len = sizeof(struct btp_bap_discover_scan_delegators_cmd), + .func = broadcast_discover_scan_delegators, + }, + { + .opcode = BTP_BAP_BROADCAST_ASSISTANT_SCAN_START, + .expect_len = sizeof(struct btp_bap_broadcast_assistant_scan_start_cmd), + .func = broadcast_assistant_scan_start, + }, + { + .opcode = BTP_BAP_BROADCAST_ASSISTANT_SCAN_STOP, + .expect_len = sizeof(struct btp_bap_broadcast_assistant_scan_stop_cmd), + .func = broadcast_assistant_scan_stop, + }, + { + .opcode = BTP_BAP_ADD_BROADCAST_SRC, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = broadcast_assistant_add_src, + }, + { + .opcode = BTP_BAP_REMOVE_BROADCAST_SRC, + .expect_len = sizeof(struct btp_bap_remove_broadcast_src_cmd), + .func = broadcast_assistant_remove_src, + }, + { + .opcode = BTP_BAP_MODIFY_BROADCAST_SRC, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = broadcast_assistant_modify_src, + }, + { + .opcode = BTP_BAP_SET_BROADCAST_CODE, + .expect_len = sizeof(struct btp_bap_set_broadcast_code_cmd), + .func = broadcast_assistant_set_broadcast_code, + }, + { + .opcode = BTP_BAP_SEND_PAST, + .expect_len = sizeof(struct btp_bap_send_past_cmd), + .func = broadcast_assistant_send_past, + }, }; uint8_t tester_init_pacs(void) @@ -2767,6 +3411,9 @@ uint8_t tester_init_bap(void) return BTP_STATUS_FAILED; } + /* For Broadcast Assistant role */ + bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_cb); + k_work_queue_init(&iso_data_work_q); k_work_queue_start(&iso_data_work_q, iso_data_thread_stack_area, K_THREAD_STACK_SIZEOF(iso_data_thread_stack_area), diff --git a/tests/bluetooth/tester/src/btp_core.c b/tests/bluetooth/tester/src/btp_core.c index 1840d2d5d0b80f2..8c157a5eccbef68 100644 --- a/tests/bluetooth/tester/src/btp_core.c +++ b/tests/bluetooth/tester/src/btp_core.c @@ -156,7 +156,8 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len, status = tester_init_ias(); break; #endif /* CONFIG_BT_IAS */ -#if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_UNICAST_SERVER) +#if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_UNICAST_SERVER) || \ + defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || defined(CONFIG_BT_BAP_BROADCAST_SINK) case BTP_SERVICE_ID_PACS: status = tester_init_pacs(); break; @@ -166,7 +167,9 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len, case BTP_SERVICE_ID_BAP: status = tester_init_bap(); break; -#endif /* CONFIG_BT_BAP_UNICAST_CLIENT or CONFIG_BT_BAP_UNICAST_SERVER */ +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT || CONFIG_BT_BAP_UNICAST_SERVER || \ + * CONFIG_BT_BAP_BROADCAST_SOURCE || CONFIG_BT_BAP_BROADCAST_SINK + */ #if defined(CONFIG_BT_MICP_MIC_DEV) || defined(CONFIG_BT_MICP_MIC_CTLR) case BTP_SERVICE_ID_MICP: status = tester_init_micp(); @@ -265,7 +268,8 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len, status = tester_unregister_ias(); break; #endif /* CONFIG_BT_IAS */ -#if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_UNICAST_SERVER) +#if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_UNICAST_SERVER) || \ + defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || defined(CONFIG_BT_BAP_BROADCAST_SINK) case BTP_SERVICE_ID_PACS: status = tester_unregister_pacs(); break; @@ -275,10 +279,17 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len, case BTP_SERVICE_ID_BAP: status = tester_unregister_bap(); break; - case BTP_SERVICE_ID_MICP: +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT || CONFIG_BT_BAP_UNICAST_SERVER || \ + * CONFIG_BT_BAP_BROADCAST_SOURCE || CONFIG_BT_BAP_BROADCAST_SINK + */ +#if defined(CONFIG_BT_MICP_MIC_DEV) || defined(CONFIG_BT_MICP_MIC_CTLR) + case BTP_SERVICE_ID_MICP: status = tester_unregister_micp(); break; -#endif /* CONFIG_BT_BAP_UNICAST_CLIENT or CONFIG_BT_BAP_UNICAST_SERVER */ + case BTP_SERVICE_ID_MICS: + status = tester_unregister_mics(); + break; +#endif /* CONFIG_BT_MICP_MIC_DEV or CONFIG_BT_MICP_MIC_CTLR */ #if defined(CONFIG_BT_HAS) case BTP_SERVICE_ID_HAS: status = tester_unregister_has(); diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c index 2191da79534e301..e09e90a06e1cf5f 100644 --- a/tests/bluetooth/tester/src/btp_gap.c +++ b/tests/bluetooth/tester/src/btp_gap.c @@ -1539,7 +1539,7 @@ static uint8_t padv_set_data(const void *cmd, uint16_t cmd_len, return BTP_STATUS_SUCCESS; } -int tester_padv_create_sync(struct bt_le_per_adv_sync_param *create_params) +int tester_gap_padv_create_sync(struct bt_le_per_adv_sync_param *create_params) { int err; @@ -1556,6 +1556,22 @@ int tester_padv_create_sync(struct bt_le_per_adv_sync_param *create_params) return err; } +int tester_gap_padv_stop_sync(void) +{ + int err; + + if (pa_sync == NULL) { + return -EALREADY; + } + + err = bt_le_per_adv_sync_delete(pa_sync); + if (err != 0) { + LOG_DBG("Unable to stop sync to PA: %d", err); + } + + return err; +} + static uint8_t padv_create_sync(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { @@ -1569,7 +1585,7 @@ static uint8_t padv_create_sync(const void *cmd, uint16_t cmd_len, create_params.skip = cp->skip; create_params.timeout = cp->sync_timeout; - err = tester_padv_create_sync(&create_params); + err = tester_gap_padv_create_sync(&create_params); if (err != 0) { return BTP_STATUS_FAILED; } From 71387ca165424958bc132d00fe6ed18f56973642 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 3 Nov 2023 13:53:54 +0800 Subject: [PATCH 0706/1049] arch/soc: introduce config for custom arch_cpu_idle implementation Each arch platform may has a general arch_cpu_idle implementation but each vendor may has a custom one, so this config will be used for vendor to override it. Some workarounds were introduced for intel cavs2.5 platform bring up. It is not general so move them to platform code. Signed-off-by: Rander Wang --- arch/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/Kconfig b/arch/Kconfig index 0a108702ad96217..5e3b96f414d497d 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -978,3 +978,10 @@ config TOOLCHAIN_HAS_BUILTIN_FFS default y if !(64BIT && RISCV) help Hidden option to signal that toolchain has __builtin_ffs*(). + +config ARCH_CPU_IDLE_CUSTOM + bool "Custom arch_cpu_idle implementation" + default n + help + This options allows applications to override the default arch idle implementation with + a custom one. From 0c27d772f68926cfa1a7127280956dd6e57e6e48 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 3 Nov 2023 14:13:37 +0800 Subject: [PATCH 0707/1049] soc: intel_adsp/cavs: add arch_cpu_idle support Cavs platforms starts from Apllolake to Raptorlake. Some of them need some workaround for arch_cpu_idle so create a bespoken one. Each workaround is configured by kconfig setting. Signed-off-by: Rander Wang --- soc/xtensa/intel_adsp/cavs/power.c | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index bc955b3cb90e214..c0a75f5c0ecec4e 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -180,6 +180,51 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) } #endif /* CONFIG_PM */ +#ifdef CONFIG_ARCH_CPU_IDLE_CUSTOM +/* xt-clang removes any NOPs more than 8. So we need to set + * no optimization to avoid those NOPs from being removed. + * + * This function is simply enough and full of hand written + * assembly that optimization is not really meaningful + * anyway. So we can skip optimization unconditionally. + * Re-evalulate its use and add #ifdef if this assumption + * is no longer valid. + */ +__no_optimization +void arch_cpu_idle(void) +{ + sys_trace_idle(); + + /* Just spin forever with interrupts unmasked, for platforms + * where WAITI can't be used or where its behavior is + * complicated (Intel DSPs will power gate on idle entry under + * some circumstances) + */ + if (IS_ENABLED(CONFIG_XTENSA_CPU_IDLE_SPIN)) { + __asm__ volatile("rsil a0, 0"); + __asm__ volatile("loop_forever: j loop_forever"); + return; + } + + /* Cribbed from SOF: workaround for a bug in some versions of + * the LX6 IP. Preprocessor ugliness avoids the need to + * figure out how to get the compiler to unroll a loop. + */ + if (IS_ENABLED(CONFIG_XTENSA_WAITI_BUG)) { +#define NOP4 __asm__ volatile("nop; nop; nop; nop"); +#define NOP32 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 +#define NOP128() NOP32 NOP32 NOP32 NOP32 + NOP128(); +#undef NOP128 +#undef NOP32 +#undef NOP4 + __asm__ volatile("isync; extw"); + } + +__asm__ volatile ("waiti 0"); +} +#endif + __imr void power_init(void) { /* Request HP ring oscillator and From 954901296c9735edc6414abb8ac0b81dbe1549b5 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 3 Nov 2023 13:53:54 +0800 Subject: [PATCH 0708/1049] arch/xtensa: clean up arch_cpu_idle function Some workarounds were introduced for intel cavs2.5 platform bring up. It is not general so move them to platform code. Signed-off-by: Rander Wang --- arch/xtensa/Kconfig | 12 ----------- arch/xtensa/core/cpu_idle.c | 39 ++--------------------------------- soc/xtensa/intel_adsp/Kconfig | 12 +++++++++++ 3 files changed, 14 insertions(+), 49 deletions(-) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 29c06667f555555..a1517f17ed0976e 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -50,18 +50,6 @@ config XTENSA_ENABLE_BACKTRACE help Enable this config option to print backtrace on panic exception -config XTENSA_CPU_IDLE_SPIN - bool "Use busy loop for k_cpu_idle" - help - Use a spin loop instead of WAITI for the CPU idle state. - -config XTENSA_WAITI_BUG - bool "Workaround sequence for WAITI bug on LX6" - help - SOF traditionally contains this workaround on its ADSP - platforms which prefixes a WAITI entry with 128 NOP - instructions followed by an ISYNC and EXTW. - config XTENSA_SMALL_VECTOR_TABLE_ENTRY bool "Workaround for small vector table entries" help diff --git a/arch/xtensa/core/cpu_idle.c b/arch/xtensa/core/cpu_idle.c index fa9384d8445a8e8..dae79f023ff7a37 100644 --- a/arch/xtensa/core/cpu_idle.c +++ b/arch/xtensa/core/cpu_idle.c @@ -6,48 +6,13 @@ #include #include -/* xt-clang removes any NOPs more than 8. So we need to set - * no optimization to avoid those NOPs from being removed. - * - * This function is simply enough and full of hand written - * assembly that optimization is not really meaningful - * anyway. So we can skip optimization unconditionally. - * Re-evalulate its use and add #ifdef if this assumption - * is no longer valid. - */ -__no_optimization +#ifndef CONFIG_ARCH_CPU_IDLE_CUSTOM void arch_cpu_idle(void) { sys_trace_idle(); - - /* Just spin forever with interrupts unmasked, for platforms - * where WAITI can't be used or where its behavior is - * complicated (Intel DSPs will power gate on idle entry under - * some circumstances) - */ - if (IS_ENABLED(CONFIG_XTENSA_CPU_IDLE_SPIN)) { - __asm__ volatile("rsil a0, 0"); - __asm__ volatile("loop_forever: j loop_forever"); - return; - } - - /* Cribbed from SOF: workaround for a bug in some versions of - * the LX6 IP. Preprocessor ugliness avoids the need to - * figure out how to get the compiler to unroll a loop. - */ - if (IS_ENABLED(CONFIG_XTENSA_WAITI_BUG)) { -#define NOP4 __asm__ volatile("nop; nop; nop; nop"); -#define NOP32 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 -#define NOP128() NOP32 NOP32 NOP32 NOP32 - NOP128(); -#undef NOP128 -#undef NOP32 -#undef NOP4 - __asm__ volatile("isync; extw"); - } - __asm__ volatile ("waiti 0"); } +#endif void arch_cpu_atomic_idle(unsigned int key) { diff --git a/soc/xtensa/intel_adsp/Kconfig b/soc/xtensa/intel_adsp/Kconfig index f04286ccae12b4d..a3d93d976ea1a86 100644 --- a/soc/xtensa/intel_adsp/Kconfig +++ b/soc/xtensa/intel_adsp/Kconfig @@ -113,4 +113,16 @@ config ADSP_IMR_CONTEXT_SAVE entering D3 state. Later this context can be used to FW restore when Host power up DSP again. +config XTENSA_CPU_IDLE_SPIN + bool "Use busy loop for k_cpu_idle" + help + Use a spin loop instead of WAITI for the CPU idle state. + +config XTENSA_WAITI_BUG + bool "Workaround sequence for WAITI bug on LX6" + help + SOF traditionally contains this workaround on its ADSP + platforms which prefixes a WAITI entry with 128 NOP + instructions followed by an ISYNC and EXTW. + endif # SOC_FAMILY_INTEL_ADSP From b0940e6e2587a3b2de397ca90ec86812514bdc9b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 13 Nov 2023 18:07:51 +0000 Subject: [PATCH 0709/1049] tests: build_all: input: unify the gpio definitions Clean up few build all device instances to use the test_gpio node and different gpio numbers. Makes them somewhat more representative of what an actual instance would look like. Signed-off-by: Fabio Baltieri --- tests/drivers/build_all/input/app.overlay | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index f065aadd5f36c57..2dcef76e2aea0e6 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -70,28 +70,28 @@ gt911@1 { compatible = "goodix,gt911"; reg = <0x1>; - irq-gpios = <&gpio0 0 0>; - reset-gpios = <&gpio0 0 0>; + irq-gpios = <&test_gpio 0 0>; + reset-gpios = <&test_gpio 1 0>; }; cst816s: cst816s@2 { compatible = "hynitron,cst816s"; reg = <0x2>; - irq-gpios = <&gpio0 0 0>; - rst-gpios = <&gpio0 0 0>; + irq-gpios = <&test_gpio 0 0>; + rst-gpios = <&test_gpio 1 0>; }; cap1203@3 { compatible = "microchip,cap1203"; reg = <0x3>; - int-gpios = <&gpio0 0 0>; + int-gpios = <&test_gpio 0 0>; input-codes = <0 1 2>; }; stmpe811@4 { compatible = "st,stmpe811"; reg = <0x4>; - int-gpios = <&gpio0 0 0>; + int-gpios = <&test_gpio 0 0>; panel-driver-settling-time-us = <10>; touch-detect-delay-us = <10>; touch-average-control = <1>; From b6a996d00a6a5950a995bb4477a50eadf7d15835 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 10:03:31 +0000 Subject: [PATCH 0710/1049] tests: build_all: input: drop a device nodelabel Other entires don't have it, keep it uniform. Signed-off-by: Fabio Baltieri --- tests/drivers/build_all/input/app.overlay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 2dcef76e2aea0e6..cf826cfe4fa9b33 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -74,7 +74,7 @@ reset-gpios = <&test_gpio 1 0>; }; - cst816s: cst816s@2 { + cst816s@2 { compatible = "hynitron,cst816s"; reg = <0x2>; irq-gpios = <&test_gpio 0 0>; From 4d554dd30cfb07863a135caace44fcd25802f480 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 17 Jul 2023 16:29:20 +0200 Subject: [PATCH 0711/1049] dts: bindings: gpio: add TLE9104 Add binding for the powertrain switch TLE9104. Signed-off-by: Benedikt Schmidt --- dts/bindings/gpio/infineon,tle9104.yaml | 50 +++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 dts/bindings/gpio/infineon,tle9104.yaml diff --git a/dts/bindings/gpio/infineon,tle9104.yaml b/dts/bindings/gpio/infineon,tle9104.yaml new file mode 100644 index 000000000000000..5893f1a355aaae6 --- /dev/null +++ b/dts/bindings/gpio/infineon,tle9104.yaml @@ -0,0 +1,50 @@ +# +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Infineon TLE9104 4-channel powertrain switch + +compatible: "infineon,tle9104" + +include: [gpio-controller.yaml, spi-device.yaml] + +properties: + "#gpio-cells": + const: 2 + + ngpios: + type: int + required: true + const: 4 + description: Number of GPIOs supported + + en-gpios: + type: phandle-array + description: "GPIO for enable" + + resn-gpios: + type: phandle-array + required: true + description: "GPIO for reset" + + in1-gpios: + type: phandle-array + description: "GPIO for controlling OUT1" + + in2-gpios: + type: phandle-array + description: "GPIO for controlling OUT2" + + in3-gpios: + type: phandle-array + description: "GPIO for controlling OUT3" + + in4-gpios: + type: phandle-array + description: "GPIO for controlling OUT4" + +gpio-cells: + - pin + - flags From bfb8eda025819395bd2f8c81783c0a0d2ec13f14 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Tue, 18 Jul 2023 11:12:31 +0200 Subject: [PATCH 0712/1049] drivers: gpio: implement driver for TLE9104 Implement a driver for the powertrain switch TLE9104. Signed-off-by: Benedikt Schmidt --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.tle9104 | 19 ++ drivers/gpio/gpio_tle9104.c | 535 +++++++++++++++++++++++++++++++++++ 4 files changed, 557 insertions(+) create mode 100644 drivers/gpio/Kconfig.tle9104 create mode 100644 drivers/gpio/gpio_tle9104.c diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 0e94d78dba3d667..b1cd06978bb2769 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -84,6 +84,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_NUMAKER gpio_numaker.c) zephyr_library_sources_ifdef(CONFIG_GPIO_EFINIX_SAPPHIRE gpio_efinix_sapphire.c) zephyr_library_sources_ifdef(CONFIG_GPIO_DAVINCI gpio_davinci.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SEDI gpio_sedi.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_TLE9104 gpio_tle9104.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ALTERA_PIO gpio_altera_pio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RA gpio_ra.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 07c3d6b47da9e1c..c49e2aa1167e40c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -226,6 +226,8 @@ source "drivers/gpio/Kconfig.efinix_sapphire" source "drivers/gpio/Kconfig.davinci" source "drivers/gpio/Kconfig.sedi" +source "drivers/gpio/Kconfig.tle9104" + source "drivers/gpio/Kconfig.altera" source "drivers/gpio/Kconfig.bcm2711" diff --git a/drivers/gpio/Kconfig.tle9104 b/drivers/gpio/Kconfig.tle9104 new file mode 100644 index 000000000000000..fd12710a5f57a68 --- /dev/null +++ b/drivers/gpio/Kconfig.tle9104 @@ -0,0 +1,19 @@ +# TLE9104 GPIO configuration options + +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +menuconfig GPIO_TLE9104 + bool "TLE9104 SPI-based powertrain switch" + default y + depends on DT_HAS_INFINEON_TLE9104_ENABLED + depends on SPI + help + Enable driver for TLE9104 SPI-based powertrain switch. + +config GPIO_TLE9104_INIT_PRIORITY + int "Init priority" + default 75 + depends on GPIO_TLE9104 + help + Device driver initialization priority. diff --git a/drivers/gpio/gpio_tle9104.c b/drivers/gpio/gpio_tle9104.c new file mode 100644 index 000000000000000..072828dec88fd0c --- /dev/null +++ b/drivers/gpio/gpio_tle9104.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_tle9104 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(gpio_tle9104, CONFIG_GPIO_LOG_LEVEL); + +/* + * The values for the defines below as well as the register definitions were + * taken from the datasheet, which can be found at: + * https://www.infineon.com/dgdl/Infineon-TLE9104SH-DataSheet-v01_31-EN.pdf?fileId=5546d462766cbe86017676144d76581b + */ +#define TLE9104_RESET_DURATION_TIME_US 10 +#define TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US 200 +#define TLE9104_RESET_DURATION_WAIT_TIME_US 10 +#define TLE9104_GPIO_COUNT 4 +#define TLE9104_INITIALIZATION_TIMEOUT_MS 1 +#define TLE9104_ICVERSIONID 0xB1 + +#define TLE9104_FRAME_RW_POS 15 +#define TLE9104_FRAME_PARITY_POS 14 +#define TLE9104_FRAME_FAULTCOMMUNICATION_POS 13 +#define TLE9104_FRAME_FAULTGLOBAL_POS 12 +#define TLE9104_FRAME_ADDRESS_POS 8 +#define TLE9104_FRAME_DATA_POS 0 + +#define TLE9104_CFG_CWDTIME_LENGTH 2 +#define TLE9104_CFG_CWDTIME_POS 6 + +#define TLE9104_CTRL_OUT1ONS_BIT BIT(1) +#define TLE9104_CTRL_OUT1ONC_BIT BIT(0) +#define TLE9104_CFG_OUT1DD_BIT BIT(0) +#define TLE9104_GLOBALSTATUS_OUTEN_BIT BIT(7) +#define TLE9104_GLOBALSTATUS_POR_LATCH_BIT BIT(0) +#define TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT BIT(13) + +enum tle9104_register { + TLE9104REGISTER_CTRL = 0x00, + TLE9104REGISTER_CFG = 0x01, + TLE9104REGISTER_GLOBALSTATUS = 0x07, + TLE9104REGISTER_ICVID = 0x08, +}; + +struct tle9104_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + + struct spi_dt_spec bus; + const struct gpio_dt_spec gpio_reset; + const struct gpio_dt_spec gpio_enable; + const struct gpio_dt_spec gpio_control[TLE9104_GPIO_COUNT]; +}; + +struct tle9104_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + /* each bit is one output channel, bit 0 = OUT1, ... */ + uint8_t state; + /* same as state, just kept for checking what has to be updated */ + uint8_t previous_state; + /* each bit defines if the output channel is configured, see state */ + uint8_t configured; + struct k_mutex lock; +}; + +static void tle9104_set_cfg_cwdtime(uint8_t *destination, uint8_t value) +{ + uint8_t length = TLE9104_CFG_CWDTIME_LENGTH; + uint8_t pos = TLE9104_CFG_CWDTIME_POS; + + *destination &= ~GENMASK(pos + length - 1, pos); + *destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value); +} + +static int tle9104_calculate_parity(uint16_t value) +{ + int parity = 1 + POPCOUNT(value); + + if ((value & BIT(TLE9104_FRAME_PARITY_POS)) != 0) { + parity--; + } + + return parity % 2; +} + +static void tle9104_apply_parity(uint16_t *value) +{ + int parity = tle9104_calculate_parity(*value); + + WRITE_BIT(*value, TLE9104_FRAME_PARITY_POS, parity); +} + +static bool tle9104_check_parity(uint16_t value) +{ + int parity = tle9104_calculate_parity(value); + + return ((value & BIT(TLE9104_FRAME_PARITY_POS)) >> TLE9104_FRAME_PARITY_POS) == parity; +} + +static int tle9104_transceive_frame(const struct device *dev, bool write, + enum tle9104_register write_reg, uint8_t write_data, + enum tle9104_register *read_reg, uint8_t *read_data) +{ + const struct tle9104_config *config = dev->config; + uint16_t write_frame; + uint16_t read_frame; + int result; + uint8_t buffer_tx[2]; + uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; + const struct spi_buf tx_buf[] = {{ + .buf = buffer_tx, + .len = ARRAY_SIZE(buffer_tx), + }}; + const struct spi_buf rx_buf[] = {{ + .buf = buffer_rx, + .len = ARRAY_SIZE(buffer_rx), + }}; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = ARRAY_SIZE(rx_buf), + }; + + write_frame = write_data << TLE9104_FRAME_DATA_POS; + write_frame |= write_reg << TLE9104_FRAME_ADDRESS_POS; + WRITE_BIT(write_frame, TLE9104_FRAME_RW_POS, write); + tle9104_apply_parity(&write_frame); + sys_put_be16(write_frame, buffer_tx); + LOG_DBG("writing in register 0x%02X of TLE9104 value 0x%02X, complete frame 0x%04X", + write_reg, write_data, write_frame); + + result = spi_transceive_dt(&config->bus, &tx, &rx); + if (result != 0) { + LOG_ERR("spi_write failed with error %i", result); + return result; + } + + read_frame = sys_get_be16(buffer_rx); + LOG_DBG("received complete frame 0x%04X", read_frame); + + if (!tle9104_check_parity(read_frame)) { + LOG_ERR("parity check for received frame of TLE9104 failed"); + return -EIO; + } + + if ((TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT & read_frame) != 0) { + LOG_WRN("communication fault reported by TLE9104"); + } + + *read_reg = FIELD_GET(GENMASK(TLE9104_FRAME_FAULTGLOBAL_POS - 1, TLE9104_FRAME_ADDRESS_POS), + read_frame); + *read_data = FIELD_GET(GENMASK(TLE9104_FRAME_ADDRESS_POS - 1, TLE9104_FRAME_DATA_POS), + read_frame); + + return 0; +} + +static int tle9104_write_register(const struct device *dev, enum tle9104_register reg, + uint8_t value) +{ + enum tle9104_register read_reg; + uint8_t read_data; + + return tle9104_transceive_frame(dev, true, reg, value, &read_reg, &read_data); +} + +static int tle9104_write_state(const struct device *dev) +{ + const struct tle9104_config *config = dev->config; + struct tle9104_data *data = dev->data; + bool spi_update_required = false; + uint8_t register_ctrl = 0x00; + int result; + + LOG_DBG("writing state 0x%02X to TLE9104", data->state); + + for (size_t i = 0; i < TLE9104_GPIO_COUNT; ++i) { + uint8_t mask = GENMASK(i, i); + bool current_value = (data->state & mask) != 0; + bool previous_value = (data->previous_state & mask) != 0; + + /* + * Setting the OUTx_ON bits results in a high impedance output, + * clearing them pulls the output to ground. Therefore the + * meaning here is intentionally inverted, as this will then turn + * out for a low active open drain output to be pulled to ground + * if set to off. + */ + if (current_value == 0) { + register_ctrl |= TLE9104_CTRL_OUT1ONS_BIT << (2 * i); + } else { + register_ctrl |= TLE9104_CTRL_OUT1ONC_BIT << (2 * i); + } + + if (current_value == previous_value) { + continue; + } + + if (config->gpio_control[i].port == NULL) { + spi_update_required = true; + continue; + } + + result = gpio_pin_set_dt(&config->gpio_control[i], current_value); + if (result != 0) { + LOG_ERR("unable to set control GPIO"); + return result; + } + } + + if (spi_update_required) { + result = tle9104_write_register(dev, TLE9104REGISTER_CTRL, register_ctrl); + if (result != 0) { + LOG_ERR("unable to set control register"); + return result; + } + } + + data->previous_state = data->state; + + return 0; +} + +static int tle9104_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + struct tle9104_data *data = dev->data; + int result; + + /* cannot execute a bus operation in an ISR context */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + if (pin >= TLE9104_GPIO_COUNT) { + LOG_ERR("invalid pin nummber %i", pin); + return -EINVAL; + } + + if ((flags & GPIO_INPUT) != 0) { + LOG_ERR("cannot configure pin as input"); + return -ENOTSUP; + } + + if ((flags & GPIO_OUTPUT) == 0) { + LOG_ERR("pin must be configured as an output"); + return -ENOTSUP; + } + + if ((flags & GPIO_SINGLE_ENDED) == 0) { + LOG_ERR("pin must be configured as single ended"); + return -ENOTSUP; + } + + if ((flags & GPIO_LINE_OPEN_DRAIN) == 0) { + LOG_ERR("pin must be configured as open drain"); + return -ENOTSUP; + } + + if ((flags & GPIO_PULL_UP) != 0) { + LOG_ERR("pin cannot have a pull up configured"); + return -ENOTSUP; + } + + if ((flags & GPIO_PULL_DOWN) != 0) { + LOG_ERR("pin cannot have a pull down configured"); + return -ENOTSUP; + } + + k_mutex_lock(&data->lock, K_FOREVER); + + if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { + WRITE_BIT(data->state, pin, 0); + } else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { + WRITE_BIT(data->state, pin, 1); + } + + WRITE_BIT(data->configured, pin, 1); + result = tle9104_write_state(dev); + k_mutex_unlock(&data->lock); + + return result; +} + +static int tle9104_port_get_raw(const struct device *dev, uint32_t *value) +{ + ARG_UNUSED(dev); + ARG_UNUSED(value); + + LOG_ERR("input pins are not available"); + return -ENOTSUP; +} + +static int tle9104_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) +{ + struct tle9104_data *data = dev->data; + int result; + + /* cannot execute a bus operation in an ISR context */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_mutex_lock(&data->lock, K_FOREVER); + data->state = (data->state & ~mask) | (mask & value); + result = tle9104_write_state(dev); + k_mutex_unlock(&data->lock); + + return result; +} + +static int tle9104_port_set_bits_raw(const struct device *dev, uint32_t mask) +{ + return tle9104_port_set_masked_raw(dev, mask, mask); +} + +static int tle9104_port_clear_bits_raw(const struct device *dev, uint32_t mask) +{ + return tle9104_port_set_masked_raw(dev, mask, 0); +} + +static int tle9104_port_toggle_bits(const struct device *dev, uint32_t mask) +{ + struct tle9104_data *data = dev->data; + int result; + + /* cannot execute a bus operation in an ISR context */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_mutex_lock(&data->lock, K_FOREVER); + data->state ^= mask; + result = tle9104_write_state(dev); + k_mutex_unlock(&data->lock); + + return result; +} + +static int tle9104_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pin); + ARG_UNUSED(mode); + ARG_UNUSED(trig); + return -ENOTSUP; +} + +static const struct gpio_driver_api api_table = { + .pin_configure = tle9104_pin_configure, + .port_get_raw = tle9104_port_get_raw, + .port_set_masked_raw = tle9104_port_set_masked_raw, + .port_set_bits_raw = tle9104_port_set_bits_raw, + .port_clear_bits_raw = tle9104_port_clear_bits_raw, + .port_toggle_bits = tle9104_port_toggle_bits, + .pin_interrupt_configure = tle9104_pin_interrupt_configure, +}; + +static int tle9104_init(const struct device *dev) +{ + const struct tle9104_config *config = dev->config; + struct tle9104_data *data = dev->data; + uint8_t register_cfg; + uint8_t register_globalstatus; + uint8_t register_icvid; + enum tle9104_register read_reg; + int result; + + LOG_DBG("initialize TLE9104 instance %s", dev->name); + + result = k_mutex_init(&data->lock); + if (result != 0) { + LOG_ERR("unable to initialize mutex"); + return result; + } + + if (!spi_is_ready_dt(&config->bus)) { + LOG_ERR("SPI bus %s is not ready", config->bus.bus->name); + return -ENODEV; + } + + register_cfg = 0x00; + + for (int i = 0; i < TLE9104_GPIO_COUNT; ++i) { + const struct gpio_dt_spec *current = config->gpio_control + i; + + if (current->port == NULL) { + LOG_DBG("got no control port for output %i, will control it via SPI", i); + continue; + } + + register_cfg |= TLE9104_CFG_OUT1DD_BIT << i; + + if (!device_is_ready(current->port)) { + LOG_ERR("control GPIO %s is not ready", current->port->name); + return -ENODEV; + } + + result = gpio_pin_configure_dt(current, GPIO_OUTPUT_INACTIVE); + if (result != 0) { + LOG_ERR("failed to initialize control GPIO %i", i); + return result; + } + } + + if (config->gpio_enable.port != NULL) { + if (!device_is_ready(config->gpio_enable.port)) { + LOG_ERR("enable GPIO %s is not ready", config->gpio_enable.port->name); + return -ENODEV; + } + + result = gpio_pin_configure_dt(&config->gpio_enable, GPIO_OUTPUT_ACTIVE); + if (result != 0) { + LOG_ERR("failed to enable TLE9104"); + return result; + } + } + + result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); + if (result != 0) { + LOG_ERR("failed to initialize GPIO for reset"); + return result; + } + + k_busy_wait(TLE9104_RESET_DURATION_TIME_US); + gpio_pin_set_dt(&config->gpio_reset, 0); + k_busy_wait(TLE9104_RESET_DURATION_WAIT_TIME_US + + TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US); + + /* + * The first read value should be the ICVID, this acts also as the setup of the + * global status register address. + */ + result = tle9104_transceive_frame(dev, false, TLE9104REGISTER_GLOBALSTATUS, 0x00, &read_reg, + ®ister_icvid); + if (result != 0) { + return result; + } + + if (read_reg != TLE9104REGISTER_ICVID) { + LOG_ERR("expected to read register ICVID, got instead 0x%02X", read_reg); + return -EIO; + } + + if (register_icvid != TLE9104_ICVERSIONID) { + LOG_ERR("got unexpected IC version id 0x%02X", register_icvid); + return -EIO; + } + + result = tle9104_transceive_frame(dev, false, TLE9104REGISTER_GLOBALSTATUS, 0x00, &read_reg, + ®ister_globalstatus); + if (result != 0) { + return result; + } + + if (read_reg != TLE9104REGISTER_GLOBALSTATUS) { + LOG_ERR("expected to read register GLOBALSTATUS, got instead 0x%02X", read_reg); + return -EIO; + } + + if ((register_globalstatus & TLE9104_GLOBALSTATUS_POR_LATCH_BIT) == 0) { + LOG_ERR("no power on reset detected"); + return -EIO; + } + + result = tle9104_write_register(dev, TLE9104REGISTER_CFG, register_cfg); + if (result != 0) { + LOG_ERR("unable to write configuration"); + return result; + } + + register_globalstatus = 0x00; + /* disable communication watchdog */ + tle9104_set_cfg_cwdtime(®ister_cfg, 0); + /* enable outputs */ + register_globalstatus |= TLE9104_GLOBALSTATUS_OUTEN_BIT; + + result = tle9104_write_register(dev, TLE9104REGISTER_GLOBALSTATUS, register_globalstatus); + if (result != 0) { + LOG_ERR("unable to write global status"); + return result; + } + + return 0; +} + +BUILD_ASSERT(CONFIG_GPIO_TLE9104_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY, + "TLE9104 must be initialized after SPI"); + +#define TLE9104_INIT_GPIO_FIELDS(inst, gpio) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, gpio), \ + (GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), gpio, 0)), ({0})) + +#define TLE9104_INIT(inst) \ + static const struct tle9104_config tle9104_##inst##_config = { \ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \ + }, \ + .bus = SPI_DT_SPEC_INST_GET( \ + inst, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ + .gpio_enable = TLE9104_INIT_GPIO_FIELDS(inst, en_gpios), \ + .gpio_reset = GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), resn_gpios, 0), \ + .gpio_control = { \ + TLE9104_INIT_GPIO_FIELDS(inst, in1_gpios), \ + TLE9104_INIT_GPIO_FIELDS(inst, in2_gpios), \ + TLE9104_INIT_GPIO_FIELDS(inst, in3_gpios), \ + TLE9104_INIT_GPIO_FIELDS(inst, in4_gpios), \ + }, \ + }; \ + \ + static struct tle9104_data tle9104_##inst##_drvdata; \ + \ + /* This has to be initialized after the SPI peripheral. */ \ + DEVICE_DT_INST_DEFINE(inst, tle9104_init, NULL, &tle9104_##inst##_drvdata, \ + &tle9104_##inst##_config, POST_KERNEL, \ + CONFIG_GPIO_TLE9104_INIT_PRIORITY, &api_table); + +DT_INST_FOREACH_STATUS_OKAY(TLE9104_INIT) From 003c132de6799bb583afb2eca8243fc0a217792f Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Tue, 18 Jul 2023 11:17:02 +0200 Subject: [PATCH 0713/1049] tests: drivers: gpio: add TLE9104 to the build_all tests Add an instance of the TLE9104 to the build_all tests. Signed-off-by: Benedikt Schmidt --- tests/drivers/build_all/gpio/app.overlay | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/drivers/build_all/gpio/app.overlay b/tests/drivers/build_all/gpio/app.overlay index 231d05a792f281f..375b3ab25dcd237 100644 --- a/tests/drivers/build_all/gpio/app.overlay +++ b/tests/drivers/build_all/gpio/app.overlay @@ -258,6 +258,17 @@ ngpios = <8>; }; }; + + test_spi_tle9104: tle9104@4 { + compatible = "infineon,tle9104"; + spi-max-frequency = <0>; + reg = <0x04>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <4>; + resn-gpios = <&test_gpio 0 0>; + en-gpios = <&test_gpio 0 0>; + }; }; }; }; From 299a10e0db4d571a1526fd5971e752d20abbf8b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 18:29:21 +0100 Subject: [PATCH 0714/1049] boards: doc: fix Toradex Verdin iMX8M title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The title for this board README was very broken, messing up not only this board's README but also the boards TOC. Signed-off-by: Benjamin Cabé --- boards/arm/verdin_imx8mp_m7/doc/index.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/boards/arm/verdin_imx8mp_m7/doc/index.rst b/boards/arm/verdin_imx8mp_m7/doc/index.rst index 6a35534a99f0e69..52eeebf3578883d 100644 --- a/boards/arm/verdin_imx8mp_m7/doc/index.rst +++ b/boards/arm/verdin_imx8mp_m7/doc/index.rst @@ -1,8 +1,7 @@ .. _verdin_imx8mp_m7: Toradex Verdin iMX8M Plus SoM - -############################################ +############################# Overview ******** From bdbf928b62f0778df92abbaaf61c60cc49f4be03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 18:35:32 +0100 Subject: [PATCH 0715/1049] boards: doc: fix Toradex Verdin iMX8M typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several fixes to this board's readme including broken build instructions. Signed-off-by: Benjamin Cabé --- boards/arm/verdin_imx8mp_m7/doc/index.rst | 30 ++++++++++++----------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/boards/arm/verdin_imx8mp_m7/doc/index.rst b/boards/arm/verdin_imx8mp_m7/doc/index.rst index 52eeebf3578883d..6dd483a0a63bfe6 100644 --- a/boards/arm/verdin_imx8mp_m7/doc/index.rst +++ b/boards/arm/verdin_imx8mp_m7/doc/index.rst @@ -25,18 +25,18 @@ The Verdin iMX8M Plus family consists of: | Verdin iMX8M Plus QuadLite 1GB IT | i.MX 8M Plus QuadLite | +-------------------------------------------------+-----------------------+ -Quoting NXP - -:: +Quoting NXP: The i.MX 8M Plus family focuses on machine learning and vision, advanced multimedia, and industrial automation with high reliability. It is built to meet the needs of Smart Home, Building, City and Industry 4.0 applications. The Verdin iMX8M Plus integrates a total of 4 Arm Cortex™-A53 CPUs, operating at 1.6 GHz, alongside a single Arm Cortex™-M7F microcontroller operating at 800 MHz. -.. image:: verdin_imx8mp_front.jpg +.. figure:: verdin_imx8mp_front.jpg :align: center - :alt: Toradex Verdin iMX8M Plus (Credit: Toradex) + :alt: Toradex Verdin iMX8M Plus + + Toradex Verdin iMX8M Plus (Credit: Toradex) Regarding the Cortex-A53 cluster, it employs the ARMv8-A architecture as a mid-range and energy-efficient processor. With four cores in this cluster, each core is equipped with its own L1 memory system. Moreover, the cluster incorporates a unified L2 cache that offers supplementary functions. This cache is housed within a single APR region. @@ -129,7 +129,8 @@ Other hardware features are not currently supported by the port. Connections and IOs =================== -UART: +UART +---- Zephyr is configured to use the UART4 by default, which is connected to the FTDI USB converter on most Toradex carrier boards. @@ -149,7 +150,8 @@ example). You can change the UART by changing the ``zephyr,console`` and | UART_4 | UART4 | Cortex-M4 debug UART | +---------------+-----------------+---------------------------+ -GPIO: +GPIO +---- All the GPIO banks available are enabled in the :zephyr_file:`dts/arm/nxp/nxp_imx8ml_m7.dtsi`. @@ -195,8 +197,8 @@ For more information about memory mapping see the At compilation time you have to choose which RAM will be used. To facilitate this process, there are two targets available: -- verdin_imx8mp_m7_itcm, which uses the ITCM configuration. -- verdin_imx8mp_m7_ddr, which uses the DDR configuration. +- ``verdin_imx8mp_m7_itcm``, which uses the ITCM configuration. +- ``verdin_imx8mp_m7_ddr``, which uses the DDR configuration. Starting the Cortex-M7 via U-Boot @@ -209,11 +211,11 @@ card into the board. Power it up and stop the u-boot execution at prompt. Load the M7 binary onto the desired memory and start its execution using: ITCM -=== +==== Loading the binary from an EXT4 partition: -.. code-block:: console +.. code-block:: shell ext4load mmc 2:2 ${loadaddr} //zephyr.bin cp.b ${loadaddr} 0x7e0000 @@ -224,7 +226,7 @@ DDR Loading the binary from an EXT4 partition: -.. code-block:: console +.. code-block:: shell ext4load mmc 2:2 ${loadaddr} //zephyr.bin cp.b ${loadaddr} 0x80000000 @@ -240,7 +242,7 @@ Here is an example for the :ref:`hello_world` application. .. zephyr-app-commands:: :zephyr-app: samples/hello_world - :board: verdin_imx8mp_m7 + :board: verdin_imx8mp_m7_ddr :goals: debug Open a serial terminal, step through the application in your debugger, and you @@ -249,7 +251,7 @@ should see the following message in the terminal: .. code-block:: console *** Booting Zephyr OS build zephyr-v3.4.0-2300-g03905f7e55d2 *** - Hello World! verdin_imx8mp_m7 + Hello World! verdin_imx8mp_m7_ddr References ========== From 3c8333ac107ee84dfb1fd28a131a03f49fb8b16b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 18:39:06 +0100 Subject: [PATCH 0716/1049] boards: doc: fix Toradex Verdin iMX8M line length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation .rst files should wrap at 100 characters. Signed-off-by: Benjamin Cabé --- boards/arm/verdin_imx8mp_m7/doc/index.rst | 95 +++++++++++++---------- 1 file changed, 54 insertions(+), 41 deletions(-) diff --git a/boards/arm/verdin_imx8mp_m7/doc/index.rst b/boards/arm/verdin_imx8mp_m7/doc/index.rst index 6dd483a0a63bfe6..455acb8c290aaa8 100644 --- a/boards/arm/verdin_imx8mp_m7/doc/index.rst +++ b/boards/arm/verdin_imx8mp_m7/doc/index.rst @@ -6,8 +6,8 @@ Toradex Verdin iMX8M Plus SoM Overview ******** -The Verdin iMX8M Plus is a Computer on Module (CoM) developed by Toradex. It is based on the NXP® i.MX 8M Plus family of -processors (or System on Chips - SoCs). +The Verdin iMX8M Plus is a Computer on Module (CoM) developed by Toradex. It is based on the NXP® +i.MX 8M Plus family of processors (or System on Chips - SoCs). The Verdin iMX8M Plus family consists of: @@ -27,10 +27,12 @@ The Verdin iMX8M Plus family consists of: Quoting NXP: - The i.MX 8M Plus family focuses on machine learning and vision, advanced multimedia, and industrial automation with high reliability. - It is built to meet the needs of Smart Home, Building, City and Industry 4.0 applications. + The i.MX 8M Plus family focuses on machine learning and vision, advanced multimedia, and + industrial automation with high reliability. It is built to meet the needs of Smart Home, + Building, City and Industry 4.0 applications. -The Verdin iMX8M Plus integrates a total of 4 Arm Cortex™-A53 CPUs, operating at 1.6 GHz, alongside a single Arm Cortex™-M7F microcontroller operating at 800 MHz. +The Verdin iMX8M Plus integrates a total of 4 Arm Cortex™-A53 CPUs, operating at 1.6 GHz, alongside +a single Arm Cortex™-M7F microcontroller operating at 800 MHz. .. figure:: verdin_imx8mp_front.jpg :align: center @@ -38,16 +40,23 @@ The Verdin iMX8M Plus integrates a total of 4 Arm Cortex™-A53 CPUs, operating Toradex Verdin iMX8M Plus (Credit: Toradex) -Regarding the Cortex-A53 cluster, it employs the ARMv8-A architecture as a mid-range and energy-efficient processor. With four cores in this cluster, each core is -equipped with its own L1 memory system. Moreover, the cluster incorporates a unified L2 cache that offers supplementary functions. This cache is housed within a single APR region. -Facilitating debugging processes, the cores support both real-time trace through the ETM system and static debugging via JTAG. Furthermore, the platform features support for real-time trace -capabilities, achieved through ARM's CoreSight ETM modules, and also enables cross-triggering by utilizing CTI and CTM modules. - -The Arm® Cortex®-M7 microcontroller is indicated for Real-time control, combining high-performance with a minimal interrupt latency. -It stands out for its compatibility with existing Cortex-M profile processors. The microcontroller employs an efficient in-order super-scalar pipeline, -allowing dual-issued instructions such as load/load and load/store pairs, thanks to its multiple memory interfaces. These interfaces encompass Tightly-Coupled Memory (TCM), Harvard caches, and an AXI master interface. -The Arm Cortex-M7 Platform boasts features like a 32 KB L1 Instruction Cache, 32 KB L1 Data Cache, Floating Point Unit (FPU) with FPv5 architecture support, and an Internal Trace (TRC) mechanism. -Furthermore, the chip supports 160 IRQs, and integrates crucial Arm CoreSight components including ETM and CTI, dedicated to facilitating debug and trace functions. +Regarding the Cortex-A53 cluster, it employs the ARMv8-A architecture as a mid-range and +energy-efficient processor. With four cores in this cluster, each core is equipped with its own L1 +memory system. Moreover, the cluster incorporates a unified L2 cache that offers supplementary +functions. This cache is housed within a single APR region. Facilitating debugging processes, the +cores support both real-time trace through the ETM system and static debugging via JTAG. +Furthermore, the platform features support for real-time trace capabilities, achieved through ARM's +CoreSight ETM modules, and also enables cross-triggering by utilizing CTI and CTM modules. + +The Arm® Cortex®-M7 microcontroller is indicated for Real-time control, combining high-performance +with a minimal interrupt latency. It stands out for its compatibility with existing Cortex-M profile +processors. The microcontroller employs an efficient in-order super-scalar pipeline, allowing +dual-issued instructions such as load/load and load/store pairs, thanks to its multiple memory +interfaces. These interfaces encompass Tightly-Coupled Memory (TCM), Harvard caches, and an AXI +master interface. The Arm Cortex-M7 Platform boasts features like a 32 KB L1 Instruction Cache, 32 +KB L1 Data Cache, Floating Point Unit (FPU) with FPv5 architecture support, and an Internal Trace +(TRC) mechanism. Furthermore, the chip supports 160 IRQs, and integrates crucial Arm CoreSight +components including ETM and CTI, dedicated to facilitating debug and trace functions. Hardware ******** @@ -118,9 +127,11 @@ The Zephyr verdin_imx8mp_m7 board configuration supports the following hardware The default configuration can be found in the defconfig file: -- :zephyr_file:`boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig`, if you choose to use the ITCM memory. +- :zephyr_file:`boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig`, if you choose to use + the ITCM memory. -- :zephyr_file:`boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig`, if you choose to use the DDR memory. +- :zephyr_file:`boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig`, if you choose to use + the DDR memory. It is recommended to disable peripherals used by the M7 core on the Linux host. @@ -132,15 +143,16 @@ Connections and IOs UART ---- -Zephyr is configured to use the UART4 by default, which is connected to the FTDI -USB converter on most Toradex carrier boards. +Zephyr is configured to use the UART4 by default, which is connected to the FTDI USB converter on +most Toradex carrier boards. -This is also the UART connected to WiFi/BT chip in modules that have the WiFi/BT -chip. Therefore, if UART4 is used, WiFI/BT will not work properly. +This is also the UART connected to WiFi/BT chip in modules that have the WiFi/BT chip. Therefore, if +UART4 is used, WiFI/BT will not work properly. -If the WiFi/BT is needed, then another UART should be used for Zephyr (UART1 for -example). You can change the UART by changing the ``zephyr,console`` and -``zephyr,shell-uart`` in the :zephyr_file:`boards/arm/verdin_imx8mp_m7_itcm.dts` or :zephyr_file:`boards/arm/verdin_imx8mp_m7_ddr.dts` file. +If the WiFi/BT is needed, then another UART should be used for Zephyr (UART1 for example). You can +change the UART by changing the ``zephyr,console`` and ``zephyr,shell-uart`` in the +:zephyr_file:`boards/arm/verdin_imx8mp_m7_itcm.dts` or +:zephyr_file:`boards/arm/verdin_imx8mp_m7_ddr.dts` file. +---------------+-----------------+---------------------------+ | Board Name | SoC Name | Usage | @@ -163,20 +175,19 @@ The M7 Core is configured to run at a 800 MHz clock speed. Serial Port =========== -The i.MX8M Plus SoC has four UARTs. UART_4 is configured for the console and -the remaining are not used/tested. +The i.MX8M Plus SoC has four UARTs. UART_4 is configured for the console and the remaining are not +used/tested. Programming and Debugging ************************* -The Verdin iMX8M Plus board doesn't have QSPI flash for the M7, and it needs -to be started by the A53 core. The A53 core is responsible to load the M7 binary -application into the RAM, put the M7 in reset, set the M7 Program Counter and -Stack Pointer, and get the M7 out of reset. The A53 can perform these steps at -bootloader level or after the Linux system has booted. +The Verdin iMX8M Plus board doesn't have QSPI flash for the M7, and it needs to be started by the +A53 core. The A53 core is responsible to load the M7 binary application into the RAM, put the M7 in +reset, set the M7 Program Counter and Stack Pointer, and get the M7 out of reset. The A53 can +perform these steps at bootloader level or after the Linux system has booted. -The M7 can use up to 3 different RAMs (currently, only two configurations are -supported: ITCM and DDR). These are the memory mapping for A53 and M7: +The M7 can use up to 3 different RAMs (currently, only two configurations are supported: ITCM and +DDR). These are the memory mapping for A53 and M7: +------------+-------------------------+------------------------+-----------------------+----------------------+ | Region | Cortex-A53 | Cortex-M7 (System Bus) | Cortex-M7 (Code Bus) | Size | @@ -192,10 +203,11 @@ supported: ITCM and DDR). These are the memory mapping for A53 and M7: | DDR | 0x80000000-0x803FFFFF | 0x80200000-0x803FFFFF | 0x80000000-0x801FFFFF | 2MB | +------------+-------------------------+------------------------+-----------------------+----------------------+ -For more information about memory mapping see the -`i.MX 8M Plus Applications Processor Reference Manual`_ (section 2.1 to 2.3) +For more information about memory mapping see the `i.MX 8M Plus Applications Processor Reference +Manual`_ (section 2.1 to 2.3) -At compilation time you have to choose which RAM will be used. To facilitate this process, there are two targets available: +At compilation time you have to choose which RAM will be used. To facilitate this process, there are +two targets available: - ``verdin_imx8mp_m7_itcm``, which uses the ITCM configuration. - ``verdin_imx8mp_m7_ddr``, which uses the DDR configuration. @@ -204,9 +216,9 @@ At compilation time you have to choose which RAM will be used. To facilitate thi Starting the Cortex-M7 via U-Boot ================================= -Load and run Zephyr on M7 from A53 using u-boot by copying the compiled -``zephyr.bin`` to the first FAT partition of the SD card and plug the SD -card into the board. Power it up and stop the u-boot execution at prompt. +Load and run Zephyr on M7 from A53 using u-boot by copying the compiled ``zephyr.bin`` to the first +FAT partition of the SD card and plug the SD card into the board. Power it up and stop the u-boot +execution at prompt. Load the M7 binary onto the desired memory and start its execution using: @@ -235,8 +247,9 @@ Loading the binary from an EXT4 partition: Debugging ========= -Toradex Verdin iMX8M Plus SoM can be debugged by connecting an external JLink JTAG debugger to the X56 debug connector and to the PC, or simply connecting a USB-C to X66 on the Verdin Development Board. -Then, the application can be debugged using the usual way. +Toradex Verdin iMX8M Plus SoM can be debugged by connecting an external JLink JTAG debugger to the +X56 debug connector and to the PC, or simply connecting a USB-C to X66 on the Verdin Development +Board. Then, the application can be debugged using the usual way. Here is an example for the :ref:`hello_world` application. From 97b9bce995c0df59fe7390650e13fba5b062e5d9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 09:25:13 +0100 Subject: [PATCH 0717/1049] doc/services/sensing: Refer to native_sim overlay instead of native_posix Refer to the native_sim overlay instead of the native_posix one, as native_posix is going to be deprecated soon. Signed-off-by: Alberto Escolar Piedras --- doc/services/sensing/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/sensing/index.rst b/doc/services/sensing/index.rst index d0ae0bea5ee9663..fac113a1772484c 100644 --- a/doc/services/sensing/index.rst +++ b/doc/services/sensing/index.rst @@ -241,7 +241,7 @@ Device Tree Configuration Sensing subsystem using device tree to configuration all sensor instances and their properties, reporting relationships. -See the example :zephyr_file:`samples/subsys/sensing/simple/boards/native_posix.overlay` +See the example :zephyr_file:`samples/subsys/sensing/simple/boards/native_sim.overlay` API Reference ************* From 196ceaf2f4ca984a1d84dc570926e793ff6a1f3e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 09:27:59 +0100 Subject: [PATCH 0718/1049] samples/drivers/uart/native_tty: Swap native_posix and sim overlay Refer to the native_sim overlay instead of the native_posix one, as native_posix is going to be deprecated soon. Signed-off-by: Alberto Escolar Piedras --- samples/drivers/uart/native_tty/README.rst | 2 +- .../uart/native_tty/boards/native_posix.overlay | 16 +--------------- .../uart/native_tty/boards/native_sim.overlay | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/samples/drivers/uart/native_tty/README.rst b/samples/drivers/uart/native_tty/README.rst index 6b6e2a3175ed73f..78c101dea1f71a4 100644 --- a/samples/drivers/uart/native_tty/README.rst +++ b/samples/drivers/uart/native_tty/README.rst @@ -28,7 +28,7 @@ Requirements ``/dev/ttyUSB0`` and ``/dev/ttyUSB1`` in the system. You can check what they are in your system by running the command ``ls -l /dev/tty*``. If that is not the case on your machine you can either change the ``serial-port`` properties - in the ``boards/native_posix.overlay`` file or using the command line options + in the ``boards/native_sim.overlay`` file or using the command line options ``-uart_port`` and ``-uart_port2``. Building and Running diff --git a/samples/drivers/uart/native_tty/boards/native_posix.overlay b/samples/drivers/uart/native_tty/boards/native_posix.overlay index 24f1bd95705bda3..6a3daca3241ac6e 100644 --- a/samples/drivers/uart/native_tty/boards/native_posix.overlay +++ b/samples/drivers/uart/native_tty/boards/native_posix.overlay @@ -1,15 +1 @@ -/ { - uart0: uart { - status = "okay"; - compatible = "zephyr,native-tty-uart"; - current-speed = <115200>; - serial-port = "/dev/ttyUSB0"; - }; - - uart2: uart2 { - status = "okay"; - compatible = "zephyr,native-tty-uart"; - current-speed = <115200>; - serial-port = "/dev/ttyUSB1"; - }; -}; +#include "native_sim.overlay" diff --git a/samples/drivers/uart/native_tty/boards/native_sim.overlay b/samples/drivers/uart/native_tty/boards/native_sim.overlay index 2b055bf3de6def2..24f1bd95705bda3 100644 --- a/samples/drivers/uart/native_tty/boards/native_sim.overlay +++ b/samples/drivers/uart/native_tty/boards/native_sim.overlay @@ -1 +1,15 @@ -#include "native_posix.overlay" +/ { + uart0: uart { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + current-speed = <115200>; + serial-port = "/dev/ttyUSB0"; + }; + + uart2: uart2 { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + current-speed = <115200>; + serial-port = "/dev/ttyUSB1"; + }; +}; From bf466da69fba5096aa1120d0c8cbcc90e6a6a63f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 09:35:01 +0100 Subject: [PATCH 0719/1049] samples zbus: Swap native_posix with native_sim In the docs replace references to native_posix with native_sim Switch the default test platform to native_sim from native_posix Signed-off-by: Alberto Escolar Piedras --- samples/subsys/zbus/remote_mock/README.rst | 10 +++++++--- samples/subsys/zbus/remote_mock/sample.yaml | 2 +- samples/subsys/zbus/uart_bridge/README.rst | 10 +++++++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/samples/subsys/zbus/remote_mock/README.rst b/samples/subsys/zbus/remote_mock/README.rst index c1a098839de016c..f599783e0fa325b 100644 --- a/samples/subsys/zbus/remote_mock/README.rst +++ b/samples/subsys/zbus/remote_mock/README.rst @@ -16,12 +16,12 @@ Building and Running ******************** This project outputs to the console. It can be built and executed -on native_posix as follows: +on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/subsys/zbus/remote_mock :host-os: unix - :board: native_posix + :board: native_sim :goals: run Sample Output @@ -63,7 +63,11 @@ The :file:`remote_mock.py` script can be executed using the following command: python3.8 samples/subsys/zbus/remote_mock/remote_mock.py /dev/pts/2 -Note the run command above prints the value of pts port because it is running in ``native_posix``. Look at the line indicating ``uart_1 connected to pseudotty: /dev/pts/2``. It can be different in your case. If you are using a board, read the documentation to get the correct port destination (in Linux is something like ``/dev/tty...`` or in Windows ``COM...``). +Note the run command above prints the value of pts port because it is running in +:ref:`native_sim `. +Look at the line indicating ``uart_1 connected to pseudotty: /dev/pts/2``. +It can be different in your case. If you are using a board, read the documentation to get the +correct port destination (in Linux is something like ``/dev/tty...`` or in Windows ``COM...``). From the remote mock (Python script), you would see something like this: diff --git a/samples/subsys/zbus/remote_mock/sample.yaml b/samples/subsys/zbus/remote_mock/sample.yaml index 3e49a6e2b03fb88..1b632901ed21d55 100644 --- a/samples/subsys/zbus/remote_mock/sample.yaml +++ b/samples/subsys/zbus/remote_mock/sample.yaml @@ -9,4 +9,4 @@ tests: - native_sim - hifive1_revb integration_platforms: - - native_posix + - native_sim diff --git a/samples/subsys/zbus/uart_bridge/README.rst b/samples/subsys/zbus/uart_bridge/README.rst index c14c0e8d64daf0f..a0101fa45b24ccf 100644 --- a/samples/subsys/zbus/uart_bridge/README.rst +++ b/samples/subsys/zbus/uart_bridge/README.rst @@ -14,12 +14,12 @@ Building and Running ******************** This project outputs to the console. It can be built and executed -on native_posix as follows: +on native_sim as follows: .. zephyr-app-commands:: :zephyr-app: samples/subsys/zbus/uart_bridge :host-os: unix - :board: native_posix + :board: native_sim :goals: run Sample Output @@ -68,7 +68,11 @@ The :file:`decoder.py` script can be executed using the following command: python3.8 samples/subsys/zbus/uart_bridge/decoder.py /dev/pts/2 -Note the run command above prints the value of pts port because it is running in ``native_posix``. Look at the line indicating ``uart_1 connected to pseudotty: /dev/pts/2``. It can be different in your case. If you are using a board, read the documentation to get the correct port destination (in Linux is something like ``/dev/tty...`` or in Windows ``COM...``). +Note the run command above prints the value of pts port because it is running in +:ref:`native_sim `. +Look at the line indicating ``uart_1 connected to pseudotty: /dev/pts/2``. +It can be different in your case. If you are using a board, read the documentation to get the +correct port destination (in Linux is something like ``/dev/tty...`` or in Windows ``COM...``). From the serial decoder (Python script), you would see something like this: From c93cef0996c19abeef50c40d2893b99347bb6b21 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 09:43:51 +0100 Subject: [PATCH 0720/1049] docs: Sample definition: Replace native_posix with native_sim As native_posix is going to be deprecated soon. Signed-off-by: Alberto Escolar Piedras --- samples/sample_definition_and_criteria.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/sample_definition_and_criteria.rst b/samples/sample_definition_and_criteria.rst index be0c9dfc3ef1f3d..8e69fe4a63ae1a3 100644 --- a/samples/sample_definition_and_criteria.rst +++ b/samples/sample_definition_and_criteria.rst @@ -38,7 +38,7 @@ Sample Criteria tests: sample.kernel.cond_var: integration_platforms: - - native_posix + - native_sim tags: kernel condition_variables harness: console harness_config: From 0ce4de8eec25a986a27db57f1731174eb023db39 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 09:50:30 +0100 Subject: [PATCH 0721/1049] pytest sample & docs: Replace native_posix with native_sim In the docs replace references to native_posix with native_sim Switch the default test platform to native_sim from native_posix Signed-off-by: Alberto Escolar Piedras --- samples/subsys/testsuite/pytest/basic/testcase.yaml | 6 ++++-- samples/subsys/testsuite/pytest/shell/testcase.yaml | 2 +- scripts/pylib/pytest-twister-harness/README.rst | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/samples/subsys/testsuite/pytest/basic/testcase.yaml b/samples/subsys/testsuite/pytest/basic/testcase.yaml index a7c28cafc3b6c63..6dc504cd64c143e 100644 --- a/samples/subsys/testsuite/pytest/basic/testcase.yaml +++ b/samples/subsys/testsuite/pytest/basic/testcase.yaml @@ -1,6 +1,8 @@ tests: sample.twister.pytest: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim harness: pytest harness_config: pytest_args: ["--custom-pytest-arg", "foo", "--cmdopt", "."] @@ -8,4 +10,4 @@ tests: - test_framework - pytest integration_platforms: - - native_posix + - native_sim diff --git a/samples/subsys/testsuite/pytest/shell/testcase.yaml b/samples/subsys/testsuite/pytest/shell/testcase.yaml index 02a3bcf9620ba94..86b9314f444416d 100644 --- a/samples/subsys/testsuite/pytest/shell/testcase.yaml +++ b/samples/subsys/testsuite/pytest/shell/testcase.yaml @@ -6,7 +6,7 @@ tests: extra_configs: - arch:posix:CONFIG_NATIVE_UART_0_ON_STDINOUT=y integration_platforms: - - native_posix + - native_sim - qemu_cortex_m3 tags: - test_framework diff --git a/scripts/pylib/pytest-twister-harness/README.rst b/scripts/pylib/pytest-twister-harness/README.rst index 814282fc57b21c4..860b7cd645de027 100644 --- a/scripts/pylib/pytest-twister-harness/README.rst +++ b/scripts/pylib/pytest-twister-harness/README.rst @@ -20,8 +20,8 @@ Run exemplary test shell application by Twister: cd ${ZEPHYR_BASE} - # native_posix & QEMU - ./scripts/twister -p native_posix -p qemu_x86 -T samples/subsys/testsuite/pytest/shell + # native_sim & QEMU + ./scripts/twister -p native_sim -p qemu_x86 -T samples/subsys/testsuite/pytest/shell # hardware ./scripts/twister -p nrf52840dk_nrf52840 --device-testing --device-serial /dev/ttyACM0 -T samples/subsys/testsuite/pytest/shell @@ -34,8 +34,8 @@ or build shell application by west and call pytest directly: cd ${ZEPHYR_BASE}/samples/subsys/testsuite/pytest/shell - # native_posix - west build -p -b native_posix -- -DCONFIG_NATIVE_UART_0_ON_STDINOUT=y + # native_sim + west build -p -b native_sim -- -DCONFIG_NATIVE_UART_0_ON_STDINOUT=y pytest --twister-harness --device-type=native --build-dir=build -p twister_harness.plugin # QEMU From 4a0dec6a5a16f16c5c88ea60af4796079be267fd Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 10:05:29 +0100 Subject: [PATCH 0722/1049] subsys/bindesc: Fix kconfig dependency BINDESC can be used with any POSIX arch based target, not just native_posix. Fix the kconfig filter and the sample yaml filter. Signed-off-by: Alberto Escolar Piedras --- samples/subsys/bindesc/hello_bindesc/sample.yaml | 3 +-- subsys/bindesc/Kconfig | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/samples/subsys/bindesc/hello_bindesc/sample.yaml b/samples/subsys/bindesc/hello_bindesc/sample.yaml index e923744c3d842af..adea05379a22104 100644 --- a/samples/subsys/bindesc/hello_bindesc/sample.yaml +++ b/samples/subsys/bindesc/hello_bindesc/sample.yaml @@ -3,7 +3,6 @@ sample: tests: sample.bindesc: tags: bindesc - filter: CONFIG_ARCH_SUPPORTS_ROM_START - build_only: true + filter: CONFIG_ARCH_SUPPORTS_ROM_START or CONFIG_ARCH_POSIX integration_platforms: - native_posix diff --git a/subsys/bindesc/Kconfig b/subsys/bindesc/Kconfig index 0f55564d46063e9..e8c158b8c84f515 100644 --- a/subsys/bindesc/Kconfig +++ b/subsys/bindesc/Kconfig @@ -3,7 +3,7 @@ menuconfig BINDESC bool "Binary Descriptors" - depends on ARCH_SUPPORTS_ROM_START || BOARD_NATIVE_POSIX + depends on ARCH_SUPPORTS_ROM_START || ARCH_POSIX help Binary Descriptors - constant data accessible outside of the executable image From b2a84eaf12b1619d334f8182a18ba0ef4719e8ac Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 10:06:43 +0100 Subject: [PATCH 0723/1049] samples bindesc: Add runtime test and change default to native_sim * In the docs replace references to native_posix with native_sim * Switch the default test platform to native_sim from native_posix * Add a runtime check for this sample Signed-off-by: Alberto Escolar Piedras --- samples/subsys/bindesc/hello_bindesc/README.rst | 2 +- samples/subsys/bindesc/hello_bindesc/sample.yaml | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/samples/subsys/bindesc/hello_bindesc/README.rst b/samples/subsys/bindesc/hello_bindesc/README.rst index f2cd9e2d16eb71a..0596639b518c96a 100644 --- a/samples/subsys/bindesc/hello_bindesc/README.rst +++ b/samples/subsys/bindesc/hello_bindesc/README.rst @@ -27,6 +27,6 @@ To dump all binary descriptors in the image, run: west bindesc dump build/zephyr/zephyr.bin (Note: you can also dump the contents of ``zephyr.elf``, if your build system -does not produce a ``*.bin`` file, e.g. compiling for ``native_posix``.) +does not produce a ``*.bin`` file, e.g. compiling for ``native_sim``.) For more details see :ref:`binary_descriptors` and :ref:`west-bindesc`. diff --git a/samples/subsys/bindesc/hello_bindesc/sample.yaml b/samples/subsys/bindesc/hello_bindesc/sample.yaml index adea05379a22104..2725b9ab241bb77 100644 --- a/samples/subsys/bindesc/hello_bindesc/sample.yaml +++ b/samples/subsys/bindesc/hello_bindesc/sample.yaml @@ -5,4 +5,16 @@ tests: tags: bindesc filter: CONFIG_ARCH_SUPPORTS_ROM_START or CONFIG_ARCH_POSIX integration_platforms: - - native_posix + - native_sim + harness: console + harness_config: + type: multi_line + ordered: true + regex: + - "Zephyr version: " + - "App version: 1.0.0" + - "Build time: " + - "Compiler: " + - "my_string: Hello world!" + - "my_int: 5" + - "my_bytes: 01 02 03 04" From 0b3a7bc7d4b7c1e242956b67449fca933444a4e4 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 11:26:22 +0100 Subject: [PATCH 0724/1049] tests/ztest/fail: Fix build for native_sim The final executable output from the native_sim (or native_posix) build is zephyr.exe (in native_posix zephyr.elf happened to be just a copy of the exe, but in native_sim it is an intermediate build step) So we need to use the exe instead. Note: As the exe is generated with a custom target, we need to install it using install(FILES), which also requires the destination and permissions to be listed manually. The permissions set are just the cmake default permissions for install(PROGRAMS). Signed-off-by: Alberto Escolar Piedras --- tests/ztest/fail/CMakeLists.txt | 4 ++-- tests/ztest/fail/core/CMakeLists.txt | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/ztest/fail/CMakeLists.txt b/tests/ztest/fail/CMakeLists.txt index f7a070377740f25..c4a88639433f51e 100644 --- a/tests/ztest/fail/CMakeLists.txt +++ b/tests/ztest/fail/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.20.0) include(ExternalProject) -# Add the sources and set up the build for either unit testing or native_posix +# Add the sources and set up the build for either unit testing or native_sim list(APPEND SOURCES src/main.cpp) if(BOARD STREQUAL unit_testing) find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE}) @@ -17,7 +17,7 @@ else() set(target app) # Set the target binary for the 'core' external project. The path to this must match the one set # below in ExternalProject_Add's CMAKE_INSTALL_PREFIX - add_compile_definitions(FAIL_TARGET_BINARY="${CMAKE_BINARY_DIR}/core/bin/zephyr.elf") + add_compile_definitions(FAIL_TARGET_BINARY="${CMAKE_BINARY_DIR}/core/bin/zephyr.exe") endif() # Create the project and set the sources for the target diff --git a/tests/ztest/fail/core/CMakeLists.txt b/tests/ztest/fail/core/CMakeLists.txt index cf56362b9ee9516..7ba86d28082d9c6 100644 --- a/tests/ztest/fail/core/CMakeLists.txt +++ b/tests/ztest/fail/core/CMakeLists.txt @@ -35,5 +35,9 @@ else() target_sources(app PRIVATE ${SOURCES}) target_include_directories(app PRIVATE include) - install(TARGETS ${logical_target_for_zephyr_elf}) + install(FILES ${APPLICATION_BINARY_DIR}/zephyr/${KERNEL_EXE_NAME} + DESTINATION bin/ + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ + WORLD_EXECUTE WORLD_READ + ) endif() From 641784cd59c07ba2c9deb294e8f3e5f2810b7dc7 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 11:38:39 +0100 Subject: [PATCH 0725/1049] tests/ztest/fail: Replace native_posix with native_sim In the docs replace references to native_posix with native_sim Switch the default test platform to native_sim from native_posix Signed-off-by: Alberto Escolar Piedras --- doc/develop/test/ztest.rst | 2 ++ tests/ztest/fail/README.rst | 5 +++-- tests/ztest/fail/testcase.yaml | 7 ++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/doc/develop/test/ztest.rst b/doc/develop/test/ztest.rst index c7d3d23911e92c5..f9255ecad2a7e59 100644 --- a/doc/develop/test/ztest.rst +++ b/doc/develop/test/ztest.rst @@ -340,6 +340,8 @@ it needs to report either a pass or fail. For example: ZTEST_SUITE(common, NULL, NULL, NULL, NULL, NULL); +.. _ztest_unit_testing: + Quick start - Unit testing ************************** diff --git a/tests/ztest/fail/README.rst b/tests/ztest/fail/README.rst index 3ed70d5229a5b3e..ab5788ba821af93 100644 --- a/tests/ztest/fail/README.rst +++ b/tests/ztest/fail/README.rst @@ -7,8 +7,9 @@ Overview ******** In order to test the actual framework's failure cases, this test suite has to do something unique. -There's a subdirectory to this test called 'core'. This project builds a sample ``native_posix`` or -``unit_testing`` binary which is expected to fail by calling one of the following: +There's a subdirectory to this test called 'core'. This project builds a sample as a +:ref:`native_sim ` or `:ref:unit_testing ` +binary which is expected to fail by calling one of the following: - ``ztest_test_fail()`` during either the ``after`` or ``teardown`` phase of the test suite - ``ztest_test_skip()`` during either the ``after`` or ``teardown`` phase of the test suite - ``ztest_test_pass()`` during either the ``after`` or ``teardown`` phase of the test suite diff --git a/tests/ztest/fail/testcase.yaml b/tests/ztest/fail/testcase.yaml index 5295847a0cb9315..2a0820fa85eaa36 100644 --- a/tests/ztest/fail/testcase.yaml +++ b/tests/ztest/fail/testcase.yaml @@ -5,7 +5,12 @@ common: tags: - test_framework # test has dependencies on host libc - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + - native_sim_64 + integration_platforms: + - native_sim tests: testing.fail.unit.assert_after: extra_configs: From 0d1045e0936980e9ef4b0c85e66c041e15580e0c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 11:39:38 +0100 Subject: [PATCH 0726/1049] tests/ztest: Swap native_posix with native_sim Switch the default test platform to native_sim from native_posix Signed-off-by: Alberto Escolar Piedras --- tests/ztest/base/testcase.yaml | 13 +++++++++---- tests/ztest/zexpect/testcase.yaml | 6 ++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/ztest/base/testcase.yaml b/tests/ztest/base/testcase.yaml index 4ac55a1dc55588b..ee566d5dd8a5d2e 100644 --- a/tests/ztest/base/testcase.yaml +++ b/tests/ztest/base/testcase.yaml @@ -6,11 +6,16 @@ tests: type: unit testing.ztest.base.cpp: extra_args: CONF_FILE=prj_cpp.conf - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + - native_sim_64 + integration_platforms: + - native_sim testing.ztest.base.verbose_0: extra_args: CONF_FILE=prj_verbose_0.conf integration_platforms: - - native_posix + - native_sim testing.ztest.base.verbose_0_userspace: filter: CONFIG_USERSPACE extra_args: CONF_FILE=prj_verbose_0.conf @@ -23,8 +28,8 @@ tests: testing.ztest.base.verbose_1: extra_args: CONF_FILE=prj_verbose_1.conf integration_platforms: - - native_posix + - native_sim testing.ztest.base.verbose_2: extra_args: CONF_FILE=prj_verbose_2.conf integration_platforms: - - native_posix + - native_sim diff --git a/tests/ztest/zexpect/testcase.yaml b/tests/ztest/zexpect/testcase.yaml index f2679fb9a6f19a4..6928a5f4198efe7 100644 --- a/tests/ztest/zexpect/testcase.yaml +++ b/tests/ztest/zexpect/testcase.yaml @@ -3,17 +3,15 @@ common: integration_platforms: - - native_posix + - native_sim tags: - test_framework tests: testing.ztest.expect: integration_platforms: - - native_posix + - native_sim testing.ztest.expect_cpp: extra_configs: - CONFIG_CPLUSPLUS=y - integration_platforms: - - native_posix testing.ztest.expect.unit: type: unit From 39bf042086366e67886b4e282a8ab83c2c598aaf Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 12:34:15 +0100 Subject: [PATCH 0727/1049] samples/subsys/pm/latency: Switch to native_sim Switch from native_posix to native_sim as default test platform. Signed-off-by: Alberto Escolar Piedras --- .../pm/latency/boards/native_posix.overlay | 32 +------------------ .../pm/latency/boards/native_sim.overlay | 31 ++++++++++++++++++ samples/subsys/pm/latency/sample.yaml | 6 ++-- 3 files changed, 36 insertions(+), 33 deletions(-) create mode 100644 samples/subsys/pm/latency/boards/native_sim.overlay diff --git a/samples/subsys/pm/latency/boards/native_posix.overlay b/samples/subsys/pm/latency/boards/native_posix.overlay index c718cbdd1ffc2cd..6a3daca3241ac6e 100644 --- a/samples/subsys/pm/latency/boards/native_posix.overlay +++ b/samples/subsys/pm/latency/boards/native_posix.overlay @@ -1,31 +1 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * SPDX-License-Identifier: Apache-2.0 - */ - -/ { - power-states { - runtime_idle: runtime-idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - min-residency-us = <1000000>; - exit-latency-us = <10000>; - }; - suspend_to_idle: suspend-to-idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1100000>; - exit-latency-us = <20000>; - }; - standby: standby { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <1200000>; - exit-latency-us = <30000>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&runtime_idle &suspend_to_idle &standby>; -}; +#include "native_sim.overlay" diff --git a/samples/subsys/pm/latency/boards/native_sim.overlay b/samples/subsys/pm/latency/boards/native_sim.overlay new file mode 100644 index 000000000000000..c718cbdd1ffc2cd --- /dev/null +++ b/samples/subsys/pm/latency/boards/native_sim.overlay @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + power-states { + runtime_idle: runtime-idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <1000000>; + exit-latency-us = <10000>; + }; + suspend_to_idle: suspend-to-idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1100000>; + exit-latency-us = <20000>; + }; + standby: standby { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <1200000>; + exit-latency-us = <30000>; + }; + }; +}; + +&cpu0 { + cpu-power-states = <&runtime_idle &suspend_to_idle &standby>; +}; diff --git a/samples/subsys/pm/latency/sample.yaml b/samples/subsys/pm/latency/sample.yaml index 4989a63dbe78e2b..2d6f68879c34cef 100644 --- a/samples/subsys/pm/latency/sample.yaml +++ b/samples/subsys/pm/latency/sample.yaml @@ -2,9 +2,11 @@ sample: name: Demonstrate usage of the PM policy latency APIs tests: sample.pm.latency: - platform_allow: native_posix - integration_platforms: + platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim tags: pm harness: console harness_config: From cb270a7ecfc410aebde38f75dd1544ea01d56f1e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 12:36:02 +0100 Subject: [PATCH 0728/1049] samples canbus: Add native_sim to platform_allow Add native_sim in these samples platform_allow filtering. Signed-off-by: Alberto Escolar Piedras --- samples/subsys/canbus/isotp/sample.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/subsys/canbus/isotp/sample.yaml b/samples/subsys/canbus/isotp/sample.yaml index 9bb24251656cdac..0036552b67b10d9 100644 --- a/samples/subsys/canbus/isotp/sample.yaml +++ b/samples/subsys/canbus/isotp/sample.yaml @@ -25,6 +25,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 harness: console harness_config: type: one_line From 33a36df60b0e65d7f8595ef26eca072c1b0887d9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 12:46:12 +0100 Subject: [PATCH 0729/1049] samples/subsys/settings: Switch from native_posix to native_sim Switch from native_posix to native_sim as default test platform Add conf and DT overlays for native_sim. Signed-off-by: Alberto Escolar Piedras --- .../settings/boards/native_posix.overlay | 23 +------------------ .../settings/boards/native_posix_64.overlay | 23 +------------------ .../subsys/settings/boards/native_sim.conf | 5 ++++ .../subsys/settings/boards/native_sim.overlay | 22 ++++++++++++++++++ .../subsys/settings/boards/native_sim_64.conf | 5 ++++ .../settings/boards/native_sim_64.overlay | 1 + samples/subsys/settings/sample.yaml | 4 +++- 7 files changed, 38 insertions(+), 45 deletions(-) create mode 100644 samples/subsys/settings/boards/native_sim.conf create mode 100644 samples/subsys/settings/boards/native_sim.overlay create mode 100644 samples/subsys/settings/boards/native_sim_64.conf create mode 100644 samples/subsys/settings/boards/native_sim_64.overlay diff --git a/samples/subsys/settings/boards/native_posix.overlay b/samples/subsys/settings/boards/native_posix.overlay index 0e4839ad0265855..6a3daca3241ac6e 100644 --- a/samples/subsys/settings/boards/native_posix.overlay +++ b/samples/subsys/settings/boards/native_posix.overlay @@ -1,22 +1 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &storage_partition; -/delete-node/ &scratch_partition; - -&flash0 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage_partition: partition@70000 { - label = "storage"; - reg = <0x00070000 0x8000>; - }; - }; -}; +#include "native_sim.overlay" diff --git a/samples/subsys/settings/boards/native_posix_64.overlay b/samples/subsys/settings/boards/native_posix_64.overlay index 0e4839ad0265855..6a3daca3241ac6e 100644 --- a/samples/subsys/settings/boards/native_posix_64.overlay +++ b/samples/subsys/settings/boards/native_posix_64.overlay @@ -1,22 +1 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &storage_partition; -/delete-node/ &scratch_partition; - -&flash0 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage_partition: partition@70000 { - label = "storage"; - reg = <0x00070000 0x8000>; - }; - }; -}; +#include "native_sim.overlay" diff --git a/samples/subsys/settings/boards/native_sim.conf b/samples/subsys/settings/boards/native_sim.conf new file mode 100644 index 000000000000000..21877f886f3a7e8 --- /dev/null +++ b/samples/subsys/settings/boards/native_sim.conf @@ -0,0 +1,5 @@ +# Enable the LittleFS file system. +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y +CONFIG_SETTINGS_FILE=y +CONFIG_SETTINGS_FILE_PATH="/ff/settings/run" diff --git a/samples/subsys/settings/boards/native_sim.overlay b/samples/subsys/settings/boards/native_sim.overlay new file mode 100644 index 000000000000000..0e4839ad0265855 --- /dev/null +++ b/samples/subsys/settings/boards/native_sim.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; +/delete-node/ &scratch_partition; + +&flash0 { + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@70000 { + label = "storage"; + reg = <0x00070000 0x8000>; + }; + }; +}; diff --git a/samples/subsys/settings/boards/native_sim_64.conf b/samples/subsys/settings/boards/native_sim_64.conf new file mode 100644 index 000000000000000..21877f886f3a7e8 --- /dev/null +++ b/samples/subsys/settings/boards/native_sim_64.conf @@ -0,0 +1,5 @@ +# Enable the LittleFS file system. +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y +CONFIG_SETTINGS_FILE=y +CONFIG_SETTINGS_FILE_PATH="/ff/settings/run" diff --git a/samples/subsys/settings/boards/native_sim_64.overlay b/samples/subsys/settings/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..6a3daca3241ac6e --- /dev/null +++ b/samples/subsys/settings/boards/native_sim_64.overlay @@ -0,0 +1 @@ +#include "native_sim.overlay" diff --git a/samples/subsys/settings/sample.yaml b/samples/subsys/settings/sample.yaml index 47276f1e6975d3f..2cd51d1405daa16 100644 --- a/samples/subsys/settings/sample.yaml +++ b/samples/subsys/settings/sample.yaml @@ -9,9 +9,11 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: multi_line From ab7682ea06b8d9d6af34bdcbc5892eedd1e242a0 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 14:55:20 +0100 Subject: [PATCH 0730/1049] samples/kernel/metairq_dispatch: Correct comment Clarify comment about why this samples is skipped in posix arch based targets. Signed-off-by: Alberto Escolar Piedras --- samples/kernel/metairq_dispatch/sample.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/kernel/metairq_dispatch/sample.yaml b/samples/kernel/metairq_dispatch/sample.yaml index 201166f7e78c2fb..82090751b33fc59 100644 --- a/samples/kernel/metairq_dispatch/sample.yaml +++ b/samples/kernel/metairq_dispatch/sample.yaml @@ -14,7 +14,7 @@ common: regex: - "MetaIRQ Test Complete" -# Note that native_posix architectures are filtered, they require +# Note that boards based on the POSIX architecture are filtered as they require # instrumentation (e.g. a k_busy_wait()) inside the worker threads # "busy" loops in order for the interrupts to fire on time, and the # sample is designed to demonstrate completely arbitrary CPU work. From 868489b98e495820fb97821434c6cc04059c7846 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 14:57:35 +0100 Subject: [PATCH 0731/1049] samples: Enable any which runs in native_posix also in native_sim Enable the remaining samples which run now in native_posix also in native_sim. Signed-off-by: Alberto Escolar Piedras --- samples/subsys/fs/format/sample.yaml | 2 ++ samples/subsys/fs/littlefs/sample.yaml | 1 + samples/subsys/testsuite/integration/testcase.yaml | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/samples/subsys/fs/format/sample.yaml b/samples/subsys/fs/format/sample.yaml index ca93e00f075c244..aafe86f79891328 100644 --- a/samples/subsys/fs/format/sample.yaml +++ b/samples/subsys/fs/format/sample.yaml @@ -4,12 +4,14 @@ tests: sample.filesystem.format.littlefs: platform_allow: - native_posix + - native_sim - nrf52dk_nrf52832 build_only: true tags: filesystem sample.filesystem.format.fat_fs: platform_allow: - native_posix + - native_sim - mimxrt1064_evk build_only: true extra_args: diff --git a/samples/subsys/fs/littlefs/sample.yaml b/samples/subsys/fs/littlefs/sample.yaml index 6ffbc14d35fd29a..cee428271733cd0 100644 --- a/samples/subsys/fs/littlefs/sample.yaml +++ b/samples/subsys/fs/littlefs/sample.yaml @@ -16,6 +16,7 @@ tests: - mimxrt1064_evk - qemu_x86 - native_posix + - native_sim - mimxrt1160_evk_cm7 - lpcxpresso55s69_cpu0 - mr_canhubk3 diff --git a/samples/subsys/testsuite/integration/testcase.yaml b/samples/subsys/testsuite/integration/testcase.yaml index 8a4c9743b75451a..1cc0ad1c8ee195e 100644 --- a/samples/subsys/testsuite/integration/testcase.yaml +++ b/samples/subsys/testsuite/integration/testcase.yaml @@ -2,7 +2,9 @@ tests: # section.subsection sample.testing.ztest: build_only: true - platform_allow: native_posix - integration_platforms: + platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim tags: test_framework From 196341c18b95ae24f3fbc11d630ad26346284245 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 16 Nov 2023 14:58:47 +0100 Subject: [PATCH 0732/1049] samples: Switch integration_platforms from native_posix to native_sim For all remaining samples which now set their integration platform as native_posix(_64) switch them to native_sim(_64) Signed-off-by: Alberto Escolar Piedras --- samples/application_development/external_lib/sample.yaml | 2 +- samples/drivers/can/babbling/sample.yaml | 2 +- samples/drivers/can/counter/sample.yaml | 2 +- samples/drivers/crypto/sample.yaml | 4 ++-- samples/hello_world/sample.yaml | 2 +- samples/modules/nanopb/sample.yaml | 4 ++-- samples/philosophers/sample.yaml | 2 +- samples/subsys/input/input_dump/sample.yaml | 2 +- samples/subsys/logging/logger/sample.yaml | 2 +- .../subsys/portability/cmsis_rtos_v1/philosophers/sample.yaml | 2 +- .../cmsis_rtos_v1/timer_synchronization/sample.yaml | 2 +- .../subsys/portability/cmsis_rtos_v2/philosophers/sample.yaml | 2 +- .../cmsis_rtos_v2/timer_synchronization/sample.yaml | 2 +- samples/subsys/rtio/sensor_batch_processing/sample.yaml | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/samples/application_development/external_lib/sample.yaml b/samples/application_development/external_lib/sample.yaml index dc06cb4c903ec85..69cbd486e23fcd6 100644 --- a/samples/application_development/external_lib/sample.yaml +++ b/samples/application_development/external_lib/sample.yaml @@ -3,7 +3,7 @@ sample: tests: sample.app_dev.external_lib: integration_platforms: - - native_posix + - native_sim tags: external harness: console harness_config: diff --git a/samples/drivers/can/babbling/sample.yaml b/samples/drivers/can/babbling/sample.yaml index 8a52e4f59cbe1a2..2e7a8320dae254b 100644 --- a/samples/drivers/can/babbling/sample.yaml +++ b/samples/drivers/can/babbling/sample.yaml @@ -6,7 +6,7 @@ tests: depends_on: can filter: dt_chosen_enabled("zephyr,canbus") integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: one_line diff --git a/samples/drivers/can/counter/sample.yaml b/samples/drivers/can/counter/sample.yaml index 20f609d0c367c4a..579fc82a069a4ee 100644 --- a/samples/drivers/can/counter/sample.yaml +++ b/samples/drivers/can/counter/sample.yaml @@ -5,7 +5,7 @@ tests: tags: can depends_on: can integration_platforms: - - native_posix + - native_sim filter: dt_chosen_enabled("zephyr,canbus") and not dt_compat_enabled("kvaser,pcican") harness: console harness_config: diff --git a/samples/drivers/crypto/sample.yaml b/samples/drivers/crypto/sample.yaml index d63e7a4a68ab83e..c969bafa67ce3df 100644 --- a/samples/drivers/crypto/sample.yaml +++ b/samples/drivers/crypto/sample.yaml @@ -12,7 +12,7 @@ tests: harness: console extra_args: EXTRA_CONF_FILE=prj_tinycrypt_shim.conf integration_platforms: - - native_posix + - native_sim harness_config: type: multi_line regex: @@ -26,7 +26,7 @@ tests: harness: console extra_args: EXTRA_CONF_FILE=prj_mtls_shim.conf integration_platforms: - - native_posix + - native_sim harness_config: type: multi_line regex: diff --git a/samples/hello_world/sample.yaml b/samples/hello_world/sample.yaml index 60cbe49360f6b6b..1bcb7db62f25553 100644 --- a/samples/hello_world/sample.yaml +++ b/samples/hello_world/sample.yaml @@ -5,7 +5,7 @@ sample: common: tags: introduction integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: one_line diff --git a/samples/modules/nanopb/sample.yaml b/samples/modules/nanopb/sample.yaml index 2ea497b0f10817d..eb990848d18eea0 100644 --- a/samples/modules/nanopb/sample.yaml +++ b/samples/modules/nanopb/sample.yaml @@ -15,5 +15,5 @@ tests: - samples - nanopb integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 diff --git a/samples/philosophers/sample.yaml b/samples/philosophers/sample.yaml index d072f2c68878fb9..2db2c1563f43930 100644 --- a/samples/philosophers/sample.yaml +++ b/samples/philosophers/sample.yaml @@ -8,7 +8,7 @@ common: harness: console min_ram: 16 integration_platforms: - - native_posix + - native_sim harness_config: type: multi_line ordered: false diff --git a/samples/subsys/input/input_dump/sample.yaml b/samples/subsys/input/input_dump/sample.yaml index 04a867b8a0733ee..1fb4d9d30a971c1 100644 --- a/samples/subsys/input/input_dump/sample.yaml +++ b/samples/subsys/input/input_dump/sample.yaml @@ -5,4 +5,4 @@ tests: tags: input build_only: true integration_platforms: - - native_posix + - native_sim diff --git a/samples/subsys/logging/logger/sample.yaml b/samples/subsys/logging/logger/sample.yaml index 131c9ea9fb5cca0..2364dabd6b40865 100644 --- a/samples/subsys/logging/logger/sample.yaml +++ b/samples/subsys/logging/logger/sample.yaml @@ -4,7 +4,7 @@ sample: tests: sample.logger.basic: integration_platforms: - - native_posix + - native_sim tags: logging harness: console harness_config: diff --git a/samples/subsys/portability/cmsis_rtos_v1/philosophers/sample.yaml b/samples/subsys/portability/cmsis_rtos_v1/philosophers/sample.yaml index 4f4fe6cf366150c..64fd5053d85df7c 100644 --- a/samples/subsys/portability/cmsis_rtos_v1/philosophers/sample.yaml +++ b/samples/subsys/portability/cmsis_rtos_v1/philosophers/sample.yaml @@ -2,7 +2,7 @@ sample: name: CMSIS_RTOS_V1 Dining Philosophers common: integration_platforms: - - native_posix + - native_sim extra_args: DEBUG_PRINTF=1 tags: cmsis_rtos min_ram: 32 diff --git a/samples/subsys/portability/cmsis_rtos_v1/timer_synchronization/sample.yaml b/samples/subsys/portability/cmsis_rtos_v1/timer_synchronization/sample.yaml index 2d8df98d7708f4d..e87d8449938313a 100644 --- a/samples/subsys/portability/cmsis_rtos_v1/timer_synchronization/sample.yaml +++ b/samples/subsys/portability/cmsis_rtos_v1/timer_synchronization/sample.yaml @@ -3,7 +3,7 @@ sample: tests: sample.portability.cmsis_rtos_v1.timer_synchronization: integration_platforms: - - native_posix + - native_sim tags: cmsis_rtos min_ram: 32 min_flash: 34 diff --git a/samples/subsys/portability/cmsis_rtos_v2/philosophers/sample.yaml b/samples/subsys/portability/cmsis_rtos_v2/philosophers/sample.yaml index 5f15a4d1ce0d099..af5a69f0af78948 100644 --- a/samples/subsys/portability/cmsis_rtos_v2/philosophers/sample.yaml +++ b/samples/subsys/portability/cmsis_rtos_v2/philosophers/sample.yaml @@ -2,7 +2,7 @@ sample: name: CMSIS_RTOS_V2 Dining Philosophers common: integration_platforms: - - native_posix + - native_sim extra_args: DEBUG_PRINTF=1 tags: cmsis_rtos min_ram: 32 diff --git a/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/sample.yaml b/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/sample.yaml index 7b7103cfb9e07c7..f4a8ad690cf27f7 100644 --- a/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/sample.yaml +++ b/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/sample.yaml @@ -3,7 +3,7 @@ sample: tests: sample.portability.cmsis_rtos_v2.timer_synchronization: integration_platforms: - - native_posix + - native_sim platform_exclude: - qemu_arc_hs5x # See issue #62405 tags: cmsis_rtos diff --git a/samples/subsys/rtio/sensor_batch_processing/sample.yaml b/samples/subsys/rtio/sensor_batch_processing/sample.yaml index 956af3a567a3863..99732a25574e918 100644 --- a/samples/subsys/rtio/sensor_batch_processing/sample.yaml +++ b/samples/subsys/rtio/sensor_batch_processing/sample.yaml @@ -4,7 +4,7 @@ tests: sample.rtio.sensor_batch_processing: tags: rtio integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: multi_line From 47e09806c804fdb9bb4abfa1523593263b852ab4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 12 Sep 2023 23:46:30 -0700 Subject: [PATCH 0733/1049] lib/os: With CBPRINTF_NANO, picolibc long-long printf isn't required CBPRINTF_FULL_INTEGRAL doesn't happen to explicitly conflict with CBPRINTF_NANO, but when CBPRINTF_NANO is enabled, there's no long long I/O support provided. Allow picolibc long-long I/O support to also be elided when CBPRINTF_NANO is enabled to save similar amounts of space. Signed-off-by: Keith Packard --- lib/os/Kconfig.cbprintf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/os/Kconfig.cbprintf b/lib/os/Kconfig.cbprintf index 93ffa90ca5d7f58..777cd7d9cf6d0ac 100644 --- a/lib/os/Kconfig.cbprintf +++ b/lib/os/Kconfig.cbprintf @@ -31,7 +31,7 @@ choice CBPRINTF_INTEGRAL_CONV # 01: 0% / 0 B (01 / 00) config CBPRINTF_FULL_INTEGRAL bool "Convert the full range of integer values" - select PICOLIBC_IO_LONG_LONG if PICOLIBC + select PICOLIBC_IO_LONG_LONG if PICOLIBC && !CBPRINTF_NANO help Build cbprintf with buffers sized to support converting the full range of all integral and pointer values. From 35e83d20e4f469a5b3899140205ee812c8f2626e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 20 Sep 2023 18:13:38 -0700 Subject: [PATCH 0734/1049] west: Update picolibc to version 1.8.5 Picolibc version 1.8.5 offers additional memory savings and new long-long and minimal printf variants which can be selected from either the SDK or module version of the library. This needed a patch to the Zephyr cmake support bits to enable one of the new picolibc 1.8.5 features. Signed-off-by: Keith Packard --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 3e7d49affecf14a..20c01f426377be1 100644 --- a/west.yml +++ b/west.yml @@ -310,7 +310,7 @@ manifest: - debug - name: picolibc path: modules/lib/picolibc - revision: d07c38ff051386f8e09a143ea0a6c1d6d66dd1d8 + revision: 1a5c603b9f8e228f9459bdafedad15ea28efc700 - name: segger revision: 9d0191285956cef43daf411edc2f1a7788346def path: modules/debug/segger From 5347a834af36e2d01f805a7f4e86932ae5738516 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 12 Sep 2023 23:49:38 -0700 Subject: [PATCH 0735/1049] libc/picolibc: Support picolibc's assert-verbose option This option in picolibc switches the assert macro between a chatty version and one which provides no information at all. This latter mode avoids placing the associated strings in memory. The Zephyr option is PICOLIBC_ASSERT_VERBOSE and it is disable by default. Signed-off-by: Keith Packard --- lib/libc/picolibc/Kconfig | 9 +++++++++ lib/libc/picolibc/libc-hooks.c | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/libc/picolibc/Kconfig b/lib/libc/picolibc/Kconfig index 21c6fc385015f59..6adc9fd0b7197d9 100644 --- a/lib/libc/picolibc/Kconfig +++ b/lib/libc/picolibc/Kconfig @@ -88,6 +88,15 @@ config PICOLIBC_FAST_STRCMP This provides a faster strcmp version even when libc is built in space-optimized mode +config PICOLIBC_ASSERT_VERBOSE + bool "assert provides verbose information" + help + The usual picolibc assert helper, __assert_func, takes file, line, + function and expression information to make the presented message + more helpful. These all require storage in the image. Unselecting + this option eliminates all of that information, making the results + less helpful but also making them consume less memory. + config PICOLIBC_IO_C99_FORMATS bool "support C99 format additions in printf/scanf" default y diff --git a/lib/libc/picolibc/libc-hooks.c b/lib/libc/picolibc/libc-hooks.c index d00b53d1e8ad222..e7539bc5dfe1111 100644 --- a/lib/libc/picolibc/libc-hooks.c +++ b/lib/libc/picolibc/libc-hooks.c @@ -206,6 +206,27 @@ void __retarget_lock_release(_LOCK_T lock) #endif /* CONFIG_MULTITHREADING */ +#ifdef CONFIG_PICOLIBC_ASSERT_VERBOSE + +FUNC_NORETURN void __assert_func(const char *file, int line, + const char *function, const char *expression) +{ + __ASSERT(0, "assertion \"%s\" failed: file \"%s\", line %d%s%s\n", + expression, file, line, + function ? ", function: " : "", function ? function : ""); + CODE_UNREACHABLE; +} + +#else + +FUNC_NORETURN void __assert_no_args(void) +{ + __ASSERT_NO_MSG(0); + CODE_UNREACHABLE; +} + +#endif + /* This function gets called if static buffer overflow detection is enabled on * stdlib side (Picolibc here), in case such an overflow is detected. Picolibc * provides an implementation not suitable for us, so we override it here. From 7a5fcb8c60e2e6ba26704fabc28fe2d4e0106513 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 12 Sep 2023 23:51:33 -0700 Subject: [PATCH 0736/1049] libc/picolibc: Support 'long long' and 'minimal' printf variants Picolibc's 'minimal' printf mode reduces functionality and size even more than the 'integer' mode. Use this where memory is at a premium and where the application knows that it does not require exact printf semantics. 1.8.5 adds two more printf variants, 'long long' and 'minimal'. The 'long long' variant is the same as the 'integer' variant but with long long support enabled. The 'minimal' variant reduces functionality and size even more than the 'integer' mode. Applications can use this where memory is at a premium and where the application does not require exact printf semantics. With these two added variants, the SDK has enough options so that all of the cbprintf modes can be supported with the pre-compiled bits: 1. CBPRINTF_NANO - picolibc's 'minimal' variant 2. CBPRINTF_REDUCED_INTEGRAL - picolibc's 'integer' variant 3. CBPRINTF_FULL_INTEGRAL - picolibc's 'long long' variant 4. CBPRINTF_FB_SUPPORT - picolibc's 'double' variant This patch makes the cbprintf Kconfig values drive the default picolibc variant, disables picolibc variants not capable of supporting the required cbprintf level, but allows applications to select more functionality in picolibc than cbprintf requires. Note that this depends on the SDK including picolibc 1.8.5. Without that, selecting the 'minimal' or 'long long' variant in Zephyr will end up with the default variant from picolibc, which is the full version with floating point support. When using the module things will work as specified. Signed-off-by: Keith Packard --- lib/libc/Kconfig | 1 - lib/libc/picolibc/CMakeLists.txt | 6 +++ lib/libc/picolibc/Kconfig | 66 ++++++++++++++++++++++++++------ lib/os/Kconfig.cbprintf | 3 +- 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index c9678adf2c24fa0..8b71808ff54845b 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -12,7 +12,6 @@ config REQUIRES_FULL_LIBC config REQUIRES_FLOAT_PRINTF bool "Requires floating point support in printf" - select PICOLIBC_IO_FLOAT if PICOLIBC select CBPRINTF_FP_SUPPORT if MINIMAL_LIBC select NEWLIB_LIBC_FLOAT_PRINTF if NEWLIB_LIBC help diff --git a/lib/libc/picolibc/CMakeLists.txt b/lib/libc/picolibc/CMakeLists.txt index 3bbe8128a1f54de..232e4ba8fc10e55 100644 --- a/lib/libc/picolibc/CMakeLists.txt +++ b/lib/libc/picolibc/CMakeLists.txt @@ -17,6 +17,12 @@ if(NOT CONFIG_PICOLIBC_USE_MODULE) if(CONFIG_PICOLIBC_IO_FLOAT) zephyr_compile_definitions(PICOLIBC_DOUBLE_PRINTF_SCANF) zephyr_link_libraries(-DPICOLIBC_DOUBLE_PRINTF_SCANF) + elseif(CONFIG_PICOLIBC_IO_MINIMAL) + zephyr_compile_definitions(PICOLIBC_MINIMAL_PRINTF_SCANF) + zephyr_link_libraries(-DPICOLIBC_MINIMAL_PRINTF_SCANF) + elseif(CONFIG_PICOLIBC_IO_LONG_LONG) + zephyr_compile_definitions(PICOLIBC_LONG_LONG_PRINTF_SCANF) + zephyr_link_libraries(-DPICOLIBC_LONG_LONG_PRINTF_SCANF) else() zephyr_compile_definitions(PICOLIBC_INTEGER_PRINTF_SCANF) zephyr_link_libraries(-DPICOLIBC_INTEGER_PRINTF_SCANF) diff --git a/lib/libc/picolibc/Kconfig b/lib/libc/picolibc/Kconfig index 6adc9fd0b7197d9..fa6ae7e6e9ba592 100644 --- a/lib/libc/picolibc/Kconfig +++ b/lib/libc/picolibc/Kconfig @@ -31,16 +31,42 @@ config PICOLIBC_HEAP_SIZE If set to -2, then the value of COMMON_LIBC_MALLOC_ARENA_SIZE will be used. -config PICOLIBC_IO_LONG_LONG - bool "support for long long in integer-only printf/scanf" +choice PICOLIBC_IO_LEVEL + prompt "Picolibc printf/scanf level" + default PICOLIBC_IO_MINIMAL if CBPRINTF_NANO + default PICOLIBC_IO_LONG_LONG if CBPRINTF_FULL_INTEGRAL + default PICOLIBC_IO_INTEGER help - Includes support for long long in integer-only printf/scanf. long long - types are always supported in the floating-point versions. + Selects the level of printf and scanf support config PICOLIBC_IO_FLOAT - bool "support for floating point values in printf/scanf" + bool "full support for integer/floating point values in printf/scanf" + help + Include full floating point and integer support in printf/scanf + functions. + +config PICOLIBC_IO_LONG_LONG + bool "full support for integer values, including long long, in printf/scanf" + depends on !REQUIRES_FLOAT_PRINTF && (!CBPRINTF_FP_SUPPORT || CBPRINTF_NANO) + help + Includes full integer with long long, but no floating + point in printf/scanf. + +config PICOLIBC_IO_INTEGER + bool "full support for integer values, other than long long, in printf/scanf" + depends on !REQUIRES_FLOAT_PRINTF && ((!CBPRINTF_FP_SUPPORT && !CBPRINTF_FULL_INTEGRAL) || CBPRINTF_NANO) + help + Include full integer other than long long, but no floating point + in printf/scanf. + +config PICOLIBC_IO_MINIMAL + bool "limited support for integer values in printf/scanf" + depends on !REQUIRES_FLOAT_PRINTF && CBPRINTF_NANO help - Include floating point support in printf/scanf functions. + Include limited integer and no floating point support in + printf/scanf. + +endchoice if PICOLIBC_USE_MODULE @@ -101,17 +127,18 @@ config PICOLIBC_IO_C99_FORMATS bool "support C99 format additions in printf/scanf" default y help - Includes support for hex floats (in floating-point version) and j, z, - t size modifiers. + Includes C99 printf and scanf support for j, z, t size + modifiers. C99 support is always included in the floating-point + variant config PICOLIBC_IO_POS_ARGS bool "Support POSIX positional args (e.g. %$1d) in printf/scanf" default y - depends on !PICOLIBC_IO_FLOAT + depends on !PICOLIBC_IO_MINIMAL help - Includes support for positional args (e.g. $1) in integer-only printf - and scanf. Positional args are always supported in the floating-point - versions. + Includes support for positional args (e.g. $1) in integer-only + printf and scanf. Positional args are always supported in the + floating-point variant. config PICOLIBC_IO_FLOAT_EXACT bool "support for exact float/string conversion" @@ -121,6 +148,21 @@ config PICOLIBC_IO_FLOAT_EXACT This ensures that printf values with enough digits can be fed to scanf and generate exactly the same binary value. +config PICOLIBC_IO_SMALL_ULTOA + bool "avoid soft division in printf" + default y + help + Replaces division and modulus by 10 with shifts and adds when + doing binary to decimal conversion in printf for 64-bit + values on 32-bit targets. + +config PICOLIBC_IO_MINIMAL_LONG_LONG + bool "Include long long support in minimal printf" + depends on PICOLIBC_IO_MINIMAL + default y if CBPRINTF_FULL_INTEGRAL + help + Include long long support in the minimal picolibc printf code + config PICOLIBC_LOCALE_INFO bool "support locales in libc functions" help diff --git a/lib/os/Kconfig.cbprintf b/lib/os/Kconfig.cbprintf index 777cd7d9cf6d0ac..54ba8ccfa502bb8 100644 --- a/lib/os/Kconfig.cbprintf +++ b/lib/os/Kconfig.cbprintf @@ -31,7 +31,7 @@ choice CBPRINTF_INTEGRAL_CONV # 01: 0% / 0 B (01 / 00) config CBPRINTF_FULL_INTEGRAL bool "Convert the full range of integer values" - select PICOLIBC_IO_LONG_LONG if PICOLIBC && !CBPRINTF_NANO + select PICOLIBC_IO_MINIMAL_LONG_LONG if PICOLIBC_IO_MINIMAL && PICOLIBC_USE_MODULE help Build cbprintf with buffers sized to support converting the full range of all integral and pointer values. @@ -67,7 +67,6 @@ config CBPRINTF_FP_SUPPORT bool "Floating point formatting in cbprintf" default y if FPU depends on CBPRINTF_COMPLETE - select PICOLIBC_IO_FLOAT if PICOLIBC help Build the cbprintf utility function with support for floating point format specifiers. Selecting this increases stack size From d04c834c0fc4d97cb83ca73af9b123700a0c3b63 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 21 Sep 2023 14:34:14 -0700 Subject: [PATCH 0737/1049] tests/kernel: Fix test printk output for new printf variants In minimal mode, format modifiers are not supported, leading to a lack of width and precision support. long long values are presented correctly in either long long or floating mode. Signed-off-by: Keith Packard --- tests/kernel/common/src/printk.c | 71 +++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/tests/kernel/common/src/printk.c b/tests/kernel/common/src/printk.c index 35e91eb960c979a..85a0ccbb4d35b81 100644 --- a/tests/kernel/common/src/printk.c +++ b/tests/kernel/common/src/printk.c @@ -17,16 +17,61 @@ int (*_old_char_out)(int); #if defined(CONFIG_PICOLIBC) +#define ZEPHYR_PICOLIBC_VERSION (__PICOLIBC__ * 10000 + \ + __PICOLIBC_MINOR__ * 100 + \ + __PICOLIBC_PATCHLEVEL__) + +#ifdef CONFIG_PICOLIBC_IO_MINIMAL +/* + * If picolibc is >= 1.8.4, then minimal printf is available. Otherwise, + * we're going to get the floating point version when the minimal one is + * selected. + */ +#if ZEPHYR_PICOLIBC_VERSION >= 10804 +#define HAS_PICOLIBC_IO_MINIMAL +#else +#define HAS_PICOLIBC_IO_FLOAT +#endif +#endif + +#ifdef CONFIG_PICOLIBC_IO_LONG_LONG +/* + * If picolibc is >= 1.8.5, then long long printf is available. Otherwise, + * we're going to get the floating point version when the long long one is + * selected. + */ +#if ZEPHYR_PICOLIBC_VERSION >= 10805 +#define HAS_PICOLIBC_IO_LONG_LONG +#else +#define HAS_PICOLIBC_IO_FLOAT +#endif +#endif + +#ifdef CONFIG_PICOLIBC_IO_FLOAT +#define HAS_PICOLIBC_IO_FLOAT +#endif + /* - * Picolibc long long support is present if the picolibc _WANT_IO_LONG_LONG - * symbol is defined or if the Zephyr configuration has enabled floating - * point support. Note that CONFIG_PICOLIBC_IO_LONG_LONG is only useful - * when using the picolibc module as it cannot affect picolibc included - * with the toolchain + * Picolibc long long support is present if Zephyr configuration has + * enabled long long or floating point support. */ char expected_32[] = "22 113 10000 32768 40000 22\n" "p 112 -10000 -32768 -40000 -22\n" +#if defined(HAS_PICOLIBC_IO_MINIMAL) + "0x1 0x1 0x1 0x1 0x1\n" + "0x1 0x1 0x1 0x1\n" + "42 42 42 42\n" + "-42 -42 -42 -42\n" + "42 42 42 42\n" + "42 42 42 42\n" + "25542abcdef 42\n" +#if defined(_WANT_MINIMAL_IO_LONG_LONG) + "68719476735 -1 18446744073709551615 ffffffffffffffff\n" +#else + "-1 -1 4294967295 ffffffff\n" +#endif +#else "0x1 0x01 0x0001 0x00000001 0x0000000000000001\n" "0x1 0x 1 0x 1 0x 1\n" "42 42 0042 00000042\n" @@ -34,15 +79,26 @@ char expected_32[] = "22 113 10000 32768 40000 22\n" "42 42 42 42\n" "42 42 0042 00000042\n" "255 42 abcdef 42\n" -#if defined(_WANT_IO_LONG_LONG) || defined(CONFIG_PICOLIBC_IO_FLOAT) +#if defined(HAS_PICOLIBC_IO_LONG_LONG) || defined(HAS_PICOLIBC_IO_FLOAT) "68719476735 -1 18446744073709551615 ffffffffffffffff\n" #else "-1 -1 4294967295 ffffffff\n" +#endif #endif "0xcafebabe 0xbeef 0x2a\n" ; + char expected_64[] = "22 113 10000 32768 40000 22\n" "p 112 -10000 -32768 -40000 -22\n" +#if defined(HAS_PICOLIBC_IO_MINIMAL) + "0x1 0x1 0x1 0x1 0x1\n" + "0x1 0x1 0x1 0x1\n" + "42 42 42 42\n" + "-42 -42 -42 -42\n" + "42 42 42 42\n" + "42 42 42 42\n" + "25542abcdef 42\n" +#else "0x1 0x01 0x0001 0x00000001 0x0000000000000001\n" "0x1 0x 1 0x 1 0x 1\n" "42 42 0042 00000042\n" @@ -50,6 +106,7 @@ char expected_64[] = "22 113 10000 32768 40000 22\n" "42 42 42 42\n" "42 42 0042 00000042\n" "255 42 abcdef 42\n" +#endif "68719476735 -1 18446744073709551615 ffffffffffffffff\n" "0xcafebabe 0xbeef 0x2a\n" ; @@ -161,6 +218,8 @@ ZTEST(printk, test_printk) printk("0x%x %p %-2p\n", hex, ptr, (char *)42); pk_console[pos] = '\0'; + __printk_hook_install(_old_char_out); + printk("expected '%s'\n", expected); zassert_true((strcmp(pk_console, expected) == 0), "printk failed"); (void)memset(pk_console, 0, sizeof(pk_console)); From 6c95f23d81e6256c42c5afd20e3076e8a8dd5ce2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 27 Sep 2023 10:25:50 -0700 Subject: [PATCH 0738/1049] samples/code_relocation_nocopy: Increase fake flash size When linking with the 0.16.3 SDK version of picolibc, using long long cbprintf support pulls in the full floating point printf which is much larger than the integer-only version. This ends up overflowing the memory region available for it. Increase the size of that by bumping the start of the fake region by 8kB. Signed-off-by: Keith Packard --- .../code_relocation_nocopy/linker_arm_nocopy.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld index 916b1efe7fa6956..7ead7f6bae48314 100644 --- a/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld +++ b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld @@ -32,7 +32,7 @@ * Add another fake portion of FLASH to simulate a secondary or external FLASH * that we can do XIP from. */ -#define EXTFLASH_ADDR 0x5000 +#define EXTFLASH_ADDR 0x7000 #define EXTFLASH_SIZE (CONFIG_FLASH_SIZE * 1K - EXTFLASH_ADDR) #endif From a4a8120b6992bb671b15e22b55301dd39feb6371 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 20 Sep 2023 22:06:27 -0700 Subject: [PATCH 0739/1049] doc: Update picolibc section in 3.5 migration guide for 1.8.5 Picolibc 1.8.5 includes more control over printf capabilities, document those in the migration guide. Signed-off-by: Keith Packard --- doc/releases/migration-guide-3.5.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/releases/migration-guide-3.5.rst b/doc/releases/migration-guide-3.5.rst index d9b81c621067865..cda3602f19f5f3b 100644 --- a/doc/releases/migration-guide-3.5.rst +++ b/doc/releases/migration-guide-3.5.rst @@ -70,6 +70,16 @@ C Library compiler will now warn about declarations of `main` which don't conform to the Zephyr required type -- ``int main(void)``. + * Picolibc has four different printf/scanf variants supported in Zephyr, + 'double', 'long long', 'integer', and 'minimal. 'double' offers a + complete printf implementation with exact floating point in decimal and + hexidecimal formats, full integer support including long long, C99 + integer size specifiers (j, z, t) and POSIX positional arguments. 'long + long' mode removes float support, 'integer' removes long long support + while 'minimal' mode also removes support for format modifiers and + positional arguments. Building the library as a module allows finer + control over the feature set provided at each level. + * Picolibc's default floating point input/output code is larger than the minimal C library version (this is necessary to conform with the C language "round trip" requirements for these operations). If you use From 8e4c588eab9828e99ca0bf696982c1275bb13229 Mon Sep 17 00:00:00 2001 From: Henning Fleddermann Date: Tue, 19 Sep 2023 14:00:41 +0200 Subject: [PATCH 0740/1049] net: lib: lwm2m: Use int16_t for signal quality RSRQ is the ratio between send and received signal strength and usually understood/expected to be represented as a ratio in dB and as such always has a negative range. So to allow RSRQ to be represented correctly the resource must allow negative values, but currently it's limited to unsigned 8bit integers. Signed-off-by: Henning Fleddermann --- subsys/net/lib/lwm2m/lwm2m_obj_connmon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c b/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c index acdd33ee21edc97..70309a0d3d68777 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c @@ -93,7 +93,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); /* resource state variables */ static int8_t net_bearer; static int16_t rss; -static uint8_t link_quality; +static int16_t link_quality; static uint32_t cellid; static uint16_t mnc; static uint16_t mcc; @@ -113,7 +113,7 @@ static struct lwm2m_engine_obj_field fields[] = { OBJ_FIELD_DATA(CONNMON_NETWORK_BEARER_ID, R, U8), OBJ_FIELD_DATA(CONNMON_AVAIL_NETWORK_BEARER_ID, R, U8), OBJ_FIELD_DATA(CONNMON_RADIO_SIGNAL_STRENGTH, R, S16), - OBJ_FIELD_DATA(CONNMON_LINK_QUALITY, R, U8), + OBJ_FIELD_DATA(CONNMON_LINK_QUALITY, R, S16), OBJ_FIELD_DATA(CONNMON_IP_ADDRESSES, R, STRING), OBJ_FIELD_DATA(CONNMON_ROUTER_IP_ADDRESSES, R_OPT, STRING), OBJ_FIELD_DATA(CONNMON_LINK_UTILIZATION, R_OPT, U8), From 6f91fd858cea07655928c3920539acb1c1646235 Mon Sep 17 00:00:00 2001 From: Franciszek Zdobylak Date: Tue, 3 Oct 2023 10:37:10 +0200 Subject: [PATCH 0741/1049] dts: arm: silabs: Configure hfxo in dtsi This commit moves configuration of hfxo from headers defined on board level to device trees of SoCs. Signed-off-by: Franciszek Zdobylak --- boards/arm/efr32_radio/CMakeLists.txt | 2 -- boards/arm/efr32_thunderboard/CMakeLists.txt | 2 -- .../sl_device_init_hfxo_config.h | 14 -------------- boards/arm/efr32xg24_dk2601b/CMakeLists.txt | 5 ----- .../efr32xg24_dk2601b/sl_device_init_hfxo_config.h | 14 -------------- dts/arm/silabs/efr32bg2x.dtsi | 10 ++++++++++ dts/arm/silabs/efr32mg24.dtsi | 10 ++++++++++ dts/bindings/clock/silabs,hfxo.yaml | 9 +++++++++ .../common}/sl_device_init_hfxo_config.h | 8 +++----- 9 files changed, 32 insertions(+), 42 deletions(-) delete mode 100644 boards/arm/efr32_radio/CMakeLists.txt delete mode 100644 boards/arm/efr32_thunderboard/sl_device_init_hfxo_config.h delete mode 100644 boards/arm/efr32xg24_dk2601b/CMakeLists.txt delete mode 100644 boards/arm/efr32xg24_dk2601b/sl_device_init_hfxo_config.h create mode 100644 dts/bindings/clock/silabs,hfxo.yaml rename {boards/arm/efr32_radio => soc/arm/silabs_exx32/common}/sl_device_init_hfxo_config.h (58%) diff --git a/boards/arm/efr32_radio/CMakeLists.txt b/boards/arm/efr32_radio/CMakeLists.txt deleted file mode 100644 index 77a7880c491c312..000000000000000 --- a/boards/arm/efr32_radio/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -zephyr_include_directories(.) diff --git a/boards/arm/efr32_thunderboard/CMakeLists.txt b/boards/arm/efr32_thunderboard/CMakeLists.txt index 17faf560addbbd6..ca93e65ac913abb 100644 --- a/boards/arm/efr32_thunderboard/CMakeLists.txt +++ b/boards/arm/efr32_thunderboard/CMakeLists.txt @@ -5,5 +5,3 @@ if(CONFIG_UART_GECKO) zephyr_library() zephyr_library_sources(board.c) endif() - -zephyr_include_directories(.) diff --git a/boards/arm/efr32_thunderboard/sl_device_init_hfxo_config.h b/boards/arm/efr32_thunderboard/sl_device_init_hfxo_config.h deleted file mode 100644 index 1b803c74f3d6154..000000000000000 --- a/boards/arm/efr32_thunderboard/sl_device_init_hfxo_config.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2022 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef SL_DEVICE_INIT_HFXO_CONFIG_H -#define SL_DEVICE_INIT_HFXO_CONFIG_H - -#define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal -#define SL_DEVICE_INIT_HFXO_FREQ 38400000 -#define SL_DEVICE_INIT_HFXO_CTUNE 120 - -#endif /* SL_DEVICE_INIT_HFXO_CONFIG_H */ diff --git a/boards/arm/efr32xg24_dk2601b/CMakeLists.txt b/boards/arm/efr32xg24_dk2601b/CMakeLists.txt deleted file mode 100644 index 7997d6923796dee..000000000000000 --- a/boards/arm/efr32xg24_dk2601b/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021 Sateesh Kotapati -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() -zephyr_library_sources(board.c) diff --git a/boards/arm/efr32xg24_dk2601b/sl_device_init_hfxo_config.h b/boards/arm/efr32xg24_dk2601b/sl_device_init_hfxo_config.h deleted file mode 100644 index 7f9e211748ee1a0..000000000000000 --- a/boards/arm/efr32xg24_dk2601b/sl_device_init_hfxo_config.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2023 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef SL_DEVICE_INIT_HFXO_CONFIG_H -#define SL_DEVICE_INIT_HFXO_CONFIG_H - -#define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal -#define SL_DEVICE_INIT_HFXO_FREQ 39000000 -#define SL_DEVICE_INIT_HFXO_CTUNE 140 - -#endif /* SL_DEVICE_INIT_HFXO_CONFIG_H */ diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index e1f3726e4297670..5202acd350ac92a 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include / { chosen { @@ -17,6 +18,15 @@ zephyr,entropy = &trng; }; + clocks { + clk_hfxo: clk-hfxo { + #clock-cells = <0>; + compatible = "silabs,hfxo"; + clock-frequency = ; + ctune = <120>; + }; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/silabs/efr32mg24.dtsi b/dts/arm/silabs/efr32mg24.dtsi index 1ee015b7334c94f..b42b775397fe6fd 100644 --- a/dts/arm/silabs/efr32mg24.dtsi +++ b/dts/arm/silabs/efr32mg24.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include / { chosen { @@ -17,6 +18,15 @@ zephyr,entropy = &se; }; + clocks { + clk_hfxo: clk-hfxo { + #clock-cells = <0>; + compatible = "silabs,hfxo"; + clock-frequency = ; + ctune = <140>; + }; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/dts/bindings/clock/silabs,hfxo.yaml b/dts/bindings/clock/silabs,hfxo.yaml new file mode 100644 index 000000000000000..cd0d3ad17426d4c --- /dev/null +++ b/dts/bindings/clock/silabs,hfxo.yaml @@ -0,0 +1,9 @@ +compatible: "silabs,hfxo" + +include: fixed-clock.yaml + +properties: + ctune: + type: int + required: true + description: Load capacitance configuration diff --git a/boards/arm/efr32_radio/sl_device_init_hfxo_config.h b/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h similarity index 58% rename from boards/arm/efr32_radio/sl_device_init_hfxo_config.h rename to soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h index c410e7c40935523..533a591fbde71a7 100644 --- a/boards/arm/efr32_radio/sl_device_init_hfxo_config.h +++ b/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h @@ -7,12 +7,10 @@ #ifndef SL_DEVICE_INIT_HFXO_CONFIG_H #define SL_DEVICE_INIT_HFXO_CONFIG_H -#ifdef CONFIG_BOARD_EFR32_RADIO_BRD4187C +#include #define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal -#define SL_DEVICE_INIT_HFXO_FREQ 39000000 -#define SL_DEVICE_INIT_HFXO_CTUNE 140 - -#endif /* CONFIG_BOARD_EFR32_RADIO_BRD4187C */ +#define SL_DEVICE_INIT_HFXO_FREQ DT_PROP(DT_NODELABEL(clk_hfxo), clock_frequency) +#define SL_DEVICE_INIT_HFXO_CTUNE DT_PROP(DT_NODELABEL(clk_hfxo), ctune) #endif /* SL_DEVICE_INIT_HFXO_CONFIG_H */ From 1d01f5c6b9bd82f90be91f3b40e4d5ffe7002d08 Mon Sep 17 00:00:00 2001 From: Franciszek Zdobylak Date: Mon, 16 Oct 2023 12:08:03 +0200 Subject: [PATCH 0742/1049] dts: arm: silabs: Move gpio gecko header include Move the include to places where it is actually used. Signed-off-by: Franciszek Zdobylak --- boards/arm/efr32_thunderboard/thunderboard.dtsi | 1 + dts/arm/silabs/efr32bg2x-pinctrl.dtsi | 1 + dts/arm/silabs/efr32bg2x.dtsi | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/boards/arm/efr32_thunderboard/thunderboard.dtsi b/boards/arm/efr32_thunderboard/thunderboard.dtsi index 31387b876098ca4..be2401138ada690 100644 --- a/boards/arm/efr32_thunderboard/thunderboard.dtsi +++ b/boards/arm/efr32_thunderboard/thunderboard.dtsi @@ -5,6 +5,7 @@ */ #include +#include / { chosen { diff --git a/dts/arm/silabs/efr32bg2x-pinctrl.dtsi b/dts/arm/silabs/efr32bg2x-pinctrl.dtsi index 388423e10d057bd..fb5fc1b8484083d 100644 --- a/dts/arm/silabs/efr32bg2x-pinctrl.dtsi +++ b/dts/arm/silabs/efr32bg2x-pinctrl.dtsi @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include &pinctrl { diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index 5202acd350ac92a..2f50f1bcbda8e83 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -5,7 +5,6 @@ */ #include -#include #include #include #include From 7cf2b0fc9dfe395c002df6a6e13b93062a4d68ab Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 13 Nov 2023 10:55:46 +0100 Subject: [PATCH 0743/1049] modem: backend: uart_async: Extend "closed" requisites The current implementation only waits for the RX disabled event to determine if the UART is closed. It should wait for all RX buffers to be released, and the TX to be done as well. We now also call uart_tx_abort() when closing the pipe. Signed-off-by: Bjarki Arge Andreasen --- .../modem/backends/modem_backend_uart_async.c | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/subsys/modem/backends/modem_backend_uart_async.c b/subsys/modem/backends/modem_backend_uart_async.c index 9c4e904ef9e3390..636f543166f05f8 100644 --- a/subsys/modem/backends/modem_backend_uart_async.c +++ b/subsys/modem/backends/modem_backend_uart_async.c @@ -13,9 +13,10 @@ LOG_MODULE_DECLARE(modem_backend_uart); #include #define MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT (0) -#define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT (1) -#define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT (2) -#define MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT (3) +#define MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT (1) +#define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT (2) +#define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT (3) +#define MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT (4) static void modem_backend_uart_async_flush(struct modem_backend_uart *backend) { @@ -26,6 +27,22 @@ static void modem_backend_uart_async_flush(struct modem_backend_uart *backend) } } +static bool modem_backend_uart_async_is_closed(struct modem_backend_uart *backend) +{ + if (!atomic_test_bit(&backend->async.state, + MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT) && + !atomic_test_bit(&backend->async.state, + MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT) && + !atomic_test_bit(&backend->async.state, + MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT) && + !atomic_test_bit(&backend->async.state, + MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT)) { + return true; + } + + return false; +} + static uint8_t modem_backend_uart_async_rx_rbuf_used_index(struct modem_backend_uart *backend) { return atomic_test_bit(&backend->async.state, @@ -122,7 +139,8 @@ static void modem_backend_uart_async_event_handler(const struct device *dev, break; case UART_RX_DISABLED: - k_work_submit(&backend->async.rx_disabled_work); + atomic_clear_bit(&backend->async.state, + MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT); break; case UART_RX_STOPPED: @@ -132,6 +150,10 @@ static void modem_backend_uart_async_event_handler(const struct device *dev, default: break; } + + if (modem_backend_uart_async_is_closed(backend)) { + k_work_submit(&backend->async.rx_disabled_work); + } } static int modem_backend_uart_async_open(void *data) @@ -159,6 +181,9 @@ static int modem_backend_uart_async_open(void *data) return ret; } + atomic_set_bit(&backend->async.state, + MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT); + modem_pipe_notify_opened(&backend->pipe); return 0; } @@ -229,6 +254,7 @@ static int modem_backend_uart_async_close(void *data) { struct modem_backend_uart *backend = (struct modem_backend_uart *)data; + uart_tx_abort(backend->uart); uart_rx_disable(backend->uart); return 0; } From 6f1d49e7b3a3455599a5a892ae87fce6f4fb9b4e Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 13 Nov 2023 19:15:30 +0100 Subject: [PATCH 0744/1049] modem: backend: uart_async: Use single ring buffer Use single ring buffer and protect it with a spinlock as it is shared between backend and UART thread (ISR). This is simpler than the double ring buffer setup. The receive idle timeout has also been made configurable instead of being a hardcoded value. Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/modem/backend/uart.h | 3 +- subsys/modem/backends/Kconfig | 4 + .../modem/backends/modem_backend_uart_async.c | 77 ++++++------------- 3 files changed, 28 insertions(+), 56 deletions(-) diff --git a/include/zephyr/modem/backend/uart.h b/include/zephyr/modem/backend/uart.h index 1aebe9e2030277f..0ddef4df734d908 100644 --- a/include/zephyr/modem/backend/uart.h +++ b/include/zephyr/modem/backend/uart.h @@ -31,7 +31,8 @@ struct modem_backend_uart_isr { struct modem_backend_uart_async { uint8_t *receive_bufs[2]; uint32_t receive_buf_size; - struct ring_buf receive_rdb[2]; + struct ring_buf receive_rb; + struct k_spinlock receive_rb_lock; uint8_t *transmit_buf; uint32_t transmit_buf_size; struct k_work rx_disabled_work; diff --git a/subsys/modem/backends/Kconfig b/subsys/modem/backends/Kconfig index 417566966a2e952..317f9d26aa8b1de 100644 --- a/subsys/modem/backends/Kconfig +++ b/subsys/modem/backends/Kconfig @@ -28,6 +28,10 @@ config MODEM_BACKEND_UART_ASYNC_TRANSMIT_TIMEOUT_MS int "Modem UART async transmit timeout in milliseconds" default 100 +config MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS + int "Modem UART async receive idle timeout in milliseconds" + default 30 + endif endif # MODEM_BACKEND_UART diff --git a/subsys/modem/backends/modem_backend_uart_async.c b/subsys/modem/backends/modem_backend_uart_async.c index 636f543166f05f8..7c59a749e2e6693 100644 --- a/subsys/modem/backends/modem_backend_uart_async.c +++ b/subsys/modem/backends/modem_backend_uart_async.c @@ -16,7 +16,6 @@ LOG_MODULE_DECLARE(modem_backend_uart); #define MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT (1) #define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT (2) #define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT (3) -#define MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT (4) static void modem_backend_uart_async_flush(struct modem_backend_uart *backend) { @@ -43,31 +42,11 @@ static bool modem_backend_uart_async_is_closed(struct modem_backend_uart *backen return false; } -static uint8_t modem_backend_uart_async_rx_rbuf_used_index(struct modem_backend_uart *backend) -{ - return atomic_test_bit(&backend->async.state, - MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT); -} - -static void modem_backend_uart_async_rx_rbuf_used_swap(struct modem_backend_uart *backend) -{ - uint8_t rx_rbuf_index = modem_backend_uart_async_rx_rbuf_used_index(backend); - - if (rx_rbuf_index) { - atomic_clear_bit(&backend->async.state, - MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT); - } else { - atomic_set_bit(&backend->async.state, - MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT); - } -} - static void modem_backend_uart_async_event_handler(const struct device *dev, struct uart_event *evt, void *user_data) { struct modem_backend_uart *backend = (struct modem_backend_uart *) user_data; - - uint8_t receive_rb_used_index; + k_spinlock_key_t key; uint32_t received; switch (evt->type) { @@ -123,18 +102,19 @@ static void modem_backend_uart_async_event_handler(const struct device *dev, break; case UART_RX_RDY: - receive_rb_used_index = modem_backend_uart_async_rx_rbuf_used_index(backend); - - received = ring_buf_put(&backend->async.receive_rdb[receive_rb_used_index], - &evt->data.rx.buf[evt->data.rx.offset], - evt->data.rx.len); + key = k_spin_lock(&backend->async.receive_rb_lock); + received = ring_buf_put(&backend->async.receive_rb, + &evt->data.rx.buf[evt->data.rx.offset], + evt->data.rx.len); if (received < evt->data.rx.len) { - ring_buf_reset(&backend->async.receive_rdb[receive_rb_used_index]); + ring_buf_reset(&backend->async.receive_rb); + k_spin_unlock(&backend->async.receive_rb_lock, key); LOG_WRN("Receive buffer overrun"); break; } + k_spin_unlock(&backend->async.receive_rb_lock, key); k_work_submit(&backend->receive_ready_work); break; @@ -163,8 +143,7 @@ static int modem_backend_uart_async_open(void *data) atomic_set(&backend->async.state, 0); modem_backend_uart_async_flush(backend); - ring_buf_reset(&backend->async.receive_rdb[0]); - ring_buf_reset(&backend->async.receive_rdb[1]); + ring_buf_reset(&backend->async.receive_rb); /* Reserve receive buffer 0 */ atomic_set_bit(&backend->async.state, @@ -175,7 +154,8 @@ static int modem_backend_uart_async_open(void *data) * used to store received data. */ ret = uart_rx_enable(backend->uart, backend->async.receive_bufs[0], - backend->async.receive_buf_size, 3000); + backend->async.receive_buf_size, + CONFIG_MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS * 1000L); if (ret < 0) { return ret; @@ -224,29 +204,19 @@ static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, siz static int modem_backend_uart_async_receive(void *data, uint8_t *buf, size_t size) { struct modem_backend_uart *backend = (struct modem_backend_uart *)data; - + k_spinlock_key_t key; uint32_t received; - uint8_t receive_rdb_unused; + bool empty; - received = 0; - receive_rdb_unused = modem_backend_uart_async_rx_rbuf_used_index(backend) ? 0 : 1; + key = k_spin_lock(&backend->async.receive_rb_lock); + received = ring_buf_get(&backend->async.receive_rb, buf, size); + empty = ring_buf_is_empty(&backend->async.receive_rb); + k_spin_unlock(&backend->async.receive_rb_lock, key); - /* Read data from unused ring double buffer first */ - received += ring_buf_get(&backend->async.receive_rdb[receive_rdb_unused], buf, size); - - if (ring_buf_is_empty(&backend->async.receive_rdb[receive_rdb_unused]) == false) { - return (int)received; + if (!empty) { + k_work_submit(&backend->receive_ready_work); } - /* Swap receive ring double buffer */ - modem_backend_uart_async_rx_rbuf_used_swap(backend); - - /* Read data from previously used buffer */ - receive_rdb_unused = modem_backend_uart_async_rx_rbuf_used_index(backend) ? 0 : 1; - - received += ring_buf_get(&backend->async.receive_rdb[receive_rdb_unused], - &buf[received], (size - received)); - return (int)received; } @@ -288,18 +258,15 @@ void modem_backend_uart_async_init(struct modem_backend_uart *backend, { uint32_t receive_buf_size_quarter = config->receive_buf_size / 4; - /* Split receive buffer into 4 buffers, use 2 parts for UART receive double buffer */ + /* Use half the receive buffer for UART receive buffers */ backend->async.receive_buf_size = receive_buf_size_quarter; backend->async.receive_bufs[0] = &config->receive_buf[0]; backend->async.receive_bufs[1] = &config->receive_buf[receive_buf_size_quarter]; - /* Use remaining 2 parts for receive double ring buffer */ - ring_buf_init(&backend->async.receive_rdb[0], receive_buf_size_quarter, + /* Use half the receive buffer for the received data ring buffer */ + ring_buf_init(&backend->async.receive_rb, (receive_buf_size_quarter * 2), &config->receive_buf[receive_buf_size_quarter * 2]); - ring_buf_init(&backend->async.receive_rdb[1], receive_buf_size_quarter, - &config->receive_buf[receive_buf_size_quarter * 3]); - backend->async.transmit_buf = config->transmit_buf; backend->async.transmit_buf_size = config->transmit_buf_size; k_work_init(&backend->async.rx_disabled_work, modem_backend_uart_async_notify_closed); From 8128a726a4f1e67cb8bed0da63d3a78a1bed466e Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Tue, 14 Nov 2023 19:28:59 +0100 Subject: [PATCH 0745/1049] modem: backend: uart_async: Remove UART flush The UART flush is not relevant for the async UART implementation. UART drivers should handle this internally. Signed-off-by: Bjarki Arge Andreasen --- subsys/modem/backends/modem_backend_uart_async.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/subsys/modem/backends/modem_backend_uart_async.c b/subsys/modem/backends/modem_backend_uart_async.c index 7c59a749e2e6693..bd18edbd2f5f45a 100644 --- a/subsys/modem/backends/modem_backend_uart_async.c +++ b/subsys/modem/backends/modem_backend_uart_async.c @@ -17,15 +17,6 @@ LOG_MODULE_DECLARE(modem_backend_uart); #define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT (2) #define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT (3) -static void modem_backend_uart_async_flush(struct modem_backend_uart *backend) -{ - uint8_t c; - - while (uart_fifo_read(backend->uart, &c, 1) > 0) { - continue; - } -} - static bool modem_backend_uart_async_is_closed(struct modem_backend_uart *backend) { if (!atomic_test_bit(&backend->async.state, @@ -142,7 +133,6 @@ static int modem_backend_uart_async_open(void *data) int ret; atomic_set(&backend->async.state, 0); - modem_backend_uart_async_flush(backend); ring_buf_reset(&backend->async.receive_rb); /* Reserve receive buffer 0 */ From d3f100355fd299c0b9d01e244a9f02b33780fec9 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Tue, 14 Nov 2023 20:48:23 +0100 Subject: [PATCH 0746/1049] tests: modem: backends: uart: Add UART backend test suite The UART backend test suite performs 9 iterations of: 1. Open UART backend pipe 2. Transmit 8192 bytes of pseudo random data 3. Receive and validate bytes 4. close UART backend pipe The test is run on real hardware, with the TX/RX pins connected to each other to provide loopback functionality. The test suite has been run on a STM32 and an nRF5340 board. The test suite tests both the UART interrupt driven and async APIs. Signed-off-by: Bjarki Arge Andreasen --- .../subsys/modem/backends/uart/CMakeLists.txt | 8 + .../uart/boards/b_u585i_iot02a.overlay | 34 +++ .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 37 +++ tests/subsys/modem/backends/uart/prj.conf | 10 + tests/subsys/modem/backends/uart/src/main.c | 210 ++++++++++++++++++ .../subsys/modem/backends/uart/testcase.yaml | 21 ++ 6 files changed, 320 insertions(+) create mode 100644 tests/subsys/modem/backends/uart/CMakeLists.txt create mode 100644 tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay create mode 100644 tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay create mode 100644 tests/subsys/modem/backends/uart/prj.conf create mode 100644 tests/subsys/modem/backends/uart/src/main.c create mode 100644 tests/subsys/modem/backends/uart/testcase.yaml diff --git a/tests/subsys/modem/backends/uart/CMakeLists.txt b/tests/subsys/modem/backends/uart/CMakeLists.txt new file mode 100644 index 000000000000000..c5e208dfd74067b --- /dev/null +++ b/tests/subsys/modem/backends/uart/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(modem_backend_uart_test) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay b/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay new file mode 100644 index 000000000000000..394facef7bb29c7 --- /dev/null +++ b/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay @@ -0,0 +1,34 @@ +/* + * Pins 2 and 3 must be connected to each other on the STMOD+1 connector to + * loopback RX/TX. + */ + +/ { + aliases { + test-uart = &usart2; + }; +}; + +&gpioh { + misc_fixed_usart2 { + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + +&gpdma1 { + status = "okay"; +}; + +&usart2 { + pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3 &usart2_rts_pa1 &usart2_cts_pa0>; + pinctrl-names = "default"; + current-speed = <115200>; + + dmas = <&gpdma1 0 27 STM32_DMA_PERIPH_TX + &gpdma1 1 26 STM32_DMA_PERIPH_RX>; + dma-names = "tx", "rx"; + + status = "okay"; +}; diff --git a/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay b/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 000000000000000..2d47b0f0744291d --- /dev/null +++ b/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,37 @@ +/* + * Pins P1.10 and P1.11 must be connected to each other to loopback RX/TX. + */ + +/ { + aliases { + test-uart = &uart1; + }; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + hw-flow-control; + pinctrl-names = "default", "sleep"; +}; + +&pinctrl { + uart1_default: uart1_default { + group1 { + psels = ; + }; + group2 { + psels = ; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/tests/subsys/modem/backends/uart/prj.conf b/tests/subsys/modem/backends/uart/prj.conf new file mode 100644 index 000000000000000..fd93accbb08a983 --- /dev/null +++ b/tests/subsys/modem/backends/uart/prj.conf @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MODEM_MODULES=y +CONFIG_MODEM_BACKEND_UART=y +CONFIG_SERIAL=y +CONFIG_ZTEST=y +CONFIG_LOG=y +CONFIG_ZTEST_SHUFFLE=y +CONFIG_ZTEST_SHUFFLE_TEST_REPEAT_COUNT=3 diff --git a/tests/subsys/modem/backends/uart/src/main.c b/tests/subsys/modem/backends/uart/src/main.c new file mode 100644 index 000000000000000..8a6c4c2813a7ab8 --- /dev/null +++ b/tests/subsys/modem/backends/uart/src/main.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This test suite sets up a modem_backend_uart instance connected to a UART which has its + * RX and TX pins wired together to provide loopback functionality. A large number of bytes + * containing a sequence of pseudo random numbers are then transmitted, received, and validated. + * + * The test suite repeats three times, opening and clsoing the modem_pipe attached to the + * modem_backend_uart instance before and after the tests respectively. + */ + +/*************************************************************************************************/ +/* Dependencies */ +/*************************************************************************************************/ +#include +#include +#include +#include + +#include +#include +#include + +/*************************************************************************************************/ +/* Mock pipe */ +/*************************************************************************************************/ +static const struct device *uart = DEVICE_DT_GET(DT_ALIAS(test_uart)); +static struct modem_backend_uart uart_backend; +static struct modem_pipe *pipe; +K_SEM_DEFINE(receive_ready_sem, 0, 1); + +/*************************************************************************************************/ +/* Buffers */ +/*************************************************************************************************/ +static uint8_t backend_receive_buffer[4096]; +static uint8_t backend_transmit_buffer[4096]; +RING_BUF_DECLARE(transmit_ring_buf, 4096); +static uint8_t receive_buffer[4096]; + +/*************************************************************************************************/ +/* Modem pipe callback */ +/*************************************************************************************************/ +static void modem_pipe_callback_handler(struct modem_pipe *pipe, enum modem_pipe_event event, + void *user_data) +{ + switch (event) { + case MODEM_PIPE_EVENT_RECEIVE_READY: + k_sem_give(&receive_ready_sem); + break; + default: + break; + } +} + +/*************************************************************************************************/ +/* Helpers */ +/*************************************************************************************************/ +static uint32_t transmit_prng_state = 1234; +static uint32_t receive_prng_state = 1234; +static uint32_t transmit_size_prng_state; + +static uint8_t transmit_prng_random(void) +{ + transmit_prng_state = ((1103515245 * transmit_prng_state) + 12345) % (1U << 31); + return (uint8_t)(transmit_prng_state & 0xFF); +} + +static uint8_t receive_prng_random(void) +{ + receive_prng_state = ((1103515245 * receive_prng_state) + 12345) % (1U << 31); + return (uint8_t)(receive_prng_state & 0xFF); +} + +static void prng_reset(void) +{ + transmit_prng_state = 1234; + receive_prng_state = 1234; + transmit_size_prng_state = 0; +} + +static void fill_transmit_ring_buf(void) +{ + uint32_t space = ring_buf_space_get(&transmit_ring_buf); + uint8_t data; + + for (uint32_t i = 0; i < space; i++) { + data = transmit_prng_random(); + ring_buf_put(&transmit_ring_buf, &data, 1); + } +} + +static uint32_t transmit_size_prng_random(void) +{ + uint32_t size = 1; + + for (uint8_t i = 0; i < transmit_size_prng_state; i++) { + size = size * 2; + } + + transmit_size_prng_state = transmit_size_prng_state == 11 + ? 0 + : transmit_size_prng_state + 1; + + return size; +} + +static int transmit_prng(uint32_t remaining) +{ + uint8_t *reserved; + uint32_t reserved_size; + uint32_t transmit_size; + int ret; + + fill_transmit_ring_buf(); + reserved_size = ring_buf_get_claim(&transmit_ring_buf, &reserved, UINT32_MAX); + transmit_size = MIN(transmit_size_prng_random(), reserved_size); + transmit_size = MIN(remaining, transmit_size); + ret = modem_pipe_transmit(pipe, reserved, transmit_size); + if (ret < 0) { + return ret; + } + printk("TX: %u,%u\n", transmit_size, (uint32_t)ret); + __ASSERT(ret <= remaining, "Impossible number of bytes sent %u", (uint32_t)ret); + ring_buf_get_finish(&transmit_ring_buf, ret); + return ret; +} + +static int receive_prng(void) +{ + int ret = 0; + + if (k_sem_take(&receive_ready_sem, K_NO_WAIT) == 0) { + ret = modem_pipe_receive(pipe, receive_buffer, sizeof(receive_buffer)); + if (ret < 0) { + return -EFAULT; + } + for (uint32_t i = 0; i < (uint32_t)ret; i++) { + if (receive_prng_random() != receive_buffer[i]) { + return -EFAULT; + } + } + printk("RX: %u\n", (uint32_t)ret); + } + + return ret; +} + +/*************************************************************************************************/ +/* Test setup */ +/*************************************************************************************************/ +static void *test_modem_backend_uart_setup(void) +{ + const struct modem_backend_uart_config config = { + .uart = uart, + .receive_buf = backend_receive_buffer, + .receive_buf_size = 1024, + .transmit_buf = backend_transmit_buffer, + .transmit_buf_size = 1024, + }; + + pipe = modem_backend_uart_init(&uart_backend, &config); + modem_pipe_attach(pipe, modem_pipe_callback_handler, NULL); + return NULL; +} + +static void test_modem_backend_uart_before(void *f) +{ + prng_reset(); + ring_buf_reset(&transmit_ring_buf); + k_sem_reset(&receive_ready_sem); + __ASSERT_NO_MSG(modem_pipe_open(pipe) == 0); +} + +static void test_modem_backend_uart_after(void *f) +{ + __ASSERT_NO_MSG(modem_pipe_close(pipe) == 0); +} + +/*************************************************************************************************/ +/* Tests */ +/*************************************************************************************************/ +ZTEST(modem_backend_uart_suite, test_transmit_receive) +{ + int32_t remaining = 8192; + uint32_t received = 0; + uint32_t transmitted = 0; + int ret; + + while ((remaining != 0) || (received < 8192)) { + ret = transmit_prng(remaining); + zassert(ret > -1, "Failed to transmit data"); + remaining -= (uint32_t)ret; + transmitted += (uint32_t)ret; + printk("TX ACC: %u\n", transmitted); + + while (received < transmitted) { + ret = receive_prng(); + zassert(ret > -1, "Received data is corrupted"); + received += (uint32_t)ret; + k_yield(); + } + } +} + +ZTEST_SUITE(modem_backend_uart_suite, NULL, test_modem_backend_uart_setup, + test_modem_backend_uart_before, test_modem_backend_uart_after, NULL); diff --git a/tests/subsys/modem/backends/uart/testcase.yaml b/tests/subsys/modem/backends/uart/testcase.yaml new file mode 100644 index 000000000000000..626ca639f757baa --- /dev/null +++ b/tests/subsys/modem/backends/uart/testcase.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +tests: + modem.backends.uart.async: + tags: modem_backend + harness: ztest + platform_allow: + - b_u585i_iot02a + - nrf5340dk_nrf5340_cpuapp + extra_configs: + - CONFIG_UART_ASYNC_API=y + + modem.backends.uart.isr: + tags: modem_backend + harness: ztest + platform_allow: + - b_u585i_iot02a + - nrf5340dk_nrf5340_cpuapp + extra_configs: + - CONFIG_UART_INTERRUPT_DRIVEN=y From ad788ad51173c08dc237653df132d500b0e40d26 Mon Sep 17 00:00:00 2001 From: Franciszek Pindel Date: Thu, 12 Oct 2023 12:57:37 +0200 Subject: [PATCH 0747/1049] gecko: pinctrl: Add missing configuration for Gecko Series usarts This commit adds missing pinctrl configuration for USARTs in efm32gg_slwstk6121a, efm32gg_stk3701a and efr32_radio boards and enables PINCTRL for efr32_radio_brd4180a and efr32_radio_brd4187c boards. Signed-off-by: Franciszek Pindel Signed-off-by: Mateusz Holenko --- .../efm32gg_slwstk6121a-pinctrl.dtsi | 19 +++++++++++++ .../efm32gg_slwstk6121a.dts | 5 ++-- .../efm32gg_stk3701a-pinctrl.dtsi | 28 +++++++++++++++++++ .../arm/efm32gg_stk3701a/efm32gg_stk3701a.dts | 9 +++--- .../arm/efr32_radio/efr32_radio-pinctrl.dtsi | 19 +++++++++++++ boards/arm/efr32_radio/efr32_radio.dtsi | 5 ++-- .../efr32_radio_brd4180a_defconfig | 1 + .../efr32_radio_brd4187c_defconfig | 1 + 8 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi create mode 100644 boards/arm/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi create mode 100644 boards/arm/efr32_radio/efr32_radio-pinctrl.dtsi diff --git a/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi b/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi new file mode 100644 index 000000000000000..ade31fddfd824b9 --- /dev/null +++ b/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* configuration for usart0 device, default state - operating as UART */ + usart0_default: usart0_default { + group1 { + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts b/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts index a45d13f7183c26e..10912535b2d197c 100644 --- a/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts +++ b/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts @@ -9,6 +9,7 @@ /dts-v1/; #include #include +#include "efm32gg_slwstk6121a-pinctrl.dtsi" / { model = "Silicon Labs EFM32GG SLWSTK6121A board"; @@ -62,8 +63,8 @@ /* Connected to the WSTK VCOM */ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi new file mode 100644 index 000000000000000..8bb7025f4b2ab88 --- /dev/null +++ b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* configuration for usart0 device, default state - operating as UART */ + usart0_default: usart0_default { + group1 { + psels = , + , + , + ; + }; + }; + + usart4_default: usart4_default { + group1 { + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts index 970cbafa1a2411b..1c457890f9105ba 100644 --- a/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts +++ b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts @@ -8,6 +8,7 @@ /dts-v1/; #include #include +#include "efm32gg_stk3701a-pinctrl.dtsi" / { model = "Silicon Labs EFM32GG STK3701A board"; @@ -60,15 +61,15 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; &usart4 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart4_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/arm/efr32_radio/efr32_radio-pinctrl.dtsi b/boards/arm/efr32_radio/efr32_radio-pinctrl.dtsi new file mode 100644 index 000000000000000..ade31fddfd824b9 --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* configuration for usart0 device, default state - operating as UART */ + usart0_default: usart0_default { + group1 { + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/efr32_radio/efr32_radio.dtsi b/boards/arm/efr32_radio/efr32_radio.dtsi index a82081de469652d..361b66b72df389d 100644 --- a/boards/arm/efr32_radio/efr32_radio.dtsi +++ b/boards/arm/efr32_radio/efr32_radio.dtsi @@ -5,6 +5,7 @@ */ #include +#include "efr32_radio-pinctrl.dtsi" / { chosen { @@ -57,8 +58,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/arm/efr32_radio/efr32_radio_brd4180a_defconfig b/boards/arm/efr32_radio/efr32_radio_brd4180a_defconfig index 79da19d546218d7..0db69e5d9e1fec0 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4180a_defconfig +++ b/boards/arm/efr32_radio/efr32_radio_brd4180a_defconfig @@ -9,3 +9,4 @@ CONFIG_SERIAL=y CONFIG_GPIO=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=38400000 CONFIG_CMU_HFCLK_HFXO=y +CONFIG_PINCTRL=y diff --git a/boards/arm/efr32_radio/efr32_radio_brd4187c_defconfig b/boards/arm/efr32_radio/efr32_radio_brd4187c_defconfig index ce32a6638c3e73a..046f8acfaeda9fc 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4187c_defconfig +++ b/boards/arm/efr32_radio/efr32_radio_brd4187c_defconfig @@ -10,6 +10,7 @@ CONFIG_GPIO=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=78000000 CONFIG_SOC_GECKO_EMU_DCDC=y CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y +CONFIG_PINCTRL=y # Use BURTC as system clock source CONFIG_GECKO_BURTC_TIMER=y From 26fd55e0a750305fbd5d9db750225d7e707458ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 16 Nov 2023 09:42:06 +0100 Subject: [PATCH 0748/1049] drivers: serial: nrfx_uarte: Rework Kconfig to use instance template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework Kconfig to improve handling of multiple UART instances by using Kconfig template file. Signed-off-by: Krzysztof Chruściński --- drivers/serial/Kconfig.nrfx | 309 +--------------------- drivers/serial/Kconfig.nrfx_uart_instance | 77 ++++++ drivers/serial/uart_nrfx_uarte.c | 14 +- 3 files changed, 101 insertions(+), 299 deletions(-) create mode 100644 drivers/serial/Kconfig.nrfx_uart_instance diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index 1775b598c355f73..53553e3d06ed521 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -36,291 +36,25 @@ config UART_ASYNC_TX_CACHE_SIZE in RAM, because EasyDMA in UARTE peripherals can only transfer data from RAM. -# ----------------- port 0 ----------------- if HAS_HW_NRF_UART0 || HAS_HW_NRF_UARTE0 +nrfx_uart_num = 0 +rsource "Kconfig.nrfx_uart_instance" +endif -config UART_0_ENHANCED_POLL_OUT - bool "Efficient poll out on port 0" - default y - depends on HAS_HW_NRF_UARTE0 - help - When enabled, polling out does not trigger interrupt which stops TX. - Feature uses a PPI channel. - -config UART_0_INTERRUPT_DRIVEN - bool "Interrupt support on port 0" - depends on UART_INTERRUPT_DRIVEN - default y - help - This option enables UART interrupt support on port 0. - -config UART_0_ASYNC - bool "Asynchronous API support on port 0" - depends on UART_ASYNC_API && !UART_0_INTERRUPT_DRIVEN - default y - help - This option enables UART Asynchronous API support on port 0. - -config UART_0_NRF_PARITY_BIT - bool "Parity bit" - help - Enable parity bit. - -config UART_0_NRF_TX_BUFFER_SIZE - int "Size of RAM buffer" - depends on HAS_HW_NRF_UARTE0 - range 1 65535 - default 32 - help - Size of the transmit buffer for API function: fifo_fill. - This value is limited by range of TXD.MAXCNT register for - particular SoC. - -config UART_0_NRF_HW_ASYNC - bool "Use hardware RX byte counting" - depends on HAS_HW_NRF_UARTE0 - depends on UART_ASYNC_API - help - If default driver uses interrupts to count incoming bytes, it is possible - that with higher speeds and/or high cpu load some data can be lost. - It is recommended to use hardware byte counting in such scenarios. - Hardware RX byte counting requires timer instance and one PPI channel - -config UART_0_NRF_ASYNC_LOW_POWER - bool "Low power mode" - depends on HAS_HW_NRF_UARTE0 - depends on UART_ASYNC_API - help - When enabled, UARTE is enabled before each TX or RX usage and disabled - when not used. Disabling UARTE while in idle allows to achieve lowest - power consumption. It is only feasible if receiver is not always on. - -config UART_0_NRF_HW_ASYNC_TIMER - int "Timer instance" - depends on UART_0_NRF_HW_ASYNC - -config UART_0_GPIO_MANAGEMENT - bool "GPIO management on port 0" - depends on PM_DEVICE - default y - help - If enabled, the driver will configure the GPIOs used by the uart to - their default configuration when device is powered down. The GPIOs - will be configured back to correct state when UART is powered up. - -endif # HAS_HW_NRF_UART0 || HAS_HW_NRF_UARTE0 - -# ----------------- port 1 ----------------- if HAS_HW_NRF_UARTE1 +nrfx_uart_num = 1 +rsource "Kconfig.nrfx_uart_instance" +endif -config UART_1_INTERRUPT_DRIVEN - bool "Interrupt support on port 1" - depends on UART_INTERRUPT_DRIVEN - default y - help - This option enables UART interrupt support on port 1. - -config UART_1_ASYNC - bool "Asynchronous API support on port 1" - depends on UART_ASYNC_API && !UART_1_INTERRUPT_DRIVEN - default y - help - This option enables UART Asynchronous API support on port 1. - -config UART_1_ENHANCED_POLL_OUT - bool "Efficient poll out on port 1" - default y - help - When enabled, polling out does not trigger interrupt which stops TX. - Feature uses a PPI channel. - -config UART_1_NRF_PARITY_BIT - bool "Parity bit" - help - Enable parity bit. - -config UART_1_NRF_TX_BUFFER_SIZE - int "Size of RAM buffer" - depends on UART_INTERRUPT_DRIVEN - range 1 65535 - default 32 - help - Size of the transmit buffer for API function: fifo_fill. - This value is limited by range of TXD.MAXCNT register for - particular SoC. - -config UART_1_NRF_HW_ASYNC - bool "Use hardware RX byte counting" - depends on UART_1_ASYNC - help - If default driver uses interrupts to count incoming bytes, it is possible - that with higher speeds and/or high cpu load some data can be lost. - It is recommended to use hardware byte counting in such scenarios. - Hardware RX byte counting requires timer instance and one PPI channel - -config UART_1_NRF_ASYNC_LOW_POWER - bool "Low power mode" - depends on UART_ASYNC_API - help - When enabled, UARTE is enabled before each TX or RX usage and disabled - when not used. Disabling UARTE while in idle allows to achieve lowest - power consumption. It is only feasible if receiver is not always on. - -config UART_1_NRF_HW_ASYNC_TIMER - int "Timer instance" - depends on UART_1_NRF_HW_ASYNC - -config UART_1_GPIO_MANAGEMENT - bool "GPIO management on port 1" - depends on PM_DEVICE - default y - help - If enabled, the driver will configure the GPIOs used by the uart to - their default configuration when device is powered down. The GPIOs - will be configured back to correct state when UART is powered up. - -endif # HAS_HW_NRF_UARTE1 - -# ----------------- port 2 ----------------- if HAS_HW_NRF_UARTE2 +nrfx_uart_num = 2 +rsource "Kconfig.nrfx_uart_instance" +endif -config UART_2_INTERRUPT_DRIVEN - bool "Interrupt support on port 2" - depends on UART_INTERRUPT_DRIVEN - default y - help - This option enables UART interrupt support on port 2. - -config UART_2_ASYNC - bool "Asynchronous API support on port 2" - depends on UART_ASYNC_API && !UART_2_INTERRUPT_DRIVEN - default y - help - This option enables UART Asynchronous API support on port 2. - -config UART_2_ENHANCED_POLL_OUT - bool "Efficient poll out on port 2" - default y - help - When enabled, polling out does not trigger interrupt which stops TX. - Feature uses a PPI channel. - -config UART_2_NRF_PARITY_BIT - bool "Parity bit" - help - Enable parity bit. - -config UART_2_NRF_TX_BUFFER_SIZE - int "Size of RAM buffer" - range 1 65535 - default 32 - help - Size of the transmit buffer for API function: fifo_fill. - This value is limited by range of TXD.MAXCNT register for - particular SoC. - -config UART_2_NRF_HW_ASYNC - bool "Use hardware RX byte counting" - depends on UART_2_ASYNC - help - If default driver uses interrupts to count incoming bytes, it is possible - that with higher speeds and/or high cpu load some data can be lost. - It is recommended to use hardware byte counting in such scenarios. - Hardware RX byte counting requires timer instance and one PPI channel - -config UART_2_NRF_ASYNC_LOW_POWER - bool "Low power mode" - depends on UART_ASYNC_API - help - When enabled, UARTE is enabled before each TX or RX usage and disabled - when not used. Disabling UARTE while in idle allows to achieve lowest - power consumption. It is only feasible if receiver is not always on. - -config UART_2_NRF_HW_ASYNC_TIMER - int "Timer instance" - depends on UART_2_NRF_HW_ASYNC - -config UART_2_GPIO_MANAGEMENT - bool "GPIO management on port 2" - depends on PM_DEVICE - default y - help - If enabled, the driver will configure the GPIOs used by the uart to - their default configuration when device is powered down. The GPIOs - will be configured back to correct state when UART is powered up. - -endif # HAS_HW_NRF_UARTE2 - -# ----------------- port 3 ----------------- if HAS_HW_NRF_UARTE3 - -config UART_3_INTERRUPT_DRIVEN - bool "Interrupt support on port 3" - depends on UART_INTERRUPT_DRIVEN - default y - help - This option enables UART interrupt support on port 3. - -config UART_3_ASYNC - bool "Asynchronous API support on port 3" - depends on UART_ASYNC_API && !UART_3_INTERRUPT_DRIVEN - default y - help - This option enables UART Asynchronous API support on port 3. - -config UART_3_ENHANCED_POLL_OUT - bool "Efficient poll out on port 3" - default y - help - When enabled, polling out does not trigger interrupt which stops TX. - Feature uses a PPI channel. - -config UART_3_NRF_PARITY_BIT - bool "Parity bit" - help - Enable parity bit. - -config UART_3_NRF_TX_BUFFER_SIZE - int "Size of RAM buffer" - range 1 65535 - default 32 - help - Size of the transmit buffer for API function: fifo_fill. - This value is limited by range of TXD.MAXCNT register for - particular SoC. - -config UART_3_NRF_HW_ASYNC - bool "Use hardware RX byte counting" - depends on UART_3_ASYNC - help - If default driver uses interrupts to count incoming bytes, it is possible - that with higher speeds and/or high cpu load some data can be lost. - It is recommended to use hardware byte counting in such scenarios. - Hardware RX byte counting requires timer instance and one PPI channel - -config UART_3_NRF_ASYNC_LOW_POWER - bool "Low power mode" - depends on UART_ASYNC_API - help - When enabled, UARTE is enabled before each TX or RX usage and disabled - when not used. Disabling UARTE while in idle allows to achieve lowest - power consumption. It is only feasible if receiver is not always on. - -config UART_3_NRF_HW_ASYNC_TIMER - int "Timer instance" - depends on UART_3_NRF_HW_ASYNC - -config UART_3_GPIO_MANAGEMENT - bool "GPIO management on port 3" - depends on PM_DEVICE - default y - help - If enabled, the driver will configure the GPIOs used by the uart to - their default configuration when device is powered down. The GPIOs - will be configured back to correct state when UART is powered up. - -endif # HAS_HW_NRF_UARTE3 - +nrfx_uart_num = 3 +rsource "Kconfig.nrfx_uart_instance" +endif config NRFX_TIMER0 default y @@ -357,23 +91,4 @@ config NRFX_TIMER4 || UART_2_NRF_HW_ASYNC_TIMER = 4 \ || UART_3_NRF_HW_ASYNC_TIMER = 4 - -config UARTE_NRF_HW_ASYNC - def_bool y - depends on UART_0_NRF_HW_ASYNC \ - || UART_1_NRF_HW_ASYNC \ - || UART_2_NRF_HW_ASYNC \ - || UART_3_NRF_HW_ASYNC - select NRFX_PPI if HAS_HW_NRF_PPI - select NRFX_DPPI if HAS_HW_NRF_DPPIC - -config UART_ENHANCED_POLL_OUT - def_bool y - depends on UART_0_ENHANCED_POLL_OUT \ - || UART_1_ENHANCED_POLL_OUT \ - || UART_2_ENHANCED_POLL_OUT \ - || UART_3_ENHANCED_POLL_OUT - select NRFX_PPI if HAS_HW_NRF_PPI - select NRFX_DPPI if HAS_HW_NRF_DPPIC - endif # UART_NRFX diff --git a/drivers/serial/Kconfig.nrfx_uart_instance b/drivers/serial/Kconfig.nrfx_uart_instance new file mode 100644 index 000000000000000..39e774e25444b62 --- /dev/null +++ b/drivers/serial/Kconfig.nrfx_uart_instance @@ -0,0 +1,77 @@ +#nRF UART(E) instance configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config UART_$(nrfx_uart_num)_INTERRUPT_DRIVEN + bool "Interrupt support on port $(nrfx_uart_num)" + depends on UART_INTERRUPT_DRIVEN + default y + help + This option enables UART interrupt support on port $(nrfx_uart_num). + +config UART_$(nrfx_uart_num)_ASYNC + bool "Asynchronous API support on port $(nrfx_uart_num)" + depends on UART_ASYNC_API && !UART_$(nrfx_uart_num)_INTERRUPT_DRIVEN + default y + help + This option enables UART Asynchronous API support on port $(nrfx_uart_num). + +config UART_$(nrfx_uart_num)_ENHANCED_POLL_OUT + bool "Efficient poll out on port $(nrfx_uart_num)" + default y + depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) + select NRFX_PPI if HAS_HW_NRF_PPI + select NRFX_DPPI if HAS_HW_NRF_DPPIC + help + When enabled, polling out does not trigger interrupt which stops TX. + Feature uses a PPI channel. + +config UART_$(nrfx_uart_num)_NRF_PARITY_BIT + bool "Parity bit" + help + Enable parity bit. + +config UART_$(nrfx_uart_num)_NRF_TX_BUFFER_SIZE + int "Size of RAM buffer" + depends on UART_INTERRUPT_DRIVEN + range 1 65535 + default 32 + help + Size of the transmit buffer for API function: fifo_fill. + This value is limited by range of TXD.MAXCNT register for + particular SoC. + +config UART_$(nrfx_uart_num)_NRF_HW_ASYNC + bool "Use hardware RX byte counting" + depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) + depends on UART_ASYNC_API + select NRFX_PPI if HAS_HW_NRF_PPI + select NRFX_DPPI if HAS_HW_NRF_DPPIC + help + If default driver uses interrupts to count incoming bytes, it is possible + that with higher speeds and/or high cpu load some data can be lost. + It is recommended to use hardware byte counting in such scenarios. + Hardware RX byte counting requires timer instance and one PPI channel. + +config UART_$(nrfx_uart_num)_NRF_ASYNC_LOW_POWER + bool "Low power mode" + depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) + depends on UART_ASYNC_API + help + When enabled, UARTE is enabled before each TX or RX usage and disabled + when not used. Disabling UARTE while in idle allows to achieve lowest + power consumption. It is only feasible if receiver is not always on. + +config UART_$(nrfx_uart_num)_NRF_HW_ASYNC_TIMER + int "Timer instance" + depends on UART_$(nrfx_uart_num)_NRF_HW_ASYNC + +config UART_$(nrfx_uart_num)_GPIO_MANAGEMENT + bool "GPIO management on port $(nrfx_uart_num)" + depends on PM_DEVICE + default y + help + If enabled, the driver will configure the GPIOs used by the uart to + their default configuration when device is powered down. The GPIOs + will be configured back to correct state when UART is powered up. diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index dc577ea9fc40bbb..3a62057a47abf33 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -65,6 +65,16 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL); #define UARTE_ANY_ASYNC 1 #endif +#if defined(CONFIG_UART_0_NRF_HW_ASYNC) || defined(CONFIG_UART_1_NRF_HW_ASYNC) || \ + defined(CONFIG_UART_2_NRF_HW_ASYNC) || defined(CONFIG_UART_3_NRF_HW_ASYNC) +#define UARTE_HW_ASYNC 1 +#endif + +#if defined(CONFIG_UART_0_ENHANCED_POLL_OUT) || defined(CONFIG_UART_1_ENHANCED_POLL_OUT) || \ + defined(CONFIG_UART_2_ENHANCED_POLL_OUT) || defined(CONFIG_UART_3_ENHANCED_POLL_OUT) +#define UARTE_ENHANCED_POLL_OUT 1 +#endif + /* * RX timeout is divided into time slabs, this define tells how many divisions * should be made. More divisions - higher timeout accuracy and processor usage. @@ -498,7 +508,7 @@ static int wait_tx_ready(const struct device *dev) * where static inline fails on linking. */ #define HW_RX_COUNTING_ENABLED(data) \ - (IS_ENABLED(CONFIG_UARTE_NRF_HW_ASYNC) ? data->async->hw_rx_counting : false) + (IS_ENABLED(UARTE_HW_ASYNC) ? data->async->hw_rx_counting : false) #endif /* UARTE_ANY_ASYNC */ @@ -1745,7 +1755,7 @@ static int uarte_instance_init(const struct device *dev, return err; } - if (IS_ENABLED(CONFIG_UART_ENHANCED_POLL_OUT) && + if (IS_ENABLED(UARTE_ENHANCED_POLL_OUT) && cfg->flags & UARTE_CFG_FLAG_PPI_ENDTX) { err = endtx_stoptx_ppi_init(uarte, data); if (err < 0) { From f9b42bc911c30fcbf4a096b20c6eca83da750c39 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 16 Nov 2023 20:39:39 +0100 Subject: [PATCH 0749/1049] drivers: serial: uart_stm32.c: RxDataFlush on async_rx_enable When enabling async RX the first time after boot, there is an additional byte received with the first RX_DATA_RDY event, which seems to be caused by the RX data not being flushed before enabling the UART RX DMA. Adding a request to flush the RX data register before enabling the RX DMA, solves the issue. Signed-off-by: Bjarki Arge Andreasen --- drivers/serial/uart_stm32.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index 6c41d0f0a2e50a5..fa2371cc1dfab24 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1579,6 +1579,13 @@ static int uart_stm32_async_rx_enable(const struct device *dev, return -EFAULT; } + /* Flush RX data buffer */ +#ifdef USART_SR_RXNE + LL_USART_ClearFlag_RXNE(config->usart); +#else + LL_USART_RequestRxDataFlush(config->usart); +#endif /* USART_SR_RXNE */ + /* Enable RX DMA requests */ uart_stm32_dma_rx_enable(dev); From fedd23f97041f3315f76ed76f67c25003fee18d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 17:16:00 +0100 Subject: [PATCH 0750/1049] bluetooth: a2dp: Add missing Doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added missing Doxygen comments to various macros. Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/a2dp-codec.h | 82 ++++++++++++++++++++------- include/zephyr/bluetooth/a2dp.h | 2 +- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/include/zephyr/bluetooth/a2dp-codec.h b/include/zephyr/bluetooth/a2dp-codec.h index 9e4e5ea34792baf..3da36420dcd2186 100644 --- a/include/zephyr/bluetooth/a2dp-codec.h +++ b/include/zephyr/bluetooth/a2dp-codec.h @@ -26,36 +26,76 @@ extern "C" { #endif -/* Sampling Frequency */ -#define A2DP_SBC_SAMP_FREQ_16000 BIT(7) -#define A2DP_SBC_SAMP_FREQ_32000 BIT(6) -#define A2DP_SBC_SAMP_FREQ_44100 BIT(5) -#define A2DP_SBC_SAMP_FREQ_48000 BIT(4) +/** + * @name Sampling Frequency + * @{ + */ +#define A2DP_SBC_SAMP_FREQ_16000 BIT(7) /**< 16 kHz */ +#define A2DP_SBC_SAMP_FREQ_32000 BIT(6) /**< 32 kHz */ +#define A2DP_SBC_SAMP_FREQ_44100 BIT(5) /**< 44.1 kHz */ +#define A2DP_SBC_SAMP_FREQ_48000 BIT(4) /**< 48 kHz */ +/** @} */ -/* Channel Mode */ -#define A2DP_SBC_CH_MODE_MONO BIT(3) -#define A2DP_SBC_CH_MODE_DUAL BIT(2) -#define A2DP_SBC_CH_MODE_STREO BIT(1) -#define A2DP_SBC_CH_MODE_JOINT BIT(0) +/** + * @name Channel Mode + * @{ + */ +#define A2DP_SBC_CH_MODE_MONO BIT(3) /**< Mono */ +#define A2DP_SBC_CH_MODE_DUAL BIT(2) /**< Dual Channel */ +#define A2DP_SBC_CH_MODE_STREO BIT(1) /**< Stereo */ +#define A2DP_SBC_CH_MODE_JOINT BIT(0) /**< Joint Stereo */ +/** @} */ -/* Block Length */ -#define A2DP_SBC_BLK_LEN_4 BIT(7) -#define A2DP_SBC_BLK_LEN_8 BIT(6) -#define A2DP_SBC_BLK_LEN_12 BIT(5) -#define A2DP_SBC_BLK_LEN_16 BIT(4) +/** + * @name Block Length + * @{ + */ +#define A2DP_SBC_BLK_LEN_4 BIT(7) /**< 4 blocks */ +#define A2DP_SBC_BLK_LEN_8 BIT(6) /**< 8 blocks */ +#define A2DP_SBC_BLK_LEN_12 BIT(5) /**< 12 blocks */ +#define A2DP_SBC_BLK_LEN_16 BIT(4) /**< 16 blocks */ +/** @} */ -/* Subbands */ -#define A2DP_SBC_SUBBAND_4 BIT(3) -#define A2DP_SBC_SUBBAND_8 BIT(2) +/** + * @name Subbands + * @{ + */ +#define A2DP_SBC_SUBBAND_4 BIT(3) /**< 4 subbands */ +#define A2DP_SBC_SUBBAND_8 BIT(2) /**< 8 subbands */ +/** @} */ -/* Allocation Method */ -#define A2DP_SBC_ALLOC_MTHD_SNR BIT(1) -#define A2DP_SBC_ALLOC_MTHD_LOUDNESS BIT(0) +/** + * @name Bit pool Allocation Method + * @{ + */ +#define A2DP_SBC_ALLOC_MTHD_SNR BIT(1) /**< Allocate based on loudness of the subband signal */ +#define A2DP_SBC_ALLOC_MTHD_LOUDNESS BIT(0) /**< Allocate based on the signal-to-noise ratio */ +/** @} */ +/** + * Gets the sampling rate from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_SAMP_FREQ(preset) ((preset->config[0] >> 4) & 0x0f) +/** + * Gets the channel mode from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_CHAN_MODE(preset) ((preset->config[0]) & 0x0f) +/** + * Gets the block length from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_BLK_LEN(preset) ((preset->config[1] >> 4) & 0x0f) +/** + * Gets the number subbands from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_SUB_BAND(preset) ((preset->config[1] >> 2) & 0x03) +/** + * Gets the bitpool allocation method from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_ALLOC_MTHD(preset) ((preset->config[1]) & 0x03) /** @brief SBC Codec */ diff --git a/include/zephyr/bluetooth/a2dp.h b/include/zephyr/bluetooth/a2dp.h index 3df6db1a6fd8175..f7e8ff35ea154a9 100644 --- a/include/zephyr/bluetooth/a2dp.h +++ b/include/zephyr/bluetooth/a2dp.h @@ -1,5 +1,5 @@ /** @file - * @brief Advance Audio Distribution Profile header. + * @brief Advanced Audio Distribution Profile header. */ /* From 5ed8bb74d424a094cd295b8d0aa4ea2caf4cefa4 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Fri, 17 Nov 2023 15:12:31 +0100 Subject: [PATCH 0751/1049] tests: coredump: Adjust logging backend patterns to xtensa Adjust tests/subsys/debug/coredump logging backend's output matching pattern to Xtensa fatal errors handler's call sequence difference. Signed-off-by: Dmitrii Golovanov --- tests/subsys/debug/coredump/testcase.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/subsys/debug/coredump/testcase.yaml b/tests/subsys/debug/coredump/testcase.yaml index 0f9e2ecead21e89..004217f36b72b63 100644 --- a/tests/subsys/debug/coredump/testcase.yaml +++ b/tests/subsys/debug/coredump/testcase.yaml @@ -7,6 +7,7 @@ tests: platform_exclude: acrn_ehl_crb arch_exclude: - posix + - xtensa integration_platforms: - qemu_x86 harness: console @@ -14,6 +15,7 @@ tests: type: multi_line regex: - "Coredump: (.*)" + - ">>> ZEPHYR FATAL ERROR " - "E: #CD:BEGIN#" - "E: #CD:5([aA])45([0-9a-fA-F]+)" - "E: #CD:41([0-9a-fA-F]+)" @@ -21,3 +23,24 @@ tests: - "E: #CD:4([dD])([0-9a-fA-F]+)" - "E: #CD:END#" - "k_sys_fatal_error_handler" + + debug.coredump.logging_backend_xtensa: + tags: coredump + ignore_faults: true + ignore_qemu_crash: true + filter: CONFIG_ARCH_SUPPORTS_COREDUMP + arch_allow: + - xtensa + harness: console + harness_config: + type: multi_line + regex: + - "Coredump: (.*)" + - "E: #CD:BEGIN#" + - "E: #CD:5([aA])45([0-9a-fA-F]+)" + - "E: #CD:41([0-9a-fA-F]+)" + - "E: #CD:4([dD])([0-9a-fA-F]+)" + - "E: #CD:4([dD])([0-9a-fA-F]+)" + - "E: #CD:END#" + - ">>> ZEPHYR FATAL ERROR " + - "k_sys_fatal_error_handler" From 23324fc5bae43a40024fdde05c893c75f3a73fff Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Fri, 17 Nov 2023 15:24:08 +0100 Subject: [PATCH 0752/1049] boards: qemu_xtensa: coredump: Enable coredump Enable coredump on qemu_xtensa and qemu_xtensa_mmu. Signed-off-by: Dmitrii Golovanov --- boards/xtensa/qemu_xtensa/Kconfig.board | 2 ++ tests/subsys/debug/coredump/src/main.c | 1 + tests/subsys/debug/coredump/testcase.yaml | 2 ++ 3 files changed, 5 insertions(+) diff --git a/boards/xtensa/qemu_xtensa/Kconfig.board b/boards/xtensa/qemu_xtensa/Kconfig.board index 4695b26396c7e74..34cdf44a15c46b8 100644 --- a/boards/xtensa/qemu_xtensa/Kconfig.board +++ b/boards/xtensa/qemu_xtensa/Kconfig.board @@ -7,9 +7,11 @@ config BOARD_QEMU_XTENSA bool "Xtensa emulation using QEMU" depends on SOC_XTENSA_DC233C select QEMU_TARGET + select ARCH_SUPPORTS_COREDUMP config BOARD_QEMU_XTENSA_MMU bool "Xtensa emulation using QEMU with MMU" depends on SOC_XTENSA_DC233C select QEMU_TARGET + select ARCH_SUPPORTS_COREDUMP select XTENSA_MMU diff --git a/tests/subsys/debug/coredump/src/main.c b/tests/subsys/debug/coredump/src/main.c index ddad60f92300f00..d5e11f2148d1e90 100644 --- a/tests/subsys/debug/coredump/src/main.c +++ b/tests/subsys/debug/coredump/src/main.c @@ -31,6 +31,7 @@ void func_3(uint32_t *addr) defined(CONFIG_BOARD_HIFIVE1) || \ defined(CONFIG_BOARD_LONGAN_NANO) || \ defined(CONFIG_BOARD_LONGAN_NANO_LITE) || \ + defined(CONFIG_BOARD_QEMU_XTENSA) || \ defined(CONFIG_SOC_FAMILY_INTEL_ADSP) ARG_UNUSED(addr); /* Call k_panic() directly so Renode doesn't pause execution. diff --git a/tests/subsys/debug/coredump/testcase.yaml b/tests/subsys/debug/coredump/testcase.yaml index 004217f36b72b63..150c07600a19b69 100644 --- a/tests/subsys/debug/coredump/testcase.yaml +++ b/tests/subsys/debug/coredump/testcase.yaml @@ -31,6 +31,8 @@ tests: filter: CONFIG_ARCH_SUPPORTS_COREDUMP arch_allow: - xtensa + integration_platforms: + - qemu_xtensa harness: console harness_config: type: multi_line From 1829cf4324074be15737632d6f8a9f55f7dc8f17 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 29 Sep 2023 16:32:46 +0200 Subject: [PATCH 0753/1049] Bluetooth: Audio: Add set functions for codec meta Add set function for all metadata types for both codec_cfg and codec_cap. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/audio.h | 361 +++++++++++++- subsys/bluetooth/audio/codec.c | 621 ++++++++++++++++++++++++- tests/bluetooth/audio/codec/src/main.c | 466 +++++++++++++++++++ 3 files changed, 1428 insertions(+), 20 deletions(-) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index 597e49ade9c0563..17bac991f186933 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -788,8 +788,8 @@ int bt_audio_codec_cfg_set_frame_blocks_per_sdu(struct bt_audio_codec_cfg *codec * @param[out] data Pointer to the data-pointer to update when item is found * @return Length of found @p data or 0 if not found */ -uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, - const uint8_t **data); +uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type, const uint8_t **data); /** * @brief Set or add a specific codec configuration value @@ -803,8 +803,9 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, u * @retval -EINVAL if arguments are invalid * @retval -ENOMEM if the new value could not set or added due to memory */ -int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t type, - const uint8_t *data, size_t data_len); +int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type, const uint8_t *data, + size_t data_len); /** @brief Lookup a specific metadata value based on type * @@ -820,6 +821,22 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t typ int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, const uint8_t **data); +/** + * @brief Set or add a specific codec configuration metadata value. + * + * @param codec_cfg The codec configuration to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @retval The meta_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type, const uint8_t *data, + size_t data_len); + /** @brief Extract preferred contexts * * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. @@ -833,6 +850,19 @@ int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, */ int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the preferred context of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ctx The preferred context to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_pref_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx); + /** @brief Extract stream contexts * * See @ref BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT for more information about this value. @@ -846,6 +876,19 @@ int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *co */ int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the stream context of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ctx The stream context to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_stream_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx); + /** @brief Extract program info * * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO for more information about this value. @@ -860,6 +903,20 @@ int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg * int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **program_info); +/** + * @brief Set the program info of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param program_info The program info to set. + * @param program_info_len The length of @p program_info. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_program_info(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info, size_t program_info_len); + /** @brief Extract stream language * * See @ref BT_AUDIO_METADATA_TYPE_STREAM_LANG for more information about this value. @@ -873,6 +930,19 @@ int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *co */ int bt_audio_codec_cfg_meta_get_stream_lang(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the stream language of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param stream_lang The 24-bit stream language to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_stream_lang(struct bt_audio_codec_cfg *codec_cfg, + uint32_t stream_lang); + /** @brief Extract CCID list * * See @ref BT_AUDIO_METADATA_TYPE_CCID_LIST for more information about this value. @@ -887,6 +957,20 @@ int bt_audio_codec_cfg_meta_get_stream_lang(const struct bt_audio_codec_cfg *cod int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **ccid_list); +/** + * @brief Set the CCID list of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ccid_list The program info to set. + * @param ccid_list_len The length of @p ccid_list. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_ccid_list(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *ccid_list, size_t ccid_list_len); + /** @brief Extract parental rating * * See @ref BT_AUDIO_METADATA_TYPE_PARENTAL_RATING for more information about this value. @@ -900,6 +984,19 @@ int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec */ int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the parental rating of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param parental_rating The parental rating to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_parental_rating(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_parental_rating parental_rating); + /** @brief Extract program info URI * * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI for more information about this value. @@ -914,6 +1011,21 @@ int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **program_info_uri); +/** + * @brief Set the program info URI of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param program_info_uri The program info URI to set. + * @param program_info_uri_len The length of @p program_info_uri. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_program_info_uri(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info_uri, + size_t program_info_uri_len); + /** @brief Extract audio active state * * See @ref BT_AUDIO_METADATA_TYPE_AUDIO_STATE for more information about this value. @@ -927,6 +1039,19 @@ int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg */ int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the audio active state of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param state The audio active state to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_audio_active_state(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_active_state state); + /** @brief Extract broadcast audio immediate rendering flag * * See @ref BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE for more information about this value. @@ -940,6 +1065,18 @@ int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_c int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the broadcast audio immediate rendering flag of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cfg *codec_cfg); + /** @brief Extract extended metadata * * See @ref BT_AUDIO_METADATA_TYPE_EXTENDED for more information about this value. @@ -954,6 +1091,20 @@ int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **extended_meta); +/** + * @brief Set the extended metadata of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param extended_meta The extended metadata to set. + * @param extended_meta_len The length of @p extended_meta. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_extended(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *extended_meta, size_t extended_meta_len); + /** @brief Extract vendor specific metadata * * See @ref BT_AUDIO_METADATA_TYPE_VENDOR for more information about this value. @@ -967,6 +1118,20 @@ int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_ */ int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **vendor_meta); + +/** + * @brief Set the vendor specific metadata of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param vendor_meta The vendor specific metadata to set. + * @param vendor_meta_len The length of @p vendor_meta. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_vendor(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *vendor_meta, size_t vendor_meta_len); /** @} */ /* End of bt_audio_codec_cfg */ /** @@ -982,14 +1147,30 @@ int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cf /** * @brief Lookup a specific value based on type * - * @param[in] codec_cap The codec data to search in. - * @param[in] type The type id to look for + * @param[in] codec_cap The codec data to search in. + * @param[in] type The type id to look for * @param[out] data Pointer to the data-pointer to update when item is found * * @return Length of found @p data or 0 if not found */ -uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, - const uint8_t **data); +uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type, const uint8_t **data); + +/** + * @brief Set or add a specific codec capability value + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to set + * @param data Pointer to the data-pointer to set + * @param data_len Length of @p data + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type, const uint8_t *data, + size_t data_len); /** * @brief Extract the frequency from a codec capability. @@ -1133,6 +1314,22 @@ int bt_audio_codec_cap_set_max_codec_frames_per_sdu(struct bt_audio_codec_cap *c int bt_audio_codec_cap_meta_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, const uint8_t **data); +/** + * @brief Set or add a specific codec capability metadata value. + * + * @param codec_cap The codec capability to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @retval The meta_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type, const uint8_t *data, + size_t data_len); + /** @brief Extract preferred contexts * * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. @@ -1146,6 +1343,19 @@ int bt_audio_codec_cap_meta_get_val(const struct bt_audio_codec_cap *codec_cap, */ int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the preferred context of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ctx The preferred context to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_pref_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx); + /** @brief Extract stream contexts * * See @ref BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT for more information about this value. @@ -1159,6 +1369,19 @@ int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *co */ int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the stream context of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ctx The stream context to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_stream_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx); + /** @brief Extract program info * * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO for more information about this value. @@ -1173,6 +1396,20 @@ int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap * int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *codec_cap, const uint8_t **program_info); +/** + * @brief Set the program info of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param program_info The program info to set. + * @param program_info_len The length of @p program_info. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_program_info(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info, size_t program_info_len); + /** @brief Extract stream language * * See @ref BT_AUDIO_METADATA_TYPE_STREAM_LANG for more information about this value. @@ -1186,6 +1423,19 @@ int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *co */ int bt_audio_codec_cap_meta_get_stream_lang(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the stream language of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param stream_lang The 24-bit stream language to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_stream_lang(struct bt_audio_codec_cap *codec_cap, + uint32_t stream_lang); + /** @brief Extract CCID list * * See @ref BT_AUDIO_METADATA_TYPE_CCID_LIST for more information about this value. @@ -1200,6 +1450,20 @@ int bt_audio_codec_cap_meta_get_stream_lang(const struct bt_audio_codec_cap *cod int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec_cap, const uint8_t **ccid_list); +/** + * @brief Set the CCID list of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ccid_list The program info to set. + * @param ccid_list_len The length of @p ccid_list. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_ccid_list(struct bt_audio_codec_cap *codec_cap, + const uint8_t *ccid_list, size_t ccid_list_len); + /** @brief Extract parental rating * * See @ref BT_AUDIO_METADATA_TYPE_PARENTAL_RATING for more information about this value. @@ -1213,6 +1477,19 @@ int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec */ int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the parental rating of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param parental_rating The parental rating to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_parental_rating(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_parental_rating parental_rating); + /** @brief Extract program info URI * * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI for more information about this value. @@ -1227,6 +1504,21 @@ int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap *codec_cap, const uint8_t **program_info_uri); +/** + * @brief Set the program info URI of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param program_info_uri The program info URI to set. + * @param program_info_uri_len The length of @p program_info_uri. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_program_info_uri(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info_uri, + size_t program_info_uri_len); + /** @brief Extract audio active state * * See @ref BT_AUDIO_METADATA_TYPE_AUDIO_STATE for more information about this value. @@ -1240,6 +1532,19 @@ int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap */ int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the audio active state of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param state The audio active state to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_audio_active_state(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_active_state state); + /** @brief Extract broadcast audio immediate rendering flag * * See @ref BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE for more information about this value. @@ -1253,6 +1558,18 @@ int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_c int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the broadcast audio immediate rendering flag of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cap *codec_cap); + /** @brief Extract extended metadata * * See @ref BT_AUDIO_METADATA_TYPE_EXTENDED for more information about this value. @@ -1267,6 +1584,20 @@ int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_cap, const uint8_t **extended_meta); +/** + * @brief Set the extended metadata of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param extended_meta The extended metadata to set. + * @param extended_meta_len The length of @p extended_meta. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_extended(struct bt_audio_codec_cap *codec_cap, + const uint8_t *extended_meta, size_t extended_meta_len); + /** @brief Extract vendor specific metadata * * See @ref BT_AUDIO_METADATA_TYPE_VENDOR for more information about this value. @@ -1281,6 +1612,20 @@ int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_ int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_cap, const uint8_t **vendor_meta); +/** + * @brief Set the vendor specific metadata of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param vendor_meta The vendor specific metadata to set. + * @param vendor_meta_len The length of @p vendor_meta. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_vendor(struct bt_audio_codec_cap *codec_cap, + const uint8_t *vendor_meta, size_t vendor_meta_len); + /** @} */ /* End of bt_audio_codec_cap */ #ifdef __cplusplus diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 382c6f370b03dda..38b1ef7d22b5c55 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -238,12 +238,12 @@ static void init_net_buf_simple_from_codec_cfg(struct net_buf_simple *buf, buf->len = codec_cfg->data_len; } -uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, - const uint8_t **data) +uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type, const uint8_t **data) { struct search_type_param param = { .found = false, - .type = type, + .type = (uint8_t)type, .data_len = 0, .data = data, }; @@ -275,8 +275,9 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, u return param.data_len; } -int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t type, - const uint8_t *data, size_t data_len) +int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type, const uint8_t *data, + size_t data_len) { struct net_buf_simple buf; int ret; @@ -519,10 +520,20 @@ int bt_audio_codec_cfg_set_frame_blocks_per_sdu(struct bt_audio_codec_cfg *codec #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 +static void init_net_buf_simple_from_meta(struct net_buf_simple *buf, uint8_t meta[], + size_t meta_len, size_t meta_size) +{ + buf->__buf = meta; + buf->data = meta; + buf->size = meta_size; + buf->len = meta_len; +} + static int codec_meta_get_val(const uint8_t meta[], size_t meta_len, uint8_t type, const uint8_t **data) { struct search_type_param param = { + .found = false, .type = type, .data_len = 0, .data = data, @@ -555,6 +566,32 @@ static int codec_meta_get_val(const uint8_t meta[], size_t meta_len, uint8_t typ return param.data_len; } +static int codec_meta_set_val(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_metadata_type type, const uint8_t *data, + size_t data_len) +{ + struct net_buf_simple buf; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(data == NULL && data_len != 0) { + LOG_DBG("data is NULL"); + return -EINVAL; + } + + CHECKIF(data_len > UINT8_MAX) { + LOG_DBG("Invalid data_len %zu", data_len); + return -EINVAL; + } + + init_net_buf_simple_from_meta(&buf, meta, meta_len, meta_size); + + return ltv_set_val(&buf, (uint8_t)type, data, data_len); +} + static int codec_meta_get_pref_context(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -577,6 +614,27 @@ static int codec_meta_get_pref_context(const uint8_t meta[], size_t meta_len) return sys_get_le16(data); } +static int codec_meta_set_pref_context(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_context ctx) +{ + uint16_t ctx_le16; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + if ((ctx & BT_AUDIO_CONTEXT_TYPE_ANY) != ctx) { + LOG_DBG("Invalid ctx value: %d", ctx); + return -EINVAL; + } + + ctx_le16 = sys_cpu_to_le16((uint16_t)ctx); + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, + (const uint8_t *)&ctx_le16, sizeof(ctx_le16)); +} + static int codec_meta_get_stream_context(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -599,6 +657,27 @@ static int codec_meta_get_stream_context(const uint8_t meta[], size_t meta_len) return sys_get_le16(data); } +static int codec_meta_set_stream_context(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_context ctx) +{ + uint16_t ctx_le16; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + if ((ctx & BT_AUDIO_CONTEXT_TYPE_ANY) != ctx) { + LOG_DBG("Invalid ctx value: %d", ctx); + return -EINVAL; + } + + ctx_le16 = sys_cpu_to_le16((uint16_t)ctx); + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + (const uint8_t *)&ctx_le16, sizeof(ctx_le16)); +} + static int codec_meta_get_program_info(const uint8_t meta[], size_t meta_len, const uint8_t **program_info) { @@ -625,6 +704,23 @@ static int codec_meta_get_program_info(const uint8_t meta[], size_t meta_len, return ret; } +static int codec_meta_set_program_info(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *program_info, size_t program_info_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(program_info == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, + program_info, program_info_len); +} + static int codec_meta_get_stream_lang(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -647,6 +743,27 @@ static int codec_meta_get_stream_lang(const uint8_t meta[], size_t meta_len) return sys_get_le24(data); } +static int codec_meta_set_stream_lang(uint8_t meta[], size_t meta_len, size_t meta_size, + uint32_t stream_lang) +{ + uint8_t stream_lang_le[3]; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + if ((stream_lang & 0xFFFFFFU) != stream_lang) { + LOG_DBG("Invalid stream_lang value: %d", stream_lang); + return -EINVAL; + } + + sys_put_le24(stream_lang, stream_lang_le); + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_STREAM_LANG, + stream_lang_le, sizeof(stream_lang_le)); +} + static int codec_meta_get_ccid_list(const uint8_t meta[], size_t meta_len, const uint8_t **ccid_list) { @@ -673,6 +790,23 @@ static int codec_meta_get_ccid_list(const uint8_t meta[], size_t meta_len, return ret; } +static int codec_meta_set_ccid_list(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *ccid_list, size_t ccid_list_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(ccid_list == NULL) { + LOG_DBG("ccid_list is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_CCID_LIST, + ccid_list, ccid_list_len); +} + static int codec_meta_get_parental_rating(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -695,6 +829,27 @@ static int codec_meta_get_parental_rating(const uint8_t meta[], size_t meta_len) return data[0]; } +static int codec_meta_set_parental_rating(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_parental_rating parental_rating) +{ + uint8_t parental_rating_u8; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + if (parental_rating > BT_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE) { + LOG_DBG("Invalid parental_rating value: %d", parental_rating); + return -EINVAL; + } + + parental_rating_u8 = (uint8_t)parental_rating; + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &parental_rating_u8, sizeof(parental_rating_u8)); +} + static int codec_meta_get_program_info_uri(const uint8_t meta[], size_t meta_len, const uint8_t **program_info_uri) { @@ -721,6 +876,25 @@ static int codec_meta_get_program_info_uri(const uint8_t meta[], size_t meta_len return ret; } +static int codec_meta_set_program_info_uri(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *program_info_uri, + size_t program_info_uri_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(program_info_uri == NULL) { + LOG_DBG("program_info_uri is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, + BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI, program_info_uri, + program_info_uri_len); +} + static int codec_meta_get_audio_active_state(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -743,6 +917,27 @@ static int codec_meta_get_audio_active_state(const uint8_t meta[], size_t meta_l return data[0]; } +static int codec_meta_set_audio_active_state(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_active_state state) +{ + uint8_t state_u8; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + if (state != BT_AUDIO_ACTIVE_STATE_DISABLED && state != BT_AUDIO_ACTIVE_STATE_ENABLED) { + LOG_DBG("Invalid state value: %d", state); + return -EINVAL; + } + + state_u8 = (uint8_t)state; + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_AUDIO_STATE, + &state_u8, sizeof(state_u8)); +} + static int codec_meta_get_bcast_audio_immediate_rend_flag(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -756,6 +951,18 @@ static int codec_meta_get_bcast_audio_immediate_rend_flag(const uint8_t meta[], &data); } +static int codec_meta_set_bcast_audio_immediate_rend_flag(uint8_t meta[], size_t meta_len, + size_t meta_size) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, + BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE, NULL, 0); +} + static int codec_meta_get_extended(const uint8_t meta[], size_t meta_len, const uint8_t **extended_meta) { @@ -782,6 +989,23 @@ static int codec_meta_get_extended(const uint8_t meta[], size_t meta_len, return ret; } +static int codec_meta_set_extended(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *extended, size_t extended_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(extended == NULL) { + LOG_DBG("extended is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_EXTENDED, + extended, extended_len); +} + static int codec_meta_get_vendor(const uint8_t meta[], size_t meta_len, const uint8_t **vendor_meta) { const uint8_t *data; @@ -807,6 +1031,23 @@ static int codec_meta_get_vendor(const uint8_t meta[], size_t meta_len, const ui return ret; } +static int codec_meta_set_vendor(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *vendor, size_t vendor_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(vendor == NULL) { + LOG_DBG("vendor is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_VENDOR, vendor, + vendor_len); +} + #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, const uint8_t **data) @@ -819,6 +1060,26 @@ int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, return codec_meta_get_val(codec_cfg->meta, codec_cfg->meta_len, type, data); } +int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type, const uint8_t *data, + size_t data_len) +{ + int ret; + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + return -EINVAL; + } + + ret = codec_meta_set_val(codec_cfg->meta, codec_cfg->meta_len, ARRAY_SIZE(codec_cfg->meta), + type, data, data_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -829,6 +1090,20 @@ int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *co return codec_meta_get_pref_context(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_pref_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx) +{ + int ret; + + ret = codec_meta_set_pref_context(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), ctx); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -839,6 +1114,20 @@ int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg * return codec_meta_get_stream_context(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_stream_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx) +{ + int ret; + + ret = codec_meta_set_stream_context(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), ctx); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **program_info) { @@ -850,6 +1139,21 @@ int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *co return codec_meta_get_program_info(codec_cfg->meta, codec_cfg->meta_len, program_info); } +int bt_audio_codec_cfg_meta_set_program_info(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info, size_t program_info_len) +{ + int ret; + + ret = codec_meta_set_program_info(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), program_info, + program_info_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_stream_lang(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -860,6 +1164,20 @@ int bt_audio_codec_cfg_meta_get_stream_lang(const struct bt_audio_codec_cfg *cod return codec_meta_get_stream_lang(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_stream_lang(struct bt_audio_codec_cfg *codec_cfg, + uint32_t stream_lang) +{ + int ret; + + ret = codec_meta_set_stream_lang(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), stream_lang); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **ccid_list) { @@ -871,6 +1189,20 @@ int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec return codec_meta_get_ccid_list(codec_cfg->meta, codec_cfg->meta_len, ccid_list); } +int bt_audio_codec_cfg_meta_set_ccid_list(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *ccid_list, size_t ccid_list_len) +{ + int ret; + + ret = codec_meta_set_ccid_list(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), ccid_list, ccid_list_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -881,6 +1213,20 @@ int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg return codec_meta_get_parental_rating(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_parental_rating(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_parental_rating parental_rating) +{ + int ret; + + ret = codec_meta_set_parental_rating(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), parental_rating); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **program_info_uri) { @@ -893,6 +1239,22 @@ int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg program_info_uri); } +int bt_audio_codec_cfg_meta_set_program_info_uri(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info_uri, + size_t program_info_uri_len) +{ + int ret; + + ret = codec_meta_set_program_info_uri(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), program_info_uri, + program_info_uri_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -903,6 +1265,20 @@ int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_c return codec_meta_get_audio_active_state(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_audio_active_state(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_active_state state) +{ + int ret; + + ret = codec_meta_set_audio_active_state(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), state); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( const struct bt_audio_codec_cfg *codec_cfg) { @@ -911,11 +1287,23 @@ int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( return -EINVAL; } - LOG_ERR("codec_cfg->meta_len %zu", codec_cfg->meta_len); - return codec_meta_get_bcast_audio_immediate_rend_flag(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cfg *codec_cfg) +{ + int ret; + + ret = codec_meta_set_bcast_audio_immediate_rend_flag(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta)); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **extended_meta) { @@ -927,6 +1315,21 @@ int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_ return codec_meta_get_extended(codec_cfg->meta, codec_cfg->meta_len, extended_meta); } +int bt_audio_codec_cfg_meta_set_extended(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *extended_meta, size_t extended_meta_len) +{ + int ret; + + ret = codec_meta_set_extended(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), extended_meta, + extended_meta_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **vendor_meta) { @@ -937,6 +1340,20 @@ int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cf return codec_meta_get_vendor(codec_cfg->meta, codec_cfg->meta_len, vendor_meta); } + +int bt_audio_codec_cfg_meta_set_vendor(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *vendor_meta, size_t vendor_meta_len) +{ + int ret; + + ret = codec_meta_set_vendor(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), vendor_meta, vendor_meta_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */ #if CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 @@ -951,6 +1368,26 @@ int bt_audio_codec_cap_meta_get_val(const struct bt_audio_codec_cap *codec_cap, return codec_meta_get_val(codec_cap->meta, codec_cap->meta_len, type, data); } +int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type, const uint8_t *data, + size_t data_len) +{ + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + ret = codec_meta_set_val(codec_cap->meta, codec_cap->meta_len, ARRAY_SIZE(codec_cap->meta), + type, data, data_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -961,6 +1398,20 @@ int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *co return codec_meta_get_pref_context(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_pref_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx) +{ + int ret; + + ret = codec_meta_set_pref_context(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), ctx); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -971,6 +1422,20 @@ int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap * return codec_meta_get_stream_context(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_stream_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx) +{ + int ret; + + ret = codec_meta_set_stream_context(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), ctx); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *codec_cap, const uint8_t **program_info) { @@ -982,6 +1447,21 @@ int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *co return codec_meta_get_program_info(codec_cap->meta, codec_cap->meta_len, program_info); } +int bt_audio_codec_cap_meta_set_program_info(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info, size_t program_info_len) +{ + int ret; + + ret = codec_meta_set_program_info(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), program_info, + program_info_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_stream_lang(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -992,6 +1472,20 @@ int bt_audio_codec_cap_meta_get_stream_lang(const struct bt_audio_codec_cap *cod return codec_meta_get_stream_lang(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_stream_lang(struct bt_audio_codec_cap *codec_cap, + uint32_t stream_lang) +{ + int ret; + + ret = codec_meta_set_stream_lang(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), stream_lang); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec_cap, const uint8_t **ccid_list) { @@ -1003,6 +1497,20 @@ int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec return codec_meta_get_ccid_list(codec_cap->meta, codec_cap->meta_len, ccid_list); } +int bt_audio_codec_cap_meta_set_ccid_list(struct bt_audio_codec_cap *codec_cap, + const uint8_t *ccid_list, size_t ccid_list_len) +{ + int ret; + + ret = codec_meta_set_ccid_list(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), ccid_list, ccid_list_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -1013,6 +1521,20 @@ int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap return codec_meta_get_parental_rating(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_parental_rating(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_parental_rating parental_rating) +{ + int ret; + + ret = codec_meta_set_parental_rating(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), parental_rating); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap *codec_cap, const uint8_t **program_info_uri) { @@ -1025,6 +1547,22 @@ int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap program_info_uri); } +int bt_audio_codec_cap_meta_set_program_info_uri(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info_uri, + size_t program_info_uri_len) +{ + int ret; + + ret = codec_meta_set_program_info_uri(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), program_info_uri, + program_info_uri_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -1035,6 +1573,20 @@ int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_c return codec_meta_get_audio_active_state(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_audio_active_state(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_active_state state) +{ + int ret; + + ret = codec_meta_set_audio_active_state(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), state); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( const struct bt_audio_codec_cap *codec_cap) { @@ -1046,6 +1598,20 @@ int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( return codec_meta_get_bcast_audio_immediate_rend_flag(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cap *codec_cap) +{ + int ret; + + ret = codec_meta_set_bcast_audio_immediate_rend_flag(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta)); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_cap, const uint8_t **extended_meta) { @@ -1057,6 +1623,21 @@ int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_ return codec_meta_get_extended(codec_cap->meta, codec_cap->meta_len, extended_meta); } +int bt_audio_codec_cap_meta_set_extended(struct bt_audio_codec_cap *codec_cap, + const uint8_t *extended_meta, size_t extended_meta_len) +{ + int ret; + + ret = codec_meta_set_extended(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), extended_meta, + extended_meta_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_cap, const uint8_t **vendor_meta) { @@ -1067,6 +1648,20 @@ int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_ca return codec_meta_get_vendor(codec_cap->meta, codec_cap->meta_len, vendor_meta); } + +int bt_audio_codec_cap_meta_set_vendor(struct bt_audio_codec_cap *codec_cap, + const uint8_t *vendor_meta, size_t vendor_meta_len) +{ + int ret; + + ret = codec_meta_set_vendor(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), vendor_meta, vendor_meta_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} #endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 */ #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ * CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 \ @@ -1083,11 +1678,12 @@ static void init_net_buf_simple_from_codec_cap(struct net_buf_simple *buf, buf->len = codec_cap->data_len; } -uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, - const uint8_t **data) +uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type, const uint8_t **data) { struct search_type_param param = { - .type = type, + .found = false, + .type = (uint8_t)type, .data_len = 0, .data = data, }; @@ -1119,8 +1715,9 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, u return param.data_len; } -int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, uint8_t type, - const uint8_t *data, size_t data_len) +int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type, const uint8_t *data, + size_t data_len) { struct net_buf_simple buf; int ret; diff --git a/tests/bluetooth/audio/codec/src/main.c b/tests/bluetooth/audio/codec/src/main.c index 99d5d6f21fdff54..386ef40e7f75eec 100644 --- a/tests/bluetooth/audio/codec/src/main.c +++ b/tests/bluetooth/audio/codec/src/main.c @@ -228,6 +228,27 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_pref_context) zassert_equal(ret, 0x0005, "unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_pref_context) +{ + const enum bt_audio_context ctx = + BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_MEDIA; + const enum bt_audio_context new_ctx = BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS; + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, + BT_BYTES_LIST_LE16(ctx))}); + int ret; + + ret = bt_audio_codec_cfg_meta_get_pref_context(&codec_cfg); + zassert_equal(ret, 0x0005, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_pref_context(&codec_cfg, new_ctx); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_pref_context(&codec_cfg); + zassert_equal(ret, 0x0100, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_stream_context) { const enum bt_audio_context ctx = @@ -242,6 +263,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_stream_context) zassert_equal(ret, 0x0005, "unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_stream_context) +{ + enum bt_audio_context ctx = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_MEDIA; + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + BT_BYTES_LIST_LE16(ctx))}); + int ret; + + ret = bt_audio_codec_cfg_meta_get_stream_context(&codec_cfg); + zassert_equal(ret, 0x0005, "Unexpected return value %d", ret); + + ctx = BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS; + ret = bt_audio_codec_cfg_meta_set_stream_context(&codec_cfg, ctx); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_stream_context(&codec_cfg); + zassert_equal(ret, 0x0100, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_program_info) { const uint8_t expected_data[] = {'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', @@ -259,6 +300,31 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_program_info) zassert_mem_equal(expected_data, program_data, ARRAY_SIZE(expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_program_info) +{ + const uint8_t expected_data[] = {'P', 'r', 'o', 'g', 'r', 'a', + 'm', ' ', 'I', 'n', 'f', 'o'}; + const uint8_t new_expected_data[] = {'N', 'e', 'w', ' ', 'i', 'n', 'f', 'o'}; + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_CFG( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, 'P', 'r', 'o', 'g', 'r', + 'a', 'm', ' ', 'I', 'n', 'f', 'o')}); + const uint8_t *program_data; + int ret; + + ret = bt_audio_codec_cfg_meta_get_program_info(&codec_cfg, &program_data); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, program_data, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cfg_meta_set_program_info(&codec_cfg, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_program_info(&codec_cfg, &program_data); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, program_data, ARRAY_SIZE(new_expected_data)); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_stream_lang) { const uint32_t expected_data = sys_get_le24((uint8_t[]){'e', 'n', 'g'}); @@ -271,6 +337,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_stream_lang) zassert_equal(ret, expected_data, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_stream_lang) +{ + const uint32_t expected_data = sys_get_le24((uint8_t[]){'e', 'n', 'g'}); + const uint32_t new_expected_data = sys_get_le24((uint8_t[]){'d', 'e', 'u'}); + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_CFG( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_LANG, 'e', 'n', 'g')}); + const uint32_t new_stream_lang = sys_le32_to_cpu(new_expected_data); + int ret; + + ret = bt_audio_codec_cfg_meta_get_stream_lang(&codec_cfg); + zassert_equal(ret, expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_stream_lang(&codec_cfg, new_stream_lang); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_stream_lang(&codec_cfg); + zassert_equal(ret, new_expected_data, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_ccid_list) { const uint8_t expected_data[] = {0x05, 0x10, 0x15}; @@ -285,6 +371,29 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_ccid_list) zassert_mem_equal(expected_data, ccid_list, ARRAY_SIZE(expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_ccid_list) +{ + const uint8_t expected_data[] = {0x05, 0x10, 0x15}; + const uint8_t new_expected_data[] = {0x25, 0x30}; + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_CFG( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, 0x05, 0x10, 0x15)}); + const uint8_t *ccid_list; + int ret; + + ret = bt_audio_codec_cfg_meta_get_ccid_list(&codec_cfg, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, ccid_list, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cfg_meta_set_ccid_list(&codec_cfg, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_ccid_list(&codec_cfg, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, ccid_list, ARRAY_SIZE(new_expected_data)); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_parental_rating) { const struct bt_audio_codec_cfg codec_cfg = @@ -297,6 +406,25 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_parental_rating) zassert_equal(ret, 0x07, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_parental_rating) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + int ret; + + ret = bt_audio_codec_cfg_meta_get_parental_rating(&codec_cfg); + zassert_equal(ret, 0x07, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_parental_rating(&codec_cfg, + BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_parental_rating(&codec_cfg); + zassert_equal(ret, 0x0a, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_program_info_uri) { const uint8_t expected_data[] = {'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm'}; @@ -312,6 +440,30 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_program_info_uri) zassert_mem_equal(expected_data, program_info_uri, ARRAY_SIZE(expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_program_info_uri) +{ + const uint8_t expected_data[] = {'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm'}; + const uint8_t new_expected_data[] = {'n', 'e', 'w', '.', 'c', 'o', 'm'}; + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_CFG( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI, 'e', 'x', 'a', 'm', + 'p', 'l', 'e', '.', 'c', 'o', 'm')}); + const uint8_t *program_info_uri; + int ret; + + ret = bt_audio_codec_cfg_meta_get_program_info_uri(&codec_cfg, &program_info_uri); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, program_info_uri, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cfg_meta_set_program_info_uri(&codec_cfg, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_program_info_uri(&codec_cfg, &program_info_uri); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, program_info_uri, ARRAY_SIZE(new_expected_data)); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_audio_active_state) { const struct bt_audio_codec_cfg codec_cfg = @@ -324,6 +476,25 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_audio_active_stat zassert_equal(ret, 0x01, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_audio_active_state) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_AUDIO_STATE, + BT_AUDIO_ACTIVE_STATE_ENABLED)}); + int ret; + + ret = bt_audio_codec_cfg_meta_get_audio_active_state(&codec_cfg); + zassert_equal(ret, 0x01, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_audio_active_state(&codec_cfg, + BT_AUDIO_ACTIVE_STATE_DISABLED); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_audio_active_state(&codec_cfg); + zassert_equal(ret, 0x00, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag) { const struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_CFG( @@ -335,6 +506,22 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_bcast_audio_immed zassert_equal(ret, 0, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + int ret; + + ret = bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag(&codec_cfg); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag(&codec_cfg); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag(&codec_cfg); + zassert_equal(ret, 0, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_extended) { const uint8_t expected_data[] = {0x00, 0x01, 0x02, 0x03}; @@ -349,6 +536,29 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_extended) zassert_mem_equal(expected_data, extended_meta, ARRAY_SIZE(expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_extended) +{ + const uint8_t expected_data[] = {0x00, 0x01, 0x02, 0x03}; + const uint8_t new_expected_data[] = {0x04, 0x05}; + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_CFG( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_EXTENDED, 0x00, 0x01, 0x02, 0x03)}); + const uint8_t *extended_meta; + int ret; + + ret = bt_audio_codec_cfg_meta_get_extended(&codec_cfg, &extended_meta); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, extended_meta, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cfg_meta_set_extended(&codec_cfg, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_extended(&codec_cfg, &extended_meta); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, extended_meta, ARRAY_SIZE(new_expected_data)); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_vendor) { const uint8_t expected_data[] = {0x00, 0x01, 0x02, 0x03}; @@ -363,6 +573,29 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_vendor) zassert_mem_equal(expected_data, vendor_meta, ARRAY_SIZE(expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_vendor) +{ + const uint8_t expected_data[] = {0x00, 0x01, 0x02, 0x03}; + const uint8_t new_expected_data[] = {0x04, 0x05, 0x06, 0x07, 0x08}; + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_CFG( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_VENDOR, 0x00, 0x01, 0x02, 0x03)}); + const uint8_t *extended_meta; + int ret; + + ret = bt_audio_codec_cfg_meta_get_vendor(&codec_cfg, &extended_meta); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, extended_meta, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cfg_meta_set_vendor(&codec_cfg, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_vendor(&codec_cfg, &extended_meta); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, extended_meta, ARRAY_SIZE(new_expected_data)); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_freq) { const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( @@ -553,6 +786,27 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_pref_context) zassert_equal(ret, 0x0005, "unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_pref_context) +{ + const enum bt_audio_context ctx = + BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_MEDIA; + const enum bt_audio_context new_ctx = BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS; + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, + BT_BYTES_LIST_LE16(ctx))}); + int ret; + + ret = bt_audio_codec_cap_meta_get_pref_context(&codec_cap); + zassert_equal(ret, 0x0005, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_set_pref_context(&codec_cap, new_ctx); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_pref_context(&codec_cap); + zassert_equal(ret, 0x0100, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_stream_context) { const enum bt_audio_context ctx = @@ -567,6 +821,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_stream_context) zassert_equal(ret, 0x0005, "unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_stream_context) +{ + enum bt_audio_context ctx = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_MEDIA; + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + BT_BYTES_LIST_LE16(ctx))}); + int ret; + + ret = bt_audio_codec_cap_meta_get_stream_context(&codec_cap); + zassert_equal(ret, 0x0005, "Unexpected return value %d", ret); + + ctx = BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS; + ret = bt_audio_codec_cap_meta_set_stream_context(&codec_cap, ctx); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_stream_context(&codec_cap); + zassert_equal(ret, 0x0100, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_program_info) { const uint8_t expected_data[] = {'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', @@ -584,6 +858,31 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_program_info) zassert_mem_equal(expected_data, program_data, ARRAY_SIZE(expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_program_info) +{ + const uint8_t expected_data[] = {'P', 'r', 'o', 'g', 'r', 'a', + 'm', ' ', 'I', 'n', 'f', 'o'}; + const uint8_t new_expected_data[] = {'N', 'e', 'w', ' ', 'i', 'n', 'f', 'o'}; + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, 'P', 'r', 'o', 'g', 'r', + 'a', 'm', ' ', 'I', 'n', 'f', 'o')}); + const uint8_t *program_data; + int ret; + + ret = bt_audio_codec_cap_meta_get_program_info(&codec_cap, &program_data); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, program_data, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cap_meta_set_program_info(&codec_cap, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_program_info(&codec_cap, &program_data); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, program_data, ARRAY_SIZE(new_expected_data)); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_stream_lang) { const uint32_t expected_data = sys_get_le24((uint8_t[]){'e', 'n', 'g'}); @@ -596,6 +895,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_stream_lang) zassert_equal(ret, expected_data, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_stream_lang) +{ + const uint32_t expected_data = sys_get_le24((uint8_t[]){'e', 'n', 'g'}); + const uint32_t new_expected_data = sys_get_le24((uint8_t[]){'d', 'e', 'u'}); + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_LANG, 'e', 'n', 'g')}); + const uint32_t new_stream_lang = sys_le32_to_cpu(new_expected_data); + int ret; + + ret = bt_audio_codec_cap_meta_get_stream_lang(&codec_cap); + zassert_equal(ret, expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_set_stream_lang(&codec_cap, new_stream_lang); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_stream_lang(&codec_cap); + zassert_equal(ret, new_expected_data, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_ccid_list) { const uint8_t expected_data[] = {0x05, 0x10, 0x15}; @@ -610,6 +929,29 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_ccid_list) zassert_mem_equal(expected_data, ccid_list, ARRAY_SIZE(expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_ccid_list) +{ + const uint8_t expected_data[] = {0x05, 0x10, 0x15}; + const uint8_t new_expected_data[] = {0x25, 0x30}; + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, 0x05, 0x10, 0x15)}); + const uint8_t *ccid_list; + int ret; + + ret = bt_audio_codec_cap_meta_get_ccid_list(&codec_cap, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, ccid_list, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cap_meta_set_ccid_list(&codec_cap, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_ccid_list(&codec_cap, &ccid_list); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, ccid_list, ARRAY_SIZE(new_expected_data)); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_parental_rating) { const struct bt_audio_codec_cap codec_cap = @@ -622,6 +964,25 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_parental_rating) zassert_equal(ret, 0x07, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_parental_rating) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + int ret; + + ret = bt_audio_codec_cap_meta_get_parental_rating(&codec_cap); + zassert_equal(ret, 0x07, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_set_parental_rating(&codec_cap, + BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_parental_rating(&codec_cap); + zassert_equal(ret, 0x0a, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_program_info_uri) { const uint8_t expected_data[] = {'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm'}; @@ -637,6 +998,30 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_program_info_uri) zassert_mem_equal(expected_data, program_info_uri, ARRAY_SIZE(expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_program_info_uri) +{ + const uint8_t expected_data[] = {'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm'}; + const uint8_t new_expected_data[] = {'n', 'e', 'w', '.', 'c', 'o', 'm'}; + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI, 'e', 'x', 'a', 'm', + 'p', 'l', 'e', '.', 'c', 'o', 'm')}); + const uint8_t *program_info_uri; + int ret; + + ret = bt_audio_codec_cap_meta_get_program_info_uri(&codec_cap, &program_info_uri); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, program_info_uri, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cap_meta_set_program_info_uri(&codec_cap, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_program_info_uri(&codec_cap, &program_info_uri); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, program_info_uri, ARRAY_SIZE(new_expected_data)); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_audio_active_state) { const struct bt_audio_codec_cap codec_cap = @@ -649,6 +1034,25 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_audio_active_stat zassert_equal(ret, 0x01, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_audio_active_state) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_AUDIO_STATE, + BT_AUDIO_ACTIVE_STATE_ENABLED)}); + int ret; + + ret = bt_audio_codec_cap_meta_get_audio_active_state(&codec_cap); + zassert_equal(ret, 0x01, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_set_audio_active_state(&codec_cap, + BT_AUDIO_ACTIVE_STATE_DISABLED); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_audio_active_state(&codec_cap); + zassert_equal(ret, 0x00, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag) { const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP( @@ -660,6 +1064,22 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_bcast_audio_immed zassert_equal(ret, 0, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + int ret; + + ret = bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag(&codec_cap); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag(&codec_cap); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag(&codec_cap); + zassert_equal(ret, 0, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_extended) { const uint8_t expected_data[] = {0x00, 0x01, 0x02, 0x03}; @@ -674,6 +1094,29 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_extended) zassert_mem_equal(expected_data, extended_meta, ARRAY_SIZE(expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_extended) +{ + const uint8_t expected_data[] = {0x00, 0x01, 0x02, 0x03}; + const uint8_t new_expected_data[] = {0x04, 0x05}; + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_EXTENDED, 0x00, 0x01, 0x02, 0x03)}); + const uint8_t *extended_meta; + int ret; + + ret = bt_audio_codec_cap_meta_get_extended(&codec_cap, &extended_meta); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, extended_meta, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cap_meta_set_extended(&codec_cap, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_extended(&codec_cap, &extended_meta); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, extended_meta, ARRAY_SIZE(new_expected_data)); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_vendor) { const uint8_t expected_data[] = {0x00, 0x01, 0x02, 0x03}; @@ -687,3 +1130,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_vendor) zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); zassert_mem_equal(expected_data, vendor_meta, ARRAY_SIZE(expected_data)); } + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_vendor) +{ + const uint8_t expected_data[] = {0x00, 0x01, 0x02, 0x03}; + const uint8_t new_expected_data[] = {0x04, 0x05, 0x06, 0x07, 0x08}; + struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP( + BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_VENDOR, 0x00, 0x01, 0x02, 0x03)}); + const uint8_t *extended_meta; + int ret; + + ret = bt_audio_codec_cap_meta_get_vendor(&codec_cap, &extended_meta); + zassert_equal(ret, ARRAY_SIZE(expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(expected_data, extended_meta, ARRAY_SIZE(expected_data)); + + ret = bt_audio_codec_cap_meta_set_vendor(&codec_cap, new_expected_data, + ARRAY_SIZE(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_vendor(&codec_cap, &extended_meta); + zassert_equal(ret, ARRAY_SIZE(new_expected_data), "Unexpected return value %d", ret); + zassert_mem_equal(new_expected_data, extended_meta, ARRAY_SIZE(new_expected_data)); +} From 176d433b98a28c8b455ead93cbe71b448246930c Mon Sep 17 00:00:00 2001 From: Adrien Bruant Date: Tue, 17 Oct 2023 15:13:51 +0200 Subject: [PATCH 0754/1049] drivers: bbram: stm32-bbram: port to stm32wl On STM32WL, the backup memory is defined as part of the TAMP peripheral. This seems to be a deviation from the stm32 family where this memory is defined as part of the RTC. The STM32WL reference manual shows that tamp_pclk is connected to rtc_pclk. This means that the clock required to run the TAMP peripheral is the same as the RTC's. A quick port of BBRAM on STM32WL is achieved by instanciating the bbram device as a child of the RTC and by modifying the address offset to the first backup register from the rtc base address. Signed-off-by: Adrien Bruant --- drivers/bbram/bbram_stm32.c | 9 ++++++++- dts/arm/st/wl/stm32wl.dtsi | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/bbram/bbram_stm32.c b/drivers/bbram/bbram_stm32.c index 30bc2c5edaaa78e..0ba429d66f8fd6e 100644 --- a/drivers/bbram/bbram_stm32.c +++ b/drivers/bbram/bbram_stm32.c @@ -14,7 +14,14 @@ LOG_MODULE_REGISTER(bbram, CONFIG_BBRAM_LOG_LEVEL); #define STM32_BKP_REG_BYTES 4 -#define STM32_BKP_REG_OFFSET 0x50 +#ifdef TAMP +/* If a SoC has a TAMP peripherals, then the backup registers are defined there, + * not in the RTC. + */ +#define STM32_BKP_REG_OFFSET (TAMP_BASE + offsetof(TAMP_TypeDef, BKP0R) - RTC_BASE) +#else +#define STM32_BKP_REG_OFFSET offsetof(RTC_TypeDef, BKP0R) +#endif #define STM32_BKP_REG_INDEX(offset) ((offset) >> 2) #define STM32_BKP_REG_BYTE_INDEX(offset) ((offset)&0x3UL) #define STM32_BKP_REG(i) (((volatile uint32_t *)config->base_addr)[(i)]) diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index 85c40256e51c145..cc4b4dc31c9ac9b 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -207,6 +207,18 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>; prescaler = <32768>; status = "disabled"; + + /* In STM32WL, the backup registers are defined as part of the TAMP + * peripheral. This peripheral is not implemented in Zephyr yet, however, + * the reference manual states that tamp_pclk is connected to rtc_pclk. + * It makes sense to have BBRAM instantiated as a child of RTC, so that + * the driver can verify that its parent device (RTC) is ready. + */ + bbram: backup_regs { + compatible = "st,stm32-bbram"; + st,backup-regs = <20>; + status = "disabled"; + }; }; iwdg: watchdog@40003000 { From 8021cde6dee36d5229d92236c71fcd370f6a30c4 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 17 Oct 2023 14:21:08 -0700 Subject: [PATCH 0755/1049] mm: polish doxygen on memory management driver APIs Makes the HTML document on the MM driver APIs a bit more easier to navigate (hopefully). Signed-off-by: Daniel Leung --- include/zephyr/drivers/mm/system_mm.h | 112 ++++++++++++++++++++------ 1 file changed, 89 insertions(+), 23 deletions(-) diff --git a/include/zephyr/drivers/mm/system_mm.h b/include/zephyr/drivers/mm/system_mm.h index c76f1097f656696..d523b706723f49f 100644 --- a/include/zephyr/drivers/mm/system_mm.h +++ b/include/zephyr/drivers/mm/system_mm.h @@ -26,12 +26,20 @@ extern "C" { /** * @brief Memory Management Driver APIs * @defgroup mm_drv_apis Memory Management Driver APIs + * + * This contains APIs for a system-wide memory management + * driver. Only one instance is permitted on the system. + * * @ingroup memory_management * @{ */ -/* - * Caching mode definitions. These are mutually exclusive. +/** + * @name Caching mode definitions. + * + * These are mutually exclusive. + * + * @{ */ /** No caching */ @@ -46,9 +54,16 @@ extern "C" { /** Reserved bits for cache modes */ #define SYS_MM_MEM_CACHE_MASK (BIT(3) - 1) -/* - * Region permission attributes. +/** + * @} + */ + +/** + * @name Region permission attributes. + * * Default should be read-only, no user, no exec. + * + * @{ */ /** Region will have read/write access (and not read-only) */ @@ -60,6 +75,18 @@ extern "C" { /** Region will be accessible to user mode (normally supervisor-only) */ #define SYS_MM_MEM_PERM_USER BIT(5) +/** + * @} + */ + +/** + * @name Memory Mapping and Unmapping + * + * On mapping and unmapping of memory. + * + * @{ + */ + /** * @brief Map one physical page into the virtual address space * @@ -177,25 +204,6 @@ int sys_mm_drv_unmap_page(void *virt); */ int sys_mm_drv_unmap_region(void *virt, size_t size); -/** - * @brief Get the mapped physical memory address from virtual address. - * - * The function queries the translation tables to find the physical - * memory address of a mapped virtual address. - * - * Behavior when providing unaligned address is undefined, this - * is assumed to be page aligned. - * - * @param virt Page-aligned virtual address - * @param[out] phys Mapped physical address (can be NULL if only checking - * if virtual address is mapped) - * - * @retval 0 if mapping is found and valid - * @retval -EINVAL if invalid arguments are provided - * @retval -EFAULT if virtual address is not mapped - */ -int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys); - /** * @brief Remap virtual pages into new address * @@ -225,6 +233,18 @@ int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys); */ int sys_mm_drv_remap_region(void *virt_old, size_t size, void *virt_new); +/** + * @} + */ + +/** + * @name Memory Moving + * + * On moving already mapped memory. + * + * @{ + */ + /** * @brief Physically move memory, with copy * @@ -294,6 +314,17 @@ int sys_mm_drv_move_region(void *virt_old, size_t size, void *virt_new, int sys_mm_drv_move_array(void *virt_old, size_t size, void *virt_new, uintptr_t *phys_new, size_t phys_cnt); +/** + * @} + */ + +/** + * @name Memory Mapping Attributes + * + * On manipulating attributes of already mapped memory. + * + * @{ + */ /** * @brief Update memory page flags @@ -340,6 +371,37 @@ int sys_mm_drv_update_page_flags(void *virt, uint32_t flags); int sys_mm_drv_update_region_flags(void *virt, size_t size, uint32_t flags); +/** + * @} + */ + +/** + * @name Memory Mappings Query + * + * On querying information on memory mappings. + * + * @{ + */ + +/** + * @brief Get the mapped physical memory address from virtual address. + * + * The function queries the translation tables to find the physical + * memory address of a mapped virtual address. + * + * Behavior when providing unaligned address is undefined, this + * is assumed to be page aligned. + * + * @param virt Page-aligned virtual address + * @param[out] phys Mapped physical address (can be NULL if only checking + * if virtual address is mapped) + * + * @retval 0 if mapping is found and valid + * @retval -EINVAL if invalid arguments are provided + * @retval -EFAULT if virtual address is not mapped + */ +int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys); + /** * @brief Represents an available memory region. * @@ -387,6 +449,10 @@ const struct sys_mm_drv_region *sys_mm_drv_query_memory_regions(void); */ void sys_mm_drv_query_memory_regions_free(const struct sys_mm_drv_region *regions); +/** + * @} + */ + /** * @} */ From ca1aae618349f67d5fb6eb0596d9fa3660da0c7a Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 17 Oct 2023 14:30:19 -0700 Subject: [PATCH 0756/1049] mm: intel_adsp_mtl_tlb: move SRAM_BANK_PAGE_NUM in driver The macro SRAM_BANK_PAGE_NUM is specfic to the mtl_tlb driver and is not universal. So move that from public header into the driver. Signed-off-by: Daniel Leung --- drivers/mm/mm_drv_intel_adsp_mtl_tlb.c | 2 ++ include/zephyr/drivers/mm/mm_drv_bank.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c index 55a9b1776a1f15c..dfe8d86ee7d43d0 100644 --- a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c @@ -27,6 +27,8 @@ #include #include +#define SRAM_BANK_PAGE_NUM (SRAM_BANK_SIZE / CONFIG_MM_DRV_PAGE_SIZE) + static struct k_spinlock tlb_lock; extern struct k_spinlock sys_mm_drv_common_lock; diff --git a/include/zephyr/drivers/mm/mm_drv_bank.h b/include/zephyr/drivers/mm/mm_drv_bank.h index 9e1a51ebcbf17db..8b1402c94e7fdde 100644 --- a/include/zephyr/drivers/mm/mm_drv_bank.h +++ b/include/zephyr/drivers/mm/mm_drv_bank.h @@ -21,8 +21,6 @@ #include #include -#define SRAM_BANK_PAGE_NUM (SRAM_BANK_SIZE / CONFIG_MM_DRV_PAGE_SIZE) - struct mem_drv_bank { uint32_t unmapped_pages; uint32_t mapped_pages; From 9a6e32f87c2cf4cdbc8077124beac37b76e47b52 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 17 Oct 2023 14:36:33 -0700 Subject: [PATCH 0757/1049] mm: rename struct mem_drv_bank to sys_mm_drv_bank Simply to put them into correct namespace as the struct is part of public API. Signed-off-by: Daniel Leung --- drivers/mm/mm_drv_bank.c | 10 +++++----- drivers/mm/mm_drv_intel_adsp_mtl_tlb.c | 2 +- include/zephyr/drivers/mm/mm_drv_bank.h | 12 ++++++------ tests/drivers/mm/sys_mm_drv_bank/src/main.c | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/mm/mm_drv_bank.c b/drivers/mm/mm_drv_bank.c index 03209ffec4196d5..ca9ad9d051b8d5a 100644 --- a/drivers/mm/mm_drv_bank.c +++ b/drivers/mm/mm_drv_bank.c @@ -18,14 +18,14 @@ #include #include -void sys_mm_drv_bank_init(struct mem_drv_bank *bank, uint32_t bank_pages) +void sys_mm_drv_bank_init(struct sys_mm_drv_bank *bank, uint32_t bank_pages) { bank->unmapped_pages = 0; bank->mapped_pages = bank_pages; bank->max_mapped_pages = bank_pages; } -uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank) +uint32_t sys_mm_drv_bank_page_mapped(struct sys_mm_drv_bank *bank) { bank->unmapped_pages--; bank->mapped_pages++; @@ -35,14 +35,14 @@ uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank) return bank->mapped_pages; } -uint32_t sys_mm_drv_bank_page_unmapped(struct mem_drv_bank *bank) +uint32_t sys_mm_drv_bank_page_unmapped(struct sys_mm_drv_bank *bank) { bank->unmapped_pages++; bank->mapped_pages--; return bank->unmapped_pages; } -void sys_mm_drv_bank_stats_get(struct mem_drv_bank *bank, +void sys_mm_drv_bank_stats_get(struct sys_mm_drv_bank *bank, struct sys_memory_stats *stats) { stats->free_bytes = bank->unmapped_pages * @@ -53,7 +53,7 @@ void sys_mm_drv_bank_stats_get(struct mem_drv_bank *bank, CONFIG_MM_DRV_PAGE_SIZE; } -void sys_mm_drv_bank_stats_reset_max(struct mem_drv_bank *bank) +void sys_mm_drv_bank_stats_reset_max(struct sys_mm_drv_bank *bank) { bank->max_mapped_pages = bank->mapped_pages; } diff --git a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c index dfe8d86ee7d43d0..ea3bb385b3b271b 100644 --- a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c @@ -32,7 +32,7 @@ static struct k_spinlock tlb_lock; extern struct k_spinlock sys_mm_drv_common_lock; -static struct mem_drv_bank hpsram_bank[L2_SRAM_BANK_NUM]; +static struct sys_mm_drv_bank hpsram_bank[L2_SRAM_BANK_NUM]; #ifdef CONFIG_SOC_INTEL_COMM_WIDGET #include diff --git a/include/zephyr/drivers/mm/mm_drv_bank.h b/include/zephyr/drivers/mm/mm_drv_bank.h index 8b1402c94e7fdde..5fc06989dc8d00c 100644 --- a/include/zephyr/drivers/mm/mm_drv_bank.h +++ b/include/zephyr/drivers/mm/mm_drv_bank.h @@ -21,7 +21,7 @@ #include #include -struct mem_drv_bank { +struct sys_mm_drv_bank { uint32_t unmapped_pages; uint32_t mapped_pages; uint32_t max_mapped_pages; @@ -39,7 +39,7 @@ struct mem_drv_bank { * @param bank Pointer to the memory bank structure used for tracking * @param bank_pages Number of pages in the memory bank */ -void sys_mm_drv_bank_init(struct mem_drv_bank *bank, uint32_t bank_pages); +void sys_mm_drv_bank_init(struct sys_mm_drv_bank *bank, uint32_t bank_pages); /** * @brief Track the mapping of a page in the specified memory bank @@ -51,7 +51,7 @@ void sys_mm_drv_bank_init(struct mem_drv_bank *bank, uint32_t bank_pages); * * @return The number of pages mapped within the memory bank */ -uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank); +uint32_t sys_mm_drv_bank_page_mapped(struct sys_mm_drv_bank *bank); /** * @brief Track the unmapping of a page in the specified memory bank @@ -63,7 +63,7 @@ uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank); * * @return The number of unmapped pages within the memory bank */ -uint32_t sys_mm_drv_bank_page_unmapped(struct mem_drv_bank *bank); +uint32_t sys_mm_drv_bank_page_unmapped(struct sys_mm_drv_bank *bank); /** * @brief Reset the max number of pages mapped in the bank @@ -74,7 +74,7 @@ uint32_t sys_mm_drv_bank_page_unmapped(struct mem_drv_bank *bank); * * @param bank Pointer to the memory bank's data structure */ -void sys_mm_drv_bank_stats_reset_max(struct mem_drv_bank *bank); +void sys_mm_drv_bank_stats_reset_max(struct sys_mm_drv_bank *bank); /** * @brief Retrieve the memory usage stats for the specified memory bank @@ -84,7 +84,7 @@ void sys_mm_drv_bank_stats_reset_max(struct mem_drv_bank *bank); * @param bank Pointer to the memory bank's data structure * @param stats Pointer to memory into which to copy the system memory stats */ -void sys_mm_drv_bank_stats_get(struct mem_drv_bank *bank, +void sys_mm_drv_bank_stats_get(struct sys_mm_drv_bank *bank, struct sys_memory_stats *stats); #endif /* ZEPHYR_INCLUDE_DRIVERS_MM_DRV_BANK_H */ diff --git a/tests/drivers/mm/sys_mm_drv_bank/src/main.c b/tests/drivers/mm/sys_mm_drv_bank/src/main.c index dfde79302d28584..882d57cb1f539f6 100644 --- a/tests/drivers/mm/sys_mm_drv_bank/src/main.c +++ b/tests/drivers/mm/sys_mm_drv_bank/src/main.c @@ -11,7 +11,7 @@ #define EXPECTED(x) ((x) * CONFIG_MM_DRV_PAGE_SIZE) -static struct mem_drv_bank bank_data = {0x123, 0x234, 0x345}; +static struct sys_mm_drv_bank bank_data = {0x123, 0x234, 0x345}; static void test_stats(const char *error_string, struct sys_memory_stats *stats, From 9c90ed6f61ac12a1884fb49f43746c9db5a88107 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 17 Oct 2023 14:45:54 -0700 Subject: [PATCH 0758/1049] mm: polish doxygen doc on memory banks driver APIs () Put the memory bank APIs under the memory management group. () Document the struct sys_mm_drv_bank. () Put proper in,out for function parameters. Signed-off-by: Daniel Leung --- include/zephyr/drivers/mm/mm_drv_bank.h | 47 +++++++++++++++++++------ 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/include/zephyr/drivers/mm/mm_drv_bank.h b/include/zephyr/drivers/mm/mm_drv_bank.h index 5fc06989dc8d00c..75fb57467ce9ae7 100644 --- a/include/zephyr/drivers/mm/mm_drv_bank.h +++ b/include/zephyr/drivers/mm/mm_drv_bank.h @@ -9,9 +9,10 @@ * @brief Memory Banks Driver APIs * * This contains generic APIs to be used by a system-wide memory management - * driver to track page usage within memory banks. It is incumbent upon the - * caller to ensure that proper locking is used to protect the data when - * using these APIs. + * driver to track page usage within memory banks. + * + * @note The caller of these functions needs to ensure proper locking + * to protect the data when using these APIs. */ #ifndef ZEPHYR_INCLUDE_DRIVERS_MM_DRV_BANK_H @@ -21,9 +22,31 @@ #include #include +/** + * @brief Memory Banks Driver APIs + * @defgroup mm_drv_bank_apis Memory Banks Driver APIs + * + * This contains APIs for a system-wide memory management driver to + * track page usage within memory banks. + * + * @note The caller of these functions needs to ensure proper locking + * to protect the data when using these APIs. + * + * @ingroup memory_management + * @{ + */ + +/** + * @brief Information about memory banks. + */ struct sys_mm_drv_bank { + /** Number of unmapped pages. */ uint32_t unmapped_pages; + + /** Number of mapped pages. */ uint32_t mapped_pages; + + /** Maximum number of mapped pages since last counter reset. */ uint32_t max_mapped_pages; }; @@ -36,8 +59,8 @@ struct sys_mm_drv_bank { * it will start with all pages mapped. In next phase of driver initialization * unused pages will be unmapped. * - * @param bank Pointer to the memory bank structure used for tracking - * @param bank_pages Number of pages in the memory bank + * @param[in,out] bank Pointer to the memory bank structure used for tracking + * @param[in] bank_pages Number of pages in the memory bank */ void sys_mm_drv_bank_init(struct sys_mm_drv_bank *bank, uint32_t bank_pages); @@ -47,7 +70,7 @@ void sys_mm_drv_bank_init(struct sys_mm_drv_bank *bank, uint32_t bank_pages); * This function is used to update the number of mapped pages within the * specified memory bank. * - * @param bank Pointer to the memory bank's data structure + * @param[in,out] bank Pointer to the memory bank's data structure * * @return The number of pages mapped within the memory bank */ @@ -59,7 +82,7 @@ uint32_t sys_mm_drv_bank_page_mapped(struct sys_mm_drv_bank *bank); * This function is used to update the number of unmapped pages within the * specified memory bank. * - * @param bank Pointer to the memory bank's data structure + * @param[in,out] bank Pointer to the memory bank's data structure * * @return The number of unmapped pages within the memory bank */ @@ -72,7 +95,7 @@ uint32_t sys_mm_drv_bank_page_unmapped(struct sys_mm_drv_bank *bank); * the specified memory bank to the current number of pages mapped in * that memory bank. * - * @param bank Pointer to the memory bank's data structure + * @param[in,out] bank Pointer to the memory bank's data structure */ void sys_mm_drv_bank_stats_reset_max(struct sys_mm_drv_bank *bank); @@ -81,10 +104,14 @@ void sys_mm_drv_bank_stats_reset_max(struct sys_mm_drv_bank *bank); * * This routine extracts the system memory stats from the memory bank. * - * @param bank Pointer to the memory bank's data structure - * @param stats Pointer to memory into which to copy the system memory stats + * @param[in] bank Pointer to the memory bank's data structure + * @param[in,out] stats Pointer to memory into which to copy the system memory stats */ void sys_mm_drv_bank_stats_get(struct sys_mm_drv_bank *bank, struct sys_memory_stats *stats); +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_DRIVERS_MM_DRV_BANK_H */ From f8a9d95549692849e8e8931945d8bf0809198034 Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Wed, 8 Nov 2023 10:32:01 +0100 Subject: [PATCH 0759/1049] soc: arm: st_stm32: stm32u5: Add STM32U5A9 support Add support for STM32U5A9XX SoC series Signed-off-by: Abderrahmane Jarmouni --- .../st_stm32/stm32u5/Kconfig.defconfig.stm32u5a9xx | 14 ++++++++++++++ soc/arm/st_stm32/stm32u5/Kconfig.soc | 4 ++++ 2 files changed, 18 insertions(+) create mode 100644 soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5a9xx diff --git a/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5a9xx b/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5a9xx new file mode 100644 index 000000000000000..0553382acb1e06e --- /dev/null +++ b/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5a9xx @@ -0,0 +1,14 @@ +# STMicroelectronics STM32U5A9XX MCU + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32U5A9XX + +config SOC + default "stm32u5a9xx" + +config NUM_IRQS + default 139 + +endif # SOC_STM32U5A9XX diff --git a/soc/arm/st_stm32/stm32u5/Kconfig.soc b/soc/arm/st_stm32/stm32u5/Kconfig.soc index 8308c64372fe385..ec8c964ad3ee80d 100644 --- a/soc/arm/st_stm32/stm32u5/Kconfig.soc +++ b/soc/arm/st_stm32/stm32u5/Kconfig.soc @@ -2,6 +2,7 @@ # Copyright (c) 2021 Linaro Limited # Copyright (c) 2023 PSICONTROL nv +# Copyright (c) 2023 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 choice @@ -23,4 +24,7 @@ config SOC_STM32U599XX config SOC_STM32U5A5XX bool "STM32U5A5XX" +config SOC_STM32U5A9XX + bool "STM32U5A9XX" + endchoice From 236ba6bf5ab0a0915083c460e5e826a85bd3bbda Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Wed, 8 Nov 2023 10:36:27 +0100 Subject: [PATCH 0760/1049] dt-bindings: clock: Add STM32U5A9 clk sel helpers Add clock selection helpers specific to STM32U59x/5Ax & STM32U5Fx/5Gx SoCs Signed-off-by: Abderrahmane Jarmouni --- .../zephyr/dt-bindings/clock/stm32u5_clock.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/include/zephyr/dt-bindings/clock/stm32u5_clock.h b/include/zephyr/dt-bindings/clock/stm32u5_clock.h index 900f77620f8508a..ca4b774d8020891 100644 --- a/include/zephyr/dt-bindings/clock/stm32u5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u5_clock.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 Linaro Limited + * Copyright (c) 2023 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -87,8 +88,8 @@ #define USART1_SEL(val) STM32_CLOCK(val, 3, 0, CCIPR1_REG) #define USART2_SEL(val) STM32_CLOCK(val, 3, 2, CCIPR1_REG) #define USART3_SEL(val) STM32_CLOCK(val, 3, 4, CCIPR1_REG) -#define USART4_SEL(val) STM32_CLOCK(val, 3, 6, CCIPR1_REG) -#define USART5_SEL(val) STM32_CLOCK(val, 3, 8, CCIPR1_REG) +#define UART4_SEL(val) STM32_CLOCK(val, 3, 6, CCIPR1_REG) +#define UART5_SEL(val) STM32_CLOCK(val, 3, 8, CCIPR1_REG) #define I2C1_SEL(val) STM32_CLOCK(val, 3, 10, CCIPR1_REG) #define I2C2_SEL(val) STM32_CLOCK(val, 3, 12, CCIPR1_REG) #define I2C4_SEL(val) STM32_CLOCK(val, 3, 14, CCIPR1_REG) @@ -106,7 +107,14 @@ #define SAE_SEL(val) STM32_CLOCK(val, 1, 11, CCIPR2_REG) #define RNG_SEL(val) STM32_CLOCK(val, 3, 12, CCIPR2_REG) #define SDMMC_SEL(val) STM32_CLOCK(val, 1, 14, CCIPR2_REG) +#define DSIHOST_SEL(val) STM32_CLOCK(val, 1, 15, CCIPR2_REG) +#define USART6_SEL(val) STM32_CLOCK(val, 1, 16, CCIPR2_REG) +#define LTDC_SEL(val) STM32_CLOCK(val, 1, 18, CCIPR2_REG) #define OCTOSPI_SEL(val) STM32_CLOCK(val, 3, 20, CCIPR2_REG) +#define HSPI_SEL(val) STM32_CLOCK(val, 3, 22, CCIPR2_REG) +#define I2C5_SEL(val) STM32_CLOCK(val, 3, 24, CCIPR2_REG) +#define I2C6_SEL(val) STM32_CLOCK(val, 3, 26, CCIPR2_REG) +#define USBPHYC_SEL(val) STM32_CLOCK(val, 3, 30, CCIPR2_REG) /** CCIPR3 devices */ #define LPUART1_SEL(val) STM32_CLOCK(val, 7, 0, CCIPR3_REG) #define SPI3_SEL(val) STM32_CLOCK(val, 3, 3, CCIPR3_REG) @@ -118,5 +126,10 @@ #define ADF1_SEL(val) STM32_CLOCK(val, 7, 16, CCIPR3_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) +/** + * Dummy: Add a specifier when no selection is possible, value may not occur + * in used RCC regs + */ +#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32U5_CLOCK_H_ */ From aeb1e8ed3407509e2de251dc54052e9a43e9123a Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Wed, 8 Nov 2023 10:42:39 +0100 Subject: [PATCH 0761/1049] dts: arm: st: add STM32U5A9 support add STM32U5A9XJ device trees. Also add ADC2 & ADC1_2 dual mode nodes Signed-off-by: Abderrahmane Jarmouni --- dts/arm/st/u5/stm32u595.dtsi | 38 ++++++++++++++++++++++++++++++++++ dts/arm/st/u5/stm32u5a9.dtsi | 13 ++++++++++++ dts/arm/st/u5/stm32u5a9Xj.dtsi | 28 +++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 dts/arm/st/u5/stm32u5a9.dtsi create mode 100644 dts/arm/st/u5/stm32u5a9Xj.dtsi diff --git a/dts/arm/st/u5/stm32u595.dtsi b/dts/arm/st/u5/stm32u595.dtsi index 401aa5ace795abe..db489205f95342e 100644 --- a/dts/arm/st/u5/stm32u595.dtsi +++ b/dts/arm/st/u5/stm32u595.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 PSICONTROl nv + * Copyright (c) 2023 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -58,5 +59,42 @@ interrupt-names = "event", "error"; status = "disabled"; }; + + /* Available in STM32U59x/5Ax/5Fx/5Gx SoCs */ + adc2: adc@42028100 { + compatible = "st,stm32-adc"; + reg = <0x42028100 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000400>; + interrupts = <37 0>; + status = "disabled"; + #io-channel-cells = <1>; + resolutions = ; + sampling-times = <5 6 12 20 36 68 391 814>; + st,adc-clock-source = ; + st,adc-sequencer = ; + }; + + /* + * Available in STM32U59x/5Ax/5Fx/5Gx SoCs + * dual mode: adc1 and adc2 coupled + */ + adc1_2: adc@42028300 { + compatible = "st,stm32-adc"; + reg = <0x42028300 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000400>; + interrupts = <37 0>; + status = "disabled"; + #io-channel-cells = <1>; + resolutions = ; + sampling-times = <5 6 12 20 36 68 391 814>; + st,adc-clock-source = ; + st,adc-sequencer = ; + }; }; }; diff --git a/dts/arm/st/u5/stm32u5a9.dtsi b/dts/arm/st/u5/stm32u5a9.dtsi new file mode 100644 index 000000000000000..13cd1e1401d151f --- /dev/null +++ b/dts/arm/st/u5/stm32u5a9.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + compatible = "st,stm32u5a9", "st,stm32u5", "simple-bus"; + }; +}; diff --git a/dts/arm/st/u5/stm32u5a9Xj.dtsi b/dts/arm/st/u5/stm32u5a9Xj.dtsi new file mode 100644 index 000000000000000..1b9b7cadd75e1f7 --- /dev/null +++ b/dts/arm/st/u5/stm32u5a9Xj.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + /* SRAM1 + SRAM2 + SRAM3 + SRAM5 */ + /* 768K + 64K + 832K + 832K */ + reg = <0x20000000 DT_SIZE_K(2496)>; + }; + sram1: memory@28000000 { + /* SRAM4, low-power background autonomous mode */ + reg = <0x28000000 DT_SIZE_K(16)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_M(4)>; + }; + }; + }; +}; From 2df99b10c5cd27618b81cf2bdf9bab44fcd62628 Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Wed, 8 Nov 2023 13:17:05 +0100 Subject: [PATCH 0762/1049] boards: arm: stm32u5a9j-dk: Add initial support Add initial support of STM32U5A9J-DK discovery kit Signed-off-by: Abderrahmane Jarmouni --- boards/arm/stm32u5a9j_dk/Kconfig.board | 8 + boards/arm/stm32u5a9j_dk/Kconfig.defconfig | 11 + boards/arm/stm32u5a9j_dk/board.cmake | 7 + .../arm/stm32u5a9j_dk/doc/img/bottom_view.jpg | Bin 0 -> 79341 bytes boards/arm/stm32u5a9j_dk/doc/img/top_view.jpg | Bin 0 -> 77907 bytes boards/arm/stm32u5a9j_dk/doc/index.rst | 186 +++++++++++ boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts | 299 ++++++++++++++++++ boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.yaml | 23 ++ .../arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig | 28 ++ 9 files changed, 562 insertions(+) create mode 100644 boards/arm/stm32u5a9j_dk/Kconfig.board create mode 100644 boards/arm/stm32u5a9j_dk/Kconfig.defconfig create mode 100644 boards/arm/stm32u5a9j_dk/board.cmake create mode 100644 boards/arm/stm32u5a9j_dk/doc/img/bottom_view.jpg create mode 100644 boards/arm/stm32u5a9j_dk/doc/img/top_view.jpg create mode 100644 boards/arm/stm32u5a9j_dk/doc/index.rst create mode 100644 boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts create mode 100644 boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.yaml create mode 100644 boards/arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig diff --git a/boards/arm/stm32u5a9j_dk/Kconfig.board b/boards/arm/stm32u5a9j_dk/Kconfig.board new file mode 100644 index 000000000000000..8482aa58f0447a3 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/Kconfig.board @@ -0,0 +1,8 @@ +# STM32U5A9J Discovery Kit board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32U5A9J_DK + bool "STM32U5A9J Discovery Kit Development Board" + depends on SOC_STM32U5A9XX diff --git a/boards/arm/stm32u5a9j_dk/Kconfig.defconfig b/boards/arm/stm32u5a9j_dk/Kconfig.defconfig new file mode 100644 index 000000000000000..8124e0227409ab9 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/Kconfig.defconfig @@ -0,0 +1,11 @@ +# STM32U5A9J DISCOVERY KIT board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32U5A9J_DK + +config BOARD + default "stm32u5a9j_dk" + +endif # BOARD_STM32U5A9J_DK diff --git a/boards/arm/stm32u5a9j_dk/board.cmake b/boards/arm/stm32u5a9j_dk/board.cmake new file mode 100644 index 000000000000000..597c0c8b676b56f --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw") + +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +# FIXME: openocd runner not yet available. diff --git a/boards/arm/stm32u5a9j_dk/doc/img/bottom_view.jpg b/boards/arm/stm32u5a9j_dk/doc/img/bottom_view.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d1c1dca173bbc36d5c47bc8ae9edf80baec8e74 GIT binary patch literal 79341 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⪼Qe`oP^T`VFHsg z5na>=3v;9ql+TKB+^x&il<_5Ue}SO9Ei^d13z2Q`=tGYB5Pfx%svz~KA%>u>nMwiP~P5&-k-8q z;j$(_KQpQH@^37od8EToUgOaAQY0j8+jod*fNgM!G!hPAUTwJi*1iL9S|wlcdPJ7R zUP6GI3;8z}a#slTs_^Ej@Rl;cJ=;JY-X2OVN|9@y zH_BddG^MMkJJ0g~!}XtH8S@b%&l%=)y|DURWubdeqzrDP_$FTFd87n}XzG?Nl4xaX zU*+cNa;<}08W3R^xzOuiJbIR@lQBU?Ai-Ofmv(z};B0s`g|15%fs|aQ&Us@Hy0ly= zTq?h(?6EMyV>)T>W@J@xnRZBK`cVR_&mw9+GnZiVWjtP%M8@V2B|#9)PM}rV{z+my zNP$6MZ%W~~u|LvX{4yyVwOS*Lsh`l&QOg3W8uxo<3?Uz^x4M2x{1(HXy#!6z1hbpfQv#a1K^_YPjB{N^UoEn z;~=3zSDms19(r)7_~*c+0{y}HfH?U01sQncaf}&w1!{#>M`&}`h{N*aD5ML5ShEKr z9V6>O_)p5)=oiCjnQ%s}cv#<#DWac=ul8Gc-eapAeQsP}djX+Myzqid|!TFS+wu zV`m)$lU}Co_x6Z#e;|Unv?X#D!*Wr+Y>8Ev#r2K<3nu=?6A$(j@MYqJ}ZZtd@E}%TUc`g+-bD=GEb?~61rQI?d()n++^FvI| zov%fe=_h%t1}P93S~+z2fnQ1Yk3JtE+^=gzQIQDB7$~5a# zGPG>yBvnv6zw7%E^)=2FR8yQt_q1Lw_p6ZN)d*f`@z&hH?uzmz zIAWiXA|E)AHo>klTZk&@Y&_Dz+!IMD`q`-$SP3)D$LdN zWYXeM4ig;<+(=!rclLXLFHGI4m_UUiF*&Ml1lO~w`_@Q`6?@OYaMQY*Wpdy&QC1`n ze&bv)y83b!3kwG;;78pAom7@##W zAs2ec+>C-IM_o>+rPI}@SS45co6MR!v0kfO(Sdq=vAv_;(8=hq9idhFpZgO^^FA#( z2;+zLO&qDTHrmmWH_6Q;v3sv{7{~ih)bx<5A3d8Fq2)4|`Vt-q8=NqH_PSksUO&^> z#FsYrLRpm(kHys;%V!VuvFvVqqXI*BTYn{u>0p{L`9}sFTvs}`khzp-s*>goW03fi z!lr73^o&8b%XK7ps5Lg=4W5(f)5n@_g3cZqS4MnC6L#R6@V9e4tVHL@(EfKVa{D@w z+Ty+&yBb~*lLiSMLk)O;=ynA8fZFK4oyvd7t7Ln{MF(0N4B5HK3FT@745H3w27ge! zH~;#pv@$#h#DoJK|8H0i>2Gc=mLvhwE)4>R4b%vZU+r}#}7uooay3xV%eB?Kt}1gfT~^#;Tn<1`aU&} zc>0-Mb3OcYVaThBP00eMnXaE+MQPA;ib!r(&GbIl3`Z2`#%7N-r(HjT$ z59mT6VBuea(t=Usr9`Yv*R%-%SkFG=Z|Z-j5wzhbtLHH3`_P3~3Lf98hnKvrqaz7B zNj|R~UErItJYSyMiRB@$;bB6-&#kZewwctuWF&%8lJn*9Qo|+G5SJjUTZqWpz3<15 z$vkZ9hPhS6la;)KLqUgNW5npozELtC_`QYR9F$&^rXwxZY2+~?-y4zcFmWJ=OWcZ* z*um;HxT_(?Cf85FZ0%{^9w)zv?H z53j)tq@L-}YWC}M$Mu;dS(&>Ds~eH>`_cT_t0jxPb&gd3YHXkLL4R z>&utjYUgID!VfPb{)-<9dIFXebQi#e?!xEP!--!LnJ$J%`0BC)zV-yH?BTh;DGAa@ zr^%`MArb3^bxIK{$_9o>6O{Vk3qk`K<}nR-wZ(h0)$)Gn&lEZVZtOO)O=BlSz2(poEtP&J<~cD&Ip`m_MHMSB z+GsJoW^a1)b94{;_%>n6gv(CMb9j1pVX%n= z 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 literal 0 HcmV?d00001 diff --git a/boards/arm/stm32u5a9j_dk/doc/index.rst b/boards/arm/stm32u5a9j_dk/doc/index.rst new file mode 100644 index 000000000000000..166dc21676ef056 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/doc/index.rst @@ -0,0 +1,186 @@ +.. _stm32u5a9j_dk_board: + +ST STM32U5A9J Discovery Kit +########################### + +Overview +******** + +The STM32U5A9J-DK Discovery kit is a complete demonstration and development +platform for the STM32U5A9NJH6Q microcontroller, featuring an Arm® Cortex®-M33 +core with Arm® TrustZone®. + +Leveraging the innovative ultra-low-power oriented features, 2.5 Mbytes of +embedded SRAM, 4 Mbytes of embedded flash memory, and rich graphics features, +the STM32U5A9J-DK Discovery kit enables users to easily prototype applications +with state-of-the-art energy efficiency, as well as providing stunning and +optimized graphics rendering with the support of the 2.5D NeoChrom Accelerator, +Chrom-ART Accelerator, and Chrom-GRC™ MMU. + +The full range of hardware features available on the board helps users to +enhance their application development by an evaluation of all the peripherals +such as a 2.47-inch RGB 480x480 pixels TFT round LCD module with MIPI DSI® +interface and capacitive touch panel, USB Type-C® HS, Octo-SPI flash memory +device, Hexadeca-SPI PSRAM memory device, eMMC flash memory device, +Time-of-Flight and gesture detection sensor, temperature sensor, and two 2.54 mm +pitch double-row flexible expansion connectors for easy prototyping with +daughterboards for specific applications (USART, LPUART, two SPIs, SAI, three +I2C, SDMMC, ADCs, timers, and GPIOs). + +The STM32U5A9J-DK Discovery kit integrates an STLINK-V3E embedded in-circuit +debugger and programmer for the STM32 microcontroller with a USB Virtual COM +port bridge and comes with the STM32CubeU5 MCU Package, which provides an STM32 +comprehensive software HAL library as well as various software examples. + +.. image:: img/top_view.jpg + :align: center + :alt: STM32U5A9J-DK Top View + +.. image:: img/bottom_view.jpg + :align: center + :alt: STM32U5A9J-DK Bottom View + +More information about the board can be found at the `STM32U5A9J-DK website`_. +More information about STM32U5A9NJH6Q can be found here: + +- `STM32U5A9NJ on www.st.com`_ +- `STM32U5 Series reference manual`_ +- `STM32U5Axxx datasheet`_ + +Supported Features +================== + +The current Zephyr stm32u5a9j_dk board configuration supports the following +hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| LPUART | on-chip | low power uart | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| FLASH | on-chip | flash memory | ++-----------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ +| SDMMC | on-chip | flash memory | ++-----------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-------------------------------------+ + +Other hardware features have not been enabled yet for this board. + +The default configuration per core can be found in the defconfig file: +``boards/arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig`` + +Pin Mapping +=========== + +For mode details please refer to `STM32U5A9J-DK board User Manual`_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- USART_1 TX/RX : PA9/PA10 (ST-Link Virtual Port Com) +- LD3 : PE0 +- LD4 : PE1 +- User Button: PC13 +- USART_3 TX/RX : PB10/PB11 +- LPUART_1 TX/RX : PG7/PG8 +- I2C1 SCL/SDA : PG14/PG13 +- I2C2 SCL/SDA : PF1/PF0 +- I2C6 SCL/SDA : PD1/PD0 +- SPI2 SCK/MISO/MOSI/CS : PB13/PD3/PD4/PB12 +- SPI3 SCK/MISO/MOSI/CS : PG9/PG10/PG11/PG15 +- ADC1 : channel5 PA0, channel14 PC5 +- ADC2 : channel9 PA4 +- ADC4 : channel5 PF14 + +System Clock +============ + +The STM32U5A9J-DK Discovery kit relies on an HSE oscillator (16 MHz crystal) +and an LSE oscillator (32.768 kHz crystal) as clock references. +Using the HSE (instead of HSI) is mandatory to manage the DSI interface for +the LCD module and the USB high‑speed interface. + +Serial Port +=========== + +The STM32U5A9J Discovery kit has up to 4 USARTs, 2 UARTs, and 1 LPUART. +The Zephyr console output is assigned to USART1 which connected to the onboard +ST-LINK/V3.0. Virtual COM port interface. Default communication settings are +115200 8N1. + + +Programming +*********** + +STM32U5A9J Discovery kit includes an ST-LINK/V3 embedded debug tool interface. +This probe allows to flash the board using various tools. + +Flashing +======== + +Board is configured to be flashed using west STM32CubeProgrammer runner. +Installation of `STM32CubeProgrammer`_ is then required to flash the board., + +Connect the STM32U5A9J Discovery board to your host computer using the USB +port, then run a serial host program to connect with your Discovery +board. For example: + +.. code-block:: console + + $ minicom -D /dev/ttyACM0 -b 115200 + +Then, build and flash in the usual way. Here is an example for the +:ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32u5a9j_dk + :goals: build flash + +You should see the following message on the console: + +.. code-block:: console + + Hello World! stm32u5a9j_dk + + +.. _STM32U5A9J-DK website: + https://www.st.com/en/evaluation-tools/stm32u5a9j-dk.html + +.. _STM32U5A9J-DK board User Manual: + https://www.st.com/resource/en/user_manual/um2967-discovery-kit-with-stm32u5a9nj-mcu-stmicroelectronics.pdf + +.. _STM32U5A9NJ on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32u5a9nj.html + +.. _STM32U5 Series reference manual: + https://www.st.com/resource/en/reference_manual/rm0456-stm32u5-series-armbased-32bit-mcus-stmicroelectronics.pdf + +.. _STM32U5Axxx datasheet: + https://www.st.com/resource/en/datasheet/stm32u5a9nj.pdf + +.. _STM32CubeProgrammer: + https://www.st.com/en/development-tools/stm32cubeprog.html + +.. _STM32U5A9J_DK board schematics: + https://www.st.com/resource/en/schematic_pack/mb1829-u5a9njq-b01-schematic.pdf diff --git a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts new file mode 100644 index 000000000000000..f236354c6f2b4f6 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32U5A9J DISCOVERY KIT board"; + compatible = "st,stm32u5a9j-dk"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + green_led_0: led_3 { + gpios = <&gpioe 0 GPIO_ACTIVE_HIGH>; + label = "User LD3"; + }; + red_led_0: led_4 { + gpios = <&gpioe 1 GPIO_ACTIVE_HIGH>; + label = "User LD4"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button_0 { + label = "User"; + gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + dsi_lcd_qsh_030: connector_dsi_lcd { + compatible = "st,dsi-lcd-qsh-030"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <4 0 &gpioe 8 0>, /* TOUCH_INT */ + <22 0 &gpiod 8 0>, /* SPI chip SEL */ + <24 0 &gpiob 13 0>, /* SPI CLK */ + <26 0 &gpiod 4 0>, /* SPI MOSI */ + <28 0 &gpiod 11 0>, /* SPI DCX */ + <35 0 &gpioe 5 0>, /* SCLK/MCLK */ + <37 0 &gpioe 4 0>, /* LRCLK */ + <40 0 &gpioh 4 0>, /* I2C5_SDA */ + <43 0 &gpioi 7 0>, /* SWIRE */ + <44 0 &gpioh 5 0>, /* I2C5_SCL */ + <49 0 &gpiof 11 0>, /* DSI_TE */ + <53 0 &gpioi 6 0>, /* LCD_BL_CTRL */ + <57 0 &gpiod 5 0>; /* DSI_RESET */ + }; + + aliases { + led0 = &green_led_0; + led1 = &red_led_0; + sw0 = &user_button; + sdhc0 = &sdmmc1; + watchdog0 = &iwdg; + die-temp0 = &die_temp; + volt-sensor0 = &vref1; + volt-sensor1 = &vbat4; + }; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +&clk_msis { + status = "okay"; + msi-range = <4>; /* 4MHz (reset value) */ + msi-pll-mode; +}; + +&pll1 { + div-m = <1>; + mul-n = <80>; + div-p = <2>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_msis>; + status = "okay"; +}; + +&rcc { + clocks = <&pll1>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb3-prescaler = <1>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +uart0: &usart3 { + pinctrl-0 = <&usart3_tx_pb10 &usart3_rx_pb11>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&lpuart1 { + pinctrl-0 = <&lpuart1_tx_pg7 &lpuart1_rx_pg8>; + pinctrl-names = "default"; + current-speed = <9600>; + status = "okay"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pg14 &i2c1_sda_pg13>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_pf1 &i2c2_sda_pf0>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&i2c6 { + pinctrl-0 = <&i2c6_scl_pd1 &i2c6_sda_pd0>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&spi2 { + pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pd3 &spi2_mosi_pd4>; + pinctrl-names = "default"; + cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; +}; + +&spi3 { + pinctrl-0 = <&spi3_sck_pg9 &spi3_miso_pg10 &spi3_mosi_pg11>; + pinctrl-names = "default"; + cs-gpios = <&gpiog 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; +}; + +&timers1 { + st,prescaler = <1>; + status = "okay"; + + pwm1: pwm { + status = "okay"; + pinctrl-0 = <&tim1_ch2_pe11>; + pinctrl-names = "default"; + }; +}; + +&timers2 { + st,prescaler = <1>; + status = "okay"; + + pwm2: pwm { + status = "okay"; + pinctrl-0 = <&tim2_ch4_pa3>; + pinctrl-names = "default"; + }; +}; + +&sdmmc1 { + pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9 + &sdmmc1_d2_pc10 &sdmmc1_d3_pc11 + &sdmmc1_d4_pb8 &sdmmc1_d5_pb9 + &sdmmc1_d6_pc6 &sdmmc1_d7_pc7 + &sdmmc1_ck_pc12 &sdmmc1_cmd_pd2>; + pinctrl-names = "default"; + status = "okay"; +}; + +&sdmmc2 { + pinctrl-0 = <&sdmmc2_d0_pb14 &sdmmc2_d1_pb15 + &sdmmc2_d2_pb3 &sdmmc2_d3_pb4 + &sdmmc2_ck_pd6 &sdmmc2_cmd_pd7>; + pinctrl-names = "default"; + status = "okay"; +}; + +&adc1 { + pinctrl-0 = <&adc1_in5_pa0 &adc1_in14_pc5>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <1>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@5 { + reg = <0x5>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; + + channel@e { + reg = <0xe>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; +}; + +&adc4 { + pinctrl-0 = <&adc4_in5_pf14>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <1>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@5 { + reg = <0x5>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * Following flash partition is dedicated to the use of bootloader + */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(1952)>; + }; + slot1_partition: partition@1f8000 { + label = "image-1"; + reg = <0x001f8000 DT_SIZE_K(1960)>; + }; + storage_partition: partition@3e2000 { + label = "storage"; + reg = <0x003e2000 DT_SIZE_K(120)>; + }; + }; +}; + +&iwdg { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&die_temp { + status = "okay"; +}; + +&vref1 { + status = "okay"; +}; + +&vbat4 { + status = "okay"; +}; diff --git a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.yaml b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.yaml new file mode 100644 index 000000000000000..82ada8651e9014c --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.yaml @@ -0,0 +1,23 @@ +identifier: stm32u5a9j_dk +name: ST STM32U5A9J-DK Discovery Kit +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - led + - button + - adc + - uart + - usart + - lpuart + - watchdog + - spi + - i2c + - flash + - sdmmc +ram: 2496 +flash: 4096 +vendor: st diff --git a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig new file mode 100644 index 000000000000000..71e92cf0450d6a0 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig @@ -0,0 +1,28 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +# Set SoC present on the board +CONFIG_SOC_SERIES_STM32U5X=y +CONFIG_SOC_STM32U5A9XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable serial +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable clocks +CONFIG_CLOCK_CONTROL=y + +# Enable pinctrl +CONFIG_PINCTRL=y From ebf67b2cef9157c5d02d3b0ca387f7e1b9f9d884 Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Wed, 8 Nov 2023 15:02:50 +0100 Subject: [PATCH 0763/1049] test: drivers: adc_api: add overlay for STM32U5A9J Add overlay for STM32U5A9J board to pass test in CI Signed-off-by: Abderrahmane Jarmouni --- .../drivers/adc/adc_api/boards/stm32u5a9j_dk.overlay | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/stm32u5a9j_dk.overlay diff --git a/tests/drivers/adc/adc_api/boards/stm32u5a9j_dk.overlay b/tests/drivers/adc/adc_api/boards/stm32u5a9j_dk.overlay new file mode 100644 index 000000000000000..83335cd9aa4efdf --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/stm32u5a9j_dk.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 5>; + }; +}; From 053c6b29cc8589120eda54f78f7beff5f966c91a Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Fri, 10 Nov 2023 18:00:47 +0100 Subject: [PATCH 0764/1049] boards: arm: stm32u5a9j-dk: add OpenOCD support Add support for debugging with OpenOCD and GDB Signed-off-by: Abderrahmane Jarmouni --- boards/arm/stm32u5a9j_dk/board.cmake | 6 ++- boards/arm/stm32u5a9j_dk/doc/index.rst | 18 ++++++-- boards/arm/stm32u5a9j_dk/support/openocd.cfg | 46 ++++++++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 boards/arm/stm32u5a9j_dk/support/openocd.cfg diff --git a/boards/arm/stm32u5a9j_dk/board.cmake b/boards/arm/stm32u5a9j_dk/board.cmake index 597c0c8b676b56f..dadc06c643e0895 100644 --- a/boards/arm/stm32u5a9j_dk/board.cmake +++ b/boards/arm/stm32u5a9j_dk/board.cmake @@ -3,5 +3,9 @@ board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw") +board_runner_args(openocd "--tcl-port=6666") +board_runner_args(openocd --cmd-pre-init "gdb_report_data_abort enable") +board_runner_args(openocd "--no-halt") + include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) -# FIXME: openocd runner not yet available. +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/stm32u5a9j_dk/doc/index.rst b/boards/arm/stm32u5a9j_dk/doc/index.rst index 166dc21676ef056..6e3e44c5942adf9 100644 --- a/boards/arm/stm32u5a9j_dk/doc/index.rst +++ b/boards/arm/stm32u5a9j_dk/doc/index.rst @@ -129,11 +129,11 @@ ST-LINK/V3.0. Virtual COM port interface. Default communication settings are 115200 8N1. -Programming -*********** +Programming and Debugging +************************* STM32U5A9J Discovery kit includes an ST-LINK/V3 embedded debug tool interface. -This probe allows to flash the board using various tools. +This probe allows to flash and debug the board using various tools. Flashing ======== @@ -163,6 +163,18 @@ You should see the following message on the console: Hello World! stm32u5a9j_dk +Debugging +========= + +Default debugger for this board is openocd. It could be used in the usual way +with "west debug" command. +Here is an example for the :zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: stm32u5a9j_dk + :goals: debug + .. _STM32U5A9J-DK website: https://www.st.com/en/evaluation-tools/stm32u5a9j-dk.html diff --git a/boards/arm/stm32u5a9j_dk/support/openocd.cfg b/boards/arm/stm32u5a9j_dk/support/openocd.cfg new file mode 100644 index 000000000000000..23e2409440fecae --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/support/openocd.cfg @@ -0,0 +1,46 @@ +source [find interface/stlink-dap.cfg] + +set WORKAREASIZE 0x8000 + +transport select "dapdirect_swd" + +set CHIPNAME STM32U5A9NJHxQ +set BOARDNAME STM32U5A9J_DK + +# Enable debug when in low power modes +set ENABLE_LOW_POWER 1 + +# Stop Watchdog counters when halt +set STOP_WATCHDOG 1 + +# STlink Debug clock frequency +set CLOCK_FREQ 8000 + +# Reset configuration +# use hardware reset, connect under reset +# connect_assert_srst needed if low power mode application running (WFI...) +reset_config srst_only srst_nogate connect_assert_srst +set CONNECT_UNDER_RESET 1 +set CORE_RESET 0 + +# ACCESS PORT NUMBER +set AP_NUM 0 +# GDB PORT +set GDB_PORT 3333 + +# BCTM CPU variables + +source [find target/stm32u5x.cfg] + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} + +gdb_memory_map disable From 43ef398614a765f04271680bbc46511bfbc71dba Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 7 Nov 2023 08:49:45 +0100 Subject: [PATCH 0765/1049] pm: add power management for stm32f4x Add soc power management for the STM32F4x chips. One low power state is added supported by all chips from the family - the Stop mode with voltage regulator in low-power mode. The Stop mode for STM32F chips has to work with the IDLE timer - CORTEX_M_SYSTICK_IDLE_TIMER, because PLL and HSI are disabled in the Stop mode (Systick is not clocked). The only possible wakeup source is RTC, which works as a IDLE timer for the Systick. The exit latency may need to be adjusted per system, depending on the system tick frequency and other variables. Signed-off-by: Dawid Niedzwiecki --- dts/arm/st/f4/stm32f4.dtsi | 18 +++- soc/arm/st_stm32/stm32f4/CMakeLists.txt | 4 + .../st_stm32/stm32f4/Kconfig.defconfig.series | 4 + soc/arm/st_stm32/stm32f4/Kconfig.series | 1 + soc/arm/st_stm32/stm32f4/power.c | 89 +++++++++++++++++++ 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 soc/arm/st_stm32/stm32f4/power.c diff --git a/dts/arm/st/f4/stm32f4.dtsi b/dts/arm/st/f4/stm32f4.dtsi index 36cbd9c8fed7f7b..f53c9cdf228228e 100644 --- a/dts/arm/st/f4/stm32f4.dtsi +++ b/dts/arm/st/f4/stm32f4.dtsi @@ -28,10 +28,26 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&stop>; + }; + + power-states { + stop: stop { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + /* It is really hard to establish these numbers precisely. + * We are basing on RTC as a wakeup source with 62,5us tick. + * It requires a proper margin. Additionally, sys_clock_announce + * works within system tick boundaries (100us by default), + * which also introduces some shift. + */ + min-residency-us = <400>; + exit-latency-us = <300>; + }; }; }; diff --git a/soc/arm/st_stm32/stm32f4/CMakeLists.txt b/soc/arm/st_stm32/stm32f4/CMakeLists.txt index e02052e39465329..021708b9d02db1a 100644 --- a/soc/arm/st_stm32/stm32f4/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32f4/CMakeLists.txt @@ -6,3 +6,7 @@ zephyr_sources( ) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +zephyr_sources_ifdef(CONFIG_PM + power.c + ) diff --git a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series index 14dea5bf4d2f850..28ed9cc3a555644 100644 --- a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series @@ -17,4 +17,8 @@ config TASK_WDT_HW_FALLBACK_DELAY depends on TASK_WDT_HW_FALLBACK default 200 +config PM + select COUNTER + select COUNTER_RTC_STM32_SUBSECONDS + endif # SOC_SERIES_STM32F4X diff --git a/soc/arm/st_stm32/stm32f4/Kconfig.series b/soc/arm/st_stm32/stm32f4/Kconfig.series index 6b8fdf80c7ba966..a4e65c97784e5a5 100644 --- a/soc/arm/st_stm32/stm32f4/Kconfig.series +++ b/soc/arm/st_stm32/stm32f4/Kconfig.series @@ -13,5 +13,6 @@ config SOC_SERIES_STM32F4X select HAS_STM32CUBE select CPU_HAS_ARM_MPU select HAS_SWO + select HAS_PM help Enable support for STM32F4 MCU series diff --git a/soc/arm/st_stm32/stm32f4/power.c b/soc/arm/st_stm32/stm32f4/power.c new file mode 100644 index 000000000000000..02b645ee9f191f8 --- /dev/null +++ b/soc/arm/st_stm32/stm32f4/power.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +BUILD_ASSERT(DT_SAME_NODE(DT_CHOSEN(zephyr_cortex_m_idle_timer), DT_NODELABEL(rtc)), + "STM32Fx series needs RTC as an additional IDLE timer for power management"); + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + LL_LPM_DisableEventOnPend(); + LL_PWR_ClearFlag_WU(); + /* According to datasheet (DS11139 Rev 8,Table 38.), wakeup with regulator in + * low-power mode takes typically 8us, max 13us more time than with the main + * regulator. We are using RTC as a wakeup source, which has a tick 62,5us. + * It means we have to add significant margin to the exit-latency anyway, + * so it is worth always using the low-power regulator. + */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU); + LL_LPM_EnableDeepSleep(); + + k_cpu_idle(); + + break; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); + + /* Restore the clock setup. */ + stm32_clock_control_init(NULL); + break; + default: + LOG_DBG("Unsupported power substate-id %u", state); + break; + } + + /* + * System is now in active mode. Reenable interrupts which were + * disabled when OS started idling code. + */ + irq_unlock(0); +} + +static int stm32_power_init(void) +{ + /* Enable Power clock. It should by done by default, but make sure to + * enable it for all STM32F4x chips. + */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); + + /* Enabling debug during STOP mode is done by the common STM32 configuration */ + return 0; +} + +SYS_INIT(stm32_power_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From e6c7a4c968f143673ccb63236353bd3a319ace52 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Fri, 10 Nov 2023 15:43:55 +0100 Subject: [PATCH 0766/1049] tests: pm: add soc pm tests and sample for stm32f4x chip Add soc power management test and blinky sample for the nucleo_f429zi board. Signed-off-by: Dawid Niedzwiecki --- .../stm32/power_mgmt/blinky/boards/nucleo_f429zi.conf | 2 ++ .../power_mgmt/blinky/boards/nucleo_f429zi.overlay | 11 +++++++++++ samples/boards/stm32/power_mgmt/blinky/sample.yaml | 4 +++- .../pm/power_mgmt_soc/boards/nucleo_f429zi.overlay | 11 +++++++++++ tests/subsys/pm/power_mgmt_soc/testcase.yaml | 1 + 5 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.conf create mode 100644 samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.overlay create mode 100644 tests/subsys/pm/power_mgmt_soc/boards/nucleo_f429zi.overlay diff --git a/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.conf b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.conf new file mode 100644 index 000000000000000..2035eb8c9557df9 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.conf @@ -0,0 +1,2 @@ +# Increase IDLE stack for the IDLE timer +CONFIG_IDLE_STACK_SIZE=640 diff --git a/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.overlay b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.overlay new file mode 100644 index 000000000000000..859c69df4140e4b --- /dev/null +++ b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,cortex-m-idle-timer = &rtc; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/blinky/sample.yaml b/samples/boards/stm32/power_mgmt/blinky/sample.yaml index 103f204a189dce8..04054268228961f 100644 --- a/samples/boards/stm32/power_mgmt/blinky/sample.yaml +++ b/samples/boards/stm32/power_mgmt/blinky/sample.yaml @@ -12,7 +12,9 @@ tests: - "Device ready" filter: dt_compat_enabled("zephyr,power-state") and dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and - dt_compat_enabled("st,stm32-lptim") + (dt_compat_enabled("st,stm32-lptim") or + dt_chosen_enabled("zephyr,cortex-m-idle-timer")) extra_args: "CONFIG_DEBUG=y" integration_platforms: - nucleo_wb55rg + - nucleo_f429zi diff --git a/tests/subsys/pm/power_mgmt_soc/boards/nucleo_f429zi.overlay b/tests/subsys/pm/power_mgmt_soc/boards/nucleo_f429zi.overlay new file mode 100644 index 000000000000000..859c69df4140e4b --- /dev/null +++ b/tests/subsys/pm/power_mgmt_soc/boards/nucleo_f429zi.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,cortex-m-idle-timer = &rtc; + }; +}; diff --git a/tests/subsys/pm/power_mgmt_soc/testcase.yaml b/tests/subsys/pm/power_mgmt_soc/testcase.yaml index 5d160d70b91a599..8fe974f0bfa4beb 100644 --- a/tests/subsys/pm/power_mgmt_soc/testcase.yaml +++ b/tests/subsys/pm/power_mgmt_soc/testcase.yaml @@ -5,6 +5,7 @@ tests: - cc1352r1_launchxl - mec15xxevb_assy6853 - mec1501modular_assy6885 + - nucleo_f429zi - nucleo_wb55rg - nucleo_l476rg - twr_ke18f From 16fd744c13a99be705cd2aa90bb1e6c1c931a2e3 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 14 Nov 2023 14:31:37 +0100 Subject: [PATCH 0767/1049] net: pkt: Add function for allocating buffers w/o preconditions Add new function to allocate additional buffers for net_pkt, w/o any additional preconditions/checks. Just allocate what was requested. Signed-off-by: Robert Lubos --- include/zephyr/net/net_pkt.h | 25 +++++++++++++++ subsys/net/ip/net_pkt.c | 61 ++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index 4f67249f15ba512..c5878213a0293e2 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -1707,6 +1707,13 @@ int net_pkt_alloc_buffer_debug(struct net_pkt *pkt, net_pkt_alloc_buffer_debug(_pkt, _size, _proto, _timeout, \ __func__, __LINE__) +int net_pkt_alloc_buffer_raw_debug(struct net_pkt *pkt, size_t size, + k_timeout_t timeout, + const char *caller, int line); +#define net_pkt_alloc_buffer_raw(_pkt, _size, _timeout) \ + net_pkt_alloc_buffer_raw_debug(_pkt, _size, _timeout, \ + __func__, __LINE__) + struct net_pkt *net_pkt_alloc_with_buffer_debug(struct net_if *iface, size_t size, sa_family_t family, @@ -1821,6 +1828,24 @@ int net_pkt_alloc_buffer(struct net_pkt *pkt, k_timeout_t timeout); #endif +/** + * @brief Allocate buffer for a net_pkt, of specified size, w/o any additional + * preconditions + * + * @details: The actual buffer size may be larger than requested one if fixed + * size buffers are in use. + * + * @param pkt The network packet requiring buffer to be allocated. + * @param size The size of buffer being requested. + * @param timeout Maximum time to wait for an allocation. + * + * @return 0 on success, negative errno code otherwise. + */ +#if !defined(NET_PKT_DEBUG_ENABLED) +int net_pkt_alloc_buffer_raw(struct net_pkt *pkt, size_t size, + k_timeout_t timeout); +#endif + /** * @brief Allocate a network packet and buffer at once * diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index ea60060abe578a5..38fc288d8f5c3d1 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -1197,6 +1197,67 @@ int net_pkt_alloc_buffer(struct net_pkt *pkt, return 0; } + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +int net_pkt_alloc_buffer_raw_debug(struct net_pkt *pkt, size_t size, + k_timeout_t timeout, const char *caller, + int line) +#else +int net_pkt_alloc_buffer_raw(struct net_pkt *pkt, size_t size, + k_timeout_t timeout) +#endif +{ + struct net_buf_pool *pool = NULL; + struct net_buf *buf; + + if (size == 0) { + return 0; + } + + if (k_is_in_isr()) { + timeout = K_NO_WAIT; + } + + NET_DBG("Data allocation size %zu", size); + + if (pkt->context) { + pool = get_data_pool(pkt->context); + } + + if (!pool) { + pool = pkt->slab == &tx_pkts ? &tx_bufs : &rx_bufs; + } + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + buf = pkt_alloc_buffer(pool, size, timeout, caller, line); +#else + buf = pkt_alloc_buffer(pool, size, timeout); +#endif + + if (!buf) { +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + NET_ERR("Data buffer (%zd) allocation failed (%s:%d)", + size, caller, line); +#else + NET_ERR("Data buffer (%zd) allocation failed.", size); +#endif + return -ENOMEM; + } + + net_pkt_append_buffer(pkt, buf); + +#if IS_ENABLED(CONFIG_NET_BUF_FIXED_DATA_SIZE) + /* net_buf allocators shrink the buffer size to the requested size. + * We don't want this behavior here, so restore the real size of the + * last fragment. + */ + buf = net_buf_frag_last(buf); + buf->size = CONFIG_NET_BUF_DATA_SIZE; +#endif + + return 0; +} + #if NET_LOG_LEVEL >= LOG_LEVEL_DBG static struct net_pkt *pkt_alloc(struct k_mem_slab *slab, k_timeout_t timeout, const char *caller, int line) From 9976ebb24b0c169c70d63a1ea0c6458376e85694 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 14 Nov 2023 12:40:49 +0100 Subject: [PATCH 0768/1049] net: tcp: Rework data queueing API Rework how data is queued for the TCP connections: * net_context no longer allocates net_pkt for TCP connections. This was not only inefficient (net_context has no knowledge of the TX window size), but also error-prone in certain configuration (for example when IP fragmentation was enabled, net_context may attempt to allocate enormous packet, instead of let the data be fragmented for the TCP stream. * Instead, implement already defined `net_tcp_queue()` API, which takes raw buffer and length. This allows to take TX window into account and also better manage the allocated net_buf's (like for example avoid allocation if there's still room in the buffer). In result, the TCP stack will not only no longer exceed the TX window, but also prevent empty gaps in allocated net_buf's, which should lead to less out-of-mem issues with the stack. * As net_pkt-based `net_tcp_queue_data()` is no longer in use, it was removed. Signed-off-by: Robert Lubos --- subsys/net/ip/net_context.c | 27 +++--- subsys/net/ip/tcp.c | 166 +++++++++++++++++++++-------------- subsys/net/ip/tcp.h | 15 +--- subsys/net/ip/tcp_internal.h | 20 +++-- 4 files changed, 132 insertions(+), 96 deletions(-) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 9cdcaadc8221cd7..a628297f650387d 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1726,7 +1726,7 @@ static int context_sendto(struct net_context *context, { const struct msghdr *msghdr = NULL; struct net_if *iface; - struct net_pkt *pkt; + struct net_pkt *pkt = NULL; size_t tmp_len; int ret; @@ -1948,6 +1948,15 @@ static int context_sendto(struct net_context *context, return -ENETDOWN; } + context->send_cb = cb; + context->user_data = user_data; + + if (IS_ENABLED(CONFIG_NET_TCP) && + net_context_get_proto(context) == IPPROTO_TCP && + !net_if_is_ip_offloaded(net_context_get_iface(context))) { + goto skip_alloc; + } + pkt = context_alloc_pkt(context, len, PKT_WAIT_TIME); if (!pkt) { NET_ERR("Failed to allocate net_pkt"); @@ -1966,9 +1975,6 @@ static int context_sendto(struct net_context *context, len = tmp_len; } - context->send_cb = cb; - context->user_data = user_data; - if (IS_ENABLED(CONFIG_NET_CONTEXT_PRIORITY)) { uint8_t priority; @@ -1990,6 +1996,7 @@ static int context_sendto(struct net_context *context, } } +skip_alloc: if (IS_ENABLED(CONFIG_NET_OFFLOAD) && net_if_is_ip_offloaded(net_context_get_iface(context))) { ret = context_write_data(pkt, buf, len, msghdr); @@ -2021,16 +2028,12 @@ static int context_sendto(struct net_context *context, } else if (IS_ENABLED(CONFIG_NET_TCP) && net_context_get_proto(context) == IPPROTO_TCP) { - ret = context_write_data(pkt, buf, len, msghdr); + ret = net_tcp_queue(context, buf, len, msghdr); if (ret < 0) { goto fail; } - net_pkt_cursor_init(pkt); - ret = net_tcp_queue_data(context, pkt); - if (ret < 0) { - goto fail; - } + len = ret; ret = net_tcp_send_data(context, cb, user_data); } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && @@ -2086,7 +2089,9 @@ static int context_sendto(struct net_context *context, return len; fail: - net_pkt_unref(pkt); + if (pkt != NULL) { + net_pkt_unref(pkt); + } return ret; } diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 82faa777694781a..2d0f753ca911585 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -1347,6 +1347,49 @@ static int tcp_pkt_peek(struct net_pkt *to, struct net_pkt *from, size_t pos, return net_pkt_copy(to, from, len); } +static int tcp_pkt_append(struct net_pkt *pkt, const uint8_t *data, size_t len) +{ + size_t alloc_len = len; + struct net_buf *buf = NULL; + int ret = 0; + + if (pkt->buffer) { + buf = net_buf_frag_last(pkt->buffer); + + if (len > net_buf_tailroom(buf)) { + alloc_len -= net_buf_tailroom(buf); + } else { + alloc_len = 0; + } + } + + if (alloc_len > 0) { + ret = net_pkt_alloc_buffer_raw(pkt, alloc_len, + TCP_PKT_ALLOC_TIMEOUT); + if (ret < 0) { + return -ENOBUFS; + } + } + + if (buf == NULL) { + buf = pkt->buffer; + } + + while (buf != NULL && len > 0) { + size_t write_len = MIN(len, net_buf_tailroom(buf)); + + net_buf_add_mem(buf, data, write_len); + + data += write_len; + len -= write_len; + buf = buf->frags; + } + + NET_ASSERT(len == 0, "Not all bytes written"); + + return ret; +} + static bool tcp_window_full(struct tcp *conn) { bool window_full = (conn->send_data_total >= conn->send_win); @@ -3229,13 +3272,12 @@ int net_tcp_update_recv_wnd(struct net_context *context, int32_t delta) return ret; } -/* net_context queues the outgoing data for the TCP connection */ -int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt) +int net_tcp_queue(struct net_context *context, const void *data, size_t len, + const struct msghdr *msg) { struct tcp *conn = context->tcp; - struct net_buf *orig_buf = NULL; + size_t queued_len = 0; int ret = 0; - size_t len; if (!conn || conn->state != TCP_ESTABLISHED) { return -ENOTCONN; @@ -3252,72 +3294,69 @@ int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt) goto out; } - len = net_pkt_get_len(pkt); + if (msg) { + len = 0; - if (conn->send_data->buffer) { - orig_buf = net_buf_frag_last(conn->send_data->buffer); + for (int i = 0; i < msg->msg_iovlen; i++) { + len += msg->msg_iov[i].iov_len; + } } - net_pkt_append_buffer(conn->send_data, pkt->buffer); - conn->send_data_total += len; - NET_DBG("conn: %p Queued %zu bytes (total %zu)", conn, len, - conn->send_data_total); - pkt->buffer = NULL; + /* Queue no more than TX window permits. It's guaranteed at this point + * that conn->send_data_total is less than conn->send_win, as it was + * verified in tcp_window_full() check above. As the connection mutex + * is held, their values shall not change since. + */ + len = MIN(conn->send_win - conn->send_data_total, len); + + if (msg) { + for (int i = 0; i < msg->msg_iovlen; i++) { + int iovlen = MIN(msg->msg_iov[i].iov_len, len); + + ret = tcp_pkt_append(conn->send_data, + msg->msg_iov[i].iov_base, + iovlen); + if (ret < 0) { + if (queued_len == 0) { + goto out; + } else { + break; + } + } + queued_len += iovlen; + len -= iovlen; + + if (len == 0) { + break; + } + } + } else { + ret = tcp_pkt_append(conn->send_data, data, len); + if (ret < 0) { + goto out; + } + + queued_len = len; + } + + conn->send_data_total += queued_len; + + /* Successfully queued data for transmission. Even if there's a transmit + * failure now (out-of-buf case), it can be ignored for now, retransmit + * timer will take care of queued data retransmission. + */ ret = tcp_send_queued_data(conn); if (ret < 0 && ret != -ENOBUFS) { tcp_conn_close(conn, ret); goto out; } - if ((ret == -ENOBUFS) && - (conn->send_data_total < (conn->unacked_len + len))) { - /* Some of the data has been sent, we cannot remove the - * whole chunk, the remainder portion is already - * in the send_data and will be transmitted upon a - * received ack or the next send call - * - * Set the return code back to 0 to pretend we just - * transmitted the chunk - */ - ret = 0; + if (tcp_window_full(conn)) { + (void)k_sem_take(&conn->tx_sem, K_NO_WAIT); } - if (ret == -ENOBUFS) { - /* Restore the original data so that we do not resend the pkt - * data multiple times. - */ - conn->send_data_total -= len; - - if (orig_buf) { - pkt->buffer = orig_buf->frags; - orig_buf->frags = NULL; - } else { - pkt->buffer = conn->send_data->buffer; - conn->send_data->buffer = NULL; - } - - /* If we have out-of-bufs case, and the send_data buffer has - * become empty, till the retransmit timer, as there is no - * data to retransmit. - * The socket layer will catch this and resend data if needed. - * Only perform this when it is just the newly added packet, - * otherwise it can disrupt any pending transmission - */ - if (conn->send_data_total == 0) { - NET_DBG("No bufs, cancelling retransmit timer"); - k_work_cancel_delayable(&conn->send_data_timer); - } - } else { - if (tcp_window_full(conn)) { - (void)k_sem_take(&conn->tx_sem, K_NO_WAIT); - } - - /* We should not free the pkt if there was an error. It will be - * freed in net_context.c:context_sendto() - */ - tcp_pkt_unref(pkt); - } + ret = queued_len; out: k_mutex_unlock(&conn->lock); @@ -3674,7 +3713,9 @@ static size_t tp_tcp_recv_cb(struct tcp *conn, struct net_pkt *pkt) net_pkt_pull(up, net_pkt_get_len(up) - len); - net_tcp_queue_data(conn->context, up); + for (struct net_buf *buf = pkt->buffer; buf != NULL; buf = buf->frags) { + net_tcp_queue(conn->context, buf->data, buf->len); + } return len; } @@ -3817,12 +3858,7 @@ enum net_verdict tp_input(struct net_conn *net_conn, responded = true; NET_DBG("tcp_send(\"%s\")", tp->data); { - struct net_pkt *data_pkt; - - data_pkt = tcp_pkt_alloc(conn, len); - net_pkt_write(data_pkt, buf, len); - net_pkt_cursor_init(data_pkt); - net_tcp_queue_data(conn->context, data_pkt); + net_tcp_queue(conn->context, buf, len); } } break; diff --git a/subsys/net/ip/tcp.h b/subsys/net/ip/tcp.h index 77d5c5634a6ccc8..975f2a97624b85d 100644 --- a/subsys/net/ip/tcp.h +++ b/subsys/net/ip/tcp.h @@ -31,6 +31,7 @@ extern "C" { #endif +#include #include /** @@ -72,18 +73,7 @@ int net_tcp_listen(struct net_context *context); */ int net_tcp_accept(struct net_context *context, net_tcp_accept_cb_t cb, void *user_data); -/** - * @brief Enqueue data for transmission - * - * @param context Network context - * @param buf Pointer to the data - * @param len Number of bytes - * @param msghdr Data for a vector array operation - * - * @return 0 if ok, < 0 if error - */ -int net_tcp_queue(struct net_context *context, const void *buf, size_t len, - const struct msghdr *msghdr); + /* TODO: split into 2 functions, conn -> context, queue -> send? */ /* The following functions are provided solely for the compatibility @@ -112,7 +102,6 @@ void net_tcp_init(void); #define net_tcp_init(...) #endif int net_tcp_update_recv_wnd(struct net_context *context, int32_t delta); -int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt); int net_tcp_finalize(struct net_pkt *pkt, bool force_chksum); #if defined(CONFIG_NET_TEST_PROTOCOL) diff --git a/subsys/net/ip/tcp_internal.h b/subsys/net/ip/tcp_internal.h index 49edae13f687da3..1dd3f23553282fc 100644 --- a/subsys/net/ip/tcp_internal.h +++ b/subsys/net/ip/tcp_internal.h @@ -283,21 +283,27 @@ struct net_tcp_hdr *net_tcp_input(struct net_pkt *pkt, #endif /** - * @brief Enqueue a single packet for transmission + * @brief Enqueue data for transmission * - * @param context TCP context - * @param pkt Packet + * @param context Network context + * @param data Pointer to the data + * @param len Number of bytes + * @param msg Data for a vector array operation * * @return 0 if ok, < 0 if error */ #if defined(CONFIG_NET_NATIVE_TCP) -int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt); +int net_tcp_queue(struct net_context *context, const void *data, size_t len, + const struct msghdr *msg); #else -static inline int net_tcp_queue_data(struct net_context *context, - struct net_pkt *pkt) +static inline int net_tcp_queue(struct net_context *context, const void *data, + size_t len, const struct msghdr *msg) { ARG_UNUSED(context); - ARG_UNUSED(pkt); + ARG_UNUSED(data); + ARG_UNUSED(len); + ARG_UNUSED(msg); + return -EPROTONOSUPPORT; } #endif From 3a38ec1aaac77224f826a44150cde7118660a49f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 15 Nov 2023 16:32:22 +0100 Subject: [PATCH 0769/1049] net: tcp: Feed TX semaphore on connection close Otherwise, if the application was for example blocked on poll() pending POLLOUT, it won't be notified. Signed-off-by: Robert Lubos --- subsys/net/ip/tcp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 2d0f753ca911585..6ffd688a20f2c98 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -638,6 +638,8 @@ static int tcp_conn_close(struct tcp *conn, int status) status, conn->recv_user_data); } + k_sem_give(&conn->tx_sem); + return tcp_conn_unref(conn); } From e6d90b409bba74c198c82db5f3882f5e996c7dcc Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 15 Nov 2023 16:33:24 +0100 Subject: [PATCH 0770/1049] net: sockets: tls: Set errno on TX waiting error In case underlying socket reported error while waiting for TX, the errno value was not set accordingly. This commit fixes this. Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/sockets_tls.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index 14b1de26af33a61..c83d2c18b80e4d6 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -2230,10 +2230,9 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf, timeout_ms = timeout_to_ms(&timeout); ret = wait_for_reason(ctx->sock, timeout_ms, ret); if (ret != 0) { - /* Retry. */ + errno = -ret; break; } - } else { (void)tls_mbedtls_reset(ctx); errno = EIO; From aa6f698d310c37c97d29ec33b7c9730a0c880039 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 15 Nov 2023 17:49:00 +0100 Subject: [PATCH 0771/1049] net: zperf: Fix TCP packet counting Make sure we send the entire packet buffer before bumping the packet counter, send() does not guarantee that all of the requested data will be sent at once with STREAM socket. Signed-off-by: Robert Lubos --- subsys/net/lib/zperf/zperf_tcp_uploader.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/zperf/zperf_tcp_uploader.c b/subsys/net/lib/zperf/zperf_tcp_uploader.c index 3e72f81e54bcb46..5fcc0530c5c6317 100644 --- a/subsys/net/lib/zperf/zperf_tcp_uploader.c +++ b/subsys/net/lib/zperf/zperf_tcp_uploader.c @@ -20,6 +20,22 @@ static char sample_packet[PACKET_SIZE_MAX]; static struct zperf_async_upload_context tcp_async_upload_ctx; +static ssize_t sendall(int sock, const void *buf, size_t len) +{ + while (len) { + ssize_t out_len = zsock_send(sock, buf, len, 0); + + if (out_len < 0) { + return out_len; + } + + buf = (const char *)buf + out_len; + len -= out_len; + } + + return 0; +} + static int tcp_upload(int sock, unsigned int duration_in_ms, unsigned int packet_size, @@ -50,7 +66,7 @@ static int tcp_upload(int sock, do { /* Send the packet */ - ret = zsock_send(sock, sample_packet, packet_size, 0); + ret = sendall(sock, sample_packet, packet_size); if (ret < 0) { if (nb_errors == 0 && ret != -ENOMEM) { NET_ERR("Failed to send the packet (%d)", errno); From 7c72d4a2d6335ba0a37babfba34abad363b0932d Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 16 Nov 2023 15:03:17 -0600 Subject: [PATCH 0772/1049] net: Fix CMakeLists Fix the CMakeLists of the tls_credentials and sockets folders to link/interface to the net library instead of the zephyr library. This fixes issues where some files are not found in the link interface when compiling the sources in this folder. Signed-off-by: Declan Snyder --- subsys/net/lib/sockets/CMakeLists.txt | 28 +++++++++---------- subsys/net/lib/tls_credentials/CMakeLists.txt | 10 ++++--- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/subsys/net/lib/sockets/CMakeLists.txt b/subsys/net/lib/sockets/CMakeLists.txt index 2a87ef1c4490040..7ffd6dc476b9597 100644 --- a/subsys/net/lib/sockets/CMakeLists.txt +++ b/subsys/net/lib/sockets/CMakeLists.txt @@ -5,37 +5,37 @@ zephyr_syscall_header( ${ZEPHYR_BASE}/include/zephyr/net/socket_select.h ) -zephyr_include_directories(.) +zephyr_library_include_directories(.) -zephyr_sources( +zephyr_library_sources( getaddrinfo.c sockets.c sockets_select.c ) if(NOT CONFIG_NET_SOCKETS_OFFLOAD) -zephyr_sources( +zephyr_library_sources( getnameinfo.c sockets_misc.c ) endif() -zephyr_sources_ifdef(CONFIG_NET_SOCKETS_CAN sockets_can.c) -zephyr_sources_ifdef(CONFIG_NET_SOCKETS_PACKET sockets_packet.c) -zephyr_sources_ifdef(CONFIG_NET_SOCKETS_SOCKOPT_TLS sockets_tls.c) -zephyr_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD socket_offload.c) -zephyr_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD_DISPATCHER socket_dispatcher.c) -zephyr_sources_ifdef(CONFIG_NET_SOCKETS_OBJ_CORE socket_obj_core.c) +zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_CAN sockets_can.c) +zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_PACKET sockets_packet.c) +zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_SOCKOPT_TLS sockets_tls.c) +zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD socket_offload.c) +zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD_DISPATCHER socket_dispatcher.c) +zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_OBJ_CORE socket_obj_core.c) if(CONFIG_NET_SOCKETS_NET_MGMT) - zephyr_sources(sockets_net_mgmt.c) - zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/ip) + zephyr_library_sources(sockets_net_mgmt.c) + zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) endif() if(CONFIG_SOCKS) - zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/lib/socks) + zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/lib/socks) endif() -zephyr_sources_ifdef(CONFIG_NET_SOCKETPAIR socketpair.c) +zephyr_library_sources_ifdef(CONFIG_NET_SOCKETPAIR socketpair.c) -zephyr_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) +zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) diff --git a/subsys/net/lib/tls_credentials/CMakeLists.txt b/subsys/net/lib/tls_credentials/CMakeLists.txt index 8acb4a5f4f104b3..490a558953d9b5b 100644 --- a/subsys/net/lib/tls_credentials/CMakeLists.txt +++ b/subsys/net/lib/tls_credentials/CMakeLists.txt @@ -1,15 +1,17 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_include_directories(.) +zephyr_library_include_directories(.) -zephyr_sources_ifdef(CONFIG_TLS_CREDENTIALS_BACKEND_VOLATILE +zephyr_library_sources_ifdef(CONFIG_TLS_CREDENTIALS_BACKEND_VOLATILE tls_credentials.c tls_credentials_digest_raw.c ) -zephyr_sources_ifdef(CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE +zephyr_library_sources_ifdef(CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE tls_credentials_trusted.c tls_credentials_digest_raw.c ) -zephyr_sources_ifdef(CONFIG_TLS_CREDENTIALS_SHELL +zephyr_library_sources_ifdef(CONFIG_TLS_CREDENTIALS_SHELL tls_credentials_shell.c ) + +zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) From cf42b8b2fbda3bdade4aabada9d4ebbdd91813c9 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Fri, 17 Nov 2023 09:58:05 -0600 Subject: [PATCH 0773/1049] net: sockets: fix shadowing warning Fix compiler local variable shadowing warning Rename ret to bytes_sent in offending funciton Signed-off-by: Declan Snyder --- subsys/net/lib/sockets/sockets.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index b10b9136272c22d..d35317352c97638 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -847,13 +847,13 @@ ssize_t zsock_sendto_ctx(struct net_context *ctx, const void *buf, size_t len, ssize_t z_impl_zsock_sendto(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { - int ret; + int bytes_sent; - ret = VTABLE_CALL(sendto, sock, buf, len, flags, dest_addr, addrlen); + bytes_sent = VTABLE_CALL(sendto, sock, buf, len, flags, dest_addr, addrlen); - sock_obj_core_update_send_stats(sock, ret); + sock_obj_core_update_send_stats(sock, bytes_sent); - return ret; + return bytes_sent; } #ifdef CONFIG_USERSPACE @@ -932,13 +932,13 @@ ssize_t zsock_sendmsg_ctx(struct net_context *ctx, const struct msghdr *msg, ssize_t z_impl_zsock_sendmsg(int sock, const struct msghdr *msg, int flags) { - int ret; + int bytes_sent; - ret = VTABLE_CALL(sendmsg, sock, msg, flags); + bytes_sent = VTABLE_CALL(sendmsg, sock, msg, flags); - sock_obj_core_update_send_stats(sock, ret); + sock_obj_core_update_send_stats(sock, bytes_sent); - return ret; + return bytes_sent; } #ifdef CONFIG_USERSPACE @@ -1498,13 +1498,13 @@ ssize_t zsock_recvfrom_ctx(struct net_context *ctx, void *buf, size_t max_len, ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { - int ret; + int bytes_received; - ret = VTABLE_CALL(recvfrom, sock, buf, max_len, flags, src_addr, addrlen); + bytes_received = VTABLE_CALL(recvfrom, sock, buf, max_len, flags, src_addr, addrlen); - sock_obj_core_update_recv_stats(sock, ret); + sock_obj_core_update_recv_stats(sock, bytes_received); - return ret; + return bytes_received; } #ifdef CONFIG_USERSPACE From bc8b5b3813d0836e93af076a7f8ae31d0758de0d Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 20 Nov 2023 13:36:27 +0200 Subject: [PATCH 0774/1049] mgmt: updatehub: Fix CMakeLists.txt file Fix the CMakeLists of the updatehub to link with mbedtls. Signed-off-by: Jukka Rissanen --- subsys/mgmt/updatehub/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/mgmt/updatehub/CMakeLists.txt b/subsys/mgmt/updatehub/CMakeLists.txt index b71f17fab1b0334..067e6168d97921a 100644 --- a/subsys/mgmt/updatehub/CMakeLists.txt +++ b/subsys/mgmt/updatehub/CMakeLists.txt @@ -23,3 +23,5 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE updatehub_handlers.c) zephyr_include_directories( ${ZEPHYR_BASE}/subsys/mgmt/updatehub/include ) + +zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) From f70e4c0f6803724d9fc5205fc77daa5a61ce0f0a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 20 Nov 2023 13:46:00 +0200 Subject: [PATCH 0775/1049] drivers: modem: Fix include paths Set the include paths properly and unconditionally to needed networking directories. Signed-off-by: Jukka Rissanen --- drivers/modem/CMakeLists.txt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/modem/CMakeLists.txt b/drivers/modem/CMakeLists.txt index 96a10be34fb3a54..a97568dfc65c519 100644 --- a/drivers/modem/CMakeLists.txt +++ b/drivers/modem/CMakeLists.txt @@ -12,33 +12,30 @@ zephyr_library_sources_ifdef(CONFIG_MODEM_IFACE_UART_ASYNC modem_iface_uart_asyn zephyr_library_sources_ifdef(CONFIG_MODEM_CMD_HANDLER modem_cmd_handler.c) zephyr_library_sources_ifdef(CONFIG_MODEM_SOCKET modem_socket.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) +zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/lib/sockets) + if(CONFIG_MODEM_UBLOX_SARA) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(ublox-sara-r4.c) endif() if(CONFIG_MODEM_QUECTEL_BG9X) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(quectel-bg9x.c) endif() if(CONFIG_MODEM_WNCM14A2A) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(wncm14a2a.c) endif() if(CONFIG_MODEM_GSM_PPP) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(gsm_ppp.c) endif() if (CONFIG_MODEM_HL7800) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(hl7800.c) endif() if (CONFIG_MODEM_SIM7080) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(simcom-sim7080.c) endif() From 4cc80097d3c2c90aa0e58164df024b5a62eeb887 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 20 Nov 2023 10:06:14 -0600 Subject: [PATCH 0776/1049] drivers: wifi: include sockets headers Some wifi drivers need internal sockets headers included to build, put this in CMakeLists Signed-off-by: Declan Snyder --- drivers/wifi/eswifi/CMakeLists.txt | 1 + drivers/wifi/simplelink/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/wifi/eswifi/CMakeLists.txt b/drivers/wifi/eswifi/CMakeLists.txt index 7b324a27b130717..9b3dae623afa866 100644 --- a/drivers/wifi/eswifi/CMakeLists.txt +++ b/drivers/wifi/eswifi/CMakeLists.txt @@ -5,6 +5,7 @@ if(CONFIG_WIFI_ESWIFI) zephyr_library_include_directories( # IP headers ${ZEPHYR_BASE}/subsys/net/ip + ${ZEPHYR_BASE}/subsys/net/lib/sockets ) zephyr_library_sources( diff --git a/drivers/wifi/simplelink/CMakeLists.txt b/drivers/wifi/simplelink/CMakeLists.txt index 8e9a24b7c828739..3dbe2a2807f2db8 100644 --- a/drivers/wifi/simplelink/CMakeLists.txt +++ b/drivers/wifi/simplelink/CMakeLists.txt @@ -3,6 +3,7 @@ if(CONFIG_WIFI_SIMPLELINK) zephyr_library_include_directories( ${ZEPHYR_BASE}/subsys/net/lib/tls_credentials + ${ZEPHYR_BASE}/subsys/net/lib/sockets ) zephyr_library_sources( simplelink_support.c From 81c5727f27701e52c6d7934b2f1fdae74668dc76 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Sun, 19 Nov 2023 17:18:50 +0100 Subject: [PATCH 0777/1049] drivers: wifi: airoc: drop default shell and sysworkq stack sizes Those configuration settings should never be part of driver Kconfig file. Drop them, since they can easily result in Kconfig symbol circular dependency error. Signed-off-by: Marcin Niestroj --- drivers/wifi/infineon/Kconfig.airoc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/wifi/infineon/Kconfig.airoc b/drivers/wifi/infineon/Kconfig.airoc index 993fbdad21268c3..a3eac53862d54c6 100644 --- a/drivers/wifi/infineon/Kconfig.airoc +++ b/drivers/wifi/infineon/Kconfig.airoc @@ -17,14 +17,6 @@ menuconfig WIFI_AIROC if WIFI_AIROC -if SHELL -config SHELL_STACK_SIZE - default 4096 -endif # SHELL - -config SYSTEM_WORKQUEUE_STACK_SIZE - default 4096 - config AIROC_WIFI_EVENT_TASK_STACK_SIZE int "Event Task Stack Size" default 4096 From 84d588e01327ca0c20135a129c87863e74baab21 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Wed, 11 Oct 2023 22:33:01 +0100 Subject: [PATCH 0778/1049] boards: arm: add support for WeAct STM32G431 Core Add support for the WeAct Studio STM32G431 Core Board. Tested with: - `samples/basic/blinky` - `samples/basic/button` Flashed samples using dfu-util. Signed-off-by: Andreas Sandberg --- boards/arm/weact_stm32g431_core/Kconfig.board | 9 + .../weact_stm32g431_core/Kconfig.defconfig | 12 ++ boards/arm/weact_stm32g431_core/board.cmake | 11 ++ boards/arm/weact_stm32g431_core/doc/index.rst | 147 ++++++++++++++ .../weact_stm32g431_core/support/openocd.cfg | 7 + .../weact_stm32g431_core.dts | 186 ++++++++++++++++++ .../weact_stm32g431_core.yaml | 20 ++ .../weact_stm32g431_core_defconfig | 24 +++ 8 files changed, 416 insertions(+) create mode 100644 boards/arm/weact_stm32g431_core/Kconfig.board create mode 100644 boards/arm/weact_stm32g431_core/Kconfig.defconfig create mode 100644 boards/arm/weact_stm32g431_core/board.cmake create mode 100644 boards/arm/weact_stm32g431_core/doc/index.rst create mode 100644 boards/arm/weact_stm32g431_core/support/openocd.cfg create mode 100644 boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts create mode 100644 boards/arm/weact_stm32g431_core/weact_stm32g431_core.yaml create mode 100644 boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig diff --git a/boards/arm/weact_stm32g431_core/Kconfig.board b/boards/arm/weact_stm32g431_core/Kconfig.board new file mode 100644 index 000000000000000..9886fd64702779b --- /dev/null +++ b/boards/arm/weact_stm32g431_core/Kconfig.board @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023 Andreas Sandberg +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BOARD_WEACT_STM32G431_CORE + bool "WeAct Studio STM32G431 Core Board" + depends on SOC_STM32G431XX diff --git a/boards/arm/weact_stm32g431_core/Kconfig.defconfig b/boards/arm/weact_stm32g431_core/Kconfig.defconfig new file mode 100644 index 000000000000000..25d65455013564e --- /dev/null +++ b/boards/arm/weact_stm32g431_core/Kconfig.defconfig @@ -0,0 +1,12 @@ +# +# Copyright (c) 2023 Andreas Sandberg +# +# SPDX-License-Identifier: Apache-2.0 +# + +if BOARD_WEACT_STM32G431_CORE + +config BOARD + default "weact_stm32g431_core" + +endif diff --git a/boards/arm/weact_stm32g431_core/board.cmake b/boards/arm/weact_stm32g431_core/board.cmake new file mode 100644 index 000000000000000..5ef1ab31d07a39e --- /dev/null +++ b/boards/arm/weact_stm32g431_core/board.cmake @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 Andreas Sandberg +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) diff --git a/boards/arm/weact_stm32g431_core/doc/index.rst b/boards/arm/weact_stm32g431_core/doc/index.rst new file mode 100644 index 000000000000000..2d367ba280827e8 --- /dev/null +++ b/boards/arm/weact_stm32g431_core/doc/index.rst @@ -0,0 +1,147 @@ +.. _weact_stm32g431_core: + +WeAct Studio STM32G431 Core Board +################################# + +The WeAct STM32G431 Core Board is a low-cost bare-bones STM32G431-based development +board. See the `STM32G431CB website`_ for more information about the MCU. More information +about the board, including schematics, is available from the `WeAct GitHub`_. + +Modifications USB-C Power Delivery +********************************** + +The board does not support USB-C PD in its standard configuration. To enable USB-C PD, CC1 +and CC2 need to be disconnected from their pull-down resistors and be connected to PB6 and +PB4 respectively. Dead battery support requires PA9 and PA10 to be routed to CC1 and +CC2. VBUS also needs to be connected to the MCU through a voltage divider. + +The pull-downs are disconnected by removing the zero-Ohm resistors on SB8 and SB9 next to +the USB-C connector. SB3, SB5, SB6, and SB7 then need to be closed to connect the CCx +lines to the MCU. The voltage divider is connected to PB2 by closing SB4. + +After these modifications have been made, PA9, PA10, PB2, PB4, and PB6 should be +considered reserved for USB-C and not available for other applications. + +.. warning:: + The internal USB DFU boot loader may not work correctly with machines that respect USB + PD signaling unless dead battery support has been enabled. A USB-C to USB-A adapter or + programming using the SWD port can be used as a workaround. + + +Supported Features +================== + +The Zephyr weact_stm32g431_core board configuration supports the following hardware +features: + ++------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++============+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++------------+------------+-------------------------------------+ +| UART | on-chip | serial port | ++------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++------------+------------+-------------------------------------+ +| ADC | on-chip | ADC Controller | ++------------+------------+-------------------------------------+ +| USB | on-chip | USB device | ++------------+------------+-------------------------------------+ +| UCPD | on-chip | ucpd | ++------------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: + + ``boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig`` + +Pin Mapping +=========== + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_2 TX/RX : PA2/PA3 +- UCPD1 CCx : PB6/PB4 (not connected by default) +- UCPD1 DBCCx : PA9/PA10 (not connected by default) +- BUTTON (User) : PC13 +- BUTTON (BOOT0) : PB8 +- LED0 : PC6 +- ADC (VBUS) : PB2 + +The ADC is disabled by default since the VBUS voltage divider is not connected in the +board's standard configuration. + + +Hardware Configuration +---------------------- ++---------------+---------+-----------------------------------------------+ +| Solder bridge | Default | Description | ++===============+=========+===============================================+ +| SB1/SB2 | Open | Route PC14/PC15 (LSE) to header | ++---------------+---------+-----------------------------------------------+ +| SB6/SB7 | Open | Connect PB4/PB6 (UCPD1_CCx) to USB-C CCx pins | ++---------------+---------+-----------------------------------------------+ +| SB3/SB5 | Open | Connect PA9/PA10 (UCPD1_DBCCx) to to PB6/PB4 | ++---------------+---------+-----------------------------------------------+ +| SB4 | Open | Connect PB2 to VBUS voltage divider | ++---------------+---------+-----------------------------------------------+ +| SB8/SB9 | Closed | Connect USB-CCx to pull-down resistors | ++---------------+---------+-----------------------------------------------+ +| SB10 | Open | VBUS protection diode bypass | ++---------------+---------+-----------------------------------------------+ + + +Clock Sources +------------- + +The board has two external oscillators. The frequency of the slow clock (LSE) is 32.768 +kHz. The frequency of the main clock (HSE) is 8 MHz. + +The default configuration sources the system clock from the PLL, which is derived from +HSE, and is set at 144 MHz. The 48 MHz clock used by the USB interface is derived from the +PLL instead of the internal 48 MHz oscillator. + +Programming and Debugging +************************* + +The MCU is normally programmed using the ROM bootloader or the exposed SWD port. + +Please note that some laptops may not detect the ROM bootloader correctly if the CCx +pull-downs have been disconnected by opening SB8 and SB9 unless dead battery support has +been enabled by closing SB3 and SB5. A USB-C to USB-A adapter can be used as a workaround +if this is a problem. + +Flashing an Application +======================= + +Connect a USB-C cable and the board should power ON. Force the board into DFU mode by +keeping the BOOT0 switch pressed while pressing and releasing the NRST switch. + +The dfu-util runner is supported on this board and so a sample can be built and tested +easily. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: weact_stm32g431_core + :goals: build flash + +Debugging +========= + +The board can be debugged by installing the included 100 mil (0.1 inch) header, and +attaching an SWD debugger to the 3V3 (3.3V), GND, SCK, and DIO pins on that header. + + +References +********** + +.. target-notes:: + +.. _WeAct GitHub: + https://github.com/WeActStudio/WeActStudio.STM32G431CoreBoard + +.. _STM32G431CB website: + https://www.st.com/en/microcontrollers-microprocessors/stm32g431cb.html + +.. _STM32F401x reference manual: + https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf diff --git a/boards/arm/weact_stm32g431_core/support/openocd.cfg b/boards/arm/weact_stm32g431_core/support/openocd.cfg new file mode 100644 index 000000000000000..d936f7d353423bc --- /dev/null +++ b/boards/arm/weact_stm32g431_core/support/openocd.cfg @@ -0,0 +1,7 @@ +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32g4x.cfg] + +reset_config srst_only diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts new file mode 100644 index 000000000000000..cdfe959b3fd186f --- /dev/null +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 Andreas Sandberg + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "WeAct Studio STM32G431 Core Board"; + compatible = "weact,stm32g431-core"; + + chosen { + zephyr,console = &usart2; + zephyr,shell-uart = &usart2; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + aliases { + led0 = &led_0; + mcuboot-button0 = &button_0; + mcuboot-led0 = &led_0; + sw0 = &button_0; + sw1 = &button_1; + usbc-port0 = &usbc1; + watchdog0 = &iwdg; + }; + + leds { + compatible = "gpio-leds"; + led_0: led0 { + gpios = <&gpioc 6 GPIO_ACTIVE_HIGH>; + label = "Status LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + button_0: button0 { + label = "User"; + gpios = <&gpioc 13 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + zephyr,code = ; + }; + button_1: button1 { + label = "Boot0"; + gpios = <&gpiob 8 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + vbus1: vbus { + compatible = "zephyr,usb-c-vbus-adc"; + status = "disabled"; + io-channels = <&adc2 12>; + output-ohms = <10000>; + full-ohms = <(100000 + 10000)>; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + usbc1: usbc-port@1 { + compatible = "usb-c-connector"; + status = "disabled"; + reg = <1>; + tcpc = <&ucpd1>; + vbus = <&vbus1>; + data-role = "device"; + power-role = "sink"; + sink-pdos = ; + }; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hsi { + status = "disabled"; +}; + +&clk_hse { + status = "okay"; + clock-frequency = ; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&pll { + status = "okay"; + div-m = <2>; + mul-n = <72>; + div-p = <2>; + div-q = <6>; + div-r = <2>; + clocks = <&clk_hse>; +}; + +&rtc { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; +}; + +&lptim1 { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, + <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* 4KiB of storage at the end of the 128KiB FLASH */ + storage_partition: partition@1f000 { + label = "storage"; + reg = <0x0001f000 DT_SIZE_K(4)>; + }; + }; +}; + +&iwdg { + status = "okay"; +}; + +&usart2 { + status = "okay"; + pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3>; + pinctrl-names = "default"; + + current-speed = <115200>; +}; + +&adc2 { + pinctrl-0 = <&adc2_in12_pb2>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@c { + reg = <12>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,vref-mv = <3300>; + }; +}; + +&ucpd1 { + psc-ucpdclk = <1>; + hbitclkdiv = <27>; + pinctrl-0 = <&ucpd1_cc1_pb6 &ucpd1_cc2_pb4>; + pinctrl-names = "default"; +}; + +zephyr_udc0: &usb { + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00800000>, + <&rcc STM32_SRC_PLL_Q CLK48_SEL(2)>; + status = "okay"; +}; diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core.yaml b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.yaml new file mode 100644 index 000000000000000..91886ad0ea51ad3 --- /dev/null +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.yaml @@ -0,0 +1,20 @@ +identifier: weact_stm32g431_core +name: WeAct Studio STM32G431 Core Board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 32 +flash: 128 +supported: + - counter + - gpio + - nvs + - pinctrl + - tcpc + - uart + - usb_device + - watchdog +vendor: weact diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig b/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig new file mode 100644 index 000000000000000..aa9e67db82199da --- /dev/null +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig @@ -0,0 +1,24 @@ +# +# Copyright (c) 2023 Andreas Sandberg +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_SERIES_STM32G4X=y +CONFIG_SOC_STM32G431XX=y + +CONFIG_CLOCK_CONTROL=y +CONFIG_PINCTRL=y + +# LSE defined as LPTIM clock source by the DTS +CONFIG_STM32_LPTIM_CLOCK_LSE=y + +CONFIG_ARM_MPU=y +CONFIG_HW_STACK_PROTECTION=y + +CONFIG_GPIO=y + +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y From b544855ba595b27db28b965d282623de086d52a9 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Wed, 11 Oct 2023 22:39:39 +0100 Subject: [PATCH 0779/1049] samples: usb-c: sink: Add support for WeAct STM32G431 core Add support for the WeAct Studio STM32G431 Core board. Note that this board does not support USB-C PD in its default configuration. See the board documentation for the necessary hardware reconfiguration. Signed-off-by: Andreas Sandberg --- .../sink/boards/weact_stm32g431_core.overlay | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 samples/subsys/usb_c/sink/boards/weact_stm32g431_core.overlay diff --git a/samples/subsys/usb_c/sink/boards/weact_stm32g431_core.overlay b/samples/subsys/usb_c/sink/boards/weact_stm32g431_core.overlay new file mode 100644 index 000000000000000..1b951a5ef772e00 --- /dev/null +++ b/samples/subsys/usb_c/sink/boards/weact_stm32g431_core.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Andreas Sandberg + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include + +&adc2 { + status = "okay"; +}; + +&vbus1 { + status = "okay"; +}; + +&usbc1 { + status = "okay"; +}; + +&clk_hsi { + /* The HSI is used by ucpd1 */ + status = "okay"; +}; + +&ucpd1 { + status = "okay"; + dead-battery; +}; From 3467a25fff805b2f8c4e295f71b7e8ce4b25ad9f Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 16 Nov 2023 14:29:55 +0100 Subject: [PATCH 0780/1049] tfm: Change SFN and FP_HARDABI dependency TF-M only suports floating point in IPC model, not the SFN model. Since floating point is a basic feature of the architecture and TF-M has the limitation it makes more sense for the dependency to exist in TF-M and and limit the TF-M model choice instead of limiting the option to enable floating point. Signed-off-by: Joakim Andersson --- arch/arm/core/Kconfig | 1 - modules/trusted-firmware-m/Kconfig.tfm | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index 524bd86ff4cc930..75a64ea90ebaeb8 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -271,7 +271,6 @@ config FP_HARDABI # TF-M build system does not build the NS app and libraries correctly with Hard ABI. # This limitation should be removed in the next TF-M synchronization. depends on !TFM_BUILD_NS - depends on !(BUILD_WITH_TFM && !TFM_IPC) help This option selects the Floating point ABI in which hardware floating point instructions are generated and uses FPU-specific calling diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index d29b7093de01fea..b635347b6e1afcb 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -324,6 +324,7 @@ config TFM_IPC config TFM_SFN bool "SFN model" + depends on !FP_HARDABI help Use the SFN Model as the SPM backend for the PSA API. The SFN model supports the SFN Partition model, and isolation level 1. From 32c3173fabae92217739743bf6098f0e5c4d86df Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Mon, 20 Nov 2023 14:38:25 +0100 Subject: [PATCH 0781/1049] tests: mcuboot: Enable mcuboot shell command Some shell modules were disabled in one of previous commits. Tests in this folder requires mcuboot shell command. Enable it with CONFIG_MCUBOOT_SHELL. Signed-off-by: Grzegorz Chwierut --- tests/boot/with_mcumgr/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/boot/with_mcumgr/prj.conf b/tests/boot/with_mcumgr/prj.conf index 5d09b05144a5434..3ddf7a4a45db92f 100644 --- a/tests/boot/with_mcumgr/prj.conf +++ b/tests/boot/with_mcumgr/prj.conf @@ -9,6 +9,7 @@ CONFIG_FLASH_MAP=y # Enable the shell MCUmgr transport. CONFIG_BASE64=y CONFIG_SHELL=y +CONFIG_MCUBOOT_SHELL=y CONFIG_SHELL_BACKEND_SERIAL=y CONFIG_MCUMGR_TRANSPORT_SHELL=y From 934a09550dd17406426ac92aac89761cbe506520 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Mon, 20 Nov 2023 14:05:19 +0100 Subject: [PATCH 0782/1049] samples: Bluetooth: Make broadcaster_multiple run on other controllers `CONFIG_BT_CTLR_ADV_DATA_CHAIN` is a Zephyr Controller exclusive. Use the max length instead to decide if we should add more data. The motivation for the change is that tests/bsim/bluetooth/host/adv/chain does not pass with Nordic's Softdevice Controller because of this. Signed-off-by: Jonathan Rico --- .../bluetooth/broadcaster_multiple/src/broadcaster_multiple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c b/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c index 30fe35d3dec6e04..d4ce51c4f252f90 100644 --- a/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c +++ b/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c @@ -56,7 +56,7 @@ static uint8_t mfg_data[BT_MFG_DATA_LEN] = { 0xFF, 0xFF, }; static const struct bt_data ad[] = { BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, sizeof(mfg_data)), -#if defined(CONFIG_BT_CTLR_ADV_DATA_CHAIN) +#if CONFIG_BT_CTLR_ADV_DATA_LEN_MAX > 255 BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, sizeof(mfg_data)), #endif }; From 23cf38934c0f68861e403b22bc3dd0ce6efbfa39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 20 Nov 2023 16:15:42 +0100 Subject: [PATCH 0783/1049] manifest: Update hal_nordic revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull in a fix in the watchdog driver initialization. Signed-off-by: Andrzej Głąbek --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 20c01f426377be1..148471091948840 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: 2ff8ce6e6ca131d87699dba260f3c0cc4a6cc365 + revision: 56e0b052dff311c2f8eb08c6804e60fc79feb56f path: modules/hal/nordic groups: - hal From 1727bbcc7046eb5870df7409310d58e0c9483233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 3 Nov 2023 12:08:09 +0100 Subject: [PATCH 0784/1049] drivers: nrf_qspi_nor: Prevent reading status before sending RDPD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After entering the Deep Power-down mode, some flash chips ignore all commands except from the one that releases the chip from the DP mode and it is not possible to successfully read their Status Register then. Since the QSPI peripheral tries to read this register when it is being activated, it consequently fails to send the actual command that would release the flash chip from the DP mode if that is to be done right after QSPI initialization. Prevent this problem by performing the QSPI activation with all pins disconnected. This causes that the Status Register value is read as all zeros and allows the activation to always finish successfully, and the RDPD command to be properly sent. Signed-off-by: Andrzej Głąbek --- drivers/flash/nrf_qspi_nor.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index 28c705f6707d8b2..467d0643d48339a 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -1339,15 +1339,34 @@ static int enter_dpd(const struct device *const dev) static int exit_dpd(const struct device *const dev) { if (IS_ENABLED(DT_INST_PROP(0, has_dpd))) { + nrf_qspi_pins_t pins; + nrf_qspi_pins_t disconnected_pins = { + .sck_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .csn_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io0_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io1_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io2_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io3_pin = NRF_QSPI_PIN_NOT_CONNECTED, + }; struct qspi_cmd cmd = { .op_code = SPI_NOR_CMD_RDPD, }; uint32_t t_exit_dpd = DT_INST_PROP_OR(0, t_exit_dpd, 0); - int ret; + nrfx_err_t res; + int rc; - ret = qspi_send_cmd(dev, &cmd, false); - if (ret < 0) { - return ret; + nrf_qspi_pins_get(NRF_QSPI, &pins); + nrf_qspi_pins_set(NRF_QSPI, &disconnected_pins); + res = nrfx_qspi_activate(true); + nrf_qspi_pins_set(NRF_QSPI, &pins); + + if (res != NRFX_SUCCESS) { + return -EIO; + } + + rc = qspi_send_cmd(dev, &cmd, false); + if (rc < 0) { + return rc; } if (t_exit_dpd) { From b172e5133b09ec0c32dbbe74dafa9ef8f2d9da33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 21 Nov 2023 08:27:07 +0100 Subject: [PATCH 0785/1049] boards: nrf52840dk_nrf52840: Fix reserved GPIO lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to commit 7a83724e0f18d7f2400517407150f9e9a1ecd6e6. There is no reason to mark that many GPIO lines as reserved on this board. And doing so causes several existing tests to fail as they are configured to use some of those now unavailable GPIO lines. Limit reservation to the lines that actually cannot be used as GPIOs without changes in the default configuration of the board or its physical modification (via solder bridges), i.e.: - XL1 and XL2 (connections for the 32.768 kHz crystal) - NFC1 and NFC2 (NFC antenna connections) - RESET - TXD and RXD (lines used by the console UART) - QSPI lines: CS, CLK, and DIO0-3 Provide names for all the GPIO lines that are described on the board. Even for the reserved ones, so that it is clear why they are reserved. Signed-off-by: Andrzej Głąbek --- .../nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts index dcee7b0db5fd48e..60c3ecf55a127af 100644 --- a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts +++ b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts @@ -149,18 +149,18 @@ &gpio0 { status = "okay"; - gpio-reserved-ranges = <0 11>, <17 7>, <26 6>; - gpio-line-names = "", "", "", "", "", "", "", "", - "", "", "", "BUTTON1", "BUTTON2", "LED1", "LED2", "LED3", - "LED4", "", "", "", "", "", "", "", - "BUTTON3", "BUTTON4", "", "", "", "", "", ""; + gpio-reserved-ranges = <0 2>, <6 1>, <8 3>, <17 7>; + gpio-line-names = "XL1", "XL2", "AREF", "A0", "A1", "RTS", "TXD", + "CTS", "RXD", "NFC1", "NFC2", "BUTTON1", "BUTTON2", "LED1", + "LED2", "LED3", "LED4", "QSPI CS", "RESET", "QSPI CLK", + "QSPI DIO0", "QSPI DIO1", "QSPI DIO2", "QSPI DIO3","BUTTON3", + "BUTTON4", "SDA", "SCL", "A2", "A3", "A4", "A5"; }; &gpio1 { status = "okay"; - gpio-reserved-ranges = <0 1>, <9 1>, <12 4>; gpio-line-names = "", "D0", "D1", "D2", "D3", "D4", "D5", "D6", - "D7", "", "D8", "D9", "", "", "", ""; + "D7", "", "D8", "D9", "D10", "D11", "D12", "D13"; }; &uart0 { From 4a4558128848b3cc01a153ab128fb6aa09316a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 6 Nov 2023 14:31:56 +0100 Subject: [PATCH 0786/1049] drivers: nrf_qspi_nor: Clean up handling of return values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consistently use `res` for results of calls to nrfx functions and `rc` for Zephyr return codes, to avoid mixing up those two and for example calling `qspi_get_zephyr_ret_code()` for a value that is already a Zephyr return code. Correct also such call in `qspi_nor_write()`. Signed-off-by: Andrzej Głąbek --- drivers/flash/nrf_qspi_nor.c | 248 ++++++++++++++++++----------------- 1 file changed, 125 insertions(+), 123 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index 467d0643d48339a..ca4673e8aa216ba 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -371,7 +371,7 @@ static int qspi_device_init(const struct device *dev) return pm_device_runtime_get(dev); #else nrfx_err_t res; - int ret = 0; + int rc = 0; qspi_lock(dev); @@ -389,13 +389,13 @@ static int qspi_device_init(const struct device *dev) res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - ret = qspi_get_zephyr_ret_code(res); - qspi_initialized = (ret == 0); + rc = qspi_get_zephyr_ret_code(res); + qspi_initialized = (rc == 0); } qspi_unlock(dev); - return ret; + return rc; #endif } @@ -408,10 +408,10 @@ static void qspi_device_uninit(const struct device *dev) } #ifdef CONFIG_PM_DEVICE_RUNTIME - int ret = pm_device_runtime_put(dev); + int rc = pm_device_runtime_put(dev); - if (ret < 0) { - LOG_ERR("Failed to schedule device sleep: %d", ret); + if (rc < 0) { + LOG_ERR("Failed to schedule device sleep: %d", rc); } #else bool last = true; @@ -526,27 +526,27 @@ static int qspi_rdsr(const struct device *dev, uint8_t sr_num) .op_code = opcode, .rx_buf = &sr_buf, }; - int ret = qspi_send_cmd(dev, &cmd, false); + int rc = qspi_send_cmd(dev, &cmd, false); - return (ret < 0) ? ret : sr; + return (rc < 0) ? rc : sr; } /* Wait until RDSR confirms write is not in progress. */ static int qspi_wait_while_writing(const struct device *dev) { - int ret; + int rc; do { - ret = qspi_rdsr(dev, 1); - } while ((ret >= 0) - && ((ret & SPI_NOR_WIP_BIT) != 0U)); + rc = qspi_rdsr(dev, 1); + } while ((rc >= 0) + && ((rc & SPI_NOR_WIP_BIT) != 0U)); - return (ret < 0) ? ret : 0; + return (rc < 0) ? rc : 0; } static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) { - int ret = 0; + int rc = 0; uint8_t opcode = SPI_NOR_CMD_WRSR; uint8_t length = 1; uint8_t sr_array[2] = {0}; @@ -559,12 +559,12 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) sr_array[0] = sr_val; #if SR1_WRITE_CLEARS_SR2 /* Writing sr1 clears sr2. need to read/modify/write both. */ - ret = qspi_rdsr(dev, 2); - if (ret < 0) { - LOG_ERR("RDSR for WRSR failed: %d", ret); - return ret; + rc = qspi_rdsr(dev, 2); + if (rc < 0) { + LOG_ERR("RDSR for WRSR failed: %d", rc); + return rc; } - sr_array[1] = ret; + sr_array[1] = rc; length = 2; #endif } else { /* sr_num == 2 */ @@ -574,12 +574,12 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) * Uses standard WRSR opcode */ sr_array[1] = sr_val; - ret = qspi_rdsr(dev, 1); - if (ret < 0) { - LOG_ERR("RDSR for WRSR failed: %d", ret); - return ret; + rc = qspi_rdsr(dev, 1); + if (rc < 0) { + LOG_ERR("RDSR for WRSR failed: %d", rc); + return rc; } - sr_array[0] = ret; + sr_array[0] = rc; length = 2; #elif IS_EQUAL(INST_0_QER, JESD216_DW15_QER_VAL_S2B1v6) /* Writing sr2 uses a dedicated WRSR2 command */ @@ -600,17 +600,17 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) .tx_buf = &sr_buf, }; - ret = qspi_send_cmd(dev, &cmd, true); + rc = qspi_send_cmd(dev, &cmd, true); /* Writing SR can take some time, and further * commands sent while it's happening can be * corrupted. Wait. */ - if (ret == 0) { - ret = qspi_wait_while_writing(dev); + if (rc == 0) { + rc = qspi_wait_while_writing(dev); } - return ret; + return rc; } #endif /* !IS_EQUAL(INST_0_QER, JESD216_DW15_QER_VAL_NONE) */ @@ -627,16 +627,16 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) return -EINVAL; } - int rv = 0; const struct qspi_nor_config *params = dev->config; + int rc, rc2; - rv = qspi_device_init(dev); - if (rv != 0) { + rc = qspi_device_init(dev); + if (rc != 0) { goto out; } qspi_trans_lock(dev); - rv = qspi_nor_write_protection_set(dev, false); - if (rv != 0) { + rc = qspi_nor_write_protection_set(dev, false); + if (rc != 0) { goto out_trans_unlock; } qspi_lock(dev); @@ -670,16 +670,16 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) size -= adj; } else { LOG_ERR("erase error at 0x%lx size %zu", (long)addr, size); - rv = qspi_get_zephyr_ret_code(res); + rc = qspi_get_zephyr_ret_code(res); break; } } qspi_unlock(dev); - int rv2 = qspi_nor_write_protection_set(dev, true); + rc2 = qspi_nor_write_protection_set(dev, true); - if (!rv) { - rv = rv2; + if (!rc) { + rc = rc2; } out_trans_unlock: @@ -687,7 +687,7 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) out: qspi_device_uninit(dev); - return rv; + return rc; } /* Configures QSPI memory for the transfer */ @@ -695,6 +695,8 @@ static int qspi_nrfx_configure(const struct device *dev) { struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; + nrfx_err_t res; + int rc; #if defined(CONFIG_SOC_SERIES_NRF53X) /* When the QSPI peripheral is activated, during the nrfx_qspi driver @@ -705,18 +707,16 @@ static int qspi_nrfx_configure(const struct device *dev) nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); #endif - nrfx_err_t res = nrfx_qspi_init(&dev_config->nrfx_cfg, - qspi_handler, - dev_data); + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); #if defined(CONFIG_SOC_SERIES_NRF53X) /* Restore the default /4 divider after the QSPI initialization. */ nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); #endif - int ret = qspi_get_zephyr_ret_code(res); - if (ret < 0) { - return ret; + rc = qspi_get_zephyr_ret_code(res); + if (rc < 0) { + return rc; } #if DT_INST_NODE_HAS_PROP(0, rx_delay) @@ -736,9 +736,9 @@ static int qspi_nrfx_configure(const struct device *dev) * bootloader) might have set DPD mode before reboot. As a result, * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. */ - ret = exit_dpd(dev); - if (ret < 0) { - return ret; + rc = exit_dpd(dev); + if (rc < 0) { + return rc; } /* Set QE to match transfer mode. If not using quad @@ -769,28 +769,28 @@ static int qspi_nrfx_configure(const struct device *dev) return -EINVAL; #endif - ret = qspi_rdsr(dev, sr_num); - if (ret < 0) { - LOG_ERR("RDSR failed: %d", ret); - return ret; + rc = qspi_rdsr(dev, sr_num); + if (rc < 0) { + LOG_ERR("RDSR failed: %d", rc); + return rc; } - uint8_t sr = (uint8_t)ret; + uint8_t sr = (uint8_t)rc; bool qe_state = ((sr & qe_mask) != 0U); LOG_DBG("RDSR %02x QE %d need %d: %s", sr, qe_state, qe_value, (qe_state != qe_value) ? "updating" : "no-change"); - ret = 0; + rc = 0; if (qe_state != qe_value) { sr ^= qe_mask; - ret = qspi_wrsr(dev, sr, sr_num); + rc = qspi_wrsr(dev, sr, sr_num); } - if (ret < 0) { + if (rc < 0) { LOG_ERR("QE %s failed: %d", qe_value ? "set" : "clear", - ret); - return ret; + rc); + return rc; } #endif @@ -802,16 +802,16 @@ static int qspi_nrfx_configure(const struct device *dev) /* Call will send write enable before instruction if that * requirement is encoded in INST_0_4BA. */ - ret = qspi_send_cmd(dev, &cmd, (INST_0_4BA & 0x02)); + rc = qspi_send_cmd(dev, &cmd, (INST_0_4BA & 0x02)); - if (ret < 0) { - LOG_ERR("E4BA cmd issue failed: %d.", ret); + if (rc < 0) { + LOG_ERR("E4BA cmd issue failed: %d.", rc); } else { LOG_DBG("E4BA cmd issued."); } } - return ret; + return rc; } static int qspi_read_jedec_id(const struct device *dev, @@ -826,14 +826,14 @@ static int qspi_read_jedec_id(const struct device *dev, .rx_buf = &rx_buf, }; - int ret = qspi_device_init(dev); + int rc = qspi_device_init(dev); - if (ret == 0) { - ret = qspi_send_cmd(dev, &cmd, false); + if (rc == 0) { + rc = qspi_send_cmd(dev, &cmd, false); } qspi_device_uninit(dev); - return ret; + return rc; } #if defined(CONFIG_FLASH_JESD216_API) @@ -856,13 +856,13 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, .io3_level = true, }; - int ret = qspi_device_init(dev); + int rc = qspi_device_init(dev); nrfx_err_t res = NRFX_SUCCESS; - if (ret != 0) { - LOG_DBG("qspi_device_init: %d", ret); + if (rc != 0) { + LOG_DBG("qspi_device_init: %d", rc); qspi_device_uninit(dev); - return ret; + return rc; } qspi_lock(dev); @@ -901,9 +901,9 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, static inline int qspi_nor_read_id(const struct device *dev) { uint8_t id[SPI_NOR_MAX_ID_LEN]; - int ret = qspi_read_jedec_id(dev, id); + int rc = qspi_read_jedec_id(dev, id); - if (ret != 0) { + if (rc != 0) { return -EIO; } @@ -1109,6 +1109,7 @@ static int qspi_nor_write(const struct device *dev, off_t addr, } const struct qspi_nor_config *params = dev->config; + int rc, rc2; /* affected region should be within device */ if (addr < 0 || @@ -1119,18 +1120,18 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } - nrfx_err_t res = NRFX_SUCCESS; - - int rc = qspi_device_init(dev); + rc = qspi_device_init(dev); if (rc != 0) { goto out; } qspi_trans_lock(dev); - res = qspi_nor_write_protection_set(dev, false); + rc = qspi_nor_write_protection_set(dev, false); qspi_lock(dev); - if (!res) { + if (rc == 0) { + nrfx_err_t res; + if (size < 4U) { res = write_sub_word(dev, addr, src, size); } else if (!nrfx_is_in_ram(src) || @@ -1140,17 +1141,18 @@ static int qspi_nor_write(const struct device *dev, off_t addr, res = nrfx_qspi_write(src, size, addr); qspi_wait_for_completion(dev, res); } + + rc = qspi_get_zephyr_ret_code(res); } qspi_unlock(dev); - int res2 = qspi_nor_write_protection_set(dev, true); + rc2 = qspi_nor_write_protection_set(dev, true); qspi_trans_unlock(dev); - if (!res) { - res = res2; + if (rc == 0) { + rc = rc2; } - rc = qspi_get_zephyr_ret_code(res); out: qspi_device_uninit(dev); return rc; @@ -1169,24 +1171,24 @@ static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) return -EINVAL; } - int ret = qspi_erase(dev, addr, size); + int rc = qspi_erase(dev, addr, size); - return ret; + return rc; } static int qspi_nor_write_protection_set(const struct device *dev, bool write_protect) { - int ret = 0; + int rc = 0; struct qspi_cmd cmd = { .op_code = ((write_protect) ? SPI_NOR_CMD_WRDI : SPI_NOR_CMD_WREN), }; if (qspi_send_cmd(dev, &cmd, false) != 0) { - ret = -EIO; + rc = -EIO; } - return ret; + return rc; } /** @@ -1198,16 +1200,16 @@ static int qspi_nor_write_protection_set(const struct device *dev, */ static int qspi_nor_configure(const struct device *dev) { - int ret = qspi_nrfx_configure(dev); + int rc = qspi_nrfx_configure(dev); - if (ret != 0) { - return ret; + if (rc != 0) { + return rc; } #ifdef CONFIG_PM_DEVICE_RUNTIME - ret = pm_device_runtime_enable(dev); - if (ret < 0) { - LOG_ERR("Failed to enable runtime power management: %d", ret); + rc = pm_device_runtime_enable(dev); + if (rc < 0) { + LOG_ERR("Failed to enable runtime power management: %d", rc); } else { LOG_DBG("Runtime power management enabled"); } @@ -1231,12 +1233,12 @@ static int qspi_nor_configure(const struct device *dev) */ static int qspi_nor_init(const struct device *dev) { - int rc; const struct qspi_nor_config *dev_config = dev->config; - int ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + int rc; - if (ret < 0) { - return ret; + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + return rc; } IRQ_CONNECT(DT_IRQN(QSPI_NODE), DT_IRQ(QSPI_NODE, priority), @@ -1317,11 +1319,11 @@ static int enter_dpd(const struct device *const dev) .op_code = SPI_NOR_CMD_DPD, }; uint32_t t_enter_dpd = DT_INST_PROP_OR(0, t_enter_dpd, 0); - int ret; + int rc; - ret = qspi_send_cmd(dev, &cmd, false); - if (ret < 0) { - return ret; + rc = qspi_send_cmd(dev, &cmd, false); + if (rc < 0) { + return rc; } if (t_enter_dpd) { @@ -1386,8 +1388,8 @@ static int qspi_nor_pm_action(const struct device *dev, { struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - int ret; - nrfx_err_t err; + int rc; + nrfx_err_t res; if (pm_device_is_busy(dev)) { return -EBUSY; @@ -1397,9 +1399,9 @@ static int qspi_nor_pm_action(const struct device *dev, case PM_DEVICE_ACTION_SUSPEND: #ifndef CONFIG_PM_DEVICE_RUNTIME /* If PM_DEVICE_RUNTIME, we don't uninit after RESUME */ - ret = qspi_device_init(dev); - if (ret < 0) { - return ret; + rc = qspi_device_init(dev); + if (rc < 0) { + return rc; } #endif @@ -1411,35 +1413,35 @@ static int qspi_nor_pm_action(const struct device *dev, return -EBUSY; } - ret = enter_dpd(dev); - if (ret < 0) { - return ret; + rc = enter_dpd(dev); + if (rc < 0) { + return rc; } nrfx_qspi_uninit(); - ret = pinctrl_apply_state(dev_config->pcfg, + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); - if (ret < 0) { - return ret; + if (rc < 0) { + return rc; } break; case PM_DEVICE_ACTION_RESUME: - ret = pinctrl_apply_state(dev_config->pcfg, + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; + if (rc < 0) { + return rc; } - err = nrfx_qspi_init(&dev_config->nrfx_cfg, + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - if (err != NRFX_SUCCESS) { + if (res != NRFX_SUCCESS) { return -EIO; } - ret = exit_dpd(dev); - if (ret < 0) { - return ret; + rc = exit_dpd(dev); + if (rc < 0) { + return rc; } #ifndef CONFIG_PM_DEVICE_RUNTIME @@ -1459,16 +1461,16 @@ static int qspi_nor_pm_action(const struct device *dev, void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) { struct qspi_nor_data *dev_data = dev->data; - int ret; + int rc; if (dev_data->xip_enabled == enable) { return; } - ret = qspi_device_init(dev); + rc = qspi_device_init(dev); - if (ret != 0) { - LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", ret); + if (rc != 0) { + LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", rc); return; } From 8c3df0aa9e9a8e7fe864b07ece840610009b3069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 6 Nov 2023 14:10:19 +0100 Subject: [PATCH 0787/1049] drivers: nrf_qspi_nor: Refactor deactivation and locking access to QSPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After integration of nrfx 3.2.0, it is no longer needed to deinitialize the nrfx_qspi driver to avoid increased power consumption when the QSPI peripheral is idle. Now it is enough to call `nrfx_qspi_dectivate()` when a given operation is done. The driver will automatically activate the QSPI peripheral again when a next operation is requested. This commit applies the following changes: - `qspi_device_init` and `qspi_device_uninit` functions are replaced by `qspi_acquire` and `qspi_release`, respectively; those handle exclusive access to the QSPI peripheral and deactivation of it or runtime device power management - locking is removed from `qspi_send_cmd` as it is the resposibility of the caller of that function - `trans_lock` and `trans_unlock` functions are removed together with the related semaphore as they are no longer needed - checking of input parameters is moved from `qspi_erase` to its caller, `qspi_nor_erase` - `qspi_nor_pm_action` is refactored to properly handle locking of the QSPI peripheral; checking of the `xip_enabled` flag is removed from that function as now the call to `pm_device_is_busy()` covers that (when XIP is enabled, the device is kept indicated as busy) Signed-off-by: Andrzej Głąbek --- drivers/flash/nrf_qspi_nor.c | 507 +++++++++++++---------------------- 1 file changed, 193 insertions(+), 314 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index ca4673e8aa216ba..aa6449763bed523 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -26,15 +26,15 @@ LOG_MODULE_REGISTER(qspi_nor, CONFIG_FLASH_LOG_LEVEL); #include struct qspi_nor_data { +#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) + /* A semaphore to control QSPI deactivation. */ + struct k_sem count; +#endif #ifdef CONFIG_MULTITHREADING - /* The semaphore to control exclusive access on write/erase. */ - struct k_sem trans; /* The semaphore to control exclusive access to the device. */ struct k_sem sem; /* The semaphore to indicate that transfer has completed. */ struct k_sem sync; - /* The semaphore to control driver init/uninit. */ - struct k_sem count; #else /* CONFIG_MULTITHREADING */ /* A flag that signals completed transfer when threads are * not enabled. @@ -173,12 +173,6 @@ BUILD_ASSERT(DT_INST_PROP(0, address_size_32), "After entering 4 byte addressing mode, 4 byte addressing is expected"); #endif -#ifndef CONFIG_PM_DEVICE_RUNTIME -static bool qspi_initialized; -#endif - -static int qspi_device_init(const struct device *dev); -static void qspi_device_uninit(const struct device *dev); void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable); void z_vrfy_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable); @@ -245,72 +239,99 @@ static inline int qspi_get_zephyr_ret_code(nrfx_err_t res) static inline void qspi_lock(const struct device *dev) { +#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; - pm_device_busy_set(dev); - -#ifdef CONFIG_MULTITHREADING k_sem_take(&dev_data->sem, K_FOREVER); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev_data); -#endif /* CONFIG_MULTITHREADING */ - - /* - * Change the base clock divider only for the time the driver is locked - * to perform a QSPI operation, otherwise the power consumption would be - * increased also when the QSPI peripheral is idle. - * When XIP is enabled, there is nothing to do here as the changed - * divider is kept all the time. - */ -#if defined(CONFIG_SOC_SERIES_NRF53X) - if (!dev_data->xip_enabled) { - nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); - } #endif } static inline void qspi_unlock(const struct device *dev) { +#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; -#if defined(CONFIG_SOC_SERIES_NRF53X) - /* Restore the default base clock divider to reduce power consumption. - * Unless XIP is enabled, then the changed divider needs to be kept. - */ - if (!dev_data->xip_enabled) { - nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); - } + k_sem_give(&dev_data->sem); #endif +} -#ifdef CONFIG_MULTITHREADING - k_sem_give(&dev_data->sem); -#else - ARG_UNUSED(dev_data); +static inline void qspi_clock_div_change(void) +{ +#ifdef CONFIG_SOC_SERIES_NRF53X + /* Make sure the base clock divider is changed accordingly + * before a QSPI transfer is performed. + */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); #endif +} - pm_device_busy_clear(dev); +static inline void qspi_clock_div_restore(void) +{ +#ifdef CONFIG_SOC_SERIES_NRF53X + /* Restore the default base clock divider to reduce power + * consumption when the QSPI peripheral is idle. + */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); +#endif } -static inline void qspi_trans_lock(const struct device *dev) +static void qspi_acquire(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; - k_sem_take(&dev_data->trans, K_FOREVER); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev); -#endif /* CONFIG_MULTITHREADING */ +#if defined(CONFIG_PM_DEVICE_RUNTIME) + int rc = pm_device_runtime_get(dev); + + if (rc < 0) { + LOG_ERR("pm_device_runtime_get failed: %d", rc); + } +#elif defined(CONFIG_MULTITHREADING) + /* In multithreading, the driver can call qspi_acquire more than once + * before calling qspi_release. Keeping count, so QSPI is deactivated + * only at the last call (count == 0). + */ + k_sem_give(&dev_data->count); +#endif + + qspi_lock(dev); + + if (!dev_data->xip_enabled) { + qspi_clock_div_change(); + + pm_device_busy_set(dev); + } } -static inline void qspi_trans_unlock(const struct device *dev) +static void qspi_release(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; + bool deactivate = true; - k_sem_give(&dev_data->trans); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev); -#endif /* CONFIG_MULTITHREADING */ +#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) + /* The last thread to finish using the driver deactivates the QSPI */ + (void) k_sem_take(&dev_data->count, K_NO_WAIT); + deactivate = (k_sem_count_get(&dev_data->count) == 0); +#endif + + if (!dev_data->xip_enabled) { + qspi_clock_div_restore(); + + if (deactivate && !IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + (void) nrfx_qspi_deactivate(); + } + + pm_device_busy_clear(dev); + } + + qspi_unlock(dev); + +#if defined(CONFIG_PM_DEVICE_RUNTIME) + int rc = pm_device_runtime_put(dev); + + if (rc < 0) { + LOG_ERR("pm_device_runtime_put failed: %d", rc); + } +#endif } static inline void qspi_wait_for_completion(const struct device *dev, @@ -359,89 +380,6 @@ static void qspi_handler(nrfx_qspi_evt_t event, void *p_context) } } -static int qspi_device_init(const struct device *dev) -{ - struct qspi_nor_data *dev_data = dev->data; - - if (dev_data->xip_enabled) { - return 0; - } - -#ifdef CONFIG_PM_DEVICE_RUNTIME - return pm_device_runtime_get(dev); -#else - nrfx_err_t res; - int rc = 0; - - qspi_lock(dev); - - /* In multithreading, driver can call qspi_device_init more than once - * before calling qspi_device_uninit. Keepping count, so QSPI is - * uninitialized only at the last call (count == 0). - */ -#ifdef CONFIG_MULTITHREADING - k_sem_give(&dev_data->count); -#endif - - if (!qspi_initialized) { - const struct qspi_nor_config *dev_config = dev->config; - - res = nrfx_qspi_init(&dev_config->nrfx_cfg, - qspi_handler, - dev_data); - rc = qspi_get_zephyr_ret_code(res); - qspi_initialized = (rc == 0); - } - - qspi_unlock(dev); - - return rc; -#endif -} - -static void qspi_device_uninit(const struct device *dev) -{ - struct qspi_nor_data *dev_data = dev->data; - - if (dev_data->xip_enabled) { - return; - } - -#ifdef CONFIG_PM_DEVICE_RUNTIME - int rc = pm_device_runtime_put(dev); - - if (rc < 0) { - LOG_ERR("Failed to schedule device sleep: %d", rc); - } -#else - bool last = true; - - qspi_lock(dev); - -#ifdef CONFIG_MULTITHREADING - /* The last thread to finish using the driver uninit the QSPI */ - (void) k_sem_take(&dev_data->count, K_NO_WAIT); - last = (k_sem_count_get(&dev_data->count) == 0); -#endif - - if (last) { - while (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) { - if (IS_ENABLED(CONFIG_MULTITHREADING)) { - k_msleep(50); - } else { - k_busy_wait(50000); - } - } - - nrfx_qspi_uninit(); - - qspi_initialized = false; - } - - qspi_unlock(dev); -#endif -} - /* QSPI send custom command. * * If this is used for both send and receive the buffer sizes must be @@ -497,11 +435,8 @@ static int qspi_send_cmd(const struct device *dev, const struct qspi_cmd *cmd, .wren = wren, }; - qspi_lock(dev); - int res = nrfx_qspi_cinstr_xfer(&cinstr_cfg, tx_buf, rx_buf); - qspi_unlock(dev); return qspi_get_zephyr_ret_code(res); } @@ -617,29 +552,13 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) /* QSPI erase */ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) { - /* address must be sector-aligned */ - if ((addr % QSPI_SECTOR_SIZE) != 0) { - return -EINVAL; - } - - /* size must be a non-zero multiple of sectors */ - if ((size == 0) || (size % QSPI_SECTOR_SIZE) != 0) { - return -EINVAL; - } - const struct qspi_nor_config *params = dev->config; int rc, rc2; - rc = qspi_device_init(dev); - if (rc != 0) { - goto out; - } - qspi_trans_lock(dev); rc = qspi_nor_write_protection_set(dev, false); if (rc != 0) { - goto out_trans_unlock; + return rc; } - qspi_lock(dev); while (size > 0) { nrfx_err_t res = !NRFX_SUCCESS; uint32_t adj = 0; @@ -674,20 +593,10 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) break; } } - qspi_unlock(dev); rc2 = qspi_nor_write_protection_set(dev, true); - if (!rc) { - rc = rc2; - } - -out_trans_unlock: - qspi_trans_unlock(dev); - -out: - qspi_device_uninit(dev); - return rc; + return rc != 0 ? rc : rc2; } /* Configures QSPI memory for the transfer */ @@ -698,22 +607,7 @@ static int qspi_nrfx_configure(const struct device *dev) nrfx_err_t res; int rc; -#if defined(CONFIG_SOC_SERIES_NRF53X) - /* When the QSPI peripheral is activated, during the nrfx_qspi driver - * initialization, it reads the status of the connected flash chip. - * Make sure this transaction is performed with a valid base clock - * divider. - */ - nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); -#endif - res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - -#if defined(CONFIG_SOC_SERIES_NRF53X) - /* Restore the default /4 divider after the QSPI initialization. */ - nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); -#endif - rc = qspi_get_zephyr_ret_code(res); if (rc < 0) { return rc; @@ -814,8 +708,7 @@ static int qspi_nrfx_configure(const struct device *dev) return rc; } -static int qspi_read_jedec_id(const struct device *dev, - uint8_t *id) +static int qspi_rdid(const struct device *dev, uint8_t *id) { const struct qspi_buf rx_buf = { .buf = id, @@ -826,18 +719,24 @@ static int qspi_read_jedec_id(const struct device *dev, .rx_buf = &rx_buf, }; - int rc = qspi_device_init(dev); + return qspi_send_cmd(dev, &cmd, false); +} - if (rc == 0) { - rc = qspi_send_cmd(dev, &cmd, false); - } - qspi_device_uninit(dev); +#if defined(CONFIG_FLASH_JESD216_API) + +static int qspi_read_jedec_id(const struct device *dev, uint8_t *id) +{ + int rc; + + qspi_acquire(dev); + + rc = qspi_rdid(dev, id); + + qspi_release(dev); return rc; } -#if defined(CONFIG_FLASH_JESD216_API) - static int qspi_sfdp_read(const struct device *dev, off_t offset, void *data, size_t len) { @@ -855,17 +754,10 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, .io2_level = true, .io3_level = true, }; + nrfx_err_t res; - int rc = qspi_device_init(dev); - nrfx_err_t res = NRFX_SUCCESS; - - if (rc != 0) { - LOG_DBG("qspi_device_init: %d", rc); - qspi_device_uninit(dev); - return rc; - } + qspi_acquire(dev); - qspi_lock(dev); res = nrfx_qspi_lfm_start(&cinstr_cfg); if (res != NRFX_SUCCESS) { LOG_DBG("lfm_start: %x", res); @@ -885,8 +777,8 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, } out: - qspi_unlock(dev); - qspi_device_uninit(dev); + qspi_release(dev); + return qspi_get_zephyr_ret_code(res); } @@ -901,7 +793,7 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, static inline int qspi_nor_read_id(const struct device *dev) { uint8_t id[SPI_NOR_MAX_ID_LEN]; - int rc = qspi_read_jedec_id(dev, id); + int rc = qspi_rdid(dev, id); if (rc != 0) { return -EIO; @@ -993,6 +885,9 @@ static inline nrfx_err_t read_non_aligned(const struct device *dev, static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, size_t size) { + const struct qspi_nor_config *params = dev->config; + nrfx_err_t res; + if (!dest) { return -EINVAL; } @@ -1002,8 +897,6 @@ static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, return 0; } - const struct qspi_nor_config *params = dev->config; - /* affected region should be within device */ if (addr < 0 || (addr + size) > params->size) { @@ -1013,23 +906,13 @@ static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, return -EINVAL; } - int rc = qspi_device_init(dev); - - if (rc != 0) { - goto out; - } - - qspi_lock(dev); - - nrfx_err_t res = read_non_aligned(dev, addr, dest, size); + qspi_acquire(dev); - qspi_unlock(dev); + res = read_non_aligned(dev, addr, dest, size); - rc = qspi_get_zephyr_ret_code(res); + qspi_release(dev); -out: - qspi_device_uninit(dev); - return rc; + return qspi_get_zephyr_ret_code(res); } /* addr aligned, sptr not null, slen less than 4 */ @@ -1094,6 +977,9 @@ static int qspi_nor_write(const struct device *dev, off_t addr, const void *src, size_t size) { + const struct qspi_nor_config *params = dev->config; + int rc, rc2; + if (!src) { return -EINVAL; } @@ -1108,9 +994,6 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } - const struct qspi_nor_config *params = dev->config; - int rc, rc2; - /* affected region should be within device */ if (addr < 0 || (addr + size) > params->size) { @@ -1120,15 +1003,9 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } + qspi_acquire(dev); - rc = qspi_device_init(dev); - if (rc != 0) { - goto out; - } - - qspi_trans_lock(dev); rc = qspi_nor_write_protection_set(dev, false); - qspi_lock(dev); if (rc == 0) { nrfx_err_t res; @@ -1144,23 +1021,28 @@ static int qspi_nor_write(const struct device *dev, off_t addr, rc = qspi_get_zephyr_ret_code(res); } - qspi_unlock(dev); rc2 = qspi_nor_write_protection_set(dev, true); - qspi_trans_unlock(dev); - if (rc == 0) { - rc = rc2; - } + qspi_release(dev); -out: - qspi_device_uninit(dev); - return rc; + return rc != 0 ? rc : rc2; } static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) { const struct qspi_nor_config *params = dev->config; + int rc; + + /* address must be sector-aligned */ + if ((addr % QSPI_SECTOR_SIZE) != 0) { + return -EINVAL; + } + + /* size must be a non-zero multiple of sectors */ + if ((size == 0) || (size % QSPI_SECTOR_SIZE) != 0) { + return -EINVAL; + } /* affected region should be within device */ if (addr < 0 || @@ -1171,7 +1053,11 @@ static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) return -EINVAL; } - int rc = qspi_erase(dev, addr, size); + qspi_acquire(dev); + + rc = qspi_erase(dev, addr, size); + + qspi_release(dev); return rc; } @@ -1206,17 +1092,6 @@ static int qspi_nor_configure(const struct device *dev) return rc; } -#ifdef CONFIG_PM_DEVICE_RUNTIME - rc = pm_device_runtime_enable(dev); - if (rc < 0) { - LOG_ERR("Failed to enable runtime power management: %d", rc); - } else { - LOG_DBG("Runtime power management enabled"); - } -#else - qspi_device_uninit(dev); -#endif - /* now the spi bus is configured, we can verify the flash id */ if (qspi_nor_read_id(dev) != 0) { return -ENODEV; @@ -1244,10 +1119,24 @@ static int qspi_nor_init(const struct device *dev) IRQ_CONNECT(DT_IRQN(QSPI_NODE), DT_IRQ(QSPI_NODE, priority), nrfx_isr, nrfx_qspi_irq_handler, 0); + qspi_clock_div_change(); + rc = qspi_nor_configure(dev); + qspi_clock_div_restore(); + +#ifdef CONFIG_PM_DEVICE_RUNTIME + int rc2 = pm_device_runtime_enable(dev); + + if (rc2 < 0) { + LOG_ERR("Failed to enable runtime power management: %d", rc2); + } else { + LOG_DBG("Runtime power management enabled"); + } +#endif + #ifdef CONFIG_NORDIC_QSPI_NOR_XIP - if (!rc) { + if (rc == 0) { /* Enable XIP mode for QSPI NOR flash, this will prevent the * flash from being powered down */ @@ -1383,108 +1272,97 @@ static int exit_dpd(const struct device *const dev) } #ifdef CONFIG_PM_DEVICE -static int qspi_nor_pm_action(const struct device *dev, - enum pm_device_action action) +static int qspi_suspend(const struct device *dev) { - struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - int rc; nrfx_err_t res; + int rc; - if (pm_device_is_busy(dev)) { + res = nrfx_qspi_mem_busy_check(); + if (res != NRFX_SUCCESS) { return -EBUSY; } - switch (action) { - case PM_DEVICE_ACTION_SUSPEND: -#ifndef CONFIG_PM_DEVICE_RUNTIME - /* If PM_DEVICE_RUNTIME, we don't uninit after RESUME */ - rc = qspi_device_init(dev); - if (rc < 0) { - return rc; - } -#endif + rc = enter_dpd(dev); + if (rc < 0) { + return rc; + } - if (dev_data->xip_enabled) { - return -EBUSY; - } + nrfx_qspi_uninit(); - if (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) { - return -EBUSY; - } + return pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); +} - rc = enter_dpd(dev); - if (rc < 0) { - return rc; - } +static int qspi_resume(const struct device *dev) +{ + const struct qspi_nor_config *dev_config = dev->config; + nrfx_err_t res; + int rc; - nrfx_qspi_uninit(); - rc = pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_SLEEP); - if (rc < 0) { - return rc; - } - break; + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + return rc; + } - case PM_DEVICE_ACTION_RESUME: - rc = pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_DEFAULT); - if (rc < 0) { - return rc; - } - res = nrfx_qspi_init(&dev_config->nrfx_cfg, - qspi_handler, - dev_data); - if (res != NRFX_SUCCESS) { - return -EIO; - } + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev->data); + if (res != NRFX_SUCCESS) { + return -EIO; + } - rc = exit_dpd(dev); - if (rc < 0) { - return rc; - } + return exit_dpd(dev); +} -#ifndef CONFIG_PM_DEVICE_RUNTIME - /* If PM_DEVICE_RUNTIME, we're immediately going to use the device */ - qspi_device_uninit(dev); -#endif +static int qspi_nor_pm_action(const struct device *dev, + enum pm_device_action action) +{ + int rc; + + if (pm_device_is_busy(dev)) { + return -EBUSY; + } + + qspi_lock(dev); + qspi_clock_div_change(); + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + rc = qspi_suspend(dev); + break; + + case PM_DEVICE_ACTION_RESUME: + rc = qspi_resume(dev); break; default: - return -ENOTSUP; + rc = -ENOTSUP; } - return 0; + qspi_clock_div_restore(); + qspi_unlock(dev); + + return rc; } #endif /* CONFIG_PM_DEVICE */ void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) { struct qspi_nor_data *dev_data = dev->data; - int rc; if (dev_data->xip_enabled == enable) { return; } - rc = qspi_device_init(dev); - - if (rc != 0) { - LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", rc); - return; - } + qspi_acquire(dev); #if NRF_QSPI_HAS_XIPEN nrf_qspi_xip_set(NRF_QSPI, enable); #endif - qspi_lock(dev); if (enable) { (void)nrfx_qspi_activate(false); } dev_data->xip_enabled = enable; - qspi_unlock(dev); - qspi_device_uninit(dev); + qspi_release(dev); } #ifdef CONFIG_USERSPACE @@ -1502,11 +1380,12 @@ void z_vrfy_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) #endif /* CONFIG_USERSPACE */ static struct qspi_nor_data qspi_nor_dev_data = { +#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) + .count = Z_SEM_INITIALIZER(qspi_nor_dev_data.count, 0, K_SEM_MAX_LIMIT), +#endif #ifdef CONFIG_MULTITHREADING - .trans = Z_SEM_INITIALIZER(qspi_nor_dev_data.trans, 1, 1), .sem = Z_SEM_INITIALIZER(qspi_nor_dev_data.sem, 1, 1), .sync = Z_SEM_INITIALIZER(qspi_nor_dev_data.sync, 0, 1), - .count = Z_SEM_INITIALIZER(qspi_nor_dev_data.count, 0, K_SEM_MAX_LIMIT), #endif /* CONFIG_MULTITHREADING */ }; From ea1be7f242b9348863a27adb17215014f15b318a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 10 Nov 2023 16:52:12 +0100 Subject: [PATCH 0788/1049] drivers: nrf_qspi_nor: Fix and refactor driver initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far the driver first changed the configuration of the flash chip and after that checked the signature of that chip. This could lead to improper change of the chip configuration if the actually found one was different than that specified in devicetree. This commit reverses the order of these two initialization steps and also restructures a bit the initialization code. Signed-off-by: Andrzej Głąbek --- drivers/flash/nrf_qspi_nor.c | 125 +++++++++++++---------------------- 1 file changed, 45 insertions(+), 80 deletions(-) diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index aa6449763bed523..d6695989857f677 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -599,41 +599,10 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) return rc != 0 ? rc : rc2; } -/* Configures QSPI memory for the transfer */ -static int qspi_nrfx_configure(const struct device *dev) +static int configure_chip(const struct device *dev) { - struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - nrfx_err_t res; - int rc; - - res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev_data); - rc = qspi_get_zephyr_ret_code(res); - if (rc < 0) { - return rc; - } - -#if DT_INST_NODE_HAS_PROP(0, rx_delay) - if (!nrf53_errata_121()) { - nrf_qspi_iftiming_set(NRF_QSPI, DT_INST_PROP(0, rx_delay)); - } -#endif - - /* It may happen that after the flash chip was previously put into - * the DPD mode, the system was reset but the flash chip was not. - * Consequently, the flash chip can be in the DPD mode at this point. - * Some flash chips will just exit the DPD mode on the first CS pulse, - * but some need to receive the dedicated command to do it, so send it. - * This can be the case even if the current image does not have - * CONFIG_PM_DEVICE set to enter DPD mode, as a previously executing image - * (for example the main image if the currently executing image is the - * bootloader) might have set DPD mode before reboot. As a result, - * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. - */ - rc = exit_dpd(dev); - if (rc < 0) { - return rc; - } + int rc = 0; /* Set QE to match transfer mode. If not using quad * it's OK to leave QE set, but doing so prevents use @@ -784,33 +753,6 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, #endif /* CONFIG_FLASH_JESD216_API */ -/** - * @brief Retrieve the Flash JEDEC ID and compare it with the one expected - * - * @param dev The device structure - * @return 0 on success, negative errno code otherwise - */ -static inline int qspi_nor_read_id(const struct device *dev) -{ - uint8_t id[SPI_NOR_MAX_ID_LEN]; - int rc = qspi_rdid(dev, id); - - if (rc != 0) { - return -EIO; - } - - const struct qspi_nor_config *qnc = dev->config; - - if (memcmp(qnc->id, id, SPI_NOR_MAX_ID_LEN) != 0) { - LOG_ERR("JEDEC id [%02x %02x %02x] expect [%02x %02x %02x]", - id[0], id[1], id[2], - qnc->id[0], qnc->id[1], qnc->id[2]); - return -ENODEV; - } - - return 0; -} - static inline nrfx_err_t read_non_aligned(const struct device *dev, off_t addr, void *dest, size_t size) @@ -1077,35 +1019,58 @@ static int qspi_nor_write_protection_set(const struct device *dev, return rc; } -/** - * @brief Configure the flash - * - * @param dev The flash device structure - * @param info The flash info structure - * @return 0 on success, negative errno code otherwise - */ -static int qspi_nor_configure(const struct device *dev) +static int qspi_init(const struct device *dev) { - int rc = qspi_nrfx_configure(dev); + const struct qspi_nor_config *dev_config = dev->config; + uint8_t id[SPI_NOR_MAX_ID_LEN]; + nrfx_err_t res; + int rc; - if (rc != 0) { + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev->data); + rc = qspi_get_zephyr_ret_code(res); + if (rc < 0) { + return rc; + } + +#if DT_INST_NODE_HAS_PROP(0, rx_delay) + if (!nrf53_errata_121()) { + nrf_qspi_iftiming_set(NRF_QSPI, DT_INST_PROP(0, rx_delay)); + } +#endif + + /* It may happen that after the flash chip was previously put into + * the DPD mode, the system was reset but the flash chip was not. + * Consequently, the flash chip can be in the DPD mode at this point. + * Some flash chips will just exit the DPD mode on the first CS pulse, + * but some need to receive the dedicated command to do it, so send it. + * This can be the case even if the current image does not have + * CONFIG_PM_DEVICE set to enter DPD mode, as a previously executing image + * (for example the main image if the currently executing image is the + * bootloader) might have set DPD mode before reboot. As a result, + * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. + */ + rc = exit_dpd(dev); + if (rc < 0) { + return rc; + } + + /* Retrieve the Flash JEDEC ID and compare it with the one expected. */ + rc = qspi_rdid(dev, id); + if (rc < 0) { return rc; } - /* now the spi bus is configured, we can verify the flash id */ - if (qspi_nor_read_id(dev) != 0) { + if (memcmp(dev_config->id, id, SPI_NOR_MAX_ID_LEN) != 0) { + LOG_ERR("JEDEC id [%02x %02x %02x] expect [%02x %02x %02x]", + id[0], id[1], id[2], dev_config->id[0], + dev_config->id[1], dev_config->id[2]); return -ENODEV; } - return 0; + /* The chip is correct, it can be configured now. */ + return configure_chip(dev); } -/** - * @brief Initialize and configure the flash - * - * @param name The flash name - * @return 0 on success, negative errno code otherwise - */ static int qspi_nor_init(const struct device *dev) { const struct qspi_nor_config *dev_config = dev->config; @@ -1121,7 +1086,7 @@ static int qspi_nor_init(const struct device *dev) qspi_clock_div_change(); - rc = qspi_nor_configure(dev); + rc = qspi_init(dev); qspi_clock_div_restore(); From 7a9ff701d434801b6e7c4b0c4c118b69ea2adf92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 30 Oct 2023 15:56:34 +0100 Subject: [PATCH 0789/1049] drivers: pinctrl_nrf: Fix pin drive configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the introduction of nrfx 3.0.0, values of `nrf_gpio_pin_drive_t` constants may be defined differently, depending on the SoC family. Since the nrf-pinctrl.h file is included also from dts files, it is not possible to use there different definitions of `NRF_GPIO_PIN_*` values based on Kconfig symbols that indicate given SoC family (as Kconfig is processed after devicetree) so that those values could still match `nrf_gpio_pin_drive_t` constants. To solve this problem, the pinctrl_nrf driver now uses a lookup table for mapping `NRF_GPIO_PIN_*` indexes to drive configuration values required by the GPIO HAL. Signed-off-by: Andrzej Głąbek --- drivers/pinctrl/pinctrl_nrf.c | 48 ++++++++++++------- .../zephyr/dt-bindings/pinctrl/nrf-pinctrl.h | 3 +- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/drivers/pinctrl/pinctrl_nrf.c b/drivers/pinctrl/pinctrl_nrf.c index c2ac538c93b9da9..12ee1d5229415ba 100644 --- a/drivers/pinctrl/pinctrl_nrf.c +++ b/drivers/pinctrl/pinctrl_nrf.c @@ -13,19 +13,24 @@ BUILD_ASSERT(((NRF_PULL_NONE == NRF_GPIO_PIN_NOPULL) && (NRF_PULL_UP == NRF_GPIO_PIN_PULLUP)), "nRF pinctrl pull settings do not match HAL values"); -BUILD_ASSERT(((NRF_DRIVE_S0S1 == NRF_GPIO_PIN_S0S1) && - (NRF_DRIVE_H0S1 == NRF_GPIO_PIN_H0S1) && - (NRF_DRIVE_S0H1 == NRF_GPIO_PIN_S0H1) && - (NRF_DRIVE_H0H1 == NRF_GPIO_PIN_H0H1) && - (NRF_DRIVE_D0S1 == NRF_GPIO_PIN_D0S1) && - (NRF_DRIVE_D0H1 == NRF_GPIO_PIN_D0H1) && - (NRF_DRIVE_S0D1 == NRF_GPIO_PIN_S0D1) && - (NRF_DRIVE_H0D1 == NRF_GPIO_PIN_H0D1) && -#if defined(GPIO_PIN_CNF_DRIVE_E0E1) - (NRF_DRIVE_E0E1 == NRF_GPIO_PIN_E0E1) && -#endif /* defined(GPIO_PIN_CNF_DRIVE_E0E1) */ - (1U)), - "nRF pinctrl drive settings do not match HAL values"); +#if defined(GPIO_PIN_CNF_DRIVE_E0E1) || defined(GPIO_PIN_CNF_DRIVE0_E0) +#define NRF_DRIVE_COUNT (NRF_DRIVE_E0E1 + 1) +#else +#define NRF_DRIVE_COUNT (NRF_DRIVE_H0D1 + 1) +#endif +static const nrf_gpio_pin_drive_t drive_modes[NRF_DRIVE_COUNT] = { + [NRF_DRIVE_S0S1] = NRF_GPIO_PIN_S0S1, + [NRF_DRIVE_H0S1] = NRF_GPIO_PIN_H0S1, + [NRF_DRIVE_S0H1] = NRF_GPIO_PIN_S0H1, + [NRF_DRIVE_H0H1] = NRF_GPIO_PIN_H0H1, + [NRF_DRIVE_D0S1] = NRF_GPIO_PIN_D0S1, + [NRF_DRIVE_D0H1] = NRF_GPIO_PIN_D0H1, + [NRF_DRIVE_S0D1] = NRF_GPIO_PIN_S0D1, + [NRF_DRIVE_H0D1] = NRF_GPIO_PIN_H0D1, +#if defined(GPIO_PIN_CNF_DRIVE_E0E1) || defined(GPIO_PIN_CNF_DRIVE0_E0) + [NRF_DRIVE_E0E1] = NRF_GPIO_PIN_E0E1, +#endif +}; /* value to indicate pin level doesn't need initialization */ #define NO_WRITE UINT32_MAX @@ -86,12 +91,19 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) { for (uint8_t i = 0U; i < pin_cnt; i++) { - nrf_gpio_pin_drive_t drive = NRF_GET_DRIVE(pins[i]); + nrf_gpio_pin_drive_t drive; + uint8_t drive_idx = NRF_GET_DRIVE(pins[i]); uint32_t psel = NRF_GET_PIN(pins[i]); uint32_t write = NO_WRITE; nrf_gpio_pin_dir_t dir; nrf_gpio_pin_input_t input; + if (drive_idx < ARRAY_SIZE(drive_modes)) { + drive = drive_modes[drive_idx]; + } else { + return -EINVAL; + } + if (psel == NRF_PIN_DISCONNECTED) { psel = PSEL_DISCONNECTED; } @@ -165,22 +177,22 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, #if defined(NRF_PSEL_TWIM) case NRF_FUN_TWIM_SCL: NRF_PSEL_TWIM(reg, SCL) = psel; - if (drive == NRF_DRIVE_S0S1) { + if (drive == NRF_GPIO_PIN_S0S1) { /* Override the default drive setting with one * suitable for TWI/TWIM peripherals (S0D1). * This drive cannot be used always so that * users are able to select e.g. H0D1 or E0E1 * in devicetree. */ - drive = NRF_DRIVE_S0D1; + drive = NRF_GPIO_PIN_S0D1; } dir = NRF_GPIO_PIN_DIR_INPUT; input = NRF_GPIO_PIN_INPUT_CONNECT; break; case NRF_FUN_TWIM_SDA: NRF_PSEL_TWIM(reg, SDA) = psel; - if (drive == NRF_DRIVE_S0S1) { - drive = NRF_DRIVE_S0D1; + if (drive == NRF_GPIO_PIN_S0S1) { + drive = NRF_GPIO_PIN_S0D1; } dir = NRF_GPIO_PIN_DIR_INPUT; input = NRF_GPIO_PIN_INPUT_CONNECT; diff --git a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h index b2dcd7ae6c98fbe..9d7f8c2312fe139 100644 --- a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h @@ -131,7 +131,6 @@ /** * @name nRF pinctrl output drive. - * @note Values match nrf_gpio_pin_drive_t constants. * @{ */ @@ -152,7 +151,7 @@ /** High drive '0', disconnect '1'. */ #define NRF_DRIVE_H0D1 7U /** Extra high drive '0', extra high drive '1'. */ -#define NRF_DRIVE_E0E1 11U +#define NRF_DRIVE_E0E1 8U /** @} */ From 0bda2169a791ae5506a0e349f8256ec927b8cd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20E=2E=20Garc=C3=ADa?= Date: Sat, 18 Nov 2023 19:12:22 -0600 Subject: [PATCH 0790/1049] boards: xtensa: add heltec_wireless_stick_lite_v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support for the Wireless Stick Lite (V3), a development board from HelTec Automation. Signed-off-by: Adolfo E. García --- .../CMakeLists.txt | 6 + .../Kconfig.board | 13 + .../Kconfig.defconfig | 21 ++ .../Kconfig.sysbuild | 10 + .../heltec_wireless_stick_lite_v3/board.cmake | 9 + .../board_init.c | 30 ++ .../doc/heltec_wireless_stick_lite_v3.webp | Bin 0 -> 13134 bytes .../heltec_wireless_stick_lite_v3_pinout.webp | Bin 0 -> 59966 bytes .../doc/index.rst | 306 ++++++++++++++++++ ...heltec_wireless_stick_lite_v3-pinctrl.dtsi | 70 ++++ .../heltec_wireless_stick_lite_v3.dts | 215 ++++++++++++ .../heltec_wireless_stick_lite_v3.yaml | 22 ++ .../heltec_wireless_stick_lite_v3_defconfig | 14 + .../support/openocd.cfg | 7 + 14 files changed, 723 insertions(+) create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3.webp create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3_pinout.webp create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/doc/index.rst create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig create mode 100644 boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt b/boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt new file mode 100644 index 000000000000000..11856690835ccb0 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_GPIO_ESP32) + zephyr_library() + zephyr_library_sources(board_init.c) +endif() diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board new file mode 100644 index 000000000000000..a590916109dc308 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board @@ -0,0 +1,13 @@ +# Heltec Wireless Stick Lite (V3) board configuration + +# Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) +# Copyright (c) 2023 The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_HELTEC_WIRELESS_STICK_LITE + bool "Heltec Wireless Stick Lite (V3) Board" + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_FN8 +endchoice diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig new file mode 100644 index 000000000000000..ce6459f509e11f9 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig @@ -0,0 +1,21 @@ +# Heltec Wireless Stick Lite (V3) board configuration + +# Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) +# Copyright (c) 2023 The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "heltec_wireless_stick_lite_v3" + depends on BOARD_HELTEC_WIRELESS_STICK_LITE + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_SIZE + default 98304 if WIFI + default 40960 if BT + default 4096 + +choice BT_HCI_BUS_TYPE + default BT_ESP32 if BT +endchoice diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild new file mode 100644 index 000000000000000..3a2d17ac5cfd067 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT +endchoice + +choice BOOT_SIGNATURE_TYPE + default BOOT_SIGNATURE_TYPE_NONE +endchoice diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake b/boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake new file mode 100644 index 000000000000000..2f04d1fe8861ea6 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c b/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c new file mode 100644 index 000000000000000..f36032fcfa495d1 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) + * Copyright (c) 2023 The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define VEXT_PIN DT_GPIO_PIN(DT_NODELABEL(vext), gpios) + +static int board_heltec_wireless_stick_lite_v3_init(void) +{ + const struct device *gpio; + + gpio = DEVICE_DT_GET(DT_NODELABEL(gpio0)); + if (!device_is_ready(gpio)) { + return -ENODEV; + } + + /* turns external VCC on */ + gpio_pin_configure(gpio, VEXT_PIN, GPIO_OUTPUT); + gpio_pin_set_raw(gpio, VEXT_PIN, 0); + + return 0; +} + +SYS_INIT(board_heltec_wireless_stick_lite_v3_init, PRE_KERNEL_2, CONFIG_GPIO_INIT_PRIORITY); diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3.webp b/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3.webp new file mode 100644 index 0000000000000000000000000000000000000000..4cdb9bfdded8ab67afaebe781c4447389da01a18 GIT binary patch literal 13134 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 z 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 -DOPENOCD_DEFAULT_PATH=`` +parameter when building. + +Here is an example for building the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: heltec_wireless_stick_lite_v3 + :goals: build flash + :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= + +You can debug an application in the usual way. Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: heltec_wireless_stick_lite_v3 + :goals: debug + +References +********** + +- `Heltec Wireless Stick Lite (v3) Pinout Diagram `_ +- `Heltec Wireless Stick Lite (v3) Schematic Diagrams `_ +- `ESP-IDF Programming Guide `_ +- `esptool documentation `_ +- `OpenOCD ESP32 `_ + +.. [1] https://heltec.org/project/wireless-stick-lite-v2/ diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi new file mode 100644 index 000000000000000..6afc36ddec6ce24 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023 The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + uart1_default: uart1_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , + , + ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + twai_default: twai_default { + group1 { + pinmux = , + ; + }; + }; + + ledc0_default: ledc0_default { + group1 { + pinmux = ; + output-enable; + }; + }; +}; diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts new file mode 100644 index 000000000000000..c91564a303f5d35 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023 The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "heltec_wireless_stick_lite_v3-pinctrl.dtsi" +#include +#include +#include + +/ { + model = "heltec_wireless_stick_lite_v3"; + compatible = "espressif,esp32s3"; + + aliases { + pwm-0 = &ledc0; + pwm-led0 = &pwm_led_white; + uart-0 = &uart0; + uart-1 = &uart1; + i2c-0 = &i2c0; + lora0 = &lora0; + sw0 = &button0; + watchdog0 = &wdt0; + }; + + leds { + compatible = "gpio-leds"; + + vext: vext { + gpios = <&gpio0 36 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Vext Control"; + }; + + adc: adc { + gpios = <&gpio0 37 GPIO_ACTIVE_LOW>; + label = "ADC Control"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led_white: pwm_led_gpio0_35 { + label = "White PWM LED"; + pwms = <&ledc0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "USER SW"; + zephyr,code = ; + }; + }; + + vbatt { + compatible = "voltage-divider"; + io-channels = <&adc1 0>; + output-ohms = <100000>; + full-ohms = <(100000 + 390000)>; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&adc1 { + status ="okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&ledc0 { + pinctrl-0 = <&ledc0_default>; + pinctrl-names = "default"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + channel0@0 { + reg = <0x0>; + timer = <0>; + }; +}; + +&i2c0 { + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; + lora0: lora@0 { + compatible = "semtech,sx1262"; + reg = <0>; + reset-gpios = <&gpio0 12 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; + busy-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + dio1-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + dio2-tx-enable; + dio3-tcxo-voltage = ; + tcxo-power-startup-delay-ms = <5>; + spi-max-frequency = <16000000>; + }; +}; + +&twai { + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; + bus-speed = <125000>; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 64kB for the bootloader */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x00010000>; + read-only; + }; + + /* Reserve 1024kB for the application in slot 0 */ + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + /* Reserve 1024kB for the application in slot 1 */ + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + /* Reserve 256kB for the scratch partition */ + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml new file mode 100644 index 000000000000000..05c89b6d9842573 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml @@ -0,0 +1,22 @@ +identifier: heltec_wireless_stick_lite_v3 +name: Heltec Wireless Stick Lite (V3) +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - spi + - can + - counter + - watchdog + - entropy + - pwm + - dma + - lora +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig new file mode 100644 index 000000000000000..a32ddde0422cdf2 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_HELTEC_WIRELESS_STICK_LITE=y +CONFIG_SOC_SERIES_ESP32S3=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CLOCK_CONTROL=y +CONFIG_CONSOLE=y +CONFIG_GPIO=y +CONFIG_PWM=y +CONFIG_SERIAL=y +CONFIG_SPI=y +CONFIG_UART_CONSOLE=y diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg b/boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg new file mode 100644 index 000000000000000..2f740b4a36ab1f4 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg @@ -0,0 +1,7 @@ +set ESP_RTOS none +set ESP32_ONLYCPU 1 + +# Source the JTAG interface configuration file +source [find interface/esp_usb_jtag.cfg] +# Source the ESP32-S3 configuration file +source [find target/esp32s3.cfg] From 7d63942c31709739578797ce91b69818308bd9e1 Mon Sep 17 00:00:00 2001 From: Alexander Leris Date: Fri, 3 Nov 2023 01:16:00 +1100 Subject: [PATCH 0791/1049] doc: logging: Fix some grammar issues Fixes some grammar issues in the documentation. Signed-off-by: Alexander Leris --- doc/services/logging/index.rst | 63 ++++++++++++++++--------------- include/zephyr/logging/log_ctrl.h | 2 +- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/doc/services/logging/index.rst b/doc/services/logging/index.rst index 2b9fe9a707a5492..84d862b9076fadd 100644 --- a/doc/services/logging/index.rst +++ b/doc/services/logging/index.rst @@ -124,9 +124,9 @@ allocated. :kconfig:option:`CONFIG_LOG_PRINTK`: Redirect printk calls to the logging. -:kconfig:option:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`: When number of buffered log -messages reaches the threshold dedicated thread (see :c:func:`log_thread_set`) -is waken up. If :kconfig:option:`CONFIG_LOG_PROCESS_THREAD` is enabled then this +:kconfig:option:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`: When the number of buffered log +messages reaches the threshold, the dedicated thread (see :c:func:`log_thread_set`) +is woken up. If :kconfig:option:`CONFIG_LOG_PROCESS_THREAD` is enabled then this threshold is used by the internal thread. :kconfig:option:`CONFIG_LOG_PROCESS_THREAD`: When enabled, logging thread is created @@ -242,7 +242,7 @@ Logging in a module instance ============================ In case of modules which are multi-instance and instances are widely used -across the system enabling logs will lead to flooding. Logger provide the tools +across the system enabling logs will lead to flooding. The logger provides the tools which can be used to provide filtering on instance level rather than module level. In that case logging can be enabled for particular instance. @@ -305,16 +305,16 @@ By default, logging processing in deferred mode is handled internally by the dedicated task which starts automatically. However, it might not be available if multithreading is disabled. It can also be disabled by unsetting :kconfig:option:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`. In that case, logging can -be controlled using API defined in :zephyr_file:`include/zephyr/logging/log_ctrl.h`. -Logging must be initialized before it can be used. Optionally, user can provide -function which returns timestamp value. If not provided, :c:macro:`k_cycle_get` +be controlled using the API defined in :zephyr_file:`include/zephyr/logging/log_ctrl.h`. +Logging must be initialized before it can be used. Optionally, the user can provide +a function which returns the timestamp value. If not provided, :c:macro:`k_cycle_get` or :c:macro:`k_cycle_get_32` is used for timestamping. -:c:func:`log_process` function is used to trigger processing of one log -message (if pending). Function returns true if there is more messages pending. +The :c:func:`log_process` function is used to trigger processing of one log +message (if pending), and returns true if there are more messages pending. However, it is recommended to use macro wrappers (:c:macro:`LOG_INIT` and -:c:macro:`LOG_PROCESS`) which handles case when logging is disabled. +:c:macro:`LOG_PROCESS`) which handle the case where logging is disabled. -Following snippet shows how logging can be processed in simple forever loop. +The following snippet shows how logging can be processed in simple forever loop. .. code-block:: c @@ -356,16 +356,17 @@ that moment all logs are processed in a blocking way. Printk ****** -Typically, logging and :c:func:`printk` is using the same output for which they -compete. This can lead to issues if the output does not support preemption but -also it may result in the corrupted output because logging data is interleaved -with printk data. However, it is possible to redirect printk messages to the +Typically, logging and :c:func:`printk` use the same output, which they compete +for. This can lead to issues if the output does not support preemption but it may +also result in corrupted output because logging data is interleaved with printk +data. However, it is possible to redirect printk messages to the logging subsystem by enabling :kconfig:option:`CONFIG_LOG_PRINTK`. In that case, printk entries are treated as log messages with level 0 (they cannot be disabled). When enabled, logging manages the output so there is no interleaving. However, -in the deferred mode it changes the behavior of the printk because output is delayed -until logging thread processes the data. :kconfig:option:`CONFIG_LOG_PRINTK` is by -default enabled. +in deferred mode the printk behaviour is changed since the output is delayed +until the logging thread processes the data. :kconfig:option:`CONFIG_LOG_PRINTK` +is enabled by default. + .. _log_architecture: @@ -384,27 +385,27 @@ instance of a module. Default Frontend ================ -Default frontend is engaged when logging API is called in a source of logging (e.g. +Default frontend is engaged when the logging API is called in a source of logging (e.g. :c:macro:`LOG_INF`) and is responsible for filtering a message (compile and run -time), allocating buffer for the message, creating the message and committing that -message. Since logging API can be called in an interrupt, frontend is optimized +time), allocating a buffer for the message, creating the message and committing that +message. Since the logging API can be called in an interrupt, the frontend is optimized to log the message as fast as possible. Log message ----------- -Log message contains message descriptor (source, domain and level), timestamp, +A log message contains a message descriptor (source, domain and level), timestamp, formatted string details (see :ref:`cbprintf_packaging`) and optional data. Log messages are stored in a continuous block of memory. -Memory is allocated from a circular packet buffer (:ref:`mpsc_pbuf`). It has -few consequences: +Memory is allocated from a circular packet buffer (:ref:`mpsc_pbuf`), which has +a few consequences: - * Each message is self-contained, continuous block of memory thus it is suited + * Each message is a self-contained, continuous block of memory thus it is suited for copying the message (e.g. for offline processing). * Messages must be sequentially freed. Backend processing is synchronous. Backend can make a copy for deferred processing. -Log message has following format: +A log message has following format: +------------------+----------------------------------------------------+ | Message Header | 2 bits: MPSC packet buffer header | @@ -446,12 +447,12 @@ Log message has following format: Log message allocation ---------------------- -It may happen that frontend cannot allocate a message. It happens if system is -generating more log messages than it can process in certain time frame. There -are two strategies to handle that case: +It may happen that the frontend cannot allocate a message. This happens if the +system is generating more log messages than it can process in certain time +frame. There are two strategies to handle that case: -- No overflow - new log is dropped if space for a message cannot be allocated. -- Overflow - oldest pending messages are freed, until new message can be +- No overflow - the new log is dropped if space for a message cannot be allocated. +- Overflow - the oldest pending messages are freed, until the new message can be allocated. Enabled by :kconfig:option:`CONFIG_LOG_MODE_OVERFLOW`. Note that it degrades performance thus it is recommended to adjust buffer size and amount of enabled logs to limit dropping. diff --git a/include/zephyr/logging/log_ctrl.h b/include/zephyr/logging/log_ctrl.h index dc5f39a2e7df6e1..6b8a5ec0414220c 100644 --- a/include/zephyr/logging/log_ctrl.h +++ b/include/zephyr/logging/log_ctrl.h @@ -82,7 +82,7 @@ __syscall void log_panic(void); /** * @brief Process one pending log message. * - * @retval true There is more messages pending to be processed. + * @retval true There are more messages pending to be processed. * @retval false No messages pending. */ __syscall bool log_process(void); From 0d42acadb43463a15bcb5be2ef39fb7c2af516bd Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 2 Oct 2023 15:10:08 +0200 Subject: [PATCH 0792/1049] boards: nucleo_wb55rg: Use stm32cubeprogrammer as default runner When playing with PM related applications, stm32cubeprogrammer is useful to allow flashing even when SoC is in Stop mode. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wb55rg/board.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/nucleo_wb55rg/board.cmake b/boards/arm/nucleo_wb55rg/board.cmake index 83fd477865f0d5d..75762ef577e8109 100644 --- a/boards/arm/nucleo_wb55rg/board.cmake +++ b/boards/arm/nucleo_wb55rg/board.cmake @@ -2,6 +2,6 @@ board_runner_args(pyocd "--target=stm32wb55rgvx") board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) -include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) From e5ab70b72431b143766935c434f139ae9b5cd3e5 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 16 Nov 2023 12:17:59 +0100 Subject: [PATCH 0793/1049] drivers: uart: stm32: Complete wakeup feature Serial wakeup feature was only working whe DBG in Stop mode setting was enabled. Add required changes to make it functional also when this configuration isn't set. Signed-off-by: Erwan Gouriou --- drivers/serial/uart_stm32.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index fa2371cc1dfab24..5c1ff75bd6d11af 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1278,6 +1278,18 @@ static void uart_stm32_isr(const struct device *dev) /* Clear errors */ uart_stm32_err_check(dev); #endif /* CONFIG_UART_ASYNC_API */ + +#ifdef CONFIG_PM + if (LL_USART_IsEnabledIT_WKUP(config->usart) && + LL_USART_IsActiveFlag_WKUP(config->usart)) { + + LL_USART_ClearFlag_WKUP(config->usart); +#ifdef USART_ISR_REACK + while (LL_USART_IsActiveFlag_REACK(config->usart) == 0) { + } +#endif + } +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API || CONFIG_PM */ @@ -2005,7 +2017,14 @@ static int uart_stm32_init(const struct device *dev) * CONFIG_PM_DEVICE=n : Always active * CONFIG_PM_DEVICE=y : Controlled by pm_device_wakeup_enable() */ + + LL_USART_Disable(config->usart); + LL_USART_SetWKUPType(config->usart, LL_USART_WAKEUP_ON_RXNE); + LL_USART_EnableIT_WKUP(config->usart); + LL_USART_ClearFlag_WKUP(config->usart); LL_USART_EnableInStopMode(config->usart); + LL_USART_Enable(config->usart); + if (config->wakeup_line != STM32_EXTI_LINE_NONE) { /* Prepare the WAKEUP with the expected EXTI line */ LL_EXTI_EnableIT_0_31(BIT(config->wakeup_line)); From b4fcbc4eb68d4def62187fa0bb4f1f12ea782ae7 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 16 Nov 2023 12:21:20 +0100 Subject: [PATCH 0794/1049] samples: boards: stm32: serial_wakeup: Fix nucloe_wb55rg configuration On STM32WB55 series, wakeup in stop mode is not supported. Disable this state in order to support this sample. Add comments to other sections of the configuration. Signed-off-by: Erwan Gouriou --- .../boards/nucleo_wb55rg.overlay | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay index f924e6fdea5f4d1..bcbed7c5824b136 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay @@ -1,19 +1,35 @@ /* * Copyright (c) 2022 Linaro Limited + * Copyright (c) 2022 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ -&clk_hsi { - status = "okay"; +&cpu0{ + /* USART Wakeup requires automatic HSI16 switch on in deepsleep mode + * which isn't possible in Stop Mode 2. + * Remove Stop Mode 2 from supported modes + */ + cpu-power-states = <&stop0 &stop1>; }; &usart1 { + /* Set domain clock to HSI to allow wakeup from Stop mode */ clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, <&rcc STM32_SRC_HSI USART1_SEL(2)>; + /* Configure device as wakeup source */ wakeup-source; + /* Configure sleep pinctrl configuration which will be used when + * device is not configured as wakeup source by the application. + * This use case is only applicable in PM_DEVICE mode. + */ pinctrl-1 = <&analog_pb6 &analog_pb7>; pinctrl-names = "default", "sleep"; }; + +&clk_hsi { + /* Make sure HSI is enabled */ + status = "okay"; +}; From 6a96ee88b319db55cf507d16c274ea903e90fbd9 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 16 Nov 2023 12:25:13 +0100 Subject: [PATCH 0795/1049] samples: boards: stm32: serial_wakeup: Minor changes Cleanup sample yaml file and code comments. Enable PM_DEVICE_RUNTIME mode. Signed-off-by: Erwan Gouriou --- samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf | 5 +++-- samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml | 2 -- samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf b/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf index 3e1a61bf9db99df..ca1e6cf73a9df25 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf @@ -1,7 +1,8 @@ CONFIG_PM=y CONFIG_PM_DEVICE=y -CONFIG_PM_DEVICE_RUNTIME=n -CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=y + CONFIG_SHELL=y CONFIG_DEBUG=n diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml b/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml index 42528be505d0245..e0f61361500c587 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml @@ -4,8 +4,6 @@ tests: sample.boards.stm32.power_mgmt.serial_wakeup: tags: - UART - - Wake - - up - power harness: console harness_config: diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c b/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c index 74284abf41b6964..35846c04411686e 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c @@ -24,7 +24,8 @@ int main(void) #if CONFIG_PM_DEVICE /* In PM_DEVICE modes, enable device as a wakeup source will prevent * system to switch it off (clock off, set pins to sleep configuration, ...) - * It is not requested in PM mode only since this mode will not + * It is not requested in CONFIG_PM mode only as in this case, device is not + * suspended before stop mode entry. */ bool ret; From c6bba39f4d8d4ac4148a59e5d8cdc0c26b9c9926 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 16 Nov 2023 12:29:34 +0100 Subject: [PATCH 0796/1049] dts: stm32wl: Configure LPUART wakeup line Rather than configuring in serial_wakeup sample, define LPUART1 wakeup line in wl.dtsi file. Additionally make few cosmetic changes to nucleo_wl55rj overlay in serial wakeup sample. Signed-off-by: Erwan Gouriou --- dts/arm/st/wl/stm32wl.dtsi | 1 + .../serial_wakeup/boards/nucleo_wl55jc.overlay | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index cc4b4dc31c9ac9b..feeb013af6e30a2 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -259,6 +259,7 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000001>; resets = <&rctl STM32_RESET(APB1H, 0U)>; interrupts = <38 0>; + wakeup-line = <28>; status = "disabled"; }; diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay index 83c607ff8a05283..8b6b062cd67f54a 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay @@ -4,17 +4,20 @@ * SPDX-License-Identifier: Apache-2.0 */ -&clk_lse { - status = "okay"; -}; -/* LPUART1 clock source on LSE : set console at 9600 */ &lpuart1 { - /delete-property/ clocks; + /* Set domain clock to LSE to allow wakeup from Stop mode */ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000001>, <&rcc STM32_SRC_LSE LPUART1_SEL(3)>; + /* LPUART1 clock source on LSE : set console at 9600 */ current-speed = <9600>; + + /* Enable as wakeup source */ wakeup-source; - wakeup-line = <28>; +}; + +&clk_lse { + /* Make sure LSE clock is enabled */ + status = "okay"; }; From 5b9605a6a20c0ebe2dab063a1b818dfb1826dc19 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 24 Aug 2023 12:20:50 -0700 Subject: [PATCH 0797/1049] xtensa: mmu: implement cached/uncached ptr funcs if !RPO_CACHE This implements the following functions when CONFIG_XTENSA_RPO_CACHE is false: * arch_xtensa_is_ptr_cached() returns false * arch_xtensa_is_ptr_uncached() returns false * arch_xtensa_cached_ptr() returns unmodified pointer * arch_xtensa_uncached_ptr() returns unmodified pointer Signed-off-by: Daniel Leung --- include/zephyr/arch/xtensa/arch.h | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 2d13615a753ac9d..0838e68ee5a64d7 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -243,7 +243,33 @@ static inline void *arch_xtensa_uncached_ptr(void __sparse_cache *ptr) FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \ } while (0) -#endif +#else /* CONFIG_XTENSA_RPO_CACHE */ + +static inline bool arch_xtensa_is_ptr_cached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline bool arch_xtensa_is_ptr_uncached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline void *arch_xtensa_cached_ptr(void *ptr) +{ + return ptr; +} + +static inline void *arch_xtensa_uncached_ptr(void *ptr) +{ + return ptr; +} + +#endif /* CONFIG_XTENSA_RPO_CACHE */ #ifdef CONFIG_XTENSA_MMU extern void arch_xtensa_mmu_post_init(bool is_core0); From 080e14f0f454b9a443de44329957cb5bcbf21a51 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Mon, 21 Aug 2023 16:54:04 -0700 Subject: [PATCH 0798/1049] arch/xtensa: Rename "ALLOCA" ZSR to "A0SAVE" This register alias was originally introduced to allow A0 to be used as a scratch register when handling exceptions from MOVSP instructions. (It replaced some upstream code from Cadence that hard-coded EXCSAVE1). Now the MMU code is now using too, and for exactly the same purpose. Calling it "ALLOCA" is only confusing. Rename it to make it clear what it's doing. Signed-off-by: Andy Ross --- arch/xtensa/core/gen_zsr.py | 2 +- arch/xtensa/core/window_vectors.S | 4 ++-- arch/xtensa/core/xtensa-asm2-util.S | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/xtensa/core/gen_zsr.py b/arch/xtensa/core/gen_zsr.py index 8d052f4891d70fa..574542a4578ed1e 100755 --- a/arch/xtensa/core/gen_zsr.py +++ b/arch/xtensa/core/gen_zsr.py @@ -11,7 +11,7 @@ # -dM") core-isa.h file for the current architecture and assigns # registers to usages. -NEEDED = ("ALLOCA", "CPU", "FLUSH") +NEEDED = ("A0SAVE", "CPU", "FLUSH") coreisa = sys.argv[1] outfile = sys.argv[2] diff --git a/arch/xtensa/core/window_vectors.S b/arch/xtensa/core/window_vectors.S index a63923cbd6fc2dd..90eba495bde809b 100644 --- a/arch/xtensa/core/window_vectors.S +++ b/arch/xtensa/core/window_vectors.S @@ -84,7 +84,7 @@ _WindowUnderflow4: /* Handle alloca exception generated by interruptee executing 'movsp'. * This uses space between the window vectors, so is essentially * "free". All interruptee's regs are intact except a0 which is saved - * in $ZSR_ALLOCA (assigned at build time, see gen_zsr.py for + * in $ZSR_A0SAVE (assigned at build time, see gen_zsr.py for * details), and PS.EXCM has been set by the exception hardware (can't * be interrupted). The fact the alloca exception was taken means the * registers associated with the base-save area have been spilled and @@ -102,7 +102,7 @@ _xt_alloca_exc: rsr a2, PS extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS xor a3, a3, a4 /* bits changed from old to current windowbase */ - rsr a4, ZSR_ALLOCA /* restore original a0 (now in a4) */ + rsr a4, ZSR_A0SAVE /* restore original a0 (now in a4) */ slli a3, a3, XCHAL_PS_OWB_SHIFT xor a2, a2, a3 /* flip changed bits in old window base */ wsr a2, PS /* update PS.OWB to new window base */ diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index d7ba88aaffc397c..bc526ae0165e248 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -342,7 +342,7 @@ DEF_EXCINT XCHAL_DEBUGLEVEL, _handle_excint, xtensa_debugint_c .pushsection .UserExceptionVector.text, "ax" .global _Level1RealVector _Level1RealVector: - wsr a0, ZSR_ALLOCA + wsr a0, ZSR_A0SAVE rsync rsr.exccause a0 #ifdef CONFIG_XTENSA_MMU @@ -355,7 +355,7 @@ _Level1RealVector: j _xt_alloca_exc _not_alloca: - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE j _Level1Vector #ifdef CONFIG_XTENSA_MMU _handle_tlb_miss_user: @@ -374,7 +374,7 @@ _handle_tlb_miss_user: */ rsr.ptevaddr a0 l32i a0, a0, 0 - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE rfe #endif /* CONFIG_XTENSA_MMU */ .popsection @@ -391,12 +391,12 @@ _handle_tlb_miss_user: .global _KernelExceptionVector _KernelExceptionVector: #ifdef CONFIG_XTENSA_MMU - wsr a0, ZSR_ALLOCA + wsr a0, ZSR_A0SAVE rsr.exccause a0 beqi a0, EXCCAUSE_ITLB_MISS, _handle_tlb_miss_kernel addi a0, a0, -EXCCAUSE_DTLB_MISS beqz a0, _handle_tlb_miss_kernel - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE #endif j _Level1Vector #ifdef CONFIG_XTENSA_MMU @@ -410,7 +410,7 @@ _handle_tlb_miss_kernel: */ rsr.ptevaddr a0 l32i a0, a0, 0 - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE rfe #endif .popsection @@ -420,14 +420,14 @@ _handle_tlb_miss_kernel: .global _DoubleExceptionVector _DoubleExceptionVector: #ifdef CONFIG_XTENSA_MMU - wsr a0, ZSR_ALLOCA + wsr a0, ZSR_A0SAVE rsync rsr.exccause a0 addi a0, a0, -EXCCAUSE_DTLB_MISS beqz a0, _handle_tlb_miss_dblexc - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE #endif #if defined(CONFIG_SIMULATOR_XTENSA) || defined(XT_SIMULATOR) 1: @@ -459,7 +459,7 @@ _handle_tlb_miss_dblexc: rsr.ptevaddr a0 l32i a0, a0, 0 - rsr a0, ZSR_ALLOCA + rsr a0, ZSR_A0SAVE rfde #endif .popsection From 3620e6b969d69d63e08c443234a9b49427949df3 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Sun, 27 Aug 2023 09:03:20 -0700 Subject: [PATCH 0799/1049] drivers/console: xtensa_sim_console: implement arch_printk_char_out() This is an older driver and didn't support the weak arch_printk_char_out() hook, which is a link-time symbol that allows logging to work from the first instruction. Some drivers can't do that because they need an initialization step, but this one works great. Signed-off-by: Andy Ross --- drivers/console/xtensa_sim_console.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/console/xtensa_sim_console.c b/drivers/console/xtensa_sim_console.c index 16e48eeee484fdc..316162ddc0c1afd 100644 --- a/drivers/console/xtensa_sim_console.c +++ b/drivers/console/xtensa_sim_console.c @@ -13,7 +13,7 @@ * @param c Character to output * @return The character passed as input. */ -static int console_out(int c) +int arch_printk_char_out(int c) { char buf[16]; @@ -54,8 +54,8 @@ extern void __printk_hook_install(int (*fn)(int)); */ static void xt_sim_console_hook_install(void) { - __stdout_hook_install(console_out); - __printk_hook_install(console_out); + __stdout_hook_install(arch_printk_char_out); + __printk_hook_install(arch_printk_char_out); } /** From a1bb2b9c640359f4d8f6f3ea9c5e89a5b821e62a Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 17 Nov 2023 13:54:36 -0800 Subject: [PATCH 0800/1049] xtensa: mmu: Simplify autorefill TLB helpers Replace all autorefill helpers with only one that invalidates both, DTLB and ITLB, since that is what is really needed. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/include/xtensa_mmu_priv.h | 115 +++------------------ 1 file changed, 14 insertions(+), 101 deletions(-) diff --git a/arch/xtensa/core/include/xtensa_mmu_priv.h b/arch/xtensa/core/include/xtensa_mmu_priv.h index 7519c1b6010649f..dcfb9deefc0d540 100644 --- a/arch/xtensa/core/include/xtensa_mmu_priv.h +++ b/arch/xtensa/core/include/xtensa_mmu_priv.h @@ -163,119 +163,32 @@ static ALWAYS_INLINE void xtensa_itlb_entry_write_sync(uint32_t pte, uint32_t en } /** - * @brief Invalidate all ITLB entries. + * @brief Invalidate all autorefill DTLB and ITLB entries. * - * This should be used carefully since all entries in the instruction TLB - * will be erased and the only way to find lookup a physical address will be - * through the page tables. - */ -static inline void xtensa_itlb_invalidate_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_ITLB_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_itlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} - -/** - * @brief Invalidate all DTLB entries. + * This should be used carefully since all refill entries in the data + * and instruction TLB. At least two pages, the current code page and + * the current stack, will be repopulated by this code as it returns. * - * This should be used carefully since all entries in the data TLB will be - * erased and the only way to find lookup a physical address will be through - * the page tables. + * This needs to be called in any circumstance where the mappings for + * a previously-used page table change. It does not need to be called + * on context switch, where ASID tagging isolates entries for us. */ -static inline void xtensa_dtlb_invalidate_sync(void) +static inline void xtensa_tlb_autorefill_invalidate(void) { - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_DTLB_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_dtlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} + uint8_t way, i, entries; -/** - * @brief Invalidates an autorefill DTLB entry. - * - * Invalidates the page table enrty that maps a given virtual address. - */ -static inline void xtensa_dtlb_autorefill_invalidate_sync(void *vaddr) -{ - uint8_t way; + entries = BIT(MAX(XCHAL_ITLB_ARF_ENTRIES_LOG2, + XCHAL_DTLB_ARF_ENTRIES_LOG2)); for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - xtensa_dtlb_entry_invalidate(Z_XTENSA_TLB_ENTRY((uint32_t)vaddr, way)); - } - __asm__ volatile("dsync"); -} - -/** - * @brief Invalidates an autorefill ITLB entry. - * - * Invalidates the page table enrty that maps a given virtual address. - */ -static inline void xtensa_itlb_autorefill_invalidate_sync(void *vaddr) -{ - uint8_t way; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - xtensa_itlb_entry_invalidate(Z_XTENSA_TLB_ENTRY((uint32_t)vaddr, way)); - } - __asm__ volatile("isync"); -} -/** - * @brief Invalidate all autorefill ITLB entries. - * - * This should be used carefully since all entries in the instruction TLB - * will be erased and the only way to find lookup a physical address will be - * through the page tables. - */ -static inline void xtensa_itlb_autorefill_invalidate_all_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) { + for (i = 0; i < entries; i++) { uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_itlb_entry_invalidate(entry); + xtensa_dtlb_entry_invalidate_sync(entry); + xtensa_itlb_entry_invalidate_sync(entry); } } - __asm__ volatile("isync"); } -/** - * @brief Invalidate all autorefill DTLB entries. - * - * This should be used carefully since all entries in the data TLB will be - * erased and the only way to find lookup a physical address will be through - * the page tables. - */ -static inline void xtensa_dtlb_autorefill_invalidate_all_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_dtlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} - - /** * @brief Set the page tables. * From fff91cb5425c75a0118a61fe69089a7fcfc3c0e4 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 1 Nov 2023 22:55:43 -0700 Subject: [PATCH 0801/1049] xtensa: mmu: Simplify initialization Simplify the logic around xtensa_mmu_init. - Do not have a different path to init part of kernel - Call xtensa_mmu_init from C Signed-off-by: Flavio Ceolin --- arch/xtensa/core/crt1.S | 8 -------- arch/xtensa/core/xtensa_mmu.c | 17 +++-------------- arch/xtensa/include/kernel_arch_func.h | 16 +++++----------- include/zephyr/arch/xtensa/xtensa_mmu.h | 2 -- 4 files changed, 8 insertions(+), 35 deletions(-) diff --git a/arch/xtensa/core/crt1.S b/arch/xtensa/core/crt1.S index 0fa3ad230995c41..c616b0889d7198e 100644 --- a/arch/xtensa/core/crt1.S +++ b/arch/xtensa/core/crt1.S @@ -24,10 +24,6 @@ .global __start .type z_cstart, @function -#ifdef CONFIG_XTENSA_MMU -.type z_xtensa_mmu_init, @function -#endif - /* Macros to abstract away ABI differences */ @@ -192,10 +188,6 @@ _start: #endif /* !XCHAL_HAVE_BOOTLOADER */ -#ifdef CONFIG_XTENSA_MMU - CALL z_xtensa_mmu_init -#endif - /* Enter C domain, never returns from here */ CALL z_cstart diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index e50c51a3848f55b..18ce5f22f63466d 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -213,19 +213,18 @@ __weak void arch_xtensa_mmu_post_init(bool is_core0) ARG_UNUSED(is_core0); } -static void xtensa_mmu_init(bool is_core0) +void z_xtensa_mmu_init(void) { volatile uint8_t entry; uint32_t ps, vecbase; - if (is_core0) { + if (_current_cpu->id == 0) { /* This is normally done via arch_kernel_init() inside z_cstart(). * However, before that is called, we go through the sys_init of * INIT_LEVEL_EARLY, which is going to result in TLB misses. * So setup whatever necessary so the exception handler can work * properly. */ - z_xtensa_kernel_init(); xtensa_init_page_tables(); } @@ -326,17 +325,7 @@ static void xtensa_mmu_init(bool is_core0) xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); - arch_xtensa_mmu_post_init(is_core0); -} - -void z_xtensa_mmu_init(void) -{ - xtensa_mmu_init(true); -} - -void z_xtensa_mmu_smp_init(void) -{ - xtensa_mmu_init(false); + arch_xtensa_mmu_post_init(_current_cpu->id == 0); } #ifdef CONFIG_ARCH_HAS_RESERVED_PAGE_FRAMES diff --git a/arch/xtensa/include/kernel_arch_func.h b/arch/xtensa/include/kernel_arch_func.h index 6427b306e623190..2256f72f64544d0 100644 --- a/arch/xtensa/include/kernel_arch_func.h +++ b/arch/xtensa/include/kernel_arch_func.h @@ -25,7 +25,7 @@ extern void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf); K_KERNEL_STACK_ARRAY_DECLARE(z_interrupt_stacks, CONFIG_MP_MAX_NUM_CPUS, CONFIG_ISR_STACK_SIZE); -static ALWAYS_INLINE void z_xtensa_kernel_init(void) +static ALWAYS_INLINE void arch_kernel_init(void) { _cpu_t *cpu0 = &_kernel.cpus[0]; @@ -51,21 +51,15 @@ static ALWAYS_INLINE void z_xtensa_kernel_init(void) * win. */ XTENSA_WSR(ZSR_CPU_STR, cpu0); -} - -static ALWAYS_INLINE void arch_kernel_init(void) -{ -#ifndef CONFIG_XTENSA_MMU - /* This is called in z_xtensa_mmu_init() before z_cstart() - * so we do not need to call it again. - */ - z_xtensa_kernel_init(); -#endif #ifdef CONFIG_INIT_STACKS memset(Z_KERNEL_STACK_BUFFER(z_interrupt_stacks[0]), 0xAA, K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0])); #endif + +#ifdef CONFIG_XTENSA_MMU + z_xtensa_mmu_init(); +#endif } void xtensa_switch(void *switch_to, void **switched_from); diff --git a/include/zephyr/arch/xtensa/xtensa_mmu.h b/include/zephyr/arch/xtensa/xtensa_mmu.h index d03f876af30b114..2ee3dc6c9ab8ee9 100644 --- a/include/zephyr/arch/xtensa/xtensa_mmu.h +++ b/include/zephyr/arch/xtensa/xtensa_mmu.h @@ -26,6 +26,4 @@ extern int xtensa_soc_mmu_ranges_num; void z_xtensa_mmu_init(void); -void z_xtensa_mmu_smp_init(void); - #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H */ From a651862b300ddb119d2ecb980d15ae5516c7de8e Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 14 Dec 2022 00:35:36 -0800 Subject: [PATCH 0802/1049] xtensa: Enable userspace Userspace support for Xtensa architecture using Xtensa MMU. Some considerations: - Syscalls are not inline functions like in other architectures because some compiler issues when using multiple registers to pass parameters to the syscall. So here we have a function call so we can use registers as we need. - TLS is not supported by xcc in xtensa and reading PS register is a privileged instruction. So, we have to use threadptr to know if a thread is an user mode thread. Signed-off-by: Flavio Ceolin Signed-off-by: Daniel Leung --- arch/Kconfig | 1 + arch/xtensa/Kconfig | 20 + arch/xtensa/core/CMakeLists.txt | 2 + arch/xtensa/core/fatal.c | 9 + arch/xtensa/core/include/xtensa_mmu_priv.h | 83 ++- arch/xtensa/core/offsets/offsets.c | 7 + arch/xtensa/core/syscall_helper.c | 124 ++++ arch/xtensa/core/userspace.S | 302 ++++++++ arch/xtensa/core/xtensa-asm2-util.S | 21 +- arch/xtensa/core/xtensa-asm2.c | 44 +- arch/xtensa/core/xtensa_mmu.c | 772 +++++++++++++++++++-- arch/xtensa/include/kernel_arch_func.h | 7 + arch/xtensa/include/offsets_short_arch.h | 16 +- arch/xtensa/include/xtensa-asm2-s.h | 13 +- include/zephyr/arch/syscall.h | 2 + include/zephyr/arch/xtensa/arch.h | 10 + include/zephyr/arch/xtensa/syscall.h | 238 +++++++ include/zephyr/arch/xtensa/thread.h | 9 + include/zephyr/arch/xtensa/xtensa_mmu.h | 34 + 19 files changed, 1646 insertions(+), 68 deletions(-) create mode 100644 arch/xtensa/core/syscall_helper.c create mode 100644 arch/xtensa/core/userspace.S create mode 100644 include/zephyr/arch/xtensa/syscall.h diff --git a/arch/Kconfig b/arch/Kconfig index 5e3b96f414d497d..cc9925e77747c95 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -125,6 +125,7 @@ config XTENSA select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD select ARCH_HAS_CODE_DATA_RELOCATION select ARCH_HAS_TIMING_FUNCTIONS + select ARCH_MEM_DOMAIN_DATA if USERSPACE imply ATOMIC_OPERATIONS_ARCH help Xtensa architecture diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index a1517f17ed0976e..c875aa3097230bb 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -113,6 +113,7 @@ config XTENSA_MMU bool "Xtensa MMU Support" default n select MMU + select ARCH_MEM_DOMAIN_SYNCHRONOUS_API if USERSPACE select XTENSA_SMALL_VECTOR_TABLE_ENTRY select KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK if XTENSA_RPO_CACHE help @@ -144,8 +145,18 @@ if XTENSA_MMU The bit shift number for the virtual address for Xtensa page table (PTEVADDR). + config XTENSA_MMU_NUM_L1_TABLES + int "Number of L1 page tables" + default 1 if !USERSPACE + default 4 + help + This option specifies the maximum number of traslation tables. + Translation tables are directly related to the number of + memory domains in the target, considering the kernel itself requires one. + config XTENSA_MMU_NUM_L2_TABLES int "Number of L2 page tables" + default 20 if USERSPACE default 10 help Each table can address up to 4MB memory address. @@ -159,6 +170,15 @@ if XTENSA_MMU endif # XTENSA_MMU +config XTENSA_SYSCALL_USE_HELPER + bool "Use userspace syscall helper" + default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "xcc-clang" + depends on USERSPACE + help + Use syscall helpers for passing more then 3 arguments. + This is a workaround for toolchains where they have + issue modeling register usage. + endif # CPU_HAS_MMU endmenu diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index c6fffd4f5e181d7..8a23b65b9a9b16d 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -22,6 +22,8 @@ zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_TIMING_FUNCTIONS timing.c) zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU xtensa_mmu.c) +zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) +zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c) zephyr_library_sources_ifdef( CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index e693937f99bfd52..3117ebc4a56d701 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -15,6 +15,7 @@ #endif #endif #include +#include #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -120,6 +121,14 @@ void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) z_fatal_error(reason, esf); } +#ifdef CONFIG_USERSPACE +Z_EXC_DECLARE(z_xtensa_user_string_nlen); + +static const struct z_exc_handle exceptions[] = { + Z_EXC_HANDLE(z_xtensa_user_string_nlen) +}; +#endif /* CONFIG_USERSPACE */ + #ifdef XT_SIMULATOR void exit(int return_code) { diff --git a/arch/xtensa/core/include/xtensa_mmu_priv.h b/arch/xtensa/core/include/xtensa_mmu_priv.h index dcfb9deefc0d540..cf72c92138373cb 100644 --- a/arch/xtensa/core/include/xtensa_mmu_priv.h +++ b/arch/xtensa/core/include/xtensa_mmu_priv.h @@ -18,18 +18,37 @@ #define Z_XTENSA_PTE_VPN_MASK 0xFFFFF000U #define Z_XTENSA_PTE_PPN_MASK 0xFFFFF000U #define Z_XTENSA_PTE_ATTR_MASK 0x0000000FU +#define Z_XTENSA_PTE_ATTR_CACHED_MASK 0x0000000CU #define Z_XTENSA_L1_MASK 0x3FF00000U #define Z_XTENSA_L2_MASK 0x3FFFFFU #define Z_XTENSA_PPN_SHIFT 12U #define Z_XTENSA_PTE_RING_MASK 0x00000030U +#define Z_XTENSA_PTE_RING_SHIFT 4U #define Z_XTENSA_PTE(paddr, ring, attr) \ (((paddr) & Z_XTENSA_PTE_PPN_MASK) | \ - (((ring) << 4) & Z_XTENSA_PTE_RING_MASK) | \ + (((ring) << Z_XTENSA_PTE_RING_SHIFT) & Z_XTENSA_PTE_RING_MASK) | \ ((attr) & Z_XTENSA_PTE_ATTR_MASK)) +#define Z_XTENSA_PTE_ATTR_GET(pte) \ + (pte) & Z_XTENSA_PTE_ATTR_MASK + +#define Z_XTENSA_PTE_ATTR_SET(pte, attr) \ + (((pte) & ~Z_XTENSA_PTE_ATTR_MASK) | (attr)) + +#define Z_XTENSA_PTE_RING_SET(pte, ring) \ + (((pte) & ~Z_XTENSA_PTE_RING_MASK) | \ + ((ring) << Z_XTENSA_PTE_RING_SHIFT)) + +#define Z_XTENSA_PTE_RING_GET(pte) \ + (((pte) & ~Z_XTENSA_PTE_RING_MASK) >> Z_XTENSA_PTE_RING_SHIFT) + +#define Z_XTENSA_PTE_ASID_GET(pte, rasid) \ + (((rasid) >> ((((pte) & Z_XTENSA_PTE_RING_MASK) \ + >> Z_XTENSA_PTE_RING_SHIFT) * 8)) & 0xFF) + #define Z_XTENSA_TLB_ENTRY(vaddr, way) \ (((vaddr) & Z_XTENSA_PTE_PPN_MASK) | (way)) @@ -38,11 +57,38 @@ (((vaddr) >> Z_XTENSA_PPN_SHIFT) & 0x03U)) #define Z_XTENSA_L2_POS(vaddr) \ - (((vaddr) & Z_XTENSA_L2_MASK) >> Z_XTENSA_PPN_SHIFT) + (((vaddr) & Z_XTENSA_L2_MASK) >> 12U) + +#define Z_XTENSA_L1_POS(vaddr) \ + ((vaddr) >> 22U) + +/* PTE attributes for entries in the L1 page table. Should never be + * writable, may be cached in non-SMP contexts only + */ +#if CONFIG_MP_MAX_NUM_CPUS == 1 +#define Z_XTENSA_PAGE_TABLE_ATTR Z_XTENSA_MMU_CACHED_WB +#else +#define Z_XTENSA_PAGE_TABLE_ATTR 0 +#endif + +/* This ASID is shared between all domains and kernel. */ +#define Z_XTENSA_MMU_SHARED_ASID 255 + +/* Fixed data TLB way to map the page table */ +#define Z_XTENSA_MMU_PTE_WAY 7 + +/* Fixed data TLB way to map the vecbase */ +#define Z_XTENSA_MMU_VECBASE_WAY 8 /* Kernel specific ASID. Ring field in the PTE */ #define Z_XTENSA_KERNEL_RING 0 +/* User specific ASID. Ring field in the PTE */ +#define Z_XTENSA_USER_RING 2 + +/* Ring value for MMU_SHARED_ASID */ +#define Z_XTENSA_SHARED_RING 3 + /* Number of data TLB ways [0-9] */ #define Z_XTENSA_DTLB_WAYS 10 @@ -96,6 +142,14 @@ #define Z_XTENSA_PAGE_TABLE_VADDR \ Z_XTENSA_PTE_ENTRY_VADDR(Z_XTENSA_PTEVADDR) +/* + * Get asid for a given ring from rasid register. + * rasid contains four asid, one per ring. + */ + +#define Z_XTENSA_RASID_ASID_GET(rasid, ring) \ + (((rasid) >> ((ring) * 8)) & 0xff) + static ALWAYS_INLINE void xtensa_rasid_set(uint32_t rasid) { __asm__ volatile("wsr %0, rasid\n\t" @@ -110,6 +164,16 @@ static ALWAYS_INLINE uint32_t xtensa_rasid_get(void) return rasid; } +static ALWAYS_INLINE void xtensa_rasid_asid_set(uint8_t asid, uint8_t pos) +{ + uint32_t rasid = xtensa_rasid_get(); + + rasid = (rasid & ~(0xff << (pos * 8))) | ((uint32_t)asid << (pos * 8)); + + xtensa_rasid_set(rasid); +} + + static ALWAYS_INLINE void xtensa_itlb_entry_invalidate(uint32_t entry) { __asm__ volatile("iitlb %0\n\t" @@ -201,6 +265,21 @@ static ALWAYS_INLINE void xtensa_ptevaddr_set(void *ptables) __asm__ volatile("wsr.ptevaddr %0" : : "a"((uint32_t)ptables)); } +/** + * @brief Get the current page tables. + * + * The page tables is obtained by reading ptevaddr address. + * + * @return ptables The page tables address (virtual address) + */ +static ALWAYS_INLINE void *xtensa_ptevaddr_get(void) +{ + uint32_t ptables; + + __asm__ volatile("rsr.ptevaddr %0" : "=a" (ptables)); + + return (void *)ptables; +} /* * The following functions are helpful when debugging. */ diff --git a/arch/xtensa/core/offsets/offsets.c b/arch/xtensa/core/offsets/offsets.c index 860a12eb408909b..8d4022fd81ef05a 100644 --- a/arch/xtensa/core/offsets/offsets.c +++ b/arch/xtensa/core/offsets/offsets.c @@ -5,6 +5,7 @@ #include #include +#include #include @@ -60,4 +61,10 @@ GEN_OFFSET_SYM(_xtensa_irq_bsa_t, fpu14); GEN_OFFSET_SYM(_xtensa_irq_bsa_t, fpu15); #endif +#ifdef CONFIG_USERSPACE +GEN_OFFSET_SYM(_thread_arch_t, psp); +GEN_OFFSET_SYM(_thread_arch_t, ptables); +#endif + + GEN_ABS_SYM_END diff --git a/arch/xtensa/core/syscall_helper.c b/arch/xtensa/core/syscall_helper.c new file mode 100644 index 000000000000000..fbbdf1041910d5d --- /dev/null +++ b/arch/xtensa/core/syscall_helper.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2022 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + register uintptr_t a9 __asm__("%a9") = arg6; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8), "r" (a9) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke5_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke4_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke3_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke2_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke1_helper(uintptr_t arg1, uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6) + : "memory"); + + return a2; +} + +uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2) + : "memory"); + + return a2; +} diff --git a/arch/xtensa/core/userspace.S b/arch/xtensa/core/userspace.S new file mode 100644 index 000000000000000..b649014fd52becf --- /dev/null +++ b/arch/xtensa/core/userspace.S @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2022, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/** + * syscall number arg1, arg2, arg3, arg4, arg5, arg6 + * -------------- ---------------------------------- + * a2 a6, a3, a4, a5, a8, a9 + * + **/ +.pushsection .text.z_xtensa_do_syscall, "ax" +.global z_xtensa_do_syscall +.align 4 +z_xtensa_do_syscall: + rsr a0, ZSR_CPU + l32i a0, a0, ___cpu_t_current_OFFSET + l32i a0, a0, _thread_offset_to_psp + + addi a0, a0, -___xtensa_irq_bsa_t_SIZEOF + + s32i a1, a0, ___xtensa_irq_bsa_t_scratch_OFFSET + s32i a2, a0, ___xtensa_irq_bsa_t_a2_OFFSET + s32i a3, a0, ___xtensa_irq_bsa_t_a3_OFFSET + rsr a2, ZSR_A0SAVE + s32i a2, a0, ___xtensa_irq_bsa_t_a0_OFFSET + rsr.ps a2 + movi a3, ~PS_OWB_MASK + and a2, a2, a3 + s32i a2, a0, ___xtensa_irq_bsa_t_ps_OFFSET + rsr.epc1 a2 + s32i a2, a0, ___xtensa_irq_bsa_t_pc_OFFSET + + movi a2, PS_WOE|PS_INTLEVEL(XCHAL_NMILEVEL) + rsr.ps a3 + or a3, a3, a2 + movi a2, ~(PS_EXCM | PS_RING_MASK) + and a3, a3, a2 + wsr.ps a3 + rsync + l32i a2, a0, ___xtensa_irq_bsa_t_a2_OFFSET + l32i a3, a0, ___xtensa_irq_bsa_t_a3_OFFSET + SPILL_ALL_WINDOWS + + rsr a0, ZSR_CPU + l32i a0, a0, ___cpu_t_current_OFFSET + l32i a0, a0, _thread_offset_to_psp + addi a0, a0, -___xtensa_irq_bsa_t_SIZEOF + + mov a1, a0 + + l32i a3, a1, ___xtensa_irq_bsa_t_pc_OFFSET +#if XCHAL_HAVE_LOOPS + /* If the syscall instruction was the last instruction in the body of + * a zero-overhead loop, and the loop will execute again, decrement + * the loop count and resume execution at the head of the loop. + */ + rsr.lend a2 + addi a3, a3, 3 + bne a2, a3, end_loop + rsr.lcount a2 + beqz a2, end_loop + addi a2, a2, -1 + wsr.lcount a2 + rsr.lbeg a3 +end_loop: +#else + /* EPC1 (and now a3) contains the address that invoked syscall. + * We need to increment it to execute the next instruction when + * we return. The instruction size is 3 bytes, so lets just add it. + */ + addi a3, a3, 3 +#endif + s32i a3, a1, ___xtensa_irq_bsa_t_pc_OFFSET + ODD_REG_SAVE + + call0 xtensa_save_high_regs + + l32i a2, a1, 0 + l32i a2, a2, ___xtensa_irq_bsa_t_a2_OFFSET + movi a0, K_SYSCALL_LIMIT + bgeu a2, a0, _bad_syscall + +_id_ok: + /* Find the function handler for the given syscall id. */ + movi a3, _k_syscall_table + slli a2, a2, 2 + add a2, a2, a3 + l32i a2, a2, 0 + + /* Clear up the threadptr because it is used + * to check if a thread is running on user mode. Since + * we are in a interruption we don't want the system + * thinking it is possibly running in user mode. + */ + movi a0, 0 + wur.THREADPTR a0 + + /* Set syscall parameters. We have an initial call4 to set up the + * the stack and then a new call4 for the syscall function itself. + * So parameters should be put as if it was a call8. + */ + mov a10, a8 + mov a11, a9 + mov a8, a4 + mov a9, a5 + l32i a3, a1, 0 + l32i a7, a3, ___xtensa_irq_bsa_t_a3_OFFSET + + + /* Since we are unmasking EXCM, we need to set RING bits to kernel + * mode, otherwise we won't be able to run the exception handler in C. + */ + movi a0, PS_WOE|PS_CALLINC(0)|PS_UM|PS_INTLEVEL(0) + wsr.ps a0 + rsync + + call4 _syscall_call0 + + /* copy return value. Lets put it in the top of stack + * because registers will be clobbered in + * xtensa_restore_high_regs + */ + l32i a3, a1, 0 + s32i a6, a3, ___xtensa_irq_bsa_t_a2_OFFSET + + j _syscall_returned + +.align 4 +_syscall_call0: + /* We want an ENTRY to set a bit in windowstart */ + jx a2 + + +_syscall_returned: + call0 xtensa_restore_high_regs + + l32i a3, a1, ___xtensa_irq_bsa_t_sar_OFFSET + wsr a3, SAR +#if XCHAL_HAVE_LOOPS + l32i a3, a1, ___xtensa_irq_bsa_t_lbeg_OFFSET + wsr a3, LBEG + l32i a3, a1, ___xtensa_irq_bsa_t_lend_OFFSET + wsr a3, LEND + l32i a3, a1, ___xtensa_irq_bsa_t_lcount_OFFSET + wsr a3, LCOUNT +#endif +#if XCHAL_HAVE_S32C1I + l32i a3, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET + wsr a3, SCOMPARE1 +#endif + + rsr a3, ZSR_CPU + l32i a3, a3, ___cpu_t_current_OFFSET + wur.THREADPTR a3 + + l32i a3, a1, ___xtensa_irq_bsa_t_ps_OFFSET + wsr.ps a3 + + l32i a3, a1, ___xtensa_irq_bsa_t_pc_OFFSET + wsr.epc1 a3 + + l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + l32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET + l32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET + + l32i a1, a1, ___xtensa_irq_bsa_t_scratch_OFFSET + rsync + + rfe + +_bad_syscall: + movi a2, K_SYSCALL_BAD + j _id_ok + +.popsection + +/* FUNC_NORETURN void z_xtensa_userspace_enter(k_thread_entry_t user_entry, + * void *p1, void *p2, void *p3, + * uint32_t stack_end, + * uint32_t stack_start) + * + * A one-way trip to userspace. + */ +.global z_xtensa_userspace_enter +.type z_xtensa_userspace_enter, @function +.align 4 +z_xtensa_userspace_enter: + /* Call entry to set a bit in the windowstart and + * do the rotation, but we are going to set our own + * stack. + */ + entry a1, 16 + + /* We have to switch to kernel stack before spill kernel data and + * erase user stack to avoid leak from previous context. + */ + mov a1, a7 /* stack start (low address) */ + addi a1, a1, -16 + + SPILL_ALL_WINDOWS + + rsr a0, ZSR_CPU + l32i a0, a0, ___cpu_t_current_OFFSET + + addi a1, a1, -28 + s32i a0, a1, 24 + s32i a2, a1, 20 + s32i a3, a1, 16 + s32i a4, a1, 12 + s32i a5, a1, 8 + s32i a6, a1, 4 + s32i a7, a1, 0 + + l32i a6, a1, 24 + call4 xtensa_user_stack_perms + + l32i a6, a1, 24 + call4 z_xtensa_swap_update_page_tables + + /* Set threadptr with the thread address, we are going to user mode. */ + l32i a0, a1, 24 + wur.THREADPTR a0 + + /* Set now z_thread_entry parameters, we are simulating a call4 + * call, so parameters start at a6, a7, ... + */ + l32i a6, a1, 20 + l32i a7, a1, 16 + l32i a8, a1, 12 + l32i a9, a1, 8 + + /* stash user stack */ + l32i a0, a1, 4 + + addi a1, a1, 28 + + /* Go back to user stack */ + mov a1, a0 + + movi a0, z_thread_entry + wsr.epc2 a0 + + /* Configuring PS register. + * We have to set callinc as well, since the called + * function will do "entry" + */ + movi a0, PS_WOE|PS_CALLINC(1)|PS_UM|PS_RING(2) + wsr a0, EPS2 + + movi a0, 0 + + rfi 2 + +/* + * size_t arch_user_string_nlen(const char *s, size_t maxsize, int *err_arg) + */ +.global arch_user_string_nlen +.type arch_user_string_nlen, @function +.align 4 +arch_user_string_nlen: + entry a1, 32 + + /* error value, set to -1. */ + movi a5, -1 + s32i a5, a4, 0 + + /* length count */ + xor a5, a5, a5 + + /* This code might page fault */ +strlen_loop: +.global z_xtensa_user_string_nlen_fault_start +z_xtensa_user_string_nlen_fault_start: + l8ui a6, a2, 0 /* Current char */ + +.global z_xtensa_user_string_nlen_fault_end +z_xtensa_user_string_nlen_fault_end: + beqz a6, strlen_done + addi a5, a5, 1 + addi a2, a2, 1 + beq a5, a3, strlen_done + j strlen_loop + +strlen_done: + /* Set return value */ + mov a2, a5 + + /* Set error value to 0 since we succeeded */ + movi a5, 0x0 + s32i a5, a4, 0 + +.global z_xtensa_user_string_nlen_fixup +z_xtensa_user_string_nlen_fixup: + retw diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index bc526ae0165e248..c108a09dee4814a 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -174,7 +174,8 @@ _restore_context: l32i a0, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET wsr a0, SCOMPARE1 #endif -#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE) +#if XCHAL_HAVE_THREADPTR && \ + (defined(CONFIG_USERSPACE) || defined(CONFIG_THREAD_LOCAL_STORAGE)) l32i a0, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET wur a0, THREADPTR #endif @@ -258,6 +259,16 @@ noflush: l32i a3, a2, ___xtensa_irq_bsa_t_a3_OFFSET s32i a1, a3, 0 +#ifdef CONFIG_USERSPACE + /* Switch page tables */ + rsr a6, ZSR_CPU + l32i a6, a6, ___cpu_t_current_OFFSET + call4 z_xtensa_swap_update_page_tables + + l32i a2, a3, 0 + l32i a2, a2, 0 +#endif + /* Switch stack pointer and restore. The jump to * _restore_context does not return as such, but we arrange * for the restored "next" address to be immediately after for @@ -347,6 +358,9 @@ _Level1RealVector: rsr.exccause a0 #ifdef CONFIG_XTENSA_MMU beqi a0, EXCCAUSE_ITLB_MISS, _handle_tlb_miss_user +#ifdef CONFIG_USERSPACE + beqi a0, EXCCAUSE_SYSCALL, _syscall +#endif /* CONFIG_USERSPACE */ addi a0, a0, -EXCCAUSE_DTLB_MISS beqz a0, _handle_tlb_miss_user rsr.exccause a0 @@ -376,6 +390,11 @@ _handle_tlb_miss_user: l32i a0, a0, 0 rsr a0, ZSR_A0SAVE rfe +#ifdef CONFIG_USERSPACE +_syscall: + rsr a0, ZSR_A0SAVE + j z_xtensa_do_syscall +#endif /* CONFIG_USERSPACE */ #endif /* CONFIG_XTENSA_MMU */ .popsection diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index c2371ac8f55d6a3..1e8c92759e42fb8 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -26,6 +26,13 @@ void *xtensa_init_stack(struct k_thread *thread, int *stack_top, { void *ret; _xtensa_irq_stack_frame_a11_t *frame; +#ifdef CONFIG_USERSPACE + struct z_xtensa_thread_stack_header *header = + (struct z_xtensa_thread_stack_header *)thread->stack_obj; + + thread->arch.psp = header->privilege_stack + + sizeof(header->privilege_stack); +#endif /* Not-a-cpu ID Ensures that the first time this is run, the * stack will be invalidated. That covers the edge case of @@ -48,11 +55,23 @@ void *xtensa_init_stack(struct k_thread *thread, int *stack_top, (void)memset(frame, 0, bsasz); - frame->bsa.pc = (uintptr_t)z_thread_entry; frame->bsa.ps = PS_WOE | PS_UM | PS_CALLINC(1); +#ifdef CONFIG_USERSPACE + if ((thread->base.user_options & K_USER) == K_USER) { + frame->bsa.pc = (uintptr_t)arch_user_mode_enter; + } else { + frame->bsa.pc = (uintptr_t)z_thread_entry; + } +#else + frame->bsa.pc = (uintptr_t)z_thread_entry; +#endif -#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE) +#if XCHAL_HAVE_THREADPTR +#ifdef CONFIG_THREAD_LOCAL_STORAGE frame->bsa.threadptr = thread->tls; +#elif CONFIG_USERSPACE + frame->bsa.threadptr = (uintptr_t)((thread->base.user_options & K_USER) ? thread : NULL); +#endif #endif /* Arguments to z_thread_entry(). Remember these start at A6, @@ -471,3 +490,24 @@ void arch_spin_relax(void) #undef NOP1 } #endif /* CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS */ + +#ifdef CONFIG_USERSPACE +FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, + void *p1, void *p2, void *p3) +{ + struct k_thread *current = _current; + size_t stack_end; + + /* Transition will reset stack pointer to initial, discarding + * any old context since this is a one-way operation + */ + stack_end = Z_STACK_PTR_ALIGN(current->stack_info.start + + current->stack_info.size - + current->stack_info.delta); + + z_xtensa_userspace_enter(user_entry, p1, p2, p3, + stack_end, current->stack_info.start); + + CODE_UNREACHABLE; +} +#endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 18ce5f22f63466d..915a26357eb894f 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include #include @@ -15,22 +16,24 @@ #include #include -/* Fixed data TLB way to map the page table */ -#define MMU_PTE_WAY 7 - -/* Fixed data TLB way to map VECBASE */ -#define MMU_VECBASE_WAY 8 - /* Level 1 contains page table entries * necessary to map the page table itself. */ #define XTENSA_L1_PAGE_TABLE_ENTRIES 1024U +/* Size of level 1 page table. + */ +#define XTENSA_L1_PAGE_TABLE_SIZE (XTENSA_L1_PAGE_TABLE_ENTRIES * sizeof(uint32_t)) + /* Level 2 contains page table entries * necessary to map the page table itself. */ #define XTENSA_L2_PAGE_TABLE_ENTRIES 1024U +/* Size of level 2 page table. + */ +#define XTENSA_L2_PAGE_TABLE_SIZE (XTENSA_L2_PAGE_TABLE_ENTRIES * sizeof(uint32_t)) + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); BUILD_ASSERT(CONFIG_MMU_PAGE_SIZE == 0x1000, @@ -40,8 +43,18 @@ BUILD_ASSERT(CONFIG_MMU_PAGE_SIZE == 0x1000, * Level 1 page table has to be 4Kb to fit into one of the wired entries. * All entries are initialized as INVALID, so an attempt to read an unmapped * area will cause a double exception. + * + * Each memory domain contains its own l1 page table. The kernel l1 page table is + * located at the index 0. */ -uint32_t l1_page_table[XTENSA_L1_PAGE_TABLE_ENTRIES] __aligned(KB(4)); +static uint32_t l1_page_table[CONFIG_XTENSA_MMU_NUM_L1_TABLES][XTENSA_L1_PAGE_TABLE_ENTRIES] + __aligned(KB(4)); + + +/* + * That is an alias for the page tables set used by the kernel. + */ +uint32_t *z_xtensa_kernel_ptables = (uint32_t *)l1_page_table[0]; /* * Each table in the level 2 maps a 4Mb memory range. It consists of 1024 entries each one @@ -50,12 +63,41 @@ uint32_t l1_page_table[XTENSA_L1_PAGE_TABLE_ENTRIES] __aligned(KB(4)); static uint32_t l2_page_tables[CONFIG_XTENSA_MMU_NUM_L2_TABLES][XTENSA_L2_PAGE_TABLE_ENTRIES] __aligned(KB(4)); +/* + * This additional variable tracks which l1 tables are in use. This is kept separated from + * the tables to keep alignment easier. + * + * @note: The first bit is set because it is used for the kernel page tables. + */ +static ATOMIC_DEFINE(l1_page_table_track, CONFIG_XTENSA_MMU_NUM_L1_TABLES); + /* * This additional variable tracks which l2 tables are in use. This is kept separated from * the tables to keep alignment easier. */ static ATOMIC_DEFINE(l2_page_tables_track, CONFIG_XTENSA_MMU_NUM_L2_TABLES); +/* + * Protects xtensa_domain_list and serializes access to page tables. + */ +static struct k_spinlock xtensa_mmu_lock; + +#ifdef CONFIG_USERSPACE + +/* + * Each domain has its own ASID. ASID can go through 1 (kernel) to 255. + * When a TLB entry matches, the hw will check the ASID in the entry and finds + * the correspondent position in the RASID register. This position will then be + * compared with the current ring (CRING) to check the permission. + */ +static uint8_t asid_count = 3; + +/* + * List with all active and initialized memory domains. + */ +static sys_slist_t xtensa_domain_list; +#endif /* CONFIG_USERSPACE */ + extern char _heap_end[]; extern char _heap_start[]; extern char __data_start[]; @@ -100,18 +142,61 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { { .start = (uint32_t)__text_region_start, .end = (uint32_t)__text_region_end, - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB, + .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB | Z_XTENSA_MMU_MAP_SHARED, .name = "text", }, /* Mark rodata segment cacheable, read only and non-executable */ { .start = (uint32_t)__rodata_region_start, .end = (uint32_t)__rodata_region_end, - .attrs = Z_XTENSA_MMU_CACHED_WB, + .attrs = Z_XTENSA_MMU_CACHED_WB | Z_XTENSA_MMU_MAP_SHARED, .name = "rodata", }, }; +static inline uint32_t *thread_page_tables_get(const struct k_thread *thread) +{ +#ifdef CONFIG_USERSPACE + if ((thread->base.user_options & K_USER) != 0U) { + return thread->arch.ptables; + } +#endif + + return z_xtensa_kernel_ptables; +} + +/** + * @brief Check if the page table entry is illegal. + * + * @param[in] Page table entry. + */ +static inline bool is_pte_illegal(uint32_t pte) +{ + uint32_t attr = pte & Z_XTENSA_PTE_ATTR_MASK; + + /* + * The ISA manual states only 12 and 14 are illegal values. + * 13 and 15 are not. So we need to be specific than simply + * testing if bits 2 and 3 are set. + */ + return (attr == 12) || (attr == 14); +} + +/* + * @brief Initialize all page table entries to be illegal. + * + * @param[in] Pointer to page table. + * @param[in] Number of page table entries in the page table. + */ +static void init_page_table(uint32_t *ptable, size_t num_entries) +{ + int i; + + for (i = 0; i < num_entries; i++) { + ptable[i] = Z_XTENSA_MMU_ILLEGAL; + } +} + static inline uint32_t *alloc_l2_table(void) { uint16_t idx; @@ -125,45 +210,86 @@ static inline uint32_t *alloc_l2_table(void) return NULL; } +/** + * @brief Switch page tables + * + * This switches the page tables to the incoming ones (@a ptables). + * Since data TLBs to L2 page tables are auto-filled, @a dtlb_inv + * can be used to invalidate these data TLBs. @a cache_inv can be + * set to true to invalidate cache to the page tables. + * + * @param[in] ptables Page tables to be switched to. + * @param[in] dtlb_inv True if to invalidate auto-fill data TLBs. + * @param[in] cache_inv True if to invalidate cache to page tables. + */ +static ALWAYS_INLINE void switch_page_tables(uint32_t *ptables, bool dtlb_inv, bool cache_inv) +{ + if (cache_inv) { + sys_cache_data_invd_range((void *)ptables, XTENSA_L1_PAGE_TABLE_SIZE); + sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + } + + /* Invalidate data TLB to L1 page table */ + xtensa_dtlb_vaddr_invalidate((void *)Z_XTENSA_PAGE_TABLE_VADDR); + + /* Now map the pagetable itself with KERNEL asid to avoid user thread + * from tampering with it. + */ + xtensa_dtlb_entry_write_sync( + Z_XTENSA_PTE((uint32_t)ptables, Z_XTENSA_KERNEL_RING, Z_XTENSA_PAGE_TABLE_ATTR), + Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, Z_XTENSA_MMU_PTE_WAY)); + + if (dtlb_inv) { + /* Since L2 page tables are auto-refilled, + * invalidate all of them to flush the old entries out. + */ + xtensa_tlb_autorefill_invalidate(); + } +} + static void map_memory_range(const uint32_t start, const uint32_t end, - const uint32_t attrs) + const uint32_t attrs, bool shared) { uint32_t page, *table; for (page = start; page < end; page += CONFIG_MMU_PAGE_SIZE) { - uint32_t pte = Z_XTENSA_PTE(page, Z_XTENSA_KERNEL_RING, attrs); + uint32_t pte = Z_XTENSA_PTE(page, + shared ? Z_XTENSA_SHARED_RING : Z_XTENSA_KERNEL_RING, + attrs); uint32_t l2_pos = Z_XTENSA_L2_POS(page); - uint32_t l1_pos = page >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS(page); - if (l1_page_table[l1_pos] == Z_XTENSA_MMU_ILLEGAL) { + if (is_pte_illegal(z_xtensa_kernel_ptables[l1_pos])) { table = alloc_l2_table(); __ASSERT(table != NULL, "There is no l2 page table available to " "map 0x%08x\n", page); - l1_page_table[l1_pos] = + init_page_table(table, XTENSA_L2_PAGE_TABLE_ENTRIES); + + z_xtensa_kernel_ptables[l1_pos] = Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_CACHED_WT); + Z_XTENSA_PAGE_TABLE_ATTR); } - table = (uint32_t *)(l1_page_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + table = (uint32_t *)(z_xtensa_kernel_ptables[l1_pos] & Z_XTENSA_PTE_PPN_MASK); table[l2_pos] = pte; } } static void map_memory(const uint32_t start, const uint32_t end, - const uint32_t attrs) + const uint32_t attrs, bool shared) { - map_memory_range(start, end, attrs); + map_memory_range(start, end, attrs, shared); #ifdef CONFIG_XTENSA_MMU_DOUBLE_MAP if (arch_xtensa_is_ptr_uncached((void *)start)) { map_memory_range(POINTER_TO_UINT(z_soc_cached_ptr((void *)start)), POINTER_TO_UINT(z_soc_cached_ptr((void *)end)), - attrs | Z_XTENSA_MMU_CACHED_WB); + attrs | Z_XTENSA_MMU_CACHED_WB, shared); } else if (arch_xtensa_is_ptr_cached((void *)start)) { map_memory_range(POINTER_TO_UINT(z_soc_uncached_ptr((void *)start)), - POINTER_TO_UINT(z_soc_uncached_ptr((void *)end)), attrs); + POINTER_TO_UINT(z_soc_uncached_ptr((void *)end)), attrs, shared); } #endif } @@ -171,16 +297,19 @@ static void map_memory(const uint32_t start, const uint32_t end, static void xtensa_init_page_tables(void) { volatile uint8_t entry; - uint32_t page; - for (page = 0; page < XTENSA_L1_PAGE_TABLE_ENTRIES; page++) { - l1_page_table[page] = Z_XTENSA_MMU_ILLEGAL; - } + init_page_table(z_xtensa_kernel_ptables, XTENSA_L1_PAGE_TABLE_ENTRIES); + atomic_set_bit(l1_page_table_track, 0); for (entry = 0; entry < ARRAY_SIZE(mmu_zephyr_ranges); entry++) { const struct xtensa_mmu_range *range = &mmu_zephyr_ranges[entry]; + bool shared; + uint32_t attrs; - map_memory(range->start, range->end, range->attrs); + shared = !!(range->attrs & Z_XTENSA_MMU_MAP_SHARED); + attrs = range->attrs & ~Z_XTENSA_MMU_MAP_SHARED; + + map_memory(range->start, range->end, attrs, shared); } /** @@ -198,8 +327,13 @@ static void xtensa_init_page_tables(void) #endif for (entry = 0; entry < xtensa_soc_mmu_ranges_num; entry++) { const struct xtensa_mmu_range *range = &xtensa_soc_mmu_ranges[entry]; + bool shared; + uint32_t attrs; + + shared = !!(range->attrs & Z_XTENSA_MMU_MAP_SHARED); + attrs = range->attrs & ~Z_XTENSA_MMU_MAP_SHARED; - map_memory(range->start, range->end, range->attrs); + map_memory(range->start, range->end, attrs, shared); } #if defined(__GNUC__) #pragma GCC diagnostic pop @@ -231,6 +365,9 @@ void z_xtensa_mmu_init(void) /* Set the page table location in the virtual address */ xtensa_ptevaddr_set((void *)Z_XTENSA_PTEVADDR); + /* Set rasid */ + xtensa_rasid_asid_set(Z_XTENSA_MMU_SHARED_ASID, Z_XTENSA_SHARED_RING); + /* Next step is to invalidate the tlb entry that contains the top level * page table. This way we don't cause a multi hit exception. */ @@ -243,9 +380,9 @@ void z_xtensa_mmu_init(void) * Lets use one of the wired entry, so we never have tlb miss for * the top level table. */ - xtensa_dtlb_entry_write(Z_XTENSA_PTE((uint32_t)l1_page_table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, MMU_PTE_WAY)); + xtensa_dtlb_entry_write(Z_XTENSA_PTE((uint32_t)z_xtensa_kernel_ptables, + Z_XTENSA_KERNEL_RING, Z_XTENSA_PAGE_TABLE_ATTR), + Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, Z_XTENSA_MMU_PTE_WAY)); /* Before invalidate the text region in the TLB entry 6, we need to * map the exception vector into one of the wired entries to avoid @@ -297,7 +434,7 @@ void z_xtensa_mmu_init(void) xtensa_dtlb_entry_write( Z_XTENSA_PTE((uint32_t)vecbase, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_CACHED_WB), - Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, MMU_VECBASE_WAY)); + Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, Z_XTENSA_MMU_VECBASE_WAY)); /* * Pre-load TLB for vecbase so exception handling won't result @@ -325,6 +462,12 @@ void z_xtensa_mmu_init(void) xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); + /* + * Clear out THREADPTR as we use it to indicate + * whether we are in user mode or not. + */ + XTENSA_WUR("THREADPTR", 0); + arch_xtensa_mmu_post_init(_current_cpu->id == 0); } @@ -351,32 +494,121 @@ __weak void arch_reserved_pages_update(void) } #endif /* CONFIG_ARCH_HAS_RESERVED_PAGE_FRAMES */ -static bool l2_page_table_map(void *vaddr, uintptr_t phys, uint32_t flags) +static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, + uint32_t flags, bool is_user) { uint32_t l1_pos = (uint32_t)vaddr >> 22; - uint32_t pte = Z_XTENSA_PTE(phys, Z_XTENSA_KERNEL_RING, flags); uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); uint32_t *table; - if (l1_page_table[l1_pos] == Z_XTENSA_MMU_ILLEGAL) { + sys_cache_data_invd_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + + if (is_pte_illegal(l1_table[l1_pos])) { table = alloc_l2_table(); if (table == NULL) { return false; } - l1_page_table[l1_pos] = Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_CACHED_WT); + init_page_table(table, XTENSA_L2_PAGE_TABLE_ENTRIES); + + l1_table[l1_pos] = Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, + Z_XTENSA_PAGE_TABLE_ATTR); + + sys_cache_data_flush_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + } + + table = (uint32_t *)(l1_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + table[l2_pos] = Z_XTENSA_PTE(phys, is_user ? Z_XTENSA_USER_RING : Z_XTENSA_KERNEL_RING, + flags); + + sys_cache_data_flush_range((void *)&table[l2_pos], sizeof(table[0])); + + return true; +} + +static inline void __arch_mem_map(void *va, uintptr_t pa, uint32_t xtensa_flags, bool is_user) +{ + bool ret; + void *vaddr, *vaddr_uc; + uintptr_t paddr, paddr_uc; + uint32_t flags, flags_uc; + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (arch_xtensa_is_ptr_cached(va)) { + vaddr = va; + vaddr_uc = arch_xtensa_uncached_ptr(va); + } else { + vaddr = arch_xtensa_cached_ptr(va); + vaddr_uc = va; + } + + if (arch_xtensa_is_ptr_cached((void *)pa)) { + paddr = pa; + paddr_uc = (uintptr_t)arch_xtensa_uncached_ptr((void *)pa); + } else { + paddr = (uintptr_t)arch_xtensa_cached_ptr((void *)pa); + paddr_uc = pa; + } + + flags_uc = (xtensa_flags & ~Z_XTENSA_PTE_ATTR_CACHED_MASK); + flags = flags_uc | Z_XTENSA_MMU_CACHED_WB; + } else { + vaddr = va; + paddr = pa; + flags = xtensa_flags; + } + + ret = l2_page_table_map(z_xtensa_kernel_ptables, (void *)vaddr, paddr, + flags, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped", va); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP) && ret) { + ret = l2_page_table_map(z_xtensa_kernel_ptables, (void *)vaddr_uc, paddr_uc, + flags_uc, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped", vaddr_uc); } - table = (uint32_t *)(l1_page_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); - table[l2_pos] = pte; +#ifndef CONFIG_USERSPACE + ARG_UNUSED(ret); +#else + if (ret) { + sys_snode_t *node; + struct arch_mem_domain *domain; + k_spinlock_key_t key; + + key = k_spin_lock(&z_mem_domain_lock); + SYS_SLIST_FOR_EACH_NODE(&xtensa_domain_list, node) { + domain = CONTAINER_OF(node, struct arch_mem_domain, node); + + ret = l2_page_table_map(domain->ptables, (void *)vaddr, paddr, + flags, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped for domain %p", + vaddr, domain); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP) && ret) { + ret = l2_page_table_map(domain->ptables, + (void *)vaddr_uc, paddr_uc, + flags_uc, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped for domain %p", + vaddr_uc, domain); + } + } + k_spin_unlock(&z_mem_domain_lock, key); + } +#endif /* CONFIG_USERSPACE */ - if ((flags & Z_XTENSA_MMU_X) == Z_XTENSA_MMU_X) { + if ((xtensa_flags & Z_XTENSA_MMU_X) == Z_XTENSA_MMU_X) { xtensa_itlb_vaddr_invalidate(vaddr); } xtensa_dtlb_vaddr_invalidate(vaddr); - return true; + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (xtensa_flags & Z_XTENSA_MMU_X) { + xtensa_itlb_vaddr_invalidate(vaddr_uc); + } + xtensa_dtlb_vaddr_invalidate(vaddr_uc); + } } void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) @@ -385,7 +617,8 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) uint32_t pa = (uint32_t)phys; uint32_t rem_size = (uint32_t)size; uint32_t xtensa_flags = 0; - int key; + k_spinlock_key_t key; + bool is_user; if (size == 0) { LOG_ERR("Cannot map physical memory at 0x%08X: invalid " @@ -414,63 +647,130 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) xtensa_flags |= Z_XTENSA_MMU_X; } - key = arch_irq_lock(); + is_user = (flags & K_MEM_PERM_USER) == K_MEM_PERM_USER; + + key = k_spin_lock(&xtensa_mmu_lock); while (rem_size > 0) { - bool ret = l2_page_table_map((void *)va, pa, xtensa_flags); + __arch_mem_map((void *)va, pa, xtensa_flags, is_user); - ARG_UNUSED(ret); - __ASSERT(ret, "Virtual address (%u) already mapped", (uint32_t)virt); rem_size -= (rem_size >= KB(4)) ? KB(4) : rem_size; va += KB(4); pa += KB(4); } - arch_irq_unlock(key); + k_spin_unlock(&xtensa_mmu_lock, key); } -static void l2_page_table_unmap(void *vaddr) +/** + * @return True if page is executable (thus need to invalidate ITLB), + * false if not. + */ +static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) { uint32_t l1_pos = (uint32_t)vaddr >> 22; uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); - uint32_t *table; + uint32_t *l2_table; uint32_t table_pos; bool exec; - if (l1_page_table[l1_pos] == Z_XTENSA_MMU_ILLEGAL) { - return; + sys_cache_data_invd_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + + if (is_pte_illegal(l1_table[l1_pos])) { + /* We shouldn't be unmapping an illegal entry. + * Return true so that we can invalidate ITLB too. + */ + return true; } - exec = l1_page_table[l1_pos] & Z_XTENSA_MMU_X; + exec = l1_table[l1_pos] & Z_XTENSA_MMU_X; + + l2_table = (uint32_t *)(l1_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + + sys_cache_data_invd_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); - table = (uint32_t *)(l1_page_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); - table[l2_pos] = Z_XTENSA_MMU_ILLEGAL; + l2_table[l2_pos] = Z_XTENSA_MMU_ILLEGAL; + + sys_cache_data_flush_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); for (l2_pos = 0; l2_pos < XTENSA_L2_PAGE_TABLE_ENTRIES; l2_pos++) { - if (table[l2_pos] != Z_XTENSA_MMU_ILLEGAL) { + if (!is_pte_illegal(l2_table[l2_pos])) { goto end; } } - l1_page_table[l1_pos] = Z_XTENSA_MMU_ILLEGAL; - table_pos = (table - (uint32_t *)l2_page_tables) / (XTENSA_L2_PAGE_TABLE_ENTRIES); + l1_table[l1_pos] = Z_XTENSA_MMU_ILLEGAL; + sys_cache_data_flush_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + + table_pos = (l2_table - (uint32_t *)l2_page_tables) / (XTENSA_L2_PAGE_TABLE_ENTRIES); atomic_clear_bit(l2_page_tables_track, table_pos); /* Need to invalidate L2 page table as it is no longer valid. */ - xtensa_dtlb_vaddr_invalidate((void *)table); + xtensa_dtlb_vaddr_invalidate((void *)l2_table); end: - if (exec) { + return exec; +} + +static inline void __arch_mem_unmap(void *va) +{ + bool is_exec; + void *vaddr, *vaddr_uc; + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (arch_xtensa_is_ptr_cached(va)) { + vaddr = va; + vaddr_uc = arch_xtensa_uncached_ptr(va); + } else { + vaddr = arch_xtensa_cached_ptr(va); + vaddr_uc = va; + } + } else { + vaddr = va; + } + + is_exec = l2_page_table_unmap(z_xtensa_kernel_ptables, (void *)vaddr); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + (void)l2_page_table_unmap(z_xtensa_kernel_ptables, (void *)vaddr_uc); + } + +#ifdef CONFIG_USERSPACE + sys_snode_t *node; + struct arch_mem_domain *domain; + k_spinlock_key_t key; + + key = k_spin_lock(&z_mem_domain_lock); + SYS_SLIST_FOR_EACH_NODE(&xtensa_domain_list, node) { + domain = CONTAINER_OF(node, struct arch_mem_domain, node); + + (void)l2_page_table_unmap(domain->ptables, (void *)vaddr); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + (void)l2_page_table_unmap(domain->ptables, (void *)vaddr_uc); + } + } + k_spin_unlock(&z_mem_domain_lock, key); +#endif /* CONFIG_USERSPACE */ + + if (is_exec) { xtensa_itlb_vaddr_invalidate(vaddr); } xtensa_dtlb_vaddr_invalidate(vaddr); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (is_exec) { + xtensa_itlb_vaddr_invalidate(vaddr_uc); + } + xtensa_dtlb_vaddr_invalidate(vaddr_uc); + } } void arch_mem_unmap(void *addr, size_t size) { uint32_t va = (uint32_t)addr; uint32_t rem_size = (uint32_t)size; - int key; + k_spinlock_key_t key; if (addr == NULL) { LOG_ERR("Cannot unmap NULL pointer"); @@ -482,13 +782,363 @@ void arch_mem_unmap(void *addr, size_t size) return; } - key = arch_irq_lock(); + key = k_spin_lock(&xtensa_mmu_lock); while (rem_size > 0) { - l2_page_table_unmap((void *)va); + __arch_mem_unmap((void *)va); + rem_size -= (rem_size >= KB(4)) ? KB(4) : rem_size; va += KB(4); } - arch_irq_unlock(key); + k_spin_unlock(&xtensa_mmu_lock, key); } + +#ifdef CONFIG_USERSPACE + +static inline uint32_t *alloc_l1_table(void) +{ + uint16_t idx; + + for (idx = 0; idx < CONFIG_XTENSA_MMU_NUM_L1_TABLES; idx++) { + if (!atomic_test_and_set_bit(l1_page_table_track, idx)) { + return (uint32_t *)&l1_page_table[idx]; + } + } + + return NULL; +} + +static uint32_t *dup_table(uint32_t *source_table) +{ + uint16_t i, j; + uint32_t *dst_table = alloc_l1_table(); + + if (!dst_table) { + return NULL; + } + + for (i = 0; i < XTENSA_L1_PAGE_TABLE_ENTRIES; i++) { + uint32_t *l2_table, *src_l2_table; + + if (is_pte_illegal(source_table[i])) { + dst_table[i] = Z_XTENSA_MMU_ILLEGAL; + continue; + } + + src_l2_table = (uint32_t *)(source_table[i] & Z_XTENSA_PTE_PPN_MASK); + l2_table = alloc_l2_table(); + if (l2_table == NULL) { + goto err; + } + + for (j = 0; j < XTENSA_L2_PAGE_TABLE_ENTRIES; j++) { + l2_table[j] = src_l2_table[j]; + } + + /* The page table is using kernel ASID because we don't + * user thread manipulate it. + */ + dst_table[i] = Z_XTENSA_PTE((uint32_t)l2_table, Z_XTENSA_KERNEL_RING, + Z_XTENSA_PAGE_TABLE_ATTR); + + sys_cache_data_flush_range((void *)l2_table, XTENSA_L2_PAGE_TABLE_SIZE); + } + + sys_cache_data_flush_range((void *)dst_table, XTENSA_L1_PAGE_TABLE_SIZE); + + return dst_table; + +err: + /* TODO: Cleanup failed allocation*/ + return NULL; +} + +int arch_mem_domain_init(struct k_mem_domain *domain) +{ + uint32_t *ptables; + k_spinlock_key_t key; + int ret; + + /* + * For now, lets just assert if we have reached the maximum number + * of asid we assert. + */ + __ASSERT(asid_count < (Z_XTENSA_MMU_SHARED_ASID), "Reached maximum of ASID available"); + + key = k_spin_lock(&xtensa_mmu_lock); + ptables = dup_table(z_xtensa_kernel_ptables); + + if (ptables == NULL) { + ret = -ENOMEM; + goto err; + } + + domain->arch.ptables = ptables; + domain->arch.asid = ++asid_count; + + sys_slist_append(&xtensa_domain_list, &domain->arch.node); + + ret = 0; + +err: + k_spin_unlock(&xtensa_mmu_lock, key); + + return ret; +} + +static int region_map_update(uint32_t *ptables, uintptr_t start, + size_t size, uint32_t ring, uint32_t flags) +{ + int ret = 0; + + for (size_t offset = 0; offset < size; offset += CONFIG_MMU_PAGE_SIZE) { + uint32_t *l2_table, pte; + uint32_t page = start + offset; + uint32_t l1_pos = page >> 22; + uint32_t l2_pos = Z_XTENSA_L2_POS(page); + + /* Make sure we grab a fresh copy of L1 page table */ + sys_cache_data_invd_range((void *)&ptables[l1_pos], sizeof(ptables[0])); + + l2_table = (uint32_t *)(ptables[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + + sys_cache_data_invd_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); + + pte = Z_XTENSA_PTE_RING_SET(l2_table[l2_pos], ring); + pte = Z_XTENSA_PTE_ATTR_SET(pte, flags); + + l2_table[l2_pos] = pte; + + sys_cache_data_flush_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); + + xtensa_dtlb_vaddr_invalidate( + (void *)(pte & Z_XTENSA_PTE_PPN_MASK)); + } + + return ret; +} + +static inline int update_region(uint32_t *ptables, uintptr_t start, + size_t size, uint32_t ring, uint32_t flags) +{ + int ret; + k_spinlock_key_t key; + + key = k_spin_lock(&xtensa_mmu_lock); + +#ifdef CONFIG_XTENSA_MMU_DOUBLE_MAP + uintptr_t va, va_uc; + uint32_t new_flags, new_flags_uc; + + if (arch_xtensa_is_ptr_cached((void *)start)) { + va = start; + va_uc = (uintptr_t)arch_xtensa_uncached_ptr((void *)start); + } else { + va = (uintptr_t)arch_xtensa_cached_ptr((void *)start); + va_uc = start; + } + + new_flags_uc = (flags & ~Z_XTENSA_PTE_ATTR_CACHED_MASK); + new_flags = new_flags_uc | Z_XTENSA_MMU_CACHED_WB; + + ret = region_map_update(ptables, va, size, ring, new_flags); + + if (ret == 0) { + ret = region_map_update(ptables, va_uc, size, ring, new_flags_uc); + } +#else + ret = region_map_update(ptables, start, size, ring, flags); +#endif /* CONFIG_XTENSA_MMU_DOUBLE_MAP */ + + k_spin_unlock(&xtensa_mmu_lock, key); + + return ret; +} + +static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size) +{ + return update_region(ptables, start, size, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_W); +} + +void xtensa_set_stack_perms(struct k_thread *thread) +{ + if ((thread->base.user_options & K_USER) == 0) { + return; + } + + update_region(thread_page_tables_get(thread), + thread->stack_info.start, thread->stack_info.size, + Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB); +} + +void xtensa_user_stack_perms(struct k_thread *thread) +{ + (void)memset((void *)thread->stack_info.start, 0xAA, + thread->stack_info.size - thread->stack_info.delta); + + update_region(thread_page_tables_get(thread), + thread->stack_info.start, thread->stack_info.size, + Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB); +} + +int arch_mem_domain_max_partitions_get(void) +{ + return CONFIG_MAX_DOMAIN_PARTITIONS; +} + +int arch_mem_domain_partition_remove(struct k_mem_domain *domain, + uint32_t partition_id) +{ + struct k_mem_partition *partition = &domain->partitions[partition_id]; + + /* Reset the partition's region back to defaults */ + return reset_region(domain->arch.ptables, partition->start, + partition->size); +} + +int arch_mem_domain_partition_add(struct k_mem_domain *domain, + uint32_t partition_id) +{ + uint32_t ring = domain->arch.asid == 0 ? Z_XTENSA_KERNEL_RING : Z_XTENSA_USER_RING; + struct k_mem_partition *partition = &domain->partitions[partition_id]; + + return update_region(domain->arch.ptables, partition->start, + partition->size, ring, partition->attr); +} + +/* These APIs don't need to do anything */ +int arch_mem_domain_thread_add(struct k_thread *thread) +{ + int ret = 0; + bool is_user, is_migration; + uint32_t *old_ptables; + struct k_mem_domain *domain; + + old_ptables = thread->arch.ptables; + domain = thread->mem_domain_info.mem_domain; + thread->arch.ptables = domain->arch.ptables; + + is_user = (thread->base.user_options & K_USER) != 0; + is_migration = (old_ptables != NULL) && is_user; + + /* Give access to the thread's stack in its new + * memory domain if it is migrating. + */ + if (is_migration) { + xtensa_set_stack_perms(thread); + } + + if (is_migration) { + ret = reset_region(old_ptables, + thread->stack_info.start, + thread->stack_info.size); + } + + return ret; +} + +int arch_mem_domain_thread_remove(struct k_thread *thread) +{ + struct k_mem_domain *domain = thread->mem_domain_info.mem_domain; + + if ((thread->base.user_options & K_USER) == 0) { + return 0; + } + + if ((thread->base.thread_state & _THREAD_DEAD) == 0) { + /* Thread is migrating to another memory domain and not + * exiting for good; we weren't called from + * z_thread_abort(). Resetting the stack region will + * take place in the forthcoming thread_add() call. + */ + return 0; + } + + /* Restore permissions on the thread's stack area since it is no + * longer a member of the domain. + */ + return reset_region(domain->arch.ptables, + thread->stack_info.start, + thread->stack_info.size); +} + +static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool write) +{ + uint8_t asid_ring; + uint32_t rasid, pte, *l2_table; + uint32_t l1_pos = page >> 22; + uint32_t l2_pos = Z_XTENSA_L2_POS(page); + + if (is_pte_illegal(ptables[l1_pos])) { + return false; + } + + l2_table = (uint32_t *)(ptables[l1_pos] & Z_XTENSA_PTE_PPN_MASK); + pte = l2_table[l2_pos]; + + if (is_pte_illegal(pte)) { + return false; + } + + asid_ring = 0; + rasid = xtensa_rasid_get(); + for (uint32_t i = 0; i < 4; i++) { + if (Z_XTENSA_PTE_ASID_GET(pte, rasid) == + Z_XTENSA_RASID_ASID_GET(rasid, i)) { + asid_ring = i; + break; + } + } + + if (ring > asid_ring) { + return false; + } + + if (write) { + return (Z_XTENSA_PTE_ATTR_GET((pte)) & Z_XTENSA_MMU_W) != 0; + } + + return true; +} + +int arch_buffer_validate(void *addr, size_t size, int write) +{ + int ret = 0; + uint8_t *virt; + size_t aligned_size; + const struct k_thread *thread = _current; + uint32_t *ptables = thread_page_tables_get(thread); + uint8_t ring = ((thread->base.user_options & K_USER) != 0) ? + Z_XTENSA_USER_RING : Z_XTENSA_KERNEL_RING; + + /* addr/size arbitrary, fix this up into an aligned region */ + k_mem_region_align((uintptr_t *)&virt, &aligned_size, + (uintptr_t)addr, size, CONFIG_MMU_PAGE_SIZE); + + for (size_t offset = 0; offset < aligned_size; + offset += CONFIG_MMU_PAGE_SIZE) { + if (!page_validate(ptables, (uint32_t)(virt + offset), ring, write)) { + ret = -1; + break; + } + } + + return ret; +} + +void z_xtensa_swap_update_page_tables(struct k_thread *incoming) +{ + uint32_t *ptables = incoming->arch.ptables; + struct arch_mem_domain *domain = + &(incoming->mem_domain_info.mem_domain->arch); + + /* Lets set the asid for the incoming thread */ + if ((incoming->base.user_options & K_USER) != 0) { + xtensa_rasid_asid_set(domain->asid, Z_XTENSA_USER_RING); + } + + switch_page_tables(ptables, true, false); +} + +#endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/include/kernel_arch_func.h b/arch/xtensa/include/kernel_arch_func.h index 2256f72f64544d0..8ce5cc52a5b51a2 100644 --- a/arch/xtensa/include/kernel_arch_func.h +++ b/arch/xtensa/include/kernel_arch_func.h @@ -174,6 +174,13 @@ static inline bool arch_is_in_isr(void) return arch_curr_cpu()->nested != 0U; } +#ifdef CONFIG_USERSPACE +extern void z_xtensa_userspace_enter(k_thread_entry_t user_entry, + void *p1, void *p2, void *p3, + uintptr_t stack_end, + uintptr_t stack_start); +#endif /* CONFIG_USERSPACE */ + #ifdef __cplusplus } #endif diff --git a/arch/xtensa/include/offsets_short_arch.h b/arch/xtensa/include/offsets_short_arch.h index 34a4a5842cf753a..f19750dc0ac8b96 100644 --- a/arch/xtensa/include/offsets_short_arch.h +++ b/arch/xtensa/include/offsets_short_arch.h @@ -2,4 +2,18 @@ * Copyright (c) 2021 Intel Corporation * SPDX-License-Identifier: Apache-2.0 */ -/* Empty File */ +#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ +#define ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ + +#define _thread_offset_to_flags \ + (___thread_t_arch_OFFSET + ___thread_arch_t_flags_OFFSET) + +#ifdef CONFIG_USERSPACE +#define _thread_offset_to_psp \ + (___thread_t_arch_OFFSET + ___thread_arch_t_psp_OFFSET) + +#define _thread_offset_to_ptables \ + (___thread_t_arch_OFFSET + ___thread_arch_t_ptables_OFFSET) +#endif /* CONFIG_USERSPACE */ + +#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ */ diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h index f691dbc6cad9b14..a98c61db253a990 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa-asm2-s.h @@ -176,7 +176,8 @@ rsr.SCOMPARE1 a0 s32i a0, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET #endif -#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE) +#if XCHAL_HAVE_THREADPTR && \ + (defined(CONFIG_USERSPACE) || defined(CONFIG_THREAD_LOCAL_STORAGE)) rur.THREADPTR a0 s32i a0, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET #endif @@ -409,6 +410,16 @@ _xstack_returned_\@: l32i a2, a1, 0 l32i a2, a2, ___xtensa_irq_bsa_t_scratch_OFFSET +#if XCHAL_HAVE_THREADPTR && defined(CONFIG_USERSPACE) + /* Clear up the threadptr because it is used + * to check if a thread is runnig on user mode. Since + * we are in a interruption we don't want the system + * thinking it is possbly running in user mode. + */ + movi.n a0, 0 + wur.THREADPTR a0 +#endif /* XCHAL_HAVE_THREADPTR && CONFIG_USERSPACE */ + /* There's a gotcha with level 1 handlers: the INTLEVEL field * gets left at zero and not set like high priority interrupts * do. That works fine for exceptions, but for L1 interrupts, diff --git a/include/zephyr/arch/syscall.h b/include/zephyr/arch/syscall.h index b657717e3d4bc6b..5b41561b681907c 100644 --- a/include/zephyr/arch/syscall.h +++ b/include/zephyr/arch/syscall.h @@ -23,6 +23,8 @@ #include #elif defined(CONFIG_RISCV) #include +#elif defined(CONFIG_XTENSA) +#include #endif #endif /* ZEPHYR_INCLUDE_ARCH_SYSCALL_H_ */ diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 0838e68ee5a64d7..397e5c7fa7894af 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -47,6 +48,15 @@ extern "C" { #endif +struct arch_mem_domain { +#ifdef CONFIG_XTENSA_MMU + uint32_t *ptables __aligned(CONFIG_MMU_PAGE_SIZE); + uint8_t asid; + bool dirty; +#endif + sys_snode_t node; +}; + extern void xtensa_arch_except(int reason_p); #define ARCH_EXCEPT(reason_p) do { \ diff --git a/include/zephyr/arch/xtensa/syscall.h b/include/zephyr/arch/xtensa/syscall.h new file mode 100644 index 000000000000000..3d78827b77c7ccc --- /dev/null +++ b/include/zephyr/arch/xtensa/syscall.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2022 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Xtensa specific syscall header + * + * This header contains the Xtensa specific syscall interface. It is + * included by the syscall interface architecture-abstraction header + * (include/arch/syscall.h) + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_SYSCALL_H_ +#define ZEPHYR_INCLUDE_ARCH_XTENSA_SYSCALL_H_ + +#ifdef CONFIG_USERSPACE +#ifndef _ASMLANGUAGE + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER +uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id); + +uintptr_t arch_syscall_invoke5_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, + uintptr_t call_id); + +uintptr_t arch_syscall_invoke4_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id); + +uintptr_t arch_syscall_invoke3_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t call_id); + +uintptr_t arch_syscall_invoke2_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id); + +uintptr_t arch_syscall_invoke1_helper(uintptr_t arg1, uintptr_t call_id); + +uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id); +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ + +/** + * We are following Linux Xtensa syscall ABI: + * + * syscall number arg1, arg2, arg3, arg4, arg5, arg6 + * -------------- ---------------------------------- + * a2 a6, a3, a4, a5, a8, a9 + * + **/ + +static inline uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke6_helper(arg1, arg2, arg3, + arg4, arg5, arg6, + call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + register uintptr_t a9 __asm__("%a9") = arg6; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8), "r" (a9) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static inline uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke5_helper(arg1, arg2, arg3, + arg4, arg5, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static inline uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke4_helper(arg1, arg2, arg3, arg4, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke3_helper(arg1, arg2, arg3, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke2_helper(arg1, arg2, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3) + : "memory"); + + return a2; +#endif +} + +static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke1_helper(arg1, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6) + : "memory"); + + return a2; +#endif +} + +static inline uintptr_t arch_syscall_invoke0(uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return arch_syscall_invoke0_helper(call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2) + : "memory"); + + return a2; +#endif +} + +/* + * There is no easy (or generic) way to figure out if a thread is runnining + * in un-privileged mode. Reading the currrent ring (PS.CRING) is a privileged + * instruction and not thread local storage is not available in xcc. + */ +static inline bool arch_is_user_context(void) +{ + uint32_t thread; + + __asm__ volatile( + "rur.THREADPTR %0\n\t" + : "=a" (thread) + ); + + return !!thread; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ +#endif /* CONFIG_USERSPACE */ +#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_SYSCALL_H_ */ diff --git a/include/zephyr/arch/xtensa/thread.h b/include/zephyr/arch/xtensa/thread.h index 4ec5da1ea2c048c..2bebe2722bcb2d5 100644 --- a/include/zephyr/arch/xtensa/thread.h +++ b/include/zephyr/arch/xtensa/thread.h @@ -7,6 +7,7 @@ #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_H_ #define ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_H_ +#include #ifndef _ASMLANGUAGE /* Xtensa doesn't use these structs, but Zephyr core requires they be @@ -22,6 +23,14 @@ typedef struct _callee_saved _callee_saved_t; struct _thread_arch { uint32_t last_cpu; +#ifdef CONFIG_USERSPACE + uint32_t *ptables; + + /* Initial privilege mode stack pointer when doing a system call. + * Un-set for surpervisor threads. + */ + uint8_t *psp; +#endif }; typedef struct _thread_arch _thread_arch_t; diff --git a/include/zephyr/arch/xtensa/xtensa_mmu.h b/include/zephyr/arch/xtensa/xtensa_mmu.h index 2ee3dc6c9ab8ee9..40fd0ff8f5c114f 100644 --- a/include/zephyr/arch/xtensa/xtensa_mmu.h +++ b/include/zephyr/arch/xtensa/xtensa_mmu.h @@ -9,8 +9,40 @@ #define Z_XTENSA_MMU_X BIT(0) #define Z_XTENSA_MMU_W BIT(1) +#define Z_XTENSA_MMU_XW (BIT(1) | BIT(0)) + #define Z_XTENSA_MMU_CACHED_WB BIT(2) #define Z_XTENSA_MMU_CACHED_WT BIT(3) + +#define K_MEM_PARTITION_IS_EXECUTABLE(attr) (((attr) & Z_XTENSA_MMU_X) != 0) +#define K_MEM_PARTITION_IS_WRITABLE(attr) (((attr) & Z_XENSA_MMU_W) != 0) + +/* Read-Write access permission attributes */ +#define K_MEM_PARTITION_P_RW_U_RW ((k_mem_partition_attr_t) \ + {Z_XTENSA_MMU_W}) +#define K_MEM_PARTITION_P_RW_U_NA ((k_mem_partition_attr_t) \ + {0}) +#define K_MEM_PARTITION_P_RO_U_RO ((k_mem_partition_attr_t) \ + {0}) +#define K_MEM_PARTITION_P_RO_U_NA ((k_mem_partition_attr_t) \ + {0}) +#define K_MEM_PARTITION_P_NA_U_NA ((k_mem_partition_attr_t) \ + {0}) + +/* Execution-allowed attributes */ +#define K_MEM_PARTITION_P_RX_U_RX ((k_mem_partition_attr_t) \ + {Z_XTENSA_MMU_X}) + +/* + * This BIT tells the mapping code whether the uncached pointer should + * be shared between all threads. That is not used in the HW, it is + * just for the implementation. + * + * The pte mapping this memory will use an ASID that is set in the + * ring 4 spot in RASID. + */ +#define Z_XTENSA_MMU_MAP_SHARED BIT(30) + #define Z_XTENSA_MMU_ILLEGAL (BIT(3) | BIT(2)) /* Struct used to map a memory region */ @@ -21,6 +53,8 @@ struct xtensa_mmu_range { const uint32_t attrs; }; +typedef uint32_t k_mem_partition_attr_t; + extern const struct xtensa_mmu_range xtensa_soc_mmu_ranges[]; extern int xtensa_soc_mmu_ranges_num; From c53325298d2bf20027b04ed08cd05db9df81741e Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 16 Nov 2022 22:48:42 -0800 Subject: [PATCH 0803/1049] xtensa: userspace: Stack object header Add a header with architecture specific macros and definitions that re used on userspace for stack objects. Signed-off-by: Flavio Ceolin --- include/zephyr/arch/xtensa/arch.h | 7 +-- include/zephyr/arch/xtensa/thread_stack.h | 67 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 include/zephyr/arch/xtensa/thread_stack.h diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 397e5c7fa7894af..9f2fb757a116c5a 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -29,16 +29,11 @@ #include #include #include +#include #include #include -#ifdef CONFIG_KERNEL_COHERENCE -#define ARCH_STACK_PTR_ALIGN XCHAL_DCACHE_LINESIZE -#else -#define ARCH_STACK_PTR_ALIGN 16 -#endif - /* Xtensa GPRs are often designated by two different names */ #define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; } diff --git a/include/zephyr/arch/xtensa/thread_stack.h b/include/zephyr/arch/xtensa/thread_stack.h new file mode 100644 index 000000000000000..eaa160ccf1fdd43 --- /dev/null +++ b/include/zephyr/arch/xtensa/thread_stack.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_STACK_H_ +#define ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_STACK_H_ + +#include +#include + +#ifdef CONFIG_KERNEL_COHERENCE +#define ARCH_STACK_PTR_ALIGN XCHAL_DCACHE_LINESIZE +#else +#define ARCH_STACK_PTR_ALIGN 16 +#endif + + +#if CONFIG_USERSPACE +#define Z_XTENSA_STACK_BASE_ALIGN CONFIG_MMU_PAGE_SIZE +#define Z_XTENSA_STACK_SIZE_ALIGN CONFIG_MMU_PAGE_SIZE +#else +#define Z_XTENSA_STACK_BASE_ALIGN ARCH_STACK_PTR_ALIGN +#define Z_XTENSA_STACK_SIZE_ALIGN ARCH_STACK_PTR_ALIGN +#endif + +/* + * + * High memory addresses + * + * +-------------------+ <- thread.stack_info.start + thread.stack_info.size + * | TLS | + * +-------------------+ <- initial sp (computable with thread.stack_info.delta) + * | | + * | Thread stack | + * | | + * +-------------------+ <- thread.stack_info.start + * | Privileged stack | } CONFIG_MMU_PAGE_SIZE + * +-------------------+ <- thread.stack_obj + * + * Low Memory addresses + */ + +#ifndef _ASMLANGUAGE + +/* thread stack */ +#ifdef CONFIG_XTENSA_MMU +struct z_xtensa_thread_stack_header { + char privilege_stack[CONFIG_MMU_PAGE_SIZE]; +} __packed __aligned(Z_XTENSA_STACK_BASE_ALIGN); + +#define ARCH_THREAD_STACK_RESERVED \ + sizeof(struct z_xtensa_thread_stack_header) +#endif /* CONFIG_XTENSA_MMU */ + +#define ARCH_THREAD_STACK_OBJ_ALIGN(size) Z_XTENSA_STACK_BASE_ALIGN +#define ARCH_THREAD_STACK_SIZE_ADJUST(size) \ + ROUND_UP((size), Z_XTENSA_STACK_SIZE_ALIGN) + +/* kernel stack */ +#define ARCH_KERNEL_STACK_RESERVED 0 +#define ARCH_KERNEL_STACK_OBJ_ALIGN ARCH_STACK_PTR_ALIGN + +#endif /* _ASMLANGUAGE */ + +#endif From c4706a382300b57032546fd4085acc474a48864e Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 31 Jan 2023 13:07:48 -0800 Subject: [PATCH 0804/1049] xtensa: mmu: handle page faults in double exception handler This changes the TLB misses handling back to the assembly in user exception, and any page faults during TLB misses to be handled in double exception handler. This should speed up simple TLB miss handling as we don't have to go all the way to the C handler. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/xtensa-asm2-util.S | 6 +- arch/xtensa/core/xtensa-asm2.c | 95 +++++++++++------------------ 2 files changed, 41 insertions(+), 60 deletions(-) diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index c108a09dee4814a..1ef9e5e1b4fd4b9 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -447,7 +447,10 @@ _DoubleExceptionVector: beqz a0, _handle_tlb_miss_dblexc rsr a0, ZSR_A0SAVE -#endif + + j _Level1Vector +#else + #if defined(CONFIG_SIMULATOR_XTENSA) || defined(XT_SIMULATOR) 1: /* Tell simulator to stop executing here, instead of trying to do @@ -465,6 +468,7 @@ _DoubleExceptionVector: 1: #endif j 1b +#endif /* CONFIG_XTENSA_MMU */ #ifdef CONFIG_XTENSA_MMU _handle_tlb_miss_dblexc: diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 1e8c92759e42fb8..3fb519cd80de8f6 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -293,34 +293,31 @@ void *xtensa_excint1_c(int *interrupted_stack) uint32_t ps; void *pc; +#ifdef CONFIG_XTENSA_MMU + bool is_dblexc; + uint32_t depc; +#else + const bool is_dblexc = false; +#endif /* CONFIG_XTENSA_MMU */ + __asm__ volatile("rsr.exccause %0" : "=r"(cause)); #ifdef CONFIG_XTENSA_MMU - /* TLB miss exception comes through level 1 interrupt also. - * We need to preserve execution context after we have handled - * the TLB miss, so we cannot unconditionally unmask interrupts. - * For other cause, we can unmask interrupts so this would act - * the same as if there is no MMU. - */ - switch (cause) { - case EXCCAUSE_ITLB_MISS: - /* Instruction TLB miss */ - __fallthrough; - case EXCCAUSE_DTLB_MISS: - /* Data TLB miss */ + __asm__ volatile("rsr.depc %0" : "=r"(depc)); - /* Do not unmask interrupt while handling TLB misses. */ - break; - default: - /* For others, we can unmask interrupts. */ - bsa->ps &= ~PS_INTLEVEL_MASK; - break; - } + is_dblexc = (depc != 0U); #endif /* CONFIG_XTENSA_MMU */ switch (cause) { case EXCCAUSE_LEVEL1_INTERRUPT: - return xtensa_int1_c(interrupted_stack); + if (!is_dblexc) { + return xtensa_int1_c(interrupted_stack); + } + break; +#ifndef CONFIG_USERSPACE + /* Syscalls are handled earlier in assembly if MMU is enabled. + * So we don't need this here. + */ case EXCCAUSE_SYSCALL: /* Just report it to the console for now */ LOG_ERR(" ** SYSCALL PS %p PC %p", @@ -333,38 +330,7 @@ void *xtensa_excint1_c(int *interrupted_stack) */ bsa->pc += 3; break; -#ifdef CONFIG_XTENSA_MMU - case EXCCAUSE_ITLB_MISS: - /* Instruction TLB miss */ - __fallthrough; - case EXCCAUSE_DTLB_MISS: - /* Data TLB miss */ - - /** - * The way it works is, when we try to access an address - * that is not mapped, we will have a miss. The HW then - * will try to get the correspondent memory in the page - * table. As the page table is not mapped in memory we will - * have a second miss, which will trigger an exception. - * In the exception (here) what we do is to exploit this - * hardware capability just trying to load the page table - * (not mapped address), which will cause a miss, but then - * the hardware will automatically map it again from - * the page table. This time it will work since the page - * necessary to map the page table itself are wired map. - */ - __asm__ volatile("wsr a0, " ZSR_EXTRA0_STR "\n\t" - "rsr.ptevaddr a0\n\t" - "l32i a0, a0, 0\n\t" - "rsr a0, " ZSR_EXTRA0_STR "\n\t" - "rsync" - : : : "a0", "memory"); - - /* Since we are dealing with TLB misses, we will probably not - * want to switch to another thread. - */ - return interrupted_stack; -#endif /* CONFIG_XTENSA_MMU */ +#endif /* !CONFIG_USERSPACE */ default: ps = bsa->ps; pc = (void *)bsa->pc; @@ -373,6 +339,7 @@ void *xtensa_excint1_c(int *interrupted_stack) /* Default for exception */ int reason = K_ERR_CPU_EXCEPTION; + is_fatal_error = true; /* We need to distinguish between an ill in xtensa_arch_except, * e.g for k_panic, and any other ill. For exceptions caused by @@ -389,13 +356,19 @@ void *xtensa_excint1_c(int *interrupted_stack) reason = bsa->a2; } - LOG_ERR(" ** FATAL EXCEPTION"); + LOG_ERR(" ** FATAL EXCEPTION%s", (is_dblexc ? " (DOUBLE)" : "")); LOG_ERR(" ** CPU %d EXCCAUSE %d (%s)", arch_curr_cpu()->id, cause, z_xtensa_exccause(cause)); LOG_ERR(" ** PC %p VADDR %p", pc, (void *)vaddr); LOG_ERR(" ** PS %p", (void *)bsa->ps); + if (is_dblexc) { + LOG_ERR(" ** DEPC %p", (void *)depc); + } +#ifdef CONFIG_USERSPACE + LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); +#endif /* CONFIG_USERSPACE */ LOG_ERR(" ** (INTLEVEL:%d EXCM: %d UM:%d RING:%d WOE:%d OWB:%d CALLINC:%d)", get_bits(0, 4, ps), get_bits(4, 1, ps), get_bits(5, 1, ps), get_bits(6, 2, ps), @@ -412,13 +385,12 @@ void *xtensa_excint1_c(int *interrupted_stack) break; } - +#ifdef CONFIG_XTENSA_MMU switch (cause) { - case EXCCAUSE_SYSCALL: case EXCCAUSE_LEVEL1_INTERRUPT: - case EXCCAUSE_ALLOCA: - case EXCCAUSE_ITLB_MISS: - case EXCCAUSE_DTLB_MISS: +#ifndef CONFIG_USERSPACE + case EXCCAUSE_SYSCALL: +#endif /* !CONFIG_USERSPACE */ is_fatal_error = false; break; default: @@ -426,7 +398,12 @@ void *xtensa_excint1_c(int *interrupted_stack) break; } - if (is_fatal_error) { + if (is_dblexc) { + __asm__ volatile("wsr.depc %0" : : "r"(0)); + } +#endif /* CONFIG_XTENSA_MMU */ + + if (is_dblexc || is_fatal_error) { uint32_t ignore; /* We are going to manipulate _current_cpu->nested manually. From bc0656a92e0689a380e464963b92a983346df7cc Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 16 Feb 2023 11:25:48 -0800 Subject: [PATCH 0805/1049] xtensa: mmu: allocate scratch registers for MMU When MMU is enabled, we need some scratch registers to preload page table entries. So update gen_zsr.py to that. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/CMakeLists.txt | 1 + arch/xtensa/core/gen_zsr.py | 24 ++++++++++++++++++++---- arch/xtensa/core/xtensa-asm2-util.S | 6 +++--- arch/xtensa/include/xtensa-asm2-s.h | 8 ++++---- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 8a23b65b9a9b16d..331bcd9bfc52d38 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -59,6 +59,7 @@ add_custom_command(OUTPUT ${CORE_ISA_DM} set(ZSR_H ${CMAKE_BINARY_DIR}/zephyr/include/generated/zsr.h) add_custom_command(OUTPUT ${ZSR_H} DEPENDS ${CORE_ISA_DM} COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/gen_zsr.py + $<$:--mmu> ${CORE_ISA_DM} ${ZSR_H}) add_custom_target(zsr_h DEPENDS ${ZSR_H}) add_dependencies(zephyr_interface zsr_h) diff --git a/arch/xtensa/core/gen_zsr.py b/arch/xtensa/core/gen_zsr.py index 574542a4578ed1e..0e3069a4c450d41 100755 --- a/arch/xtensa/core/gen_zsr.py +++ b/arch/xtensa/core/gen_zsr.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # Copyright (c) 2022 Intel corporation # SPDX-License-Identifier: Apache-2.0 -import sys +import argparse import re # Scratch register allocator. Zephyr uses multiple Xtensa SRs as @@ -11,10 +11,26 @@ # -dM") core-isa.h file for the current architecture and assigns # registers to usages. -NEEDED = ("A0SAVE", "CPU", "FLUSH") +def parse_args(): + parser = argparse.ArgumentParser(allow_abbrev=False) -coreisa = sys.argv[1] -outfile = sys.argv[2] + parser.add_argument("--mmu", action="store_true", + help="Enable scratch registers for MMU usage") + parser.add_argument("coreisa", + help="Path to preprocessed core-isa.h") + parser.add_argument("outfile", + help="Output file") + + return parser.parse_args() + +args = parse_args() + +NEEDED = ["A0SAVE", "CPU", "FLUSH"] +if args.mmu: + NEEDED += ["MMU_0", "MMU_1", "DBLEXC"] + +coreisa = args.coreisa +outfile = args.outfile syms = {} diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index 1ef9e5e1b4fd4b9..7dfd1d0bc92b317 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -439,14 +439,14 @@ _handle_tlb_miss_kernel: .global _DoubleExceptionVector _DoubleExceptionVector: #ifdef CONFIG_XTENSA_MMU - wsr a0, ZSR_A0SAVE + wsr a0, ZSR_DBLEXC rsync rsr.exccause a0 addi a0, a0, -EXCCAUSE_DTLB_MISS beqz a0, _handle_tlb_miss_dblexc - rsr a0, ZSR_A0SAVE + rsr a0, ZSR_DBLEXC j _Level1Vector #else @@ -482,7 +482,7 @@ _handle_tlb_miss_dblexc: rsr.ptevaddr a0 l32i a0, a0, 0 - rsr a0, ZSR_A0SAVE + rsr a0, ZSR_DBLEXC rfde #endif .popsection diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h index a98c61db253a990..8c08916c8c65216 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa-asm2-s.h @@ -558,8 +558,8 @@ _Level\LVL\()VectorHelper : _Level\LVL\()Vector: #endif #ifdef CONFIG_XTENSA_MMU - wsr.ZSR_EXTRA0 a2 - wsr.ZSR_EXTRA1 a3 + wsr.ZSR_MMU_0 a2 + wsr.ZSR_MMU_1 a3 rsync /* Calculations below will clobber registers used. @@ -579,8 +579,8 @@ _Level\LVL\()Vector: rsr.ZSR_CPU a3 PRELOAD_PTEVADDR a3, a2 - rsr.ZSR_EXTRA1 a3 - rsr.ZSR_EXTRA0 a2 + rsr.ZSR_MMU_1 a3 + rsr.ZSR_MMU_0 a2 #endif /* CONFIG_XTENSA_MMU */ addi a1, a1, -___xtensa_irq_bsa_t_SIZEOF s32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET From e9c449a737e98c95b983a38d6855742c9f6c6d0c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 16 Mar 2023 14:34:28 -0700 Subject: [PATCH 0806/1049] xtensa: mmu: do not fault for known exceptions There are known exceptions which are not fatal, and we need to handle them properly by returning to the fixup addresses as indicated. This adds the code necessary in the exception handler for this situation. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/fatal.c | 8 ------- arch/xtensa/core/xtensa-asm2.c | 38 ++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 3117ebc4a56d701..b262a8aad4dac71 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -121,14 +121,6 @@ void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) z_fatal_error(reason, esf); } -#ifdef CONFIG_USERSPACE -Z_EXC_DECLARE(z_xtensa_user_string_nlen); - -static const struct z_exc_handle exceptions[] = { - Z_EXC_HANDLE(z_xtensa_user_string_nlen) -}; -#endif /* CONFIG_USERSPACE */ - #ifdef XT_SIMULATOR void exit(int return_code) { diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 3fb519cd80de8f6..79c784f5f7d99ad 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -15,11 +15,20 @@ #include #include #include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); extern char xtensa_arch_except_epc[]; +#ifdef CONFIG_USERSPACE +Z_EXC_DECLARE(z_xtensa_user_string_nlen); + +static const struct z_exc_handle exceptions[] = { + Z_EXC_HANDLE(z_xtensa_user_string_nlen) +}; +#endif /* CONFIG_USERSPACE */ + void *xtensa_init_stack(struct k_thread *thread, int *stack_top, void (*entry)(void *, void *, void *), void *arg1, void *arg2, void *arg3) @@ -335,6 +344,21 @@ void *xtensa_excint1_c(int *interrupted_stack) ps = bsa->ps; pc = (void *)bsa->pc; +#ifdef CONFIG_USERSPACE + /* If the faulting address is from one of the known + * exceptions that should not be fatal, return to + * the fixup address. + */ + for (int i = 0; i < ARRAY_SIZE(exceptions); i++) { + if ((pc >= exceptions[i].start) && + (pc < exceptions[i].end)) { + bsa->pc = (uintptr_t)exceptions[i].fixup; + + goto fixup_out; + } + } +#endif /* CONFIG_USERSPACE */ + __asm__ volatile("rsr.excvaddr %0" : "=r"(vaddr)); /* Default for exception */ @@ -397,10 +421,6 @@ void *xtensa_excint1_c(int *interrupted_stack) is_fatal_error = true; break; } - - if (is_dblexc) { - __asm__ volatile("wsr.depc %0" : : "r"(0)); - } #endif /* CONFIG_XTENSA_MMU */ if (is_dblexc || is_fatal_error) { @@ -432,6 +452,16 @@ void *xtensa_excint1_c(int *interrupted_stack) _current_cpu->nested = 1; } +#ifdef CONFIG_XTENSA_MMU +#ifdef CONFIG_USERSPACE +fixup_out: +#endif + if (is_dblexc) { + __asm__ volatile("wsr.depc %0" : : "r"(0)); + } +#endif /* CONFIG_XTENSA_MMU */ + + return return_to(interrupted_stack); } From 716efb2e405d4478dc7438e8c28ef311280e4b09 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 12 Apr 2023 16:04:12 -0700 Subject: [PATCH 0807/1049] xtensa: extract printing of fatal exception into its own func This extracts the printing of fatal exception information into its own function to declutter xtensa_excint1_c(). Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/xtensa-asm2.c | 65 +++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 79c784f5f7d99ad..92b410c46c82584 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -202,6 +202,39 @@ static inline unsigned int get_bits(int offset, int num_bits, unsigned int val) return val & mask; } +static void print_fatal_exception(_xtensa_irq_bsa_t *bsa, int cause, + bool is_dblexc, uint32_t depc) +{ + void *pc; + uint32_t ps, vaddr; + + ps = bsa->ps; + pc = (void *)bsa->pc; + + __asm__ volatile("rsr.excvaddr %0" : "=r"(vaddr)); + + LOG_ERR(" ** FATAL EXCEPTION%s", (is_dblexc ? " (DOUBLE)" : "")); + LOG_ERR(" ** CPU %d EXCCAUSE %d (%s)", + arch_curr_cpu()->id, cause, + z_xtensa_exccause(cause)); + LOG_ERR(" ** PC %p VADDR %p", pc, (void *)vaddr); + + if (is_dblexc) { + LOG_ERR(" ** DEPC %p", (void *)depc); + } + +#ifdef CONFIG_USERSPACE + LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); +#endif /* CONFIG_USERSPACE */ + + LOG_ERR(" ** PS %p", (void *)bsa->ps); + LOG_ERR(" ** (INTLEVEL:%d EXCM: %d UM:%d RING:%d WOE:%d OWB:%d CALLINC:%d)", + get_bits(0, 4, ps), get_bits(4, 1, ps), + get_bits(5, 1, ps), get_bits(6, 2, ps), + get_bits(18, 1, ps), + get_bits(8, 4, ps), get_bits(16, 2, ps)); +} + static ALWAYS_INLINE void usage_stop(void) { #ifdef CONFIG_SCHED_THREAD_USAGE @@ -296,18 +329,13 @@ static inline DEF_INT_C_HANDLER(1) */ void *xtensa_excint1_c(int *interrupted_stack) { - int cause, vaddr; + int cause; _xtensa_irq_bsa_t *bsa = (void *)*(int **)interrupted_stack; bool is_fatal_error = false; + bool is_dblexc = false; uint32_t ps; void *pc; - -#ifdef CONFIG_XTENSA_MMU - bool is_dblexc; - uint32_t depc; -#else - const bool is_dblexc = false; -#endif /* CONFIG_XTENSA_MMU */ + uint32_t depc = 0; __asm__ volatile("rsr.exccause %0" : "=r"(cause)); @@ -359,8 +387,6 @@ void *xtensa_excint1_c(int *interrupted_stack) } #endif /* CONFIG_USERSPACE */ - __asm__ volatile("rsr.excvaddr %0" : "=r"(vaddr)); - /* Default for exception */ int reason = K_ERR_CPU_EXCEPTION; is_fatal_error = true; @@ -380,24 +406,7 @@ void *xtensa_excint1_c(int *interrupted_stack) reason = bsa->a2; } - LOG_ERR(" ** FATAL EXCEPTION%s", (is_dblexc ? " (DOUBLE)" : "")); - LOG_ERR(" ** CPU %d EXCCAUSE %d (%s)", - arch_curr_cpu()->id, cause, - z_xtensa_exccause(cause)); - LOG_ERR(" ** PC %p VADDR %p", - pc, (void *)vaddr); - LOG_ERR(" ** PS %p", (void *)bsa->ps); - if (is_dblexc) { - LOG_ERR(" ** DEPC %p", (void *)depc); - } -#ifdef CONFIG_USERSPACE - LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); -#endif /* CONFIG_USERSPACE */ - LOG_ERR(" ** (INTLEVEL:%d EXCM: %d UM:%d RING:%d WOE:%d OWB:%d CALLINC:%d)", - get_bits(0, 4, ps), get_bits(4, 1, ps), - get_bits(5, 1, ps), get_bits(6, 2, ps), - get_bits(18, 1, ps), - get_bits(8, 4, ps), get_bits(16, 2, ps)); + print_fatal_exception(bsa, cause, is_dblexc, depc); /* FIXME: legacy xtensa port reported "HW" exception * for all unhandled exceptions, which seems incorrect From 75936d8db2217e88c1e0db048c8fe00b7e855d4c Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 15 Dec 2022 15:05:14 -0800 Subject: [PATCH 0808/1049] xtensa: userspace: Implement arch_syscall_oops This function is needed by userspace. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/fatal.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index b262a8aad4dac71..fbf19d9df91039d 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -141,3 +141,11 @@ FUNC_NORETURN void z_system_halt(unsigned int reason) CODE_UNREACHABLE; } #endif + +FUNC_NORETURN void arch_syscall_oops(void *ssf) +{ + z_arch_esf_t *esf = ssf; + + z_xtensa_fatal_error(K_ERR_KERNEL_OOPS, esf); + CODE_UNREACHABLE; +} From 586bb920492ef89717fd71c8d9635452a30de908 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 8 Feb 2023 13:35:18 -0800 Subject: [PATCH 0809/1049] xtensa: userspace: Add syscall for user exception Trigger exception on Xtensa requires kernel privileges. Add a new syscall that is used when ARCH_EXCEPT is invoked from userspace. Signed-off-by: Flavio Ceolin --- arch/xtensa/CMakeLists.txt | 1 + arch/xtensa/core/fatal.c | 21 +++++++++++++++++++++ include/zephyr/arch/xtensa/arch.h | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/arch/xtensa/CMakeLists.txt b/arch/xtensa/CMakeLists.txt index 133d74331d8e667..4626421f11a4ae6 100644 --- a/arch/xtensa/CMakeLists.txt +++ b/arch/xtensa/CMakeLists.txt @@ -1,4 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/arch/xtensa/arch.h) set_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf32-xtensa-le) add_subdirectory(core) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index fbf19d9df91039d..307f4b6ff1de0a7 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -149,3 +149,24 @@ FUNC_NORETURN void arch_syscall_oops(void *ssf) z_xtensa_fatal_error(K_ERR_KERNEL_OOPS, esf); CODE_UNREACHABLE; } + +#ifdef CONFIG_USERSPACE +void z_impl_xtensa_user_fault(unsigned int reason) +{ + if ((_current->base.user_options & K_USER) != 0) { + if ((reason != K_ERR_KERNEL_OOPS) && + (reason != K_ERR_STACK_CHK_FAIL)) { + reason = K_ERR_KERNEL_OOPS; + } + } + xtensa_arch_except(reason); +} + +static void z_vrfy_xtensa_user_fault(unsigned int reason) +{ + z_impl_xtensa_user_fault(reason); +} + +#include + +#endif /* CONFIG_USERSPACE */ diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 9f2fb757a116c5a..16bfd08091a475a 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -54,11 +55,31 @@ struct arch_mem_domain { extern void xtensa_arch_except(int reason_p); +#ifdef CONFIG_USERSPACE + +#define ARCH_EXCEPT(reason_p) do { \ + if (k_is_user_context()) { \ + arch_syscall_invoke1(reason_p, \ + K_SYSCALL_XTENSA_USER_FAULT); \ + } else { \ + xtensa_arch_except(reason_p); \ + } \ + CODE_UNREACHABLE; \ +} while (false) + +#else + #define ARCH_EXCEPT(reason_p) do { \ xtensa_arch_except(reason_p); \ CODE_UNREACHABLE; \ } while (false) +#endif + +__syscall void xtensa_user_fault(unsigned int reason); + +#include + /* internal routine documented in C file, needed by IRQ_CONNECT() macro */ extern void z_irq_priority_set(uint32_t irq, uint32_t prio, uint32_t flags); From eb546a8d877fdfbaaad8935e414f95cb5ca15555 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 12 Apr 2023 15:42:38 -0700 Subject: [PATCH 0810/1049] xtensa: rework kernel oops exception path When kernel OOPS is raised, we need to actually go through the process of terminating the offending thread, instead of simply printing the stack and continue running. This change employs similar mechanism to xtensa_arch_except() to use illegal instruction to raise hardware exception, and going through the fatal exception path. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- arch/xtensa/core/fatal.c | 8 ++++--- arch/xtensa/core/xtensa-asm2-util.S | 14 +++++++++++ arch/xtensa/core/xtensa-asm2.c | 36 ++++++++++++++++++++++------- include/zephyr/arch/xtensa/arch.h | 1 + 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 307f4b6ff1de0a7..79a24baa1056243 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -87,6 +87,8 @@ char *z_xtensa_exccause(unsigned int cause_code) case 63: /* i.e. z_except_reason */ return "zephyr exception"; + case 64: + return "kernel oops"; default: return "unknown/reserved"; } @@ -114,7 +116,6 @@ void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) z_xtensa_backtrace_print(100, (int *)esf); #endif #endif - arch_irq_unlock(key); } @@ -144,9 +145,10 @@ FUNC_NORETURN void z_system_halt(unsigned int reason) FUNC_NORETURN void arch_syscall_oops(void *ssf) { - z_arch_esf_t *esf = ssf; + ARG_UNUSED(ssf); + + xtensa_arch_kernel_oops(K_ERR_KERNEL_OOPS, ssf); - z_xtensa_fatal_error(K_ERR_KERNEL_OOPS, esf); CODE_UNREACHABLE; } diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S index 7dfd1d0bc92b317..4f8af894ccb572b 100644 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ b/arch/xtensa/core/xtensa-asm2-util.S @@ -204,6 +204,20 @@ xtensa_arch_except_epc: ill retw +/* + * void xtensa_arch_kernel_oops(int reason_p, void *ssf); + * + * Simply to raise hardware exception for Kernel OOPS. + */ +.global xtensa_arch_kernel_oops +.global xtensa_arch_kernel_oops_epc +.align 4 +xtensa_arch_kernel_oops: + entry a1, 16 +xtensa_arch_kernel_oops_epc: + ill + retw + /* * void xtensa_switch(void *new, void **old_return); * diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index 92b410c46c82584..ed8f340f1bcb454 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -20,6 +20,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); extern char xtensa_arch_except_epc[]; +extern char xtensa_arch_kernel_oops_epc[]; #ifdef CONFIG_USERSPACE Z_EXC_DECLARE(z_xtensa_user_string_nlen); @@ -202,11 +203,12 @@ static inline unsigned int get_bits(int offset, int num_bits, unsigned int val) return val & mask; } -static void print_fatal_exception(_xtensa_irq_bsa_t *bsa, int cause, +static void print_fatal_exception(void *print_stack, int cause, bool is_dblexc, uint32_t depc) { void *pc; uint32_t ps, vaddr; + _xtensa_irq_bsa_t *bsa = (void *)*(int **)print_stack; ps = bsa->ps; pc = (void *)bsa->pc; @@ -334,7 +336,7 @@ void *xtensa_excint1_c(int *interrupted_stack) bool is_fatal_error = false; bool is_dblexc = false; uint32_t ps; - void *pc; + void *pc, *print_stack = (void *)interrupted_stack; uint32_t depc = 0; __asm__ volatile("rsr.exccause %0" : "=r"(cause)); @@ -399,14 +401,32 @@ void *xtensa_excint1_c(int *interrupted_stack) * We assign EXCCAUSE the unused, reserved code 63; this may be * problematic if the app or new boards also decide to repurpose * this code. + * + * Another intentionally ill is from xtensa_arch_kernel_oops. + * Kernel OOPS has to be explicity raised so we can simply + * set the reason and continue. */ - if ((pc == (void *) &xtensa_arch_except_epc) && (cause == 0)) { - cause = 63; - __asm__ volatile("wsr.exccause %0" : : "r"(cause)); - reason = bsa->a2; + if (cause == EXCCAUSE_ILLEGAL) { + if (pc == (void *)&xtensa_arch_except_epc) { + cause = 63; + __asm__ volatile("wsr.exccause %0" : : "r"(cause)); + reason = bsa->a2; + } else if (pc == (void *)&xtensa_arch_kernel_oops_epc) { + cause = 64; /* kernel oops */ + reason = K_ERR_KERNEL_OOPS; + + /* A3 contains the second argument to + * xtensa_arch_kernel_oops(reason, ssf) + * where ssf is the stack frame causing + * the kernel oops. + */ + print_stack = (void *)bsa->a3; + } } - print_fatal_exception(bsa, cause, is_dblexc, depc); + if (reason != K_ERR_KERNEL_OOPS) { + print_fatal_exception(print_stack, cause, is_dblexc, depc); + } /* FIXME: legacy xtensa port reported "HW" exception * for all unhandled exceptions, which seems incorrect @@ -414,7 +434,7 @@ void *xtensa_excint1_c(int *interrupted_stack) * up. */ z_xtensa_fatal_error(reason, - (void *)interrupted_stack); + (void *)print_stack); break; } diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 16bfd08091a475a..d486bb4d7b6212f 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -54,6 +54,7 @@ struct arch_mem_domain { }; extern void xtensa_arch_except(int reason_p); +extern void xtensa_arch_kernel_oops(int reason_p, void *ssf); #ifdef CONFIG_USERSPACE From 81ea43692cf855c4ee5af2cd828eafe3785e889b Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 16 Mar 2023 20:27:47 -0700 Subject: [PATCH 0811/1049] xtensa: mmu: send IPI to invalidate TLBs on other CPUs After changing content of page table(s), it is needed to notify the other CPUs that the page table(s) have been changed so they can do the necessary steps to use the updated version. Note that the actual way to send IPI is SoC specific as Xtensa does not have a common way to do this at the moment. Signed-off-by: Daniel Leung --- arch/xtensa/core/xtensa_mmu.c | 79 +++++++++++++++++++++++++ include/zephyr/arch/xtensa/xtensa_mmu.h | 20 +++++++ 2 files changed, 99 insertions(+) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 915a26357eb894f..8a2dcab7ee8bda8 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -659,6 +659,10 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) pa += KB(4); } +#if CONFIG_MP_MAX_NUM_CPUS > 1 + z_xtensa_mmu_tlb_ipi(); +#endif + k_spin_unlock(&xtensa_mmu_lock, key); } @@ -791,9 +795,80 @@ void arch_mem_unmap(void *addr, size_t size) va += KB(4); } +#if CONFIG_MP_MAX_NUM_CPUS > 1 + z_xtensa_mmu_tlb_ipi(); +#endif + k_spin_unlock(&xtensa_mmu_lock, key); } +/* This should be implemented in the SoC layer. + * This weak version is here to avoid build errors. + */ +void __weak z_xtensa_mmu_tlb_ipi(void) +{ +} + +void z_xtensa_mmu_tlb_shootdown(void) +{ + unsigned int key; + + /* Need to lock interrupts to prevent any context + * switching until all the page tables are updated. + * Or else we would be switching to another thread + * and running that with incorrect page tables + * which would result in permission issues. + */ + key = arch_irq_lock(); + + /* We don't have information on which page tables have changed, + * so we just invalidate the cache for all L1 page tables. + */ + sys_cache_data_invd_range((void *)l1_page_table, sizeof(l1_page_table)); + sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + +#ifdef CONFIG_USERSPACE + struct k_thread *thread = _current_cpu->current; + + /* If current thread is a user thread, we need to see if it has + * been migrated to another memory domain as the L1 page table + * is different from the currently used one. + */ + if ((thread->base.user_options & K_USER) == K_USER) { + uint32_t ptevaddr_entry, ptevaddr, thread_ptables; + + /* Need to read the currently used L1 page table. + * We know that L1 page table is always mapped at way + * MMU_PTE_WAY, so we can skip the probing step by + * generating the query entry directly. + */ + ptevaddr_entry = Z_XTENSA_PAGE_TABLE_VADDR | MMU_PTE_WAY; + ptevaddr = xtensa_dtlb_paddr_read(ptevaddr_entry); + + thread_ptables = (uint32_t)thread->arch.ptables; + + if (thread_ptables != ptevaddr) { + /* Need to remap the thread page tables if the ones + * indicated by the current thread are different + * than the current mapped page table. + */ + switch_page_tables((uint32_t *)thread_ptables, false, false); + } + + } +#endif /* CONFIG_USERSPACE */ + + /* L2 are done via autofill, so invalidate autofill TLBs + * would refresh the L2 page tables. + * + * L1 will be refreshed during context switch so no need + * to do anything here. + */ + xtensa_tlb_autorefill_invalidate(); + + arch_irq_unlock(key); +} + #ifdef CONFIG_USERSPACE static inline uint32_t *alloc_l1_table(void) @@ -951,6 +1026,10 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, ret = region_map_update(ptables, start, size, ring, flags); #endif /* CONFIG_XTENSA_MMU_DOUBLE_MAP */ +#if CONFIG_MP_MAX_NUM_CPUS > 1 + z_xtensa_mmu_tlb_ipi(); +#endif + k_spin_unlock(&xtensa_mmu_lock, key); return ret; diff --git a/include/zephyr/arch/xtensa/xtensa_mmu.h b/include/zephyr/arch/xtensa/xtensa_mmu.h index 40fd0ff8f5c114f..aa00f935a8a4f09 100644 --- a/include/zephyr/arch/xtensa/xtensa_mmu.h +++ b/include/zephyr/arch/xtensa/xtensa_mmu.h @@ -60,4 +60,24 @@ extern int xtensa_soc_mmu_ranges_num; void z_xtensa_mmu_init(void); +/** + * @brief Tell other processors to flush TLBs. + * + * This sends IPI to other processors to telling them to + * invalidate cache to page tables and flush TLBs. This is + * needed when one processor is updating page tables that + * may affect threads running on other processors. + * + * @note This needs to be implemented in the SoC layer. + */ +void z_xtensa_mmu_tlb_ipi(void); + +/** + * @brief Invalidate cache to page tables and flush TLBs. + * + * This invalidates cache to all page tables and flush TLBs + * as they may have been modified by other processors. + */ +void z_xtensa_mmu_tlb_shootdown(void); + #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H */ From c9c88a4368f5d23a513d1f6391f9a760c90066b7 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 27 Mar 2023 16:27:34 -0700 Subject: [PATCH 0812/1049] xtensa: mmu: cache and TLB actions when adding thread to domain When adding a thread to a memory domain, we need to also update the mapped page table if it is the current running thread on the same CPU. If it's not on the same CPU, we need to notify the other CPUs in case the thread is running in one of them. Signed-off-by: Daniel Leung Signed-off-by: Anas Nashif Signed-off-by: Flavio Ceolin --- arch/xtensa/core/xtensa_mmu.c | 80 +++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 8a2dcab7ee8bda8..ef0020a76c657d5 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -16,6 +16,12 @@ #include #include +/* Skip TLB IPI when updating page tables. + * This allows us to send IPI only after the last + * changes of a series. + */ +#define OPTION_NO_TLB_IPI BIT(0) + /* Level 1 contains page table entries * necessary to map the page table itself. */ @@ -995,7 +1001,8 @@ static int region_map_update(uint32_t *ptables, uintptr_t start, } static inline int update_region(uint32_t *ptables, uintptr_t start, - size_t size, uint32_t ring, uint32_t flags) + size_t size, uint32_t ring, uint32_t flags, + uint32_t option) { int ret; k_spinlock_key_t key; @@ -1027,7 +1034,9 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, #endif /* CONFIG_XTENSA_MMU_DOUBLE_MAP */ #if CONFIG_MP_MAX_NUM_CPUS > 1 - z_xtensa_mmu_tlb_ipi(); + if ((option & OPTION_NO_TLB_IPI) != OPTION_NO_TLB_IPI) { + z_xtensa_mmu_tlb_ipi(); + } #endif k_spin_unlock(&xtensa_mmu_lock, key); @@ -1035,20 +1044,9 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, return ret; } -static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size) +static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size, uint32_t option) { - return update_region(ptables, start, size, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_W); -} - -void xtensa_set_stack_perms(struct k_thread *thread) -{ - if ((thread->base.user_options & K_USER) == 0) { - return; - } - - update_region(thread_page_tables_get(thread), - thread->stack_info.start, thread->stack_info.size, - Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB); + return update_region(ptables, start, size, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_W, option); } void xtensa_user_stack_perms(struct k_thread *thread) @@ -1058,7 +1056,7 @@ void xtensa_user_stack_perms(struct k_thread *thread) update_region(thread_page_tables_get(thread), thread->stack_info.start, thread->stack_info.size, - Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB); + Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, 0); } int arch_mem_domain_max_partitions_get(void) @@ -1073,7 +1071,7 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain, /* Reset the partition's region back to defaults */ return reset_region(domain->arch.ptables, partition->start, - partition->size); + partition->size, 0); } int arch_mem_domain_partition_add(struct k_mem_domain *domain, @@ -1083,7 +1081,7 @@ int arch_mem_domain_partition_add(struct k_mem_domain *domain, struct k_mem_partition *partition = &domain->partitions[partition_id]; return update_region(domain->arch.ptables, partition->start, - partition->size, ring, partition->attr); + partition->size, ring, partition->attr, 0); } /* These APIs don't need to do anything */ @@ -1101,19 +1099,42 @@ int arch_mem_domain_thread_add(struct k_thread *thread) is_user = (thread->base.user_options & K_USER) != 0; is_migration = (old_ptables != NULL) && is_user; - /* Give access to the thread's stack in its new - * memory domain if it is migrating. - */ - if (is_migration) { - xtensa_set_stack_perms(thread); - } - if (is_migration) { + /* Give access to the thread's stack in its new + * memory domain if it is migrating. + */ + update_region(thread_page_tables_get(thread), + thread->stack_info.start, thread->stack_info.size, + Z_XTENSA_USER_RING, + Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, + OPTION_NO_TLB_IPI); + /* and reset thread's stack permission in + * the old page tables. + */ ret = reset_region(old_ptables, thread->stack_info.start, - thread->stack_info.size); + thread->stack_info.size, 0); + } + + /* Need to switch to new page tables if this is + * the current thread running. + */ + if (thread == _current_cpu->current) { + switch_page_tables(thread->arch.ptables, true, true); } +#if CONFIG_MP_MAX_NUM_CPUS > 1 + /* Need to tell other CPUs to switch to the new page table + * in case the thread is running on one of them. + * + * Note that there is no need to send TLB IPI if this is + * migration as it was sent above during reset_region(). + */ + if ((thread != _current_cpu->current) && !is_migration) { + z_xtensa_mmu_tlb_ipi(); + } +#endif + return ret; } @@ -1136,10 +1157,15 @@ int arch_mem_domain_thread_remove(struct k_thread *thread) /* Restore permissions on the thread's stack area since it is no * longer a member of the domain. + * + * Note that, since every thread must have an associated memory + * domain, removing a thread from domain will be followed by + * adding it back to another. So there is no need to send TLB IPI + * at this point. */ return reset_region(domain->arch.ptables, thread->stack_info.start, - thread->stack_info.size); + thread->stack_info.size, OPTION_NO_TLB_IPI); } static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool write) From 7a5d2a2d8146223f40428578b2a2924a01053367 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 6 Sep 2023 11:26:41 -0700 Subject: [PATCH 0813/1049] xtensa: userspace: swap page tables at context restore Swap page tables at exit of exception handler if we are going to be restored to another thread context. Or else we would be using the outgoing thread's page tables which is not going to work correctly due to mapping and permissions. Signed-off-by: Daniel Leung --- arch/xtensa/include/xtensa-asm2-s.h | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h index 8c08916c8c65216..3f3ffd90b7ae043 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa-asm2-s.h @@ -507,6 +507,8 @@ _do_call_\@: * spills to the right place. */ beq a6, a1, _restore_\@ + +#ifndef CONFIG_USERSPACE l32i a1, a1, 0 l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF @@ -516,7 +518,37 @@ _do_call_\@: */ SPILL_ALL_WINDOWS #endif + + /* Restore A1 stack pointer from "next" handle. */ mov a1, a6 +#else + /* With userspace, we cannot simply restore A1 stack pointer + * at this pointer because we need to swap page tables to + * the incoming thread, and we do not want to call that + * function with thread's stack. So we stash the new stack + * pointer into A2 first, then move it to A1 after we have + * swapped the page table. + */ + mov a2, a6 + + /* Need to switch page tables because the "next" handle + * returned above is not the same handle as we started + * with. This means we are being restored to another + * thread. + */ + rsr a6, ZSR_CPU + l32i a6, a6, ___cpu_t_current_OFFSET + + call4 z_xtensa_swap_update_page_tables + l32i a1, a1, 0 + l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF + + SPILL_ALL_WINDOWS + + /* Moved stashed stack pointer to A1 to restore stack. */ + mov a1, a2 +#endif _restore_\@: j _restore_context From be5eccdd15522e33d4b7bf588bf142b76da8bead Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 19 Jan 2023 10:05:43 -0800 Subject: [PATCH 0814/1049] tests: userspace: Add xtensa support This test requires architecture specific code to work. Signed-off-by: Flavio Ceolin Signed-off-by: Daniel Leung --- tests/kernel/mem_protect/userspace/src/main.c | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/tests/kernel/mem_protect/userspace/src/main.c b/tests/kernel/mem_protect/userspace/src/main.c index 1c0e7d3ef210104..bcf504102db87c8 100644 --- a/tests/kernel/mem_protect/userspace/src/main.c +++ b/tests/kernel/mem_protect/userspace/src/main.c @@ -20,6 +20,11 @@ #include "test_syscall.h" #include /* for z_libc_partition */ +#if defined(CONFIG_XTENSA) +#include +#include +#endif + #if defined(CONFIG_ARC) #include #endif @@ -178,6 +183,12 @@ ZTEST_USER(userspace, test_write_control) set_fault(K_ERR_CPU_EXCEPTION); __asm__ volatile("csrr %0, mstatus" : "=r" (status)); +#elif defined(CONFIG_XTENSA) + unsigned int ps; + + set_fault(K_ERR_CPU_EXCEPTION); + + __asm__ volatile("rsr.ps %0" : "=r" (ps)); #else #error "Not implemented for this architecture" zassert_unreachable("Write to control register did not fault"); @@ -245,6 +256,24 @@ ZTEST_USER(userspace, test_disable_mmu_mpu) */ csr_write(pmpaddr3, LLONG_MAX); csr_write(pmpcfg0, (PMP_R|PMP_W|PMP_X|PMP_NAPOT) << 24); +#elif defined(CONFIG_XTENSA) + set_fault(K_ERR_CPU_EXCEPTION); + + /* Reset way 6 to do identity mapping. + * Complier would complain addr going out of range if we + * simply do addr = i * 0x20000000 inside the loop. So + * we do increment instead. + */ + uint32_t addr = 0U; + + for (int i = 0; i < 8; i++) { + uint32_t attr = addr | Z_XTENSA_MMU_XW; + + __asm__ volatile("wdtlb %0, %1; witlb %0, %1" + :: "r"(attr), "r"(addr)); + + addr += 0x20000000; + } #else #error "Not implemented for this architecture" #endif @@ -381,7 +410,8 @@ ZTEST_USER(userspace, test_read_priv_stack) s[0] = 0; priv_stack_ptr = (char *)&s[0] - size; -#elif defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_RISCV) || defined(CONFIG_ARM64) +#elif defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_RISCV) || \ + defined(CONFIG_ARM64) || defined(CONFIG_XTENSA) /* priv_stack_ptr set by test_main() */ #else #error "Not implemented for this architecture" @@ -405,7 +435,8 @@ ZTEST_USER(userspace, test_write_priv_stack) s[0] = 0; priv_stack_ptr = (char *)&s[0] - size; -#elif defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_RISCV) || defined(CONFIG_ARM64) +#elif defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_RISCV) || \ + defined(CONFIG_ARM64) || defined(CONFIG_XTENSA) /* priv_stack_ptr set by test_main() */ #else #error "Not implemented for this architecture" From 6c6894c8d8afea3817c7679845942c488563a5c4 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 31 Jan 2023 15:35:15 -0800 Subject: [PATCH 0815/1049] tests: mem_protect: enable for Xtensa This enables tests/kernel/mem_protect/mem_protect to be tested on Xtensa. Signed-off-by: Daniel Leung Signed-off-by: Flavio Ceolin --- tests/kernel/mem_protect/mem_protect/src/mem_protect.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/kernel/mem_protect/mem_protect/src/mem_protect.h b/tests/kernel/mem_protect/mem_protect/src/mem_protect.h index ef0ba48a5190483..4d5400bb1d6bbfa 100644 --- a/tests/kernel/mem_protect/mem_protect/src/mem_protect.h +++ b/tests/kernel/mem_protect/mem_protect/src/mem_protect.h @@ -67,6 +67,8 @@ static inline void set_fault_valid(bool valid) #else #define MEM_REGION_ALLOC (4) #endif +#elif defined(CONFIG_XTENSA) +#define MEM_REGION_ALLOC (4096) #else #error "Test suite not compatible for the given architecture" #endif From 156f1d443623aa443851fce73848ef42ba05890e Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 2 Jun 2023 22:36:14 -0700 Subject: [PATCH 0816/1049] xtensa: mmu: Flush cache when altering pages When the target has a cache way size (cache size / cache wasy) bigger than the page size we have cache aliasing, since the number of bits required by the cache index is bigger than the number of bits in the page offset. To avoid this problem we flush the whole cache on context switch or when the current page table is changed. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/xtensa_mmu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index ef0020a76c657d5..74ced4242109b65 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -231,8 +231,7 @@ static inline uint32_t *alloc_l2_table(void) static ALWAYS_INLINE void switch_page_tables(uint32_t *ptables, bool dtlb_inv, bool cache_inv) { if (cache_inv) { - sys_cache_data_invd_range((void *)ptables, XTENSA_L1_PAGE_TABLE_SIZE); - sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + sys_cache_data_flush_and_invd_all(); } /* Invalidate data TLB to L1 page table */ @@ -669,6 +668,7 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) z_xtensa_mmu_tlb_ipi(); #endif + sys_cache_data_flush_and_invd_all(); k_spin_unlock(&xtensa_mmu_lock, key); } @@ -805,6 +805,7 @@ void arch_mem_unmap(void *addr, size_t size) z_xtensa_mmu_tlb_ipi(); #endif + sys_cache_data_flush_and_invd_all(); k_spin_unlock(&xtensa_mmu_lock, key); } @@ -858,7 +859,7 @@ void z_xtensa_mmu_tlb_shootdown(void) * indicated by the current thread are different * than the current mapped page table. */ - switch_page_tables((uint32_t *)thread_ptables, false, false); + switch_page_tables((uint32_t *)thread_ptables, true, true); } } @@ -1039,6 +1040,7 @@ static inline int update_region(uint32_t *ptables, uintptr_t start, } #endif + sys_cache_data_flush_and_invd_all(); k_spin_unlock(&xtensa_mmu_lock, key); return ret; From 9a33c400a164ba77f7b644ad8c6d3b51cb527108 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 29 Aug 2023 10:08:27 -0700 Subject: [PATCH 0817/1049] xtensa: mmu: Fix possible race condition on tlb shootdown We need to use the mmu spin lock when invalidating the cache during tlb shootdown, otherwise it is possible that this happens when another thread is updating the page tables. Signed-off-by: Flavio Ceolin Signed-off-by: Anas Nashif --- arch/xtensa/core/xtensa_mmu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 74ced4242109b65..1c120d5eb31a41f 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -828,11 +828,13 @@ void z_xtensa_mmu_tlb_shootdown(void) */ key = arch_irq_lock(); - /* We don't have information on which page tables have changed, - * so we just invalidate the cache for all L1 page tables. - */ - sys_cache_data_invd_range((void *)l1_page_table, sizeof(l1_page_table)); - sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + K_SPINLOCK(&xtensa_mmu_lock) { + /* We don't have information on which page tables have changed, + * so we just invalidate the cache for all L1 page tables. + */ + sys_cache_data_invd_range((void *)l1_page_table, sizeof(l1_page_table)); + sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + } #ifdef CONFIG_USERSPACE struct k_thread *thread = _current_cpu->current; From d9f643d007b65ee24ad3872427c9dca3180f6629 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 29 Aug 2023 10:49:56 -0700 Subject: [PATCH 0818/1049] xtensa: mmu: do not map heap if not using heap Do not map the heap area by default if we are not using heap at all. Signed-off-by: Daniel Leung --- arch/xtensa/core/xtensa_mmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index 1c120d5eb31a41f..eba89c970ad81c6 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -133,6 +133,7 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { #endif .name = "data", }, +#if CONFIG_HEAP_MEM_POOL_SIZE > 0 /* System heap memory */ { .start = (uint32_t)_heap_start, @@ -144,6 +145,7 @@ static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { #endif .name = "heap", }, +#endif /* Mark text segment cacheable, read only and executable */ { .start = (uint32_t)__text_region_start, From 6252fcfccfae49fa18beee1b1bec0f57b4e37a0a Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 29 Aug 2023 12:07:19 -0700 Subject: [PATCH 0819/1049] xtensa: userspace: simplify syscall helper Consolidate all syscall helpers into one functions. Signed-off-by: Daniel Leung --- arch/xtensa/core/syscall_helper.c | 103 ++------------------------- include/zephyr/arch/xtensa/syscall.h | 62 ++++++---------- 2 files changed, 27 insertions(+), 138 deletions(-) diff --git a/arch/xtensa/core/syscall_helper.c b/arch/xtensa/core/syscall_helper.c index fbbdf1041910d5d..f8fb7ec903ec3e1 100644 --- a/arch/xtensa/core/syscall_helper.c +++ b/arch/xtensa/core/syscall_helper.c @@ -6,10 +6,10 @@ #include -uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, uintptr_t arg6, - uintptr_t call_id) +uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) { register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -27,98 +27,3 @@ uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, return a2; } - -uintptr_t arch_syscall_invoke5_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - register uintptr_t a3 __asm__("%a3") = arg2; - register uintptr_t a4 __asm__("%a4") = arg3; - register uintptr_t a5 __asm__("%a5") = arg4; - register uintptr_t a8 __asm__("%a8") = arg5; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6), "r" (a3), "r" (a4), - "r" (a5), "r" (a8) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke4_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - register uintptr_t a3 __asm__("%a3") = arg2; - register uintptr_t a4 __asm__("%a4") = arg3; - register uintptr_t a5 __asm__("%a5") = arg4; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6), "r" (a3), "r" (a4), - "r" (a5) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke3_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - register uintptr_t a3 __asm__("%a3") = arg2; - register uintptr_t a4 __asm__("%a4") = arg3; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6), "r" (a3), "r" (a4) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke2_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - register uintptr_t a3 __asm__("%a3") = arg2; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6), "r" (a3) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke1_helper(uintptr_t arg1, uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - register uintptr_t a6 __asm__("%a6") = arg1; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2), "r" (a6) - : "memory"); - - return a2; -} - -uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id) -{ - register uintptr_t a2 __asm__("%a2") = call_id; - - __asm__ volatile("syscall\n\t" - : "=r" (a2) - : "r" (a2) - : "memory"); - - return a2; -} diff --git a/include/zephyr/arch/xtensa/syscall.h b/include/zephyr/arch/xtensa/syscall.h index 3d78827b77c7ccc..70a075db4543280 100644 --- a/include/zephyr/arch/xtensa/syscall.h +++ b/include/zephyr/arch/xtensa/syscall.h @@ -29,29 +29,14 @@ extern "C" { #endif #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER -uintptr_t arch_syscall_invoke6_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, uintptr_t arg6, - uintptr_t call_id); +uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id); -uintptr_t arch_syscall_invoke5_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, - uintptr_t call_id); - -uintptr_t arch_syscall_invoke4_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t call_id); - -uintptr_t arch_syscall_invoke3_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t call_id); - -uintptr_t arch_syscall_invoke2_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t call_id); - -uintptr_t arch_syscall_invoke1_helper(uintptr_t arg1, uintptr_t call_id); - -uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id); +#define SYSINL ALWAYS_INLINE +#else +#define SYSINL inline #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ /** @@ -63,15 +48,13 @@ uintptr_t arch_syscall_invoke0_helper(uintptr_t call_id); * **/ -static inline uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke6_helper(arg1, arg2, arg3, - arg4, arg5, arg6, - call_id); + return xtensa_syscall_helper(arg1, arg2, arg3, arg4, arg5, arg6, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -91,13 +74,12 @@ static inline uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static inline uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke5_helper(arg1, arg2, arg3, - arg4, arg5, call_id); + return xtensa_syscall_helper(arg1, arg2, arg3, arg4, arg5, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -116,12 +98,12 @@ static inline uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static inline uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke4_helper(arg1, arg2, arg3, arg4, call_id); + return xtensa_syscall_helper(arg1, arg2, arg3, arg4, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -139,11 +121,11 @@ static inline uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke3_helper(arg1, arg2, arg3, call_id); + return xtensa_syscall_helper(arg1, arg2, arg3, 0, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -159,11 +141,11 @@ static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, +static SYSINL uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke2_helper(arg1, arg2, call_id); + return xtensa_syscall_helper(arg1, arg2, 0, 0, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -178,11 +160,11 @@ static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, #endif } -static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1, +static SYSINL uintptr_t arch_syscall_invoke1(uintptr_t arg1, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke1_helper(arg1, call_id); + return xtensa_syscall_helper(arg1, 0, 0, 0, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -196,10 +178,10 @@ static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1, #endif } -static inline uintptr_t arch_syscall_invoke0(uintptr_t call_id) +static SYSINL uintptr_t arch_syscall_invoke0(uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return arch_syscall_invoke0_helper(call_id); + return xtensa_syscall_helper(0, 0, 0, 0, 0, 0, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; @@ -229,6 +211,8 @@ static inline bool arch_is_user_context(void) return !!thread; } +#undef SYSINL + #ifdef __cplusplus } #endif From 0e7def1977aab1d4578fa9ebe93648c58b15280f Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 11 Sep 2023 16:25:22 -0700 Subject: [PATCH 0820/1049] xtensa: selectively init interrupt stack at boot During arch_kernel_init(), the interrupt stack is being initialized. However, if the current in-use stack is the interrupt stack, it would wipe all the data up to that point in stack, and might result in crash. So skip initializing the interrupt stack if the current stack pointer is within the boundary of interrupt stack. Signed-off-by: Daniel Leung --- arch/xtensa/include/kernel_arch_func.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/include/kernel_arch_func.h b/arch/xtensa/include/kernel_arch_func.h index 8ce5cc52a5b51a2..080b81d72bf9525 100644 --- a/arch/xtensa/include/kernel_arch_func.h +++ b/arch/xtensa/include/kernel_arch_func.h @@ -53,8 +53,22 @@ static ALWAYS_INLINE void arch_kernel_init(void) XTENSA_WSR(ZSR_CPU_STR, cpu0); #ifdef CONFIG_INIT_STACKS - memset(Z_KERNEL_STACK_BUFFER(z_interrupt_stacks[0]), 0xAA, - K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0])); + char *stack_start = Z_KERNEL_STACK_BUFFER(z_interrupt_stacks[0]); + size_t stack_sz = K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0]); + char *stack_end = stack_start + stack_sz; + + uint32_t sp; + + __asm__ volatile("mov %0, sp" : "=a"(sp)); + + /* Only clear the interrupt stack if the current stack pointer + * is not within the interrupt stack. Or else we would be + * wiping the in-use stack. + */ + if (((uintptr_t)sp < (uintptr_t)stack_start) || + ((uintptr_t)sp >= (uintptr_t)stack_end)) { + memset(stack_start, 0xAA, stack_sz); + } #endif #ifdef CONFIG_XTENSA_MMU From 0d794815403224d6942e72a576e6c8694f524e01 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 30 Aug 2023 15:36:21 -0700 Subject: [PATCH 0821/1049] xtensa: userspace: only write 0xAA to stack if INIT_STACKS Only clear the user stack to 0xAA if CONFIG_INIT_STACKS is enabled. Otherwise, write 0x00 as if the stack is in BSS. Signed-off-by: Daniel Leung --- arch/xtensa/core/xtensa_mmu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c index eba89c970ad81c6..2130a870e7757d9 100644 --- a/arch/xtensa/core/xtensa_mmu.c +++ b/arch/xtensa/core/xtensa_mmu.c @@ -1057,8 +1057,9 @@ static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size, void xtensa_user_stack_perms(struct k_thread *thread) { - (void)memset((void *)thread->stack_info.start, 0xAA, - thread->stack_info.size - thread->stack_info.delta); + (void)memset((void *)thread->stack_info.start, + (IS_ENABLED(CONFIG_INIT_STACKS)) ? 0xAA : 0x00, + thread->stack_info.size - thread->stack_info.delta); update_region(thread_page_tables_get(thread), thread->stack_info.start, thread->stack_info.size, From a36e39c2a65f3705832875053f8a4e13320dcd4c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 28 Aug 2023 17:01:16 -0700 Subject: [PATCH 0822/1049] xtensa: dc233c: enable userspace support This massages kconfig and linker script to enable userspace support on dc233c core. Signed-off-by: Daniel Leung --- soc/xtensa/dc233c/Kconfig.soc | 1 + soc/xtensa/dc233c/include/xtensa-dc233c.ld | 94 +++++++++++++--------- soc/xtensa/dc233c/mmu.c | 7 +- 3 files changed, 61 insertions(+), 41 deletions(-) diff --git a/soc/xtensa/dc233c/Kconfig.soc b/soc/xtensa/dc233c/Kconfig.soc index 89b814da4d2bd95..617eaa13849b165 100644 --- a/soc/xtensa/dc233c/Kconfig.soc +++ b/soc/xtensa/dc233c/Kconfig.soc @@ -9,3 +9,4 @@ config SOC_XTENSA_DC233C select ARCH_HAS_THREAD_LOCAL_STORAGE select CPU_HAS_MMU select ARCH_HAS_RESERVED_PAGE_FRAMES if XTENSA_MMU + select ARCH_HAS_USERSPACE if XTENSA_MMU diff --git a/soc/xtensa/dc233c/include/xtensa-dc233c.ld b/soc/xtensa/dc233c/include/xtensa-dc233c.ld index b165016fa6a1da9..2153c4a420cef86 100644 --- a/soc/xtensa/dc233c/include/xtensa-dc233c.ld +++ b/soc/xtensa/dc233c/include/xtensa-dc233c.ld @@ -20,7 +20,7 @@ #include #define RAMABLE_REGION RAM :sram0_phdr -#define ROMABLE_REGION rom0_seg :rom0_phdr +#define ROMABLE_REGION RAM :sram0_phdr #ifdef CONFIG_MMU #define MMU_PAGE_ALIGN . = ALIGN(CONFIG_MMU_PAGE_SIZE); @@ -287,6 +287,9 @@ SECTIONS _DoubleExceptionVector_text_end = ABSOLUTE(.); } >sram0_18_seg :sram0_18_phdr +#define LIB_OBJ_FUNC_IN_SECT(library, obj_file, func) \ + *##library##:##obj_file##(.literal.##func .text.##func) \ + #ifdef CONFIG_XTENSA_MMU .vec_helpers : { @@ -301,48 +304,45 @@ SECTIONS * TLB multi-hit exception. */ - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.literal) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.text) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.iram.text) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.iram0.text) + *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.literal .text) + *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.iram.text .iram0.text) *libarch__xtensa__core.a:window_vectors.S.obj(.iram.text) - *libarch__xtensa__core.a:xtensa-asm2.c.obj(.literal.*) - *libarch__xtensa__core.a:xtensa-asm2.c.obj(.text.*) - - *libarch__xtensa__core.a:fatal.c.obj(.literal.*) - *libarch__xtensa__core.a:fatal.c.obj(.text.*) - - *libarch__xtensa__core.a:crt1.S.obj(.literal) - *libarch__xtensa__core.a:crt1.S.obj(.text) + *libarch__xtensa__core.a:crt1.S.obj(.literal .text) - *libarch__xtensa__core.a:cpu_idle.c.obj(.literal.*) - *libarch__xtensa__core.a:cpu_idle.c.obj(.text.*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa-asm2.c.obj,*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,fatal.c.obj,*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,cpu_idle.c.obj,*) *(.text.arch_is_in_isr) /* To support backtracing */ - *libarch__xtensa__core.a:xtensa_backtrace.c.obj(.literal.*) - *libarch__xtensa__core.a:xtensa_backtrace.c.obj(.text.*) - *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal) - *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_backtrace.c.obj,*) - *libkernel.a:fatal.c.obj(.literal.*) - *libkernel.a:fatal.c.obj(.text.*) + *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal .iram1) + + /* Userspace related stuff */ + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,z_xtensa_do_syscall) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_mmu.c.obj,z_xtensa_swap_update_page_tables) /* Below are to speed up execution by avoiding TLB misses * on frequently used functions. + * + * There is almost 1MB space (due to TLB pinning) so we can + * be generous. */ - *libkernel.a:sched.c.obj(.literal.*) - *libkernel.a:sched.c.obj(.text.*) - *libkernel.a:timeout.c.obj(.literal.*) - *libkernel.a:timeout.c.obj(.text.*) - - *libdrivers__console.a:(.literal.*) - *libdrivers__console.a:(.text.*) - *libdrivers__timer.a:(.literal.*) - *libdrivers__timer.a:(.text.*) + LIB_OBJ_FUNC_IN_SECT(libkernel.a,,*) + + LIB_OBJ_FUNC_IN_SECT(libdrivers__console.a,,*) + LIB_OBJ_FUNC_IN_SECT(libdrivers__timer.a,,*) + + *(.literal.z_vrfy_* .text.z_vrfy_*) + *(.literal.z_mrsh_* .text.z_mrsh_*) + *(.literal.z_impl_* .text.z_impl_*) + *(.literal.z_obj_* .text.z_obj_*) + + *(.literal.k_sys_fatal_error_handler .text.k_sys_fatal_error_handler) } >vec_helpers :vec_helpers_phdr #endif /* CONFIG_XTENSA_MMU */ @@ -380,7 +380,7 @@ SECTIONS _text_end = ABSOLUTE(.); _etext = .; - } >RAM :sram0_phdr + } >RAMABLE_REGION __text_region_end = .; .rodata : HDR_MMU_PAGE_ALIGN @@ -394,7 +394,16 @@ SECTIONS . = ALIGN(4); #include #include + } >RAMABLE_REGION + +#include + +#include +#include + + .rodata_end : ALIGN(4) + { . = ALIGN(4); /* this table MUST be 4-byte aligned */ _bss_table_start = ABSOLUTE(.); LONG(_bss_start) @@ -404,19 +413,26 @@ SECTIONS MMU_PAGE_ALIGN __rodata_region_end = ABSOLUTE(.); - } >RAM :sram0_phdr + } >RAMABLE_REGION -#include +#ifdef CONFIG_USERSPACE +#define SMEM_PARTITION_ALIGN(size) MMU_PAGE_ALIGN +#define APP_SHARED_ALIGN MMU_PAGE_ALIGN -#include +#include -#include - -#include + _image_ram_start = _app_smem_start; + _app_smem_size = _app_smem_end - _app_smem_start; + _app_smem_num_words = _app_smem_size >> 2; + _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); + _app_smem_num_words = _app_smem_size >> 2; +#endif /* CONFIG_USERSPACE */ .data : HDR_MMU_PAGE_ALIGN { +#ifndef CONFIG_USERSPACE _image_ram_start = ABSOLUTE(.); +#endif __data_start = ABSOLUTE(.); *(.data) *(.data.*) @@ -438,7 +454,9 @@ SECTIONS MMU_PAGE_ALIGN __data_end = ABSOLUTE(.); - } >RAM :sram0_phdr + } >RAMABLE_REGION + +#include #include diff --git a/soc/xtensa/dc233c/mmu.c b/soc/xtensa/dc233c/mmu.c index 4b8d6b154b84c68..718f79779ebd5ce 100644 --- a/soc/xtensa/dc233c/mmu.c +++ b/soc/xtensa/dc233c/mmu.c @@ -18,7 +18,7 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { { .start = (uint32_t)XCHAL_VECBASE_RESET_VADDR, .end = (uint32_t)CONFIG_SRAM_OFFSET, - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB, + .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB | Z_XTENSA_MMU_MAP_SHARED, .name = "vecbase", }, { @@ -52,7 +52,8 @@ void arch_xtensa_mmu_post_init(bool is_core0) /* Map VECBASE permanently in instr TLB way 4 so we will always have * access to exception handlers. Each way 4 TLB covers 1MB (unless * ITLBCFG has been changed before this, which should not have - * happened). + * happened). Also this needs to be mapped as SHARED so both kernel + * and userspace can execute code here => same as .text. * * Note that we don't want to map the first 1MB in data TLB as * we want to keep page 0 (0x00000000) unmapped to catch null pointer @@ -60,7 +61,7 @@ void arch_xtensa_mmu_post_init(bool is_core0) */ vecbase = ROUND_DOWN(vecbase, MB(1)); xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, + Z_XTENSA_PTE(vecbase, Z_XTENSA_SHARED_RING, Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, 4)); } From 1247f8465c22b00e7a5ab0cf1179d54ba883052c Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 7 Sep 2023 19:48:35 +0000 Subject: [PATCH 0823/1049] xtensa: userspace: Supports tls on userspace Use thread local storage to check whether or not a thread is running in user mode. This allows to use threadptr to properly support tls. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/userspace.S | 31 +++++++++++++++++++++++++--- arch/xtensa/core/xtensa-asm2.c | 8 +++++++ include/zephyr/arch/xtensa/syscall.h | 9 ++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/arch/xtensa/core/userspace.S b/arch/xtensa/core/userspace.S index b649014fd52becf..1a000d75d570717 100644 --- a/arch/xtensa/core/userspace.S +++ b/arch/xtensa/core/userspace.S @@ -100,8 +100,17 @@ _id_ok: * we are in a interruption we don't want the system * thinking it is possibly running in user mode. */ +#ifdef CONFIG_THREAD_LOCAL_STORAGE + movi a0, is_user_mode@tpoff + rur.THREADPTR a3 + add a0, a3, a0 + + movi a3, 0 + s32i a3, a0, 0 +#else movi a0, 0 wur.THREADPTR a0 +#endif /* Set syscall parameters. We have an initial call4 to set up the * the stack and then a new call4 for the syscall function itself. @@ -157,9 +166,17 @@ _syscall_returned: wsr a3, SCOMPARE1 #endif +#ifdef CONFIG_THREAD_LOCAL_STORAGE + l32i a3, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET + movi a0, is_user_mode@tpoff + add a0, a3, a0 + movi a3, 1 + s32i a3, a0, 0 +#else rsr a3, ZSR_CPU l32i a3, a3, ___cpu_t_current_OFFSET wur.THREADPTR a3 +#endif l32i a3, a1, ___xtensa_irq_bsa_t_ps_OFFSET wsr.ps a3 @@ -225,9 +242,17 @@ z_xtensa_userspace_enter: l32i a6, a1, 24 call4 z_xtensa_swap_update_page_tables - /* Set threadptr with the thread address, we are going to user mode. */ - l32i a0, a1, 24 - wur.THREADPTR a0 +#ifdef CONFIG_THREAD_LOCAL_STORAGE + rur.threadptr a3 + movi a0, is_user_mode@tpoff + add a0, a3, a0 + movi a3, 1 + s32i a3, a0, 0 +#else + rsr a3, ZSR_CPU + l32i a3, a3, ___cpu_t_current_OFFSET + wur.THREADPTR a3 +#endif /* Set now z_thread_entry parameters, we are simulating a call4 * call, so parameters start at a6, a7, ... diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index ed8f340f1bcb454..88783c178c64267 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -28,6 +28,14 @@ Z_EXC_DECLARE(z_xtensa_user_string_nlen); static const struct z_exc_handle exceptions[] = { Z_EXC_HANDLE(z_xtensa_user_string_nlen) }; + +#ifdef CONFIG_THREAD_LOCAL_STORAGE +/* + * Per-thread (TLS) variable indicating whether execution is in user mode. + */ +__thread uint32_t is_user_mode; +#endif + #endif /* CONFIG_USERSPACE */ void *xtensa_init_stack(struct k_thread *thread, int *stack_top, diff --git a/include/zephyr/arch/xtensa/syscall.h b/include/zephyr/arch/xtensa/syscall.h index 70a075db4543280..b8b0bea8cdbce9f 100644 --- a/include/zephyr/arch/xtensa/syscall.h +++ b/include/zephyr/arch/xtensa/syscall.h @@ -207,8 +207,17 @@ static inline bool arch_is_user_context(void) "rur.THREADPTR %0\n\t" : "=a" (thread) ); +#ifdef CONFIG_THREAD_LOCAL_STORAGE + extern __thread uint32_t is_user_mode; + if (!thread) { + return false; + } + + return is_user_mode != 0; +#else return !!thread; +#endif } #undef SYSINL From 8679c58644716b11310682a25c9605dac46f536d Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 18 Sep 2023 12:44:03 -0700 Subject: [PATCH 0824/1049] kernel: Option to not use tls to get current thread Add a Kconfig option to tell whether or not using thread local storage to store current thread. The function using it can be called from ISR and using TLS variables in this context may (should ???) not be allowed Signed-off-by: Flavio Ceolin --- include/zephyr/kernel.h | 3 ++- kernel/Kconfig | 14 ++++++++++++++ lib/os/thread_entry.c | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index fac7df01904fb66..d2b912f6d46e13f 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -596,7 +596,8 @@ __syscall k_tid_t k_sched_current_thread_query(void); __attribute_const__ static inline k_tid_t k_current_get(void) { -#ifdef CONFIG_THREAD_LOCAL_STORAGE +#ifdef CONFIG_CURRENT_THREAD_USE_TLS + /* Thread-local cache of current thread ID, set in z_thread_entry() */ extern __thread k_tid_t z_tls_current; diff --git a/kernel/Kconfig b/kernel/Kconfig index 6280e80a400b4be..4a72d76da67054f 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -288,6 +288,20 @@ config ERRNO_IN_TLS Use thread local storage to store errno instead of storing it in the kernel thread struct. This avoids a syscall if userspace is enabled. +config CURRENT_THREAD_USE_NO_TLS + bool + help + Hidden symbol to not use thread local storage to store current + thread. + +config CURRENT_THREAD_USE_TLS + bool "Store current thread in thread local storage (TLS)" + depends on THREAD_LOCAL_STORAGE && !CURRENT_THREAD_USE_NO_TLS + default y + help + Use thread local storage to store the current thread. This avoids a + syscall if userspace is enabled. + choice SCHED_ALGORITHM prompt "Scheduler priority queue algorithm" default SCHED_DUMB diff --git a/lib/os/thread_entry.c b/lib/os/thread_entry.c index 89eb2fe7b4b32f5..ed6ca142d99f7cd 100644 --- a/lib/os/thread_entry.c +++ b/lib/os/thread_entry.c @@ -12,7 +12,7 @@ */ #include -#ifdef CONFIG_THREAD_LOCAL_STORAGE +#ifdef CONFIG_CURRENT_THREAD_USE_TLS #include __thread k_tid_t z_tls_current; @@ -35,7 +35,7 @@ extern __thread volatile uintptr_t __stack_chk_guard; FUNC_NORETURN void z_thread_entry(k_thread_entry_t entry, void *p1, void *p2, void *p3) { -#ifdef CONFIG_THREAD_LOCAL_STORAGE +#ifdef CONFIG_CURRENT_THREAD_USE_TLS z_tls_current = k_sched_current_thread_query(); #endif #ifdef CONFIG_STACK_CANARIES_TLS From dd36389879abda87e8999a12105702c4f223761b Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 29 Sep 2023 21:33:45 -0700 Subject: [PATCH 0825/1049] arch: xtensa: Not use TLS to store current thread Xtensa clears out threadptr durint ISR when userspace is enabled. Signed-off-by: Flavio Ceolin --- arch/xtensa/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index c875aa3097230bb..fefc77e25211739 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -116,6 +116,7 @@ config XTENSA_MMU select ARCH_MEM_DOMAIN_SYNCHRONOUS_API if USERSPACE select XTENSA_SMALL_VECTOR_TABLE_ENTRY select KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK if XTENSA_RPO_CACHE + select CURRENT_THREAD_USE_NO_TLS if USERSPACE help Enable support for Xtensa Memory Management Unit. From b7d96ab42ab31050c28c1de6f65b9b673cfa74e8 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 17 Oct 2023 15:50:31 -0700 Subject: [PATCH 0826/1049] xtensa: userspace: Warning about impl security Add a Kconfig option (and build warning) alerting about the problem of the kernel spilling register in behave of the userspace. Signed-off-by: Flavio Ceolin --- arch/xtensa/CMakeLists.txt | 6 ++++++ arch/xtensa/Kconfig | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/arch/xtensa/CMakeLists.txt b/arch/xtensa/CMakeLists.txt index 4626421f11a4ae6..21de223d4ec2015 100644 --- a/arch/xtensa/CMakeLists.txt +++ b/arch/xtensa/CMakeLists.txt @@ -3,3 +3,9 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/arch/xtensa/arch.h) set_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf32-xtensa-le) add_subdirectory(core) + +if (CONFIG_XTENSA_INSECURE_USERSPACE) + message(WARNING " + This userspace implementation uses the window ABI this means that the kernel + will spill registers in behave of the userpsace. Use it carefully.") +endif() diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index fefc77e25211739..326c7749e6b20f2 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -180,6 +180,11 @@ config XTENSA_SYSCALL_USE_HELPER This is a workaround for toolchains where they have issue modeling register usage. +config XTENSA_INSECURE_USERSPACE + bool + default y if USERSPACE + depends on XTENSA_MMU + endif # CPU_HAS_MMU endmenu From e7e8f6655c27ae6b77fdab25f168b59092e9295a Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Sun, 27 Aug 2023 12:32:57 -0700 Subject: [PATCH 0827/1049] arch/xtensa: #include cleanup This file doesn't need the asm2 header, and the preprocessor logic around whether to include the backtrace header is needless (all it does is declare functions). Signed-off-by: Andy Ross --- arch/xtensa/core/fatal.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index 79a24baa1056243..6e939e243cd3f64 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -8,12 +8,7 @@ #include #include #include -#include -#if defined(CONFIG_XTENSA_ENABLE_BACKTRACE) -#if XCHAL_HAVE_WINDOWED #include -#endif -#endif #include #include #include From 8dd84bc1816ae749e45ebd8de687504017d036b9 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 1 Nov 2023 16:07:02 -0700 Subject: [PATCH 0828/1049] arch: xtensa: Rename xtensa_mmu.c to ptables.c Initial work to split page table manipulation from mmu hardware interaction. Signed-off-by: Flavio Ceolin --- arch/xtensa/core/CMakeLists.txt | 2 +- arch/xtensa/core/{xtensa_mmu.c => ptables.c} | 0 soc/xtensa/dc233c/include/xtensa-dc233c.ld | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/xtensa/core/{xtensa_mmu.c => ptables.c} (100%) diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 331bcd9bfc52d38..1e4b045085ec5b4 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -21,7 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_XTENSA_ENABLE_BACKTRACE debug_helpers_asm.S) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_TIMING_FUNCTIONS timing.c) zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) -zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU xtensa_mmu.c) +zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c) diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/ptables.c similarity index 100% rename from arch/xtensa/core/xtensa_mmu.c rename to arch/xtensa/core/ptables.c diff --git a/soc/xtensa/dc233c/include/xtensa-dc233c.ld b/soc/xtensa/dc233c/include/xtensa-dc233c.ld index 2153c4a420cef86..9c120e1b9d86225 100644 --- a/soc/xtensa/dc233c/include/xtensa-dc233c.ld +++ b/soc/xtensa/dc233c/include/xtensa-dc233c.ld @@ -324,7 +324,7 @@ SECTIONS /* Userspace related stuff */ LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,z_xtensa_do_syscall) - LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_mmu.c.obj,z_xtensa_swap_update_page_tables) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,ptables.c.obj,z_xtensa_swap_update_page_tables) /* Below are to speed up execution by avoiding TLB misses * on frequently used functions. From c47880af0d98cdeef05e2aa331f35ee41d0de44f Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Sun, 19 Nov 2023 15:44:56 -0800 Subject: [PATCH 0829/1049] arch/xtensa: Add new MMU layer Andy Ross re-implementation of MMU layer with some subtle changes, like re-using existent macros, fix page table cache property when direct mapping it in TLB. From Andy's original commit message: This is a reworked MMU layer, sitting cleanly below the page table handling in the OS. Notable differences from the original work: + Significantly smaller code and simpler API (just three functions to be called from the OS/userspace/ptable layer). + Big README-MMU document containing my learnings over the process, so hopefully fewer people need to go through this in the future. + No TLB flushing needed. Clean separation of ASIDs, just requires that the upper levels match the ASID to the L1 page table page consistently. + Vector mapping is done with a 4k page and not a 4M page, leading to much more flexibility with hardware memory layout. The original scheme required that the 4M region containing vecbase be mapped virtually to a location other than the hardware address, which makes confusing linkage with call0 and difficult initialization constraints where the exception vectors run at different addresses before and after MMU setup (effectively forcing them to be PIC code). + More provably correct initialization, all MMU changes happen in a single asm block with no memory accesses which would generate a refill. Signed-off-by: Andy Ross Signed-off-by: Flavio Ceolin --- arch/xtensa/core/CMakeLists.txt | 2 +- arch/xtensa/core/README-MMU.txt | 268 +++++++++++++++++++++ arch/xtensa/core/include/xtensa_mmu_priv.h | 15 +- arch/xtensa/core/mmu.c | 178 ++++++++++++++ arch/xtensa/core/ptables.c | 213 ++-------------- arch/xtensa/include/xtensa-asm2-s.h | 25 -- soc/xtensa/dc233c/mmu.c | 30 --- 7 files changed, 479 insertions(+), 252 deletions(-) create mode 100644 arch/xtensa/core/README-MMU.txt create mode 100644 arch/xtensa/core/mmu.c diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 1e4b045085ec5b4..f3122c1a5504da3 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -21,7 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_XTENSA_ENABLE_BACKTRACE debug_helpers_asm.S) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_TIMING_FUNCTIONS timing.c) zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) -zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c) +zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c mmu.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c) diff --git a/arch/xtensa/core/README-MMU.txt b/arch/xtensa/core/README-MMU.txt new file mode 100644 index 000000000000000..499a251cdf2f2f4 --- /dev/null +++ b/arch/xtensa/core/README-MMU.txt @@ -0,0 +1,268 @@ +# Xtensa MMU Operation + +As with other elements of the architecture, paged virtual memory +management on Xtensa is somewhat unique. And there is similarly a +lack of introductory material available. This document is an attempt +to introduce the architecture at an overview/tutorial level, and to +describe Zephyr's specific implementation choices. + +## General TLB Operation + +The Xtensa MMU operates on top of a fairly conventional TLB cache. +The TLB stores virtual to physical translation for individual pages of +memory. It is partitioned into an automatically managed +4-way-set-associative bank of entries mapping 4k pages, and 3-6 +"special" ways storing mappings under OS control. Some of these are +for mapping pages larger than 4k, which Zephyr does not directly +support. A few are for bootstrap and initialization, and will be +discussed below. + +Like the L1 cache, the TLB is split into separate instruction and data +entries. Zephyr manages both as needed, but symmetrically. The +architecture technically supports separately-virtualized instruction +and data spaces, but the hardware page table refill mechanism (see +below) does not, and Zephyr's memory spaces are unified regardless. + +The TLB may be loaded with permissions and attributes controlling +cacheability, access control based on ring (i.e. the contents of the +RING field of the PS register) and togglable write and execute access. +Memory access, even with a matching TLB entry, may therefore create +Kernel/User exceptions as desired to enforce permissions choices on +userspace code. + +Live TLB entries are tagged with an 8-bit "ASID" value derived from +their ring field of the PTE that loaded them, via a simple translation +specified in the RASID special register. The intent is that each +non-kernel address space will get a separate ring 3 ASID set in RASID, +such that you can switch between them without a TLB flush. The ASID +value of ring zero is fixed at 1, it may not be changed. (An ASID +value of zero is used to tag an invalid/unmapped TLB entry at +initialization, but this mechanism isn't accessible to OS code except +in special circumstances, and in any case there is already an invalid +attribute value that can be used in a PTE). + +## Virtually-mapped Page Tables + +Xtensa has a unique (and, to someone exposed for the first time, +extremely confusing) "page table" format. The simplest was to begin +to explain this is just to describe the (quite simple) hardware +behavior: + +On a TLB miss, the hardware immediately does a single fetch (at ring 0 +privilege) from RAM by adding the "desired address right shifted by +10 bits with the bottom two bits set to zero" (i.e. the page frame +number in units of 4 bytes) to the value in the PTEVADDR special +register. If this load succeeds, then the word is treated as a PTE +with which to fill the TLB and use for a (restarted) memory access. +This is extremely simple (just one extra hardware state that does just +one thing the hardware can already do), and quite fast (only one +memory fetch vs. e.g. the 2-5 fetches required to walk a page table on +x86). + +This special "refill" fetch is otherwise identical to any other memory +access, meaning it too uses the TLB to translate from a virtual to +physical address. Which means that the page tables occupy a 4M region +of virtual, not physical, address space, in the same memory space +occupied by the running code. The 1024 pages in that range (not all +of which might be mapped in physical memory) are a linear array of +1048576 4-byte PTE entries, each describing a mapping for 4k of +virtual memory. Note especially that exactly one of those pages +contains the 1024 PTE entries for the 4M page table itself, pointed to +by PTEVADDR. + +Obviously, the page table memory being virtual means that the fetch +can fail: there are 1024 possible pages in a complete page table +covering all of memory, and the ~16 entry TLB clearly won't contain +entries mapping all of them. If we are missing a TLB entry for the +page translation we want (NOT for the original requested address, we +already know we're missing that TLB entry), the hardware has exactly +one more special trick: it throws a TLB Miss exception (there are two, +one each for instruction/data TLBs, but in Zephyr they operate +identically). + +The job of that exception handler is simply to ensure that the TLB has +an entry for the page table page we want. And the simplest way to do +that is to just load the faulting PTE as an address, which will then +go through the same refill process above. This second TLB fetch in +the exception handler may result in an invalid/inapplicable mapping +within the 4M page table region. This is an typical/expected runtime +fault, and simply indicates unmapped memory. The result is TLB miss +exception from within the TLB miss exception handler (i.e. while the +EXCM bit is set). This will produce a Double Exception fault, which +is handled by the OS identically to a general Kernel/User data access +prohibited exception. + +After the TLB refill exception, the original faulting instruction is +restarted, which retries the refill process, which succeeds in +fetching a new TLB entry, which is then used to service the original +memory access. (And may then result in yet another exception if it +turns out that the TLB entry doesn't permit the access requested, of +course.) + +## Special Cases + +The page-tables-specified-in-virtual-memory trick works very well in +practice. But it does have a chicken/egg problem with the initial +state. Because everything depends on state in the TLB, something +needs to tell the hardware how to find a physical address using the +TLB to begin the process. Here we exploit the separate +non-automatically-refilled TLB ways to store bootstrap records. + +First, note that the refill process to load a PTE requires that the 4M +space of PTE entries be resolvable by the TLB directly, without +requiring another refill. This 4M mapping is provided by a single +page of PTE entries (which itself lives in the 4M page table region!). +This page must always be in the TLB. + +Thankfully, for the data TLB Xtensa provides 3 special/non-refillable +ways (ways 7-9) with at least one 4k page mapping each. We can use +one of these to "pin" the top-level page table entry in place, +ensuring that a refill access will be able to find a PTE address. + +But now note that the load from that PTE address for the refill is +done in an exception handler. And running an exception handler +requires doing a fetch via the instruction TLB. And that obviously +means that the page(s) containing the exception handler must never +require a refill exception of its own. + +Ideally we would just pin the vector/handler page in the ITLB in the +same way we do for data, but somewhat inexplicably, Xtensa does not +provide 4k "pinnable" ways in the instruction TLB (frankly this seems +like a design flaw). + +Instead, we load ITLB entries for vector handlers via the refill +mechanism using the data TLB, and so need the refill mechanism for the +vector page to succeed always. The way to do this is to similarly pin +the page table page containing the (single) PTE for the vector page in +the data TLB, such that instruction fetches always find their TLB +mapping via refill, without requiring an exception. + +## Initialization + +Unlike most other architectures, Xtensa does not have a "disable" mode +for the MMU. Virtual address translation through the TLB is active at +all times. There therefore needs to be a mechanism for the CPU to +execute code before the OS is able to initialize a refillable page +table. + +The way Xtensa resolves this (on the hardware Zephyr supports, see the +note below) is to have an 8-entry set ("way 6") of 512M pages able to +cover all of memory. These 8 entries are initialized as valid, with +attributes specifying that they are accessible only to an ASID of 1 +(i.e. the fixed ring zero / kernel ASID), writable, executable, and +uncached. So at boot the CPU relies on these TLB entries to provide a +clean view of hardware memory. + +But that means that enabling page-level translation requires some +care, as the CPU will throw an exception ("multi hit") if a memory +access matches more than one live entry in the TLB. The +initialization algorithm is therefore: + +0. Start with a fully-initialized page table layout, including the + top-level "L1" page containing the mappings for the page table + itself. + +1. Ensure that the initialization routine does not cross a page + boundary (to prevent stray TLB refill exceptions), that it occupies + a separate 4k page than the exception vectors (which we must + temporarily double-map), and that it operates entirely in registers + (to avoid doing memory access at inopportune moments). + +2. Pin the L1 page table PTE into the data TLB. This creates a double + mapping condition, but it is safe as nothing will use it until we + start refilling. + +3. Pin the page table page containing the PTE for the TLB miss + exception handler into the data TLB. This will likewise not be + accessed until the double map condition is resolved. + +4. Set PTEVADDR appropriately. The CPU state to handle refill + exceptions is now complete, but cannot be used until we resolve the + double mappings. + +5. Disable the initial/way6 data TLB entries first, by setting them to + an ASID of zero. This is safe as the code being executed is not + doing data accesses yet (including refills), and will resolve the + double mapping conditions we created above. + +6. Disable the initial/way6 instruction TLBs second. The very next + instruction following the invalidation of the currently-executing + code page will then cause a TLB refill exception, which will work + normally because we just resolved the final double-map condition. + (Pedantic note: if the vector page and the currently-executing page + are in different 512M way6 pages, disable the mapping for the + exception handlers first so the trap from our current code can be + handled. Currently Zephyr doesn't handle this condition as in all + reasonable hardware these regions will be near each other) + +Note: there is a different variant of the Xtensa MMU architecture +where the way 5/6 pages are immutable, and specify a set of +unchangable mappings from the final 384M of memory to the bottom and +top of physical memory. The intent here would (presumably) be that +these would be used by the kernel for all physical memory and that the +remaining memory space would be used for virtual mappings. This +doesn't match Zephyr's architecture well, as we tend to assume +page-level control over physical memory (e.g. .text/.rodata is cached +but .data is not on SMP, etc...). And in any case we don't have any +such hardware to experiment with. But with a little address +translation we could support this. + +## ASID vs. Virtual Mapping + +The ASID mechanism in Xtensa works like other architectures, and is +intended to be used similarly. The intent of the design is that at +context switch time, you can simply change RADID and the page table +data, and leave any existing mappings in place in the TLB using the +old ASID value(s). So in the common case where you switch back, +nothing needs to be flushed. + +Unfortunately this runs afoul of the virtual mapping of the page +refill: data TLB entries storing the 4M page table mapping space are +stored at ASID 1 (ring 0), they can't change when the page tables +change! So this region naively would have to be flushed, which is +tantamount to flushing the entire TLB regardless (the TLB is much +smaller than the 1024-page PTE array). + +The resolution in Zephyr is to give each ASID its own PTEVADDR mapping +in virtual space, such that the page tables don't overlap. This is +expensive in virtual address space: assigning 4M of space to each of +the 256 ASIDs (actually 254 as 0 and 1 are never used by user access) +would take a full gigabyte of address space. Zephyr optimizes this a +bit by deriving a unique sequential ASID from the hardware address of +the statically allocated array of L1 page table pages. + +Note, obviously, that any change of the mappings within an ASID +(e.g. to re-use it for another memory domain, or just for any runtime +mapping change other than mapping previously-unmapped pages) still +requires a TLB flush, and always will. + +## SMP/Cache Interaction + +A final important note is that the hardware PTE refill fetch works +like any other CPU memory access, and in particular it is governed by +the cacheability attributes of the TLB entry through which it was +loaded. This means that if the page table entries are marked +cacheable, then the hardware TLB refill process will be downstream of +the L1 data cache on the CPU. If the physical memory storing page +tables has been accessed recently by the CPU (for a refill of another +page mapped within the same cache line, or to change the tables) then +the refill will be served from the data cache and not main memory. + +This may or may not be desirable depending on access patterns. It +lets the L1 data cache act as a "L2 TLB" for applications with a lot +of access variability. But it also means that the TLB entries end up +being stored twice in the same CPU, wasting transistors that could +presumably store other useful data. + +But it it also important to note that the L1 data cache on Xtensa is +incoherent! The cache being used for refill reflects the last access +on the current CPU only, and not of the underlying memory being +mapped. Page table changes in the data cache of one CPU will be +invisible to the data cache of another. There is no simple way of +notifying another CPU of changes to page mappings beyond doing +system-wide flushes on all cpus every time a memory domain is +modified. + +The result is that, when SMP is enabled, Zephyr must ensure that all +page table mappings in the system are set uncached. The OS makes no +attempt to bolt on a software coherence layer. diff --git a/arch/xtensa/core/include/xtensa_mmu_priv.h b/arch/xtensa/core/include/xtensa_mmu_priv.h index cf72c92138373cb..7b1030786f424d3 100644 --- a/arch/xtensa/core/include/xtensa_mmu_priv.h +++ b/arch/xtensa/core/include/xtensa_mmu_priv.h @@ -132,15 +132,8 @@ * * PTE_ENTRY_ADDRESS = PTEVADDR + ((VADDR / 4096) * 4) */ -#define Z_XTENSA_PTE_ENTRY_VADDR(vaddr) \ - (Z_XTENSA_PTEVADDR + (((vaddr) / KB(4)) * 4)) - -/* - * The address of the top level page where the page - * is located in the virtual address. - */ -#define Z_XTENSA_PAGE_TABLE_VADDR \ - Z_XTENSA_PTE_ENTRY_VADDR(Z_XTENSA_PTEVADDR) +#define Z_XTENSA_PTE_ENTRY_VADDR(base, vaddr) \ + ((base) + (((vaddr) / KB(4)) * 4)) /* * Get asid for a given ring from rasid register. @@ -349,4 +342,8 @@ static inline void xtensa_dtlb_vaddr_invalidate(void *vaddr) } } +void xtensa_init_paging(uint32_t *l1_page); + +void xtensa_set_paging(uint32_t asid, uint32_t *l1_page); + #endif /* ZEPHYR_ARCH_XTENSA_XTENSA_MMU_PRIV_H_ */ diff --git a/arch/xtensa/core/mmu.c b/arch/xtensa/core/mmu.c new file mode 100644 index 000000000000000..24e47a42b9ded3b --- /dev/null +++ b/arch/xtensa/core/mmu.c @@ -0,0 +1,178 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#define ASID_INVALID 0 + +struct tlb_regs { + uint32_t rasid; + uint32_t ptevaddr; + uint32_t ptepin_as; + uint32_t ptepin_at; + uint32_t vecpin_as; + uint32_t vecpin_at; +}; + +static void compute_regs(uint32_t user_asid, uint32_t *l1_page, struct tlb_regs *regs) +{ + uint32_t vecbase = XTENSA_RSR("VECBASE"); + + __ASSERT_NO_MSG((((uint32_t)l1_page) & 0xfff) == 0); + __ASSERT_NO_MSG((user_asid == 0) || ((user_asid > 2) && + (user_asid < Z_XTENSA_MMU_SHARED_ASID))); + + /* We don't use ring 1, ring 0 ASID must be 1 */ + regs->rasid = (Z_XTENSA_MMU_SHARED_ASID << 24) | + (user_asid << 16) | 0x000201; + + /* Derive PTEVADDR from ASID so each domain gets its own PTE area */ + regs->ptevaddr = CONFIG_XTENSA_MMU_PTEVADDR + user_asid * 0x400000; + + /* The ptables code doesn't add the mapping for the l1 page itself */ + l1_page[Z_XTENSA_L1_POS(regs->ptevaddr)] = + (uint32_t)l1_page | Z_XTENSA_PAGE_TABLE_ATTR; + + regs->ptepin_at = (uint32_t)l1_page; + regs->ptepin_as = Z_XTENSA_PTE_ENTRY_VADDR(regs->ptevaddr, regs->ptevaddr) + | Z_XTENSA_MMU_PTE_WAY; + + /* Pin mapping for refilling the vector address into the ITLB + * (for handling TLB miss exceptions). Note: this is NOT an + * instruction TLB entry for the vector code itself, it's a + * DATA TLB entry for the page containing the vector mapping + * so the refill on instruction fetch can find it. The + * hardware doesn't have a 4k pinnable instruction TLB way, + * frustratingly. + */ + uint32_t vb_pte = l1_page[Z_XTENSA_L1_POS(vecbase)]; + + regs->vecpin_at = vb_pte; + regs->vecpin_as = Z_XTENSA_PTE_ENTRY_VADDR(regs->ptevaddr, vecbase) + | Z_XTENSA_MMU_VECBASE_WAY; +} + +/* Switch to a new page table. There are four items we have to set in + * the hardware: the PTE virtual address, the ring/ASID mapping + * register, and two pinned entries in the data TLB handling refills + * for the page tables and the vector handlers. + * + * These can be done in any order, provided that we ensure that no + * memory access which cause a TLB miss can happen during the process. + * This means that we must work entirely within registers in a single + * asm block. Also note that instruction fetches are memory accesses + * too, which means we cannot cross a page boundary which might reach + * a new page not in the TLB (a single jump to an aligned address that + * holds our five instructions is sufficient to guarantee that: I + * couldn't think of a way to do the alignment statically that also + * interoperated well with inline assembly). + */ +void xtensa_set_paging(uint32_t user_asid, uint32_t *l1_page) +{ + /* Optimization note: the registers computed here are pure + * functions of the two arguments. With a minor API tweak, + * they could be cached in e.g. a thread struct instead of + * being recomputed. This is called on context switch paths + * and is performance-sensitive. + */ + struct tlb_regs regs; + + compute_regs(user_asid, l1_page, ®s); + + __asm__ volatile("j 1f\n" + ".align 16\n" /* enough for 5 insns */ + "1:\n" + "wsr %0, PTEVADDR\n" + "wsr %1, RASID\n" + "wdtlb %2, %3\n" + "wdtlb %4, %5\n" + "isync" + :: "r"(regs.ptevaddr), "r"(regs.rasid), + "r"(regs.ptepin_at), "r"(regs.ptepin_as), + "r"(regs.vecpin_at), "r"(regs.vecpin_as)); +} + +/* This is effectively the same algorithm from xtensa_set_paging(), + * but it also disables the hardware-initialized 512M TLB entries in + * way 6 (because the hardware disallows duplicate TLB mappings). For + * instruction fetches this produces a critical ordering constraint: + * the instruction following the invalidation of ITLB entry mapping + * the current PC will by definition create a refill condition, which + * will (because the data TLB was invalidated) cause a refill + * exception. Therefore this step must be the very last one, once + * everything else is setup up and working, which includes the + * invalidation of the virtual PTEVADDR area so that the resulting + * refill can complete. + * + * Note that we can't guarantee that the compiler won't insert a data + * fetch from our stack memory after exit from the asm block (while it + * might be double-mapped), so we invalidate that data TLB inside the + * asm for correctness. The other 13 entries get invalidated in a C + * loop at the end. + */ +void xtensa_init_paging(uint32_t *l1_page) +{ + extern char z_xt_init_pc; /* defined in asm below */ + struct tlb_regs regs; + +#if CONFIG_MP_MAX_NUM_CPUS > 1 + /* The incoherent cache can get into terrible trouble if it's + * allowed to cache PTEs differently across CPUs. We require + * that all page tables supplied by the OS have exclusively + * uncached mappings for page data, but can't do anything + * about earlier code/firmware. Dump the cache to be safe. + */ + sys_cache_data_flush_and_invd_all(); +#endif + + compute_regs(ASID_INVALID, l1_page, ®s); + + uint32_t idtlb_pte = (regs.ptevaddr & 0xe0000000) | XCHAL_SPANNING_WAY; + uint32_t idtlb_stk = (((uint32_t)®s) & ~0xfff) | XCHAL_SPANNING_WAY; + uint32_t iitlb_pc = (((uint32_t)&z_xt_init_pc) & ~0xfff) | XCHAL_SPANNING_WAY; + + /* Note: the jump is mostly pedantry, as it's almost + * inconceivable that a hardware memory region at boot is + * going to cross a 512M page boundary. But we need the entry + * symbol to get the address above, so the jump is here for + * symmetry with the set_paging() code. + */ + __asm__ volatile("j z_xt_init_pc\n" + ".align 32\n" /* room for 10 insns */ + ".globl z_xt_init_pc\n" + "z_xt_init_pc:\n" + "wsr %0, PTEVADDR\n" + "wsr %1, RASID\n" + "wdtlb %2, %3\n" + "wdtlb %4, %5\n" + "idtlb %6\n" /* invalidate pte */ + "idtlb %7\n" /* invalidate stk */ + "isync\n" + "iitlb %8\n" /* invalidate pc */ + "isync\n" /* <--- traps a ITLB miss */ + :: "r"(regs.ptevaddr), "r"(regs.rasid), + "r"(regs.ptepin_at), "r"(regs.ptepin_as), + "r"(regs.vecpin_at), "r"(regs.vecpin_as), + "r"(idtlb_pte), "r"(idtlb_stk), "r"(iitlb_pc)); + + /* Invalidate the remaining (unused by this function) + * initialization entries. Now we're flying free with our own + * page table. + */ + for (int i = 0; i < 8; i++) { + uint32_t ixtlb = (i * 0x2000000000) | XCHAL_SPANNING_WAY; + + if (ixtlb != iitlb_pc) { + __asm__ volatile("iitlb %0" :: "r"(ixtlb)); + } + if (ixtlb != idtlb_stk && ixtlb != idtlb_pte) { + __asm__ volatile("idtlb %0" :: "r"(ixtlb)); + } + } + __asm__ volatile("isync"); +} diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index 2130a870e7757d9..17950114544f4b9 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -218,42 +218,6 @@ static inline uint32_t *alloc_l2_table(void) return NULL; } -/** - * @brief Switch page tables - * - * This switches the page tables to the incoming ones (@a ptables). - * Since data TLBs to L2 page tables are auto-filled, @a dtlb_inv - * can be used to invalidate these data TLBs. @a cache_inv can be - * set to true to invalidate cache to the page tables. - * - * @param[in] ptables Page tables to be switched to. - * @param[in] dtlb_inv True if to invalidate auto-fill data TLBs. - * @param[in] cache_inv True if to invalidate cache to page tables. - */ -static ALWAYS_INLINE void switch_page_tables(uint32_t *ptables, bool dtlb_inv, bool cache_inv) -{ - if (cache_inv) { - sys_cache_data_flush_and_invd_all(); - } - - /* Invalidate data TLB to L1 page table */ - xtensa_dtlb_vaddr_invalidate((void *)Z_XTENSA_PAGE_TABLE_VADDR); - - /* Now map the pagetable itself with KERNEL asid to avoid user thread - * from tampering with it. - */ - xtensa_dtlb_entry_write_sync( - Z_XTENSA_PTE((uint32_t)ptables, Z_XTENSA_KERNEL_RING, Z_XTENSA_PAGE_TABLE_ATTR), - Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, Z_XTENSA_MMU_PTE_WAY)); - - if (dtlb_inv) { - /* Since L2 page tables are auto-refilled, - * invalidate all of them to flush the old entries out. - */ - xtensa_tlb_autorefill_invalidate(); - } -} - static void map_memory_range(const uint32_t start, const uint32_t end, const uint32_t attrs, bool shared) { @@ -345,6 +309,17 @@ static void xtensa_init_page_tables(void) #if defined(__GNUC__) #pragma GCC diagnostic pop #endif + /* Finally, the direct-mapped pages used in the page tables + * must be fixed up to use the same cache attribute (but these + * must be writable, obviously). They shouldn't be left at + * the default. + */ + map_memory_range((uint32_t) &l1_page_table[0], + (uint32_t) &l1_page_table[CONFIG_XTENSA_MMU_NUM_L1_TABLES], + Z_XTENSA_PAGE_TABLE_ATTR | Z_XTENSA_MMU_W, false); + map_memory_range((uint32_t) &l2_page_tables[0], + (uint32_t) &l2_page_tables[CONFIG_XTENSA_MMU_NUM_L2_TABLES], + Z_XTENSA_PAGE_TABLE_ATTR | Z_XTENSA_MMU_W, false); sys_cache_data_flush_all(); } @@ -356,9 +331,6 @@ __weak void arch_xtensa_mmu_post_init(bool is_core0) void z_xtensa_mmu_init(void) { - volatile uint8_t entry; - uint32_t ps, vecbase; - if (_current_cpu->id == 0) { /* This is normally done via arch_kernel_init() inside z_cstart(). * However, before that is called, we go through the sys_init of @@ -369,111 +341,7 @@ void z_xtensa_mmu_init(void) xtensa_init_page_tables(); } - /* Set the page table location in the virtual address */ - xtensa_ptevaddr_set((void *)Z_XTENSA_PTEVADDR); - - /* Set rasid */ - xtensa_rasid_asid_set(Z_XTENSA_MMU_SHARED_ASID, Z_XTENSA_SHARED_RING); - - /* Next step is to invalidate the tlb entry that contains the top level - * page table. This way we don't cause a multi hit exception. - */ - xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, 6)); - xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, 6)); - - /* We are not using a flat table page, so we need to map - * only the top level page table (which maps the page table itself). - * - * Lets use one of the wired entry, so we never have tlb miss for - * the top level table. - */ - xtensa_dtlb_entry_write(Z_XTENSA_PTE((uint32_t)z_xtensa_kernel_ptables, - Z_XTENSA_KERNEL_RING, Z_XTENSA_PAGE_TABLE_ATTR), - Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, Z_XTENSA_MMU_PTE_WAY)); - - /* Before invalidate the text region in the TLB entry 6, we need to - * map the exception vector into one of the wired entries to avoid - * a page miss for the exception. - */ - __asm__ volatile("rsr.vecbase %0" : "=r"(vecbase)); - - xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY( - Z_XTENSA_PTEVADDR + MB(4), 3)); - - xtensa_dtlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY( - Z_XTENSA_PTEVADDR + MB(4), 3)); - - /* Temporarily uses KernelExceptionVector for level 1 interrupts - * handling. This is due to UserExceptionVector needing to jump to - * _Level1Vector. The jump ('j') instruction offset is incorrect - * when we move VECBASE below. - */ - __asm__ volatile("rsr.ps %0" : "=r"(ps)); - ps &= ~PS_UM; - __asm__ volatile("wsr.ps %0; rsync" :: "a"(ps)); - - __asm__ volatile("wsr.vecbase %0; rsync\n\t" - :: "a"(Z_XTENSA_PTEVADDR + MB(4))); - - - /* Finally, lets invalidate all entries in way 6 as the page tables - * should have already mapped the regions we care about for boot. - */ - for (entry = 0; entry < BIT(XCHAL_ITLB_ARF_ENTRIES_LOG2); entry++) { - __asm__ volatile("iitlb %[idx]\n\t" - "isync" - :: [idx] "a"((entry << 29) | 6)); - } - - for (entry = 0; entry < BIT(XCHAL_DTLB_ARF_ENTRIES_LOG2); entry++) { - __asm__ volatile("idtlb %[idx]\n\t" - "dsync" - :: [idx] "a"((entry << 29) | 6)); - } - - /* Map VECBASE to a fixed data TLB */ - xtensa_dtlb_entry_write( - Z_XTENSA_PTE((uint32_t)vecbase, - Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_CACHED_WB), - Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, Z_XTENSA_MMU_VECBASE_WAY)); - - /* - * Pre-load TLB for vecbase so exception handling won't result - * in TLB miss during boot, and that we can handle single - * TLB misses. - */ - xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_AUTOFILL_TLB_ENTRY(vecbase)); - - /* To finish, just restore vecbase and invalidate TLB entries - * used to map the relocated vecbase. - */ - __asm__ volatile("wsr.vecbase %0; rsync\n\t" - :: "a"(vecbase)); - - /* Restore PS_UM so that level 1 interrupt handling will go to - * UserExceptionVector. - */ - __asm__ volatile("rsr.ps %0" : "=r"(ps)); - ps |= PS_UM; - __asm__ volatile("wsr.ps %0; rsync" :: "a"(ps)); - - xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); - xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); - - /* - * Clear out THREADPTR as we use it to indicate - * whether we are in user mode or not. - */ - XTENSA_WUR("THREADPTR", 0); + xtensa_init_paging(z_xtensa_kernel_ptables); arch_xtensa_mmu_post_init(_current_cpu->id == 0); } @@ -504,7 +372,7 @@ __weak void arch_reserved_pages_update(void) static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, uint32_t flags, bool is_user) { - uint32_t l1_pos = (uint32_t)vaddr >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS((uint32_t)vaddr); uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); uint32_t *table; @@ -530,6 +398,7 @@ static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, flags); sys_cache_data_flush_range((void *)&table[l2_pos], sizeof(table[0])); + xtensa_tlb_autorefill_invalidate(); return true; } @@ -604,18 +473,6 @@ static inline void __arch_mem_map(void *va, uintptr_t pa, uint32_t xtensa_flags, k_spin_unlock(&z_mem_domain_lock, key); } #endif /* CONFIG_USERSPACE */ - - if ((xtensa_flags & Z_XTENSA_MMU_X) == Z_XTENSA_MMU_X) { - xtensa_itlb_vaddr_invalidate(vaddr); - } - xtensa_dtlb_vaddr_invalidate(vaddr); - - if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { - if (xtensa_flags & Z_XTENSA_MMU_X) { - xtensa_itlb_vaddr_invalidate(vaddr_uc); - } - xtensa_dtlb_vaddr_invalidate(vaddr_uc); - } } void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) @@ -680,7 +537,7 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) */ static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) { - uint32_t l1_pos = (uint32_t)vaddr >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS((uint32_t)vaddr); uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); uint32_t *l2_table; uint32_t table_pos; @@ -717,10 +574,9 @@ static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) table_pos = (l2_table - (uint32_t *)l2_page_tables) / (XTENSA_L2_PAGE_TABLE_ENTRIES); atomic_clear_bit(l2_page_tables_track, table_pos); - /* Need to invalidate L2 page table as it is no longer valid. */ - xtensa_dtlb_vaddr_invalidate((void *)l2_table); - end: + /* Need to invalidate L2 page table as it is no longer valid. */ + xtensa_tlb_autorefill_invalidate(); return exec; } @@ -764,18 +620,6 @@ static inline void __arch_mem_unmap(void *va) } k_spin_unlock(&z_mem_domain_lock, key); #endif /* CONFIG_USERSPACE */ - - if (is_exec) { - xtensa_itlb_vaddr_invalidate(vaddr); - } - xtensa_dtlb_vaddr_invalidate(vaddr); - - if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { - if (is_exec) { - xtensa_itlb_vaddr_invalidate(vaddr_uc); - } - xtensa_dtlb_vaddr_invalidate(vaddr_uc); - } } void arch_mem_unmap(void *addr, size_t size) @@ -853,7 +697,7 @@ void z_xtensa_mmu_tlb_shootdown(void) * MMU_PTE_WAY, so we can skip the probing step by * generating the query entry directly. */ - ptevaddr_entry = Z_XTENSA_PAGE_TABLE_VADDR | MMU_PTE_WAY; + ptevaddr_entry = (uint32_t)xtensa_ptevaddr_get() | Z_XTENSA_MMU_PTE_WAY; ptevaddr = xtensa_dtlb_paddr_read(ptevaddr_entry); thread_ptables = (uint32_t)thread->arch.ptables; @@ -863,7 +707,9 @@ void z_xtensa_mmu_tlb_shootdown(void) * indicated by the current thread are different * than the current mapped page table. */ - switch_page_tables((uint32_t *)thread_ptables, true, true); + struct arch_mem_domain *domain = + &(thread->mem_domain_info.mem_domain->arch); + xtensa_set_paging(domain->asid, (uint32_t *)thread_ptables); } } @@ -981,9 +827,8 @@ static int region_map_update(uint32_t *ptables, uintptr_t start, for (size_t offset = 0; offset < size; offset += CONFIG_MMU_PAGE_SIZE) { uint32_t *l2_table, pte; uint32_t page = start + offset; - uint32_t l1_pos = page >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS(page); uint32_t l2_pos = Z_XTENSA_L2_POS(page); - /* Make sure we grab a fresh copy of L1 page table */ sys_cache_data_invd_range((void *)&ptables[l1_pos], sizeof(ptables[0])); @@ -998,8 +843,7 @@ static int region_map_update(uint32_t *ptables, uintptr_t start, sys_cache_data_flush_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); - xtensa_dtlb_vaddr_invalidate( - (void *)(pte & Z_XTENSA_PTE_PPN_MASK)); + xtensa_dtlb_vaddr_invalidate((void *)page); } return ret; @@ -1127,7 +971,7 @@ int arch_mem_domain_thread_add(struct k_thread *thread) * the current thread running. */ if (thread == _current_cpu->current) { - switch_page_tables(thread->arch.ptables, true, true); + xtensa_set_paging(domain->arch.asid, thread->arch.ptables); } #if CONFIG_MP_MAX_NUM_CPUS > 1 @@ -1179,7 +1023,7 @@ static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool w { uint8_t asid_ring; uint32_t rasid, pte, *l2_table; - uint32_t l1_pos = page >> 22; + uint32_t l1_pos = Z_XTENSA_L1_POS(page); uint32_t l2_pos = Z_XTENSA_L2_POS(page); if (is_pte_illegal(ptables[l1_pos])) { @@ -1245,12 +1089,7 @@ void z_xtensa_swap_update_page_tables(struct k_thread *incoming) struct arch_mem_domain *domain = &(incoming->mem_domain_info.mem_domain->arch); - /* Lets set the asid for the incoming thread */ - if ((incoming->base.user_options & K_USER) != 0) { - xtensa_rasid_asid_set(domain->asid, Z_XTENSA_USER_RING); - } - - switch_page_tables(ptables, true, false); + xtensa_set_paging(domain->asid, ptables); } #endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h index 3f3ffd90b7ae043..416a83453a2d0e2 100644 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ b/arch/xtensa/include/xtensa-asm2-s.h @@ -589,31 +589,6 @@ _Level\LVL\()VectorHelper : .global _Level\LVL\()Vector _Level\LVL\()Vector: #endif -#ifdef CONFIG_XTENSA_MMU - wsr.ZSR_MMU_0 a2 - wsr.ZSR_MMU_1 a3 - rsync - - /* Calculations below will clobber registers used. - * So we make a copy of the stack pointer to avoid - * changing it. - */ - mov a3, a1 - - CALC_PTEVADDR_BASE a2 - - /* Preload PTE entry page of current stack. */ - PRELOAD_PTEVADDR a3, a2 - - /* Preload PTE entry page of new stack, where - * it will be used later (in EXCINT_HANDLER above). - */ - rsr.ZSR_CPU a3 - PRELOAD_PTEVADDR a3, a2 - - rsr.ZSR_MMU_1 a3 - rsr.ZSR_MMU_0 a2 -#endif /* CONFIG_XTENSA_MMU */ addi a1, a1, -___xtensa_irq_bsa_t_SIZEOF s32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET s32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET diff --git a/soc/xtensa/dc233c/mmu.c b/soc/xtensa/dc233c/mmu.c index 718f79779ebd5ce..8decc952bf2ac66 100644 --- a/soc/xtensa/dc233c/mmu.c +++ b/soc/xtensa/dc233c/mmu.c @@ -35,33 +35,3 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { }; int xtensa_soc_mmu_ranges_num = ARRAY_SIZE(xtensa_soc_mmu_ranges); - -void arch_xtensa_mmu_post_init(bool is_core0) -{ - uint32_t vecbase; - - ARG_UNUSED(is_core0); - - __asm__ volatile("rsr.vecbase %0" : "=r"(vecbase)); - - /* Invalidate any autorefill instr TLBs of VECBASE so we can map it - * permanently below. - */ - xtensa_itlb_vaddr_invalidate((void *)vecbase); - - /* Map VECBASE permanently in instr TLB way 4 so we will always have - * access to exception handlers. Each way 4 TLB covers 1MB (unless - * ITLBCFG has been changed before this, which should not have - * happened). Also this needs to be mapped as SHARED so both kernel - * and userspace can execute code here => same as .text. - * - * Note that we don't want to map the first 1MB in data TLB as - * we want to keep page 0 (0x00000000) unmapped to catch null pointer - * de-references. - */ - vecbase = ROUND_DOWN(vecbase, MB(1)); - xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_SHARED_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, 4)); -} From d7513fb5260dd4dec4aded2c35d5cd059a6743a6 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 14 Nov 2023 16:49:18 +0100 Subject: [PATCH 0830/1049] driver: serial: stm32u5: DMAT Errata behavior valid only on some SoCs Workaround for DMAT errata was applied on all SoCs declaring STM32U5 DMA compatible. This errata has been fixed in later SoCs revisions and should not be applied anymore as this can cause compatibility issues with power mgmt (can not enter STOP1 in some cases). Declare a specific Kconfig symbol to restrict the workaround only to the set of SoCs impacted by the issue and requiring workaround. Note that I preferred using Kconfig over device tree since it doesn't feel right to declare a compatible on a silicon bug base. Signed-off-by: Erwan Gouriou --- drivers/serial/Kconfig.stm32 | 15 +++++++++++++++ drivers/serial/uart_stm32.c | 8 ++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/serial/Kconfig.stm32 b/drivers/serial/Kconfig.stm32 index c6aa6051993e9da..75d0e22c157ce4c 100644 --- a/drivers/serial/Kconfig.stm32 +++ b/drivers/serial/Kconfig.stm32 @@ -21,3 +21,18 @@ config UART_STM32 This option enables the UART driver for STM32 family of processors. Say y if you wish to use serial port on STM32 MCU. + +if UART_STM32 + +config UART_STM32U5_ERRATA_DMAT + bool + default y + depends on SOC_STM32U575XX || SOC_STM32U585XX || \ + SOC_STM32H562XX || SOC_STM32H563XX || SOC_STM32H573XX + help + Handles erratum "USART does not generate DMA requests after + setting/clearing DMAT bit". + Seen in Errata Sheet 0499 § 2.19.2 and §2.20.1 for stm32u57x/u58x, + Errata Sheet 0565 § 2.14.1 and §2.15.1 for stm32h56x/h57x + +endif diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index 5c1ff75bd6d11af..dd79612322d70bf 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1321,7 +1321,7 @@ static inline void uart_stm32_dma_tx_enable(const struct device *dev) static inline void uart_stm32_dma_tx_disable(const struct device *dev) { -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) +#ifdef CONFIG_UART_STM32U5_ERRATA_DMAT ARG_UNUSED(dev); /* @@ -1333,7 +1333,7 @@ static inline void uart_stm32_dma_tx_disable(const struct device *dev) const struct uart_stm32_config *config = dev->config; LL_USART_DisableDMAReq_TX(config->usart); -#endif /* ! st_stm32u5_dma */ +#endif } static inline void uart_stm32_dma_rx_enable(const struct device *dev) @@ -1633,9 +1633,9 @@ static int uart_stm32_async_tx_abort(const struct device *dev) data->dma_tx.counter = tx_buffer_length - stat.pending_length; } -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) +#ifdef CONFIG_UART_STM32U5_ERRATA_DMAT dma_suspend(data->dma_tx.dma_dev, data->dma_tx.dma_channel); -#endif /* st_stm32u5_dma */ +#endif dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel); async_evt_tx_abort(data); From 3ee526b4c3fc59cde98f1528f19870a0e148b645 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 16 Nov 2023 10:06:02 +0100 Subject: [PATCH 0831/1049] drivers: audio: Codec shell fix compiler warnings This commit fixes the following compiler warnings: * implicit declaration of function 'strtoul'; did you mean 'strtok'? * passing argument 2 of 'parse_named_int' discards 'const' qualifier Signed-off-by: Pieter De Gendt --- drivers/audio/codec_shell.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/audio/codec_shell.c b/drivers/audio/codec_shell.c index 6fb47d111847179..b5c3421bf265e17 100644 --- a/drivers/audio/codec_shell.c +++ b/drivers/audio/codec_shell.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include @@ -55,7 +56,7 @@ static const struct args_index args_indx = { .value = 4, }; -static int parse_named_int(const char *name, const char *keystack[], size_t count) +static int parse_named_int(const char *name, const char *const keystack[], size_t count) { char *endptr; int i; From ca7ce90dc7b4ad7e8835718b7c60cb7409102500 Mon Sep 17 00:00:00 2001 From: Ibe Van de Veire Date: Tue, 14 Nov 2023 11:15:57 +0100 Subject: [PATCH 0832/1049] net: ip: utils: changed input arguments of igmp_checksum to net_pkt Added igmpv3 checksum function to make it possible to calculate the checksum of a complete igmpv3 pkt at once. Signed-off-by: Ibe Van de Veire --- subsys/net/ip/Kconfig.ipv4 | 8 +++++++- subsys/net/ip/igmp.c | 5 ++--- subsys/net/ip/net_private.h | 4 ++-- subsys/net/ip/utils.c | 11 +++-------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/subsys/net/ip/Kconfig.ipv4 b/subsys/net/ip/Kconfig.ipv4 index a5e073051de82e1..3158fe43e41d5aa 100644 --- a/subsys/net/ip/Kconfig.ipv4 +++ b/subsys/net/ip/Kconfig.ipv4 @@ -50,7 +50,7 @@ config NET_IPV4_ACCEPT_ZERO_BROADCAST 0.0.0.0 broadcast address as described in RFC 1122 ch. 3.3.6 config NET_IPV4_IGMP - bool "Internet Group Management Protocol (IGMP) support" + bool "Internet Group Management Protocol (IGMPv2) support" select NET_IPV4_HDR_OPTIONS help The value depends on your network needs. IGMP should normally be @@ -59,6 +59,12 @@ config NET_IPV4_IGMP because IP Router Alert option must be sent. See RFC 2236 for details. +config NET_IPV4_IGMPV3 + bool "Internet Group Management Protocol version 3 (IGMPv3) support" + depends on NET_IPV4_IGMP + help + Use IGMPv3 for managing the multicast groups. + config NET_DHCPV4 bool "DHCPv4 client" select NET_MGMT diff --git a/subsys/net/ip/igmp.c b/subsys/net/ip/igmp.c index f09aecc4bf9f526..a8ecc0d28f91706 100644 --- a/subsys/net/ip/igmp.c +++ b/subsys/net/ip/igmp.c @@ -56,7 +56,7 @@ static int igmp_v2_create(struct net_pkt *pkt, const struct in_addr *addr, igmp->max_rsp = 0U; net_ipaddr_copy(&igmp->address, addr); igmp->chksum = 0; - igmp->chksum = net_calc_chksum_igmp((uint8_t *)igmp, sizeof(*igmp)); + igmp->chksum = net_calc_chksum_igmp(pkt); if (net_pkt_set_data(pkt, &igmp_access)) { return -ENOBUFS; @@ -217,8 +217,7 @@ enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, return NET_DROP; } - if (net_calc_chksum_igmp((uint8_t *)igmp_hdr, - sizeof(*igmp_hdr)) != 0U) { + if (net_calc_chksum_igmp(pkt)) { NET_DBG("DROP: Invalid checksum"); goto drop; } diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 0906a7a28b1ab13..2fd0928b170b7e2 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -230,12 +230,12 @@ void net_ipv4_igmp_init(struct net_if *iface); #endif /* CONFIG_NET_IPV4_IGMP */ #if defined(CONFIG_NET_IPV4_IGMP) -uint16_t net_calc_chksum_igmp(uint8_t *data, size_t len); +uint16_t net_calc_chksum_igmp(struct net_pkt *pkt); enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr); #else #define net_ipv4_igmp_input(...) -#define net_calc_chksum_igmp(data, len) 0U +#define net_calc_chksum_igmp(struct net_pkt *pkt) 0U #endif /* CONFIG_NET_IPV4_IGMP */ static inline uint16_t net_calc_chksum_icmpv6(struct net_pkt *pkt) diff --git a/subsys/net/ip/utils.c b/subsys/net/ip/utils.c index 0e3bbce5d33ee77..a1b3facd9056d7a 100644 --- a/subsys/net/ip/utils.c +++ b/subsys/net/ip/utils.c @@ -644,7 +644,7 @@ uint16_t net_calc_chksum(struct net_pkt *pkt, uint8_t proto) if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { - if (proto != IPPROTO_ICMP) { + if (proto != IPPROTO_ICMP && proto != IPPROTO_IGMP) { len = 2 * sizeof(struct in_addr); sum = net_pkt_get_len(pkt) - net_pkt_ip_hdr_len(pkt) - @@ -700,14 +700,9 @@ uint16_t net_calc_chksum_ipv4(struct net_pkt *pkt) #endif /* CONFIG_NET_IPV4 */ #if defined(CONFIG_NET_IPV4_IGMP) -uint16_t net_calc_chksum_igmp(uint8_t *data, size_t len) +uint16_t net_calc_chksum_igmp(struct net_pkt *pkt) { - uint16_t sum; - - sum = calc_chksum(0, data, len); - sum = (sum == 0U) ? 0xffff : htons(sum); - - return ~sum; + return net_calc_chksum(pkt, IPPROTO_IGMP); } #endif /* CONFIG_NET_IPV4_IGMP */ From 1d0f47b00576bbd8b0ac3e3d468ea4f7a5d78f8d Mon Sep 17 00:00:00 2001 From: Ibe Van de Veire Date: Thu, 16 Nov 2023 10:36:56 +0100 Subject: [PATCH 0833/1049] net: ip: igmp: add igmpv3 support Added igmpv3 support based on the already existing structure for igmpv2. The already existing api is not modified to prevent breaking exisiting applications. Signed-off-by: Ibe Van de Veire --- include/zephyr/net/igmp.h | 15 +- include/zephyr/net/net_if.h | 11 + subsys/net/ip/Kconfig.ipv4 | 4 + subsys/net/ip/igmp.c | 390 +++++++++++++++++++++++++-- subsys/net/ip/ipv4.h | 53 ++++ subsys/net/ip/net_private.h | 2 +- subsys/net/lib/dns/llmnr_responder.c | 4 +- subsys/net/lib/dns/mdns_responder.c | 4 +- subsys/net/lib/shell/ipv4.c | 2 +- tests/net/igmp/src/main.c | 2 +- 10 files changed, 451 insertions(+), 36 deletions(-) diff --git a/include/zephyr/net/igmp.h b/include/zephyr/net/igmp.h index 7119676f237de4c..ed39a31359f2b04 100644 --- a/include/zephyr/net/igmp.h +++ b/include/zephyr/net/igmp.h @@ -27,22 +27,31 @@ extern "C" { #endif +struct igmp_param { + struct in_addr *source_list; /* List of sources to include or exclude */ + size_t sources_len; /* Length of source list */ + bool include; /* Source list filter type */ +}; + /** * @brief Join a given multicast group. * * @param iface Network interface where join message is sent * @param addr Multicast group to join + * @param param Optional parameters * * @return Return 0 if joining was done, <0 otherwise. */ #if defined(CONFIG_NET_IPV4_IGMP) -int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr); +int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr, + const struct igmp_param *param); #else -static inline int net_ipv4_igmp_join(struct net_if *iface, - const struct in_addr *addr) +static inline int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr, + const struct igmp_param *param) { ARG_UNUSED(iface); ARG_UNUSED(addr); + ARG_UNUSED(param); return -ENOSYS; } diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 788c33163918fbb..1780adeb5ca1706 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -94,6 +94,17 @@ struct net_if_mcast_addr { /** IP address */ struct net_addr address; +#if defined(CONFIG_NET_IPV4_IGMPV3) + /** Sources to filter on */ + struct net_addr sources[CONFIG_NET_IF_MCAST_IPV4_SOURCE_COUNT]; + + /** Number of sources to be used by the filter */ + uint16_t sources_len; + + /** Filter mode (used in IGMPV3) */ + uint8_t record_type; +#endif + /** Is this multicast IP address used or not */ uint8_t is_used : 1; diff --git a/subsys/net/ip/Kconfig.ipv4 b/subsys/net/ip/Kconfig.ipv4 index 3158fe43e41d5aa..e5d30cfc27c83ef 100644 --- a/subsys/net/ip/Kconfig.ipv4 +++ b/subsys/net/ip/Kconfig.ipv4 @@ -37,6 +37,10 @@ config NET_IF_MCAST_IPV4_ADDR_COUNT default 2 if NET_IPV4_IGMP default 1 +config NET_IF_MCAST_IPV4_SOURCE_COUNT + int "Max number of IPv4 sources per mcast address to be included or excluded" + default 1 + config NET_ICMPV4_ACCEPT_BROADCAST bool "Accept broadcast ICMPv4 echo-request" help diff --git a/subsys/net/ip/igmp.c b/subsys/net/ip/igmp.c index a8ecc0d28f91706..3cd7be7de498cb0 100644 --- a/subsys/net/ip/igmp.c +++ b/subsys/net/ip/igmp.c @@ -28,8 +28,18 @@ LOG_MODULE_DECLARE(net_ipv4, CONFIG_NET_IPV4_LOG_LEVEL); #define IPV4_OPT_HDR_ROUTER_ALERT_LEN 4 +#define IGMPV3_MODE_IS_INCLUDE 0x01 +#define IGMPV3_MODE_IS_EXCLUDE 0x02 +#define IGMPV3_CHANGE_TO_INCLUDE_MODE 0x03 +#define IGMPV3_CHANGE_TO_EXCLUDE_MODE 0x04 +#define IGMPV3_ALLOW_NEW_SOURCES 0x05 +#define IGMPV3_BLOCK_OLD_SOURCES 0x06 + static const struct in_addr all_systems = { { { 224, 0, 0, 1 } } }; static const struct in_addr all_routers = { { { 224, 0, 0, 2 } } }; +#if defined(CONFIG_NET_IPV4_IGMPV3) +static const struct in_addr igmp_multicast_addr = { { { 224, 0, 0, 22 } } }; +#endif #define dbg_addr(action, pkt_str, src, dst) \ NET_DBG("%s %s from %s to %s", action, pkt_str, \ @@ -39,6 +49,12 @@ static const struct in_addr all_routers = { { { 224, 0, 0, 2 } } }; #define dbg_addr_recv(pkt_str, src, dst) \ dbg_addr("Received", pkt_str, src, dst) +enum igmp_version { + IGMPV1, + IGMPV2, + IGMPV3, +}; + static int igmp_v2_create(struct net_pkt *pkt, const struct in_addr *addr, uint8_t type) { @@ -56,14 +72,118 @@ static int igmp_v2_create(struct net_pkt *pkt, const struct in_addr *addr, igmp->max_rsp = 0U; net_ipaddr_copy(&igmp->address, addr); igmp->chksum = 0; + + if (net_pkt_set_data(pkt, &igmp_access)) { + return -ENOBUFS; + } + igmp->chksum = net_calc_chksum_igmp(pkt); + net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_init(pkt); + + net_pkt_skip(pkt, offsetof(struct net_ipv4_igmp_v2_report, chksum)); + if (net_pkt_write(pkt, &igmp->chksum, sizeof(igmp->chksum))) { + return -ENOBUFS; + } + + return 0; +} + +#if defined(CONFIG_NET_IPV4_IGMPV3) +static int igmp_v3_create(struct net_pkt *pkt, uint8_t type, struct net_if_mcast_addr mcast[], + size_t mcast_len) +{ + NET_PKT_DATA_ACCESS_DEFINE(igmp_access, struct net_ipv4_igmp_v3_report); + NET_PKT_DATA_ACCESS_DEFINE(group_record_access, struct net_ipv4_igmp_v3_group_record); + struct net_ipv4_igmp_v3_report *igmp; + struct net_ipv4_igmp_v3_group_record *group_record; + + uint16_t group_count = 0; + + igmp = (struct net_ipv4_igmp_v3_report *)net_pkt_get_data(pkt, &igmp_access); + if (!igmp) { + return -ENOBUFS; + } + + for (int i = 0; i < mcast_len; i++) { + /* We don't need to send an IGMP membership report to the IGMP + * all systems multicast address of 224.0.0.1 so skip over it. + * Since the IGMP all systems multicast address is marked as + * used and joined during init time, we have to check this + * address separately to skip over it. + */ + if (!mcast[i].is_used || !mcast[i].is_joined || + net_ipv4_addr_cmp_raw((uint8_t *)&mcast[i].address.in_addr, + (uint8_t *)&all_systems)) { + continue; + } + + group_count++; + } + + igmp->type = type; + igmp->reserved_1 = 0U; + igmp->reserved_2 = 0U; + igmp->groups_len = htons(group_count); + /* Setting initial value of chksum to 0 to calculate chksum as described in RFC 3376 + * ch 4.1.2 + */ + igmp->chksum = 0; + if (net_pkt_set_data(pkt, &igmp_access)) { return -ENOBUFS; } + for (int i = 0; i < mcast_len; i++) { + /* We don't need to send an IGMP membership report to the IGMP + * all systems multicast address of 224.0.0.1 so skip over it. + * Since the IGMP all systems multicast address is marked as + * used and joined during init time, we have to check this + * address separately to skip over it. + */ + if (!mcast[i].is_used || !mcast[i].is_joined || + net_ipv4_addr_cmp_raw((uint8_t *)&mcast[i].address.in_addr, + (uint8_t *)&all_systems)) { + continue; + } + + group_record = (struct net_ipv4_igmp_v3_group_record *)net_pkt_get_data( + pkt, &group_record_access); + if (!group_record) { + return -ENOBUFS; + } + + group_record->type = mcast[i].record_type; + group_record->aux_len = 0U; + net_ipaddr_copy(&group_record->address, &mcast[i].address.in_addr); + group_record->sources_len = htons(mcast[i].sources_len); + + if (net_pkt_set_data(pkt, &group_record_access)) { + return -ENOBUFS; + } + + for (int j = 0; j < mcast[i].sources_len; j++) { + if (net_pkt_write(pkt, &mcast[i].sources[j].in_addr.s_addr, + sizeof(mcast[i].sources[j].in_addr.s_addr))) { + return -ENOBUFS; + } + } + } + + igmp->chksum = net_calc_chksum_igmp(pkt); + + net_pkt_set_overwrite(pkt, true); + net_pkt_cursor_init(pkt); + + net_pkt_skip(pkt, offsetof(struct net_ipv4_igmp_v3_report, chksum)); + if (net_pkt_write(pkt, &igmp->chksum, sizeof(igmp->chksum))) { + return -ENOBUFS; + } + return 0; } +#endif static int igmp_v2_create_packet(struct net_pkt *pkt, const struct in_addr *dst, const struct in_addr *group, uint8_t type) @@ -95,6 +215,30 @@ static int igmp_v2_create_packet(struct net_pkt *pkt, const struct in_addr *dst, return igmp_v2_create(pkt, group, type); } +#if defined(CONFIG_NET_IPV4_IGMPV3) +static int igmp_v3_create_packet(struct net_pkt *pkt, const struct in_addr *dst, + struct net_if_mcast_addr mcast[], size_t mcast_len, uint8_t type) +{ + const uint32_t router_alert = 0x94040000; /* RFC 2213 ch 2.1 */ + int ret; + + ret = net_ipv4_create_full(pkt, net_if_ipv4_select_src_addr(net_pkt_iface(pkt), dst), dst, + 0U, 0U, 0U, 0U, 1U); /* TTL set to 1, RFC 3376 ch 2 */ + if (ret) { + return -ENOBUFS; + } + + /* Add router alert option, RFC 3376 ch 2 */ + if (net_pkt_write_be32(pkt, router_alert)) { + return -ENOBUFS; + } + + net_pkt_set_ipv4_opts_len(pkt, IPV4_OPT_HDR_ROUTER_ALERT_LEN); + + return igmp_v3_create(pkt, type, mcast, mcast_len); +} +#endif + static int igmp_send(struct net_pkt *pkt) { int ret; @@ -195,41 +339,156 @@ static int send_igmp_report(struct net_if *iface, return ret; } -enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, - struct net_ipv4_hdr *ip_hdr) +#if defined(CONFIG_NET_IPV4_IGMPV3) +static int send_igmp_v3_report(struct net_if *iface, struct net_ipv4_igmp_v3_query *igmp_v3_hdr) { - NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(igmp_access, - struct net_ipv4_igmp_v2_query); - struct net_ipv4_igmp_v2_query *igmp_hdr; + struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4; + struct net_pkt *pkt = NULL; + int i, group_count = 0, source_count = 0; + int ret = 0; + + if (!ipv4) { + return -ENOENT; + } - /* TODO: receive from arbitrary group address instead of - * all_systems + for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) { + /* We don't need to send an IGMP membership report to the IGMP + * all systems multicast address of 224.0.0.1 so skip over it. + * Since the IGMP all systems multicast address is marked as + * used and joined during init time, we have to check this + * address separately to skip over it. + */ + if (!ipv4->mcast[i].is_used || !ipv4->mcast[i].is_joined || + net_ipv4_addr_cmp_raw((uint8_t *)&ipv4->mcast[i].address.in_addr, + (uint8_t *)&all_systems)) { + continue; + } + + group_count++; + source_count += ipv4->mcast[i].sources_len; + } + + if (group_count == 0) { + return -ESRCH; + } + + pkt = net_pkt_alloc_with_buffer( + iface, + IPV4_OPT_HDR_ROUTER_ALERT_LEN + sizeof(struct net_ipv4_igmp_v3_report) + + sizeof(struct net_ipv4_igmp_v3_group_record) * group_count + + sizeof(struct in_addr) * source_count, + AF_INET, IPPROTO_IGMP, PKT_WAIT_TIME); + if (!pkt) { + return -ENOMEM; + } + + /* Send the IGMP V3 membership report to the igmp multicast + * address, as per RFC 3376 Section 4.2.14. */ + + ret = igmp_v3_create_packet(pkt, &igmp_multicast_addr, ipv4->mcast, NET_IF_MAX_IPV4_MADDR, + NET_IPV4_IGMP_REPORT_V3); + if (ret < 0) { + goto drop; + } + + ret = igmp_send(pkt); + if (ret < 0) { + goto drop; + } + + /* So that we do not free the data while it is being sent */ + pkt = NULL; + +drop: + if (pkt) { + net_pkt_unref(pkt); + } + + return ret; +} +#endif + +enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr) +{ +#if defined(CONFIG_NET_IPV4_IGMPV3) + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(igmpv3_access, struct net_ipv4_igmp_v3_query); + struct net_ipv4_igmp_v3_query *igmpv3_hdr; +#endif + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(igmpv2_access, struct net_ipv4_igmp_v2_query); + struct net_ipv4_igmp_v2_query *igmpv2_hdr; + enum igmp_version version; + int ret; + int igmp_buf_len = pkt->buffer->len - net_pkt_ip_hdr_len(pkt); + + /* Detect IGMP type (RFC 3376 ch 7.1) */ + if (igmp_buf_len == 8) { + /* IGMPv1/2 detected */ + version = IGMPV2; + } else if (igmp_buf_len >= 12) { + /* IGMPv3 detected */ + version = IGMPV3; +#if !defined(CONFIG_NET_IPV4_IGMPV3) + NET_DBG("DROP: %sv3 msg received but %s support is disabled", "IGMP", "IGMP"); + return NET_DROP; +#endif + } else { + NET_DBG("DROP: unsupported payload length"); + return NET_DROP; + } + if (!net_ipv4_addr_cmp_raw(ip_hdr->dst, (uint8_t *)&all_systems)) { NET_DBG("DROP: Invalid dst address"); return NET_DROP; } - igmp_hdr = (struct net_ipv4_igmp_v2_query *)net_pkt_get_data(pkt, - &igmp_access); - if (!igmp_hdr) { - NET_DBG("DROP: NULL IGMP header"); - return NET_DROP; +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (version == IGMPV3) { + igmpv3_hdr = (struct net_ipv4_igmp_v3_query *)net_pkt_get_data(pkt, &igmpv3_access); + if (!igmpv3_hdr) { + NET_DBG("DROP: NULL %sv3 header", "IGMP"); + return NET_DROP; + } + } else { +#endif + igmpv2_hdr = (struct net_ipv4_igmp_v2_query *)net_pkt_get_data(pkt, &igmpv2_access); + if (!igmpv2_hdr) { + NET_DBG("DROP: NULL %s header", "IGMP"); + return NET_DROP; + } +#if defined(CONFIG_NET_IPV4_IGMPV3) } +#endif - if (net_calc_chksum_igmp(pkt)) { + ret = net_calc_chksum_igmp(pkt); + if (ret != 0u) { NET_DBG("DROP: Invalid checksum"); goto drop; } - net_pkt_acknowledge_data(pkt, &igmp_access); +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (version == IGMPV3) { + net_pkt_acknowledge_data(pkt, &igmpv3_access); + } else { +#endif + net_pkt_acknowledge_data(pkt, &igmpv2_access); +#if defined(CONFIG_NET_IPV4_IGMPV3) + } +#endif - dbg_addr_recv("Internet Group Management Protocol", &ip_hdr->src, - &ip_hdr->dst); + dbg_addr_recv("Internet Group Management Protocol", &ip_hdr->src, &ip_hdr->dst); net_stats_update_ipv4_igmp_recv(net_pkt_iface(pkt)); - (void)send_igmp_report(net_pkt_iface(pkt), igmp_hdr); +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (version == IGMPV3) { + (void)send_igmp_v3_report(net_pkt_iface(pkt), igmpv3_hdr); + } else { +#endif + (void)send_igmp_report(net_pkt_iface(pkt), igmpv2_hdr); +#if defined(CONFIG_NET_IPV4_IGMPV3) + } +#endif net_pkt_unref(pkt); @@ -241,6 +500,7 @@ enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, return NET_DROP; } +#if !defined(CONFIG_NET_IPV4_IGMPV3) static int igmp_send_generic(struct net_if *iface, const struct in_addr *addr, bool join) @@ -280,12 +540,57 @@ static int igmp_send_generic(struct net_if *iface, return ret; } +#endif + +#if defined(CONFIG_NET_IPV4_IGMPV3) +static int igmpv3_send_generic(struct net_if *iface, struct net_if_mcast_addr *mcast) +{ + struct net_pkt *pkt; + int ret; + + pkt = net_pkt_alloc_with_buffer(iface, + IPV4_OPT_HDR_ROUTER_ALERT_LEN + + sizeof(struct net_ipv4_igmp_v3_report) + + sizeof(struct net_ipv4_igmp_v3_group_record) + + sizeof(struct in_addr) * mcast->sources_len, + AF_INET, IPPROTO_IGMP, PKT_WAIT_TIME); + if (!pkt) { + return -ENOMEM; + } + + ret = igmp_v3_create_packet(pkt, &igmp_multicast_addr, mcast, 1, NET_IPV4_IGMP_REPORT_V3); + if (ret < 0) { + goto drop; + } + + ret = igmp_send(pkt); + if (ret < 0) { + goto drop; + } + + return 0; + +drop: + net_pkt_unref(pkt); + + return ret; +} +#endif -int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr) +int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr, + const struct igmp_param *param) { struct net_if_mcast_addr *maddr; int ret; +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (param != NULL) { + if (param->sources_len > CONFIG_NET_IF_MCAST_IPV4_SOURCE_COUNT) { + return -ENOMEM; + } + } +#endif + maddr = net_if_ipv4_maddr_lookup(addr, &iface); if (maddr && net_if_ipv4_maddr_is_joined(maddr)) { return -EALREADY; @@ -298,18 +603,45 @@ int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr) } } +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (param != NULL) { + maddr->record_type = param->include ? IGMPV3_CHANGE_TO_INCLUDE_MODE + : IGMPV3_CHANGE_TO_EXCLUDE_MODE; + maddr->sources_len = param->sources_len; + for (int i = 0; i < param->sources_len; i++) { + net_ipaddr_copy(&maddr->sources[i].in_addr.s_addr, + ¶m->source_list[i].s_addr); + } + } else { + maddr->record_type = IGMPV3_CHANGE_TO_EXCLUDE_MODE; + } +#endif + + net_if_ipv4_maddr_join(iface, maddr); + +#if defined(CONFIG_NET_IPV4_IGMPV3) + ret = igmpv3_send_generic(iface, maddr); +#else ret = igmp_send_generic(iface, addr, true); +#endif if (ret < 0) { + net_if_ipv4_maddr_leave(iface, maddr); return ret; } - net_if_ipv4_maddr_join(iface, maddr); +#if defined(CONFIG_NET_IPV4_IGMPV3) + if (param != NULL) { + /* Updating the record type for further use after sending the join report */ + maddr->record_type = + param->include ? IGMPV3_MODE_IS_INCLUDE : IGMPV3_MODE_IS_EXCLUDE; + } +#endif net_if_mcast_monitor(iface, &maddr->address, true); - net_mgmt_event_notify_with_info(NET_EVENT_IPV4_MCAST_JOIN, iface, - &maddr->address.in_addr, + net_mgmt_event_notify_with_info(NET_EVENT_IPV4_MCAST_JOIN, iface, &maddr->address.in_addr, sizeof(struct in_addr)); + return ret; } @@ -323,21 +655,27 @@ int net_ipv4_igmp_leave(struct net_if *iface, const struct in_addr *addr) return -ENOENT; } - if (!net_if_ipv4_maddr_rm(iface, addr)) { - return -EINVAL; - } +#if defined(CONFIG_NET_IPV4_IGMPV3) + maddr->record_type = IGMPV3_CHANGE_TO_INCLUDE_MODE; + maddr->sources_len = 0; + ret = igmpv3_send_generic(iface, maddr); +#else ret = igmp_send_generic(iface, addr, false); +#endif if (ret < 0) { return ret; } + if (!net_if_ipv4_maddr_rm(iface, addr)) { + return -EINVAL; + } + net_if_ipv4_maddr_leave(iface, maddr); net_if_mcast_monitor(iface, &maddr->address, false); - net_mgmt_event_notify_with_info(NET_EVENT_IPV4_MCAST_LEAVE, iface, - &maddr->address.in_addr, + net_mgmt_event_notify_with_info(NET_EVENT_IPV4_MCAST_LEAVE, iface, &maddr->address.in_addr, sizeof(struct in_addr)); return ret; } diff --git a/subsys/net/ip/ipv4.h b/subsys/net/ip/ipv4.h index 1359d04bc03210a..1d7d64fd0b552a4 100644 --- a/subsys/net/ip/ipv4.h +++ b/subsys/net/ip/ipv4.h @@ -50,19 +50,72 @@ #define NET_IPV4_IGMP_REPORT_V3 0x22 /* v3 Membership report */ struct net_ipv4_igmp_v2_query { + /* IGMP message type */ uint8_t type; + /* Max response code */ uint8_t max_rsp; + /* 16-bit ones' complement of the entire message */ uint16_t chksum; + /* The multicast address being queried */ struct in_addr address; } __packed; struct net_ipv4_igmp_v2_report { + /* IGMP message type */ uint8_t type; + /* Max response code */ uint8_t max_rsp; + /* 16-bit ones' complement of the entire message */ uint16_t chksum; + /* The multicast address being queried */ struct in_addr address; } __packed; +struct net_ipv4_igmp_v3_query { + /* IGMP message type */ + uint8_t type; + /* Max response code */ + uint8_t max_rsp; + /* 16-bit ones' complement of the entire message */ + uint16_t chksum; + /* The multicast address being queried */ + struct in_addr address; + /* Reserved field, ignore */ + uint8_t reserved: 4; + /* Suppress Router-side Processing Flag */ + uint8_t suppress: 1; + /* Querier's Robustness Variable */ + uint8_t qrv: 3; + /* Querier's Query Interval Code */ + uint8_t qqic; + /* Number of Source Addresses */ + uint16_t sources_len; +} __packed; + +struct net_ipv4_igmp_v3_group_record { + /* Record type */ + uint8_t type; + /* Aux Data Len */ + uint8_t aux_len; + /* Number of Source Addresses */ + uint16_t sources_len; + /* The multicast address to report to*/ + struct in_addr address; +} __packed; + +struct net_ipv4_igmp_v3_report { + /* IGMP message type */ + uint8_t type; + /* Reserved field, ignore */ + uint8_t reserved_1; + /* 16-bit ones' complement of the entire message */ + uint16_t chksum; + /* Reserved field, ignore */ + uint16_t reserved_2; + /* Number of Group Records */ + uint16_t groups_len; +} __packed; + /** * @brief Create IPv4 packet in provided net_pkt with option to set all the * caller settable values. diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 2fd0928b170b7e2..73b15ae4cfa9f4d 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -235,7 +235,7 @@ enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr); #else #define net_ipv4_igmp_input(...) -#define net_calc_chksum_igmp(struct net_pkt *pkt) 0U +#define net_calc_chksum_igmp(pkt) 0U #endif /* CONFIG_NET_IPV4_IGMP */ static inline uint16_t net_calc_chksum_icmpv6(struct net_pkt *pkt) diff --git a/subsys/net/lib/dns/llmnr_responder.c b/subsys/net/lib/dns/llmnr_responder.c index e52e986d1455c6f..0c41b7df424ee60 100644 --- a/subsys/net/lib/dns/llmnr_responder.c +++ b/subsys/net/lib/dns/llmnr_responder.c @@ -118,7 +118,7 @@ static void llmnr_iface_event_handler(struct net_mgmt_event_callback *cb, { if (mgmt_event == NET_EVENT_IF_UP) { #if defined(CONFIG_NET_IPV4) - int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr); + int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr, NULL); if (ret < 0) { NET_DBG("Cannot add IPv4 multicast address to iface %p", @@ -592,7 +592,7 @@ static void iface_ipv4_cb(struct net_if *iface, void *user_data) struct in_addr *addr = user_data; int ret; - ret = net_ipv4_igmp_join(iface, addr); + ret = net_ipv4_igmp_join(iface, addr, NULL); if (ret < 0) { NET_DBG("Cannot add IPv4 multicast address to iface %p", iface); diff --git a/subsys/net/lib/dns/mdns_responder.c b/subsys/net/lib/dns/mdns_responder.c index 04acbabbecd17cc..4b8ad11dc1b3b05 100644 --- a/subsys/net/lib/dns/mdns_responder.c +++ b/subsys/net/lib/dns/mdns_responder.c @@ -94,7 +94,7 @@ static void mdns_iface_event_handler(struct net_mgmt_event_callback *cb, { if (mgmt_event == NET_EVENT_IF_UP) { #if defined(CONFIG_NET_IPV4) - int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr); + int ret = net_ipv4_igmp_join(iface, &local_addr4.sin_addr, NULL); if (ret < 0) { NET_DBG("Cannot add IPv4 multicast address to iface %p", @@ -634,7 +634,7 @@ static void iface_ipv4_cb(struct net_if *iface, void *user_data) struct in_addr *addr = user_data; int ret; - ret = net_ipv4_igmp_join(iface, addr); + ret = net_ipv4_igmp_join(iface, addr, NULL); if (ret < 0) { NET_DBG("Cannot add IPv4 multicast address to iface %p", iface); diff --git a/subsys/net/lib/shell/ipv4.c b/subsys/net/lib/shell/ipv4.c index 8fc88168c9a68cd..752b1cda0467f4b 100644 --- a/subsys/net/lib/shell/ipv4.c +++ b/subsys/net/lib/shell/ipv4.c @@ -118,7 +118,7 @@ static int cmd_net_ip_add(const struct shell *sh, size_t argc, char *argv[]) if (net_ipv4_is_addr_mcast(&addr)) { int ret; - ret = net_ipv4_igmp_join(iface, &addr); + ret = net_ipv4_igmp_join(iface, &addr, NULL); if (ret < 0) { PR_ERROR("Cannot %s multicast group %s for interface %d (%d)\n", "join", net_sprint_ipv4_addr(&addr), idx, ret); diff --git a/tests/net/igmp/src/main.c b/tests/net/igmp/src/main.c index 473b66d32413e89..ca43c33d164475c 100644 --- a/tests/net/igmp/src/main.c +++ b/tests/net/igmp/src/main.c @@ -236,7 +236,7 @@ static void join_group(void) { int ret; - ret = net_ipv4_igmp_join(net_iface, &mcast_addr); + ret = net_ipv4_igmp_join(net_iface, &mcast_addr, NULL); if (ignore_already) { zassert_true(ret == 0 || ret == -EALREADY, From a43e516ff2f7bc7091835bf9a97c979937a75366 Mon Sep 17 00:00:00 2001 From: Ibe Van de Veire Date: Tue, 21 Nov 2023 11:53:39 +0100 Subject: [PATCH 0834/1049] doc: migration guide: add note about IGMP migration Added note about the migration steps needed to support the new IGMP api. The api now expects an additional argument used for joining an IGMPv3 group. Signed-off-by: Ibe Van de Veire --- doc/releases/migration-guide-3.6.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index c4b93e5f150718e..aed44043e3fb2af 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -139,6 +139,13 @@ Networking ``request`` argument for :c:func:`coap_well_known_core_get` is made ``const``. (:github:`64265`) +* The IGMP multicast library now supports IGMPv3. This results in a minor change to the existing + api. The :c:func:`net_ipv4_igmp_join` now takes an additional argument of the type + ``const struct igmp_param *param``. This allows IGMPv3 to exclude/include certain groups of + addresses. If this functionality is not used or available (when using IGMPv2), you can safely pass + a NULL pointer. IGMPv3 can be enabled using the Kconfig ``CONFIG_NET_IPV4_IGMPV3``. + (:github:`65293`) + Other Subsystems ================ From a38c8d25e7b387ead1ded76d372c918e3147ba4c Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 21 Nov 2023 16:59:27 +0100 Subject: [PATCH 0835/1049] drivers: serial: stm32u5: Serial wakeup is based on autonomous capability On some devices such as STM32U5, there is no UART WKUP dedicated registers as the hardware block has an integrated autonomous wakeup capability. Hence it's capable to wake up the device from stop modes (down to Stop 1). This behavior relies on RCC UESM bit which is enabled by default at reset and not modified today in drivers. Since driver will not compile otherwise, remain in this simple configuration. This might be changed later on, if a need is seen to disable UESM bit. Signed-off-by: Erwan Gouriou --- drivers/serial/uart_stm32.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index dd79612322d70bf..097ba70c1b6cd4e 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1279,7 +1279,8 @@ static void uart_stm32_isr(const struct device *dev) uart_stm32_err_check(dev); #endif /* CONFIG_UART_ASYNC_API */ -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE) \ + && defined(USART_CR3_WUFIE) if (LL_USART_IsEnabledIT_WKUP(config->usart) && LL_USART_IsActiveFlag_WKUP(config->usart)) { @@ -2017,13 +2018,14 @@ static int uart_stm32_init(const struct device *dev) * CONFIG_PM_DEVICE=n : Always active * CONFIG_PM_DEVICE=y : Controlled by pm_device_wakeup_enable() */ - +#ifdef USART_CR3_WUFIE LL_USART_Disable(config->usart); LL_USART_SetWKUPType(config->usart, LL_USART_WAKEUP_ON_RXNE); LL_USART_EnableIT_WKUP(config->usart); LL_USART_ClearFlag_WKUP(config->usart); - LL_USART_EnableInStopMode(config->usart); LL_USART_Enable(config->usart); +#endif + LL_USART_EnableInStopMode(config->usart); if (config->wakeup_line != STM32_EXTI_LINE_NONE) { /* Prepare the WAKEUP with the expected EXTI line */ From 7be1a8119bfd43810aae71a04670e40c0cc4e04b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 21 Nov 2023 17:03:23 +0100 Subject: [PATCH 0836/1049] samples: stm32: serial_wakeup: b_u585i_iot02a support Add a sample overlay for b_u585i_iot02a Signed-off-by: Erwan Gouriou --- .../boards/b_u585i_iot02a.overlay | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay new file mode 100644 index 000000000000000..cce711c785c4454 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpu0{ + /* USART Wakeup requires automatic HSI16 switch on in deepsleep mode + * which isn't possible in Stop Mode 2. + * Remove Stop Mode 2 from supported modes + */ + cpu-power-states = <&stop0 &stop1>; +}; + +&usart1 { + /* Set domain clock to HSI to allow wakeup from Stop mode */ + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, + <&rcc STM32_SRC_HSI16 USART1_SEL(2)>; + + /* Configure device as wakeup source */ + wakeup-source; + + /* Configure sleep pinctrl configuration which will be used when + * device is not configured as wakeup source by the application. + * This use case is only applicable in PM_DEVICE mode. + */ + pinctrl-1 = <&analog_pa9 &analog_pa10>; + pinctrl-names = "default", "sleep"; +}; + +&clk_hsi { + /* Make sure HSI is enabled */ + status = "okay"; +}; From aedefd41d7acadcca61cc297d666b391d047e566 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 21 Nov 2023 10:42:47 -0800 Subject: [PATCH 0837/1049] tests/kernel/mem_protect/mem_map: Reduce printf size for qemu_x86_tiny qemu_x86_tiny has very limited memory resources; if too much text is included in this test, it will not have enough remaining memory to run it. When using picolibc before 1.8.5, the only way to get 'long long' support was to use the full version, including floating point support. This is too large for this testcase. Reduce the size of the printf code by switching to the version without 64-bit integer support. This allows the test to pass when using older picolibc versions, such as that included with SDK version 0.16.3. Signed-off-by: Keith Packard --- tests/kernel/mem_protect/mem_map/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/kernel/mem_protect/mem_map/testcase.yaml b/tests/kernel/mem_protect/mem_map/testcase.yaml index ff42310403befb8..860c76dcb6b7c9a 100644 --- a/tests/kernel/mem_protect/mem_map/testcase.yaml +++ b/tests/kernel/mem_protect/mem_map/testcase.yaml @@ -7,7 +7,9 @@ tests: kernel.memory_protection.mem_map: filter: CONFIG_MMU and not CONFIG_X86_64 extra_sections: _TRANSPLANTED_FUNC - extra_args: CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 + extra_configs: + - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 + - CONFIG_CBPRINTF_REDUCED_INTEGRAL=y platform_exclude: qemu_x86_64 integration_platforms: - qemu_x86 From 1dc6279d12ea81041c21c8e76d6eae6a2e17bba0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 21 Nov 2023 11:15:37 -0800 Subject: [PATCH 0838/1049] tests/subsys/logging/log_backend_uart: Reduce printf size When using picolibc before 1.8.5, the only way to get 'long long' support was to use the full version, including floating point support. This is too large for this testcase. Reduce the size of the printf code by switching to the version without 64-bit integer support. This allows the test to pass when using older picolibc versions, such as that included with SDK version 0.16.3. Signed-off-by: Keith Packard --- tests/subsys/logging/log_backend_uart/testcase.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/subsys/logging/log_backend_uart/testcase.yaml b/tests/subsys/logging/log_backend_uart/testcase.yaml index 05a4626ba628569..b28181b3d530bf6 100644 --- a/tests/subsys/logging/log_backend_uart/testcase.yaml +++ b/tests/subsys/logging/log_backend_uart/testcase.yaml @@ -12,5 +12,9 @@ common: tests: logging.backend.uart.single: extra_args: DTC_OVERLAY_FILE="./single.overlay" + extra_configs: + - CONFIG_CBPRINTF_REDUCED_INTEGRAL=y logging.backend.uart.multi: extra_args: DTC_OVERLAY_FILE="./multi.overlay" + extra_configs: + - CONFIG_CBPRINTF_REDUCED_INTEGRAL=y From 23408ac538741317471c17f83e430f06634d662e Mon Sep 17 00:00:00 2001 From: David Leach Date: Tue, 21 Nov 2023 16:27:44 -0600 Subject: [PATCH 0839/1049] drivers: eth_mcus: Conditionally wrap IPV4/6 code Regression failure introduced problem where driver code was not properly wrapping code that only existed when compiled for IPv4/v6 applications. Fixes #65549 Signed-off-by: David Leach --- drivers/ethernet/eth_mcux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/eth_mcux.c index f9ab95db9aa34cd..81edc564259db73 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/eth_mcux.c @@ -1163,6 +1163,7 @@ static int eth_init(const struct device *dev) return 0; } +#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) static void net_if_mcast_cb(struct net_if *iface, const struct net_addr *addr, bool is_joined) @@ -1185,15 +1186,18 @@ static void net_if_mcast_cb(struct net_if *iface, ENET_LeaveMulticastGroup(context->base, mac_addr.addr); } } +#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ static void eth_iface_init(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); struct eth_context *context = dev->data; +#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) static struct net_if_mcast_monitor mon; net_if_mcast_mon_register(&mon, iface, net_if_mcast_cb); +#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ net_if_set_link_addr(iface, context->mac_addr, sizeof(context->mac_addr), From bf6c2fcde81e0651ca0918820b52bfc2e182412f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 21 Nov 2023 13:26:36 -0800 Subject: [PATCH 0840/1049] samples/bluetooth/hci_ipc: Reduce printf size When using picolibc before 1.8.5, the only way to get 'long long' support was to use the full version, including floating point support. This is too large for this testcase. Reduce the size of the printf code by switching to the version without 64-bit integer support. This allows the test to pass when using older picolibc versions, such as that included with SDK version 0.16.3. Signed-off-by: Keith Packard --- samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf index e9e5ac634835f3e..f80f324be53e465 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf @@ -7,6 +7,7 @@ CONFIG_MAIN_STACK_SIZE=512 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 CONFIG_IPC_SERVICE_BACKEND_RPMSG_WQ_STACK_SIZE=512 CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_CBPRINTF_REDUCED_INTEGRAL=y CONFIG_BT=y CONFIG_BT_HCI_RAW=y From e1a14bad30bb89bf62000ce0a7d18bc1142bf078 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 19 Oct 2023 15:21:57 +0200 Subject: [PATCH 0841/1049] Bluetooth: audio: has: Add non-volatile settings This adds non-volatile settings for the HAS Server. Those are needed to restore the client awareness of preset list entries exposed by the server. Based on the settings, the implementation determines how to notify the client about the HAS related characteristic value changes. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/has.c | 108 ++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 21 deletions(-) diff --git a/subsys/bluetooth/audio/has.c b/subsys/bluetooth/audio/has.c index fc1aba7aec20297..6013cadd01452c5 100644 --- a/subsys/bluetooth/audio/has.c +++ b/subsys/bluetooth/audio/has.c @@ -15,6 +15,7 @@ #include #include "../bluetooth/host/hci_core.h" +#include "../bluetooth/host/settings.h" #include "audio_internal.h" #include "has_internal.h" @@ -298,8 +299,6 @@ static struct has_client *client_alloc(struct bt_conn *conn) } LOG_DBG("New client_context for %s", bt_addr_le_str(info.le.dst)); - } else { - LOG_DBG("Restored client_context for %s", bt_addr_le_str(info.le.dst)); } return client; @@ -508,26 +507,15 @@ static void bond_deleted_cb(uint8_t id, const bt_addr_le_t *addr) if (context != NULL) { context_free(context); } + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_settings_delete("has", 0, addr); + } } static struct bt_conn_auth_info_cb auth_info_cb = { .bond_deleted = bond_deleted_cb, }; - -static void restore_client_context(const struct bt_bond_info *info, void *user_data) -{ - struct client_context *context; - - context = context_alloc(&info->addr); - if (context == NULL) { - LOG_ERR("Failed to allocate client_context for %s", bt_addr_le_str(&info->addr)); - return; - } - - /* Notify all the characteristics values after reboot */ - atomic_set(context->flags, BONDED_CLIENT_INIT_FLAGS); -} - #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) @@ -868,10 +856,86 @@ static int bt_has_cp_generic_update(struct has_client *client, uint8_t prev_inde } } +#if defined(CONFIG_BT_SETTINGS) +struct client_context_store { + /* Last notified preset index */ + uint8_t last_preset_index_known; +} __packed; + +static int settings_set_cb(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) +{ + struct client_context_store store; + struct client_context *context; + bt_addr_le_t addr; + ssize_t len; + int err; + + if (!name) { + LOG_ERR("Insufficient number of arguments"); + return -EINVAL; + } + + err = bt_settings_decode_key(name, &addr); + if (err) { + LOG_ERR("Unable to decode address %s", name); + return -EINVAL; + } + + context = context_find(&addr); + if (context == NULL) { + /* Find and initialize a free entry */ + context = context_alloc(&addr); + if (context == NULL) { + LOG_ERR("Failed to allocate client_context for %s", bt_addr_le_str(&addr)); + return -ENOMEM; + } + } + + if (len_rd) { + len = read_cb(cb_arg, &store, sizeof(store)); + if (len < 0) { + LOG_ERR("Failed to decode value (err %zd)", len); + return len; + } + + context->last_preset_index_known = store.last_preset_index_known; + } else { + context->last_preset_index_known = 0x00; + } + + /* Notify all the characteristics values after reboot */ + atomic_set(context->flags, BONDED_CLIENT_INIT_FLAGS); + + return 0; +} + +BT_SETTINGS_DEFINE(has, "has", settings_set_cb, NULL); + +static void store_client_context(struct client_context *context) +{ + struct client_context_store store = { + .last_preset_index_known = context->last_preset_index_known, + }; + int err; + + LOG_DBG("%s last_preset_index_known 0x%02x", + bt_addr_le_str(&context->addr), store.last_preset_index_known); + + err = bt_settings_store("has", 0, &context->addr, &store, sizeof(store)); + if (err != 0) { + LOG_ERR("Failed to store err %d", err); + } +} +#else +#define store_client_context(...) +#endif /* CONFIG_BT_SETTINGS */ + static void update_last_preset_index_known(struct has_client *client, uint8_t index) { - if (client != NULL) { + if (client != NULL && client->context != NULL && + client->context->last_preset_index_known != index) { client->context->last_preset_index_known = index; + store_client_context(client->context); return; } @@ -879,8 +943,10 @@ static void update_last_preset_index_known(struct has_client *client, uint8_t in client = &has_client_list[i]; /* For each connected client */ - if (client->conn != NULL && client->context != NULL) { + if (client->conn != NULL && client->context != NULL && + client->context->last_preset_index_known != index) { client->context->last_preset_index_known = index; + store_client_context(client->context); } } } @@ -933,6 +999,8 @@ static int bt_has_cp_preset_record_deleted(struct has_client *client, uint8_t in NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) + sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t)); + LOG_DBG("client %p index 0x%02x", client, index); + preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_DELETED, BT_HAS_IS_LAST); net_buf_simple_add_u8(&buf, index); @@ -1709,8 +1777,6 @@ int bt_has_register(const struct bt_has_features_param *features) #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) bt_conn_auth_info_cb_register(&auth_info_cb); - - bt_foreach_bond(BT_ID_DEFAULT, restore_client_context, NULL); #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ has.registered = true; From 300746310eac1fbfdb6b7c916c39d876ec06cc92 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 31 Oct 2023 13:01:17 +0000 Subject: [PATCH 0842/1049] doc: mcumgr: smp_group_3: Fix rc text Fixes the "rc" text to include that it can also be returned when SMP version 2 is used to indicate an SMP error instead of a group error. Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/smp_groups/smp_group_3.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/services/device_mgmt/smp_groups/smp_group_3.rst b/doc/services/device_mgmt/smp_groups/smp_group_3.rst index c70897809e1c33f..0636e72e3f64977 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_3.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_3.rst @@ -132,7 +132,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Write setting request @@ -220,7 +220,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Delete setting command @@ -310,7 +310,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Commit settings command @@ -386,7 +386,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Load/Save settings command @@ -462,7 +462,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Save settings request @@ -532,7 +532,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+------------------------------------------------------------------------+ Settings access callback From 3613f94fdc4be895a6c5c711a5a8758b6f37da04 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 31 Oct 2023 13:04:30 +0000 Subject: [PATCH 0843/1049] doc: mcumgr: smp_group_63: Add zephyr mgmt group documentation Adds documentation describing the MCUmgr Zephyr management group and supported commands Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/index.rst | 1 + .../device_mgmt/smp_groups/smp_group_63.rst | 92 +++++++++++++++++++ doc/services/device_mgmt/smp_protocol.rst | 2 +- 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 doc/services/device_mgmt/smp_groups/smp_group_63.rst diff --git a/doc/services/device_mgmt/index.rst b/doc/services/device_mgmt/index.rst index 96ba59e4a0146ca..6094e49acc1cda7 100644 --- a/doc/services/device_mgmt/index.rst +++ b/doc/services/device_mgmt/index.rst @@ -28,3 +28,4 @@ SMP Groups smp_groups/smp_group_3.rst smp_groups/smp_group_8.rst smp_groups/smp_group_9.rst + smp_groups/smp_group_63.rst diff --git a/doc/services/device_mgmt/smp_groups/smp_group_63.rst b/doc/services/device_mgmt/smp_groups/smp_group_63.rst new file mode 100644 index 000000000000000..8d1f9015bcb1fc5 --- /dev/null +++ b/doc/services/device_mgmt/smp_groups/smp_group_63.rst @@ -0,0 +1,92 @@ +.. _mcumgr_smp_group_63: + +Zephyr Management Group +####################### + +Zephyr management group defines the following commands: + +.. table:: + :align: center + + +----------------+------------------------------+ + | ``Command ID`` | Command description | + +================+==============================+ + | ``0`` | Erase storage | + +----------------+------------------------------+ + +Erase storage command +********************* + +Erase storage command allows clearing the ``storage_partition`` flash partition on a device, +generally this is used when switching to a new application build if the application uses storage +that should be cleared (application dependent). + +Erase storage request +===================== + +Erase storage request header fields: + +.. table:: + :align: center + + +--------+--------------+----------------+ + | ``OP`` | ``Group ID`` | ``Command ID`` | + +========+==============+================+ + | ``2`` | ``63`` | ``0`` | + +--------+--------------+----------------+ + +The command sends sends empty CBOR map as data. + +Erase storage response +====================== + +Read setting response header fields: + +.. table:: + :align: center + + +--------+--------------+----------------+ + | ``OP`` | ``Group ID`` | ``Command ID`` | + +========+==============+================+ + | ``3`` | ``63`` | ``0`` | + +--------+--------------+----------------+ + +The command sends an empty CBOR map as data if successful. In case of error the CBOR data takes +the form: + +.. tabs:: + + .. group-tab:: SMP version 2 + + .. code-block:: none + + { + (str)"err" : { + (str)"group" : (uint) + (str)"rc" : (uint) + } + } + + .. group-tab:: SMP version 1 + + .. code-block:: none + + { + (str)"rc" : (int) + } + +where: + +.. table:: + :align: center + + +------------------+-------------------------------------------------------------------------+ + | "err" -> "group" | :c:enum:`mcumgr_group_t` group of the group-based error code. Only | + | | appears if an error is returned when using SMP version 2. | + +------------------+-------------------------------------------------------------------------+ + | "err" -> "rc" | contains the index of the group-based error code. Only appears if | + | | non-zero (error condition) when using SMP version 2. | + +------------------+-------------------------------------------------------------------------+ + | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | + | | using SMP version 1 or for SMP errors when using SMP version 2. | + +------------------+-------------------------------------------------------------------------+ diff --git a/doc/services/device_mgmt/smp_protocol.rst b/doc/services/device_mgmt/smp_protocol.rst index 44c30f32d29c97d..1ad4634d6e7bd30 100644 --- a/doc/services/device_mgmt/smp_protocol.rst +++ b/doc/services/device_mgmt/smp_protocol.rst @@ -141,7 +141,7 @@ groups. The following table presents a list of common groups: +---------------+-----------------------------------------------+ | ``9`` | :ref:`mcumgr_smp_group_9` | +---------------+-----------------------------------------------+ - | ``63`` | Zephyr specific basic commands group | + | ``63`` | :ref:`mcumgr_smp_group_63` | +---------------+-----------------------------------------------+ | ``64`` | This is the base group for defining | | | an application specific management groups. | From f03192f489aef8399e132f84f574811e7e9b85d8 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 31 Oct 2023 13:05:12 +0000 Subject: [PATCH 0844/1049] doc: mcumgr: Add missing Settings management text Adds that settings (config) management is supported to the list of supported command groups Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/mcumgr.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/services/device_mgmt/mcumgr.rst b/doc/services/device_mgmt/mcumgr.rst index f868aaceb17b64d..f16a77d43a9654f 100644 --- a/doc/services/device_mgmt/mcumgr.rst +++ b/doc/services/device_mgmt/mcumgr.rst @@ -12,9 +12,10 @@ The following management operations are available: * Image management * File System management * OS management +* Settings (config) management * Shell management * Statistic management -* Zephyr-basic management +* Zephyr management over the following transports: From 4ddbf51042808015f51b40453bb2381ffea92f0e Mon Sep 17 00:00:00 2001 From: "F. Ramu" Date: Thu, 16 Nov 2023 13:24:15 +0100 Subject: [PATCH 0845/1049] west.yml: update modules/hal/stm32/hal_stm32 for stm32h503 Update the stm32h5xx/drivers/include/ to enable the SAI, DelayBlock and DCACHE only if the instance exists in the soc. Which is not the case for stm32h503x device https://github.com/zephyrproject-rtos/hal_stm32/pull/181/ Signed-off-by: Francois Ramu --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 148471091948840..f1fd789503e6ad2 100644 --- a/west.yml +++ b/west.yml @@ -229,7 +229,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: 89ef0a3383edebf661073073bcdf6e2836fe90ee + revision: af2d314b6f7f87cfa8365009497132468ca3a686 path: modules/hal/stm32 groups: - hal From 65b6d2f18010dc999d9416d4c2acff54121d320e Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Fri, 17 Nov 2023 15:48:09 +0700 Subject: [PATCH 0846/1049] toolchain: esp32: fix cmake build issue with 'espressif' toolchain Change CROSS_COMPILE_TARGET to be defined based on CONFIG_SOC_SERIES. This fix adjusts CROSS_COMPILE_TARGET to ensure compatibility with the 'espressif' toolchain variant, following the changes in commit 6b57b3b786be. Signed-off-by: Pisit Sawangvonganan --- cmake/toolchain/espressif/target.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/toolchain/espressif/target.cmake b/cmake/toolchain/espressif/target.cmake index 35d2a01555a4a64..7d6f7eddf162e51 100644 --- a/cmake/toolchain/espressif/target.cmake +++ b/cmake/toolchain/espressif/target.cmake @@ -12,7 +12,7 @@ set(CROSS_COMPILE_TARGET_xtensa_esp32s2 xtensa-esp32s2-elf) set(CROSS_COMPILE_TARGET_xtensa_esp32s3 xtensa-esp32s3-elf) set(CROSS_COMPILE_TARGET_riscv_esp32c3 riscv32-esp-elf) -set(CROSS_COMPILE_TARGET ${CROSS_COMPILE_TARGET_${ARCH}_${CONFIG_SOC}}) +set(CROSS_COMPILE_TARGET ${CROSS_COMPILE_TARGET_${ARCH}_${CONFIG_SOC_SERIES}}) set(SYSROOT_TARGET ${CROSS_COMPILE_TARGET}) if(ESPRESSIF_DEPRECATED_PATH) From adcb2f580cedd21273cb71d1dbd2be2683e78cd5 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 17 Nov 2023 13:12:24 +0000 Subject: [PATCH 0847/1049] input: gpio_kbd_matrix: define a type for the row data Add a typedef for the row type rather than using uint8_t directly, this allow supporting bigger matrix as an option by using a different type. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 2 +- drivers/input/input_ite_it8xxx2_kbd.c | 2 +- drivers/input/input_kbd_matrix.c | 22 ++++++++++----------- drivers/input/input_npcx_kbd.c | 2 +- include/zephyr/input/input_kbd_matrix.h | 26 +++++++++++++++---------- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index 9d532bfd0af0db2..f81a01837f9ad11 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -64,7 +64,7 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) data->last_col_state = state; } -static int gpio_kbd_matrix_read_row(const struct device *dev) +static kbd_row_t gpio_kbd_matrix_read_row(const struct device *dev) { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; diff --git a/drivers/input/input_ite_it8xxx2_kbd.c b/drivers/input/input_ite_it8xxx2_kbd.c index 8d688d42db1531f..5e62e6ee32e1a43 100644 --- a/drivers/input/input_ite_it8xxx2_kbd.c +++ b/drivers/input/input_ite_it8xxx2_kbd.c @@ -79,7 +79,7 @@ static void it8xxx2_kbd_drive_column(const struct device *dev, int col) } } -static int it8xxx2_kbd_read_row(const struct device *dev) +static kbd_row_t it8xxx2_kbd_read_row(const struct device *dev) { const struct it8xxx2_kbd_config *const config = dev->config; struct kscan_it8xxx2_regs *const inst = config->base; diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 6005a76b3b332ed..07e3c4c05456aa2 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -16,8 +16,6 @@ LOG_MODULE_REGISTER(input_kbd_matrix, CONFIG_INPUT_LOG_LEVEL); -#define INPUT_KBD_MATRIX_ROW_MASK UINT8_MAX - void input_kbd_matrix_poll_start(const struct device *dev) { struct input_kbd_matrix_common_data *data = dev->data; @@ -28,7 +26,7 @@ void input_kbd_matrix_poll_start(const struct device *dev) static bool input_kbd_matrix_ghosting(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; - const uint8_t *state = cfg->matrix_new_state; + const kbd_row_t *state = cfg->matrix_new_state; /* * Matrix keyboard designs are suceptible to ghosting. @@ -59,7 +57,7 @@ static bool input_kbd_matrix_ghosting(const struct device *dev) * using z&(z-1) which is non-zero only if z has more * than one bit set. */ - uint8_t common_row_bits = state[c] & state[c_next]; + kbd_row_t common_row_bits = state[c] & state[c_next]; if (common_row_bits & (common_row_bits - 1)) { return true; @@ -74,8 +72,8 @@ static bool input_kbd_matrix_scan(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; const struct input_kbd_matrix_api *api = cfg->api; - int row; - uint8_t key_event = 0U; + kbd_row_t row; + kbd_row_t key_event = 0U; for (int col = 0; col < cfg->col_size; col++) { api->drive_column(dev, col); @@ -83,7 +81,7 @@ static bool input_kbd_matrix_scan(const struct device *dev) /* Allow the matrix to stabilize before reading it */ k_busy_wait(cfg->settle_time_us); - row = api->read_row(dev) & INPUT_KBD_MATRIX_ROW_MASK; + row = api->read_row(dev); cfg->matrix_new_state[col] = row; key_event |= row; } @@ -97,10 +95,10 @@ static void input_kbd_matrix_update_state(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; struct input_kbd_matrix_common_data *data = dev->data; - uint8_t *matrix_new_state = cfg->matrix_new_state; + kbd_row_t *matrix_new_state = cfg->matrix_new_state; uint32_t cycles_now; - uint8_t row_changed; - uint8_t deb_col; + kbd_row_t row_changed; + kbd_row_t deb_col; cycles_now = k_cycle_get_32(); @@ -143,8 +141,8 @@ static void input_kbd_matrix_update_state(const struct device *dev) /* Debouncing for each row key occurs here */ for (int r = 0; r < cfg->row_size; r++) { - uint8_t mask = BIT(r); - uint8_t row_bit = matrix_new_state[c] & mask; + kbd_row_t mask = BIT(r); + kbd_row_t row_bit = matrix_new_state[c] & mask; /* Continue if we already debounce a key */ if (!(deb_col & mask)) { diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index 64cde93bda9e4fd..25f28e3e60ec0fe 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -97,7 +97,7 @@ static void npcx_kbd_drive_column(const struct device *dev, int col) inst->KBSOUT1 = ((mask >> 16) & 0x03); } -static int npcx_kbd_read_row(const struct device *dev) +static kbd_row_t npcx_kbd_read_row(const struct device *dev) { const struct npcx_kbd_config *config = dev->config; const struct input_kbd_matrix_common_config *common = &config->common; diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 0566f14d2cdc2bb..98bd791d49a7b1f 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -29,6 +29,12 @@ /** Number of tracked scan cycles */ #define INPUT_KBD_MATRIX_SCAN_OCURRENCES 30U +/** Row entry data type */ +typedef uint8_t kbd_row_t; + +/** Maximum number of rows */ +#define INPUT_KBD_MATRIX_ROW_BITS NUM_BITS(kbd_row_t) + /** * @brief Keyboard matrix internal APIs. */ @@ -49,7 +55,7 @@ struct input_kbd_matrix_api { * * @param dev Pointer to the keyboard matrix device. */ - int (*read_row)(const struct device *dev); + kbd_row_t (*read_row)(const struct device *dev); /** * @brief Request to put the matrix in detection mode. * @@ -80,10 +86,10 @@ struct input_kbd_matrix_common_config { bool ghostkey_check; /* extra data pointers */ - uint8_t *matrix_stable_state; - uint8_t *matrix_unstable_state; - uint8_t *matrix_previous_state; - uint8_t *matrix_new_state; + kbd_row_t *matrix_stable_state; + kbd_row_t *matrix_unstable_state; + kbd_row_t *matrix_previous_state; + kbd_row_t *matrix_new_state; uint8_t *scan_cycle_idx; }; @@ -96,12 +102,12 @@ struct input_kbd_matrix_common_config { * specify row and col count. */ #define INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL(node_id, _row_size, _col_size) \ - BUILD_ASSERT(IN_RANGE(_row_size, 1, 8), "invalid row-size"); \ + BUILD_ASSERT(IN_RANGE(_row_size, 1, INPUT_KBD_MATRIX_ROW_BITS), "invalid row-size"); \ BUILD_ASSERT(IN_RANGE(_col_size, 1, UINT8_MAX), "invalid col-size"); \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state)[_col_size]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state)[_col_size]; \ static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx)[_row_size * _col_size]; /** From f9ed74e0d5836c6cfe60d604e66c3aeff40f799e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 17 Nov 2023 13:22:30 +0000 Subject: [PATCH 0848/1049] input: gpio_kbd_matrix: add 16 bit rows support Add a Kconfig option to extend the row type to 16 bits, allowing the library to handle a 16 row matrix. Signed-off-by: Fabio Baltieri --- drivers/input/Kconfig.kbd_matrix | 6 ++++++ include/zephyr/input/input_kbd_matrix.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix index 5d1328a227ff064..002c7f3cb8a2f19 100644 --- a/drivers/input/Kconfig.kbd_matrix +++ b/drivers/input/Kconfig.kbd_matrix @@ -14,4 +14,10 @@ config INPUT_KBD_MATRIX_THREAD_STACK_SIZE help Size of the stack used for the keyboard matrix thread. +config INPUT_KBD_MATRIX_16_BIT_ROW + bool "16 bit row size support" + help + Use a 16 bit type for the internal structure, allow using a matrix + with up to 16 rows if the driver supports it. + endif # INPUT_KBD_MATRIX diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 98bd791d49a7b1f..a8e85b088553f35 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -30,7 +30,11 @@ #define INPUT_KBD_MATRIX_SCAN_OCURRENCES 30U /** Row entry data type */ +#if CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW +typedef uint16_t kbd_row_t; +#else typedef uint8_t kbd_row_t; +#endif /** Maximum number of rows */ #define INPUT_KBD_MATRIX_ROW_BITS NUM_BITS(kbd_row_t) From 5e10cd9aeedb4a8ccc78927ff4c24152c57d4b80 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 17 Nov 2023 13:54:13 +0000 Subject: [PATCH 0849/1049] tests: build_all: input: test the 16 bit row option Add a test case for the 16 bit row size option. Signed-off-by: Fabio Baltieri --- tests/drivers/build_all/input/testcase.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/drivers/build_all/input/testcase.yaml b/tests/drivers/build_all/input/testcase.yaml index 32fe44b883f2275..2831b693e28b013 100644 --- a/tests/drivers/build_all/input/testcase.yaml +++ b/tests/drivers/build_all/input/testcase.yaml @@ -13,3 +13,7 @@ tests: - CONFIG_INPUT_CST816S_INTERRUPT=n - CONFIG_INPUT_FT5336_INTERRUPT=y - CONFIG_INPUT_GT911_INTERRUPT=y + + drivers.input.kbd_16_bit: + extra_configs: + - CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW=y From 71db6550cd5511ad9814477409fc47c237cf9efd Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 11:39:12 +0100 Subject: [PATCH 0850/1049] native simulator: Get latest from upstream Align with native_simulator's upstream main 7d652dbfb313260cf07d595ccf26638f2b3c2959 Which includes: * 7d652db Provide macros for noreturn and unreachable & annotate Signed-off-by: Alberto Escolar Piedras --- scripts/native_simulator/common/src/include/nsi_main.h | 4 +++- scripts/native_simulator/common/src/include/nsi_utils.h | 4 ++++ scripts/native_simulator/common/src/main.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/native_simulator/common/src/include/nsi_main.h b/scripts/native_simulator/common/src/include/nsi_main.h index 83ba8cac4330ccf..33508edb7fe9953 100644 --- a/scripts/native_simulator/common/src/include/nsi_main.h +++ b/scripts/native_simulator/common/src/include/nsi_main.h @@ -7,6 +7,8 @@ #ifndef NSI_COMMON_SRC_INCL_NSI_MAIN_H #define NSI_COMMON_SRC_INCL_NSI_MAIN_H +#include "nsi_utils.h" + #ifdef __cplusplus extern "C" { #endif @@ -31,7 +33,7 @@ int nsi_exit_inner(int exit_code); * Note that other components may have requested a different * exit code which may have precedence if it was !=0 */ -void nsi_exit(int exit_code); +NSI_FUNC_NORETURN void nsi_exit(int exit_code); #ifdef __cplusplus } diff --git a/scripts/native_simulator/common/src/include/nsi_utils.h b/scripts/native_simulator/common/src/include/nsi_utils.h index f41fdf9ddc8de1e..996ad635409187f 100644 --- a/scripts/native_simulator/common/src/include/nsi_utils.h +++ b/scripts/native_simulator/common/src/include/nsi_utils.h @@ -25,4 +25,8 @@ #define NSI_ARG_UNUSED(x) (void)(x) #endif +#define NSI_CODE_UNREACHABLE __builtin_unreachable() + +#define NSI_FUNC_NORETURN __attribute__((__noreturn__)) + #endif /* NSI_COMMON_SRC_INCL_NSI_UTILS_H */ diff --git a/scripts/native_simulator/common/src/main.c b/scripts/native_simulator/common/src/main.c index ffe1d3b93d19437..b9d97c917489655 100644 --- a/scripts/native_simulator/common/src/main.c +++ b/scripts/native_simulator/common/src/main.c @@ -44,7 +44,7 @@ int nsi_exit_inner(int exit_code) return max_exit_code; } -void nsi_exit(int exit_code) +NSI_FUNC_NORETURN void nsi_exit(int exit_code) { exit(nsi_exit_inner(exit_code)); } From ab896ad6efcbaad7c8cbb0beff8d3faf935ba908 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 11:41:57 +0100 Subject: [PATCH 0851/1049] arch posix: annotate posix_exit and nsi_exit as noreturn Annotate posix_exit() and nsi_exit() as noreturn mainly to ease the life of static analysis tools. Signed-off-by: Alberto Escolar Piedras --- arch/posix/core/nsi_compat/nsi_compat.c | 7 ++++--- soc/posix/inf_clock/posix_board_if.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/posix/core/nsi_compat/nsi_compat.c b/arch/posix/core/nsi_compat/nsi_compat.c index cd338ca1e4f2114..eccf419efb1bbe0 100644 --- a/arch/posix/core/nsi_compat/nsi_compat.c +++ b/arch/posix/core/nsi_compat/nsi_compat.c @@ -13,6 +13,8 @@ */ #include +#include +#include "posix_board_if.h" void nsi_print_error_and_exit(const char *format, ...) { @@ -41,9 +43,8 @@ void nsi_print_trace(const char *format, ...) va_end(variable_args); } -void nsi_exit(int exit_code) +FUNC_NORETURN void nsi_exit(int exit_code) { - extern void posix_exit(int exit_code); - posix_exit(exit_code); + CODE_UNREACHABLE; } diff --git a/soc/posix/inf_clock/posix_board_if.h b/soc/posix/inf_clock/posix_board_if.h index 1d851fb3935c177..49384530e14e41c 100644 --- a/soc/posix/inf_clock/posix_board_if.h +++ b/soc/posix/inf_clock/posix_board_if.h @@ -7,6 +7,7 @@ #define _POSIX_CORE_BOARD_PROVIDED_IF_H #include +#include /* * This file lists the functions the posix "inf_clock" soc @@ -22,7 +23,7 @@ extern "C" { #endif void posix_irq_handler(void); -void posix_exit(int exit_code); +FUNC_NORETURN void posix_exit(int exit_code); uint64_t posix_get_hw_cycle(void); void posix_cpu_hold(uint32_t usec_to_waste); From c3b7159cdf7680affd8314bd0e5454e27081fd0c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:17:43 +0100 Subject: [PATCH 0852/1049] tests/bluetooth/mesh: Enable for native_sim Enable this tests for native_sim and switch the default integration platform to be native_sim from native_posix Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/mesh/blob_io_flash/testcase.yaml | 6 ++++-- tests/bluetooth/mesh/rpl/testcase.yaml | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/bluetooth/mesh/blob_io_flash/testcase.yaml b/tests/bluetooth/mesh/blob_io_flash/testcase.yaml index 3bc3651f5ccd096..c27ea3081af9017 100644 --- a/tests/bluetooth/mesh/blob_io_flash/testcase.yaml +++ b/tests/bluetooth/mesh/blob_io_flash/testcase.yaml @@ -1,8 +1,10 @@ tests: bluetooth.mesh.blob_io_flash: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: - bluetooth - mesh integration_platforms: - - native_posix + - native_sim diff --git a/tests/bluetooth/mesh/rpl/testcase.yaml b/tests/bluetooth/mesh/rpl/testcase.yaml index e1f1d5323bf4aa4..16b947fe626b691 100644 --- a/tests/bluetooth/mesh/rpl/testcase.yaml +++ b/tests/bluetooth/mesh/rpl/testcase.yaml @@ -1,8 +1,10 @@ tests: bluetooth.mesh.rpl: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: - bluetooth - mesh integration_platforms: - - native_posix + - native_sim From fd6f473515a58ab0cd9502f65639fa96cc07db6b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:24:49 +0100 Subject: [PATCH 0853/1049] tests/bluetooth/ctrl_isoal: Remove instructions from header comment How to run tests is described in the twister documentation, let's not replicate that kind of instructions in all files. Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/ctrl_isoal/src/isoal_test_common.c | 5 ----- tests/bluetooth/ctrl_isoal/src/isoal_test_common.h | 5 ----- tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c | 5 ----- tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h | 5 ----- tests/bluetooth/ctrl_isoal/src/main.c | 5 ----- tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c | 5 ----- tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c | 5 ----- 7 files changed, 35 deletions(-) diff --git a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.c b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.c index 359476563363005..32536201a3a01c4 100644 --- a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.c +++ b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.c @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #include diff --git a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h index 730cb2e6f40af5f..d9a6f14664862e6 100644 --- a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h +++ b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h @@ -2,11 +2,6 @@ * Copyright (c) 2022 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #ifndef _ISOAL_TEST_COMMON_H_ diff --git a/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c b/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c index 084677cf4621484..d990a2b96299335 100644 --- a/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c +++ b/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.c @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #include diff --git a/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h b/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h index 5fc535a080661dd..85465a9c539b86f 100644 --- a/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h +++ b/tests/bluetooth/ctrl_isoal/src/isoal_test_debug.h @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #ifndef _ISOAL_TEST_DEBUG_H_ diff --git a/tests/bluetooth/ctrl_isoal/src/main.c b/tests/bluetooth/ctrl_isoal/src/main.c index 8cbd36c509a2d20..7c0747b3639f743 100644 --- a/tests/bluetooth/ctrl_isoal/src/main.c +++ b/tests/bluetooth/ctrl_isoal/src/main.c @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ #include diff --git a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c index fdb86af1f5c5b2e..06407816c38e1c0 100644 --- a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c +++ b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c @@ -2,11 +2,6 @@ * Copyright (c) 2022 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ FAKE_VALUE_FUNC(isoal_status_t, diff --git a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c index c9a6fe67637b7a7..a8749a7909b19f4 100644 --- a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c +++ b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_tx.c @@ -2,11 +2,6 @@ * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 - * - * Run this test from zephyr directory as: - * - * ./scripts/twister --coverage -p native_posix -v -T tests/bluetooth/ctrl_isoal/ - * */ /* Each segment header in a test would usually be written to when it is first From 53103b9a65a67ea55ce5c8b31619fc10a2460fcc Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:57:34 +0100 Subject: [PATCH 0854/1049] tests/bluetooth/shell: Enable for native_sim Enable these tests for native_sim and switch the default integration platform from native_posix to native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/shell/boards/native_sim.conf | 16 +++++ .../bluetooth/shell/boards/native_sim_64.conf | 16 +++++ tests/bluetooth/shell/testcase.yaml | 58 +++++-------------- 3 files changed, 47 insertions(+), 43 deletions(-) create mode 100644 tests/bluetooth/shell/boards/native_sim.conf create mode 100644 tests/bluetooth/shell/boards/native_sim_64.conf diff --git a/tests/bluetooth/shell/boards/native_sim.conf b/tests/bluetooth/shell/boards/native_sim.conf new file mode 100644 index 000000000000000..a2ab2f4e87a5ff2 --- /dev/null +++ b/tests/bluetooth/shell/boards/native_sim.conf @@ -0,0 +1,16 @@ +CONFIG_NO_OPTIMIZATIONS=y +# Allows for copying larger amount of data into the shell +CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE=4096 + +# For native posix k_sleep is used in the data path as well as for shell input +# detection, hence data processing is at least two ticks per packet. To support +# 5ms ISO interval bidirectional data the system shall never stall for more +# than 1.5 ms in average. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=500 + +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y +# The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence +# inctease stack size for that thread. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/bluetooth/shell/boards/native_sim_64.conf b/tests/bluetooth/shell/boards/native_sim_64.conf new file mode 100644 index 000000000000000..a2ab2f4e87a5ff2 --- /dev/null +++ b/tests/bluetooth/shell/boards/native_sim_64.conf @@ -0,0 +1,16 @@ +CONFIG_NO_OPTIMIZATIONS=y +# Allows for copying larger amount of data into the shell +CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE=4096 + +# For native posix k_sleep is used in the data path as well as for shell input +# detection, hence data processing is at least two ticks per packet. To support +# 5ms ISO interval bidirectional data the system shall never stall for more +# than 1.5 ms in average. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=500 + +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y +# The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence +# inctease stack size for that thread. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index 4b46c8d6781f80b..9dae1a53868e529 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -1,3 +1,10 @@ +common: + # Default platform_allow & integration_platforms for the tests below, which a few override + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tests: bluetooth.shell.main: extra_configs: @@ -6,6 +13,8 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - nrf52840dk_nrf52840 integration_platforms: - qemu_x86 @@ -21,9 +30,11 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - nrf52840dk_nrf52840 integration_platforms: - - native_posix + - native_sim platform_exclude: nrf52dk_nrf52810 tags: bluetooth harness: keyboard @@ -37,19 +48,19 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim platform_exclude: nrf52dk_nrf52810 tags: bluetooth harness: keyboard bluetooth.shell.no_privacy: build_only: true extra_args: CONFIG_BT_PRIVACY=n - platform_allow: native_posix tags: bluetooth bluetooth.shell.log_defaults: build_only: true - platform_allow: native_posix extra_args: CONF_FILE="log.conf" tags: bluetooth @@ -57,19 +68,16 @@ tests: bluetooth.shell.audio: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix tags: bluetooth bluetooth.shell.audio.no_vcs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_REND=n tags: bluetooth bluetooth.shell.audio.no_vocs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VOCS_MAX_INSTANCE_COUNT=0 - CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT=0 @@ -77,7 +85,6 @@ tests: bluetooth.shell.audio.no_aics: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_AICS_MAX_INSTANCE_COUNT=0 - CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT=0 @@ -86,7 +93,6 @@ tests: bluetooth.shell.audio.no_aics_vocs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VOCS_MAX_INSTANCE_COUNT=0 - CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT=0 @@ -97,14 +103,12 @@ tests: bluetooth.shell.audio.no_vcp_vol_ctlr: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_CTLR=n tags: bluetooth bluetooth.shell.audio.no_vcs_vcp_vol_ctlr: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_REND=n - CONFIG_BT_VCP_VOL_CTLR=n @@ -112,35 +116,30 @@ tests: bluetooth.shell.audio.vcp_vol_ctlr_no_aics_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST=0 tags: bluetooth bluetooth.shell.audio.vcp_vol_ctlr_no_vocs_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST=0 tags: bluetooth bluetooth.shell.audio.no_micp_mic_dev: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MICP_MIC_DEV=n tags: bluetooth bluetooth.shell.audio.no_micp_mic_ctlr: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MICP_MIC_CTLR=n tags: bluetooth bluetooth.shell.audio.no_micp_mic_dev_micp_mic_ctlr: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MICP_MIC_DEV=n - CONFIG_BT_MICP_MIC_CTLR=n @@ -148,42 +147,36 @@ tests: bluetooth.shell.audio.micp_mic_ctlr_no_aics_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST=0 tags: bluetooth bluetooth.shell.audio.no_mcs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MCS=n tags: bluetooth bluetooth.shell.audio.no_mcc: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MCC=n tags: bluetooth bluetooth.shell.audio.no_ots: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_OTS=n tags: bluetooth bluetooth.shell.audio.no_mcc_ots: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_MCC_OTS=n tags: bluetooth bluetooth.shell.audio.no_otsc: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_OTS=n - CONFIG_BT_MCC_OTS=n @@ -191,68 +184,57 @@ tests: bluetooth.audio_shell.no_pac_snk: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_PAC_SNK=n bluetooth.audio_shell.no_pac_src: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_PAC_SRC=n bluetooth.audio_shell.no_unicast_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_UNICAST_CLIENT=n bluetooth.audio_shell.no_unicast_server: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_UNICAST_SERVER=n - CONFIG_BT_HAS=n bluetooth.audio_shell.no_server_ase_snk: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_ASCS_ASE_SNK_COUNT=0 bluetooth.audio_shell.no_server_ase_src: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_ASCS_ASE_SRC_COUNT=0 bluetooth.audio_shell.no_client_ase_snk: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=0 bluetooth.audio_shell.no_client_ase_src: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=0 bluetooth.audio_shell.no_broadcast_source: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_BROADCAST_SOURCE=n bluetooth.audio_shell.no_broadcast_sink: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_BROADCAST_SINK=n bluetooth.audio_shell.no_audio_tx: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_BROADCAST_SOURCE=n - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=0 @@ -260,7 +242,6 @@ tests: bluetooth.audio_shell.no_audio_rx: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_BAP_BROADCAST_SINK=n - CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=0 @@ -268,26 +249,22 @@ tests: bluetooth.audio_shell.no_has: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_HAS=n bluetooth.audio_shell.no_has_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_HAS_CLIENT=n bluetooth.shell.audio.no_tbs: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_TBS=n tags: bluetooth bluetooth.shell.audio.no_tbs_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_TBS_CLIENT_TBS=n - CONFIG_BT_TBS_CLIENT_GTBS=n @@ -295,32 +272,27 @@ tests: bluetooth.shell.audio.tbs_only_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_TBS_CLIENT_GTBS=n tags: bluetooth bluetooth.shell.audio.gtbs_only_client: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_TBS_CLIENT_TBS=n tags: bluetooth bluetooth.audio_shell.no_cap_acceptor: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_CAP_ACCEPTOR=n bluetooth.audio_shell.no_cap_acceptor_set_member: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER=n bluetooth.audio_shell.no_cap_initiator: extra_args: CONF_FILE="audio.conf" build_only: true - platform_allow: native_posix extra_configs: - CONFIG_BT_CAP_INITIATOR=n From ed2251ae751e7b1109a0f525ca7807dcb32a4579 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:03:07 +0100 Subject: [PATCH 0855/1049] tests/bluetooth/hci_uart_async: Switch to native_sim Switch from native_posix to native_sim as default test platform And add overlays for native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/hci_uart_async/boards/native_posix.conf | 2 +- tests/bluetooth/hci_uart_async/boards/native_sim.conf | 3 +++ tests/bluetooth/hci_uart_async/testcase.yaml | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/bluetooth/hci_uart_async/boards/native_sim.conf diff --git a/tests/bluetooth/hci_uart_async/boards/native_posix.conf b/tests/bluetooth/hci_uart_async/boards/native_posix.conf index e638cd6a0efa62a..d9130d07be5bd25 100644 --- a/tests/bluetooth/hci_uart_async/boards/native_posix.conf +++ b/tests/bluetooth/hci_uart_async/boards/native_posix.conf @@ -1,3 +1,3 @@ -# Print logs and test results on stdout. For some reason, this not the +# Print logs and test results on stdout as this not the # default when SERIAL=y. CONFIG_LOG_BACKEND_NATIVE_POSIX=y diff --git a/tests/bluetooth/hci_uart_async/boards/native_sim.conf b/tests/bluetooth/hci_uart_async/boards/native_sim.conf new file mode 100644 index 000000000000000..d9130d07be5bd25 --- /dev/null +++ b/tests/bluetooth/hci_uart_async/boards/native_sim.conf @@ -0,0 +1,3 @@ +# Print logs and test results on stdout as this not the +# default when SERIAL=y. +CONFIG_LOG_BACKEND_NATIVE_POSIX=y diff --git a/tests/bluetooth/hci_uart_async/testcase.yaml b/tests/bluetooth/hci_uart_async/testcase.yaml index 31b7ac8bde485f1..8df5113b354cd52 100644 --- a/tests/bluetooth/hci_uart_async/testcase.yaml +++ b/tests/bluetooth/hci_uart_async/testcase.yaml @@ -6,3 +6,6 @@ tests: harness: ztest platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim From 6c9dfe1b2c1821d86693cb4d1100d884584060b4 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:00:59 +0100 Subject: [PATCH 0856/1049] tests/bluetooth/*: Enable for native_sim Enable all remaining bluetooth tests for native_sim and switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/bluetooth/addr/testcase.yaml | 4 +++- tests/bluetooth/bluetooth/testcase.yaml | 2 ++ tests/bluetooth/bt_crypto/testcase.yaml | 4 +++- tests/bluetooth/bt_crypto_ccm/testcase.yaml | 4 +++- tests/bluetooth/ctrl_isoal/testcase.yaml | 6 +++++- tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml | 6 +++++- tests/bluetooth/gatt/testcase.yaml | 4 +++- tests/bluetooth/hci_prop_evt/testcase.yaml | 4 +++- tests/bluetooth/host_long_adv_recv/testcase.yaml | 4 +++- tests/bluetooth/l2cap/testcase.yaml | 4 +++- tests/bluetooth/uuid/testcase.yaml | 4 +++- 11 files changed, 36 insertions(+), 10 deletions(-) diff --git a/tests/bluetooth/addr/testcase.yaml b/tests/bluetooth/addr/testcase.yaml index 8a803c14d40f173..736d4b5a2badc52 100644 --- a/tests/bluetooth/addr/testcase.yaml +++ b/tests/bluetooth/addr/testcase.yaml @@ -3,10 +3,12 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 tags: - bluetooth - addr integration_platforms: - - native_posix + - native_sim diff --git a/tests/bluetooth/bluetooth/testcase.yaml b/tests/bluetooth/bluetooth/testcase.yaml index d423b0515399970..7f8ac6108219022 100644 --- a/tests/bluetooth/bluetooth/testcase.yaml +++ b/tests/bluetooth/bluetooth/testcase.yaml @@ -5,6 +5,8 @@ tests: - qemu_cortex_m3 - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - qemu_x86 tags: bluetooth diff --git a/tests/bluetooth/bt_crypto/testcase.yaml b/tests/bluetooth/bt_crypto/testcase.yaml index 4c24d9fb05cb641..5de0839b29ee305 100644 --- a/tests/bluetooth/bt_crypto/testcase.yaml +++ b/tests/bluetooth/bt_crypto/testcase.yaml @@ -3,8 +3,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim tags: bluetooth diff --git a/tests/bluetooth/bt_crypto_ccm/testcase.yaml b/tests/bluetooth/bt_crypto_ccm/testcase.yaml index 119ff184f42cf2c..b1827e56aff4641 100644 --- a/tests/bluetooth/bt_crypto_ccm/testcase.yaml +++ b/tests/bluetooth/bt_crypto_ccm/testcase.yaml @@ -3,6 +3,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: bluetooth diff --git a/tests/bluetooth/ctrl_isoal/testcase.yaml b/tests/bluetooth/ctrl_isoal/testcase.yaml index 9b7b4a1f06a6d16..d638f089b3dbb7f 100644 --- a/tests/bluetooth/ctrl_isoal/testcase.yaml +++ b/tests/bluetooth/ctrl_isoal/testcase.yaml @@ -2,4 +2,8 @@ common: tags: bluetooth tests: bluetooth.isoal.test: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml b/tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml index a965acfbcae329c..7dd0dcbc16efea0 100644 --- a/tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml +++ b/tests/bluetooth/ctrl_sw_privacy_unit/testcase.yaml @@ -2,4 +2,8 @@ common: tags: bluetooth tests: bluetooth.privacy.test: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/bluetooth/gatt/testcase.yaml b/tests/bluetooth/gatt/testcase.yaml index 5acd783861008c3..9a02af34de0e2f7 100644 --- a/tests/bluetooth/gatt/testcase.yaml +++ b/tests/bluetooth/gatt/testcase.yaml @@ -3,10 +3,12 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - gatt diff --git a/tests/bluetooth/hci_prop_evt/testcase.yaml b/tests/bluetooth/hci_prop_evt/testcase.yaml index 457414d5082d469..6f41a722e80a99d 100644 --- a/tests/bluetooth/hci_prop_evt/testcase.yaml +++ b/tests/bluetooth/hci_prop_evt/testcase.yaml @@ -5,8 +5,10 @@ tests: - qemu_cortex_m3 - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - hci diff --git a/tests/bluetooth/host_long_adv_recv/testcase.yaml b/tests/bluetooth/host_long_adv_recv/testcase.yaml index 708bef794c862da..a94b021d1ef4764 100644 --- a/tests/bluetooth/host_long_adv_recv/testcase.yaml +++ b/tests/bluetooth/host_long_adv_recv/testcase.yaml @@ -3,8 +3,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - host diff --git a/tests/bluetooth/l2cap/testcase.yaml b/tests/bluetooth/l2cap/testcase.yaml index 39b7164a37fb298..18a2fc528583022 100644 --- a/tests/bluetooth/l2cap/testcase.yaml +++ b/tests/bluetooth/l2cap/testcase.yaml @@ -3,10 +3,12 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - l2cap diff --git a/tests/bluetooth/uuid/testcase.yaml b/tests/bluetooth/uuid/testcase.yaml index bfd161e7cd44331..d7ad13764d128ec 100644 --- a/tests/bluetooth/uuid/testcase.yaml +++ b/tests/bluetooth/uuid/testcase.yaml @@ -3,10 +3,12 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_cortex_m3 integration_platforms: - - native_posix + - native_sim tags: - bluetooth - uuid From c1fa9f736b768568739ba82b95e7098de2bfafd9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 12:45:13 +0100 Subject: [PATCH 0857/1049] tests/drivers kscan_input: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 .../{native_posix_64.overlay => native_sim_64.overlay} | 2 +- tests/drivers/kscan/kscan_input/testcase.yaml | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) rename tests/drivers/kscan/kscan_input/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/kscan/kscan_input/boards/{native_posix_64.overlay => native_sim_64.overlay} (70%) diff --git a/tests/drivers/kscan/kscan_input/boards/native_posix.overlay b/tests/drivers/kscan/kscan_input/boards/native_sim.overlay similarity index 100% rename from tests/drivers/kscan/kscan_input/boards/native_posix.overlay rename to tests/drivers/kscan/kscan_input/boards/native_sim.overlay diff --git a/tests/drivers/kscan/kscan_input/boards/native_posix_64.overlay b/tests/drivers/kscan/kscan_input/boards/native_sim_64.overlay similarity index 70% rename from tests/drivers/kscan/kscan_input/boards/native_posix_64.overlay rename to tests/drivers/kscan/kscan_input/boards/native_sim_64.overlay index 166e6f02e82d5b0..a906fce7488c3fc 100644 --- a/tests/drivers/kscan/kscan_input/boards/native_posix_64.overlay +++ b/tests/drivers/kscan/kscan_input/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/kscan/kscan_input/testcase.yaml b/tests/drivers/kscan/kscan_input/testcase.yaml index 9b233608dd23004..e9565c5de0f4d5d 100644 --- a/tests/drivers/kscan/kscan_input/testcase.yaml +++ b/tests/drivers/kscan/kscan_input/testcase.yaml @@ -3,11 +3,11 @@ tests: drivers.input.kscan_input: platform_allow: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: - drivers - kscan - input integration_platforms: - - native_posix + - native_sim From a7ee8b27574c1b4e4d90fa35a75d3a964fb90eb8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 12:50:21 +0100 Subject: [PATCH 0858/1049] tests/drivers/adc: Switch to native_sim Switch from native_posix to native_sim as default test platform. For test with overlays, switch overlays and platform_allow from native_posix to native_sim. For tests without overlays, enable also in native_sim, and set native_sim as integration platform. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/adc/adc_emul/testcase.yaml | 6 +++++- .../boards/{native_posix.overlay => native_sim.overlay} | 0 .../{native_posix_64.overlay => native_sim_64.overlay} | 2 +- tests/drivers/adc/adc_rescale/testcase.yaml | 4 +++- 4 files changed, 9 insertions(+), 3 deletions(-) rename tests/drivers/adc/adc_rescale/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/adc/adc_rescale/boards/{native_posix_64.overlay => native_sim_64.overlay} (73%) diff --git a/tests/drivers/adc/adc_emul/testcase.yaml b/tests/drivers/adc/adc_emul/testcase.yaml index 6f857096531007c..a82efd67a93e895 100644 --- a/tests/drivers/adc/adc_emul/testcase.yaml +++ b/tests/drivers/adc/adc_emul/testcase.yaml @@ -6,4 +6,8 @@ common: tests: drivers.adc.emul: depends_on: adc - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/drivers/adc/adc_rescale/boards/native_posix.overlay b/tests/drivers/adc/adc_rescale/boards/native_sim.overlay similarity index 100% rename from tests/drivers/adc/adc_rescale/boards/native_posix.overlay rename to tests/drivers/adc/adc_rescale/boards/native_sim.overlay diff --git a/tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay b/tests/drivers/adc/adc_rescale/boards/native_sim_64.overlay similarity index 73% rename from tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay rename to tests/drivers/adc/adc_rescale/boards/native_sim_64.overlay index b71b19b0e766bb4..13b1a7899b9eed4 100644 --- a/tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay +++ b/tests/drivers/adc/adc_rescale/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/adc/adc_rescale/testcase.yaml b/tests/drivers/adc/adc_rescale/testcase.yaml index 3d60d07148668cd..a03f30895cc66dd 100644 --- a/tests/drivers/adc/adc_rescale/testcase.yaml +++ b/tests/drivers/adc/adc_rescale/testcase.yaml @@ -3,4 +3,6 @@ common: tests: drivers.adc.rescale: depends_on: adc - platform_allow: native_posix + platform_allow: + - native_sim + - native_sim_64 From 5c7eae67450f16f02889e9e82d414bb55c1685e9 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 12:57:08 +0100 Subject: [PATCH 0859/1049] tests/drivers/bbram: Switch to native_sim Switch from native_posix to native_sim as default test platform, switch overlays to native_sim. For the HW test, filter whole posix arch to speed up twister run. Signed-off-by: Alberto Escolar Piedras --- .../emul/boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/bbram/emul/testcase.yaml | 4 ++-- tests/drivers/bbram/testcase.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename tests/drivers/bbram/emul/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/bbram/emul/boards/native_posix.overlay b/tests/drivers/bbram/emul/boards/native_sim.overlay similarity index 100% rename from tests/drivers/bbram/emul/boards/native_posix.overlay rename to tests/drivers/bbram/emul/boards/native_sim.overlay diff --git a/tests/drivers/bbram/emul/testcase.yaml b/tests/drivers/bbram/emul/testcase.yaml index 49ca3ec6e742b53..219027b85aa1f7c 100644 --- a/tests/drivers/bbram/emul/testcase.yaml +++ b/tests/drivers/bbram/emul/testcase.yaml @@ -7,6 +7,6 @@ tests: - drivers - bbram harness: ztest - platform_allow: native_posix + platform_allow: native_sim integration_platforms: - - native_posix + - native_sim diff --git a/tests/drivers/bbram/testcase.yaml b/tests/drivers/bbram/testcase.yaml index db1d1640772881a..261b1f137b320e8 100644 --- a/tests/drivers/bbram/testcase.yaml +++ b/tests/drivers/bbram/testcase.yaml @@ -7,7 +7,7 @@ common: - bbram build_only: true harness: ztest - platform_exclude: native_posix + arch_exclude: posix tests: drivers.bbram.it8xxx2: filter: dt_compat_enabled("ite,it8xxx2-bbram") From 5f61df65698d62a6aa1f62717fdd9064a2271b88 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:00:25 +0100 Subject: [PATCH 0860/1049] tests/drivers/bc12: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../drivers/bc12/boards/{native_posix.conf => native_sim.conf} | 0 .../bc12/boards/{native_posix.overlay => native_sim.overlay} | 0 tests/drivers/bc12/testcase.yaml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename tests/drivers/bc12/boards/{native_posix.conf => native_sim.conf} (100%) rename tests/drivers/bc12/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/drivers/bc12/boards/native_posix.conf b/tests/drivers/bc12/boards/native_sim.conf similarity index 100% rename from tests/drivers/bc12/boards/native_posix.conf rename to tests/drivers/bc12/boards/native_sim.conf diff --git a/tests/drivers/bc12/boards/native_posix.overlay b/tests/drivers/bc12/boards/native_sim.overlay similarity index 100% rename from tests/drivers/bc12/boards/native_posix.overlay rename to tests/drivers/bc12/boards/native_sim.overlay diff --git a/tests/drivers/bc12/testcase.yaml b/tests/drivers/bc12/testcase.yaml index 1562b625592285f..36f879fb2f7269c 100644 --- a/tests/drivers/bc12/testcase.yaml +++ b/tests/drivers/bc12/testcase.yaml @@ -4,4 +4,4 @@ tests: - drivers - usb - bc12 - platform_allow: native_posix + platform_allow: native_sim From 982425f8188887e2ab0da65efd825b7216cc1797 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 13:14:02 +0100 Subject: [PATCH 0861/1049] tests/drivers/gpio/*: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. For gpio_enable_disable_interrupt, also filter with platform_allow to save time, as the dt filter requires cmake to be run, but only the platforms with overlays provided by the test can be run. Signed-off-by: Alberto Escolar Piedras --- ...ative_posix.overlay => native_sim.overlay} | 0 ...posix_64.overlay => native_sim_64.overlay} | 2 +- ...ative_posix.overlay => native_sim.overlay} | 0 ...posix_64.overlay => native_sim_64.overlay} | 2 +- .../boards/native_posix_64.overlay | 1 - ...ative_posix.overlay => native_sim.overlay} | 0 .../boards/native_sim_64.overlay | 1 + .../testcase.yaml | 3 ++ .../boards/native_posix_64.overlay | 1 - ...ative_posix.overlay => native_sim.overlay} | 0 .../boards/native_sim_64.overlay | 1 + .../gpio_hogs/boards/native_posix_64.overlay | 35 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../gpio_hogs/boards/native_sim_64.overlay | 7 ++++ tests/drivers/gpio/gpio_hogs/testcase.yaml | 8 ++--- .../boards/native_posix_64.overlay | 2 +- .../gpio/gpio_reserved_ranges/testcase.yaml | 8 +++-- 17 files changed, 24 insertions(+), 47 deletions(-) rename tests/drivers/gpio/gpio_api_1pin/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/gpio/gpio_api_1pin/boards/{native_posix_64.overlay => native_sim_64.overlay} (78%) rename tests/drivers/gpio/gpio_basic_api/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/drivers/gpio/gpio_basic_api/boards/{native_posix_64.overlay => native_sim_64.overlay} (78%) delete mode 100644 tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay rename tests/drivers/gpio/gpio_enable_disable_interrupt/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim_64.overlay delete mode 100644 tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay rename tests/drivers/gpio/gpio_get_direction/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/drivers/gpio/gpio_get_direction/boards/native_sim_64.overlay delete mode 100644 tests/drivers/gpio/gpio_hogs/boards/native_posix_64.overlay rename tests/drivers/gpio/gpio_hogs/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/drivers/gpio/gpio_hogs/boards/native_sim_64.overlay diff --git a/tests/drivers/gpio/gpio_api_1pin/boards/native_posix.overlay b/tests/drivers/gpio/gpio_api_1pin/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_api_1pin/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_api_1pin/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_api_1pin/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_api_1pin/boards/native_sim_64.overlay similarity index 78% rename from tests/drivers/gpio/gpio_api_1pin/boards/native_posix_64.overlay rename to tests/drivers/gpio/gpio_api_1pin/boards/native_sim_64.overlay index 02b0040e8a6d070..2a9749002bd1df8 100644 --- a/tests/drivers/gpio/gpio_api_1pin/boards/native_posix_64.overlay +++ b/tests/drivers/gpio/gpio_api_1pin/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_basic_api/boards/native_posix.overlay b/tests/drivers/gpio/gpio_basic_api/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_basic_api/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_basic_api/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_basic_api/boards/native_sim_64.overlay similarity index 78% rename from tests/drivers/gpio/gpio_basic_api/boards/native_posix_64.overlay rename to tests/drivers/gpio/gpio_basic_api/boards/native_sim_64.overlay index 02b0040e8a6d070..2a9749002bd1df8 100644 --- a/tests/drivers/gpio/gpio_basic_api/boards/native_posix_64.overlay +++ b/tests/drivers/gpio/gpio_basic_api/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay deleted file mode 100644 index 2b055bf3de6def2..000000000000000 --- a/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay +++ /dev/null @@ -1 +0,0 @@ -#include "native_posix.overlay" diff --git a/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix.overlay b/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim_64.overlay b/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..6a3daca3241ac6e --- /dev/null +++ b/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_sim_64.overlay @@ -0,0 +1 @@ +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_enable_disable_interrupt/testcase.yaml b/tests/drivers/gpio/gpio_enable_disable_interrupt/testcase.yaml index e60dc4efe86203b..0e88895295e987e 100644 --- a/tests/drivers/gpio/gpio_enable_disable_interrupt/testcase.yaml +++ b/tests/drivers/gpio/gpio_enable_disable_interrupt/testcase.yaml @@ -5,3 +5,6 @@ tests: - gpio depends_on: gpio filter: dt_compat_enabled("test-gpio-enable-disable-interrupt") + platform_allow: + - native_sim + - native_sim_64 diff --git a/tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay deleted file mode 100644 index 2b055bf3de6def2..000000000000000 --- a/tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay +++ /dev/null @@ -1 +0,0 @@ -#include "native_posix.overlay" diff --git a/tests/drivers/gpio/gpio_get_direction/boards/native_posix.overlay b/tests/drivers/gpio/gpio_get_direction/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_get_direction/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_get_direction/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_get_direction/boards/native_sim_64.overlay b/tests/drivers/gpio/gpio_get_direction/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..6a3daca3241ac6e --- /dev/null +++ b/tests/drivers/gpio/gpio_get_direction/boards/native_sim_64.overlay @@ -0,0 +1 @@ +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_hogs/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_hogs/boards/native_posix_64.overlay deleted file mode 100644 index 44a29b59ab32cb4..000000000000000 --- a/tests/drivers/gpio/gpio_hogs/boards/native_posix_64.overlay +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Vestas Wind Systems A/S - * - * SPDX-License-Identifier: Apache-2.0 -*/ - -#include - -/ { - zephyr,user { - output-high-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; - output-low-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; - input-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; - }; -}; - -&gpio0 { - hog1 { - gpio-hog; - gpios = <1 GPIO_ACTIVE_LOW>; - output-high; - }; - - hog2 { - gpio-hog; - gpios = <2 GPIO_ACTIVE_HIGH>; - output-low; - }; - - hog3 { - gpio-hog; - gpios = <3 GPIO_ACTIVE_HIGH>; - input; - }; -}; diff --git a/tests/drivers/gpio/gpio_hogs/boards/native_posix.overlay b/tests/drivers/gpio/gpio_hogs/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_hogs/boards/native_posix.overlay rename to tests/drivers/gpio/gpio_hogs/boards/native_sim.overlay diff --git a/tests/drivers/gpio/gpio_hogs/boards/native_sim_64.overlay b/tests/drivers/gpio/gpio_hogs/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..d3b3d26173499ed --- /dev/null +++ b/tests/drivers/gpio/gpio_hogs/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_hogs/testcase.yaml b/tests/drivers/gpio/gpio_hogs/testcase.yaml index 6c02bf5f7f1f227..98e279b789c8103 100644 --- a/tests/drivers/gpio/gpio_hogs/testcase.yaml +++ b/tests/drivers/gpio/gpio_hogs/testcase.yaml @@ -5,8 +5,8 @@ tests: - gpio depends_on: gpio platform_allow: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - frdm_k64f - nrf52840dk_nrf52840 - nucleo_g474re @@ -15,5 +15,5 @@ tests: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 diff --git a/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay b/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay index 0d3e3ea93f2fc46..2c46f3ddc56ee93 100644 --- a/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay +++ b/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml b/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml index 57c6f2c291a1436..015cf79c3fcc503 100644 --- a/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml +++ b/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml @@ -3,7 +3,9 @@ tests: tags: drivers gpio depends_on: gpio filter: dt_compat_enabled("test-gpio-reserved-ranges") - platform_allow: native_posix native_posix_64 + platform_allow: + - native_sim + - native_sim_64 integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 From 3692675dcf4e54fd6ebcc6b2a3688a31d151892b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:27:29 +0100 Subject: [PATCH 0862/1049] tests/subsys/settings/fcb: Switch to native_sim Switch from native_posix to native_sim as default test platform Switch overlays from native_posix to native_sim. And move overlays into a boards/ directory Signed-off-by: Alberto Escolar Piedras --- .../native_sim.overlay} | 0 .../settings/fcb/boards/native_sim_64.overlay | 7 ++++++ .../{ => boards}/nrf52840dk_nrf52840.overlay | 0 .../fcb/{ => boards}/nrf52dk_nrf52832.overlay | 0 .../settings/fcb/native_posix_64.overlay | 22 ------------------- tests/subsys/settings/fcb/testcase.yaml | 6 ++--- 6 files changed, 10 insertions(+), 25 deletions(-) rename tests/subsys/settings/fcb/{native_posix.overlay => boards/native_sim.overlay} (100%) create mode 100644 tests/subsys/settings/fcb/boards/native_sim_64.overlay rename tests/subsys/settings/fcb/{ => boards}/nrf52840dk_nrf52840.overlay (100%) rename tests/subsys/settings/fcb/{ => boards}/nrf52dk_nrf52832.overlay (100%) delete mode 100644 tests/subsys/settings/fcb/native_posix_64.overlay diff --git a/tests/subsys/settings/fcb/native_posix.overlay b/tests/subsys/settings/fcb/boards/native_sim.overlay similarity index 100% rename from tests/subsys/settings/fcb/native_posix.overlay rename to tests/subsys/settings/fcb/boards/native_sim.overlay diff --git a/tests/subsys/settings/fcb/boards/native_sim_64.overlay b/tests/subsys/settings/fcb/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..8dbed8eb97ab75a --- /dev/null +++ b/tests/subsys/settings/fcb/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/settings/fcb/nrf52840dk_nrf52840.overlay b/tests/subsys/settings/fcb/boards/nrf52840dk_nrf52840.overlay similarity index 100% rename from tests/subsys/settings/fcb/nrf52840dk_nrf52840.overlay rename to tests/subsys/settings/fcb/boards/nrf52840dk_nrf52840.overlay diff --git a/tests/subsys/settings/fcb/nrf52dk_nrf52832.overlay b/tests/subsys/settings/fcb/boards/nrf52dk_nrf52832.overlay similarity index 100% rename from tests/subsys/settings/fcb/nrf52dk_nrf52832.overlay rename to tests/subsys/settings/fcb/boards/nrf52dk_nrf52832.overlay diff --git a/tests/subsys/settings/fcb/native_posix_64.overlay b/tests/subsys/settings/fcb/native_posix_64.overlay deleted file mode 100644 index f7f0961513832bd..000000000000000 --- a/tests/subsys/settings/fcb/native_posix_64.overlay +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &storage_partition; -/delete-node/ &scratch_partition; - -&flash0 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage_partition: partition@70000 { - label = "storage"; - reg = <0x00070000 0x10000>; - }; - }; -}; diff --git a/tests/subsys/settings/fcb/testcase.yaml b/tests/subsys/settings/fcb/testcase.yaml index dd000db1c09a555..0382c74ff00af5a 100644 --- a/tests/subsys/settings/fcb/testcase.yaml +++ b/tests/subsys/settings/fcb/testcase.yaml @@ -3,12 +3,12 @@ tests: platform_allow: - nrf52840dk_nrf52840 - nrf52dk_nrf52832 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - nrf52840dk_nrf52840 - - native_posix + - native_sim tags: - settings - fcb From f27760ab47a5e73928dbd26e0668a58905f77f37 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:30:11 +0100 Subject: [PATCH 0863/1049] tests/subsys/settings/file: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../file/boards/native_posix_64.overlay | 21 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../file/boards/native_sim_64.overlay | 7 +++++++ tests/subsys/settings/file/testcase.yaml | 4 ++-- 4 files changed, 9 insertions(+), 23 deletions(-) delete mode 100644 tests/subsys/settings/file/boards/native_posix_64.overlay rename tests/subsys/settings/file/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/settings/file/boards/native_sim_64.overlay diff --git a/tests/subsys/settings/file/boards/native_posix_64.overlay b/tests/subsys/settings/file/boards/native_posix_64.overlay deleted file mode 100644 index 1c4d5371fc9cc32..000000000000000 --- a/tests/subsys/settings/file/boards/native_posix_64.overlay +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&flashcontroller0 { - reg = <0x00000000 DT_SIZE_K(4096)>; -}; - -&flash0 { - reg = <0x00000000 DT_SIZE_K(4096)>; - partitions { - compatible = "fixed-partitions"; - - settings_file_partition: partition@0 { - label = "settings_file_partition"; - reg = <0x00000000 0x00010000>; - }; - }; -}; diff --git a/tests/subsys/settings/file/boards/native_posix.overlay b/tests/subsys/settings/file/boards/native_sim.overlay similarity index 100% rename from tests/subsys/settings/file/boards/native_posix.overlay rename to tests/subsys/settings/file/boards/native_sim.overlay diff --git a/tests/subsys/settings/file/boards/native_sim_64.overlay b/tests/subsys/settings/file/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..55d159158f84c94 --- /dev/null +++ b/tests/subsys/settings/file/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/settings/file/testcase.yaml b/tests/subsys/settings/file/testcase.yaml index 68add10790bef33..9491f9b20468706 100644 --- a/tests/subsys/settings/file/testcase.yaml +++ b/tests/subsys/settings/file/testcase.yaml @@ -5,8 +5,8 @@ tests: settings.file.raw: platform_allow: - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 tags: - settings From b7fa935a0d4d8695fe8b29852ed8611bd9c72039 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:30:45 +0100 Subject: [PATCH 0864/1049] tests/subsys/settings/functional/*: Switch to native_sim Enable native_sim for these tests (platform_allow filter) Switch from native_posix to native_sim as default test platform And switch overlays from native_posix to native_sim Signed-off-by: Alberto Escolar Piedras --- .../settings/functional/fcb/testcase.yaml | 6 ++++- .../functional/file/native_posix_64.overlay | 22 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../functional/file/native_sim_64.overlay | 7 ++++++ .../settings/functional/file/testcase.yaml | 6 ++--- .../settings/functional/nvs/testcase.yaml | 4 ++++ 6 files changed, 19 insertions(+), 26 deletions(-) delete mode 100644 tests/subsys/settings/functional/file/native_posix_64.overlay rename tests/subsys/settings/functional/file/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/settings/functional/file/native_sim_64.overlay diff --git a/tests/subsys/settings/functional/fcb/testcase.yaml b/tests/subsys/settings/functional/fcb/testcase.yaml index fb484e210b10c64..d9d63adc66c383d 100644 --- a/tests/subsys/settings/functional/fcb/testcase.yaml +++ b/tests/subsys/settings/functional/fcb/testcase.yaml @@ -5,6 +5,8 @@ tests: - nrf52dk_nrf52832 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - nrf52840dk_nrf52840 @@ -16,9 +18,11 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - - native_posix + - native_sim tags: - settings - fcb diff --git a/tests/subsys/settings/functional/file/native_posix_64.overlay b/tests/subsys/settings/functional/file/native_posix_64.overlay deleted file mode 100644 index 294dd4b1e62ce8a..000000000000000 --- a/tests/subsys/settings/functional/file/native_posix_64.overlay +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &storage_partition; -/delete-node/ &scratch_partition; - -&flash0 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage_partition: partition@70000 { - label = "storage"; - reg = <0x00070000 0x20000>; - }; - }; -}; diff --git a/tests/subsys/settings/functional/file/native_posix.overlay b/tests/subsys/settings/functional/file/native_sim.overlay similarity index 100% rename from tests/subsys/settings/functional/file/native_posix.overlay rename to tests/subsys/settings/functional/file/native_sim.overlay diff --git a/tests/subsys/settings/functional/file/native_sim_64.overlay b/tests/subsys/settings/functional/file/native_sim_64.overlay new file mode 100644 index 000000000000000..8dbed8eb97ab75a --- /dev/null +++ b/tests/subsys/settings/functional/file/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/settings/functional/file/testcase.yaml b/tests/subsys/settings/functional/file/testcase.yaml index 7a28a2f41bca73f..6f876e93f3f4331 100644 --- a/tests/subsys/settings/functional/file/testcase.yaml +++ b/tests/subsys/settings/functional/file/testcase.yaml @@ -3,11 +3,11 @@ tests: platform_allow: - nrf52840dk_nrf52840 - nrf52dk_nrf52832 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - - native_posix + - native_sim tags: - settings - file diff --git a/tests/subsys/settings/functional/nvs/testcase.yaml b/tests/subsys/settings/functional/nvs/testcase.yaml index 6f2be71a86f10d3..def7aa02a5240ba 100644 --- a/tests/subsys/settings/functional/nvs/testcase.yaml +++ b/tests/subsys/settings/functional/nvs/testcase.yaml @@ -4,6 +4,8 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 tags: - settings - nvs @@ -12,6 +14,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 tags: - settings - nvs From 3d702e6ffa3aadfd5d16808fc78cda4d2e97beb7 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:46:22 +0100 Subject: [PATCH 0865/1049] tests/subsys/dfu/*: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/dfu/img_util/testcase.yaml | 21 +++++------ tests/subsys/dfu/mcuboot/testcase.yaml | 2 + .../dfu/mcuboot_multi/native_posix_64.overlay | 37 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../dfu/mcuboot_multi/native_sim_64.overlay | 7 ++++ tests/subsys/dfu/mcuboot_multi/testcase.yaml | 4 +- 6 files changed, 20 insertions(+), 51 deletions(-) delete mode 100644 tests/subsys/dfu/mcuboot_multi/native_posix_64.overlay rename tests/subsys/dfu/mcuboot_multi/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/dfu/mcuboot_multi/native_sim_64.overlay diff --git a/tests/subsys/dfu/img_util/testcase.yaml b/tests/subsys/dfu/img_util/testcase.yaml index 89d443395727d88..e90fb0842b1e598 100644 --- a/tests/subsys/dfu/img_util/testcase.yaml +++ b/tests/subsys/dfu/img_util/testcase.yaml @@ -1,18 +1,15 @@ +common: + platform_allow: + - nrf52840dk_nrf52840 + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - nrf52840dk_nrf52840 tests: dfu.image_util: - platform_allow: - - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 tags: dfu_image_util - integration_platforms: - - nrf52840dk_nrf52840 dfu.image_util.progressive: extra_args: OVERLAY_CONFIG=progressively_overlay.conf - platform_allow: - - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 tags: dfu_image_util - integration_platforms: - - nrf52840dk_nrf52840 diff --git a/tests/subsys/dfu/mcuboot/testcase.yaml b/tests/subsys/dfu/mcuboot/testcase.yaml index c05a05ae5df6fea..6b630c71865d66e 100644 --- a/tests/subsys/dfu/mcuboot/testcase.yaml +++ b/tests/subsys/dfu/mcuboot/testcase.yaml @@ -4,6 +4,8 @@ tests: - nrf52840dk_nrf52840 - native_posix - native_posix_64 + - native_sim + - native_sim_64 tags: dfu_mcuboot integration_platforms: - nrf52840dk_nrf52840 diff --git a/tests/subsys/dfu/mcuboot_multi/native_posix_64.overlay b/tests/subsys/dfu/mcuboot_multi/native_posix_64.overlay deleted file mode 100644 index 5166674f432c729..000000000000000 --- a/tests/subsys/dfu/mcuboot_multi/native_posix_64.overlay +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &scratch_partition; -/delete-node/ &storage_partition; - -&flash0 { - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x0000C000>; - }; - slot0_partition: partition@c000 { - label = "image-0"; - reg = <0x0000C000 0x00069000>; - }; - slot1_partition: partition@75000 { - label = "image-1"; - reg = <0x00075000 0x00069000>; - }; - slot2_partition: partition@DE000 { - label = "image-2"; - reg = <0x000DE000 0x00069000>; - }; - slot3_partition: partition@146000 { - label = "image-3"; - reg = <0x00146000 0x00069000>; - }; - }; -}; diff --git a/tests/subsys/dfu/mcuboot_multi/native_posix.overlay b/tests/subsys/dfu/mcuboot_multi/native_sim.overlay similarity index 100% rename from tests/subsys/dfu/mcuboot_multi/native_posix.overlay rename to tests/subsys/dfu/mcuboot_multi/native_sim.overlay diff --git a/tests/subsys/dfu/mcuboot_multi/native_sim_64.overlay b/tests/subsys/dfu/mcuboot_multi/native_sim_64.overlay new file mode 100644 index 000000000000000..3e51723713a3e28 --- /dev/null +++ b/tests/subsys/dfu/mcuboot_multi/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/dfu/mcuboot_multi/testcase.yaml b/tests/subsys/dfu/mcuboot_multi/testcase.yaml index dbebd3fddbd98ed..742bbe38ce62b4d 100644 --- a/tests/subsys/dfu/mcuboot_multi/testcase.yaml +++ b/tests/subsys/dfu/mcuboot_multi/testcase.yaml @@ -2,8 +2,8 @@ tests: dfu.mcuboot.multiimage: platform_allow: - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: dfu_mcuboot integration_platforms: - nrf52840dk_nrf52840 From ec7ed0ea7d95bac152d30d4870f39de2da16d3fa Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:52:18 +0100 Subject: [PATCH 0866/1049] tests/drivers smbus_emul: Switch to native_sim Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/drivers/smbus/smbus_emul/testcase.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/drivers/smbus/smbus_emul/testcase.yaml b/tests/drivers/smbus/smbus_emul/testcase.yaml index 26fc9254c55c011..8eef32526bb8b2a 100644 --- a/tests/drivers/smbus/smbus_emul/testcase.yaml +++ b/tests/drivers/smbus/smbus_emul/testcase.yaml @@ -1,5 +1,9 @@ common: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tests: drivers.smbus.emul: tags: smbus From 81179bcd637265d99fb24d396d66ebbe26d581a6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 14:52:44 +0100 Subject: [PATCH 0867/1049] tests/subsys/mem_mgmt/mem_attr: Switch to native_sim Enable native_sim for this test. Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/mem_mgmt/mem_attr/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/subsys/mem_mgmt/mem_attr/testcase.yaml b/tests/subsys/mem_mgmt/mem_attr/testcase.yaml index ecb445a077e5200..63e5c1668d6b0ea 100644 --- a/tests/subsys/mem_mgmt/mem_attr/testcase.yaml +++ b/tests/subsys/mem_mgmt/mem_attr/testcase.yaml @@ -2,7 +2,9 @@ common: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tests: mem_mgmt.mem_attr.default: {} From 6caf76346ac380ad7173c8eefb387b17a012f0cf Mon Sep 17 00:00:00 2001 From: Alexander Vasiliev Date: Thu, 2 Nov 2023 16:30:55 +0000 Subject: [PATCH 0868/1049] net: mqtt-sn: Add a function to get topic name by topic ID Add a function to MQTT-SN library API to get topic name by ID from the internal topics list. Signed-off-by: Alexander Vasiliev --- include/zephyr/net/mqtt_sn.h | 13 +++++++++++++ subsys/net/lib/mqtt_sn/mqtt_sn.c | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/zephyr/net/mqtt_sn.h b/include/zephyr/net/mqtt_sn.h index 7700558f1fefc40..cb1a6d3373123a1 100644 --- a/include/zephyr/net/mqtt_sn.h +++ b/include/zephyr/net/mqtt_sn.h @@ -397,6 +397,19 @@ int mqtt_sn_publish(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, */ int mqtt_sn_input(struct mqtt_sn_client *client); +/** + * @brief Get topic name by topic ID. + * + * @param[in] client The MQTT-SN client that uses this topic. + * @param[in] id Topic identifier. + * @param[out] topic_name Will be assigned to topic name. + * + * @return 0 on success, -ENOENT if topic ID doesn't exist, + * or -EINVAL on invalid arguments. + */ +int mqtt_sn_get_topic_name(struct mqtt_sn_client *client, uint16_t id, + struct mqtt_sn_data *topic_name); + #ifdef __cplusplus } #endif diff --git a/subsys/net/lib/mqtt_sn/mqtt_sn.c b/subsys/net/lib/mqtt_sn/mqtt_sn.c index 213ca55753fe659..4c0be807c214077 100644 --- a/subsys/net/lib/mqtt_sn/mqtt_sn.c +++ b/subsys/net/lib/mqtt_sn/mqtt_sn.c @@ -1224,3 +1224,22 @@ int mqtt_sn_input(struct mqtt_sn_client *client) /* Should be zero */ return -client->rx.len; } + +int mqtt_sn_get_topic_name(struct mqtt_sn_client *client, uint16_t id, + struct mqtt_sn_data *topic_name) +{ + struct mqtt_sn_topic *topic; + + if (!client || !topic_name) { + return -EINVAL; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&client->topic, topic, next) { + if (topic->topic_id == id) { + topic_name->data = (const uint8_t *)topic->name; + topic_name->size = topic->namelen; + return 0; + } + } + return -ENOENT; +} From 76276e2bd3ddb698a081ecfec79fc2c36b9450b4 Mon Sep 17 00:00:00 2001 From: Alexander Vasiliev Date: Thu, 2 Nov 2023 16:38:12 +0000 Subject: [PATCH 0869/1049] net: mqtt-sn: Remember incoming registered topic name When a client uses wildcard subscription and a new message is published to the matching topic for the first time, the gateway sends REGISTER message to the client, containing the exact topic name and a new topic ID. This change fixes adding these topic ID and name to the internal topics list. Signed-off-by: Alexander Vasiliev --- subsys/net/lib/mqtt_sn/mqtt_sn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/net/lib/mqtt_sn/mqtt_sn.c b/subsys/net/lib/mqtt_sn/mqtt_sn.c index 4c0be807c214077..2a7b71ae05554fa 100644 --- a/subsys/net/lib/mqtt_sn/mqtt_sn.c +++ b/subsys/net/lib/mqtt_sn/mqtt_sn.c @@ -949,6 +949,8 @@ static void handle_register(struct mqtt_sn_client *client, struct mqtt_sn_param_ topic->topic_id = p->topic_id; topic->type = MQTT_SN_TOPIC_TYPE_NORMAL; + sys_slist_append(&client->topic, &topic->next); + response.params.regack.ret_code = MQTT_SN_CODE_ACCEPTED; response.params.regack.topic_id = p->topic_id; response.params.regack.msg_id = p->msg_id; From bc8313e26e342684b52c6d694e13ee5ebc294715 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 17:01:12 +0100 Subject: [PATCH 0870/1049] pm: Fix definition of pm device slot This pointers need to be writable by the power management code, but were declared as const, resulting in a fault for platforms which prevent writing to RAM containing const values. Signed-off-by: Alberto Escolar Piedras --- include/zephyr/pm/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index cbfbf6f5f46df67..ab54fd677fe7091 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -220,7 +220,7 @@ struct pm_device { * @param dev_id Device id. */ #define Z_PM_DEVICE_DEFINE_SLOT(dev_id) \ - static const STRUCT_SECTION_ITERABLE_ALTERNATE(pm_device_slots, device, \ + static STRUCT_SECTION_ITERABLE_ALTERNATE(pm_device_slots, device, \ _CONCAT(__pm_slot_, dev_id)) #ifdef CONFIG_PM_DEVICE From b39d7c2c3d9d31afa1fdbf5bddac347387609320 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 16:44:25 +0100 Subject: [PATCH 0871/1049] tests/subsys/pm/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform And switch native_posix overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/subsys/pm/device_driver_init/testcase.yaml | 3 +++ tests/subsys/pm/device_power_domains/testcase.yaml | 3 +++ tests/subsys/pm/device_runtime_api/testcase.yaml | 2 +- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/subsys/pm/device_wakeup_api/testcase.yaml | 3 ++- tests/subsys/pm/policy_api/testcase.yaml | 4 +++- tests/subsys/pm/power_domain/testcase.yaml | 6 +++++- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/subsys/pm/power_mgmt/testcase.yaml | 2 +- .../boards/{native_posix.overlay => native_sim.overlay} | 0 tests/subsys/pm/power_states_api/testcase.yaml | 3 ++- 11 files changed, 20 insertions(+), 6 deletions(-) rename tests/subsys/pm/device_wakeup_api/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/subsys/pm/power_mgmt/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/subsys/pm/power_states_api/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/subsys/pm/device_driver_init/testcase.yaml b/tests/subsys/pm/device_driver_init/testcase.yaml index 8920e38741b25b2..cf8e338e5c578b8 100644 --- a/tests/subsys/pm/device_driver_init/testcase.yaml +++ b/tests/subsys/pm/device_driver_init/testcase.yaml @@ -1,6 +1,9 @@ common: platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim tags: - pm tests: diff --git a/tests/subsys/pm/device_power_domains/testcase.yaml b/tests/subsys/pm/device_power_domains/testcase.yaml index 11b00299f5c4058..4d2037dff767aa9 100644 --- a/tests/subsys/pm/device_power_domains/testcase.yaml +++ b/tests/subsys/pm/device_power_domains/testcase.yaml @@ -4,3 +4,6 @@ tests: - pm platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/subsys/pm/device_runtime_api/testcase.yaml b/tests/subsys/pm/device_runtime_api/testcase.yaml index 4b9f38fd8bb8243..72c9c51294288b2 100644 --- a/tests/subsys/pm/device_runtime_api/testcase.yaml +++ b/tests/subsys/pm/device_runtime_api/testcase.yaml @@ -2,4 +2,4 @@ tests: pm.device_runtime.api: tags: pm integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/pm/device_wakeup_api/boards/native_posix.overlay b/tests/subsys/pm/device_wakeup_api/boards/native_sim.overlay similarity index 100% rename from tests/subsys/pm/device_wakeup_api/boards/native_posix.overlay rename to tests/subsys/pm/device_wakeup_api/boards/native_sim.overlay diff --git a/tests/subsys/pm/device_wakeup_api/testcase.yaml b/tests/subsys/pm/device_wakeup_api/testcase.yaml index 790173546f90d6f..4106eb8aac101e6 100644 --- a/tests/subsys/pm/device_wakeup_api/testcase.yaml +++ b/tests/subsys/pm/device_wakeup_api/testcase.yaml @@ -1,4 +1,5 @@ tests: pm.device-wakeup-api.dts: tags: pm - platform_allow: native_posix + platform_allow: + - native_sim diff --git a/tests/subsys/pm/policy_api/testcase.yaml b/tests/subsys/pm/policy_api/testcase.yaml index 1e770694f337cb9..5df6032ab1d4ecc 100644 --- a/tests/subsys/pm/policy_api/testcase.yaml +++ b/tests/subsys/pm/policy_api/testcase.yaml @@ -6,8 +6,10 @@ common: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tests: pm.policy.api.default: {} pm.policy.api.app: diff --git a/tests/subsys/pm/power_domain/testcase.yaml b/tests/subsys/pm/power_domain/testcase.yaml index e2f814068063cfe..287267ba0f8b9f4 100644 --- a/tests/subsys/pm/power_domain/testcase.yaml +++ b/tests/subsys/pm/power_domain/testcase.yaml @@ -1,4 +1,8 @@ tests: pm.power_domain: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim tags: pm diff --git a/tests/subsys/pm/power_mgmt/boards/native_posix.overlay b/tests/subsys/pm/power_mgmt/boards/native_sim.overlay similarity index 100% rename from tests/subsys/pm/power_mgmt/boards/native_posix.overlay rename to tests/subsys/pm/power_mgmt/boards/native_sim.overlay diff --git a/tests/subsys/pm/power_mgmt/testcase.yaml b/tests/subsys/pm/power_mgmt/testcase.yaml index d08f0386aa21720..b51b282ea554905 100644 --- a/tests/subsys/pm/power_mgmt/testcase.yaml +++ b/tests/subsys/pm/power_mgmt/testcase.yaml @@ -1,4 +1,4 @@ tests: pm.system: - platform_allow: native_posix + platform_allow: native_sim tags: pm diff --git a/tests/subsys/pm/power_states_api/boards/native_posix.overlay b/tests/subsys/pm/power_states_api/boards/native_sim.overlay similarity index 100% rename from tests/subsys/pm/power_states_api/boards/native_posix.overlay rename to tests/subsys/pm/power_states_api/boards/native_sim.overlay diff --git a/tests/subsys/pm/power_states_api/testcase.yaml b/tests/subsys/pm/power_states_api/testcase.yaml index 507e8f3e22f49c1..7ad42f206816f14 100644 --- a/tests/subsys/pm/power_states_api/testcase.yaml +++ b/tests/subsys/pm/power_states_api/testcase.yaml @@ -1,4 +1,5 @@ tests: pm.states.api.dts: tags: pm - platform_allow: native_posix + platform_allow: + - native_sim From 1a2fc865d2bd5fef788022b509e8c131e13a9384 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 15:50:46 +0100 Subject: [PATCH 0872/1049] tests/subsys/fs/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform And switch native_posix overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../fs/ext2/boards/native_posix_64.overlay | 31 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../fs/ext2/boards/native_sim_64.overlay | 7 +++++ tests/subsys/fs/ext2/testcase.yaml | 18 ++++++++--- tests/subsys/fs/fat_fs_api/README.txt | 4 +-- ...ative_posix.overlay => native_sim.overlay} | 0 ...ive_posix_ram.conf => prj_native_ram.conf} | 0 tests/subsys/fs/fat_fs_api/testcase.yaml | 14 ++++++--- .../subsys/fs/fat_fs_dual_drive/testcase.yaml | 3 +- ...x00.overlay => native_sim_ev_0x00.overlay} | 0 tests/subsys/fs/fcb/testcase.yaml | 8 +++-- tests/subsys/fs/fs_api/testcase.yaml | 2 +- .../littlefs/boards/native_posix_64.overlay | 31 ------------------- ...ative_posix.overlay => native_sim.overlay} | 0 .../fs/littlefs/boards/native_sim_64.overlay | 7 +++++ tests/subsys/fs/littlefs/testcase.yaml | 4 +-- tests/subsys/fs/multi-fs/testcase.yaml | 6 ++-- ...ative_posix.overlay => native_sim.overlay} | 0 tests/subsys/fs/nvs/src/main.c | 6 ++-- tests/subsys/fs/nvs/testcase.yaml | 2 +- 20 files changed, 57 insertions(+), 86 deletions(-) delete mode 100644 tests/subsys/fs/ext2/boards/native_posix_64.overlay rename tests/subsys/fs/ext2/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/fs/ext2/boards/native_sim_64.overlay rename tests/subsys/fs/fat_fs_api/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/subsys/fs/fat_fs_api/{prj_native_posix_ram.conf => prj_native_ram.conf} (100%) rename tests/subsys/fs/fcb/boards/{native_posix_ev_0x00.overlay => native_sim_ev_0x00.overlay} (100%) delete mode 100644 tests/subsys/fs/littlefs/boards/native_posix_64.overlay rename tests/subsys/fs/littlefs/boards/{native_posix.overlay => native_sim.overlay} (100%) create mode 100644 tests/subsys/fs/littlefs/boards/native_sim_64.overlay rename tests/subsys/fs/nvs/boards/{native_posix.overlay => native_sim.overlay} (100%) diff --git a/tests/subsys/fs/ext2/boards/native_posix_64.overlay b/tests/subsys/fs/ext2/boards/native_posix_64.overlay deleted file mode 100644 index 5b40394859052a4..000000000000000 --- a/tests/subsys/fs/ext2/boards/native_posix_64.overlay +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2023 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&flashcontroller0 { - reg = <0x00000000 DT_SIZE_M(128)>; -}; - -&flash0 { - reg = <0x00000000 DT_SIZE_M(128)>; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage: partition@0 { - reg = <0x00000000 0x08000000>; - }; - }; -}; - -/ { - storage_disk { - compatible = "zephyr,flash-disk"; - partition = <&storage>; - disk-name = "NAND"; - cache-size = <4096>; - }; -}; diff --git a/tests/subsys/fs/ext2/boards/native_posix.overlay b/tests/subsys/fs/ext2/boards/native_sim.overlay similarity index 100% rename from tests/subsys/fs/ext2/boards/native_posix.overlay rename to tests/subsys/fs/ext2/boards/native_sim.overlay diff --git a/tests/subsys/fs/ext2/boards/native_sim_64.overlay b/tests/subsys/fs/ext2/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..f3f8b087d9b219b --- /dev/null +++ b/tests/subsys/fs/ext2/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/fs/ext2/testcase.yaml b/tests/subsys/fs/ext2/testcase.yaml index 21615994ba61326..7466e0984b9789c 100644 --- a/tests/subsys/fs/ext2/testcase.yaml +++ b/tests/subsys/fs/ext2/testcase.yaml @@ -2,20 +2,30 @@ common: tags: filesystem tests: filesystem.ext2.default: - platform_allow: native_posix native_posix_64 hifive_unmatched bl5340_dvk_cpuapp + platform_allow: + - native_sim + - native_sim_64 + - hifive_unmatched + - bl5340_dvk_cpuapp extra_args: - EXTRA_DTC_OVERLAY_FILE="ramdisk_small.overlay" filesystem.ext2.big: - platform_allow: native_posix native_posix_64 + platform_allow: + - native_sim + - native_sim_64 extra_args: - CONF_FILE=prj_big.conf - EXTRA_DTC_OVERLAY_FILE="ramdisk_big.overlay" filesystem.ext2.sdcard: - platform_allow: hifive_unmatched bl5340_dvk_cpuapp + platform_allow: + - hifive_unmatched + - bl5340_dvk_cpuapp extra_args: CONF_FILE=prj_sdcard.conf filesystem.ext2.flash: - platform_allow: native_posix native_posix_64 + platform_allow: + - native_sim + - native_sim_64 extra_args: CONF_FILE=prj_flash.conf diff --git a/tests/subsys/fs/fat_fs_api/README.txt b/tests/subsys/fs/fat_fs_api/README.txt index 10fbfb73118ced8..58ddbb3c6cd4154 100644 --- a/tests/subsys/fs/fat_fs_api/README.txt +++ b/tests/subsys/fs/fat_fs_api/README.txt @@ -7,10 +7,10 @@ Demonstrates basic file and dir operations using the Zephyr file system. Building and Running Project: -The demo will run on native_posix and will use the on-board SPI flash. +The demo will run on native_sim using the flash simulator. mkdir build; cd build - cmake -DBOARD=native_posix .. + cmake -DBOARD=native_sim .. make run To test fatfs on MMC, add this cmake option to your build command: diff --git a/tests/subsys/fs/fat_fs_api/boards/native_posix.overlay b/tests/subsys/fs/fat_fs_api/boards/native_sim.overlay similarity index 100% rename from tests/subsys/fs/fat_fs_api/boards/native_posix.overlay rename to tests/subsys/fs/fat_fs_api/boards/native_sim.overlay diff --git a/tests/subsys/fs/fat_fs_api/prj_native_posix_ram.conf b/tests/subsys/fs/fat_fs_api/prj_native_ram.conf similarity index 100% rename from tests/subsys/fs/fat_fs_api/prj_native_posix_ram.conf rename to tests/subsys/fs/fat_fs_api/prj_native_ram.conf diff --git a/tests/subsys/fs/fat_fs_api/testcase.yaml b/tests/subsys/fs/fat_fs_api/testcase.yaml index bc3927def92764f..59cd6035ddd3d93 100644 --- a/tests/subsys/fs/fat_fs_api/testcase.yaml +++ b/tests/subsys/fs/fat_fs_api/testcase.yaml @@ -6,20 +6,24 @@ common: - fatfs tests: filesystem.fat.api: - platform_allow: native_posix + platform_allow: + - native_sim filesystem.fat.api.lfn: extra_args: CONF_FILE="prj_lfn.conf" - platform_allow: native_posix + platform_allow: + - native_sim filesystem.fat.api.mmc: extra_args: CONF_FILE="prj_mmc.conf" filter: dt_compat_enabled("zephyr,mmc-disk") filesystem.fat.ram.api: - platform_allow: native_posix + platform_allow: + - native_sim extra_args: - - CONF_FILE="prj_native_posix_ram.conf" + - CONF_FILE="prj_native_ram.conf" - EXTRA_DTC_OVERLAY_FILE="ramdisk.overlay" filesystem.fat.api.reentrant: - platform_allow: native_posix + platform_allow: + - native_sim extra_configs: - CONFIG_FS_FATFS_REENTRANT=y - CONFIG_MULTITHREADING=y diff --git a/tests/subsys/fs/fat_fs_dual_drive/testcase.yaml b/tests/subsys/fs/fat_fs_dual_drive/testcase.yaml index a4db89c676ce836..ab8264579ad7998 100644 --- a/tests/subsys/fs/fat_fs_dual_drive/testcase.yaml +++ b/tests/subsys/fs/fat_fs_dual_drive/testcase.yaml @@ -3,9 +3,10 @@ tests: platform_allow: - qemu_x86 - native_posix + - native_sim - qemu_leon3 - qemu_riscv32 - qemu_riscv64 tags: filesystem integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/fs/fcb/boards/native_posix_ev_0x00.overlay b/tests/subsys/fs/fcb/boards/native_sim_ev_0x00.overlay similarity index 100% rename from tests/subsys/fs/fcb/boards/native_posix_ev_0x00.overlay rename to tests/subsys/fs/fcb/boards/native_sim_ev_0x00.overlay diff --git a/tests/subsys/fs/fcb/testcase.yaml b/tests/subsys/fs/fcb/testcase.yaml index 0d5d1938b25cd0e..3945049a53462e0 100644 --- a/tests/subsys/fs/fcb/testcase.yaml +++ b/tests/subsys/fs/fcb/testcase.yaml @@ -6,13 +6,15 @@ tests: - nrf51dk_nrf51422 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 tags: flash_circural_buffer integration_platforms: - nrf52840dk_nrf52840 - filesystem.fcb.native_posix.fcb_0x00: - extra_args: DTC_OVERLAY_FILE=boards/native_posix_ev_0x00.overlay - platform_allow: native_posix + filesystem.fcb.native_sim.fcb_0x00: + extra_args: DTC_OVERLAY_FILE=boards/native_sim_ev_0x00.overlay + platform_allow: native_sim filesystem.fcb.qemu_x86.fcb_0x00: extra_args: DTC_OVERLAY_FILE=boards/qemu_x86_ev_0x00.overlay platform_allow: qemu_x86 diff --git a/tests/subsys/fs/fs_api/testcase.yaml b/tests/subsys/fs/fs_api/testcase.yaml index 7f8e1a03b27a272..635598cc85645ac 100644 --- a/tests/subsys/fs/fs_api/testcase.yaml +++ b/tests/subsys/fs/fs_api/testcase.yaml @@ -2,4 +2,4 @@ tests: filesystem.api: tags: filesystem integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/fs/littlefs/boards/native_posix_64.overlay b/tests/subsys/fs/littlefs/boards/native_posix_64.overlay deleted file mode 100644 index f44d78c8a1150b4..000000000000000 --- a/tests/subsys/fs/littlefs/boards/native_posix_64.overlay +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&flashcontroller0 { - reg = <0x00000000 DT_SIZE_K(4096)>; -}; - -&flash0 { - reg = <0x00000000 DT_SIZE_K(4096)>; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - small_partition: partition@0 { - label = "small"; - reg = <0x00000000 0x00010000>; - }; - medium_partition: partition@10000 { - label = "medium"; - reg = <0x00010000 0x000F0000>; - }; - large_partition: partition@100000 { - label = "large"; - reg = <0x00100000 0x00300000>; - }; - }; -}; diff --git a/tests/subsys/fs/littlefs/boards/native_posix.overlay b/tests/subsys/fs/littlefs/boards/native_sim.overlay similarity index 100% rename from tests/subsys/fs/littlefs/boards/native_posix.overlay rename to tests/subsys/fs/littlefs/boards/native_sim.overlay diff --git a/tests/subsys/fs/littlefs/boards/native_sim_64.overlay b/tests/subsys/fs/littlefs/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..8dbed8eb97ab75a --- /dev/null +++ b/tests/subsys/fs/littlefs/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/fs/littlefs/testcase.yaml b/tests/subsys/fs/littlefs/testcase.yaml index 4fa20c791a9eb77..211137180f8a7fe 100644 --- a/tests/subsys/fs/littlefs/testcase.yaml +++ b/tests/subsys/fs/littlefs/testcase.yaml @@ -4,8 +4,8 @@ common: - littlefs platform_allow: - nrf52840dk_nrf52840 - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 - mimxrt1060_evk - mr_canhubk3 integration_platforms: diff --git a/tests/subsys/fs/multi-fs/testcase.yaml b/tests/subsys/fs/multi-fs/testcase.yaml index b4c1e49d1950442..35d4c5626078745 100644 --- a/tests/subsys/fs/multi-fs/testcase.yaml +++ b/tests/subsys/fs/multi-fs/testcase.yaml @@ -12,15 +12,17 @@ tests: - EXTRA_DTC_OVERLAY_FILE="ramdisk.overlay" platform_allow: - native_posix + - native_sim - qemu_x86 integration_platforms: - - native_posix + - native_sim filesystem.fs_shell: extra_args: - CONF_FILE="prj_fs_shell.conf" - EXTRA_DTC_OVERLAY_FILE="ramdisk.overlay" platform_allow: - native_posix + - native_sim - qemu_x86 integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/fs/nvs/boards/native_posix.overlay b/tests/subsys/fs/nvs/boards/native_sim.overlay similarity index 100% rename from tests/subsys/fs/nvs/boards/native_posix.overlay rename to tests/subsys/fs/nvs/boards/native_sim.overlay diff --git a/tests/subsys/fs/nvs/src/main.c b/tests/subsys/fs/nvs/src/main.c index 34899277f55471b..d8cedee63a1688d 100644 --- a/tests/subsys/fs/nvs/src/main.c +++ b/tests/subsys/fs/nvs/src/main.c @@ -8,11 +8,11 @@ * This test is designed to be run using flash-simulator which provide * functionality for flash property customization and emulating errors in * flash operation in parallel to regular flash API. - * Test should be run on qemu_x86 or native_posix target. + * Test should be run on qemu_x86 or native_sim target. */ -#if !defined(CONFIG_BOARD_QEMU_X86) && !defined(CONFIG_BOARD_NATIVE_POSIX) -#error "Run on qemu_x86 or native_posix only" +#if !defined(CONFIG_BOARD_QEMU_X86) && !defined(CONFIG_ARCH_POSIX) +#error "Run only on qemu_x86 or a posix architecture based target (for ex. native_sim)" #endif #include diff --git a/tests/subsys/fs/nvs/testcase.yaml b/tests/subsys/fs/nvs/testcase.yaml index fd8386ffbd77f3f..f462a33ff0ed527 100644 --- a/tests/subsys/fs/nvs/testcase.yaml +++ b/tests/subsys/fs/nvs/testcase.yaml @@ -10,4 +10,4 @@ tests: extra_args: - CONFIG_NVS_LOOKUP_CACHE=y - CONFIG_NVS_LOOKUP_CACHE_SIZE=64 - platform_allow: native_posix + platform_allow: native_sim From 13b7557fe10b037ced8aa5cdac2d064bb1c45ca5 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 15:54:07 +0100 Subject: [PATCH 0873/1049] tests/subsys/modem/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim And add native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/modem/backends/tty/testcase.yaml | 6 +++++- tests/subsys/modem/modem_chat/testcase.yaml | 6 +++++- tests/subsys/modem/modem_cmux/testcase.yaml | 6 +++++- tests/subsys/modem/modem_ppp/testcase.yaml | 6 +++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/subsys/modem/backends/tty/testcase.yaml b/tests/subsys/modem/backends/tty/testcase.yaml index 11f78b1d64120ce..28d3c3d4aa288be 100644 --- a/tests/subsys/modem/backends/tty/testcase.yaml +++ b/tests/subsys/modem/backends/tty/testcase.yaml @@ -5,4 +5,8 @@ tests: modem.backends.tty: tags: modem_backend_tty harness: ztest - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/subsys/modem/modem_chat/testcase.yaml b/tests/subsys/modem/modem_chat/testcase.yaml index 8716d7f0d17071b..2b8723428ea7e31 100644 --- a/tests/subsys/modem/modem_chat/testcase.yaml +++ b/tests/subsys/modem/modem_chat/testcase.yaml @@ -5,4 +5,8 @@ tests: modem.modem_chat: tags: modem_chat harness: ztest - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/subsys/modem/modem_cmux/testcase.yaml b/tests/subsys/modem/modem_cmux/testcase.yaml index c7d1f53a0853b8a..fd89a3f565649ea 100644 --- a/tests/subsys/modem/modem_cmux/testcase.yaml +++ b/tests/subsys/modem/modem_cmux/testcase.yaml @@ -5,4 +5,8 @@ tests: modem.modem_cmux: tags: modem_cmux harness: ztest - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim diff --git a/tests/subsys/modem/modem_ppp/testcase.yaml b/tests/subsys/modem/modem_ppp/testcase.yaml index 0b3fef701f3ab38..7e0937ea1449529 100644 --- a/tests/subsys/modem/modem_ppp/testcase.yaml +++ b/tests/subsys/modem/modem_ppp/testcase.yaml @@ -5,4 +5,8 @@ tests: modem.modem_ppp: tags: modem_ppp harness: ztest - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim From f59c9c0ddea97c668320a10547c1f75c8c8d13d2 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 16:16:03 +0100 Subject: [PATCH 0874/1049] tests/subsys/input/*: Switch to native_sim Switch from native_posix to native_sim as default test platform And switch overlays to native_sim. Signed-off-by: Alberto Escolar Piedras --- .../boards/{native_posix.overlay => native_sim.overlay} | 0 .../{native_posix_64.overlay => native_sim_64.overlay} | 2 +- tests/subsys/input/input_longpress/testcase.yaml | 6 +++--- tests/subsys/input/input_shell/testcase.yaml | 4 ++++ 4 files changed, 8 insertions(+), 4 deletions(-) rename tests/subsys/input/input_longpress/boards/{native_posix.overlay => native_sim.overlay} (100%) rename tests/subsys/input/input_longpress/boards/{native_posix_64.overlay => native_sim_64.overlay} (70%) diff --git a/tests/subsys/input/input_longpress/boards/native_posix.overlay b/tests/subsys/input/input_longpress/boards/native_sim.overlay similarity index 100% rename from tests/subsys/input/input_longpress/boards/native_posix.overlay rename to tests/subsys/input/input_longpress/boards/native_sim.overlay diff --git a/tests/subsys/input/input_longpress/boards/native_posix_64.overlay b/tests/subsys/input/input_longpress/boards/native_sim_64.overlay similarity index 70% rename from tests/subsys/input/input_longpress/boards/native_posix_64.overlay rename to tests/subsys/input/input_longpress/boards/native_sim_64.overlay index 166e6f02e82d5b0..a906fce7488c3fc 100644 --- a/tests/subsys/input/input_longpress/boards/native_posix_64.overlay +++ b/tests/subsys/input/input_longpress/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/subsys/input/input_longpress/testcase.yaml b/tests/subsys/input/input_longpress/testcase.yaml index 10ca378dd60f078..8ad1d41a31afbe1 100644 --- a/tests/subsys/input/input_longpress/testcase.yaml +++ b/tests/subsys/input/input_longpress/testcase.yaml @@ -3,10 +3,10 @@ tests: input.input_longpress: platform_allow: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 tags: - drivers - input integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/input/input_shell/testcase.yaml b/tests/subsys/input/input_shell/testcase.yaml index e226780164f7518..2848957f74a38bb 100644 --- a/tests/subsys/input/input_shell/testcase.yaml +++ b/tests/subsys/input/input_shell/testcase.yaml @@ -6,6 +6,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - native_sim harness: console harness_config: type: multi_line From 6d762359a563c556ac665a1af9dca0796021223b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 20 Nov 2023 16:20:49 +0100 Subject: [PATCH 0875/1049] tests/subsys/storage/*: Switch to native_sim Enable all these tests which run in native_posix in native_sim, Switch from native_posix to native_sim as default test platform Signed-off-by: Alberto Escolar Piedras --- tests/subsys/storage/flash_map/testcase.yaml | 8 +++++-- .../storage/stream/stream_flash/testcase.yaml | 22 ++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/subsys/storage/flash_map/testcase.yaml b/tests/subsys/storage/flash_map/testcase.yaml index b9b13002d520b57..1d03fc2ed2f24af 100644 --- a/tests/subsys/storage/flash_map/testcase.yaml +++ b/tests/subsys/storage/flash_map/testcase.yaml @@ -5,10 +5,12 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 tags: flash_map integration_platforms: - - native_posix + - native_sim storage.flash_map.mpu: extra_args: OVERLAY_CONFIG=overlay-mpu.conf platform_allow: @@ -27,7 +29,9 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 tags: flash_map integration_platforms: - - native_posix + - native_sim diff --git a/tests/subsys/storage/stream/stream_flash/testcase.yaml b/tests/subsys/storage/stream/stream_flash/testcase.yaml index 4caff73e58db98c..9f4b8c163838d62 100644 --- a/tests/subsys/storage/stream/stream_flash/testcase.yaml +++ b/tests/subsys/storage/stream/stream_flash/testcase.yaml @@ -1,22 +1,24 @@ +common: + platform_allow: + - native_posix + - native_posix_64 + - native_sim + - native_sim_64 + integration_platforms: + - native_sim tests: storage.stream_flash: - platform_allow: - - native_posix - - native_posix_64 tags: stream_flash storage.stream_flash.dword_wbs: extra_args: DTC_OVERLAY_FILE=unaligned_flush.overlay - platform_allow: - - native_posix - - native_posix_64 tags: stream_flash storage.stream_flash.no_erase: extra_args: OVERLAY_CONFIG=no_erase.overlay - platform_allow: - - native_posix - - native_posix_64 tags: stream_flash storage.stream_flash.mpu_allow_flash_write: extra_args: OVERLAY_CONFIG=mpu_allow_flash_write.overlay - platform_allow: nrf52840dk_nrf52840 + platform_allow: + - nrf52840dk_nrf52840 + integration_platforms: + - nrf52840dk_nrf52840 tags: stream_flash From eb127538b10e792179d60ca7124e9f41571e487c Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 13 Nov 2023 13:33:58 +0200 Subject: [PATCH 0876/1049] test: lwm2m: Mark some tests as slow This allows quick filtering with pytest_args: ['-k not slow'] Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/pytest/pytest.ini | 3 +++ tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py | 9 +++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/net/lib/lwm2m/interop/pytest/pytest.ini diff --git a/tests/net/lib/lwm2m/interop/pytest/pytest.ini b/tests/net/lib/lwm2m/interop/pytest/pytest.ini new file mode 100644 index 000000000000000..761785364d830bb --- /dev/null +++ b/tests/net/lib/lwm2m/interop/pytest/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +markers = + slow: marks tests as slow (deselect with '-m "not slow"') diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index 8f3acd69c7e3430..c37a3900aa6a486 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -51,6 +51,7 @@ def test_LightweightM2M_1_1_int_104(shell: Shell, dut: DeviceAdapter, leshan: Le leshan.execute(endpoint, '1/0/8') dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) +@pytest.mark.slow def test_LightweightM2M_1_1_int_107(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-107 - Extending the lifetime of a registration""" leshan.write(endpoint, '1/0/1', 120) @@ -66,6 +67,7 @@ def test_LightweightM2M_1_1_int_108(leshan, endpoint): """LightweightM2M-1.1-int-108 - Turn on Queue Mode""" assert leshan.get(f'/clients/{endpoint}')["queuemode"] +@pytest.mark.slow def test_LightweightM2M_1_1_int_109(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-109 - Behavior in Queue Mode""" logger.debug('Wait for Queue RX OFF') @@ -500,6 +502,7 @@ def test_LightweightM2M_1_1_int_281(shell: Shell, leshan: Leshan, endpoint: str) # Information Reporting Interface [300-399] # +@pytest.mark.slow def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-301 - Observation and Notification of parameter values""" pwr_src = leshan.read(endpoint, '3/0/6') @@ -527,6 +530,7 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) assert (start + 15) <= time.time() + 1 # Allow 1 second slack. (pMinx + pMax=15) leshan.cancel_observe(endpoint, '3/0/7') +@pytest.mark.slow def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation""" leshan.observe(endpoint, '3/0/7') @@ -546,6 +550,7 @@ def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write /3/0/8/0 -u32 50') dut.readlines_until(regex=r'.*Observer removed for 3/0/8') +@pytest.mark.slow def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-304 - Observe-Composite Operation""" assert leshan.put_raw(f'/clients/{endpoint}/1/0/1/attributes?pmin=30')['status'] == 'CHANGED(204)' @@ -590,6 +595,8 @@ def test_LightweightM2M_1_1_int_307(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m send /3/0') dut.readlines_until(regex=r'.*SEND status: 0', timeout=5.0) + +@pytest.mark.slow def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-308 - Observe-Composite and Creating Object Instance""" shell.exec_command('lwm2m delete /16/0') @@ -631,6 +638,7 @@ def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') +@pytest.mark.slow def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-309 - Observe-Composite and Deleting Object Instance""" shell.exec_command('lwm2m delete /16/0') @@ -673,6 +681,7 @@ def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') +@pytest.mark.slow def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-310 - Observe-Composite and modification of parameter values""" # Need to use Configuration C.1 From 92ceaab491a0a579a585b55c85d66673bceb7ea6 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 13 Nov 2023 16:02:07 +0200 Subject: [PATCH 0877/1049] test: lwm2m: Implement write_attributes() Implement write and remove attributes command for Leshan. Remove all written attributes at the end of test, so it won't affect the next test case. Remove skip marks from testcase that is fixed on Leshan side. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/README.md | 2 +- tests/net/lib/lwm2m/interop/pytest/leshan.py | 19 ++++++- .../lib/lwm2m/interop/pytest/test_lwm2m.py | 56 ++++++++++--------- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index bda38924d266e67..3654ca94b0142d8 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -167,7 +167,7 @@ Tests are written from test spec; |LightweightM2M-1.1-int-256 - Write Operation Failure|:white_check_mark:| | |LightweightM2M-1.1-int-257 - Write-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-260 - Discover Command|:white_check_mark:| | -|LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource|:large_orange_diamond:|Leshan don't allow writing attributes to resource instance| +|LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource|:white_check_mark:| | |LightweightM2M-1.1-int-280 - Successful Read-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-281 - Partially Successful Read-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-301 - Observation and Notification of parameter values|:white_check_mark:| | diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 7240aae2baf8739..4add988ea77137e 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -62,9 +62,9 @@ def get(self, path: str): resp = self._s.get(f'{self.api_url}{path}', params=params, timeout=self.timeout) return Leshan.handle_response(resp) - def put_raw(self, path: str, data: str | dict | None = None, headers: dict | None = None): + def put_raw(self, path: str, data: str | dict | None = None, headers: dict | None = None, params: dict | None = None): """Send HTTP PUT query without any default parameters""" - resp = self._s.put(f'{self.api_url}{path}', data=data, headers=headers, timeout=self.timeout) + resp = self._s.put(f'{self.api_url}{path}', data=data, headers=headers, params=params, timeout=self.timeout) return Leshan.handle_response(resp) def put(self, path: str, data: str | dict, uri_options: str = ''): @@ -108,6 +108,21 @@ def write(self, endpoint: str, path: str, value: bool | int | str): rid = path.split('/')[-1] return self.put(f'/clients/{endpoint}/{path}', self._define_resource(rid, value, kind)) + def write_attributes(self, endpoint: str, path: str, attributes: dict): + """Send LwM2M Write-Attributes to given path + example: + leshan.write_attributes(endpoint, '1/2/3, {'pmin': 10, 'pmax': 40}) + """ + return self.put_raw(f'/clients/{endpoint}/{path}/attributes', params=attributes) + + def remove_attributes(self, endpoint: str, path: str, attributes: list): + """Send LwM2M Write-Attributes to given path + example: + leshan.remove_attributes(endpoint, '1/2/3, ['pmin', 'pmax']) + """ + attrs = '&'.join(attributes) + return self.put_raw(f'/clients/{endpoint}/{path}/attributes?'+ attrs) + def update_obj_instance(self, endpoint: str, path: str, resources: dict): """Update object instance""" data = self._define_obj_inst(path, resources) diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index c37a3900aa6a486..f596f74d30ab93d 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -202,7 +202,7 @@ def test_LightweightM2M_1_1_int_221(shell: Shell, leshan: Leshan, endpoint: str) """LightweightM2M-1.1-int-221 - Attempt to perform operations on Security""" assert leshan.read(endpoint, '0/0')['status'] == 'UNAUTHORIZED(401)' assert leshan.write(endpoint, '0/0/0', 'coap://localhost')['status'] == 'UNAUTHORIZED(401)' - assert leshan.put_raw(f'/clients/{endpoint}/0/attributes?pmin=10')['status'] == 'UNAUTHORIZED(401)' + assert leshan.write_attributes(endpoint, '0', {'pmin':10})['status'] == 'UNAUTHORIZED(401)' def test_LightweightM2M_1_1_int_222(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-222 - Read on Object""" @@ -429,15 +429,12 @@ def test_LightweightM2M_1_1_int_260(shell: Shell, leshan: Leshan, endpoint: str) expected_keys = ['/3', '/3/0', '/3/0/1', '/3/0/2', '/3/0/3', '/3/0/4', '/3/0/6', '/3/0/7', '/3/0/8', '/3/0/9', '/3/0/11', '/3/0/16'] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmin=10')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmax=200')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3', {'pmin': 10, 'pmax': 200})['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0') assert int(resp['/3/0/6']['dim']) == 2 assert int(resp['/3/0/7']['dim']) == 2 assert int(resp['/3/0/8']['dim']) == 2 - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?lt=1')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?gt=6')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?st=1')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3/0/7', {'lt': 1, 'gt': 6, 'st': 1})['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0') expected_keys = ['/3/0', '/3/0/1', '/3/0/2', '/3/0/3', '/3/0/4', '/3/0/6', '/3/0/7', '/3/0/8', '/3/0/9', '/3/0/11', '/3/0/16'] missing_keys = [key for key in expected_keys if key not in resp.keys()] @@ -451,8 +448,9 @@ def test_LightweightM2M_1_1_int_260(shell: Shell, leshan: Leshan, endpoint: str) missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 assert len(resp) == len(expected_keys) + # restore + leshan.remove_attributes(endpoint, '3', ['pmin', 'pmax']) -@pytest.mark.skip(reason="Leshan don't allow writing attributes to resource instance") def test_LightweightM2M_1_1_int_261(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource""" resp = leshan.discover(endpoint, '3/0/11') @@ -462,19 +460,20 @@ def test_LightweightM2M_1_1_int_261(shell: Shell, leshan: Leshan, endpoint: str) assert len(missing_keys) == 0 assert len(resp) == len(expected_keys) assert int(resp['/3/0/11']['dim']) == 1 - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmin=10')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmax=200')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/attributes?pmax=320')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/11/0/attributes?pmax=100')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/11/0/attributes?epmin=1')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/11/0/attributes?epmax=20')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3', {'pmin':10, 'pmax':200})['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3/0', {'pmax':320})['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3/0/11/0', {'pmax':100, 'epmin':1, 'epmax':20})['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0/11') logger.debug(resp) assert int(resp['/3/0/11']['pmin']) == 10 assert int(resp['/3/0/11']['pmax']) == 320 assert int(resp['/3/0/11/0']['pmax']) == 100 - assert int(resp['/3/0/11/0']['epmin']) == 1 - assert int(resp['/3/0/11/0']['epmax']) == 20 + # Note: Zephyr does not support epmin&epmax. + # Restore + leshan.remove_attributes(endpoint, '3', ['pmin', 'pmax']) + leshan.remove_attributes(endpoint, '3/0', ['pmax']) + leshan.remove_attributes(endpoint, '3/0/11/0', ['pmax']) + def test_LightweightM2M_1_1_int_280(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-280 - Successful Read-Composite Operation""" @@ -509,8 +508,7 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) logger.debug(pwr_src) assert pwr_src[6][0] == 1 assert pwr_src[6][1] == 5 - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?pmin=5')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/3/0/7/attributes?pmax=10')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3/0/7', {'pmin': 5, 'pmax': 10})['status'] == 'CHANGED(204)' leshan.observe(endpoint, '3/0/7') with leshan.get_event_stream(endpoint, timeout=30) as events: shell.exec_command('lwm2m write /3/0/7/0 -u32 3000') @@ -529,6 +527,7 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) assert data[3][0][7][0] == 3500 assert (start + 15) <= time.time() + 1 # Allow 1 second slack. (pMinx + pMax=15) leshan.cancel_observe(endpoint, '3/0/7') + leshan.remove_attributes(endpoint, '3/0/7', ['pmin', 'pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): @@ -553,8 +552,10 @@ def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Le @pytest.mark.slow def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-304 - Observe-Composite Operation""" - assert leshan.put_raw(f'/clients/{endpoint}/1/0/1/attributes?pmin=30')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/1/0/1/attributes?pmax=45')['status'] == 'CHANGED(204)' + # Need to use Configuration C.1 + shell.exec_command('lwm2m write 1/0/2 -u32 0') + shell.exec_command('lwm2m write 1/0/3 -u32 0') + assert leshan.write_attributes(endpoint, '1/0/1', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) assert data[1][0][1] is not None assert data[3][0][11][0] is not None @@ -575,6 +576,10 @@ def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str) assert (start + 30) < time.time() assert (start + 45) > time.time() - 1 leshan.cancel_composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) + # Restore configuration C.3 + shell.exec_command('lwm2m write 1/0/2 -u32 1') + shell.exec_command('lwm2m write 1/0/3 -u32 10') + leshan.remove_attributes(endpoint, '1/0/1', ['pmin', 'pmax']) def test_LightweightM2M_1_1_int_306(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-306 - Send Operation""" @@ -620,8 +625,7 @@ def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Le content_both = {16: {0: resources_a, 1: resources_b}} assert leshan.create_obj_instance(endpoint, '16/0', resources_a)['status'] == 'CREATED(201)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) - assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmin=30')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmax=45')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '16/0', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/16/0', '/16/1']) assert data == content_one with leshan.get_event_stream(endpoint, timeout=50) as events: @@ -637,6 +641,7 @@ def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Le # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') + leshan.remove_attributes(endpoint, '16/0', ['pmin','pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): @@ -663,8 +668,7 @@ def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Le assert leshan.create_obj_instance(endpoint, '16/0', resources_a)['status'] == 'CREATED(201)' assert leshan.create_obj_instance(endpoint, '16/1', resources_b)['status'] == 'CREATED(201)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) - assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmin=30')['status'] == 'CHANGED(204)' - assert leshan.put_raw(f'/clients/{endpoint}/16/0/attributes?pmax=45')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '16/0', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/16/0', '/16/1']) assert data == content_both with leshan.get_event_stream(endpoint, timeout=50) as events: @@ -680,6 +684,7 @@ def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Le # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') + leshan.remove_attributes(endpoint, '16/0', ['pmin', 'pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str): @@ -687,11 +692,9 @@ def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str) # Need to use Configuration C.1 shell.exec_command('lwm2m write 1/0/2 -u32 0') shell.exec_command('lwm2m write 1/0/3 -u32 0') - # Ensure that our previous attributes are not conflicting - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmin=0')['status'] == 'CHANGED(204)' leshan.composite_observe(endpoint, ['/1/0/1', '/3/0']) with leshan.get_event_stream(endpoint, timeout=50) as events: - assert leshan.put_raw(f'/clients/{endpoint}/3/attributes?pmax=5')['status'] == 'CHANGED(204)' + assert leshan.write_attributes(endpoint, '3', {'pmax': 5})['status'] == 'CHANGED(204)' start = time.time() data = events.next_event('NOTIFICATION') assert data[3][0][0] == 'Zephyr' @@ -704,6 +707,7 @@ def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str) # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') + leshan.remove_attributes(endpoint, '3', ['pmax']) def test_LightweightM2M_1_1_int_311(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-311 - Send command""" From 2135e009e4d9dbc77a9083313705236708868dad Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 13 Nov 2023 16:36:03 +0200 Subject: [PATCH 0878/1049] test: lwm2m: Implement Read-Composite Operation on root path Test case: LightweightM2M-1.1-int-235 - Read-Composite Operation on root path is now working as Leshan added a support for reading the root path. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/README.md | 2 +- tests/net/lib/lwm2m/interop/pytest/leshan.py | 4 ++++ tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py | 7 +++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 3654ca94b0142d8..204aff636ac5d1e 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -160,7 +160,7 @@ Tests are written from test spec; |LightweightM2M-1.1-int-232 - Querying basic information in SenML CBOR format|:white_check_mark:| | |LightweightM2M-1.1-int-233 - Setting basic information in SenML CBOR format|:white_check_mark:| | |LightweightM2M-1.1-int-234 - Setting basic information in SenML JSON format|:white_check_mark:| | -|LightweightM2M-1.1-int-235 - Read-Composite Operation on root path|:large_orange_diamond:|Root Path is not yet supported by Leshan.| +|LightweightM2M-1.1-int-235 - Read-Composite Operation on root path|:white_check_mark:| | |LightweightM2M-1.1-int-236 - Read-Composite - Partial Presence|:white_check_mark:| | |LightweightM2M-1.1-int-237 - Read on Object without specifying Content-Type|:white_check_mark:| | |LightweightM2M-1.1-int-241 - Executable Resource: Rebooting the device|:white_check_mark:| | diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 4add988ea77137e..65295e652bc1b68 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -271,6 +271,10 @@ def parse_composite(cls, payload: dict): raise RuntimeError(f'No content received') payload = payload['content'] for path, content in payload.items(): + if path == "/": + for obj in content['objects']: + data.update(cls._decode_obj(obj)) + continue keys = [int(key) for key in path.lstrip("/").split('/')] if len(keys) == 1: data.update(cls._decode_obj(content)) diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index f596f74d30ab93d..eabc4bbc61405b4 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -367,9 +367,12 @@ def test_LightweightM2M_1_1_int_234(shell: Shell, leshan: Leshan, endpoint: str) """LightweightM2M-1.1-int-234 - Setting basic information in SenML JSON format""" setting_basic_senml(shell, leshan, endpoint, 'SENML_JSON') -@pytest.mark.skip("Leshan does not allow reading root path") -def test_LightweightM2M_1_1_int_235(): +def test_LightweightM2M_1_1_int_235(leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-235 - Read-Composite Operation on root path""" + resp = leshan.composite_read(endpoint, ['/']) + expected_keys = [16, 1, 3, 5] + missing_keys = [key for key in expected_keys if key not in resp.keys()] + assert len(missing_keys) == 0 def test_LightweightM2M_1_1_int_236(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-236 - Read-Composite - Partial Presence""" From 31e9a5674267dbc3efc717f15bf601a2e064d1ec Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 20 Nov 2023 16:14:07 +0200 Subject: [PATCH 0879/1049] test: lwm2m: Test cancellation using observe parameter Implement test cases: LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation Modify existing Leshan API to passive_cancel(). Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/interop/README.md | 4 +-- tests/net/lib/lwm2m/interop/pytest/leshan.py | 7 +++++ .../lib/lwm2m/interop/pytest/test_lwm2m.py | 30 +++++++++++++++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/tests/net/lib/lwm2m/interop/README.md b/tests/net/lib/lwm2m/interop/README.md index 204aff636ac5d1e..3acbfcc71f80709 100644 --- a/tests/net/lib/lwm2m/interop/README.md +++ b/tests/net/lib/lwm2m/interop/README.md @@ -172,9 +172,9 @@ Tests are written from test spec; |LightweightM2M-1.1-int-281 - Partially Successful Read-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-301 - Observation and Notification of parameter values|:white_check_mark:| | |LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation|:white_check_mark:| | -|LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter|:large_orange_diamond:|Leshan only supports passive cancelling| +|LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter|:white_check_mark:|| |LightweightM2M-1.1-int-304 - Observe-Composite Operation|:white_check_mark:| | -|LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation|:large_orange_diamond:|Leshan only supports passive cancelling| +|LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation|:white_check_mark:| | |LightweightM2M-1.1-int-306 – Send Operation|:white_check_mark:|[~~#64290~~](https://github.com/zephyrproject-rtos/zephyr/issues/64290)| |LightweightM2M-1.1-int-307 – Muting Send|:white_check_mark:| | |LightweightM2M-1.1-int-308 - Observe-Composite and Creating Object Instance|:white_check_mark:|[~~#64634~~](https://github.com/zephyrproject-rtos/zephyr/issues/64634)| diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 65295e652bc1b68..181f15ebf6138e2 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -389,6 +389,9 @@ def observe(self, endpoint: str, path: str): return self.post(f'/clients/{endpoint}/{path}/observe', data="") def cancel_observe(self, endpoint: str, path: str): + return self.delete_raw(f'/clients/{endpoint}/{path}/observe?active') + + def passive_cancel_observe(self, endpoint: str, path: str): return self.delete_raw(f'/clients/{endpoint}/{path}/observe') def composite_observe(self, endpoint: str, paths: list[str]): @@ -398,6 +401,10 @@ def composite_observe(self, endpoint: str, paths: list[str]): return self.parse_composite(payload) def cancel_composite_observe(self, endpoint: str, paths: list[str]): + paths = [path if path.startswith('/') else '/' + path for path in paths] + return self.delete_raw(f'/clients/{endpoint}/composite/observe?paths=' + ','.join(paths) + '&active') + + def passive_cancel_composite_observe(self, endpoint: str, paths: list[str]): paths = [path if path.startswith('/') else '/' + path for path in paths] return self.delete_raw(f'/clients/{endpoint}/composite/observe?paths=' + ','.join(paths)) diff --git a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py index eabc4bbc61405b4..131acb68e14cef4 100644 --- a/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py +++ b/tests/net/lib/lwm2m/interop/pytest/test_lwm2m.py @@ -532,7 +532,6 @@ def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str) leshan.cancel_observe(endpoint, '3/0/7') leshan.remove_attributes(endpoint, '3/0/7', ['pmin', 'pmax']) -@pytest.mark.slow def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation""" leshan.observe(endpoint, '3/0/7') @@ -541,17 +540,34 @@ def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Le shell.exec_command('lwm2m write /3/0/7/0 -u32 4000') data = events.next_event('NOTIFICATION') assert data[3][0][7][0] == 4000 - leshan.cancel_observe(endpoint, '3/0/7') + leshan.passive_cancel_observe(endpoint, '3/0/7') shell.exec_command('lwm2m write /3/0/7/0 -u32 3000') dut.readlines_until(regex=r'.*Observer removed for 3/0/7') with leshan.get_event_stream(endpoint) as events: shell.exec_command('lwm2m write /3/0/8/0 -u32 100') data = events.next_event('NOTIFICATION') assert data[3][0][8][0] == 100 - leshan.cancel_observe(endpoint, '3/0/8') + leshan.passive_cancel_observe(endpoint, '3/0/8') shell.exec_command('lwm2m write /3/0/8/0 -u32 50') dut.readlines_until(regex=r'.*Observer removed for 3/0/8') +def test_LightweightM2M_1_1_int_303(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): + """LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter""" + leshan.observe(endpoint, '3/0/7') + leshan.observe(endpoint, '3/0/8') + with leshan.get_event_stream(endpoint) as events: + shell.exec_command('lwm2m write /3/0/7/0 -u32 4000') + data = events.next_event('NOTIFICATION') + assert data[3][0][7][0] == 4000 + leshan.cancel_observe(endpoint, '3/0/7') + dut.readlines_until(regex=r'.*Observer removed for 3/0/7') + with leshan.get_event_stream(endpoint) as events: + shell.exec_command('lwm2m write /3/0/8/0 -u32 100') + data = events.next_event('NOTIFICATION') + assert data[3][0][8][0] == 100 + leshan.cancel_observe(endpoint, '3/0/8') + dut.readlines_until(regex=r'.*Observer removed for 3/0/8') + @pytest.mark.slow def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-304 - Observe-Composite Operation""" @@ -584,6 +600,14 @@ def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str) shell.exec_command('lwm2m write 1/0/3 -u32 10') leshan.remove_attributes(endpoint, '1/0/1', ['pmin', 'pmax']) +def test_LightweightM2M_1_1_int_305(dut: DeviceAdapter, leshan: Leshan, endpoint: str): + """LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation""" + leshan.composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) + leshan.cancel_composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) + dut.readlines_until(regex=r'.*Observer removed for 1/0/1') + dut.readlines_until(regex=r'.*Observer removed for 3/0/11/0') + dut.readlines_until(regex=r'.*Observer removed for 3/0/16') + def test_LightweightM2M_1_1_int_306(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-306 - Send Operation""" with leshan.get_event_stream(endpoint) as events: From 90dfbf99d8e83e11bfae64fb1216613e24ac0bcc Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 20 Nov 2023 15:00:59 +0000 Subject: [PATCH 0880/1049] drivers: ieee802154: nrf5: Fix missed variable rename Fixes and issue with a variable that has been renamed but whose reference in the source file has not Signed-off-by: Jamie McCrae --- drivers/ieee802154/ieee802154_nrf5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 9a02aef7e4ce7f0..2b7d9b8fb6d3a1f 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -930,9 +930,9 @@ static int nrf5_configure(const struct device *dev, #if defined(CONFIG_NRF_802154_SER_HOST) net_time_t period_ns = nrf5_data.csl_period * NSEC_PER_TEN_SYMBOLS; - bool changed = (config->csl_rx_time - nrf5_data.csl_rx_time) % period_ns; + bool changed = (config->expected_rx_time - nrf5_data.csl_rx_time) % period_ns; - nrf5_data.csl_rx_time = config->csl_rx_time; + nrf5_data.csl_rx_time = config->expected_rx_time; if (changed) #endif /* CONFIG_NRF_802154_SER_HOST */ From 98f33a76d69fd13ce6c2f741f2b8823409f13349 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Nov 2023 15:06:08 +0200 Subject: [PATCH 0881/1049] drivers: tsl2561: Fix type Use int as correct type, fixes also warning comparing uint8_t < 0. Signed-off-by: Andrei Emeltchenko --- drivers/sensor/tsl2561/tsl2561.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/tsl2561/tsl2561.c b/drivers/sensor/tsl2561/tsl2561.c index 42efffb224243b0..0e5c0209b6b194f 100644 --- a/drivers/sensor/tsl2561/tsl2561.c +++ b/drivers/sensor/tsl2561/tsl2561.c @@ -136,7 +136,7 @@ static int tsl2561_sample_fetch(const struct device *dev, enum sensor_channel ch const struct tsl2561_config *config = dev->config; struct tsl2561_data *data = dev->data; uint8_t bytes[2]; - uint8_t ret; + int ret; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_LIGHT) { LOG_ERR("Unsupported sensor channel"); From 69d4c13ab39fd36a67d4f1efc835c2d3bb837172 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Tue, 21 Nov 2023 17:21:55 +0100 Subject: [PATCH 0882/1049] dt-bindings: sensor: fix typos in ST sensors comment Fix dt-binding wrong filename in dts comment for ST sensors. Signed-off-by: Armando Visconti --- dts/bindings/sensor/st,iis2dlpc-common.yaml | 4 ++-- dts/bindings/sensor/st,iis2iclx-common.yaml | 4 ++-- dts/bindings/sensor/st,ism330dhcx-common.yaml | 4 ++-- dts/bindings/sensor/st,lis2dh-common.yaml | 4 ++-- dts/bindings/sensor/st,lis2ds12-common.yaml | 4 ++-- dts/bindings/sensor/st,lis2dw12-common.yaml | 4 ++-- dts/bindings/sensor/st,lps22df-common.yaml | 4 ++-- dts/bindings/sensor/st,lps22hh-common.yaml | 4 ++-- dts/bindings/sensor/st,lsm6dso-common.yaml | 4 ++-- dts/bindings/sensor/st,lsm6dso16is-common.yaml | 4 ++-- dts/bindings/sensor/st,lsm6dsv16x-common.yaml | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dts/bindings/sensor/st,iis2dlpc-common.yaml b/dts/bindings/sensor/st,iis2dlpc-common.yaml index 997b0b189f03c28..d21f4a6d195ae22 100644 --- a/dts/bindings/sensor/st,iis2dlpc-common.yaml +++ b/dts/bindings/sensor/st,iis2dlpc-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr property in a .dts or .dtsi file you may include - st_iis2dlpc.h and use the macros defined there. + iis2dlpc.h and use the macros defined there. Example: - #include + #include iis2dlpc: iis2dlpc@0 { ... diff --git a/dts/bindings/sensor/st,iis2iclx-common.yaml b/dts/bindings/sensor/st,iis2iclx-common.yaml index 0a312824c989d4a..73bf28940810fd4 100644 --- a/dts/bindings/sensor/st,iis2iclx-common.yaml +++ b/dts/bindings/sensor/st,iis2iclx-common.yaml @@ -3,10 +3,10 @@ description: | When setting the range, odr properties in a .dts or .dtsi file you may - include st_iis2iclx.h and use the macros defined there. + include iis2iclx.h and use the macros defined there. Example: - #include + #include iis2iclx: iis2iclx@0 { ... diff --git a/dts/bindings/sensor/st,ism330dhcx-common.yaml b/dts/bindings/sensor/st,ism330dhcx-common.yaml index f00f37c17006691..a12ab3446c1a5c3 100644 --- a/dts/bindings/sensor/st,ism330dhcx-common.yaml +++ b/dts/bindings/sensor/st,ism330dhcx-common.yaml @@ -3,10 +3,10 @@ description: | When setting the accel-odr and gyro-odr properties in a .dts or .dtsi file you may include - st_ism330dhcx.h and use the macros defined there. + ism330dhcx.h and use the macros defined there. Example: - #include + #include ism330dhcx: ism330dhcx@0 { ... diff --git a/dts/bindings/sensor/st,lis2dh-common.yaml b/dts/bindings/sensor/st,lis2dh-common.yaml index 351fa0dc97fda79..1988a7c1deb5e9b 100644 --- a/dts/bindings/sensor/st,lis2dh-common.yaml +++ b/dts/bindings/sensor/st,lis2dh-common.yaml @@ -3,10 +3,10 @@ description: | When setting the int1-gpio-config/int2-gpio-config and anym-mode properties - in a .dts or .dtsi file you may include st_lis2dh.h and use the macros defined there. + in a .dts or .dtsi file you may include lis2dh.h and use the macros defined there. Example: - #include + #include lis2dh: lis2dh@0 { ... diff --git a/dts/bindings/sensor/st,lis2ds12-common.yaml b/dts/bindings/sensor/st,lis2ds12-common.yaml index 4ac18b40a553c0e..230e57c0bb5d9a4 100644 --- a/dts/bindings/sensor/st,lis2ds12-common.yaml +++ b/dts/bindings/sensor/st,lis2ds12-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr and power-mode properties in a .dts or .dtsi file you may include - st_lis2ds12.h and use the macros defined there. + lis2ds12.h and use the macros defined there. Example: - #include + #include lis2ds12: lis2ds12@0 { ... diff --git a/dts/bindings/sensor/st,lis2dw12-common.yaml b/dts/bindings/sensor/st,lis2dw12-common.yaml index 0c9f8dcee678935..c95a97da3987ccd 100644 --- a/dts/bindings/sensor/st,lis2dw12-common.yaml +++ b/dts/bindings/sensor/st,lis2dw12-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr property in a .dts or .dtsi file you may include - st_lis2dw12.h and use the macros defined there. + lis2dw12.h and use the macros defined there. Example: - #include + #include lis2dw12: lis2dw12@0 { ... diff --git a/dts/bindings/sensor/st,lps22df-common.yaml b/dts/bindings/sensor/st,lps22df-common.yaml index cc3f11c106fb388..f8b549606488269 100644 --- a/dts/bindings/sensor/st,lps22df-common.yaml +++ b/dts/bindings/sensor/st,lps22df-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr, lpf, avg properties in a .dts or .dtsi file - you may include st_lps22df.h and use the macros defined there. + you may include lps22df.h and use the macros defined there. Example: - #include + #include lps22df@5d { ... diff --git a/dts/bindings/sensor/st,lps22hh-common.yaml b/dts/bindings/sensor/st,lps22hh-common.yaml index eeeffe25f9687e6..a5e27c30b30d03d 100644 --- a/dts/bindings/sensor/st,lps22hh-common.yaml +++ b/dts/bindings/sensor/st,lps22hh-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr property in a .dts or .dtsi file you may include - st_lps22hh.h and use the macros defined there. + lps22hh.h and use the macros defined there. Example: - #include + #include lps22hh: lps22hh@0 { ... diff --git a/dts/bindings/sensor/st,lsm6dso-common.yaml b/dts/bindings/sensor/st,lsm6dso-common.yaml index 0b4b17df720b6a4..fe1c4d90ab1b98f 100644 --- a/dts/bindings/sensor/st,lsm6dso-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso-common.yaml @@ -3,11 +3,11 @@ description: | When setting the accel-pm, accel-range, accel-odr, gyro-pm, gyro-range, - gyro-odr properties in a .dts or .dtsi file you may include st_lsm6dso.h + gyro-odr properties in a .dts or .dtsi file you may include lsm6dso.h and use the macros defined there. Example: - #include + #include lsm6dso: lsm6dso@0 { ... diff --git a/dts/bindings/sensor/st,lsm6dso16is-common.yaml b/dts/bindings/sensor/st,lsm6dso16is-common.yaml index 49f7fd187fb67b0..07c1f21adeff148 100644 --- a/dts/bindings/sensor/st,lsm6dso16is-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso16is-common.yaml @@ -3,11 +3,11 @@ description: | When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in - a .dts or .dtsi file you may include st_lsm6dso16is.h and use the macros + a .dts or .dtsi file you may include lsm6dso16is.h and use the macros defined there. Example: - #include + #include lsm6dso16is: lsm6dso16is@0 { ... diff --git a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml index 99167a6506dadbd..420c1d728c48cc5 100644 --- a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml +++ b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml @@ -3,11 +3,11 @@ description: | When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in - a .dts or .dtsi file you may include st_lsm6dsv16x.h and use the macros + a .dts or .dtsi file you may include lsm6dsv16x.h and use the macros defined there. Example: - #include + #include lsm6dsv16x: lsm6dsv16x@0 { ... From a877bb50010ca230c34aff0f4e5767264e22d8ee Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 21 Nov 2023 12:46:45 +0100 Subject: [PATCH 0883/1049] timer: cortex_m_systick: add idle timer dependency Allow enabling the Cortex-m idle timer only if power management is set. It doesn't make sense to use an idle timer without PM. It allows adding the idle timer chosen node to dts without enabling the idle timer by default. Now, the PM config has to be set as well. Signed-off-by: Dawid Niedzwiecki --- drivers/timer/Kconfig.cortex_m_systick | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/timer/Kconfig.cortex_m_systick b/drivers/timer/Kconfig.cortex_m_systick index baf1f6c817efbd4..2a4f48832cf78a5 100644 --- a/drivers/timer/Kconfig.cortex_m_systick +++ b/drivers/timer/Kconfig.cortex_m_systick @@ -48,6 +48,7 @@ config CORTEX_M_SYSTICK_IDLE_TIMER default $(dt_chosen_enabled,$(DT_CHOSEN_IDLE_TIMER)) depends on COUNTER depends on TICKLESS_KERNEL + depends on PM help There are chips e.g. STMFX family that use SysTick as a system timer, but SysTick is not clocked in low power mode. These chips usually have From 3387c57a9448c144d08d643ebc4821ff21c01713 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 21 Nov 2023 12:55:11 +0100 Subject: [PATCH 0884/1049] dts: stm32f4: set RTC as idle timer by default Only RTC can be used as the idle timer for cortex-m systick. Set the chosen node as RTC by default. The idle timer will be enabled only if PM management is set. Signed-off-by: Dawid Niedzwiecki --- dts/arm/st/f4/stm32f4.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/arm/st/f4/stm32f4.dtsi b/dts/arm/st/f4/stm32f4.dtsi index f53c9cdf228228e..4a03abd609b80c8 100644 --- a/dts/arm/st/f4/stm32f4.dtsi +++ b/dts/arm/st/f4/stm32f4.dtsi @@ -22,6 +22,7 @@ / { chosen { zephyr,flash-controller = &flash; + zephyr,cortex-m-idle-timer = &rtc; }; cpus { From 3f1024b93f687266524898399e03e74d3ebc3bc5 Mon Sep 17 00:00:00 2001 From: ingram weeks Date: Tue, 31 Oct 2023 12:24:52 +0000 Subject: [PATCH 0885/1049] doc: README.rst added to subsys/console/echo sample README added to the console echo sample Signed-off-by: ingram weeks --- samples/subsys/console/echo/README.rst | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 samples/subsys/console/echo/README.rst diff --git a/samples/subsys/console/echo/README.rst b/samples/subsys/console/echo/README.rst new file mode 100644 index 000000000000000..b5851f16265591a --- /dev/null +++ b/samples/subsys/console/echo/README.rst @@ -0,0 +1,43 @@ +.. zephyr:code-sample:: console_echo + :name: Console echo + :relevant-api: console_api + + Echo an input character back to the output using the Console API. + +Overview +******** + +This example shows how the :c:func:`console_getchar` and +:c:func:`console_putchar` functions can be used to echo an input character +back to the console. + +Requirements +************ + +UART console is required to run this sample. + +Building and Running +******************** + +Build and flash the sample as follows, changing ``nucleo_f401re`` for your +board. Alternatively you can run this using QEMU, as described in +:zephyr:code-sample:`console_getchar`. + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/console/echo + :host-os: unix + :board: nucleo_f401re + :goals: build flash + :compact: + +Following the initial prompt given by the firmware, start pressing keys on a +keyboard, and they will be echoed back to the terminal program you are using. + +Sample Output +============= + +.. code-block:: console + + You should see another line with instructions below. If not, + the (interrupt-driven) console device doesn't work as expected: + Start typing characters to see them echoed back From 6718a21b56b9e85e9d696a8f60029e7a97a6239e Mon Sep 17 00:00:00 2001 From: ingram weeks Date: Thu, 2 Nov 2023 11:49:58 +0000 Subject: [PATCH 0886/1049] doc: console_api group added to doxygen console.h modified to include console api in doxygen Signed-off-by: ingram weeks --- include/zephyr/console/console.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/zephyr/console/console.h b/include/zephyr/console/console.h index 9ce09c081de8ae1..fbecfdad0d3bc88 100644 --- a/include/zephyr/console/console.h +++ b/include/zephyr/console/console.h @@ -15,6 +15,13 @@ extern "C" { #endif +/** + * @brief Console API + * @defgroup console_api Console API + * @ingroup os_services + * @{ + */ + /** @brief Initialize console device. * * This function should be called once to initialize pull-style @@ -107,4 +114,8 @@ char *console_getline(void); } #endif +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_CONSOLE_CONSOLE_H_ */ From 45a5cedfd6a0d647f6976547e3868a00b1d83269 Mon Sep 17 00:00:00 2001 From: ingram weeks Date: Mon, 6 Nov 2023 14:37:58 +0000 Subject: [PATCH 0887/1049] doc: Console.rst added to os_services docs Barebones Console.rst added to os_services docs Signed-off-by: ingram weeks --- doc/services/console.rst | 6 ++++++ doc/services/index.rst | 1 + 2 files changed, 7 insertions(+) create mode 100644 doc/services/console.rst diff --git a/doc/services/console.rst b/doc/services/console.rst new file mode 100644 index 000000000000000..05e506bb14a9644 --- /dev/null +++ b/doc/services/console.rst @@ -0,0 +1,6 @@ +.. _console: + +Console +####### + +.. doxygengroup:: console_api diff --git a/doc/services/index.rst b/doc/services/index.rst index c9055e8081f4547..9e4dc3c98dc15ef 100644 --- a/doc/services/index.rst +++ b/doc/services/index.rst @@ -8,6 +8,7 @@ OS Services binary_descriptors/index.rst + console.rst crypto/index debugging/index.rst device_mgmt/index From 8ec1b5487e464514e05d9dc2b678bc865fcee4a2 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 9 Nov 2023 15:48:28 +0000 Subject: [PATCH 0888/1049] input: gpio_kbd_matrix: add column drive mode Add an option to drive inactive columns to inactive state rather than high impedance. This is useful if the matrix has isolation diodes for every key, as it allows the matrix to stabilize faster and the API for changing the pin value is more efficient than the one to change the pin configuration. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 12 ++++++++++-- dts/bindings/input/gpio-kbd-matrix.yaml | 11 +++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index f81a01837f9ad11..f7310d37b65e58c 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -24,6 +24,7 @@ struct gpio_kbd_matrix_config { const struct gpio_dt_spec *col_gpio; struct gpio_callback *gpio_cb; gpio_callback_handler_t handler; + bool col_drive_inactive; }; struct gpio_kbd_matrix_data { @@ -53,7 +54,9 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) const struct gpio_dt_spec *gpio = &cfg->col_gpio[i]; if ((data->last_col_state ^ state) & BIT(i)) { - if (state & BIT(i)) { + if (cfg->col_drive_inactive) { + gpio_pin_set_dt(gpio, state & BIT(i)); + } else if (state & BIT(i)) { gpio_pin_configure_dt(gpio, GPIO_OUTPUT_ACTIVE); } else { gpio_pin_configure_dt(gpio, GPIO_INPUT); @@ -114,7 +117,11 @@ static int gpio_kbd_matrix_init(const struct device *dev) return -ENODEV; } - ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + if (cfg->col_drive_inactive) { + ret = gpio_pin_configure_dt(gpio, GPIO_OUTPUT_INACTIVE); + } else { + ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + } if (ret != 0) { LOG_ERR("Pin %d configuration failed: %d", i, ret); return ret; @@ -186,6 +193,7 @@ static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { .col_gpio = gpio_kbd_matrix_col_gpio_##n, \ .gpio_cb = gpio_kbd_matrix_gpio_cb_##n, \ .handler = gpio_kbd_matrix_cb_##n, \ + .col_drive_inactive = DT_INST_PROP(n, col_drive_inactive), \ }; \ \ static struct gpio_kbd_matrix_data gpio_kbd_matrix_data_##n; \ diff --git a/dts/bindings/input/gpio-kbd-matrix.yaml b/dts/bindings/input/gpio-kbd-matrix.yaml index ef08ebaa44e67a1..7cdc07dd4dd6854 100644 --- a/dts/bindings/input/gpio-kbd-matrix.yaml +++ b/dts/bindings/input/gpio-kbd-matrix.yaml @@ -39,5 +39,12 @@ properties: required: true description: | GPIO for the keyboard matrix columns, supports up to 32 different GPIOs. - The pins will be driven according to the GPIO_ACTIVE_HIGH or - GPIO_ACTIVE_LOW flags when selected, high impedance when not selected. + When unselected, this pin will be either driven to inactive state or + configured to high impedance (input) depending on the col-drive-inactive + property. + + col-drive-inactive: + type: boolean + description: | + If enabled, unselected column GPIOs will be driven to inactive state. + Default to configure unselected column GPIOs to high impedance. From 6cd72493ff2235b3f9f560d3f6e58a0068c1ffdd Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 9 Nov 2023 10:12:59 +0000 Subject: [PATCH 0889/1049] input: gpio_kbd_matrix: add direct access support When the matrix is connected to consecutive pins on the same port, it's possible to read the whole row or set the whole column in a single operation. For the column, this is only possible if the matrix is configured for driving unselected column, as there's no API to configure multiple pins at the same time at the moment. This is more efficient than checking the pins individually, and it's particularly useful if the row or columns are driven from a GPIO port expander. Add some code to detect the condition and enable it automatically as long as the hw configuration supports it. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index f7310d37b65e58c..3d8cc2a3104750c 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -30,6 +30,8 @@ struct gpio_kbd_matrix_config { struct gpio_kbd_matrix_data { struct input_kbd_matrix_common_data common; uint32_t last_col_state; + bool direct_read; + bool direct_write; }; INPUT_KBD_STRUCT_CHECK(struct gpio_kbd_matrix_config, @@ -50,6 +52,19 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) state = BIT(col); } + if (data->direct_write) { + const struct gpio_dt_spec *gpio0 = &cfg->col_gpio[0]; + gpio_port_pins_t gpio_mask; + gpio_port_value_t gpio_val; + + gpio_mask = BIT_MASK(common->col_size) << gpio0->pin; + gpio_val = state << gpio0->pin; + + gpio_port_set_masked(gpio0->port, gpio_mask, gpio_val); + + return; + } + for (int i = 0; i < common->col_size; i++) { const struct gpio_dt_spec *gpio = &cfg->col_gpio[i]; @@ -71,8 +86,18 @@ static kbd_row_t gpio_kbd_matrix_read_row(const struct device *dev) { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; + struct gpio_kbd_matrix_data *data = dev->data; int val = 0; + if (data->direct_read) { + const struct gpio_dt_spec *gpio0 = &cfg->row_gpio[0]; + gpio_port_value_t gpio_val; + + gpio_port_get(gpio0->port, &gpio_val); + + return (gpio_val >> gpio0->pin) & BIT_MASK(common->row_size); + } + for (int i = 0; i < common->row_size; i++) { const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; @@ -102,10 +127,27 @@ static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabl } } +static bool gpio_kbd_matrix_is_gpio_coherent( + const struct gpio_dt_spec *gpio, int gpio_count) +{ + const struct gpio_dt_spec *gpio0 = &gpio[0]; + + for (int i = 1; i < gpio_count; i++) { + if (gpio[i].port != gpio0->port || + gpio[i].dt_flags != gpio0->dt_flags || + gpio[i].pin != gpio0->pin + i) { + return false; + } + } + + return true; +} + static int gpio_kbd_matrix_init(const struct device *dev) { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; + struct gpio_kbd_matrix_data *data = dev->data; int ret; int i; @@ -152,6 +194,17 @@ static int gpio_kbd_matrix_init(const struct device *dev) } } + data->direct_read = gpio_kbd_matrix_is_gpio_coherent( + cfg->row_gpio, common->row_size); + + if (cfg->col_drive_inactive) { + data->direct_write = gpio_kbd_matrix_is_gpio_coherent( + cfg->col_gpio, common->col_size); + } + + LOG_DBG("direct_read: %d direct_write: %d", + data->direct_read, data->direct_write); + gpio_kbd_matrix_set_detect_mode(dev, true); return input_kbd_matrix_common_init(dev); From ea887af0aa112b1e707be84a299788a789b0c129 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 20 Nov 2023 16:18:37 +0000 Subject: [PATCH 0890/1049] input: gpio_kbd_matrix: drop redundant gpio_kbd_matrix_set_detect_mode This is called already as soon as the polling thread starts, so the call in the gpio init function is harmless but redundant, drop it. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_kbd_matrix.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index 3d8cc2a3104750c..2c0d22bbaaa8546 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -205,8 +205,6 @@ static int gpio_kbd_matrix_init(const struct device *dev) LOG_DBG("direct_read: %d direct_write: %d", data->direct_read, data->direct_write); - gpio_kbd_matrix_set_detect_mode(dev, true); - return input_kbd_matrix_common_init(dev); } From 1ab08634f2799556e924cc8c7f70a60cd292ed4e Mon Sep 17 00:00:00 2001 From: Kamil Piszczek Date: Tue, 7 Nov 2023 12:27:25 +0100 Subject: [PATCH 0891/1049] settings: nvs: improve the name ID metadata handling on delete operation Improved the updates to the name ID metadata (NVS_NAMECNT_ID) item in the Settings NVS backend implementation. The improvements should make the implementation more robust in handling edge cases such as: power downs, resets or a case in which the storage partition is full. In the last case, the NVS backend could return an ENOSPC error in the context of the settings_delete API. This change also fixes this issue. Signed-off-by: Kamil Piszczek --- subsys/settings/src/settings_nvs.c | 59 ++++++++++++++++++------------ 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/subsys/settings/src/settings_nvs.c b/subsys/settings/src/settings_nvs.c index 8e5bfbf3767628f..f1e53bfad228fcf 100644 --- a/subsys/settings/src/settings_nvs.c +++ b/subsys/settings/src/settings_nvs.c @@ -147,6 +147,17 @@ static int settings_nvs_load(struct settings_store *cs, &buf, sizeof(buf)); if ((rc1 <= 0) && (rc2 <= 0)) { + /* Settings largest ID in use is invalid due to + * reset, power failure or partition overflow. + * Decrement it and check the next ID in subsequent + * iteration. + */ + if (name_id == cf->last_name_id) { + cf->last_name_id--; + nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, + &cf->last_name_id, sizeof(uint16_t)); + } + continue; } @@ -156,13 +167,15 @@ static int settings_nvs_load(struct settings_store *cs, * or deleted. Clean dirty entries to make space for * future settings item. */ + nvs_delete(&cf->cf_nvs, name_id); + nvs_delete(&cf->cf_nvs, name_id + NVS_NAME_ID_OFFSET); + if (name_id == cf->last_name_id) { cf->last_name_id--; nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, &cf->last_name_id, sizeof(uint16_t)); } - nvs_delete(&cf->cf_nvs, name_id); - nvs_delete(&cf->cf_nvs, name_id + NVS_NAME_ID_OFFSET); + continue; } @@ -254,6 +267,16 @@ static int settings_nvs_save(struct settings_store *cs, const char *name, return 0; } + rc = nvs_delete(&cf->cf_nvs, name_id); + if (rc >= 0) { + rc = nvs_delete(&cf->cf_nvs, name_id + + NVS_NAME_ID_OFFSET); + } + + if (rc < 0) { + return rc; + } + if (name_id == cf->last_name_id) { cf->last_name_id--; rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, @@ -266,17 +289,6 @@ static int settings_nvs_save(struct settings_store *cs, const char *name, } } - rc = nvs_delete(&cf->cf_nvs, name_id); - - if (rc >= 0) { - rc = nvs_delete(&cf->cf_nvs, name_id + - NVS_NAME_ID_OFFSET); - } - - if (rc < 0) { - return rc; - } - return 0; } @@ -285,6 +297,16 @@ static int settings_nvs_save(struct settings_store *cs, const char *name, return -ENOMEM; } + /* update the last_name_id and write to flash if required*/ + if (write_name_id > cf->last_name_id) { + cf->last_name_id = write_name_id; + rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, &cf->last_name_id, + sizeof(uint16_t)); + if (rc < 0) { + return rc; + } + } + /* write the value */ rc = nvs_write(&cf->cf_nvs, write_name_id + NVS_NAME_ID_OFFSET, value, val_len); @@ -300,17 +322,6 @@ static int settings_nvs_save(struct settings_store *cs, const char *name, } } - /* update the last_name_id and write to flash if required*/ - if (write_name_id > cf->last_name_id) { - cf->last_name_id = write_name_id; - rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, &cf->last_name_id, - sizeof(uint16_t)); - } - - if (rc < 0) { - return rc; - } - return 0; } From 46bbe052d370dde2795107da28bf29890df6b013 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Fri, 27 Oct 2023 13:01:50 +0200 Subject: [PATCH 0892/1049] drivers: regulator: add LDO/DCDC support for Smartbond. This add regulator driver for Smartbond DA1469X SOC. Driver can control VDD, V14, V18, V18P, V30 rails, full voltage range supported by SOC is covered. For VDD, V14, V18, V18P DCDC can be configured. Special VDD_CLAMP (always on) and VDD_SLEPP are added to allow configuration of VDD in sleep modes. Signed-off-by: Jerzy Kasenberg --- drivers/regulator/CMakeLists.txt | 1 + drivers/regulator/Kconfig | 1 + drivers/regulator/Kconfig.da1469x | 16 + drivers/regulator/regulator_da1469x.c | 415 ++++++++++++++++++ dts/arm/renesas/smartbond/da1469x.dtsi | 46 ++ .../regulator/renesas,da1469x-regulator.yaml | 46 ++ 6 files changed, 525 insertions(+) create mode 100644 drivers/regulator/Kconfig.da1469x create mode 100644 drivers/regulator/regulator_da1469x.c create mode 100644 dts/bindings/regulator/renesas,da1469x-regulator.yaml diff --git a/drivers/regulator/CMakeLists.txt b/drivers/regulator/CMakeLists.txt index 94c3a032aff48eb..c7612fa2067abef 100644 --- a/drivers/regulator/CMakeLists.txt +++ b/drivers/regulator/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library() zephyr_library_sources(regulator_common.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_AXP192 regulator_axp192.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_ADP5360 regulator_adp5360.c) +zephyr_library_sources_ifdef(CONFIG_REGULATOR_DA1469X regulator_da1469x.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_FAKE regulator_fake.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_FIXED regulator_fixed.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_GPIO regulator_gpio.c) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c35ae389669ff14..754ba31783e7073 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -28,6 +28,7 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/regulator/Kconfig.axp192" source "drivers/regulator/Kconfig.adp5360" +source "drivers/regulator/Kconfig.da1469x" source "drivers/regulator/Kconfig.fake" source "drivers/regulator/Kconfig.fixed" source "drivers/regulator/Kconfig.gpio" diff --git a/drivers/regulator/Kconfig.da1469x b/drivers/regulator/Kconfig.da1469x new file mode 100644 index 000000000000000..d8205ed4925dff4 --- /dev/null +++ b/drivers/regulator/Kconfig.da1469x @@ -0,0 +1,16 @@ +# Copyright 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config REGULATOR_DA1469X + bool "DA1469X regulators driver" + default y + depends on DT_HAS_RENESAS_SMARTBOND_REGULATOR_ENABLED + help + Enable support for the Smartbond DA1469x regulators. + +config REGULATOR_DA1469X_INIT_PRIORITY + int "Renesas DA1469x regulators driver init priority" + default KERNEL_INIT_PRIORITY_DEVICE + depends on REGULATOR_DA1469X + help + Init priority for the Renesas DA1469x regulators driver. diff --git a/drivers/regulator/regulator_da1469x.c b/drivers/regulator/regulator_da1469x.c new file mode 100644 index 000000000000000..36d8fe1d35ff7da --- /dev/null +++ b/drivers/regulator/regulator_da1469x.c @@ -0,0 +1,415 @@ +/* + * Copyright 2023 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_smartbond_regulator + +#include + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(regulator_da1469x, CONFIG_REGULATOR_LOG_LEVEL); + +#define DCDC_REQUESTED (DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_HV_Msk |\ + DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_LV_Msk) + +#define DA1469X_LDO_3V0_MODE_VBAT BIT(8) +#define DA1469X_LDO_3V0_MODE_VBUS BIT(9) + +static const struct linear_range curren_ranges[] = { + LINEAR_RANGE_INIT(30000, 30000, 0, 31), +}; + +static const struct linear_range vdd_clamp_ranges[] = { + LINEAR_RANGE_INIT(706000, 0, 15, 15), + LINEAR_RANGE_INIT(798000, 0, 14, 14), + LINEAR_RANGE_INIT(828000, 0, 13, 13), + LINEAR_RANGE_INIT(861000, 0, 11, 11), + LINEAR_RANGE_INIT(862000, 0, 12, 12), + LINEAR_RANGE_INIT(889000, 0, 10, 10), + LINEAR_RANGE_INIT(918000, 0, 9, 9), + LINEAR_RANGE_INIT(946000, 0, 3, 3), + LINEAR_RANGE_INIT(952000, 0, 8, 8), + LINEAR_RANGE_INIT(978000, 0, 2, 2), + LINEAR_RANGE_INIT(1005000, 0, 1, 1), + LINEAR_RANGE_INIT(1030000, 0, 7, 7), + LINEAR_RANGE_INIT(1037000, 0, 0, 0), + LINEAR_RANGE_INIT(1058000, 0, 6, 6), + LINEAR_RANGE_INIT(1089000, 0, 5, 5), + LINEAR_RANGE_INIT(1120000, 0, 4, 4), +}; + +static const struct linear_range vdd_ranges[] = { + LINEAR_RANGE_INIT(900000, 100000, 0, 3), +}; + +static const struct linear_range vdd_sleep_ranges[] = { + LINEAR_RANGE_INIT(750000, 50000, 0, 3), +}; + +static const struct linear_range v14_ranges[] = { + LINEAR_RANGE_INIT(1200000, 50000, 0, 7), +}; + +static const struct linear_range v30_ranges[] = { + LINEAR_RANGE_INIT(3000000, 300000, 0, 1), +}; + +static const struct linear_range v18_ranges[] = { + LINEAR_RANGE_INIT(1200000, 600000, 0, 1), +}; + +static const struct linear_range v18p_ranges[] = { + LINEAR_RANGE_INIT(1800000, 0, 0, 0), +}; + +enum da1469x_rail { + VDD_CLAMP, + VDD_SLEEP, + VDD, + V14, + V18, + V18P, + V30, +}; + +struct regulator_da1469x_desc { + const struct linear_range *voltage_ranges; + const struct linear_range *current_ranges; + uint8_t voltage_range_count; + /* Bit from POWER_CTRL_REG that can be used for enabling rail */ + uint32_t enable_mask; + uint32_t voltage_idx_mask; + volatile uint32_t *dcdc_register; +}; + +static const struct regulator_da1469x_desc vdd_desc = { + .voltage_ranges = vdd_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(vdd_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_CORE_ENABLE_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_LEVEL_Msk, + .dcdc_register = &DCDC->DCDC_VDD_REG, +}; + +static const struct regulator_da1469x_desc vdd_sleep_desc = { + .voltage_ranges = vdd_sleep_ranges, + .voltage_range_count = ARRAY_SIZE(vdd_sleep_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_CORE_RET_ENABLE_SLEEP_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_SLEEP_LEVEL_Msk, +}; + +static const struct regulator_da1469x_desc vdd_clamp_desc = { + .voltage_ranges = vdd_clamp_ranges, + .voltage_range_count = ARRAY_SIZE(vdd_clamp_ranges), + .enable_mask = 0, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_CLAMP_LEVEL_Msk, +}; + +static const struct regulator_da1469x_desc v14_desc = { + .voltage_ranges = v14_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(v14_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V14_LEVEL_Msk, + .dcdc_register = &DCDC->DCDC_V14_REG, +}; + +static const struct regulator_da1469x_desc v18_desc = { + .voltage_ranges = v18_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(v18_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_1V8_ENABLE_Msk | + CRG_TOP_POWER_CTRL_REG_LDO_1V8_RET_ENABLE_SLEEP_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V18_LEVEL_Msk, + .dcdc_register = &DCDC->DCDC_V18_REG, +}; + +static const struct regulator_da1469x_desc v18p_desc = { + .voltage_ranges = v18p_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(v18p_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_1V8P_ENABLE_Msk | + CRG_TOP_POWER_CTRL_REG_LDO_1V8P_RET_ENABLE_SLEEP_Msk, + .voltage_idx_mask = 0, + .dcdc_register = &DCDC->DCDC_V18P_REG, +}; + +static const struct regulator_da1469x_desc v30_desc = { + .voltage_ranges = v30_ranges, + .voltage_range_count = ARRAY_SIZE(v30_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_3V0_RET_ENABLE_SLEEP_Msk | + CRG_TOP_POWER_CTRL_REG_LDO_3V0_MODE_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V30_LEVEL_Msk, +}; + +#define DA1469X_LDO_VDD_CLAMP_RET 0 +#define DA1469X_LDO_VDD_SLEEP_RET 0 +#define DA1469X_LDO_VDD_RET CRG_TOP_POWER_CTRL_REG_LDO_CORE_RET_ENABLE_SLEEP_Msk +#define DA1469X_LDO_V14_RET 0 +#define DA1469X_LDO_V18_RET CRG_TOP_POWER_CTRL_REG_LDO_1V8_RET_ENABLE_SLEEP_Msk +#define DA1469X_LDO_V18P_RET CRG_TOP_POWER_CTRL_REG_LDO_1V8P_RET_ENABLE_SLEEP_Msk +#define DA1469X_LDO_V30_RET CRG_TOP_POWER_CTRL_REG_LDO_3V0_RET_ENABLE_SLEEP_Msk + +struct regulator_da1469x_config { + struct regulator_common_config common; + enum da1469x_rail rail; + const struct regulator_da1469x_desc *desc; + uint32_t power_bits; + uint32_t dcdc_bits; +}; + +struct regulator_da1469x_data { + struct regulator_common_data common; +}; + +static int regulator_da1469x_enable(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + uint32_t reg_val; + + if (config->desc->enable_mask & config->power_bits) { + reg_val = CRG_TOP->POWER_CTRL_REG & ~(config->desc->enable_mask); + reg_val |= config->power_bits & config->desc->enable_mask; + CRG_TOP->POWER_CTRL_REG |= reg_val; + } + + if (config->desc->dcdc_register) { + reg_val = *config->desc->dcdc_register & + ~(DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_HV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_LV_Msk); + reg_val |= config->dcdc_bits; + *config->desc->dcdc_register = reg_val; + } + + /* + * Enable DCDC if: + * 1. it was not already enabled, and + * 2. VBAT is above minimal value + * 3. Just turned on rail requested DCDC + */ + if (((DCDC->DCDC_CTRL1_REG & DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk) == 0) && + (CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_COMP_VBAT_HIGH_Msk) && + config->dcdc_bits & DCDC_REQUESTED) { + DCDC->DCDC_CTRL1_REG |= DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk; + } + + return 0; +} + +static int regulator_da1469x_disable(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + uint32_t reg_val; + + if (config->desc->enable_mask & config->power_bits) { + CRG_TOP->POWER_CTRL_REG &= ~(config->desc->enable_mask & + config->power_bits); + } + if (config->desc->dcdc_register) { + reg_val = *config->desc->dcdc_register & + ~(DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_HV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_LV_Msk); + *config->desc->dcdc_register = reg_val; + } + + /* Turn off DCDC if it's no longer requested by any rail */ + if ((DCDC->DCDC_CTRL1_REG & DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk) && + (DCDC->DCDC_VDD_REG & DCDC_REQUESTED) == 0 && + (DCDC->DCDC_V14_REG & DCDC_REQUESTED) == 0 && + (DCDC->DCDC_V18_REG & DCDC_REQUESTED) == 0 && + (DCDC->DCDC_V18P_REG & DCDC_REQUESTED) == 0) { + DCDC->DCDC_CTRL1_REG &= ~DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk; + } + + return 0; +} + +static unsigned int regulator_da1469x_count_voltages(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + + return linear_range_group_values_count(config->desc->voltage_ranges, + config->desc->voltage_range_count); +} + +static int regulator_da1469x_list_voltage(const struct device *dev, + unsigned int idx, + int32_t *volt_uv) +{ + const struct regulator_da1469x_config *config = dev->config; + + if (config->desc->voltage_ranges) { + return linear_range_group_get_value(config->desc->voltage_ranges, + config->desc->voltage_range_count, + idx, volt_uv); + } + + return -ENOTSUP; +} + +static int regulator_da1469x_set_voltage(const struct device *dev, int32_t min_uv, + int32_t max_uv) +{ + int ret; + const struct regulator_da1469x_config *config = dev->config; + uint16_t idx; + uint32_t mask; + + ret = linear_range_group_get_win_index(config->desc->voltage_ranges, + config->desc->voltage_range_count, + min_uv, max_uv, &idx); + + if (ret == 0) { + mask = config->desc->voltage_idx_mask; + /* + * Mask is 0 for V18. + * Setting value 1.8V is accepted since range is valid and already checked. + */ + if (mask) { + CRG_TOP->POWER_CTRL_REG = (CRG_TOP->POWER_CTRL_REG & ~mask) | + FIELD_PREP(mask, idx); + } + } + + return ret; +} + +static int regulator_da1469x_get_voltage(const struct device *dev, + int32_t *volt_uv) +{ + const struct regulator_da1469x_config *config = dev->config; + uint16_t idx; + + if (config->desc->voltage_idx_mask) { + idx = FIELD_GET(CRG_TOP->POWER_CTRL_REG, config->desc->voltage_idx_mask); + } else { + idx = 0; + } + + return linear_range_group_get_value(config->desc->voltage_ranges, + config->desc->voltage_range_count, idx, volt_uv); +} + +static int regulator_da1469x_set_current_limit(const struct device *dev, + int32_t min_ua, int32_t max_ua) +{ + const struct regulator_da1469x_config *config = dev->config; + int ret; + uint16_t idx; + uint32_t reg_val; + + if (config->desc->current_ranges == NULL) { + return -ENOTSUP; + } + + ret = linear_range_group_get_win_index(config->desc->current_ranges, + 1, + min_ua, max_ua, &idx); + if (ret) { + return ret; + } + + /* All registers have same bits layout */ + reg_val = *config->desc->dcdc_register & ~(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_LV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MIN_Msk); + reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk, idx); + reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_LV_Msk, idx); + reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MIN_Msk, idx); + + *config->desc->dcdc_register = reg_val; + + return ret; +} + +static int regulator_da1469x_get_current_limit(const struct device *dev, + int32_t *curr_ua) +{ + const struct regulator_da1469x_config *config = dev->config; + int ret; + uint16_t idx; + + if (config->desc->current_ranges == NULL) { + return -ENOTSUP; + } + idx = FIELD_GET(*config->desc->dcdc_register, + DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk); + ret = linear_range_group_get_value(config->desc->current_ranges, 1, idx, curr_ua); + + return ret; +} + +static const struct regulator_driver_api regulator_da1469x_api = { + .enable = regulator_da1469x_enable, + .disable = regulator_da1469x_disable, + .count_voltages = regulator_da1469x_count_voltages, + .list_voltage = regulator_da1469x_list_voltage, + .set_voltage = regulator_da1469x_set_voltage, + .get_voltage = regulator_da1469x_get_voltage, + .set_current_limit = regulator_da1469x_set_current_limit, + .get_current_limit = regulator_da1469x_get_current_limit, +}; + +static int regulator_da1469x_init(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + + regulator_common_data_init(dev); + + if ((config->rail == V30) && + (config->power_bits & CRG_TOP_POWER_CTRL_REG_LDO_3V0_REF_Msk)) { + CRG_TOP->POWER_CTRL_REG |= CRG_TOP_POWER_CTRL_REG_LDO_3V0_REF_Msk; + } + + return regulator_common_init(dev, 0); +} + +#define REGULATOR_DA1469X_DEFINE(node, id, rail_id) \ + static struct regulator_da1469x_data data_##id; \ + \ + static const struct regulator_da1469x_config config_##id = { \ + .common = REGULATOR_DT_COMMON_CONFIG_INIT(node), \ + .desc = &id ## _desc, \ + .power_bits = \ + (DT_PROP(node, renesas_regulator_v30_clamp) * \ + CRG_TOP_POWER_CTRL_REG_CLAMP_3V0_VBAT_ENABLE_Msk) | \ + (DT_PROP(node, renesas_regulator_v30_vbus) * \ + DA1469X_LDO_3V0_MODE_VBAT) | \ + (DT_PROP(node, renesas_regulator_v30_vbat) * \ + DA1469X_LDO_3V0_MODE_VBUS) | \ + (DT_PROP(node, renesas_regulator_sleep_ldo) * \ + (DA1469X_LDO_ ## rail_id ##_RET)) | \ + (DT_PROP(node, renesas_regulator_v30_ref_bandgap) * \ + CRG_TOP_POWER_CTRL_REG_LDO_3V0_REF_Msk), \ + .dcdc_bits = \ + (DT_PROP(node, renesas_regulator_dcdc_vbat_high) * \ + DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_HV_Msk) | \ + (DT_PROP(node, renesas_regulator_dcdc_vbat_low) * \ + DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_LV_Msk) \ + }; \ + DEVICE_DT_DEFINE(node, regulator_da1469x_init, NULL, &data_##id, \ + &config_##id, PRE_KERNEL_1, \ + CONFIG_REGULATOR_DA1469X_INIT_PRIORITY, \ + ®ulator_da1469x_api); + +#define REGULATOR_DA1469X_DEFINE_COND(inst, child, source) \ + COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \ + (REGULATOR_DA1469X_DEFINE( \ + DT_INST_CHILD(inst, child), child, source)), \ + ()) + +#define REGULATOR_DA1469X_DEFINE_ALL(inst) \ + REGULATOR_DA1469X_DEFINE_COND(inst, vdd_clamp, VDD_CLAMP) \ + REGULATOR_DA1469X_DEFINE_COND(inst, vdd_sleep, VDD_SLEEP) \ + REGULATOR_DA1469X_DEFINE_COND(inst, vdd, VDD) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v14, V14) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v18, V18) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v18p, V18P) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v30, V30) \ + +DT_INST_FOREACH_STATUS_OKAY(REGULATOR_DA1469X_DEFINE_ALL) diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index 6916b2b804cd58a..72f7e6fa89ffd1a 100644 --- a/dts/arm/renesas/smartbond/da1469x.dtsi +++ b/dts/arm/renesas/smartbond/da1469x.dtsi @@ -86,6 +86,52 @@ clock-src = <&rc32k>; status = "okay"; }; + + regulators { + compatible = "renesas,smartbond-regulator"; + vdd: VDD { + regulator-init-microvolt = <900000>; + regulator-boot-on; + renesas,regulator-sleep-ldo; + renesas,regulator-dcdc-vbat-high; + renesas,regulator-dcdc-vbat-low; + }; + vdd_clamp: VDD_CLAMP { + regulator-boot-on; + regulator-always-on; + regulator-init-microvolt = <706000>; + }; + vdd_sleep: VDD_SLEEP { + regulator-boot-on; + regulator-init-microvolt = <750000>; + }; + v14: V14 { + regulator-init-microvolt = <1400000>; + regulator-boot-on; + renesas,regulator-dcdc-vbat-high; + renesas,regulator-dcdc-vbat-low; + }; + v18: V18 { + regulator-init-microvolt = <1800000>; + regulator-boot-on; + renesas,regulator-dcdc-vbat-high; + }; + v18p: V18P { + regulator-init-microvolt = <1800000>; + regulator-boot-on; + renesas,regulator-sleep-ldo; + renesas,regulator-dcdc-vbat-high; + }; + v30: V30 { + regulator-init-microvolt = <3000000>; + regulator-boot-on; + renesas,regulator-sleep-ldo; + renesas,regulator-v30-vbus; + renesas,regulator-v30-vbat; + renesas,regulator-v30-clamp; + renesas,regulator-v30-ref-bandgap; + }; + }; }; soc { diff --git a/dts/bindings/regulator/renesas,da1469x-regulator.yaml b/dts/bindings/regulator/renesas,da1469x-regulator.yaml new file mode 100644 index 000000000000000..2537b7e09d7da8e --- /dev/null +++ b/dts/bindings/regulator/renesas,da1469x-regulator.yaml @@ -0,0 +1,46 @@ +# Copyright (c), 2023 Renesas Electronics Corporation +# SPDX -License-Identifier: Apache-2.0 + +description: | + Renesas Smartbond(tm) LDO and DCDC regulators + +compatible: "renesas,smartbond-regulator" + +child-binding: + include: + - name: regulator.yaml + property-allowlist: + - regulator-always-on + - regulator-boot-on + - regulator-init-microvolt + - regulator-initial-mode + - regulator-max-microamp + properties: + renesas,regulator-v30-ref-bandgap: + type: boolean + description: | + Selects reference source for V30 LDO to Bandgap output. + renesas,regulator-v30-clamp: + type: boolean + description: | + Enables clamp that can supply V30 from VBAT. + renesas,regulator-v30-vbus: + type: boolean + description: | + Allow V30 to be powered from VBUS. + renesas,regulator-v30-vbat: + type: boolean + description: | + Allow V30 to be powered from VBAT. + renesas,regulator-dcdc-vbat-high: + type: boolean + description: | + Enable DCDC in high battery voltage mode. + renesas,regulator-dcdc-vbat-low: + type: boolean + description: | + Enable DCDC in low battery voltage mode. + renesas,regulator-sleep-ldo: + type: boolean + description: | + Enable LDO in sleep mode. From 4e976e0d58588366b138a5b33f42e02027ce8696 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 16 Nov 2023 10:03:06 +0100 Subject: [PATCH 0893/1049] sys: atomic: Fix includes, create `atomic_types.h` This patch fixes the include of `atomic_builtin.h` and `atomic_arch.h` so that they are IWYU. This mean they compile correctly independent of other includes at the include-site. It was nessessary to move the definition of the atomic types out of `atomic.h` to avoid unsatifiable circular dependencies between `atomic.h` and `atomic_builtin.h`, as well as definition conflicts between `atomic_arch.h` and `atomic_builtin.h`. The definition of the type was to moved to a new file `atomic_types.h`. The include in `atomic.h` has a IWYU pragma which will preserve backwards compatibility with code expecting the types to be defined in `atomic.h` if we start linting for IWYU. Signed-off-by: Aleksander Wasaznik --- include/zephyr/sys/atomic.h | 7 ++----- include/zephyr/sys/atomic_arch.h | 4 ++++ include/zephyr/sys/atomic_builtin.h | 4 ++++ include/zephyr/sys/atomic_types.h | 24 ++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 include/zephyr/sys/atomic_types.h diff --git a/include/zephyr/sys/atomic.h b/include/zephyr/sys/atomic.h index bcb122bf38aca7d..8618e1bf9038a66 100644 --- a/include/zephyr/sys/atomic.h +++ b/include/zephyr/sys/atomic.h @@ -1,6 +1,7 @@ /* * Copyright (c) 1997-2015, Wind River Systems, Inc. * Copyright (c) 2021 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +13,7 @@ #include #include +#include /* IWYU pragma: export */ #include #include @@ -19,11 +21,6 @@ extern "C" { #endif -typedef long atomic_t; -typedef atomic_t atomic_val_t; -typedef void *atomic_ptr_t; -typedef atomic_ptr_t atomic_ptr_val_t; - /* Low-level primitives come in several styles: */ #if defined(CONFIG_ATOMIC_OPERATIONS_C) diff --git a/include/zephyr/sys/atomic_arch.h b/include/zephyr/sys/atomic_arch.h index 7305743c4fbf143..1225a2e097077e3 100644 --- a/include/zephyr/sys/atomic_arch.h +++ b/include/zephyr/sys/atomic_arch.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2021 Demant A/S + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +8,9 @@ #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_ARCH_H_ #define ZEPHYR_INCLUDE_SYS_ATOMIC_ARCH_H_ +#include +#include + /* Included from */ /* Arch specific atomic primitives */ diff --git a/include/zephyr/sys/atomic_builtin.h b/include/zephyr/sys/atomic_builtin.h index 43b40e8bed48df6..972200c4fc6fe3e 100644 --- a/include/zephyr/sys/atomic_builtin.h +++ b/include/zephyr/sys/atomic_builtin.h @@ -2,6 +2,7 @@ /* * Copyright (c) 1997-2015, Wind River Systems, Inc. + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +10,9 @@ #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_BUILTIN_H_ #define ZEPHYR_INCLUDE_SYS_ATOMIC_BUILTIN_H_ +#include +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/include/zephyr/sys/atomic_types.h b/include/zephyr/sys/atomic_types.h new file mode 100644 index 000000000000000..33935971f50bdc1 --- /dev/null +++ b/include/zephyr/sys/atomic_types.h @@ -0,0 +1,24 @@ +/* Copyright (c) 1997-2015, Wind River Systems, Inc. + * Copyright (c) 2021 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_TYPES_H_ +#define ZEPHYR_INCLUDE_SYS_ATOMIC_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long atomic_t; +typedef atomic_t atomic_val_t; +typedef void *atomic_ptr_t; +typedef atomic_ptr_t atomic_ptr_val_t; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_TYPES_H_ */ From 589f3ad904b04fd9f4b453d6045bbcdcb3e67826 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Wed, 23 Mar 2022 16:54:36 +0100 Subject: [PATCH 0894/1049] Bluetooth: testlib: Create `testlib/conn.h` This header file declares the functions that rely on `bluetooth/conn.h`. This collects `testlib/connect.h`, `conn_ref.h` and `conn_wait.h` into one. Initial documentation for the functions in this file is also added. Signed-off-by: Aleksander Wasaznik --- tests/bluetooth/common/testlib/CMakeLists.txt | 3 +- .../common/testlib/include/testlib/conn.h | 75 +++++++++++++++++++ .../testlib/include/testlib/conn_wait.h | 12 --- .../common/testlib/include/testlib/connect.h | 12 --- .../testlib/conn_ref.h => src/conn_ref.c} | 8 +- .../bluetooth/common/testlib/src/conn_wait.c | 2 + tests/bluetooth/common/testlib/src/connect.c | 2 +- .../bsim/bluetooth/host/att/long_read/main.c | 4 +- .../host/att/retry_on_sec_err/client/main.c | 2 +- 9 files changed, 84 insertions(+), 36 deletions(-) create mode 100644 tests/bluetooth/common/testlib/include/testlib/conn.h delete mode 100644 tests/bluetooth/common/testlib/include/testlib/conn_wait.h delete mode 100644 tests/bluetooth/common/testlib/include/testlib/connect.h rename tests/bluetooth/common/testlib/{include/testlib/conn_ref.h => src/conn_ref.c} (80%) diff --git a/tests/bluetooth/common/testlib/CMakeLists.txt b/tests/bluetooth/common/testlib/CMakeLists.txt index 7166abd3e069e2a..91d685439c82bcd 100644 --- a/tests/bluetooth/common/testlib/CMakeLists.txt +++ b/tests/bluetooth/common/testlib/CMakeLists.txt @@ -17,8 +17,9 @@ target_sources(testlib PRIVATE src/adv.c src/att_read.c src/att_write.c - src/connect.c + src/conn_ref.c src/conn_wait.c + src/connect.c src/scan.c src/security.c ) diff --git a/tests/bluetooth/common/testlib/include/testlib/conn.h b/tests/bluetooth/common/testlib/include/testlib/conn.h new file mode 100644 index 000000000000000..9554eb7b033a0ef --- /dev/null +++ b/tests/bluetooth/common/testlib/include/testlib/conn.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_H_ +#define ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_H_ + +#include + +/** + * @brief Scan and connect using address + * + * Synchronous: Blocks until the connection procedure completes. + * Thread-safe: + * + * This is a synchronous wrapper around @ref bt_conn_le_create with + * default params. It will wait until the @ref bt_conn_cb.connected + * event and return the HCI status of the connection creation. + * + * The reference created by @ref bt_conn_le_create is put in @p connp. + * + * @note The connection reference presists if the connection procedure + * fails at a later point. @p connp is a reified reference: if it's not + * NULL, then it's a valid reference. + * + * @remark Not disposing of the connection reference in the case of + * connection failure is intentional. It's useful for comparing against + * raw @ref bt_conn_cb.connected events. + * + * @note The reference variable @p connp is required be empty (i.e. + * NULL) on entry. + * + * @param peer Peer address. + * @param[out] conn Connection reference variable. + * + * @retval 0 Connection was enstablished. + * @retval -errno @ref bt_conn_le_create error. No connection object + * reference was created. + * @retval BT_HCI_ERR HCI reason for connection failure. A connection + * object reference was created and put in @p connp. + * + */ +int bt_testlib_connect(const bt_addr_le_t *peer, struct bt_conn **connp); + +/** + * @brief Wait for connected state + * + * Thread-safe. + * + * @attention This function does not look at the history of a connection + * object. If it's already disconnected after a connection, then this + * function will wait forever. Don't use this function if you cannot + * guarantee that any disconnection event comes after this function is + * called. This is only truly safe in a simulated environment. + */ +int bt_testlib_wait_connected(struct bt_conn *conn); + +/** + * @brief Wait for disconnected state + * + * Thread-safe. + */ +int bt_testlib_wait_disconnected(struct bt_conn *conn); + +/** + * @brief Dispose of a reified connection reference + * + * Thread-safe. + * + * Atomically swaps NULL into the reference variable @p connp, then + * moves the reference into @ref bt_conn_unref. + */ +void bt_testlib_conn_unref(struct bt_conn **connp); + +#endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_H_ */ diff --git a/tests/bluetooth/common/testlib/include/testlib/conn_wait.h b/tests/bluetooth/common/testlib/include/testlib/conn_wait.h deleted file mode 100644 index 00f8ddb5cdc0faf..000000000000000 --- a/tests/bluetooth/common/testlib/include/testlib/conn_wait.h +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright (c) 2023 Nordic Semiconductor ASA - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_WAIT_H_ -#define ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_WAIT_H_ -#include - -int bt_testlib_wait_connected(struct bt_conn *conn); -int bt_testlib_wait_disconnected(struct bt_conn *conn); - -#endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_WAIT_H_ */ diff --git a/tests/bluetooth/common/testlib/include/testlib/connect.h b/tests/bluetooth/common/testlib/include/testlib/connect.h deleted file mode 100644 index 912e4d0cdc73494..000000000000000 --- a/tests/bluetooth/common/testlib/include/testlib/connect.h +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright (c) 2023 Nordic Semiconductor ASA - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONNECT_H_ -#define ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONNECT_H_ - -#include - -int bt_testlib_connect(const bt_addr_le_t *peer, struct bt_conn **conn); - -#endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONNECT_H_ */ diff --git a/tests/bluetooth/common/testlib/include/testlib/conn_ref.h b/tests/bluetooth/common/testlib/src/conn_ref.c similarity index 80% rename from tests/bluetooth/common/testlib/include/testlib/conn_ref.h rename to tests/bluetooth/common/testlib/src/conn_ref.c index 9e96eb3fc405380..8e26c7104dcfc64 100644 --- a/tests/bluetooth/common/testlib/include/testlib/conn_ref.h +++ b/tests/bluetooth/common/testlib/src/conn_ref.c @@ -2,11 +2,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_REF_H_ -#define ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_REF_H_ - +#include +#include #include -#include /** * @file @@ -38,5 +36,3 @@ void bt_testlib_conn_unref(struct bt_conn **connp) __ASSERT_NO_MSG(conn); bt_conn_unref(conn); } - -#endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_REF_H_ */ diff --git a/tests/bluetooth/common/testlib/src/conn_wait.c b/tests/bluetooth/common/testlib/src/conn_wait.c index a99b47a0edcc0b6..fdcaa4680d4f8dc 100644 --- a/tests/bluetooth/common/testlib/src/conn_wait.c +++ b/tests/bluetooth/common/testlib/src/conn_wait.c @@ -13,6 +13,8 @@ #include #include +#include + #include LOG_MODULE_REGISTER(bt_testlib_conn_wait, LOG_LEVEL_DBG); diff --git a/tests/bluetooth/common/testlib/src/connect.c b/tests/bluetooth/common/testlib/src/connect.c index afb4b9c271deec7..e8f5a90224ee053 100644 --- a/tests/bluetooth/common/testlib/src/connect.c +++ b/tests/bluetooth/common/testlib/src/connect.c @@ -7,7 +7,7 @@ #include #include -#include +#include LOG_MODULE_REGISTER(bt_testlib_connect, LOG_LEVEL_INF); diff --git a/tests/bsim/bluetooth/host/att/long_read/main.c b/tests/bsim/bluetooth/host/att/long_read/main.c index 29a3de0a9e6ff15..2f13b346a808e72 100644 --- a/tests/bsim/bluetooth/host/att/long_read/main.c +++ b/tests/bsim/bluetooth/host/att/long_read/main.c @@ -15,9 +15,7 @@ #include "testlib/att_write.h" #include "bs_macro.h" #include "bs_sync.h" -#include "testlib/conn_ref.h" -#include "testlib/conn_wait.h" -#include "testlib/connect.h" +#include #include "testlib/log_utils.h" #include "testlib/scan.h" #include "testlib/security.h" diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c index 2a3c005515c7b83..fc86d8aa5e35971 100644 --- a/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/client/main.c @@ -13,7 +13,7 @@ #include "../common_defs.h" #include "../test_utils.h" -#include "testlib/connect.h" +#include #include "testlib/scan.h" #include "testlib/security.h" From 608cc4d1f21d7ae413f3293d7b7f46e0ee602aaa Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Sat, 18 Nov 2023 07:40:58 +0530 Subject: [PATCH 0895/1049] drivers: ns16550: remove parent init level dependency remove parent init level dependency such as PRE_KERNEL or POST_KERNEL. Uart driver init level change always to PRE_KERNEL Signed-off-by: Najumon B.A --- drivers/serial/Kconfig.ns16550 | 10 ---------- drivers/serial/uart_ns16550.c | 3 +-- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index 1c97a08637ed6e7..594216092e7e3d2 100644 --- a/drivers/serial/Kconfig.ns16550 +++ b/drivers/serial/Kconfig.ns16550 @@ -60,16 +60,6 @@ config UART_NS16550_ACCESS_WORD_ONLY 16550 (DesignWare UART) only allows word access, byte access will raise exception. -config UART_NS16550_PARENT_INIT_LEVEL - bool "Boot level based on parent node" - default y if ACPI - help - Boot level based on parent node (PCI or no PCI device). Some platforms the - PCI bus driver depends on ACPI sub system to retrieve platform information - such as interrupt routing information. But ACPI sub system currently support - only post kernel and hence such platforms the UART driver instance init - should be invoked only post kernel in case parent node is PCI. - config UART_NS16550_TI_K3 bool "Add support for NS16550 variant specific to TI K3 SoCs" help diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index a41cdca784341f0..3f64d83cf36af1d 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -1423,8 +1423,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = { }; \ DEVICE_DT_INST_DEFINE(n, &uart_ns16550_init, NULL, \ &uart_ns16550_dev_data_##n, &uart_ns16550_dev_cfg_##n, \ - COND_CODE_1(CONFIG_UART_NS16550_PARENT_INIT_LEVEL, \ - (POST_KERNEL), (PRE_KERNEL_1)), \ + PRE_KERNEL_1, \ CONFIG_SERIAL_INIT_PRIORITY, \ &uart_ns16550_driver_api); \ UART_NS16550_PCIE_IRQ_FUNC_DEFINE(n) From c0d61d0bbd8c0174b23920833a0a0963c0ef1b6e Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Sat, 18 Nov 2023 07:43:47 +0530 Subject: [PATCH 0896/1049] board: x86: remove parent init level dependency config remove parent init level config from Intel Alder Lake platform Signed-off-by: Najumon B.A --- boards/x86/intel_adl/intel_adl_crb_defconfig | 1 - boards/x86/intel_adl/intel_adl_rvp_defconfig | 1 - boards/x86/intel_adl/up_squared_pro_7000_defconfig | 1 - 3 files changed, 3 deletions(-) diff --git a/boards/x86/intel_adl/intel_adl_crb_defconfig b/boards/x86/intel_adl/intel_adl_crb_defconfig index c2c1a37850d44e0..5287bfcacc08a33 100644 --- a/boards/x86/intel_adl/intel_adl_crb_defconfig +++ b/boards/x86/intel_adl/intel_adl_crb_defconfig @@ -12,4 +12,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y diff --git a/boards/x86/intel_adl/intel_adl_rvp_defconfig b/boards/x86/intel_adl/intel_adl_rvp_defconfig index 41260a3b233625d..0f6ed718268ef37 100644 --- a/boards/x86/intel_adl/intel_adl_rvp_defconfig +++ b/boards/x86/intel_adl/intel_adl_rvp_defconfig @@ -12,4 +12,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y diff --git a/boards/x86/intel_adl/up_squared_pro_7000_defconfig b/boards/x86/intel_adl/up_squared_pro_7000_defconfig index 211ce9f24e1d987..4c228677a70c535 100644 --- a/boards/x86/intel_adl/up_squared_pro_7000_defconfig +++ b/boards/x86/intel_adl/up_squared_pro_7000_defconfig @@ -12,4 +12,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y From 5edb7cbe41f82ea0b5641f75d6206829801fd77e Mon Sep 17 00:00:00 2001 From: Peter van der Perk Date: Sat, 18 Nov 2023 19:08:21 +0100 Subject: [PATCH 0897/1049] soc: arm: nxp_imx: rt11xx: add support for CONFIG_ETH_MCUX_RMII_EXT_CLK ENET_REF_CLK as an input during rt11xx clock initialization. Signed-off-by: Peter van der Perk --- boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi | 3 ++- soc/arm/nxp_imx/rt/soc_rt11xx.c | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi b/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi index 3f27e5c3a337589..d556fff21aed57c 100644 --- a/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi +++ b/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi @@ -38,8 +38,9 @@ group3 { pinmux = <&iomuxc_gpio_disp_b1_11_enet_1g_ref_clk1>; drive-strength = "high"; - slew-rate = "slow"; + slew-rate = "fast"; input-enable; + bias-pull-down; }; }; diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c index f9eb7b7e381ac9a..190be4746ed6832 100644 --- a/soc/arm/nxp_imx/rt/soc_rt11xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c @@ -402,10 +402,16 @@ static ALWAYS_INLINE void clock_init(void) rootCfg.mux = kCLOCK_ENET1_ClockRoot_MuxSysPll1Div2; rootCfg.div = 10; CLOCK_SetRootClock(kCLOCK_Root_Enet1, &rootCfg); +#if CONFIG_ETH_MCUX_RMII_EXT_CLK + /* Set ENET_REF_CLK as an input driven by PHY */ + IOMUXC_GPR->GPR4 &= ~IOMUXC_GPR_GPR4_ENET_REF_CLK_DIR(0x01U); + IOMUXC_GPR->GPR4 |= IOMUXC_GPR_GPR4_ENET_TX_CLK_SEL(0x1U); +#else /* Set ENET_REF_CLK as an output driven by ENET1_CLK_ROOT */ IOMUXC_GPR->GPR4 |= (IOMUXC_GPR_GPR4_ENET_REF_CLK_DIR(0x01U) | IOMUXC_GPR_GPR4_ENET_TX_CLK_SEL(0x1U)); #endif +#endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet1g), okay) /* * 50 MHz clock for 10/100Mbit RMII PHY - @@ -414,11 +420,17 @@ static ALWAYS_INLINE void clock_init(void) rootCfg.mux = kCLOCK_ENET2_ClockRoot_MuxSysPll1Div2; rootCfg.div = 10; CLOCK_SetRootClock(kCLOCK_Root_Enet2, &rootCfg); +#if CONFIG_ETH_MCUX_RMII_EXT_CLK + /* Set ENET1G_REF_CLK as an input driven by PHY */ + IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_ENET1G_REF_CLK_DIR(0x01U); + IOMUXC_GPR->GPR5 |= IOMUXC_GPR_GPR5_ENET1G_TX_CLK_SEL(0x1U); +#else /* Set ENET1G_REF_CLK as an output driven by ENET2_CLK_ROOT */ IOMUXC_GPR->GPR5 |= (IOMUXC_GPR_GPR5_ENET1G_REF_CLK_DIR(0x01U) | IOMUXC_GPR_GPR5_ENET1G_TX_CLK_SEL(0x1U)); #endif #endif +#endif #ifdef CONFIG_PTP_CLOCK_MCUX /* 24MHz PTP clock */ From efc32081893dd607dfc51938ef93787872008fe2 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 20 Nov 2023 11:29:01 +0800 Subject: [PATCH 0898/1049] soc: intel_adsp: cavs: mask idc interrupt before halting cpu Secondary dsp is idle and waiting for interrupt before it is totally halted. The other active cores can trigger idc interrupt to this core, this can wake it up and result to fw panic. Mask idc interrupt as timer interrupt to prevent this case. Signed-off-by: Rander Wang --- soc/xtensa/intel_adsp/cavs/multiprocessing.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/soc/xtensa/intel_adsp/cavs/multiprocessing.c b/soc/xtensa/intel_adsp/cavs/multiprocessing.c index 85d834065a7b1df..5b13b8138585527 100644 --- a/soc/xtensa/intel_adsp/cavs/multiprocessing.c +++ b/soc/xtensa/intel_adsp/cavs/multiprocessing.c @@ -186,19 +186,25 @@ __imr void soc_mp_init(void) int soc_adsp_halt_cpu(int id) { + unsigned int irq_mask; + if (id == 0 || id == arch_curr_cpu()->id) { return -EINVAL; } + irq_mask = CAVS_L2_IDC; + #ifdef CONFIG_INTEL_ADSP_TIMER /* * Mask timer interrupt for this CPU so it won't wake up * by itself once WFI (wait for interrupt) instruction * runs. */ - CAVS_INTCTRL[id].l2.set = CAVS_L2_DWCT0; + irq_mask |= CAVS_L2_DWCT0; #endif + CAVS_INTCTRL[id].l2.set = irq_mask; + /* Stop sending IPIs to this core */ soc_cpus_active[id] = false; From 18c4574786371146608c359353c3d9ae4597bffd Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Mon, 20 Nov 2023 13:38:00 -0800 Subject: [PATCH 0899/1049] drivers: clock_control: clock_control_ra.c: main oscillator select fix Due to a typo it is not possible to select the main oscillator (MOSC) as a clock source for an RA Microcontroller. This patch resolves the issue. Signed-off-by: Ian Morris --- drivers/clock_control/clock_control_ra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_control_ra.c b/drivers/clock_control/clock_control_ra.c index b1008e3bf83cc51..d3549c1e7c45ddf 100644 --- a/drivers/clock_control/clock_control_ra.c +++ b/drivers/clock_control/clock_control_ra.c @@ -16,7 +16,7 @@ #if DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, pll)) #define SYSCLK_SRC pll #elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, mosc)) -#define SYSCLK_SRC moco +#define SYSCLK_SRC mosc #elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, sosc)) #define SYSCLK_SRC soco #elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, hoco)) From 716de6fef2c6163ee3c6f89abe5c5b50de9adcbb Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Tue, 21 Nov 2023 15:47:05 +0800 Subject: [PATCH 0900/1049] MAINTAINERS: Add myself to ARM arch as collaborator Adding myself as a collaborator on ARM arch so that I can help maintain the aarch32 cortex-a/r codes. Signed-off-by: Huifeng Zhang --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 97d0ec0222faa7e..a4ad483ce2cd1d3 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -155,6 +155,7 @@ ARM arch: - bbolen - povergoing - ithinuel + - sgrrzhf files: - arch/arm/ - arch/arm/core/offsets/ From f66930fd3edd4680a45b6bf63ac7864a9f47462c Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Fri, 13 Oct 2023 20:19:03 +0530 Subject: [PATCH 0901/1049] drivers: uart: uart_ns16550: Enable Async operations using DMA Enabled Async API feature for ns16550 driver using DMA support. Signed-off-by: Anisetti Avinash Krishna --- drivers/serial/Kconfig.ns16550 | 7 + drivers/serial/uart_ns16550.c | 561 ++++++++++++++++++++++++++++++++- 2 files changed, 565 insertions(+), 3 deletions(-) diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index 594216092e7e3d2..fd7f1156a14e727 100644 --- a/drivers/serial/Kconfig.ns16550 +++ b/drivers/serial/Kconfig.ns16550 @@ -30,6 +30,13 @@ config UART_NS16550_DRV_CMD Says n if not sure. +config UART_NS16550_INTEL_LPSS_DMA + bool "INTEL LPSS support for NS16550" + select SERIAL_SUPPORT_ASYNC + select DMA if UART_ASYNC_API + help + This enables the usage of INTEL LPSS internal DMA for Async operations. + choice UART_NS16550_VARIANT prompt "UART variant" default UART_NS16550_VARIANT_NS16550 diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 3f64d83cf36af1d..22243a34d1687cf 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -58,6 +58,16 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #include #endif +#if defined(CONFIG_UART_ASYNC_API) +#include +#include + +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#include +#endif + +#endif + /* If any node has property io-mapped set, we need to support IO port * access in the code and device config struct. * @@ -90,6 +100,12 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define REG_PCP 0x200 /* PRV_CLOCK_PARAMS (Apollo Lake) */ #define REG_MDR1 0x08 /* Mode control reg. (TI_K3) */ +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#define REG_LPSS_SRC_TRAN 0xAF8 /* SRC Transfer LPSS DMA */ +#define REG_LPSS_CLR_SRC_TRAN 0xB48 /* Clear SRC Tran LPSS DMA */ +#define REG_LPSS_MST 0xB20 /* Mask SRC Transfer LPSS DMA */ +#endif + /* equates for interrupt enable register */ #define IER_RXRDY 0x01 /* receiver data ready */ @@ -240,6 +256,15 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define DLF(dev) (get_port(dev) + REG_DLF) #define PCP(dev) (get_port(dev) + REG_PCP) +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#define SRC_TRAN(dev) (get_port(dev) + REG_LPSS_SRC_TRAN) +#define CLR_SRC_TRAN(dev) (get_port(dev) + REG_LPSS_CLR_SRC_TRAN) +#define MST(dev) (get_port(dev) + REG_LPSS_MST) + +#define MASK_LPSS_INT(chan) (BIT(8) << chan) /* mask LPSS DMA Interrupt */ +#define UNMASK_LPSS_INT(chan) (BIT(chan) | (BIT(8) << chan)) /* unmask LPSS DMA Interrupt */ +#endif + #define IIRC(dev) (((struct uart_ns16550_dev_data *)(dev)->data)->iir_cache) #ifdef CONFIG_UART_NS16550_ITE_HIGH_SPEED_BUADRATE @@ -259,6 +284,45 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define ECSPMR(dev) (get_port(dev) + REG_ECSPMR * reg_interval(dev)) #endif +#if defined(CONFIG_UART_ASYNC_API) +struct uart_ns16550_rx_dma_params { + const struct device *dma_dev; + uint8_t dma_channel; + struct dma_config dma_cfg; + struct dma_block_config active_dma_block; + uint8_t *buf; + size_t buf_len; + size_t offset; + size_t counter; + struct k_work_delayable timeout_work; + size_t timeout_us; +}; + +struct uart_ns16550_tx_dma_params { + const struct device *dma_dev; + uint8_t dma_channel; + struct dma_config dma_cfg; + struct dma_block_config active_dma_block; + const uint8_t *buf; + size_t buf_len; + struct k_work_delayable timeout_work; + size_t timeout_us; +}; + +struct uart_ns16550_async_data { + const struct device *uart_dev; + struct uart_ns16550_tx_dma_params tx_dma_params; + struct uart_ns16550_rx_dma_params rx_dma_params; + uint8_t *next_rx_buffer; + size_t next_rx_buffer_len; + uart_callback_t user_callback; + void *user_data; +}; + +static void uart_ns16550_async_rx_timeout(struct k_work *work); +static void uart_ns16550_async_tx_timeout(struct k_work *work); +#endif + /* device config */ struct uart_ns16550_device_config { union { @@ -309,6 +373,11 @@ struct uart_ns16550_dev_data { #if defined(CONFIG_UART_INTERRUPT_DRIVEN) && defined(CONFIG_PM) bool tx_stream_on; #endif + +#if defined(CONFIG_UART_ASYNC_API) + uint64_t phys_addr; + struct uart_ns16550_async_data async; +#endif }; static void ns16550_outbyte(const struct uart_ns16550_device_config *cfg, @@ -358,7 +427,8 @@ static uint8_t ns16550_inbyte(const struct uart_ns16550_device_config *cfg, return 0; } -#if UART_NS16550_PCP_ENABLED +#if (defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) & (defined(CONFIG_UART_ASYNC_API)))\ + | UART_NS16550_PCP_ENABLED static void ns16550_outword(const struct uart_ns16550_device_config *cfg, uintptr_t port, uint32_t val) { @@ -689,6 +759,16 @@ static int uart_reset_config(const struct reset_dt_spec *reset_spec) } #endif /* UART_NS16550_RESET_ENABLED */ +#if (IS_ENABLED(CONFIG_UART_ASYNC_API)) +static inline void async_timer_start(struct k_work_delayable *work, size_t timeout_us) +{ + if ((timeout_us != SYS_FOREVER_US) && (timeout_us != 0)) { + k_work_reschedule(work, K_USEC(timeout_us)); + } +} + +#endif + /** * @brief Initialize individual UART port * @@ -729,6 +809,12 @@ static int uart_ns16550_init(const struct device *dev) device_map(DEVICE_MMIO_RAM_PTR(dev), mbar.phys_addr, mbar.size, K_MEM_CACHE_NONE); +#if defined(CONFIG_UART_ASYNC_API) + if (data->async.tx_dma_params.dma_dev != NULL) { + pcie_set_cmd(dev_cfg->pcie->bdf, PCIE_CONF_CMDSTAT_MASTER, true); + data->phys_addr = mbar.phys_addr; + } +#endif } else #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) */ { @@ -741,7 +827,34 @@ static int uart_ns16550_init(const struct device *dev) DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); } } - +#if defined(CONFIG_UART_ASYNC_API) + if (data->async.tx_dma_params.dma_dev != NULL) { + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0; + data->async.uart_dev = dev; + k_work_init_delayable(&data->async.rx_dma_params.timeout_work, + uart_ns16550_async_rx_timeout); + k_work_init_delayable(&data->async.tx_dma_params.timeout_work, + uart_ns16550_async_tx_timeout); + data->async.rx_dma_params.dma_cfg.head_block = + &data->async.rx_dma_params.active_dma_block; + data->async.tx_dma_params.dma_cfg.head_block = + &data->async.tx_dma_params.active_dma_block; +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) + if (!dev_cfg->io_map) { + uintptr_t base; + + base = DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_OFFSET; + dma_intel_lpss_set_base(data->async.tx_dma_params.dma_dev, base); + dma_intel_lpss_setup(data->async.tx_dma_params.dma_dev); + sys_write32((uint32_t)data->phys_addr, + DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_REMAP_LOW); + sys_write32((uint32_t)(data->phys_addr >> DMA_INTEL_LPSS_ADDR_RIGHT_SHIFT), + DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_REMAP_HI); + } +#endif + } +#endif ret = uart_ns16550_configure(dev, &data->uart_config); if (ret != 0) { return ret; @@ -1155,6 +1268,31 @@ static void uart_ns16550_isr(const struct device *dev) if (dev_data->cb) { dev_data->cb(dev, dev_data->cb_data); } +#if (IS_ENABLED(CONFIG_UART_ASYNC_API)) + if (dev_data->async.tx_dma_params.dma_dev != NULL) { + const struct uart_ns16550_device_config * const config = dev->config; + uint8_t IIR_status = ns16550_inbyte(config, IIR(dev)); +#if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) + uint32_t dma_status = ns16550_inword(config, SRC_TRAN(dev)); + + if (dma_status & BIT(dev_data->async.rx_dma_params.dma_channel)) { + async_timer_start(&dev_data->async.rx_dma_params.timeout_work, + dev_data->async.rx_dma_params.timeout_us); + ns16550_outword(config, CLR_SRC_TRAN(dev), + BIT(dev_data->async.rx_dma_params.dma_channel)); + return; + } + dma_intel_lpss_isr(dev_data->async.rx_dma_params.dma_dev); +#endif + if (IIR_status & IIR_RBRF) { + async_timer_start(&dev_data->async.rx_dma_params.timeout_work, + dev_data->async.rx_dma_params.timeout_us); + ns16550_outword(config, CLR_SRC_TRAN(dev), + BIT(dev_data->async.rx_dma_params.dma_channel)); + return; + } + } +#endif #ifdef CONFIG_UART_NS16550_WA_ISR_REENABLE_INTERRUPT const struct uart_ns16550_device_config * const dev_cfg = dev->config; @@ -1257,6 +1395,352 @@ static int uart_ns16550_drv_cmd(const struct device *dev, uint32_t cmd, #endif /* CONFIG_UART_NS16550_DRV_CMD */ +#if (IS_ENABLED(CONFIG_UART_ASYNC_API)) +static void async_user_callback(const struct device *dev, struct uart_event *evt) +{ + const struct uart_ns16550_dev_data *data = dev->data; + + if (data->async.user_callback) { + data->async.user_callback(dev, evt, data->async.user_data); + } +} + +static void async_evt_tx_done(struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + + (void)k_work_cancel_delayable(&data->async.tx_dma_params.timeout_work); + + struct uart_event event = { + .type = UART_TX_DONE, + .data.tx.buf = tx_params->buf, + .data.tx.len = tx_params->buf_len + }; + + tx_params->buf = NULL; + tx_params->buf_len = 0U; + + async_user_callback(dev, &event); +} + +static void async_evt_rx_rdy(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; + + struct uart_event event = { + .type = UART_RX_RDY, + .data.rx.buf = dma_params->buf, + .data.rx.len = dma_params->counter - dma_params->offset, + .data.rx.offset = dma_params->offset + }; + + dma_params->offset = dma_params->counter; + + if (event.data.rx.len > 0) { + async_user_callback(dev, &event); + } +} + +static void async_evt_rx_buf_release(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; + struct uart_event evt = { + .type = UART_RX_BUF_RELEASED, + .data.rx_buf.buf = data->async.rx_dma_params.buf + }; + + async_user_callback(dev, &evt); + data->async.rx_dma_params.buf = NULL; + data->async.rx_dma_params.buf_len = 0U; + data->async.rx_dma_params.offset = 0U; + data->async.rx_dma_params.counter = 0U; +} + +static void async_evt_rx_buf_request(const struct device *dev) +{ + struct uart_event evt = { + .type = UART_RX_BUF_REQUEST + }; + async_user_callback(dev, &evt); +} + +static void uart_ns16550_async_rx_flush(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; + struct dma_status status; + + dma_get_status(dma_params->dma_dev, + dma_params->dma_channel, + &status); + + const int rx_count = dma_params->buf_len - status.pending_length; + + if (rx_count > dma_params->counter) { + dma_params->counter = rx_count; + async_evt_rx_rdy(dev); + } +} + +static int uart_ns16550_rx_disable(const struct device *dev) +{ + const struct uart_ns16550_device_config * const config = dev->config; + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; + struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + if (!device_is_ready(dma_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + (void)k_work_cancel_delayable(&data->async.rx_dma_params.timeout_work); + + if (dma_params->buf && (dma_params->buf_len > 0)) { + uart_ns16550_async_rx_flush(dev); + async_evt_rx_buf_release(dev); + if (data->async.next_rx_buffer != NULL) { + dma_params->buf = data->async.next_rx_buffer; + dma_params->buf_len = data->async.next_rx_buffer_len; + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0; + async_evt_rx_buf_release(dev); + } + } + ret = dma_stop(dma_params->dma_dev, + dma_params->dma_channel); + + struct uart_event event = { + .type = UART_RX_DISABLED + }; + + async_user_callback(dev, &event); + + if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) { + ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(dma_params->dma_channel)); + } + +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static void prepare_rx_dma_block_config(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; + struct uart_ns16550_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + + assert(rx_dma_params->buf != NULL); + assert(rx_dma_params->buf_len > 0); + + struct dma_block_config *head_block_config = &rx_dma_params->active_dma_block; + + head_block_config->dest_address = (uint64_t)rx_dma_params->buf; + head_block_config->source_address = data->phys_addr; + head_block_config->block_size = rx_dma_params->buf_len; +} + +static void dma_callback(const struct device *dev, void *user_data, uint32_t channel, + int status) +{ + struct device *uart_dev = (struct device *)user_data; + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)uart_dev->data; + struct uart_ns16550_rx_dma_params *rx_params = &data->async.rx_dma_params; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + + if (channel == tx_params->dma_channel) { + async_evt_tx_done(uart_dev); + } else if (channel == rx_params->dma_channel) { + + rx_params->counter = rx_params->buf_len; + + async_evt_rx_rdy(uart_dev); + async_evt_rx_buf_release(uart_dev); + + rx_params->buf = data->async.next_rx_buffer; + rx_params->buf_len = data->async.next_rx_buffer_len; + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0U; + + if (rx_params->buf != NULL && + rx_params->buf_len > 0) { + dma_reload(dev, rx_params->dma_channel, data->phys_addr, + (uint64_t)rx_params->buf, rx_params->buf_len); + dma_start(dev, rx_params->dma_channel); + async_evt_rx_buf_request(uart_dev); + } else { + uart_ns16550_rx_disable(uart_dev); + } + } +} + +static int uart_ns16550_callback_set(const struct device *dev, uart_callback_t callback, + void *user_data) +{ + struct uart_ns16550_dev_data *data = dev->data; + + data->async.user_callback = callback; + data->async.user_data = user_data; + + return 0; +} + +static int uart_ns16550_tx(const struct device *dev, const uint8_t *buf, size_t len, + int32_t timeout_us) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + if (!device_is_ready(tx_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + tx_params->buf = buf; + tx_params->buf_len = len; + tx_params->active_dma_block.source_address = (uint64_t)buf; + tx_params->active_dma_block.dest_address = data->phys_addr; + tx_params->active_dma_block.block_size = len; + tx_params->active_dma_block.next_block = NULL; + + ret = dma_config(tx_params->dma_dev, + tx_params->dma_channel, + (struct dma_config *)&tx_params->dma_cfg); + + if (ret == 0) { + ret = dma_start(tx_params->dma_dev, + tx_params->dma_channel); + if (ret) { + ret = -EIO; + goto out; + } + async_timer_start(&data->async.tx_dma_params.timeout_work, timeout_us); + } + +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int uart_ns16550_tx_abort(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + struct dma_status status; + int ret = 0; + size_t bytes_tx; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (!device_is_ready(tx_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + (void)k_work_cancel_delayable(&data->async.tx_dma_params.timeout_work); + + ret = dma_stop(tx_params->dma_dev, tx_params->dma_channel); + dma_get_status(tx_params->dma_dev, + tx_params->dma_channel, + &status); + bytes_tx = tx_params->buf_len - status.pending_length; + + if (ret == 0) { + struct uart_event tx_aborted_event = { + .type = UART_TX_ABORTED, + .data.tx.buf = tx_params->buf, + .data.tx.len = bytes_tx + }; + async_user_callback(dev, &tx_aborted_event); + } +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int uart_ns16550_rx_enable(const struct device *dev, uint8_t *buf, const size_t len, + const int32_t timeout_us) +{ + struct uart_ns16550_dev_data *data = dev->data; + const struct uart_ns16550_device_config *config = dev->config; + struct uart_ns16550_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + int ret = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (!device_is_ready(rx_dma_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + rx_dma_params->timeout_us = timeout_us; + rx_dma_params->buf = buf; + rx_dma_params->buf_len = len; + + if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) { + ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(DMA_INTEL_LPSS_RX_CHAN)); + } else { + ns16550_outbyte(config, IER(dev), + (ns16550_inbyte(config, IER(dev)) | IER_RXRDY)); + ns16550_outbyte(config, FCR(dev), FCR_FIFO); + } + prepare_rx_dma_block_config(dev); + dma_config(rx_dma_params->dma_dev, + rx_dma_params->dma_channel, + (struct dma_config *)&rx_dma_params->dma_cfg); + dma_start(rx_dma_params->dma_dev, rx_dma_params->dma_channel); + async_evt_rx_buf_request(dev); +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int uart_ns16550_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len) +{ + struct uart_ns16550_dev_data *data = dev->data; + + assert(data->async.next_rx_buffer == NULL); + assert(data->async.next_rx_buffer_len == 0); + data->async.next_rx_buffer = buf; + data->async.next_rx_buffer_len = len; + + return 0; +} + +static void uart_ns16550_async_rx_timeout(struct k_work *work) +{ + struct k_work_delayable *work_delay = CONTAINER_OF(work, struct k_work_delayable, work); + struct uart_ns16550_rx_dma_params *rx_params = + CONTAINER_OF(work_delay, struct uart_ns16550_rx_dma_params, + timeout_work); + struct uart_ns16550_async_data *async_data = + CONTAINER_OF(rx_params, struct uart_ns16550_async_data, + rx_dma_params); + const struct device *dev = async_data->uart_dev; + + uart_ns16550_async_rx_flush(dev); + +} + +static void uart_ns16550_async_tx_timeout(struct k_work *work) +{ + struct k_work_delayable *work_delay = CONTAINER_OF(work, struct k_work_delayable, work); + struct uart_ns16550_tx_dma_params *tx_params = + CONTAINER_OF(work_delay, struct uart_ns16550_tx_dma_params, + timeout_work); + struct uart_ns16550_async_data *async_data = + CONTAINER_OF(tx_params, struct uart_ns16550_async_data, + tx_dma_params); + const struct device *dev = async_data->uart_dev; + + (void)uart_ns16550_tx_abort(dev); +} + +#endif /* CONFIG_UART_ASYNC_API */ static const struct uart_driver_api uart_ns16550_driver_api = { .poll_in = uart_ns16550_poll_in, @@ -1285,6 +1769,15 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #endif +#ifdef CONFIG_UART_ASYNC_API + .callback_set = uart_ns16550_callback_set, + .tx = uart_ns16550_tx, + .tx_abort = uart_ns16550_tx_abort, + .rx_enable = uart_ns16550_rx_enable, + .rx_disable = uart_ns16550_rx_disable, + .rx_buf_rsp = uart_ns16550_rx_buf_rsp, +#endif + #ifdef CONFIG_UART_NS16550_LINE_CTRL .line_ctrl_set = uart_ns16550_line_ctrl_set, #endif @@ -1356,6 +1849,67 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #define UART_NS16550_PCIE_IRQ_FUNC_DEFINE(n) #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +#ifdef CONFIG_UART_ASYNC_API +#define DMA_PARAMS(n) \ + .async.tx_dma_params = { \ + .dma_dev = \ + DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(n, tx)), \ + .dma_channel = \ + DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ + .dma_cfg = { \ + .source_burst_length = 1, \ + .dest_burst_length = 1, \ + .source_data_size = 1, \ + .dest_data_size = 1, \ + .complete_callback_en = 0, \ + .error_callback_en = 1, \ + .block_count = 1, \ + .channel_direction = MEMORY_TO_PERIPHERAL, \ + .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ + .dma_callback = dma_callback, \ + .user_data = (void *)DEVICE_DT_INST_GET(n) \ + }, \ + }, \ + .async.rx_dma_params = { \ + .dma_dev = \ + DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(n, rx)), \ + .dma_channel = \ + DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ + .dma_cfg = { \ + .source_burst_length = 1, \ + .dest_burst_length = 1, \ + .source_data_size = 1, \ + .dest_data_size = 1, \ + .complete_callback_en = 0, \ + .error_callback_en = 1, \ + .block_count = 1, \ + .channel_direction = PERIPHERAL_TO_MEMORY, \ + .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ + .dma_callback = dma_callback, \ + .user_data = (void *)DEVICE_DT_INST_GET(n) \ + }, \ + }, \ + COND_CODE_0(DT_INST_ON_BUS(n, pcie), \ + (.phys_addr = DT_INST_REG_ADDR(n),), ()) + +#define DMA_PARAMS_NULL(n) \ + .async.tx_dma_params = { \ + .dma_dev = NULL \ + }, \ + .async.rx_dma_params = { \ + .dma_dev = NULL \ + }, \ + +#define DEV_DATA_ASYNC(n) \ + COND_CODE_0(DT_INST_PROP(n, io_mapped), \ + (COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \ + (DMA_PARAMS(n)), (DMA_PARAMS_NULL(n)))), \ + (DMA_PARAMS_NULL(n))) +#else +#define DEV_DATA_ASYNC(n) +#endif /* CONFIG_UART_ASYNC_API */ + + #define UART_NS16550_COMMON_DEV_CFG_INITIALIZER(n) \ COND_CODE_1(DT_INST_NODE_HAS_PROP(n, clock_frequency), ( \ .sys_clk_freq = DT_INST_PROP(n, clock_frequency), \ @@ -1386,7 +1940,8 @@ static const struct uart_driver_api uart_ns16550_driver_api = { (UART_CFG_FLOW_CTRL_RTS_CTS), \ (UART_CFG_FLOW_CTRL_NONE)), \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, dlf), \ - (.dlf = DT_INST_PROP_OR(n, dlf, 0),)) + (.dlf = DT_INST_PROP_OR(n, dlf, 0),)) \ + DEV_DATA_ASYNC(n) \ #define UART_NS16550_DEVICE_IO_MMIO_INIT(n) \ UART_NS16550_IRQ_FUNC_DECLARE(n); \ From 05fd5b042658d4d5cd9ca640084b594ee52d7f21 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Sat, 14 Oct 2023 23:00:33 +0530 Subject: [PATCH 0902/1049] boards: x86: intel_rpl: Added modifications for Asycn NS16550 Added modifications to support async apis for ns16550 on RPL-s using LPSS DMA. Signed-off-by: Anisetti Avinash Krishna --- boards/x86/intel_rpl/Kconfig.defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boards/x86/intel_rpl/Kconfig.defconfig b/boards/x86/intel_rpl/Kconfig.defconfig index 78c10d200a35c99..ea93b03e039c10d 100644 --- a/boards/x86/intel_rpl/Kconfig.defconfig +++ b/boards/x86/intel_rpl/Kconfig.defconfig @@ -53,4 +53,7 @@ config DMA_DW_CHANNEL_COUNT default 2 endif +config UART_NS16550_INTEL_LPSS_DMA + default y + endif # BOARD_INTEL_RPL_S_CRB From 7b412be883d8fe5f4822b45904075c2ea2e8e4bc Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Sat, 14 Oct 2023 23:15:08 +0530 Subject: [PATCH 0903/1049] dts: x86: intel: raptor_lake: Added LPSS dma node for UART Added LPSS dma node for UART Async API support Signed-off-by: Anisetti Avinash Krishna --- dts/x86/intel/raptor_lake.dtsi | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/dts/x86/intel/raptor_lake.dtsi b/dts/x86/intel/raptor_lake.dtsi index 797a3fa0e544a14..ab3e9958928eba1 100644 --- a/dts/x86/intel/raptor_lake.dtsi +++ b/dts/x86/intel/raptor_lake.dtsi @@ -79,7 +79,7 @@ compatible = "intel,lpss"; dma-parent = <&i2c0>; #dma-cells = <1>; - status = "okay"; + status = "disabled"; }; i2c1: i2c1 { @@ -272,6 +272,12 @@ status = "disabled"; }; + uart0_dma: uart0_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + uart0: uart0 { compatible = "ns16550"; vendor-id = <0x8086>; @@ -281,7 +287,15 @@ interrupts = ; interrupt-parent = <&intc>; current-speed = <115200>; - status = "okay"; + dmas = <&uart0_dma 0>, <&uart0_dma 1>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + uart1_dma: uart1_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; }; uart1: uart1 { @@ -293,7 +307,9 @@ interrupts = ; interrupt-parent = <&intc>; current-speed = <115200>; - status = "okay"; + dmas = <&uart1_dma 0>, <&uart1_dma 1>; + dma-names = "tx", "rx"; + status = "disabled"; }; uart2: uart2 { From 6de5a1a5d578e99da0852c4661abfeed40f3f994 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Sat, 14 Oct 2023 23:21:15 +0530 Subject: [PATCH 0904/1049] tests: drivers: uart: uart_async_api: Enabled tests for rpl_s platform Enabled tests for intel_rpl_s_crb platform. Signed-off-by: Anisetti Avinash Krishna --- .../uart/uart_async_api/boards/intel_rpl_s_crb.conf | 1 + .../uart_async_api/boards/intel_rpl_s_crb.overlay | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.conf create mode 100644 tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.conf b/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.conf new file mode 100644 index 000000000000000..86df0aff3e6242a --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.conf @@ -0,0 +1 @@ +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.overlay b/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.overlay new file mode 100644 index 000000000000000..35c408a852677de --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/intel_rpl_s_crb.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +dut: &uart0 { + status = "okay"; +}; + +&uart0_dma { + status = "okay"; +}; From bd6d43d4c8e134437865b5e5d2222119c62c493a Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 1 Nov 2023 14:47:08 +0000 Subject: [PATCH 0905/1049] sysbuild: bootloader: Fix setting application Kconfig in MCUboot Fixes wrongly setting configuration to generate an unsigned image in the MCUboot configuration when this does not apply to MCUboot Signed-off-by: Jamie McCrae --- .../image_configurations/BOOTLOADER_image_default.cmake | 8 -------- 1 file changed, 8 deletions(-) diff --git a/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake b/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake index 5594109668b45b4..0da5a89ce117ce8 100644 --- a/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake +++ b/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake @@ -27,11 +27,3 @@ foreach(loopkeytype ${keytypes}) set_config_bool(${ZCMAKE_APPLICATION} ${loopkeytype} n) endif() endforeach() - -if(SB_CONFIG_BOOTLOADER_MCUBOOT) - if("${SB_CONFIG_SIGNATURE_TYPE}" STREQUAL "NONE") - set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE y) - else() - set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE n) - endif() -endif() From 67696b7311b1cd88926349c0064449236d03951f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 1 Nov 2023 14:48:03 +0000 Subject: [PATCH 0906/1049] sysbuild: mcuboot: Disable signing key in no signing mode Prevents allowing the user to enter a signing key when the signing mode is set to hash check only without signatures Signed-off-by: Jamie McCrae --- share/sysbuild/images/bootloader/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/sysbuild/images/bootloader/Kconfig b/share/sysbuild/images/bootloader/Kconfig index e8c788f72c57550..d8e1bf70d75b20d 100644 --- a/share/sysbuild/images/bootloader/Kconfig +++ b/share/sysbuild/images/bootloader/Kconfig @@ -56,7 +56,7 @@ config BOOT_SIGNATURE_TYPE_ED25519 endchoice config BOOT_SIGNATURE_KEY_FILE - string "Signing PEM key file" + string "Signing PEM key file" if !BOOT_SIGNATURE_TYPE_NONE default "$(ZEPHYR_MCUBOOT_MODULE_DIR)/root-ec-p256.pem" if BOOT_SIGNATURE_TYPE_ECDSA_P256 default "$(ZEPHYR_MCUBOOT_MODULE_DIR)/root-ed25519.pem" if BOOT_SIGNATURE_TYPE_ED25519 default "$(ZEPHYR_MCUBOOT_MODULE_DIR)/root-rsa-2048.pem" if BOOT_SIGNATURE_TYPE_RSA From 2a6cec0687c279dde5756aa9aa38ff5bbba9fa42 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 21 Nov 2023 10:41:03 +0000 Subject: [PATCH 0907/1049] west.yml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: 47b34362552835621bc289d53d2127691088cb7c Brings following Zephyr relevant fixes: - 47b34362 zephyr: kconfig: Prevent MBEDTLS selection when tinycrypt is used - cd82f8bf boot: zephyr: add support for lpcxpresso55s28 Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index f1fd789503e6ad2..fbeb9919eacdc1c 100644 --- a/west.yml +++ b/west.yml @@ -282,7 +282,7 @@ manifest: groups: - crypto - name: mcuboot - revision: 0c0470e294dcfb52aab92299356a5f3caa0aa52b + revision: 47b34362552835621bc289d53d2127691088cb7c path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From 939b90be4c9a242b4e5dced0c2b00f145ccd671c Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 16 Nov 2023 16:26:38 +0000 Subject: [PATCH 0908/1049] drivers: drop few redundant guard around pm_policy_state_lock_* The pm_policy_state_lock_put and pm_policy_state_lock_put functions already become a no-op if CONFIG_PM is not enabled. Drop the guards around it in few different drivers. Signed-off-by: Fabio Baltieri --- drivers/display/display_rm67162.c | 18 +++++++----------- drivers/dma/dma_mcux_smartdma.c | 12 ++++++------ drivers/eeprom/eeprom_mchp_xec.c | 11 +++-------- drivers/kscan/kscan_mchp_xec.c | 6 ++---- drivers/ps2/ps2_mchp_xec.c | 16 ++++++---------- drivers/sensor/mchp_tach_xec/tach_mchp_xec.c | 7 +++---- 6 files changed, 27 insertions(+), 43 deletions(-) diff --git a/drivers/display/display_rm67162.c b/drivers/display/display_rm67162.c index 5516e57789de23d..afb7f4dd851b396 100644 --- a/drivers/display/display_rm67162.c +++ b/drivers/display/display_rm67162.c @@ -434,18 +434,14 @@ static int rm67162_write(const struct device *dev, const uint16_t x, * give to the TE semaphore) before sending the frame */ if (config->te_gpio.port != NULL) { - if (IS_ENABLED(CONFIG_PM)) { - /* Block sleep state until next TE interrupt - * so we can send frame during that interval - */ - pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, - PM_ALL_SUBSTATES); - } + /* Block sleep state until next TE interrupt so we can send + * frame during that interval + */ + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); k_sem_take(&data->te_sem, K_FOREVER); - if (IS_ENABLED(CONFIG_PM)) { - pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, - PM_ALL_SUBSTATES); - } + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); } src = buf; first_cmd = true; diff --git a/drivers/dma/dma_mcux_smartdma.c b/drivers/dma/dma_mcux_smartdma.c index b1870b3959c1545..9899797ae53f151 100644 --- a/drivers/dma/dma_mcux_smartdma.c +++ b/drivers/dma/dma_mcux_smartdma.c @@ -148,12 +148,12 @@ static int dma_mcux_smartdma_start(const struct device *dev, uint32_t channel) { const struct dma_mcux_smartdma_config *config = dev->config; -#ifdef CONFIG_PM /* Block PM transition until DMA completes */ pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* Kick off SMARTDMA */ config->base->CTRL = SMARTDMA_MAGIC | SMARTDMA_BOOT; + return 0; } @@ -162,12 +162,13 @@ static int dma_mcux_smartdma_stop(const struct device *dev, uint32_t channel) { ARG_UNUSED(dev); ARG_UNUSED(channel); + /* Stop DMA */ SMARTDMA_Reset(); -#ifdef CONFIG_PM + /* Release PM lock */ pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + return 0; } @@ -195,10 +196,9 @@ static void dma_mcux_smartdma_irq(const struct device *dev) if (data->callback) { data->callback(dev, data->user_data, 0, 0); } -#ifdef CONFIG_PM + /* Release PM lock */ pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } /** diff --git a/drivers/eeprom/eeprom_mchp_xec.c b/drivers/eeprom/eeprom_mchp_xec.c index bd1c83e4c74d7a4..171940a008d4fbf 100644 --- a/drivers/eeprom/eeprom_mchp_xec.c +++ b/drivers/eeprom/eeprom_mchp_xec.c @@ -241,9 +241,8 @@ static int eeprom_xec_read(const struct device *dev, off_t offset, } k_mutex_lock(&data->lock_mtx, K_FOREVER); -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* EEPROM HW READ */ for (chunk_idx = 0; chunk_idx < len; chunk_idx += XEC_EEPROM_TRANSFER_SIZE_READ) { if ((len-chunk_idx) < XEC_EEPROM_TRANSFER_SIZE_READ) { @@ -252,9 +251,7 @@ static int eeprom_xec_read(const struct device *dev, off_t offset, eeprom_xec_data_read_32_bytes(regs, &data_buf[chunk_idx], chunk_size, (offset+chunk_idx)); } -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif k_mutex_unlock(&data->lock_mtx); return 0; @@ -280,9 +277,8 @@ static int eeprom_xec_write(const struct device *dev, off_t offset, } k_mutex_lock(&data->lock_mtx, K_FOREVER); -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* EEPROM HW WRITE */ for (chunk_idx = 0; chunk_idx < len; chunk_idx += XEC_EEPROM_TRANSFER_SIZE_WRITE) { if ((len-chunk_idx) < XEC_EEPROM_TRANSFER_SIZE_WRITE) { @@ -291,9 +287,8 @@ static int eeprom_xec_write(const struct device *dev, off_t offset, eeprom_xec_data_write_32_bytes(regs, &data_buf[chunk_idx], chunk_size, (offset+chunk_idx)); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif k_mutex_unlock(&data->lock_mtx); return 0; diff --git a/drivers/kscan/kscan_mchp_xec.c b/drivers/kscan/kscan_mchp_xec.c index e0960b1c9463ef5..e3e8fa4043ecde6 100644 --- a/drivers/kscan/kscan_mchp_xec.c +++ b/drivers/kscan/kscan_mchp_xec.c @@ -373,9 +373,8 @@ void polling_task(const struct device *dev, void *dummy2, void *dummy3) drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_ALL); k_sem_take(&data->poll_lock, K_FOREVER); -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + uint32_t start_poll_cycles = k_cycle_get_32(); while (atomic_get(&data->enable_scan) == 1U) { @@ -416,9 +415,8 @@ void polling_task(const struct device *dev, void *dummy2, void *dummy3) /* Allow other threads to run while we sleep */ k_usleep(wait_period); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } } diff --git a/drivers/ps2/ps2_mchp_xec.c b/drivers/ps2/ps2_mchp_xec.c index f3b1a9e10bfe6af..0a6677869127bae 100644 --- a/drivers/ps2/ps2_mchp_xec.c +++ b/drivers/ps2/ps2_mchp_xec.c @@ -172,9 +172,9 @@ static int ps2_xec_write(const struct device *dev, uint8_t value) LOG_DBG("PS2 write timed out"); return -ETIMEDOUT; } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* Inhibit ps2 controller and clear status register */ regs->CTRL = 0x00; @@ -306,33 +306,29 @@ static void ps2_xec_isr(const struct device *dev) ps2_xec_girq_clr(config->girq_id, config->girq_bit); if (status & MCHP_PS2_STATUS_RXD_RDY) { -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + regs->CTRL = 0x00; if (data->callback_isr) { data->callback_isr(dev, regs->TRX_BUFF); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } else if (status & (MCHP_PS2_STATUS_TX_TMOUT | MCHP_PS2_STATUS_TX_ST_TMOUT)) { /* Clear sticky bits and go to read mode */ regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK; LOG_ERR("TX time out: %0x", status); -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } else if (status & (MCHP_PS2_STATUS_RX_TMOUT | MCHP_PS2_STATUS_PE | MCHP_PS2_STATUS_FE)) { /* catch and clear rx error if any */ regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK; } else if (status & MCHP_PS2_STATUS_TX_IDLE) { /* Transfer completed, release the lock to enter low per mode */ -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } /* The control register reverts to RX automatically after diff --git a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c index 49fbbac8fe2d50e..12cd63ee316732d 100644 --- a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c +++ b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c @@ -58,9 +58,8 @@ int tach_xec_sample_fetch(const struct device *dev, enum sensor_channel chan) struct tach_regs * const tach = cfg->regs; uint8_t poll_count = 0; -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + while (poll_count < PIN_STS_TIMEOUT) { /* See whether internal counter is already latched */ if (tach->STATUS & MCHP_TACH_STS_CNT_RDY) { @@ -74,9 +73,9 @@ int tach_xec_sample_fetch(const struct device *dev, enum sensor_channel chan) /* Allow other threads to run while we sleep */ k_usleep(USEC_PER_MSEC); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + if (poll_count == PIN_STS_TIMEOUT) { return -EINVAL; } From 43d5f392090dd5060d056a527917312bef913864 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 22 Nov 2023 15:40:15 +0100 Subject: [PATCH 0909/1049] zbus: add MULTITHREADING dependency Zbus uses mutexes internally that are available only when MULTITHREADING is enabled so add it to fix the following error: /opt/zephyr-sdk-0.16.3/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/ 12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: zephyr/subsys/ zbus/libsubsys__zbus.a(zbus.c.obj): in function `k_mutex_init': /builds/zephyr/mcuboot/zephyr/include/generated/syscalls/kernel.h:969: undefined reference to `z_impl_k_mutex_init' Signed-off-by: Bartosz Bilas --- subsys/zbus/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/zbus/Kconfig b/subsys/zbus/Kconfig index f250865b4666284..ba1c9dd08d0784d 100644 --- a/subsys/zbus/Kconfig +++ b/subsys/zbus/Kconfig @@ -3,6 +3,7 @@ menuconfig ZBUS bool "Zbus support" + depends on MULTITHREADING help Enables support for Zephyr message bus. From 46889819e6d2fbc3e8ff919f0f695faee55438c8 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 22 Nov 2023 10:12:11 +0000 Subject: [PATCH 0910/1049] cmake: modules: dts: Fix board revision 0 overlay Fixes an issue whereby a board revision is 0 and the overlay file exists but would not be included Signed-off-by: Jamie McCrae --- cmake/modules/dts.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/dts.cmake b/cmake/modules/dts.cmake index c9ac751a1e5015c..23659c186924470 100644 --- a/cmake/modules/dts.cmake +++ b/cmake/modules/dts.cmake @@ -125,7 +125,7 @@ set(VENDOR_PREFIXES dts/bindings/vendor-prefixes.txt) set_ifndef(DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts) if(EXISTS ${DTS_SOURCE}) # We found a devicetree. Check for a board revision overlay. - if(BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) + if(DEFINED BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) list(APPEND DTS_SOURCE ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) endif() else() From d34f725df81852b468dba2727a4d569022cb907d Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Thu, 16 Nov 2023 19:28:13 +0100 Subject: [PATCH 0911/1049] soc: xtensa: esp32s3: Update SOC variant list Add missing combinations of the ESP32-S3 Wroom module. Signed-off-by: Marek Matej --- .../espressif/esp32s3/esp32s3_wroom_n16r2.dtsi | 18 ++++++++++++++++++ .../espressif/esp32s3/esp32s3_wroom_n4r2.dtsi | 18 ++++++++++++++++++ .../espressif/esp32s3/esp32s3_wroom_n8r2.dtsi | 18 ++++++++++++++++++ .../espressif/esp32s3/esp32s3_wroom_n8r8.dtsi | 1 + soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc | 8 +++++++- 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi new file mode 100644 index 000000000000000..c4c0929063d5951 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 16MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi new file mode 100644 index 000000000000000..b8f733a3c547911 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi new file mode 100644 index 000000000000000..b77169f172beea0 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi index eac737e3d619092..34ec0ec5ac1aae6 100644 --- a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi @@ -14,4 +14,5 @@ /* 8MB psram */ &psram0 { reg = <0x3c000000 DT_SIZE_M(8)>; + status = "okay"; }; diff --git a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc index b8cc95b62cb5a00..ad8b4b4234b8a93 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc @@ -43,7 +43,13 @@ choice SOC_PART_NUMBER config SOC_ESP32S3_WROOM_N8R8 bool "ESP32S3_WROOM_N8R8" config SOC_ESP32S3_WROOM_N16R8 - bool "ESP32S3_WROOM_N16" + bool "ESP32S3_WROOM_N16R8" + config SOC_ESP32S3_WROOM_N4R2 + bool "ESP32S3_WROOM_N4R2" + config SOC_ESP32S3_WROOM_N8R2 + bool "ESP32S3_WROOM_N8R2" + config SOC_ESP32S3_WROOM_N16R2 + bool "ESP32S3_WROOM_N16R2" endchoice # SOC_PART_NUMBER From d9fd752392624285d906838c9271448421f85c37 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 20:35:40 +0000 Subject: [PATCH 0912/1049] sensor: mchp_tach_xec: drop PM_DEVICE guards These are not needed and are now causing build errors since the pm_device calls are always there and need the header to become a no-op. Signed-off-by: Fabio Baltieri --- drivers/sensor/mchp_tach_xec/tach_mchp_xec.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c index 12cd63ee316732d..9ee732475da93c3 100644 --- a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c +++ b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c @@ -22,9 +22,7 @@ #include #include -#ifdef CONFIG_PM_DEVICE #include -#endif LOG_MODULE_REGISTER(tach_xec, CONFIG_SENSOR_LOG_LEVEL); From 5efa5b28926097becd6aa4f7ab42a2966f6c2a1e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 22 Nov 2023 17:30:45 +0000 Subject: [PATCH 0913/1049] tests: drop input_ prefix from input tests These are already in a "input" subdirectory, the prefix is redundant, drop it. Signed-off-by: Fabio Baltieri --- tests/subsys/input/{input_longpress => longpress}/CMakeLists.txt | 0 .../{input_longpress => longpress}/boards/native_sim.overlay | 0 .../{input_longpress => longpress}/boards/native_sim_64.overlay | 0 tests/subsys/input/{input_longpress => longpress}/prj.conf | 0 tests/subsys/input/{input_longpress => longpress}/src/main.c | 0 tests/subsys/input/{input_longpress => longpress}/testcase.yaml | 0 tests/subsys/input/{input_shell => shell}/CMakeLists.txt | 0 tests/subsys/input/{input_shell => shell}/prj.conf | 0 tests/subsys/input/{input_shell => shell}/src/main.c | 0 tests/subsys/input/{input_shell => shell}/testcase.yaml | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename tests/subsys/input/{input_longpress => longpress}/CMakeLists.txt (100%) rename tests/subsys/input/{input_longpress => longpress}/boards/native_sim.overlay (100%) rename tests/subsys/input/{input_longpress => longpress}/boards/native_sim_64.overlay (100%) rename tests/subsys/input/{input_longpress => longpress}/prj.conf (100%) rename tests/subsys/input/{input_longpress => longpress}/src/main.c (100%) rename tests/subsys/input/{input_longpress => longpress}/testcase.yaml (100%) rename tests/subsys/input/{input_shell => shell}/CMakeLists.txt (100%) rename tests/subsys/input/{input_shell => shell}/prj.conf (100%) rename tests/subsys/input/{input_shell => shell}/src/main.c (100%) rename tests/subsys/input/{input_shell => shell}/testcase.yaml (100%) diff --git a/tests/subsys/input/input_longpress/CMakeLists.txt b/tests/subsys/input/longpress/CMakeLists.txt similarity index 100% rename from tests/subsys/input/input_longpress/CMakeLists.txt rename to tests/subsys/input/longpress/CMakeLists.txt diff --git a/tests/subsys/input/input_longpress/boards/native_sim.overlay b/tests/subsys/input/longpress/boards/native_sim.overlay similarity index 100% rename from tests/subsys/input/input_longpress/boards/native_sim.overlay rename to tests/subsys/input/longpress/boards/native_sim.overlay diff --git a/tests/subsys/input/input_longpress/boards/native_sim_64.overlay b/tests/subsys/input/longpress/boards/native_sim_64.overlay similarity index 100% rename from tests/subsys/input/input_longpress/boards/native_sim_64.overlay rename to tests/subsys/input/longpress/boards/native_sim_64.overlay diff --git a/tests/subsys/input/input_longpress/prj.conf b/tests/subsys/input/longpress/prj.conf similarity index 100% rename from tests/subsys/input/input_longpress/prj.conf rename to tests/subsys/input/longpress/prj.conf diff --git a/tests/subsys/input/input_longpress/src/main.c b/tests/subsys/input/longpress/src/main.c similarity index 100% rename from tests/subsys/input/input_longpress/src/main.c rename to tests/subsys/input/longpress/src/main.c diff --git a/tests/subsys/input/input_longpress/testcase.yaml b/tests/subsys/input/longpress/testcase.yaml similarity index 100% rename from tests/subsys/input/input_longpress/testcase.yaml rename to tests/subsys/input/longpress/testcase.yaml diff --git a/tests/subsys/input/input_shell/CMakeLists.txt b/tests/subsys/input/shell/CMakeLists.txt similarity index 100% rename from tests/subsys/input/input_shell/CMakeLists.txt rename to tests/subsys/input/shell/CMakeLists.txt diff --git a/tests/subsys/input/input_shell/prj.conf b/tests/subsys/input/shell/prj.conf similarity index 100% rename from tests/subsys/input/input_shell/prj.conf rename to tests/subsys/input/shell/prj.conf diff --git a/tests/subsys/input/input_shell/src/main.c b/tests/subsys/input/shell/src/main.c similarity index 100% rename from tests/subsys/input/input_shell/src/main.c rename to tests/subsys/input/shell/src/main.c diff --git a/tests/subsys/input/input_shell/testcase.yaml b/tests/subsys/input/shell/testcase.yaml similarity index 100% rename from tests/subsys/input/input_shell/testcase.yaml rename to tests/subsys/input/shell/testcase.yaml From 3b4523588724d52c2e037d65fbe98ae4f06097d2 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 12 Oct 2023 20:02:16 -0400 Subject: [PATCH 0914/1049] doc: posix: structural reorganization of posix docs Revise the structure of the POSIX API docs. This separates related items out to dedicated pages. Further improvements could yet be made - e.g. using the 'collapse' feature to expand and collapse large sections of text or tables. Signed-off-by: Christopher Friedt --- doc/_scripts/redirects.py | 2 +- doc/introduction/index.rst | 2 + doc/services/portability/index.rst | 2 +- doc/services/portability/posix/aep/index.rst | 191 ++++++++ .../portability/posix/conformance/index.rst | 145 +++++++ .../posix/implementation/index.rst | 77 ++++ doc/services/portability/posix/index.rst | 14 + .../portability/posix/kconfig/index.rst | 52 +++ .../option_groups/index.rst} | 408 ++++++++++-------- .../portability/posix/overview/index.rst | 135 ++++++ .../{ => posix/overview}/posix.svg | 2 +- 11 files changed, 851 insertions(+), 179 deletions(-) create mode 100644 doc/services/portability/posix/aep/index.rst create mode 100644 doc/services/portability/posix/conformance/index.rst create mode 100644 doc/services/portability/posix/implementation/index.rst create mode 100644 doc/services/portability/posix/index.rst create mode 100644 doc/services/portability/posix/kconfig/index.rst rename doc/services/portability/{posix.rst => posix/option_groups/index.rst} (57%) create mode 100644 doc/services/portability/posix/overview/index.rst rename doc/services/portability/{ => posix/overview}/posix.svg (68%) diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 0180d1f5373faf3..78c5c8ed84fc1a5 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -71,7 +71,7 @@ ('guides/pm/power_domain', 'services/pm/power_domain'), ('guides/pm/system', 'services/pm/system'), ('guides/portability/index', 'services/portability/index'), - ('guides/portability/posix', 'services/portability/posix'), + ('guides/portability/posix', 'services/portability/posix/index'), ('guides/porting/arch', 'hardware/porting/arch'), ('guides/porting/board_porting', 'hardware/porting/board_porting'), ('guides/porting/index', 'hardware/porting/index'), diff --git a/doc/introduction/index.rst b/doc/introduction/index.rst index 85968ca456a1032..985ffe8e002d887 100644 --- a/doc/introduction/index.rst +++ b/doc/introduction/index.rst @@ -80,6 +80,8 @@ Zephyr offers a large and ever growing number of features including: * Red/black tree ready queue * Traditional multi-queue ready queue +.. _zephyr_intro_configurability: + **Highly configurable / Modular for flexibility** Allows an application to incorporate *only* the capabilities it needs as it needs them, and to specify their quantity and size. diff --git a/doc/services/portability/index.rst b/doc/services/portability/index.rst index 18b1a83c95f7f1d..357aa778514a254 100644 --- a/doc/services/portability/index.rst +++ b/doc/services/portability/index.rst @@ -14,6 +14,6 @@ supported by the Zephyr RTOS. .. toctree:: :maxdepth: 1 - posix.rst + posix/index.rst cmsis_rtos_v1.rst cmsis_rtos_v2.rst diff --git a/doc/services/portability/posix/aep/index.rst b/doc/services/portability/posix/aep/index.rst new file mode 100644 index 000000000000000..857635c103116e4 --- /dev/null +++ b/doc/services/portability/posix/aep/index.rst @@ -0,0 +1,191 @@ +.. _posix_aep: + +POSIX Application Environment Profiles (AEP) +############################################ + +Although inactive, `IEEE 1003.13-2003`_ defined a number of AEP that inspired the modern +subprofiling options of `IEEE 1003.1-2017`_. The single-purpose realtime system profiles +are listed below, for reference, in terms that agree with the current POSIX-1 standard. PSE54 +is not considered at this time. + +.. _posix_aep_pse51: + +Minimal Realtime System Profile (PSE51) +======================================= + +.. Conforming implementations shall define _POSIX_AEP_REALTIME_MINIMAL to the value 200312L + +.. csv-table:: PSE51 System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_AEP_REALTIME_MINIMAL, -1, + +.. csv-table:: PSE51 Option Groups + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + POSIX_C_LANG_JUMP,, + POSIX_C_LANG_SUPPORT, yes, :ref:`†` + POSIX_DEVICE_IO,, :ref:`†` + POSIX_FILE_LOCKING,, + POSIX_SIGNALS,, :ref:`†` + POSIX_SINGLE_PROCESS,, :ref:`†` + POSIX_THREADS_BASE, yes, :ref:`†` + XSI_THREADS_EXT, yes, :ref:`†` + +.. csv-table:: PSE51 Option Requirements + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_CLOCK_SELECTION, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_FSYNC, -1, + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_REALTIME_SIGNALS, -1, + _POSIX_SEMAPHORES, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SYNCHRONIZED_IO, -1, + _POSIX_THREAD_ATTR_STACKADDR, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_ATTR_STACKSIZE, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + +.. note:: + For PSE51 support, 44 of 75 symbols are currently implemented. + +.. _posix_aep_pse52: + +Realtime Controller System Profile (PSE52) +========================================== + +.. Conforming implementations shall define _POSIX_AEP_REALTIME_CONTROLLER to the value 200312L + +.. csv-table:: PSE52 System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_AEP_REALTIME_CONTROLLER, -1, + +.. csv-table:: PSE52 Option Groups + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + POSIX_C_LANG_JUMP,, + POSIX_C_LANG_MATH, yes, + POSIX_C_LANG_SUPPORT, yes, :ref:`†` + POSIX_DEVICE_IO,, :ref:`†` + POSIX_FD_MGMT,, + POSIX_FILE_LOCKING,, + POSIX_FILE_SYSTEM,, + POSIX_SIGNALS,, :ref:`†` + POSIX_SINGLE_PROCESS,, :ref:`†` + POSIX_THREADS_BASE, yes, :ref:`†` + XSI_THREADS_EXT, yes, :ref:`†` + +.. csv-table:: PSE52 Option Requirements + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_CLOCK_SELECTION, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_FSYNC, -1, + _POSIX_MAPPED_FILES, -1, + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + _POSIX_MESSAGE_PASSING, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_REALTIME_SIGNALS, -1, + _POSIX_SEMAPHORES, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SYNCHRONIZED_IO, -1, + _POSIX_THREAD_ATTR_STACKADDR, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_ATTR_STACKSIZE, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_TRACE, -1, + _POSIX_TRACE_EVENT_FILTER, -1, + _POSIX_TRACE_LOG, -1, + +.. _posix_aep_pse53: + +Dedicated Realtime System Profile (PSE53) +========================================= + +.. Conforming implementations shall define _POSIX_AEP_REALTIME_MINIMAL to the value 200312L + +.. csv-table:: PSE53 System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_AEP_REALTIME_CONTROLLER, -1, + +.. csv-table:: PSE53 Option Groups + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + POSIX_C_LANG_JUMP,, + POSIX_C_LANG_MATH, yes, + POSIX_C_LANG_SUPPORT, yes, :ref:`†` + POSIX_DEVICE_IO,, :ref:`†` + POSIX_FD_MGMT,, + POSIX_FILE_LOCKING,, + POSIX_FILE_SYSTEM,, + POSIX_MULTI_PROCESS,, :ref:`†` + POSIX_NETWORKING, yes, :ref:`†` + POSIX_PIPE,, :ref:`†` + POSIX_SIGNALS,, :ref:`†` + POSIX_SIGNAL_JUMP,, :ref:`†` + POSIX_SINGLE_PROCESS,, :ref:`†` + POSIX_THREADS_BASE, yes, :ref:`†` + XSI_THREADS_EXT, yes, :ref:`†` + +.. csv-table:: PSE53 Option Requirements + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_ASYNCHRONOUS_IO, -1, + _POSIX_CLOCK_SELECTION, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_CPUTIME, -1, + _POSIX_FSYNC, -1, + _POSIX_MAPPED_FILES, -1, + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + _POSIX_MEMORY_PROTECTION, -1, + _POSIX_MESSAGE_PASSING, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_PRIORITIZED_IO, -1, + _POSIX_PRIORITY_SCHEDULING, -1, + _POSIX_RAW_SOCKETS, 200809L, :kconfig:option:`CONFIG_NET_SOCKETS` + _POSIX_REALTIME_SIGNALS, -1, + _POSIX_SEMAPHORES, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SPAWN, -1, + _POSIX_SPORADIC_SERVER, -1, + _POSIX_SYNCHRONIZED_IO, -1, + _POSIX_THREAD_ATTR_STACKADDR, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_ATTR_STACKSIZE, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, + _POSIX_THREAD_PROCESS_SHARED, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_TRACE, -1, + _POSIX_TRACE_EVENT_FILTER, -1, + _POSIX_TRACE_LOG, -1, + +.. _IEEE 1003.1-2017: https://standards.ieee.org/ieee/1003.1/7101/ +.. _IEEE 1003.13-2003: https://standards.ieee.org/ieee/1003.13/3322/ diff --git a/doc/services/portability/posix/conformance/index.rst b/doc/services/portability/posix/conformance/index.rst new file mode 100644 index 000000000000000..7d28efcf9acf150 --- /dev/null +++ b/doc/services/portability/posix/conformance/index.rst @@ -0,0 +1,145 @@ +.. _posix_conformance: + +POSIX Conformance +################# + +As per `IEEE 1003.1-2017`, this section details Zephyr's POSIX conformance. + +.. _posix_undefined_behaviour: + +.. note:: + As per POSIX 1003.13, single process mode is supported directly by both PSE51 and PSE52 + profiles. While Zephyr includes support for many features found in PSE53, PSE53 itself requires + supporting multiple processes. Since supporting multiple processes is beyond the scope of + Zephyr's current design, some features requiring multi-process capabilities may exhibit + undefined behaviour, which we denote with the † (obelus) symbol. + +.. _posix_system_interfaces: + +POSIX System Interfaces +======================= + +.. The following have values greater than -1 in Zephyr, conformant with the POSIX specification. + +.. csv-table:: POSIX System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_CHOWN_RESTRICTED, 0, + _POSIX_NO_TRUNC, 0, + _POSIX_VDISABLE, 0, + +.. The following should be valued greater than zero in Zephyr, in order to be strictly conformant + with the POSIX specification. + +.. csv-table:: POSIX System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_JOB_CONTROL, -1, :ref:`†` + _POSIX_REGEXP, -1, :ref:`†` + _POSIX_SAVED_IDS, -1, :ref:`†` + _POSIX_SHELL, -1, :ref:`†` + +.. TODO: POSIX_ASYNCHRONOUS_IO, and other interfaces below, are mandatory. That means that a + strictly conforming application need not be modified in order to compile against Zephyr. + However, we may add implementations that simply fail with ENOSYS as long as the functional + modification is clearly documented. The implementation is not required for PSE51 or PSE52 + and beyond that POSIX async I/O functions are rarely used in practice. + +.. csv-table:: POSIX System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_VERSION, 200809L, + _POSIX_ASYNCHRONOUS_IO, -1, :ref:`†` + :ref:`_POSIX_BARRIERS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_BARRIER` + :ref:`_POSIX_CLOCK_SELECTION`, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_MAPPED_FILES, -1, :ref:`†` + _POSIX_MEMORY_PROTECTION, -1, :ref:`†` + :ref:`_POSIX_READER_WRITER_LOCKS`, -1, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_REALTIME_SIGNALS, -1, :ref:`†` + :ref:`_POSIX_SEMAPHORES`, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + :ref:`_POSIX_SPIN_LOCKS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_SPINLOCK` + _POSIX_THREAD_SAFE_FUNCTIONS, 200809L, + :ref:`_POSIX_THREADS`, -1, :kconfig:option:`CONFIG_PTHREAD_IPC` + :ref:`_POSIX_TIMEOUTS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + :ref:`_POSIX_TIMERS`, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX2_C_BIND, 200809L, + +.. csv-table:: POSIX System Interfaces (Optional) + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_ADVISORY_INFO, -1, + _POSIX_CPUTIME, -1, + _POSIX_FSYNC, -1, + _POSIX_IPV6, 200809L, :kconfig:option:`CONFIG_NET_IPV6` + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + :ref:`_POSIX_MESSAGE_PASSING`, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_PRIORITIZED_IO, -1, + :ref:`_POSIX_PRIORITY_SCHEDULING`, -1, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_RAW_SOCKETS, 200809L, :kconfig:option:`CONFIG_NET_SOCKETS` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SPAWN, -1, + _POSIX_SPORADIC_SERVER, -1, + _POSIX_SYNCHRONIZED_IO, -1, + :ref:`_POSIX_THREAD_ATTR_STACKADDR`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + :ref:`_POSIX_THREAD_ATTR_STACKSIZE`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + :ref:`_POSIX_THREAD_PRIORITY_SCHEDULING`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_PROCESS_SHARED, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TRACE, -1, + _POSIX_TRACE_EVENT_FILTER, -1, + _POSIX_TRACE_INHERIT, -1, + _POSIX_TRACE_LOG, -1, + _POSIX_TYPED_MEMORY_OBJECTS, -1, + _XOPEN_CRYPT, -1, + _XOPEN_REALTIME, -1, + _XOPEN_REALTIME_THREADS, -1, + :ref:`_XOPEN_STREAMS`, -1, :kconfig:option:`CONFIG_NET_SOCKETS` + _XOPEN_UNIX, -1, + +POSIX Shell and Utilities +========================= + +Zephyr does not support a POSIX shell or utilities at this time. + +.. csv-table:: POSIX Shell and Utilities + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX2_C_DEV, -1, :ref:`†` + _POSIX2_CHAR_TERM, -1, :ref:`†` + _POSIX2_FORT_DEV, -1, :ref:`†` + _POSIX2_FORT_RUN, -1, :ref:`†` + _POSIX2_LOCALEDEF, -1, :ref:`†` + _POSIX2_PBS, -1, :ref:`†` + _POSIX2_PBS_ACCOUNTING, -1, :ref:`†` + _POSIX2_PBS_LOCATE, -1, :ref:`†` + _POSIX2_PBS_MESSAGE, -1, :ref:`†` + _POSIX2_PBS_TRACK, -1, :ref:`†` + _POSIX2_SW_DEV, -1, :ref:`†` + _POSIX2_UPE, -1, :ref:`†` + _POSIX2_UNIX, -1, :ref:`†` + _POSIX2_UUCP, -1, :ref:`†` + +XSI Conformance +############### + +XSI System Interfaces +===================== + +.. csv-table:: XSI System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_FSYNC, -1, :ref:`†` + :ref:`_POSIX_THREAD_ATTR_STACKADDR`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + :ref:`_POSIX_THREAD_ATTR_STACKSIZE`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_PROCESS_SHARED, -1, diff --git a/doc/services/portability/posix/implementation/index.rst b/doc/services/portability/posix/implementation/index.rst new file mode 100644 index 000000000000000..011317fef34a1c7 --- /dev/null +++ b/doc/services/portability/posix/implementation/index.rst @@ -0,0 +1,77 @@ +.. _posix_details: + +Implementation Details +###################### + +In many ways, Zephyr provides support like any POSIX OS; API bindings are provided in the C +programming language, POSIX headers are available in the standard include path, when configured. + +Unlike other multi-purpose POSIX operating systems + +- Zephyr is not "a POSIX OS". The Zephyr kernel was not designed around the POSIX standard, and + POSIX support is an opt-in feature +- Zephyr apps are not linked separately, nor do they execute as subprocesses +- Zephyr, libraries, and application code are compiled and linked together, running similarly to + a single-process application, in a single (possibly virtual) address space +- Zephyr does not provide a POSIX shell, compiler, utilities, and is not self-hosting. + +.. note:: + Unlike the Linux kernel or FreeBSD, Zephyr does not maintain a static table of system call + numbers for each supported architecture, but instead generates system calls dynamically at + build time. See `System Calls `_ for more information. + +Design +====== + +As a library, Zephyr's POSIX API implementation makes an effort to be a thin abstraction layer +between the application, middleware, and the Zephyr kernel. + +Some general design considerations: + +- The POSIX interface and implementations should be part of Zephyr's POSIX library, and not + elsewhere, unless required both by the POSIX API implementation and some other feature. An + example where the implementation should remain part of the POSIX implementation is + ``getopt()``. Examples where the implementation should be part of separate libraries are + multithreading and networking. + +- When the POSIX API and another Zephyr subsystem both rely on a feature, the implementation of + that feature should be as a separate Zephyr library that can be used by both the POSIX API and + the other library or subsystem. This reduces the likelihood of dependency cycles in code. When + practical, that rule should expand to include macros. In the example below, ``libposix`` + depends on ``libzfoo`` for the implementation of some functionality "foo" in Zephyr. If + ``libzfoo`` also depends on ``libposix``, then there is a dependency cycle. The cycle can be + removed via mutual dependency, ``libcommon``. + +.. graphviz:: + :caption: Dependency cycle between POSIX and another Zephyr library + + digraph { + node [shape=rect, style=rounded]; + rankdir=LR; + + libposix [fillcolor="#d5e8d4"]; + libzfoo [fillcolor="#dae8fc"]; + + libposix -> libzfoo; + libzfoo -> libposix; + } + +.. graphviz:: + :caption: Mutual dependencies between POSIX and other Zephyr libraries + + digraph { + node [shape=rect, style=rounded]; + rankdir=LR; + + libposix [fillcolor="#d5e8d4"]; + libzfoo [fillcolor="#dae8fc"]; + libcommon [fillcolor="#f8cecc"]; + + libposix -> libzfoo; + libposix -> libcommon; + libzfoo -> libcommon; + } + +- POSIX API calls should be provided as regular callable C functions; if a Zephyr + `System Call `_ is needed as part of the implementation, the declaration and the + implementation of that system call should be hidden behind the POSIX API. diff --git a/doc/services/portability/posix/index.rst b/doc/services/portability/posix/index.rst new file mode 100644 index 000000000000000..5fc5117df4419f7 --- /dev/null +++ b/doc/services/portability/posix/index.rst @@ -0,0 +1,14 @@ +.. _posix_support: + +POSIX +##### + +.. toctree:: + :maxdepth: 2 + + overview/index.rst + conformance/index.rst + aep/index.rst + implementation/index.rst + option_groups/index.rst + kconfig/index.rst diff --git a/doc/services/portability/posix/kconfig/index.rst b/doc/services/portability/posix/kconfig/index.rst new file mode 100644 index 000000000000000..c1599dd55063c0c --- /dev/null +++ b/doc/services/portability/posix/kconfig/index.rst @@ -0,0 +1,52 @@ +.. _posix_kconfig_options: + +Configuration Options +********************* + +This is a non-exhaustive list of specific :ref:`kconfig` options relating to Zephyr's +implementation of the POSIX API. + +* :kconfig:option:`CONFIG_APP_LINK_WITH_POSIX_SUBSYS` +* :kconfig:option:`CONFIG_EVENTFD` +* :kconfig:option:`CONFIG_EVENTFD_MAX` +* :kconfig:option:`CONFIG_FDTABLE` +* :kconfig:option:`CONFIG_FNMATCH` +* :kconfig:option:`CONFIG_GETOPT` +* :kconfig:option:`CONFIG_GETOPT_LONG` +* :kconfig:option:`CONFIG_MAX_PTHREAD_BARRIER_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_KEY_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_MUTEX_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_SPINLOCK_COUNT` +* :kconfig:option:`CONFIG_MAX_TIMER_COUNT` +* :kconfig:option:`CONFIG_MQUEUE_NAMELEN_MAX` +* :kconfig:option:`CONFIG_MSG_COUNT_MAX` +* :kconfig:option:`CONFIG_MSG_SIZE_MAX` +* :kconfig:option:`CONFIG_NET_SOCKETPAIR` +* :kconfig:option:`CONFIG_NET_SOCKETS` +* :kconfig:option:`CONFIG_NET_SOCKETS_POLL_MAX` +* :kconfig:option:`CONFIG_NET_SOCKETS_POSIX_NAMES` +* :kconfig:option:`CONFIG_POSIX_API` +* :kconfig:option:`CONFIG_POSIX_CLOCK` +* :kconfig:option:`CONFIG_POSIX_FS` +* :kconfig:option:`CONFIG_POSIX_LIMITS_RTSIG_MAX` +* :kconfig:option:`CONFIG_POSIX_MAX_FDS` +* :kconfig:option:`CONFIG_POSIX_MAX_OPEN_FILES` +* :kconfig:option:`CONFIG_POSIX_MQUEUE` +* :kconfig:option:`CONFIG_POSIX_RTSIG_MAX` +* :kconfig:option:`CONFIG_POSIX_SIGNAL` +* :kconfig:option:`CONFIG_POSIX_SIGNAL_STRING_DESC` +* :kconfig:option:`CONFIG_POSIX_UNAME` +* :kconfig:option:`CONFIG_POSIX_UNAME_NODENAME_LEN` +* :kconfig:option:`CONFIG_POSIX_UNAME_VERSION_LEN` +* :kconfig:option:`CONFIG_PTHREAD` +* :kconfig:option:`CONFIG_PTHREAD_BARRIER` +* :kconfig:option:`CONFIG_PTHREAD_COND` +* :kconfig:option:`CONFIG_PTHREAD_CREATE_BARRIER` +* :kconfig:option:`CONFIG_PTHREAD_IPC` +* :kconfig:option:`CONFIG_PTHREAD_KEY` +* :kconfig:option:`CONFIG_PTHREAD_MUTEX` +* :kconfig:option:`CONFIG_PTHREAD_RECYCLER_DELAY_MS` +* :kconfig:option:`CONFIG_PTHREAD_SPINLOCK` +* :kconfig:option:`CONFIG_SEM_VALUE_MAX` +* :kconfig:option:`CONFIG_TIMER` diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix/option_groups/index.rst similarity index 57% rename from doc/services/portability/posix.rst rename to doc/services/portability/posix/option_groups/index.rst index 392147594c83ad0..0381b1848200c45 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -1,131 +1,18 @@ -.. _posix_support: +.. _posix_option_groups: -POSIX Support -############# +Subprofiling Option Groups +########################## -The Portable Operating System Interface (POSIX) is a family of standards -specified by the IEEE Computer Society for maintaining compatibility between -operating systems. Zephyr implements a subset of the embedded profiles PSE51 -and PSE52, and BSD Sockets API. - -With the POSIX support available in Zephyr, an existing POSIX compliant -application can be ported to run on the Zephyr kernel, and therefore leverage -Zephyr features and functionality. Additionally, a library designed for use with -POSIX threading compatible operating systems can be ported to Zephyr kernel -based applications with minimal or no changes. - -.. figure:: posix.svg - :align: center - :alt: POSIX Support in Zephyr - - POSIX support in Zephyr - -The POSIX API subset is an increasingly popular OSAL (operating system -abstraction layer) for IoT and embedded applications, as can be seen in -Zephyr, AWS:FreeRTOS, TI-RTOS, and NuttX. - -Benefits of POSIX support in Zephyr include: - -- Offering a familiar API to non-embedded programmers, especially from Linux -- Enabling reuse (portability) of existing libraries based on POSIX APIs -- Providing an efficient API subset appropriate for small (MCU) embedded systems - - -System Overview -=============== - -Units of Functionality -++++++++++++++++++++++ - -The system profile is defined in terms of component profiles that specify Units -of Functionality that can be combined to realize the application platform. A Unit -of Functionality is a defined set of services which can be implemented. If -implemented, the standard prescribes that all services in the Unit must -be implemented. - -A Minimal Realtime System Profile implementation must support the -following Units of Functionality as defined in IEEE Std. 1003.1 (also referred to -as POSIX.1-2017). - - -.. csv-table:: Units of Functionality - :header: Requirements, Supported, Remarks - :widths: 50,10,60 - - - POSIX_C_LANG_JUMP, - POSIX_C_LANG_SUPPORT,yes - POSIX_DEVICE_IO, - POSIX_FILE_LOCKING, - POSIX_SIGNALS, - POSIX_SINGLE_PROCESS, - POSIX_SPIN_LOCKS,yes - POSIX_THREADS_BASE,yes - XSI_THREAD_MUTEX_EXT,yes - XSI_THREADS_EXT,yes - - -Option Requirements -++++++++++++++++++++ - -An implementation supporting the Minimal Realtime System -Profile must support the POSIX.1 Option Requirements which are defined in the -standard. Options Requirements are used for further sub-profiling within the -units of functionality: they further define the functional behavior of the -system service (normally adding extra functionality). Depending on the profile -to which the POSIX implementation complies,parameters and/or the precise -functionality of certain services may differ. - -The following list shows the option requirements that are implemented in -Zephyr. - - -.. csv-table:: Option Requirements - :header: Requirements, Supported - :widths: 50,10 - - _POSIX_BARRIERS,yes - _POSIX_CLOCK_SELECTION,yes - _POSIX_FSYNC, - _POSIX_MEMLOCK, - _POSIX_MEMLOCK_RANGE, - _POSIX_MONOTONIC_CLOCK,yes - _POSIX_NO_TRUNC, - _POSIX_REALTIME_SIGNALS, - _POSIX_SEMAPHORES,yes - _POSIX_SHARED_MEMORY_OBJECTS, - _POSIX_SPIN_LOCKS,yes - _POSIX_SYNCHRONIZED_IO, - _POSIX_THREAD_ATTR_STACKADDR,yes - _POSIX_THREAD_ATTR_STACKSIZE,yes - _POSIX_THREAD_CPUTIME, - _POSIX_THREAD_PRIO_INHERIT, - _POSIX_THREAD_PRIO_PROTECT, - _POSIX_THREAD_PRIORITY_SCHEDULING,yes - _POSIX_THREAD_SPORADIC_SERVER, - _POSIX_TIMEOUTS, - _POSIX_TIMERS,yes - _POSIX2_C_DEV, - _POSIX2_SW_DEV, - - - -Units of Functionality -====================== - -This section describes the Units of Functionality (fixed sets of interfaces) -which are implemented (partially or completely) in Zephyr. Please refer to the -standard for a full description of each listed interface. +.. _posix_option_group_threads_base: POSIX_THREADS_BASE -+++++++++++++++++++ +================== The basic assumption in this profile is that the system consists of a single (implicit) process with multiple threads. Therefore, the standard requires all basic thread services, except those related to multiple processes. - .. csv-table:: POSIX_THREADS_BASE :header: API, Supported :widths: 50,10 @@ -179,12 +66,12 @@ multiple processes. pthread_sigmask(), pthread_testcancel(), - +.. _posix_option_group_xsi_thread_ext: XSI_THREAD_EXT -++++++++++++++ +============== -The XSI_THREADS_EXT Unit of Functionality is required because it provides +The XSI_THREADS_EXT option group is required because it provides functions to control a thread's stack. This is considered useful for any real-time application. @@ -201,33 +88,14 @@ This table lists service support status in Zephyr: pthread_getconcurrency(), pthread_setconcurrency() - -XSI_THREAD_MUTEX_EXT -++++++++++++++++++++ - -The XSI_THREAD_MUTEX_EXT Unit of Functionality is required because it has -options for controlling the behavior of mutexes under erroneous application use. - - -This table lists service support status in Zephyr: - -.. csv-table:: XSI_THREAD_MUTEX_EXT - :header: API, Supported - :widths: 50,10 - - pthread_mutexattr_gettype(),yes - pthread_mutexattr_settype(),yes - +.. _posix_option_group_c_lang_support: POSIX_C_LANG_SUPPORT -++++++++++++++++++++ +==================== -The POSIX_C_LANG_SUPPORT Unit of Functionality contains the general ISO C +The POSIX_C_LANG_SUPPORT option group contains the general ISO C Library. -This is implemented as part of the minimal C library available in Zephyr. - - .. csv-table:: POSIX_C_LANG_SUPPORT :header: API, Supported :widths: 50,10 @@ -338,11 +206,12 @@ This is implemented as part of the minimal C library available in Zephyr. vsprintf(),yes vsscanf(), +.. _posix_option_group_single_process: POSIX_SINGLE_PROCESS -+++++++++++++++++++++ +==================== -The POSIX_SINGLE_PROCESS Unit of Functionality contains services for single +The POSIX_SINGLE_PROCESS option group contains services for single process applications. .. csv-table:: POSIX_SINGLE_PROCESS @@ -358,9 +227,10 @@ process applications. uname(),yes unsetenv() +.. _posix_option_group_signals: POSIX_SIGNALS -+++++++++++++ +============= Signal services are a basic mechanism within POSIX-based systems and are required for error and event handling. @@ -369,7 +239,6 @@ required for error and event handling. :header: API, Supported :widths: 50,10 - abort(),yes alarm(), kill(), @@ -388,32 +257,20 @@ required for error and event handling. sigwait(), strsignal(),yes -.. csv-table:: POSIX_SPIN_LOCKS - :header: API, Supported - :widths: 50,10 - - pthread_spin_destroy(),yes - pthread_spin_init(),yes - pthread_spin_lock(),yes - pthread_spin_trylock(),yes - pthread_spin_unlock(),yes - +.. _posix_option_group_device_io: POSIX_DEVICE_IO -+++++++++++++++ +=============== .. csv-table:: POSIX_DEVICE_IO :header: API, Supported :widths: 50,10 - flockfile(), - ftrylockfile(), - funlockfile(), - getc_unlocked(), - getchar_unlocked(),yes - putc_unlocked(), - putchar_unlocked() - clearerr(), + FD_CLR(),yes + FD_ISSET(),yes + FD_SET(),yes + FD_ZERO(),yes + clearerr(),yes close(),yes fclose(), fdopen(), @@ -436,17 +293,22 @@ POSIX_DEVICE_IO gets(), open(),yes perror(),yes + poll(),yes printf(),yes + pread(), + pselect(), putc(),yes putchar(),yes puts(),yes + pwrite(), read(),yes scanf(), + select(),yes setbuf(), setvbuf(), - stderr,yes - stdin,yes - stdout,yes + stderr, + stdin, + stdout, ungetc(), vfprintf(),yes vfscanf(), @@ -454,8 +316,72 @@ POSIX_DEVICE_IO vscanf(), write(),yes +.. _posix_option_group_barriers: + +POSIX_BARRIERS +============== + +.. csv-table:: POSIX_BARRIERS + :header: API, Supported + :widths: 50,10 + + pthread_barrier_destroy(),yes + pthread_barrier_init(),yes + pthread_barrier_wait(),yes + pthread_barrierattr_destroy(),yes + pthread_barrierattr_init(),yes + +.. _posix_option_group_clock_selection: + +POSIX_CLOCK_SELECTION +===================== + +.. csv-table:: POSIX_CLOCK_SELECTION + :header: API, Supported + :widths: 50,10 + + pthread_condattr_getclock(),yes + pthread_condattr_setclock(),yes + clock_nanosleep(),yes + +.. _posix_option_group_semaphores: + +POSIX_SEMAPHORES +================ + +.. csv-table:: POSIX_SEMAPHORES + :header: API, Supported + :widths: 50,10 + + sem_close(), + sem_destroy(),yes + sem_getvalue(),yes + sem_init(),yes + sem_open(), + sem_post(),yes + sem_trywait(),yes + sem_unlink(), + sem_wait(),yes + +.. _posix_option_group_spin_locks: + +POSIX_SPIN_LOCKS +================ + +.. csv-table:: POSIX_SPIN_LOCKS + :header: API, Supported + :widths: 50,10 + + pthread_spin_destroy(),yes + pthread_spin_init(),yes + pthread_spin_lock(),yes + pthread_spin_trylock(),yes + pthread_spin_unlock(),yes + +.. _posix_option_group_timers: + POSIX_TIMERS -++++++++++++ +============ .. csv-table:: POSIX_TIMERS :header: API, Supported @@ -471,13 +397,143 @@ POSIX_TIMERS timer_getoverrun(),yes timer_settime(),yes -POSIX_CLOCK_SELECTION -+++++++++++++++++++++ -.. csv-table:: POSIX_CLOCK_SELECTION +.. _posix_options: + +Additional POSIX Options +======================== + +.. _posix_option_message_passing: + +_POSIX_MESSAGE_PASSING +++++++++++++++++++++++ + +.. csv-table:: _POSIX_MESSAGE_PASSING :header: API, Supported :widths: 50,10 - pthread_condattr_getclock(),yes - pthread_condattr_setclock(),yes - clock_nanosleep(),yes + mq_close(),yes + mq_getattr(),yes + mq_notify(), + mq_open(),yes + mq_receive(),yes + mq_send(),yes + mq_setattr(),yes + mq_unlink(),yes + +_POSIX_PRIORITY_SCHEDULING +++++++++++++++++++++++++++ + +.. _posix_option_priority_scheduling: + +.. csv-table:: _POSIX_PRIORITY_SCHEDULING + :header: API, Supported + :widths: 50,10 + + sched_get_priority_max(),yes + sched_get_priority_min(),yes + sched_getparam(), + sched_getscheduler(), + sched_rr_get_interval(), + sched_setparam(), + sched_setscheduler(), + sched_yield(),yes + +.. _posix_option_reader_writer_locks: + +_POSIX_READER_WRITER_LOCKS +++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_READER_WRITER_LOCKS + :header: API, Supported + :widths: 50,10 + + pthread_rwlock_destroy(),yes + pthread_rwlock_init(),yes + pthread_rwlock_rdlock(),yes + pthread_rwlock_tryrdlock(),yes + pthread_rwlock_trywrlock(),yes + pthread_rwlock_unlock(),yes + pthread_rwlock_wrlock(),yes + pthread_rwlockattr_destroy(),yes + pthread_rwlockattr_getpshared(), + pthread_rwlockattr_init(),yes + pthread_rwlockattr_setpshared(), + +.. _posix_option_thread_attr_stackaddr: + +_POSIX_THREAD_ATTR_STACKADDR +++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_ATTR_STACKADDR + :header: API, Supported + :widths: 50,10 + + pthread_attr_getstackaddr(),yes + pthread_attr_setstackaddr(),yes + +.. _posix_option_thread_attr_stacksize: + +_POSIX_THREAD_ATTR_STACKSIZE +++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_ATTR_STACKSIZE + :header: API, Supported + :widths: 50,10 + + pthread_attr_getstacksize(),yes + pthread_attr_setstacksize(),yes + +.. _posix_option_thread_priority_scheduling: + +_POSIX_THREAD_PRIORITY_SCHEDULING ++++++++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_PRIORITY_SCHEDULING + :header: API, Supported + :widths: 50,10 + + pthread_attr_getinheritsched(), + pthread_attr_getschedpolicy(),yes + pthread_attr_getscope(), + pthread_attr_setinheritsched(), + pthread_attr_setschedpolicy(),yes + pthread_attr_setscope(), + pthread_getschedparam(),yes + pthread_setschedparam(),yes + pthread_setschedprio(),yes + +.. _posix_option_timeouts: + +_POSIX_TIMEOUTS ++++++++++++++++ + +.. csv-table:: _POSIX_TIMEOUTS + :header: API, Supported + :widths: 50,10 + + mq_timedreceive(), + mq_timedsend(), + pthread_mutex_timedlock(),yes + pthread_rwlock_timedrdlock(),yes + pthread_rwlock_timedwrlock(),yes + sem_timedwait(),yes + posix_trace_timedgetnext_event(), + +.. _posix_option_xopen_streams: + +_XOPEN_STREAMS +++++++++++++++ + +.. csv-table:: _XOPEN_STREAMS + :header: API, Supported + :widths: 50,10 + + fattach(), + fdetach(), + getmsg(), + getpmsg(), + ioctl(),yes + isastream(), + putmsg(), + putpmsg(), diff --git a/doc/services/portability/posix/overview/index.rst b/doc/services/portability/posix/overview/index.rst new file mode 100644 index 000000000000000..56810e49ac1419b --- /dev/null +++ b/doc/services/portability/posix/overview/index.rst @@ -0,0 +1,135 @@ +.. _posix_overview: + +Overview +######## + +The Portable Operating System Interface (POSIX) is a family of standards specified by the +`IEEE Computer Society`_ for maintaining compatibility between operating systems. Zephyr +implements a subset of the standard POSIX API specified by `IEEE 1003.1-2017`_ (also known as +POSIX-1.2017). + +.. figure:: posix.svg + :align: center + :alt: POSIX Support in Zephyr + + POSIX support in Zephyr + +.. note:: + This page does not document Zephyr's :ref:`POSIX architecture`, which is used to + run Zephyr as a native application under the host operating system for prototyping, + test, and diagnostic purposes. + +With the POSIX support available in Zephyr, an existing POSIX conformant +application can be ported to run on the Zephyr kernel, and therefore leverage +Zephyr features and functionality. Additionally, a library designed to be +POSIX conformant can be ported to Zephyr kernel based applications with no changes. + +The POSIX API is an increasingly popular OSAL (operating system abstraction layer) for IoT and +embedded applications, as can be seen in Zephyr, AWS:FreeRTOS, TI-RTOS, and NuttX. + +Benefits of POSIX support in Zephyr include: + +- Offering a familiar API to non-embedded programmers, especially from Linux +- Enabling reuse (portability) of existing libraries based on POSIX APIs +- Providing an efficient API subset appropriate for small (MCU) embedded systems + +.. _posix_subprofiles: + +POSIX Subprofiles +================= + +While Zephyr supports running multiple `threads `_ (possibly in an `SMP `_ +configuration), as well as `Virtual Memory and MMUs `_, Zephyr code and data +normally share a common address space. The Zephyr kernel executable code and the application +executable code are typically compiled into the same binary artifact. From that perspective, Zephyr +apps can be seen as running in the context of a single process. + +While multi-purpose operating systems (OS) offer full POSIX conformance, Real-Time Operating +Systems (RTOS) such as Zephyr typically serve a fixed-purpose, have limited hardware resources, +and experience limited user interaction. In such systems, full POSIX conformance can be +impractical and unnecessary. + +For that reason, POSIX defined the following :ref:`Application Environment Profiles (AEP)` +as part of `IEEE 1003.13-2003`_ (also known as POSIX.13-2003). + +* Minimal Realtime System Profile (:ref:`PSE51 `) +* Realtime Controller System Profile (:ref:`PSE52 `) +* Dedicated Realtime System Profile (:ref:`PSE53 `) +* Multi-Purpose Realtime System (PSE54) + +POSIX.13-2003 AEP were formalized in 2003 via "Units of Functionality" but the specification is now +inactive (for reference only). Nevertheless, the intent is still captured as part of POSIX-1.2017 +via :ref:`Options` and :ref:`Option Groups`, in Appendix E. + +.. _posix_apps: + +POSIX Applications in Zephyr +============================ + +A POSIX app in Zephyr is :ref:`built like any other app` and therefore requires the +usual :file:`prj.conf`, :file:`CMakeLists.txt`, and source code. For example, the app below +leverages the ``nanosleep()`` and ``perror()`` POSIX functions. + +.. code-block:: cfg + :caption: `prj.conf` for a simple POSIX app in Zephyr + + CONFIG_POSIX_API=y + +.. code-block:: c + :caption: A simple app that uses Zephyr's POSIX API + + #include + #include + #include + + void megasleep(size_t megaseconds) + { + struct timespec ts = { + .tv_sec = megaseconds * 1000000, + .tv_nsec = 0, + }; + + printf("See you in a while!\n"); + if (nanosleep(&ts, NULL) == -1) { + perror("nanosleep"); + } + } + + int main() + { + megasleep(42); + return 0; + } + +.. + TODO: insert a link to a list of all samples tagged with 'posix' + +.. _posix_config: + +Configuration +============= + +Like most features in Zephyr, POSIX features are +:ref:`highly configurable` but disabled by default. Users must +explicitly choose to enable POSIX options via :ref:`Kconfig` selection. Indeed, there are +:ref:`many Kconfig options in Zephyr` for the POSIX API to allow for +feature selection at various levels of granularity. + +Alternatively, users may enable one of the Kconfig options below as a shortcut to enable multiple +:ref:`Option Groups`. + +* :kconfig:option:`CONFIG_POSIX_API` +* :kconfig:option:`CONFIG_PTHREAD_IPC` + +.. note:: + Since the POSIX environment in Zephyr is fully configurable via :ref:`Kconfig`, + configurations that require modifying features should not be made if strict compliance is + required (POSIX-1.2017, section 2.1.3.1). + +.. + TODO: create Kconfig shortcuts for PSE51, PSE52, and PSE53 + +.. _IEEE: https://www.ieee.org/ +.. _IEEE Computer Society: https://www.computer.org/ +.. _IEEE 1003.1-2017: https://standards.ieee.org/ieee/1003.1/7101/ +.. _IEEE 1003.13-2003: https://standards.ieee.org/ieee/1003.13/3322/ diff --git a/doc/services/portability/posix.svg b/doc/services/portability/posix/overview/posix.svg similarity index 68% rename from doc/services/portability/posix.svg rename to doc/services/portability/posix/overview/posix.svg index c21ecba2ae507a6..a62be70994ec2fd 100644 --- a/doc/services/portability/posix.svg +++ b/doc/services/portability/posix/overview/posix.svg @@ -1,2 +1,2 @@ -
Hardware
Hardware
BSP
BSP
Zephyr Kernel
Zephyr Kernel
POSIX PSE51
POSIX PSE51
File System
File System
POSIX PSE52
<div>POSIX PSE52</div>
Networking
Networking
BSD Sockets
<div>BSD Sockets<br></div>
 Middleware
 Middleware
Application
Application
\ No newline at end of file +
Hardware
Hardware
BSP
BSP
Zephyr Kernel
Zephyr Kernel
POSIX PSE51
POSIX PSE51
File System
File System
POSIX PSE52
POSIX PSE52
Networking
Networking
POSIX PSE53
POSIX PSE53
 Middleware
 Middleware
Application
Application
\ No newline at end of file From a0c307c0a56cc89bfa51e631da58119911c03797 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 21:29:00 -0500 Subject: [PATCH 0915/1049] posix: pthread: implement pthread_atfork() pthread_atfork() is required by the POSIX_THREADS_BASE Option Group as detailed in Section E.1 of IEEE-1003.1-2017. The POSIX_THREADS_BASE Option Group is required for PSE51, PSE52, PSE53, and PSE54 conformance, and is otherwise mandatory for any POSIX conforming system as per Section A.2.1.3 of IEEE-1003-1.2017. Since Zephyr does not yet support processes and (by extension) fork(), this implementation includes a deviation and should be categorized as producing undefined behaviour. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 1 + lib/posix/pthread.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index d978e914a5e7fdc..2f942f6553cb2a8 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -473,6 +473,7 @@ int pthread_key_create(pthread_key_t *key, int pthread_key_delete(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); void *pthread_getspecific(pthread_key_t key); +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); /* Glibc / Oracle Extension Functions */ diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index f2bbc07ae9a4634..c5c00a53491b7a3 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -954,6 +954,15 @@ int pthread_getname_np(pthread_t thread, char *name, size_t len) #endif } +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) +{ + ARG_UNUSED(prepare); + ARG_UNUSED(parent); + ARG_UNUSED(child); + + return ENOSYS; +} + static int posix_thread_pool_init(void) { size_t i; From 1d501a76afc5e24806309390a8a53c6c5814ec96 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 21:49:37 -0500 Subject: [PATCH 0916/1049] doc: services: portability: posix: pthread_atfork() supported Mark pthread_atfork() as supported in the documentation. This option is a mandatory requirement (i.e. it must be present) even when calling it produces undefined behaviour. That is the case here, and documentation sbould be updated to reflect that. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 0381b1848200c45..e151788586de4ad 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -17,7 +17,7 @@ multiple processes. :header: API, Supported :widths: 50,10 - pthread_atfork(), + pthread_atfork(),yes pthread_attr_destroy(),yes pthread_attr_getdetachstate(),yes pthread_attr_getschedparam(),yes From 41b7c17ac4bd0198fc9bb3a0e55aa8d5e2fae96e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 21:53:07 -0500 Subject: [PATCH 0917/1049] tests: posix: pthread: check that pthread_atfork() exists Add a simple existence check that pthread_atfork() has some kind of implementation. The function is mandatory by all conforming POSIX systems. Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index d535a134693b9b1..b249c337c18c207 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -60,7 +60,7 @@ ZTEST(posix_headers, test_pthread_h) /* pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; */ /* not implemented */ if (IS_ENABLED(CONFIG_POSIX_API)) { - /* zassert_not_null(pthread_atfork); */ /* not implemented */ + zassert_not_null(pthread_atfork); zassert_not_null(pthread_attr_destroy); zassert_not_null(pthread_attr_getdetachstate); /* zassert_not_null(pthread_attr_getguardsize); */ /* not implemented */ From d2bd778bcce2b4cc12b1c286b2a3c3584b540a89 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 7 Nov 2023 10:46:26 +0100 Subject: [PATCH 0918/1049] kconfig: mcuboot: Add MCUBOOT_IMGTOOL_OVERWRITE_ONLY option Add MCUBOOT_IMGTOOL_OVERWRITE_ONLY Kconfig option which passes the --overwrite-only option to imgtool to avoid adding the swap status area size when calculating overflow. It is used by non-swap update modes. Signed-off-by: Andrej Butok --- cmake/mcuboot.cmake | 5 +++++ modules/Kconfig.mcuboot | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake index 3b29069ca354242..2347ae3108c4304 100644 --- a/cmake/mcuboot.cmake +++ b/cmake/mcuboot.cmake @@ -96,6 +96,11 @@ function(zephyr_mcuboot_tasks) set(imgtool_extra --key "${keyfile}" ${imgtool_extra}) endif() + # Use overwrite-only instead of swap upgrades. + if(CONFIG_MCUBOOT_IMGTOOL_OVERWRITE_ONLY) + set(imgtool_extra --overwrite-only ${imgtool_extra}) + endif() + set(imgtool_args -- ${imgtool_extra}) # Extensionless prefix of any output file. diff --git a/modules/Kconfig.mcuboot b/modules/Kconfig.mcuboot index 8df4bde8829c5b7..7f41167d3d38872 100644 --- a/modules/Kconfig.mcuboot +++ b/modules/Kconfig.mcuboot @@ -110,6 +110,12 @@ config MCUBOOT_IMGTOOL_SIGN_VERSION argument to the tool. The format is major.minor.revision+build. +config MCUBOOT_IMGTOOL_OVERWRITE_ONLY + bool "Use overwrite-only instead of swap upgrades" + help + If enabled, --overwrite-only option passed to imgtool to avoid + adding the swap status area size when calculating overflow. + config MCUBOOT_EXTRA_IMGTOOL_ARGS string "Extra arguments to pass to imgtool when signing" default "" @@ -148,6 +154,7 @@ choice MCUBOOT_BOOTLOADER_MODE config MCUBOOT_BOOTLOADER_MODE_SINGLE_APP bool "MCUboot has been configured for single slot execution" + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot will only boot slot0_partition placed application and does not care about other slots. In this mode application is not able @@ -178,6 +185,7 @@ config MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH config MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY bool "MCUboot has been configured to just overwrite primary slot" select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot will take contents of secondary slot of an image and will overwrite primary slot with it. @@ -191,6 +199,7 @@ config MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP bool "MCUboot has been configured for DirectXIP operation" select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE select MCUBOOT_BOOTLOADER_NO_DOWNGRADE + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot expects slot0_partition and slot1_partition to exist in DT. In this mode MCUboot can boot from either partition and will @@ -206,6 +215,7 @@ config MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT select MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE select MCUBOOT_BOOTLOADER_NO_DOWNGRADE + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot expects slot0_partition and slot1_partition to exist in DT. In this mode MCUboot will boot the application with the higher version From 061a87aff8650ba55bc698dbe7f00a08a4abb6e5 Mon Sep 17 00:00:00 2001 From: Siddharth Chandrasekaran Date: Sat, 15 Jul 2023 03:32:29 +0200 Subject: [PATCH 0919/1049] mgmt/osdp: Replace __ASSERT() with an explicit if Commit c7fec71193a ("mgmt/osdp: Add length checks for commands and replies") attempted to remove code duplication by adding a macro to perform a length check. At the time, a CI linter did not like macros with control flow so the code was switched to a method which called __ASSERT() on this condition. The __ASSERT() macro is a nop if CONFIG_ASSERT=n (which is the default) and causes the buffer access to be unguarded which may lead to OOB accesses. This patch fixes the issue by reintroducing the if check. Fixes: c7fec71193a19f6be1a2adca8cf7753cd7103c78. Signed-off-by: Siddharth Chandrasekaran --- subsys/mgmt/osdp/src/osdp_cp.c | 73 +++++++++++++++++++++++++--------- subsys/mgmt/osdp/src/osdp_pd.c | 61 ++++++++++++++++++++-------- 2 files changed, 99 insertions(+), 35 deletions(-) diff --git a/subsys/mgmt/osdp/src/osdp_cp.c b/subsys/mgmt/osdp/src/osdp_cp.c index 86a1e9d20e35f27..e9c5d19d2eb963b 100644 --- a/subsys/mgmt/osdp/src/osdp_cp.c +++ b/subsys/mgmt/osdp/src/osdp_cp.c @@ -114,10 +114,13 @@ int osdp_extract_address(int *address) return (pd_offset == CONFIG_OSDP_NUM_CONNECTED_PD) ? 0 : -1; } -static inline void assert_buf_len(int need, int have) +static inline bool check_buf_len(int need, int have) { - __ASSERT(need < have, "OOM at build command: need:%d have:%d", - need, have); + if (need >= have) { + LOG_ERR("OOM at build command: need:%d have:%d", need, have); + return false; + } + return true; } static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) @@ -137,42 +140,60 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) switch (pd->cmd_id) { case CMD_POLL: - assert_buf_len(CMD_POLL_LEN, max_len); + if (!check_buf_len(CMD_POLL_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_LSTAT: - assert_buf_len(CMD_LSTAT_LEN, max_len); + if (!check_buf_len(CMD_LSTAT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_ISTAT: - assert_buf_len(CMD_ISTAT_LEN, max_len); + if (!check_buf_len(CMD_ISTAT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_OSTAT: - assert_buf_len(CMD_OSTAT_LEN, max_len); + if (!check_buf_len(CMD_OSTAT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_RSTAT: - assert_buf_len(CMD_RSTAT_LEN, max_len); + if (!check_buf_len(CMD_RSTAT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; break; case CMD_ID: - assert_buf_len(CMD_ID_LEN, max_len); + if (!check_buf_len(CMD_ID_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; buf[len++] = 0x00; break; case CMD_CAP: - assert_buf_len(CMD_CAP_LEN, max_len); + if (!check_buf_len(CMD_CAP_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; buf[len++] = 0x00; break; case CMD_DIAG: - assert_buf_len(CMD_DIAG_LEN, max_len); + if (!check_buf_len(CMD_DIAG_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; buf[len++] = 0x00; break; case CMD_OUT: - assert_buf_len(CMD_OUT_LEN, max_len); + if (!check_buf_len(CMD_OUT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; buf[len++] = pd->cmd_id; buf[len++] = cmd->output.output_no; @@ -181,7 +202,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) buf[len++] = BYTE_1(cmd->output.timer_count); break; case CMD_LED: - assert_buf_len(CMD_LED_LEN, max_len); + if (!check_buf_len(CMD_LED_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; buf[len++] = pd->cmd_id; buf[len++] = cmd->led.reader; @@ -202,7 +225,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) buf[len++] = cmd->led.permanent.off_color; break; case CMD_BUZ: - assert_buf_len(CMD_BUZ_LEN, max_len); + if (!check_buf_len(CMD_BUZ_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; buf[len++] = pd->cmd_id; buf[len++] = cmd->buzzer.reader; @@ -213,7 +238,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) break; case CMD_TEXT: cmd = (struct osdp_cmd *)pd->ephemeral_data; - assert_buf_len(CMD_TEXT_LEN + cmd->text.length, max_len); + if (!check_buf_len(CMD_TEXT_LEN + cmd->text.length, max_len)) { + return OSDP_CP_ERR_GENERIC; + } buf[len++] = pd->cmd_id; buf[len++] = cmd->text.reader; buf[len++] = cmd->text.control_code; @@ -225,7 +252,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) len += cmd->text.length; break; case CMD_COMSET: - assert_buf_len(CMD_COMSET_LEN, max_len); + if (!check_buf_len(CMD_COMSET_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; buf[len++] = pd->cmd_id; buf[len++] = cmd->comset.address; @@ -240,7 +269,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) LOG_ERR("Cannot perform KEYSET without SC!"); return OSDP_CP_ERR_GENERIC; } - assert_buf_len(CMD_KEYSET_LEN, max_len); + if (!check_buf_len(CMD_KEYSET_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } cmd = (struct osdp_cmd *)pd->ephemeral_data; if (cmd->keyset.length != 16) { LOG_ERR("Invalid key length"); @@ -260,7 +291,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) len += 16; break; case CMD_CHLNG: - assert_buf_len(CMD_CHLNG_LEN, max_len); + if (!check_buf_len(CMD_CHLNG_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } if (smb == NULL) { LOG_ERR("Invalid secure message block!"); return -1; @@ -273,7 +306,9 @@ static int cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) len += 8; break; case CMD_SCRYPT: - assert_buf_len(CMD_SCRYPT_LEN, max_len); + if (!check_buf_len(CMD_SCRYPT_LEN, max_len)) { + return OSDP_CP_ERR_GENERIC; + } if (smb == NULL) { LOG_ERR("Invalid secure message block!"); return -1; diff --git a/subsys/mgmt/osdp/src/osdp_pd.c b/subsys/mgmt/osdp/src/osdp_pd.c index ceb17c2d1a9a3dd..9f3e7d42892ddfc 100644 --- a/subsys/mgmt/osdp/src/osdp_pd.c +++ b/subsys/mgmt/osdp/src/osdp_pd.c @@ -556,10 +556,13 @@ static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len) return ret; } -static inline void assert_buf_len(int need, int have) +static inline bool check_buf_len(int need, int have) { - __ASSERT(need < have, "OOM at build command: need:%d have:%d", - need, have); + if (need >= have) { + LOG_ERR("OOM at build reply: need:%d have:%d", need, have); + return false; + } + return true; } /** @@ -582,12 +585,16 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) switch (pd->reply_id) { case REPLY_ACK: - assert_buf_len(REPLY_ACK_LEN, max_len); + if (!check_buf_len(REPLY_ACK_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; ret = OSDP_PD_ERR_NONE; break; case REPLY_PDID: - assert_buf_len(REPLY_PDID_LEN, max_len); + if (!check_buf_len(REPLY_PDID_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = BYTE_0(pd->id.vendor_code); @@ -608,7 +615,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) ret = OSDP_PD_ERR_NONE; break; case REPLY_PDCAP: - assert_buf_len(REPLY_PDCAP_LEN, max_len); + if (!check_buf_len(REPLY_PDCAP_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; for (i = 1; i < OSDP_PD_CAP_SENTINEL; i++) { if (pd->cap[i].function_code != i) { @@ -626,21 +635,27 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) ret = OSDP_PD_ERR_NONE; break; case REPLY_LSTATR: - assert_buf_len(REPLY_LSTATR_LEN, max_len); + if (!check_buf_len(REPLY_LSTATR_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = ISSET_FLAG(pd, PD_FLAG_TAMPER); buf[len++] = ISSET_FLAG(pd, PD_FLAG_POWER); ret = OSDP_PD_ERR_NONE; break; case REPLY_RSTATR: - assert_buf_len(REPLY_RSTATR_LEN, max_len); + if (!check_buf_len(REPLY_RSTATR_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = ISSET_FLAG(pd, PD_FLAG_R_TAMPER); ret = OSDP_PD_ERR_NONE; break; case REPLY_KEYPPAD: event = (struct osdp_event *)pd->ephemeral_data; - assert_buf_len(REPLY_KEYPAD_LEN + event->keypress.length, max_len); + if (!check_buf_len(REPLY_KEYPAD_LEN + event->keypress.length, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = (uint8_t)event->keypress.reader_no; buf[len++] = (uint8_t)event->keypress.length; @@ -653,7 +668,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) event = (struct osdp_event *)pd->ephemeral_data; len_bytes = (event->cardread.length + 7) / 8; - assert_buf_len(REPLY_RAW_LEN + len_bytes, max_len); + if (!check_buf_len(REPLY_RAW_LEN + len_bytes, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = (uint8_t)event->cardread.reader_no; buf[len++] = (uint8_t)event->cardread.format; @@ -666,7 +683,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) } case REPLY_FMT: event = (struct osdp_event *)pd->ephemeral_data; - assert_buf_len(REPLY_FMT_LEN + event->cardread.length, max_len); + if (!check_buf_len(REPLY_FMT_LEN + event->cardread.length, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = (uint8_t)event->cardread.reader_no; buf[len++] = (uint8_t)event->cardread.direction; @@ -676,7 +695,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) ret = OSDP_PD_ERR_NONE; break; case REPLY_COM: - assert_buf_len(REPLY_COM_LEN, max_len); + if (!check_buf_len(REPLY_COM_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } /** * If COMSET succeeds, the PD must reply with the old params and * then switch to the new params from then then on. We have the @@ -702,7 +723,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) ret = OSDP_PD_ERR_NONE; break; case REPLY_NAK: - assert_buf_len(REPLY_NAK_LEN, max_len); + if (!check_buf_len(REPLY_NAK_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[len++] = pd->reply_id; buf[len++] = pd->ephemeral_data[0]; ret = OSDP_PD_ERR_NONE; @@ -712,7 +735,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) if (smb == NULL) { break; } - assert_buf_len(REPLY_CCRYPT_LEN, max_len); + if (!check_buf_len(REPLY_CCRYPT_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } osdp_fill_random(pd->sc.pd_random, 8); osdp_compute_session_keys(pd); osdp_compute_pd_cryptogram(pd); @@ -730,7 +755,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) if (smb == NULL) { break; } - assert_buf_len(REPLY_RMAC_I_LEN, max_len); + if (!check_buf_len(REPLY_RMAC_I_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } osdp_compute_rmac_i(pd); buf[len++] = pd->reply_id; memcpy(buf + len, pd->sc.r_mac, 16); @@ -766,7 +793,9 @@ static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) /* catch all errors and report it as a RECORD error to CP */ LOG_ERR("Failed to build REPLY(%02x); Sending NAK instead!", pd->reply_id); - assert_buf_len(REPLY_NAK_LEN, max_len); + if (!check_buf_len(REPLY_NAK_LEN, max_len)) { + return OSDP_PD_ERR_GENERIC; + } buf[0] = REPLY_NAK; buf[1] = OSDP_PD_NAK_RECORD; len = 2; From 5b24a8ad72c5dc37f14a4469be8683b057ed6f62 Mon Sep 17 00:00:00 2001 From: Siddharth Chandrasekaran Date: Tue, 24 Oct 2023 22:15:09 +0200 Subject: [PATCH 0920/1049] mgmt/osdp: Fix off-by-one in buf len checks Initially, the command/reply ID byte was not part of the data length macros. But later, when it was changed to include it, the buffer length checks was not adjusted. Due to this, we were not using the last byte in the buffer. Fix this issue by correcting the condition. Signed-off-by: Siddharth Chandrasekaran --- subsys/mgmt/osdp/src/osdp_cp.c | 2 +- subsys/mgmt/osdp/src/osdp_pd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/mgmt/osdp/src/osdp_cp.c b/subsys/mgmt/osdp/src/osdp_cp.c index e9c5d19d2eb963b..cf475c5c4cb8792 100644 --- a/subsys/mgmt/osdp/src/osdp_cp.c +++ b/subsys/mgmt/osdp/src/osdp_cp.c @@ -116,7 +116,7 @@ int osdp_extract_address(int *address) static inline bool check_buf_len(int need, int have) { - if (need >= have) { + if (need > have) { LOG_ERR("OOM at build command: need:%d have:%d", need, have); return false; } diff --git a/subsys/mgmt/osdp/src/osdp_pd.c b/subsys/mgmt/osdp/src/osdp_pd.c index 9f3e7d42892ddfc..bbaa24a5f0ec97c 100644 --- a/subsys/mgmt/osdp/src/osdp_pd.c +++ b/subsys/mgmt/osdp/src/osdp_pd.c @@ -558,7 +558,7 @@ static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len) static inline bool check_buf_len(int need, int have) { - if (need >= have) { + if (need > have) { LOG_ERR("OOM at build reply: need:%d have:%d", need, have); return false; } From 2750e1e3b58a17b631bf84e6b55703e8a2b24c6a Mon Sep 17 00:00:00 2001 From: Hein Wessels Date: Sat, 18 Nov 2023 07:47:05 +0100 Subject: [PATCH 0921/1049] drivers: dma: stm32: add utilities to access properties by idx Some drivers like the ADC access the DMA through it's index and not the DMA name. This commit add some better support for such instances. Signed-off-by: Hein Wessels --- include/zephyr/drivers/dma/dma_stm32.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/zephyr/drivers/dma/dma_stm32.h b/include/zephyr/drivers/dma/dma_stm32.h index 3ccfeb9be10550f..c4c593457cb516d 100644 --- a/include/zephyr/drivers/dma/dma_stm32.h +++ b/include/zephyr/drivers/dma/dma_stm32.h @@ -33,8 +33,10 @@ /* macro for dma slot (only for dma-v1 or dma-v2 types) */ #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_dma_v2bis) #define STM32_DMA_SLOT(id, dir, slot) 0 +#define STM32_DMA_SLOT_BY_IDX(id, idx, slot) #else #define STM32_DMA_SLOT(id, dir, slot) DT_INST_DMAS_CELL_BY_NAME(id, dir, slot) +#define STM32_DMA_SLOT_BY_IDX(id, idx, slot) DT_INST_DMAS_CELL_BY_IDX(id, idx, slot) #endif #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_dma_v2) || \ @@ -50,6 +52,8 @@ DT_INST_DMAS_CTLR_BY_NAME(id, dir) #define STM32_DMA_CHANNEL_CONFIG(id, dir) \ DT_INST_DMAS_CELL_BY_NAME(id, dir, channel_config) +#define STM32_DMA_CHANNEL_CONFIG_BY_IDX(id, idx) \ + DT_INST_DMAS_CELL_BY_IDX(id, idx, channel_config) /* macros for channel-config */ /* direction defined on bits 6-7 */ From f27e45473ae2c096d4b6bd03427723ec6fa8894f Mon Sep 17 00:00:00 2001 From: Hein Wessels Date: Sat, 18 Nov 2023 08:15:44 +0100 Subject: [PATCH 0922/1049] drivers: adc: stm32: driver now agnostic of actual dma name Previously the STM32 DMA driver was dependent on a very specific name for the DMA in the DTS. This hidden requirement has caused a bit of confusion. This commit changes the driver to instead always use the first DMA listed in the ADC node's dma property. Should fix: #65387 Signed-off-by: Hein Wessels --- drivers/adc/adc_stm32.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 12a38c415fda868..fd5dd686d46a58d 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -1521,39 +1521,39 @@ static void adc_stm32_irq_init(void) #define ADC_STM32_IRQ_CONFIG(index) #define ADC_STM32_IRQ_FUNC(index) \ .irq_cfg_func = adc_stm32_irq_init, -#define ADC_DMA_CHANNEL(id, dir, DIR, src, dest) +#define ADC_DMA_CHANNEL(id, src, dest) #elif defined(CONFIG_ADC_STM32_DMA) /* !CONFIG_ADC_STM32_SHARED_IRQS */ -#define ADC_DMA_CHANNEL_INIT(index, name, dir_cap, src_dev, dest_dev) \ +#define ADC_DMA_CHANNEL_INIT(index, src_dev, dest_dev) \ .dma = { \ - .dma_dev = DEVICE_DT_GET(STM32_DMA_CTLR(index, name)), \ - .channel = DT_INST_DMAS_CELL_BY_NAME(index, name, channel), \ + .dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_IDX(index, 0)), \ + .channel = STM32_DMA_SLOT_BY_IDX(index, 0, channel), \ .dma_cfg = { \ - .dma_slot = STM32_DMA_SLOT(index, name, slot), \ + .dma_slot = STM32_DMA_SLOT_BY_IDX(index, 0, slot), \ .channel_direction = STM32_DMA_CONFIG_DIRECTION( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .source_data_size = STM32_DMA_CONFIG_##src_dev##_DATA_SIZE( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .dest_data_size = STM32_DMA_CONFIG_##dest_dev##_DATA_SIZE( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .source_burst_length = 1, /* SINGLE transfer */ \ .dest_burst_length = 1, /* SINGLE transfer */ \ .channel_priority = STM32_DMA_CONFIG_PRIORITY( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .dma_callback = dma_callback, \ .block_count = 2, \ }, \ .src_addr_increment = STM32_DMA_CONFIG_##src_dev##_ADDR_INC( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .dst_addr_increment = STM32_DMA_CONFIG_##dest_dev##_ADDR_INC( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ } -#define ADC_DMA_CHANNEL(id, dir, DIR, src, dest) \ - COND_CODE_1(DT_INST_DMAS_HAS_NAME(id, dir), \ - (ADC_DMA_CHANNEL_INIT(id, dir, DIR, src, dest)), \ - (EMPTY)) +#define ADC_DMA_CHANNEL(id, src, dest) \ + COND_CODE_1(DT_INST_DMAS_HAS_IDX(id, 0), \ + (ADC_DMA_CHANNEL_INIT(id, src, dest)), \ + (/* Required for other adc instances without dma */)) #define ADC_STM32_IRQ_CONFIG(index) \ static void adc_stm32_cfg_func_##index(void){ EMPTY } @@ -1572,7 +1572,7 @@ static void adc_stm32_cfg_func_##index(void) \ } #define ADC_STM32_IRQ_FUNC(index) \ .irq_cfg_func = adc_stm32_cfg_func_##index, -#define ADC_DMA_CHANNEL(id, dir, DIR, src, dest) +#define ADC_DMA_CHANNEL(id, src, dest) #endif /* CONFIG_ADC_STM32_DMA && CONFIG_ADC_STM32_SHARED_IRQS */ @@ -1605,7 +1605,7 @@ static struct adc_stm32_data adc_stm32_data_##index = { \ ADC_CONTEXT_INIT_TIMER(adc_stm32_data_##index, ctx), \ ADC_CONTEXT_INIT_LOCK(adc_stm32_data_##index, ctx), \ ADC_CONTEXT_INIT_SYNC(adc_stm32_data_##index, ctx), \ - ADC_DMA_CHANNEL(index, dmamux, NULL, PERIPHERAL, MEMORY) \ + ADC_DMA_CHANNEL(index, PERIPHERAL, MEMORY) \ }; \ \ PM_DEVICE_DT_INST_DEFINE(index, adc_stm32_pm_action); \ From a257bcb73589779985b2c3632d7236c42c159b58 Mon Sep 17 00:00:00 2001 From: Hein Wessels Date: Mon, 20 Nov 2023 14:24:04 +0100 Subject: [PATCH 0923/1049] drivers: adc: stm32: add dma support for other mcus This commit adds support for more STM32 CPUs that has a different DMA interface. This was tested only for the nucleo_l476rg. Signed-off-by: Hein Wessels --- drivers/adc/adc_stm32.c | 49 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index fd5dd686d46a58d..767308a396b255a 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -216,6 +216,39 @@ static bool init_irq = true; #endif #ifdef CONFIG_ADC_STM32_DMA +static void adc_stm32_enable_dma_support(ADC_TypeDef *adc) +{ + /* Allow ADC to create DMA request and set to one-shot mode as implemented in HAL drivers */ + +#if defined(CONFIG_SOC_SERIES_STM32H7X) + +#if defined(ADC_VER_V5_V90) + if (adc == ADC3) { + LL_ADC_REG_SetDMATransferMode(adc, + ADC3_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); + LL_ADC_EnableDMAReq(adc); + } else { + LL_ADC_REG_SetDataTransferMode(adc, + ADC_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); + } +#elif defined(ADC_VER_V5_X) + LL_ADC_REG_SetDataTransferMode(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED); +#else +#error "Unsupported ADC version" +#endif + +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) /* defined(CONFIG_SOC_SERIES_STM32H7X) */ + +#error "The STM32F1 ADC + DMA is not yet supported" + +#else /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ + + /* Default mechanism for other MCUs */ + LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED); + +#endif +} + static int adc_stm32_dma_start(const struct device *dev, void *buffer, size_t channel_count) { @@ -257,21 +290,7 @@ static int adc_stm32_dma_start(const struct device *dev, return ret; } - /* Allow ADC to create DMA request and set to one-shot mode, - * as implemented in HAL drivers, if applicable. - */ -#if defined(ADC_VER_V5_V90) - if (adc == ADC3) { - LL_ADC_REG_SetDMATransferMode(adc, - ADC3_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); - LL_ADC_EnableDMAReq(adc); - } else { - LL_ADC_REG_SetDataTransferMode(adc, - ADC_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); - } -#elif defined(ADC_VER_V5_X) - LL_ADC_REG_SetDataTransferMode(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED); -#endif + adc_stm32_enable_dma_support(adc); data->dma_error = 0; ret = dma_start(data->dma.dma_dev, data->dma.channel); From 82a6a69b818df6830e1d1bfa0fe82f5a89e65011 Mon Sep 17 00:00:00 2001 From: Hein Wessels Date: Mon, 20 Nov 2023 14:36:04 +0100 Subject: [PATCH 0924/1049] tests: drivers: adc_dma: add test for nucleo_l476rg Add test to verify the ADC + DMA functionality works for the STM32L476 MCU. Signed-off-by: Hein Wessels --- .../adc/adc_dma/boards/nucleo_l476rg.conf | 8 ++++++++ .../adc/adc_dma/boards/nucleo_l476rg.overlay | 17 +++++++++++++++++ tests/drivers/adc/adc_dma/src/test_adc.c | 11 +++++++++++ 3 files changed, 36 insertions(+) create mode 100644 tests/drivers/adc/adc_dma/boards/nucleo_l476rg.conf create mode 100644 tests/drivers/adc/adc_dma/boards/nucleo_l476rg.overlay diff --git a/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.conf b/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.conf new file mode 100644 index 000000000000000..e3fe93c1c0c6e29 --- /dev/null +++ b/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2023 Hein Wessels, Nobleo Technology +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_ADC_STM32_DMA=y +CONFIG_ADC_ASYNC=y diff --git a/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.overlay b/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.overlay new file mode 100644 index 000000000000000..990a83f351b41cf --- /dev/null +++ b/tests/drivers/adc/adc_dma/boards/nucleo_l476rg.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Hein Wessels, Nobleo Technology + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&adc1 { + dmas = < &dma1 1 0 (STM32_DMA_PERIPH_RX | STM32_DMA_MEM_16BITS | STM32_DMA_PERIPH_16BITS) >; + dma-names = "dma"; + + #address-cells = <1>; + #size-cells = <0>; +}; + +test_dma: &dma1 { + status = "okay"; +}; diff --git a/tests/drivers/adc/adc_dma/src/test_adc.c b/tests/drivers/adc/adc_dma/src/test_adc.c index c9a1ac4b0dc91dc..f80ee54dd7e8bec 100644 --- a/tests/drivers/adc/adc_dma/src/test_adc.c +++ b/tests/drivers/adc/adc_dma/src/test_adc.c @@ -61,6 +61,17 @@ #define ADC_2ND_CHANNEL_ID 7 #define ALIGNMENT 32 +#elif defined(CONFIG_BOARD_NUCLEO_L476RG) + +#define ADC_DEVICE_NODE DT_INST(0, st_stm32_adc) +#define ADC_RESOLUTION 12 +#define ADC_GAIN ADC_GAIN_1 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 1 +#define ADC_2ND_CHANNEL_ID 7 +#define ALIGNMENT 32 + #endif /* Invalid value that is not supposed to be written by the driver. It is used From c0eb91803771ad0a0df30af5e1152c5da31ac865 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Wed, 22 Nov 2023 14:07:15 +0100 Subject: [PATCH 0925/1049] posix: sys: fix missing include to _timeval.h in native_sim zephyr/net/socket_types.h file also includes _timeval.h, but it uses correct path/filename depending on configuration. Signed-off-by: Kamil Rakoczy --- include/zephyr/posix/sys/select.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/posix/sys/select.h b/include/zephyr/posix/sys/select.h index 0fd2b5de9e691d2..4420b69eabae193 100644 --- a/include/zephyr/posix/sys/select.h +++ b/include/zephyr/posix/sys/select.h @@ -6,8 +6,8 @@ #ifndef ZEPHYR_INCLUDE_POSIX_SYS_SELECT_H_ #define ZEPHYR_INCLUDE_POSIX_SYS_SELECT_H_ +#include #include -#include #ifdef __cplusplus extern "C" { From 58175fcf1829a9350ce936b9e02dd2e20279961e Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Wed, 22 Nov 2023 13:30:36 +0100 Subject: [PATCH 0926/1049] boards: nrf9131ek and nrf9161dk: update readme to emphasize nr-plus This patch changes readme files of nRF91x1 dev kits to highlight their added NR+ feature. Signed-off-by: Maximilian Deubel --- boards/arm/nrf9131ek_nrf9131/doc/index.rst | 3 ++- boards/arm/nrf9161dk_nrf9161/doc/index.rst | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/boards/arm/nrf9131ek_nrf9131/doc/index.rst b/boards/arm/nrf9131ek_nrf9131/doc/index.rst index a72cd1526e354ae..57473c631ed5413 100644 --- a/boards/arm/nrf9131ek_nrf9131/doc/index.rst +++ b/boards/arm/nrf9131ek_nrf9131/doc/index.rst @@ -6,7 +6,8 @@ nRF9131 EK Overview ******** -The nRF9131 EK (PCA10165) is a single-board evaluation kit for the nRF9131 SiP for LTE-M and NB-IoT. +The nRF9131 EK (PCA10165) is a single-board evaluation kit for the nRF9131 SiP +for DECT NR+ and LTE-M/NB-IoT with GNSS. The nrf9131ek_nrf9131 board configuration provides support for the Nordic Semiconductor nRF9131 ARM Cortex-M33F CPU with ARMv8-M Security Extension and the following devices: diff --git a/boards/arm/nrf9161dk_nrf9161/doc/index.rst b/boards/arm/nrf9161dk_nrf9161/doc/index.rst index 559288b06aabd0b..18b214a7fde9188 100644 --- a/boards/arm/nrf9161dk_nrf9161/doc/index.rst +++ b/boards/arm/nrf9161dk_nrf9161/doc/index.rst @@ -7,7 +7,7 @@ Overview ******** The nRF9161 DK (PCA10153) is a single-board development kit for evaluation and -development on the nRF9161 SiP for LTE-M and NB-IoT. The nrf9161dk_nrf9161 +development on the nRF9161 SiP for DECT NR+ and LTE-M/NB-IoT with GNSS. The nrf9161dk_nrf9161 board configuration provides support for the Nordic Semiconductor nRF9161 ARM Cortex-M33F CPU with ARMv8-M Security Extension and the following devices: From 1ab669e3d08510da2b107d917da501f376e6a76d Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Tue, 21 Nov 2023 17:40:23 +0100 Subject: [PATCH 0927/1049] tfm: Remove SFN model FP limitation Despite what the TF-M documentation says about SFN model not supporting Floating Point, it does support it, according to TF-M developers. Remove SFN limitation not supported with FP Hard ABI. Signed-off-by: Joakim Andersson --- arch/arm/core/Kconfig | 2 -- modules/trusted-firmware-m/Kconfig.tfm | 1 - 2 files changed, 3 deletions(-) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index 75a64ea90ebaeb8..ac3fe19b9841720 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -276,8 +276,6 @@ config FP_HARDABI point instructions are generated and uses FPU-specific calling conventions. - Note: When building with TF-M enabled only the IPC mode is supported. - config FP_SOFTABI bool "Floating point Soft ABI" help diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index b635347b6e1afcb..d29b7093de01fea 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -324,7 +324,6 @@ config TFM_IPC config TFM_SFN bool "SFN model" - depends on !FP_HARDABI help Use the SFN Model as the SPM backend for the PSA API. The SFN model supports the SFN Partition model, and isolation level 1. From 2ad6dda9fdfc81ef2a83e44e25a85be01719d623 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Tue, 21 Nov 2023 19:02:47 +0100 Subject: [PATCH 0928/1049] tfm: Remove limitation of enabling FP when build TF-M NS application Remove limitation of enabling FP when building TF-M NS application. FP support have been fixed in the tf-m-tests repository for NS application. Board support for NS executable may still be lacking for some boards. Signed-off-by: Joakim Andersson --- arch/arm/core/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index ac3fe19b9841720..dd322bff626c5cc 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -268,9 +268,6 @@ choice config FP_HARDABI bool "Floating point Hard ABI" - # TF-M build system does not build the NS app and libraries correctly with Hard ABI. - # This limitation should be removed in the next TF-M synchronization. - depends on !TFM_BUILD_NS help This option selects the Floating point ABI in which hardware floating point instructions are generated and uses FPU-specific calling From b43271dc2d6f4bde312b96c675bead73a122dcbd Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 21 Nov 2023 10:08:03 -0800 Subject: [PATCH 0929/1049] doc: vuln: Disclose information about CVE-2023-5055 Information about CVE-2023-5055 Signed-off-by: Flavio Ceolin --- doc/security/vulnerabilities.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index 61d0d25f618486c..eb2e4e47229bd5a 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1506,7 +1506,16 @@ Under embargo until 2023/11/01 CVE-2023-5055 ------------- -Under embargo until 2023/11/01 +L2CAP: Possible Stack based buffer overflow in le_ecred_reconf_req() + +- `Zephyr project bug tracker GHSA-wr8r-7f8x-24jj + `_ + +This has been fixed in main for v3.5.0 + +- `PR 62381 fix for main + `_ + CVE-2023-5139 ------------- From 062fc2242acb39f21aae9ae4a5a8251b780d43f0 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 21 Nov 2023 12:56:12 -0800 Subject: [PATCH 0930/1049] sys: arch_interface: include arch/syscall.h if USERSPACE Due to arch_syscall_invoke are declared static, if there are no corresponding definition, compiler will complain. It has been working fine so far because arch/syscall.h is included indirectly through some other headers (especially through generated syscall stubs). However, with enough header files shuffling this becomes an issue. So include arch/syscall.h in arch_interface.h explicitly. Signed-off-by: Daniel Leung --- include/zephyr/sys/arch_interface.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/zephyr/sys/arch_interface.h b/include/zephyr/sys/arch_interface.h index e694bce55cca46c..1e5eaad87b10e22 100644 --- a/include/zephyr/sys/arch_interface.h +++ b/include/zephyr/sys/arch_interface.h @@ -517,6 +517,8 @@ static inline unsigned int arch_num_cpus(void); */ #ifdef CONFIG_USERSPACE +#include + /** * Invoke a system call with 0 arguments. * From 40ba4015e313863facc721f7f06210b03057197c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 21 Nov 2023 15:04:02 -0800 Subject: [PATCH 0931/1049] kernel: mm: only include demand_paging.h if needed This moves including of demand_paging.h out of kernel/mm.h, so that users of demand paging APIs must include the header explicitly. Since the main user is kernel itself, we can be more discipline about header inclusion. Signed-off-by: Daniel Leung --- arch/x86/core/userspace.c | 4 ++++ include/zephyr/kernel/mm.h | 1 - include/zephyr/kernel/thread.h | 2 +- kernel/mmu.c | 4 ++++ kernel/paging/statistics.c | 2 +- .../demand_paging/backing_store/backing_store_qemu_x86_tiny.c | 1 + subsys/demand_paging/backing_store/ram.c | 1 + subsys/demand_paging/eviction/nru.c | 2 ++ tests/kernel/fatal/exception/src/main.c | 4 ++++ tests/kernel/mem_protect/demand_paging/src/main.c | 1 + 10 files changed, 19 insertions(+), 3 deletions(-) diff --git a/arch/x86/core/userspace.c b/arch/x86/core/userspace.c index 2b058206232397c..9380c14d005b839 100644 --- a/arch/x86/core/userspace.c +++ b/arch/x86/core/userspace.c @@ -11,6 +11,10 @@ #include #include +#ifdef CONFIG_DEMAND_PAGING +#include +#endif + #ifndef CONFIG_X86_KPTI /* Update the to the incoming thread's page table, and update the location of * the privilege elevation stack. diff --git a/include/zephyr/kernel/mm.h b/include/zephyr/kernel/mm.h index 392dc4b7cdec21f..0f6c76e7cdcdeb8 100644 --- a/include/zephyr/kernel/mm.h +++ b/include/zephyr/kernel/mm.h @@ -14,7 +14,6 @@ #endif #include -#include /** * @brief Kernel Memory Management diff --git a/include/zephyr/kernel/thread.h b/include/zephyr/kernel/thread.h index b152dfb909aef30..91cf710e870c661 100644 --- a/include/zephyr/kernel/thread.h +++ b/include/zephyr/kernel/thread.h @@ -8,7 +8,7 @@ #define ZEPHYR_INCLUDE_KERNEL_THREAD_H_ #ifdef CONFIG_DEMAND_PAGING_THREAD_STATS -#include +#include #endif #include diff --git a/kernel/mmu.c b/kernel/mmu.c index 6abd9349dd6c788..a58bc77189bc68b 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -20,6 +20,10 @@ #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); +#ifdef CONFIG_DEMAND_PAGING +#include +#endif + /* * General terminology: * - A page frame is a page-sized physical memory region in RAM. It is a diff --git a/kernel/paging/statistics.c b/kernel/paging/statistics.c index e8972738135db68..06e867cd218b133 100644 --- a/kernel/paging/statistics.c +++ b/kernel/paging/statistics.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include extern struct k_mem_paging_stats_t paging_stats; diff --git a/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c b/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c index 023adc06fad7e23..9f100649d49d466 100644 --- a/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c +++ b/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c @@ -20,6 +20,7 @@ #include #include #include +#include void *location_to_flash(uintptr_t location) { diff --git a/subsys/demand_paging/backing_store/ram.c b/subsys/demand_paging/backing_store/ram.c index c8ba9378a0b78aa..a18995e1b7fd59e 100644 --- a/subsys/demand_paging/backing_store/ram.c +++ b/subsys/demand_paging/backing_store/ram.c @@ -8,6 +8,7 @@ #include #include #include +#include /* * TODO: diff --git a/subsys/demand_paging/eviction/nru.c b/subsys/demand_paging/eviction/nru.c index 108bc504c02cd27..83c4a3b53d76512 100644 --- a/subsys/demand_paging/eviction/nru.c +++ b/subsys/demand_paging/eviction/nru.c @@ -10,6 +10,8 @@ #include #include +#include + /* The accessed and dirty states of each page frame are used to create * a hierarchy with a numerical value. When evicting a page, try to evict * page with the highest value (we prefer clean, not accessed pages). diff --git a/tests/kernel/fatal/exception/src/main.c b/tests/kernel/fatal/exception/src/main.c index ea4ffaa7c34bbe5..07ac26ffc5567e6 100644 --- a/tests/kernel/fatal/exception/src/main.c +++ b/tests/kernel/fatal/exception/src/main.c @@ -18,6 +18,10 @@ #include "test_syscalls.h" #endif +#if defined(CONFIG_DEMAND_PAGING) +#include +#endif + #if defined(CONFIG_X86) && defined(CONFIG_X86_MMU) #define STACKSIZE (8192) #else diff --git a/tests/kernel/mem_protect/demand_paging/src/main.c b/tests/kernel/mem_protect/demand_paging/src/main.c index a453c06a573a0db..7b733bfc340abc1 100644 --- a/tests/kernel/mem_protect/demand_paging/src/main.c +++ b/tests/kernel/mem_protect/demand_paging/src/main.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include From 468890d70fa407b5013bf3bcb9911d0fcae4c7b8 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Wed, 15 Nov 2023 15:51:44 -0300 Subject: [PATCH 0932/1049] drivers: clock_control: clock_control_esp32 assert remotion No longer necessary assert removal Signed-off-by: Marcio Ribeiro --- drivers/clock_control/clock_control_esp32.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index fba7091b871a557..52fb330d4b4eb57 100644 --- a/drivers/clock_control/clock_control_esp32.c +++ b/drivers/clock_control/clock_control_esp32.c @@ -602,9 +602,3 @@ DEVICE_DT_DEFINE(DT_NODELABEL(rtc), PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_esp32_api); - -#ifndef CONFIG_SOC_SERIES_ESP32C3 -BUILD_ASSERT((CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) == - DT_PROP(DT_INST(0, DT_CPU_COMPAT), clock_frequency), - "SYS_CLOCK_HW_CYCLES_PER_SEC Value must be equal to CPU_Freq"); -#endif From e7c7c5a769025bb1363b81c2fb4e630949093ad4 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Tue, 21 Nov 2023 20:36:12 +0100 Subject: [PATCH 0933/1049] doc: zbus: add missing timeout arg for zbus_chan_add/rm_obs funcs zbus_chan_add_obs and zbus_chan_rm_obs functions require a timeout as their third arg. Signed-off-by: Bartosz Bilas --- doc/services/zbus/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/zbus/index.rst b/doc/services/zbus/index.rst index ca8ab6142a8f24f..59d45317a7b2c2c 100644 --- a/doc/services/zbus/index.rst +++ b/doc/services/zbus/index.rst @@ -763,9 +763,9 @@ following example illustrates the runtime registration usage. void thread_entry(void) { // ... /* Adding the observer to channel chan1 */ - zbus_chan_add_obs(&chan1, &my_listener); + zbus_chan_add_obs(&chan1, &my_listener, K_NO_WAIT); /* Removing the observer from channel chan1 */ - zbus_chan_rm_obs(&chan1, &my_listener); + zbus_chan_rm_obs(&chan1, &my_listener, K_NO_WAIT); Samples From 4a262c3947e745fff542a2d78dbedfe460cc2541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 21 Nov 2023 17:36:52 +0100 Subject: [PATCH 0934/1049] tests: drivers: flash: Update nrf52840dk_mx25r_high_perf.overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to commit 7a83724e0f18d7f2400517407150f9e9a1ecd6e6. This overlay uses an alternative connection (via spi2) for the external flash present on the nRF52840 DK and it needs to use one of the QSPI pins as GPIO, to get CS line control in the SPI communication. To make it possible, that GPIO must be removed from those marked as reserved. Signed-off-by: Andrzej Głąbek --- .../flash/common/boards/nrf52840dk_mx25r_high_perf.overlay | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay b/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay index eabb26ebda6ff8d..a67f25e46c08b06 100644 --- a/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay +++ b/tests/drivers/flash/common/boards/nrf52840dk_mx25r_high_perf.overlay @@ -1,5 +1,9 @@ /delete-node/ &qspi; +&gpio0 { + gpio-reserved-ranges = <0 2>, <6 1>, <8 3>, <18 6>; +}; + &spi2 { compatible = "nordic,nrf-spim"; status = "okay"; From c949018d36bd6a2b0453a52062adcc108060cce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 21 Nov 2023 17:43:35 +0100 Subject: [PATCH 0935/1049] tests: drivers: flash: Use fixtures for tests requiring external chips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several scenarios in this test require specific external flash chips to be connected to the nRF52840 DK. Specify proper fixture for them so that they are not performed on the board without those required external components connected. Signed-off-by: Andrzej Głąbek --- tests/drivers/flash/common/testcase.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index f7ee0b7fc6d0ddd..b0b0c9af91a45e6 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -21,7 +21,7 @@ tests: - OVERLAY_CONFIG=boards/nrf52840_flash_qspi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_mx25l51245g.overlay harness_config: - fixture: external_flash + fixture: external_flash_mx25l51245g integration_platforms: - nrf52840dk_nrf52840 drivers.flash.common.soc_flash_nrf: @@ -78,11 +78,15 @@ tests: extra_args: - OVERLAY_CONFIG=boards/nrf52840dk_flash_spi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_spi_nor.overlay + harness_config: + fixture: external_flash_mx25v1635f drivers.flash.common.spi_nor_wp_hold: platform_allow: nrf52840dk_nrf52840 extra_args: - OVERLAY_CONFIG=boards/nrf52840dk_flash_spi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_spi_nor_wp_hold.overlay + harness_config: + fixture: external_flash_mx25v1635f drivers.flash.common.sam0: platform_allow: - atsamd20_xpro From f442c03a20f4d17b8a05ad304a9776493c2e4ecc Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 21 Nov 2023 16:15:50 +0100 Subject: [PATCH 0936/1049] samples: subsys: nvs on nucleo_g431 requires 6kB for storage partitions Add the overlay for running the samples/subsys/nvs/ application on the nucleo_g31rb. Define a 6kB storage_partition at the end of the 128kB flash. Signed-off-by: Francois Ramu --- samples/subsys/nvs/boards/nucleo_g431rb.overlay | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 samples/subsys/nvs/boards/nucleo_g431rb.overlay diff --git a/samples/subsys/nvs/boards/nucleo_g431rb.overlay b/samples/subsys/nvs/boards/nucleo_g431rb.overlay new file mode 100644 index 000000000000000..ee0f1af77ac6df7 --- /dev/null +++ b/samples/subsys/nvs/boards/nucleo_g431rb.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; + +&flash0 { + partitions { + /* Set 6KB of storage at the end of 128KB flash */ + storage_partition: partition@1e800 { + label = "storage"; + reg = <0x0001e800 DT_SIZE_K(6)>; + }; + }; +}; From c143daf98dbdc88f2154f86c05c4256d01cb79f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 15:59:33 +0100 Subject: [PATCH 0937/1049] tests: logging: log_backend_uart: Disable backends other than UART MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test expects that there are no other backends enabled and some may be enabled by default. Signed-off-by: Krzysztof Chruściński --- tests/subsys/logging/log_backend_uart/prj.conf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/subsys/logging/log_backend_uart/prj.conf b/tests/subsys/logging/log_backend_uart/prj.conf index ef6894f355ea1e6..c8615a65adb4a59 100644 --- a/tests/subsys/logging/log_backend_uart/prj.conf +++ b/tests/subsys/logging/log_backend_uart/prj.conf @@ -9,3 +9,8 @@ CONFIG_LOG=y CONFIG_LOG_BACKEND_UART=y CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_LOG_PRINTK=n +# +# Disable all potential other default backends +CONFIG_LOG_BACKEND_NATIVE_POSIX=n +CONFIG_LOG_BACKEND_RTT=n +CONFIG_LOG_BACKEND_XTENSA_SIM=n From 84955951efba678bc024bc07caa362f92d13c6e2 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 21 Nov 2023 15:02:20 +0100 Subject: [PATCH 0938/1049] boards: lpcxpresso55Sxx: Make Jlink a default runner. Make Jlink a default runner for lpcxpresso55Sxx. The LinkServer runner command line tool does not support .hex flashing. This feature is planned for LinkServer v1.6 (July 2024). Signed-off-by: Andrej Butok --- boards/arm/lpcxpresso55s06/board.cmake | 2 +- boards/arm/lpcxpresso55s16/board.cmake | 2 +- boards/arm/lpcxpresso55s28/board.cmake | 4 +++- boards/arm/lpcxpresso55s36/board.cmake | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/boards/arm/lpcxpresso55s06/board.cmake b/boards/arm/lpcxpresso55s06/board.cmake index 305ed963f21c912..a6df50bba733395 100644 --- a/boards/arm/lpcxpresso55s06/board.cmake +++ b/boards/arm/lpcxpresso55s06/board.cmake @@ -8,5 +8,5 @@ board_runner_args(linkserver "--device=LPC55S06:LPCXpresso55S06") board_runner_args(jlink "--device=LPC55S06" "--reset-after-load") -include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) diff --git a/boards/arm/lpcxpresso55s16/board.cmake b/boards/arm/lpcxpresso55s16/board.cmake index 45ca5dcfe1cf358..f1a6370b01fe55e 100644 --- a/boards/arm/lpcxpresso55s16/board.cmake +++ b/boards/arm/lpcxpresso55s16/board.cmake @@ -9,6 +9,6 @@ board_runner_args(linkserver "--device=LPC55S16:LPCXpresso55S16") board_runner_args(jlink "--device=LPC55S16" "--reset-after-load") board_runner_args(pyocd "--target=lpc55s16") -include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/lpcxpresso55s28/board.cmake b/boards/arm/lpcxpresso55s28/board.cmake index 9cd2296a40437d8..933e3815a8c9281 100644 --- a/boards/arm/lpcxpresso55s28/board.cmake +++ b/boards/arm/lpcxpresso55s28/board.cmake @@ -4,8 +4,10 @@ # SPDX-License-Identifier: Apache-2.0 # +board_runner_args(linkserver "--device=LPC55S28:LPCXpresso55S28") board_runner_args(pyocd "--target=lpc55s28") board_runner_args(jlink "--device=LPC55S28" "--reset-after-load") -include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/lpcxpresso55s36/board.cmake b/boards/arm/lpcxpresso55s36/board.cmake index b1e16906bd56e30..d1a92d0164d0ef2 100644 --- a/boards/arm/lpcxpresso55s36/board.cmake +++ b/boards/arm/lpcxpresso55s36/board.cmake @@ -8,6 +8,6 @@ board_runner_args(linkserver "--device=LPC55S36:LPCXpresso55S36") board_runner_args(jlink "--device=LPC55S36" "--reset-after-load") board_runner_args(pyocd "--target=lpc55s36") -include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) From a1698b691d9bfd25dfd70fc1ed42e819cdec61a3 Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Tue, 21 Nov 2023 11:01:17 +0100 Subject: [PATCH 0939/1049] twister: pytest: Add --pytest-args to Twister command line Extend Twister command line with --pytest-args. This parameter is passed to pytest subprocess. It allows to select a specific testcase from a test suite. Signed-off-by: Grzegorz Chwierut --- doc/develop/test/pytest.rst | 10 +++ .../pylib/twister/twisterlib/environment.py | 5 ++ scripts/pylib/twister/twisterlib/harness.py | 19 ++++-- .../pytest_integration/test_harness_pytest.py | 66 +++++++++++++++++++ 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index e644882191ef7db..f3db6fcee89c6ac 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -56,6 +56,16 @@ Pytest scans the given locations looking for tests, following its default `discovery rules `_ One can also pass some extra arguments to the pytest from yaml file using ``pytest_args`` keyword under ``harness_config``, e.g.: ``pytest_args: [‘-k=test_method’, ‘--log-level=DEBUG’]``. +There is also an option to pass ``--pytest-args`` through Twister command line parameters. +This can be particularly useful when one wants to select a specific testcase from a test suite. +For instance, one can use a command: + +.. code-block:: console + + $ ./scripts/twister --platform native_sim -T samples/subsys/testsuite/pytest/shell \ + -s samples/subsys/testsuite/pytest/shell/sample.pytest.shell \ + --pytest-args='-k test_shell_print_version' + Helpers & fixtures ================== diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 86965f1f9cfbadc..b7e11406cd4d5d5 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -216,6 +216,11 @@ def add_parse_arguments(parser = None): and 'fifo_loop' is a name of a function found in main.c without test prefix. """) + parser.add_argument("--pytest-args", + help="""Pass additional arguments to the pytest subprocess. This parameter + will override the pytest_args from the harness_config in YAML file. + """) + valgrind_asan_group.add_argument( "--enable-valgrind", action="store_true", help="""Run binary through valgrind and check for several memory access diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index 052def7162a812b..dece1673c7a9ec8 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -309,8 +309,9 @@ def pytest_run(self, timeout): def generate_command(self): config = self.instance.testsuite.harness_config + handler: Handler = self.instance.handler pytest_root = config.get('pytest_root', ['pytest']) if config else ['pytest'] - pytest_args = config.get('pytest_args', []) if config else [] + pytest_args_yaml = config.get('pytest_args', []) if config else [] pytest_dut_scope = config.get('pytest_dut_scope', None) if config else None command = [ 'pytest', @@ -324,12 +325,19 @@ def generate_command(self): ] command.extend([os.path.normpath(os.path.join( self.source_dir, os.path.expanduser(os.path.expandvars(src)))) for src in pytest_root]) - command.extend(pytest_args) + + if handler.options.pytest_args: + command.append(handler.options.pytest_args) + if pytest_args_yaml: + logger.warning(f'The pytest_args ({handler.options.pytest_args}) specified ' + 'in the command line will override the pytest_args defined ' + f'in the YAML file {pytest_args_yaml}') + else: + command.extend(pytest_args_yaml) + if pytest_dut_scope: command.append(f'--dut-scope={pytest_dut_scope}') - handler: Handler = self.instance.handler - if handler.options.verbose > 1: command.extend([ '--log-cli-level=DEBUG', @@ -489,6 +497,9 @@ def _parse_report_file(self, report): tc.status = 'error' tc.reason = elem.get('message') tc.output = elem.text + else: + self.state = 'skipped' + self.instance.reason = 'No tests collected' class Gtest(Harness): diff --git a/scripts/tests/twister/pytest_integration/test_harness_pytest.py b/scripts/tests/twister/pytest_integration/test_harness_pytest.py index 150980059b3d7df..fc60b99e0d13eeb 100644 --- a/scripts/tests/twister/pytest_integration/test_harness_pytest.py +++ b/scripts/tests/twister/pytest_integration/test_harness_pytest.py @@ -25,6 +25,7 @@ def testinstance() -> TestInstance: testinstance.handler = mock.Mock() testinstance.handler.options = mock.Mock() testinstance.handler.options.verbose = 1 + testinstance.handler.options.pytest_args = None testinstance.handler.type_str = 'native' return testinstance @@ -67,6 +68,18 @@ def test_pytest_command_extra_args(testinstance: TestInstance): assert c in command +def test_pytest_command_extra_args_in_options(testinstance: TestInstance): + pytest_harness = Pytest() + pytest_args_from_yaml = '-k test_from_yaml' + pytest_args_from_cmd = '-k test_from_cmd' + testinstance.testsuite.harness_config['pytest_args'] = [pytest_args_from_yaml] + testinstance.handler.options.pytest_args = pytest_args_from_cmd + pytest_harness.configure(testinstance) + command = pytest_harness.generate_command() + assert pytest_args_from_cmd in command + assert pytest_args_from_yaml not in command + + @pytest.mark.parametrize( ('pytest_root', 'expected'), [ @@ -222,3 +235,56 @@ def test_skip_2(): assert len(testinstance.testcases) == 2 for tc in testinstance.testcases: assert tc.status == "skipped" + + +def test_if_report_with_filter(pytester, testinstance: TestInstance): + test_file_content = textwrap.dedent(""" + import pytest + def test_A(): + pass + def test_B(): + pass + """) + test_file = pytester.path / 'test_filter.py' + test_file.write_text(test_file_content) + report_file = pytester.path / 'report.xml' + result = pytester.runpytest( + str(test_file), + '-k', 'test_B', + f'--junit-xml={str(report_file)}' + ) + result.assert_outcomes(passed=1) + assert report_file.is_file() + + pytest_harness = Pytest() + pytest_harness.configure(testinstance) + pytest_harness.report_file = report_file + pytest_harness._update_test_status() + assert pytest_harness.state == "passed" + assert testinstance.status == "passed" + assert len(testinstance.testcases) == 1 + + +def test_if_report_with_no_collected(pytester, testinstance: TestInstance): + test_file_content = textwrap.dedent(""" + import pytest + def test_A(): + pass + """) + test_file = pytester.path / 'test_filter.py' + test_file.write_text(test_file_content) + report_file = pytester.path / 'report.xml' + result = pytester.runpytest( + str(test_file), + '-k', 'test_B', + f'--junit-xml={str(report_file)}' + ) + result.assert_outcomes(passed=0) + assert report_file.is_file() + + pytest_harness = Pytest() + pytest_harness.configure(testinstance) + pytest_harness.report_file = report_file + pytest_harness._update_test_status() + assert pytest_harness.state == "skipped" + assert testinstance.status == "skipped" From d4c1e8ef6715da8b09e107b60b45f3d3101c7d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 16:50:02 +0100 Subject: [PATCH 0940/1049] lorawan: include: add missing Doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added missing comments to various structs and enums in the lorawan.h header. Signed-off-by: Benjamin Cabé --- include/zephyr/lorawan/lorawan.h | 72 ++++++++++++++++---------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/include/zephyr/lorawan/lorawan.h b/include/zephyr/lorawan/lorawan.h index 2e07e99d69416e7..b0f0117d91d3297 100644 --- a/include/zephyr/lorawan/lorawan.h +++ b/include/zephyr/lorawan/lorawan.h @@ -26,63 +26,63 @@ extern "C" { * @brief LoRaWAN class types. */ enum lorawan_class { - LORAWAN_CLASS_A = 0x00, - LORAWAN_CLASS_B = 0x01, - LORAWAN_CLASS_C = 0x02, + LORAWAN_CLASS_A = 0x00, /**< Class A device */ + LORAWAN_CLASS_B = 0x01, /**< Class B device */ + LORAWAN_CLASS_C = 0x02, /**< Class C device */ }; /** * @brief LoRaWAN activation types. */ enum lorawan_act_type { - LORAWAN_ACT_OTAA = 0, - LORAWAN_ACT_ABP, + LORAWAN_ACT_OTAA = 0, /**< Over-the-Air Activation (OTAA) */ + LORAWAN_ACT_ABP, /**< Activation by Personalization (ABP) */ }; /** * @brief LoRaWAN datarate types. */ enum lorawan_datarate { - LORAWAN_DR_0 = 0, - LORAWAN_DR_1, - LORAWAN_DR_2, - LORAWAN_DR_3, - LORAWAN_DR_4, - LORAWAN_DR_5, - LORAWAN_DR_6, - LORAWAN_DR_7, - LORAWAN_DR_8, - LORAWAN_DR_9, - LORAWAN_DR_10, - LORAWAN_DR_11, - LORAWAN_DR_12, - LORAWAN_DR_13, - LORAWAN_DR_14, - LORAWAN_DR_15, + LORAWAN_DR_0 = 0, /**< DR0 data rate */ + LORAWAN_DR_1, /**< DR1 data rate */ + LORAWAN_DR_2, /**< DR2 data rate */ + LORAWAN_DR_3, /**< DR3 data rate */ + LORAWAN_DR_4, /**< DR4 data rate */ + LORAWAN_DR_5, /**< DR5 data rate */ + LORAWAN_DR_6, /**< DR6 data rate */ + LORAWAN_DR_7, /**< DR7 data rate */ + LORAWAN_DR_8, /**< DR8 data rate */ + LORAWAN_DR_9, /**< DR9 data rate */ + LORAWAN_DR_10, /**< DR10 data rate */ + LORAWAN_DR_11, /**< DR11 data rate */ + LORAWAN_DR_12, /**< DR12 data rate */ + LORAWAN_DR_13, /**< DR13 data rate */ + LORAWAN_DR_14, /**< DR14 data rate */ + LORAWAN_DR_15, /**< DR15 data rate */ }; /** * @brief LoRaWAN region types. */ enum lorawan_region { - LORAWAN_REGION_AS923, - LORAWAN_REGION_AU915, - LORAWAN_REGION_CN470, - LORAWAN_REGION_CN779, - LORAWAN_REGION_EU433, - LORAWAN_REGION_EU868, - LORAWAN_REGION_KR920, - LORAWAN_REGION_IN865, - LORAWAN_REGION_US915, - LORAWAN_REGION_RU864, + LORAWAN_REGION_AS923, /**< Asia 923 MHz frequency band */ + LORAWAN_REGION_AU915, /**< Australia 915 MHz frequency band */ + LORAWAN_REGION_CN470, /**< China 470 MHz frequency band */ + LORAWAN_REGION_CN779, /**< China 779 MHz frequency band */ + LORAWAN_REGION_EU433, /**< Europe 433 MHz frequency band */ + LORAWAN_REGION_EU868, /**< Europe 868 MHz frequency band */ + LORAWAN_REGION_KR920, /**< South Korea 920 MHz frequency band */ + LORAWAN_REGION_IN865, /**< India 865 MHz frequency band */ + LORAWAN_REGION_US915, /**< United States 915 MHz frequency band */ + LORAWAN_REGION_RU864, /**< Russia 864 MHz frequency band */ }; /** * @brief LoRaWAN message types. */ enum lorawan_message_type { - LORAWAN_MSG_UNCONFIRMED = 0, - LORAWAN_MSG_CONFIRMED, + LORAWAN_MSG_UNCONFIRMED = 0, /**< Unconfirmed message */ + LORAWAN_MSG_CONFIRMED, /**< Confirmed message */ }; /** @@ -128,9 +128,10 @@ struct lorawan_join_abp { * @brief LoRaWAN join parameters */ struct lorawan_join_config { + /** Join parameters */ union { - struct lorawan_join_otaa otaa; - struct lorawan_join_abp abp; + struct lorawan_join_otaa otaa; /**< OTAA join parameters */ + struct lorawan_join_abp abp; /**< ABP join parameters */ }; /** Device EUI. Optional if a secure element is present. */ @@ -140,6 +141,7 @@ struct lorawan_join_config { enum lorawan_act_type mode; }; +/** Flag to indicate receiving on any port */ #define LW_RECV_PORT_ANY UINT16_MAX /** From 64cce4866f3da605b2f1c8af314d6df84e0ab42c Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Wed, 8 Nov 2023 18:16:24 -0800 Subject: [PATCH 0941/1049] MAINTAINERS: add Nuvoton collaborators for Nuvoton NPCX Platforms Add Nuvoton guys, TomChang19 and alvsun, in collaborators of Nuvoton NPCX Platforms and remove MulinChao and ChiHuaL since they are already the maintainers. Signed-off-by: Mulin Chao --- MAINTAINERS.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index a4ad483ce2cd1d3..8a514d236c221bf 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2503,8 +2503,8 @@ Nuvoton NPCX Platforms: - MulinChao - ChiHuaL collaborators: - - MulinChao - - ChiHuaL + - TomChang19 + - alvsun - sjg20 - keith-zephyr - jackrosenthal From c3a54ae1c34e939db83431bea354c0f4d0add0b3 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 22 Nov 2023 16:34:02 +0000 Subject: [PATCH 0942/1049] drivers: regulator: Fixed reference counting during enable Reference counting was broken when adding the enable delay. Now reverted to previous pattern. Signed-off-by: Andy Sinclair --- drivers/regulator/regulator_common.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index 7f33040d2d91ab8..14866a3738f268f 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -107,10 +107,13 @@ int regulator_enable(const struct device *dev) (void)k_mutex_lock(&data->lock, K_FOREVER); #endif - if (data->refcnt == 0) { + data->refcnt++; + + if (data->refcnt == 1) { ret = api->enable(dev); - if (ret == 0) { - data->refcnt++; + if (ret < 0) { + data->refcnt--; + } else { regulator_delay(config->off_on_delay_us); } } From eeb6bf7dd998c8c191f58df692097bfcfaf1e3bf Mon Sep 17 00:00:00 2001 From: Juliane Schulze Date: Fri, 10 Nov 2023 17:37:24 +0100 Subject: [PATCH 0943/1049] input: make short-inputs optional By making short inputs optional, the user can bypass short-events all together if necessary (e.g. custom button-press listener). Signed-off-by: Juliane Schulze --- .../input/zephyr,input-longpress.yaml | 9 +++-- subsys/input/input_longpress.c | 11 ++++-- .../input/longpress/boards/native_sim.overlay | 8 +++++ tests/subsys/input/longpress/src/main.c | 34 +++++++++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/dts/bindings/input/zephyr,input-longpress.yaml b/dts/bindings/input/zephyr,input-longpress.yaml index abf87a158030627..a6ef96f5d40b881 100644 --- a/dts/bindings/input/zephyr,input-longpress.yaml +++ b/dts/bindings/input/zephyr,input-longpress.yaml @@ -8,7 +8,9 @@ description: | corresponding to short and long press. Can be optionally be associated to a specific device to listen for events - only from that device. Example configuration: + only from that device. + + Example configuration: #include @@ -23,12 +25,14 @@ description: | Example output: + # short press input event: dev=buttons SYN type= 1 code= 11 value=1 # INPUT_KEY_0 press # release before one second input event: dev=buttons SYN type= 1 code= 11 value=0 # INPUT_KEY_0 release input event: dev=longpress SYN type= 1 code= 30 value=1 # INPUT_KEY_A press input event: dev=longpress SYN type= 1 code= 30 value=0 # INPUT_KEY_A release + # long press input event: dev=buttons SYN type= 1 code= 11 value=1 # INPUT_KEY_0 press # hold for more than one second input event: dev=longpress SYN type= 1 code= 45 value=1 # INPUT_KEY_X press @@ -52,9 +56,8 @@ properties: short-codes: type: array - required: true description: | - Array of key codes to be generated for short press (INPUT_KEY_* or + Optional array of key codes to be generated for short press (INPUT_KEY_* or INPUT_BTN_*). long-codes: diff --git a/subsys/input/input_longpress.c b/subsys/input/input_longpress.c index c9acbbf14fe4afb..5e0b6f0ac9f7a78 100644 --- a/subsys/input/input_longpress.c +++ b/subsys/input/input_longpress.c @@ -80,7 +80,7 @@ static void longpress_cb(const struct device *dev, struct input_event *evt) k_work_cancel_delayable(&entry->work); if (entry->long_fired) { input_report_key(dev, cfg->long_codes[i], 0, true, K_FOREVER); - } else { + } else if (cfg->short_codes != NULL) { input_report_key(dev, cfg->short_codes[i], 1, true, K_FOREVER); input_report_key(dev, cfg->short_codes[i], 0, true, K_FOREVER); } @@ -109,8 +109,9 @@ static int longpress_init(const struct device *dev) } #define INPUT_LONGPRESS_DEFINE(inst) \ - BUILD_ASSERT(DT_INST_PROP_LEN(inst, input_codes) == \ - DT_INST_PROP_LEN(inst, short_codes)); \ + BUILD_ASSERT((DT_INST_PROP_LEN(inst, input_codes) == \ + DT_INST_PROP_LEN_OR(inst, short_codes, 0)) || \ + !DT_INST_NODE_HAS_PROP(inst, short_codes)); \ BUILD_ASSERT(DT_INST_PROP_LEN(inst, input_codes) == \ DT_INST_PROP_LEN(inst, long_codes)); \ static void longpress_cb_##inst(struct input_event *evt) \ @@ -120,12 +121,16 @@ static int longpress_init(const struct device *dev) INPUT_CALLBACK_DEFINE(DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, input)), \ longpress_cb_##inst); \ static const uint16_t longpress_input_codes_##inst[] = DT_INST_PROP(inst, input_codes); \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, short_codes), ( \ static const uint16_t longpress_short_codes_##inst[] = DT_INST_PROP(inst, short_codes); \ + )); \ static const uint16_t longpress_long_codes_##inst[] = DT_INST_PROP(inst, long_codes); \ static const struct longpress_config longpress_config_##inst = { \ .input_dev = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, input)), \ .input_codes = longpress_input_codes_##inst, \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, short_codes), ( \ .short_codes = longpress_short_codes_##inst, \ + )) \ .long_codes = longpress_long_codes_##inst, \ .num_codes = DT_INST_PROP_LEN(inst, input_codes), \ .long_delays_ms = DT_INST_PROP(inst, long_delay_ms), \ diff --git a/tests/subsys/input/longpress/boards/native_sim.overlay b/tests/subsys/input/longpress/boards/native_sim.overlay index 14dcd8d0d4e9ff7..a742ed99c5c44b4 100644 --- a/tests/subsys/input/longpress/boards/native_sim.overlay +++ b/tests/subsys/input/longpress/boards/native_sim.overlay @@ -19,4 +19,12 @@ long-codes = , ; long-delay-ms = <100>; }; + + longpress_no_short: longpress-no-short { + input = <&fake_input_device>; + compatible = "zephyr,input-longpress"; + input-codes = , ; + long-codes = , ; + long-delay-ms = <100>; + }; }; diff --git a/tests/subsys/input/longpress/src/main.c b/tests/subsys/input/longpress/src/main.c index 22d5e7200381e6c..4f81901a742192a 100644 --- a/tests/subsys/input/longpress/src/main.c +++ b/tests/subsys/input/longpress/src/main.c @@ -13,6 +13,8 @@ static const struct device *const fake_dev = DEVICE_DT_GET( DT_NODELABEL(fake_input_device)); static const struct device *const longpress_dev = DEVICE_DT_GET( DT_NODELABEL(longpress)); +static const struct device *const longpress_no_short_dev = DEVICE_DT_GET( + DT_NODELABEL(longpress_no_short)); DEVICE_DT_DEFINE(DT_INST(0, vnd_input_device), NULL, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL); @@ -30,6 +32,18 @@ static void test_cb(struct input_event *evt) } INPUT_CALLBACK_DEFINE(longpress_dev, test_cb); +static int event_count_no_short; +static struct input_event last_events_no_short[2]; +static void test_cb_no_short(struct input_event *evt) +{ + TC_PRINT("%s: %d %x %d\n", __func__, event_count_no_short, evt->code, evt->value); + + event_count_no_short++; + memcpy(&last_events_no_short[1], &last_events_no_short[0], sizeof(struct input_event)); + memcpy(&last_events_no_short[0], evt, sizeof(struct input_event)); +} +INPUT_CALLBACK_DEFINE(longpress_no_short_dev, test_cb_no_short); + ZTEST(longpress, test_longpress_test) { zassert_equal(event_count, 0); @@ -38,9 +52,11 @@ ZTEST(longpress, test_longpress_test) input_report_key(fake_dev, INPUT_KEY_3, 1, true, K_FOREVER); input_report_key(fake_dev, INPUT_KEY_3, 0, true, K_FOREVER); zassert_equal(event_count, 0); + zassert_equal(event_count_no_short, 0); input_report_abs(fake_dev, INPUT_KEY_0, 1, true, K_FOREVER); input_report_abs(fake_dev, INPUT_KEY_0, 0, true, K_FOREVER); zassert_equal(event_count, 0); + zassert_equal(event_count_no_short, 0); /* short press */ input_report_key(fake_dev, INPUT_KEY_0, 1, true, K_FOREVER); @@ -53,6 +69,7 @@ ZTEST(longpress, test_longpress_test) zassert_equal(last_events[0].type, INPUT_EV_KEY); zassert_equal(last_events[0].code, INPUT_KEY_A); zassert_equal(last_events[0].value, 0); + zassert_equal(event_count_no_short, 0); /* short press - other key */ input_report_key(fake_dev, INPUT_KEY_1, 1, true, K_FOREVER); @@ -65,6 +82,7 @@ ZTEST(longpress, test_longpress_test) zassert_equal(last_events[0].type, INPUT_EV_KEY); zassert_equal(last_events[0].code, INPUT_KEY_B); zassert_equal(last_events[0].value, 0); + zassert_equal(event_count_no_short, 0); /* long press */ input_report_key(fake_dev, INPUT_KEY_0, 1, true, K_FOREVER); @@ -78,6 +96,14 @@ ZTEST(longpress, test_longpress_test) zassert_equal(last_events[0].code, INPUT_KEY_X); zassert_equal(last_events[0].value, 0); + zassert_equal(event_count_no_short, 2); + zassert_equal(last_events_no_short[1].type, INPUT_EV_KEY); + zassert_equal(last_events_no_short[1].code, INPUT_KEY_X); + zassert_equal(last_events_no_short[1].value, 1); + zassert_equal(last_events_no_short[0].type, INPUT_EV_KEY); + zassert_equal(last_events_no_short[0].code, INPUT_KEY_X); + zassert_equal(last_events_no_short[0].value, 0); + /* long press - other key */ input_report_key(fake_dev, INPUT_KEY_1, 1, true, K_FOREVER); k_sleep(K_MSEC(150)); @@ -89,6 +115,14 @@ ZTEST(longpress, test_longpress_test) zassert_equal(last_events[0].type, INPUT_EV_KEY); zassert_equal(last_events[0].code, INPUT_KEY_Y); zassert_equal(last_events[0].value, 0); + + zassert_equal(event_count_no_short, 4); + zassert_equal(last_events_no_short[1].type, INPUT_EV_KEY); + zassert_equal(last_events_no_short[1].code, INPUT_KEY_Y); + zassert_equal(last_events_no_short[1].value, 1); + zassert_equal(last_events_no_short[0].type, INPUT_EV_KEY); + zassert_equal(last_events_no_short[0].code, INPUT_KEY_Y); + zassert_equal(last_events_no_short[0].value, 0); } ZTEST_SUITE(longpress, NULL, NULL, NULL, NULL, NULL); From 67ec329a702616e39ec9ea44d8d3f350e8cf3e2a Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 23 Nov 2023 14:32:25 +0100 Subject: [PATCH 0944/1049] tests: kernel: mem_protect: mem_map: fix wrong include This test needs to include zephyr/kernel/mm/demand_paging.h, not zephyr/kernel/mm.h, due to its use of k_mem_pin(). Signed-off-by: Henrik Brix Andersen --- tests/kernel/mem_protect/mem_map/src/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/kernel/mem_protect/mem_map/src/main.c b/tests/kernel/mem_protect/mem_map/src/main.c index 45ca0aa1cf37ecc..93ba040669329fb 100644 --- a/tests/kernel/mem_protect/mem_map/src/main.c +++ b/tests/kernel/mem_protect/mem_map/src/main.c @@ -5,11 +5,14 @@ */ #include -#include #include #include #include +#ifdef CONFIG_DEMAND_PAGING +#include +#endif /* CONFIG_DEMAND_PAGING */ + /* 32-bit IA32 page tables have no mechanism to restrict execution */ #if defined(CONFIG_X86) && !defined(CONFIG_X86_64) && !defined(CONFIG_X86_PAE) #define SKIP_EXECUTE_TESTS From 69d62add980bcafa6d90b73920372390cc10ea7c Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Thu, 23 Nov 2023 19:19:18 +0530 Subject: [PATCH 0945/1049] drivers: serial: ns16550: Fixed few bugs causing CI failure Removed if (IS_ENABLED()) and used #if as they are causing CI failures and removed LPSS related functions which are not under LPSS config. Signed-off-by: Anisetti Avinash Krishna --- drivers/serial/uart_ns16550.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 22243a34d1687cf..e0c9ccebd03f8b2 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -261,7 +261,6 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define CLR_SRC_TRAN(dev) (get_port(dev) + REG_LPSS_CLR_SRC_TRAN) #define MST(dev) (get_port(dev) + REG_LPSS_MST) -#define MASK_LPSS_INT(chan) (BIT(8) << chan) /* mask LPSS DMA Interrupt */ #define UNMASK_LPSS_INT(chan) (BIT(chan) | (BIT(8) << chan)) /* unmask LPSS DMA Interrupt */ #endif @@ -1287,8 +1286,6 @@ static void uart_ns16550_isr(const struct device *dev) if (IIR_status & IIR_RBRF) { async_timer_start(&dev_data->async.rx_dma_params.timeout_work, dev_data->async.rx_dma_params.timeout_us); - ns16550_outword(config, CLR_SRC_TRAN(dev), - BIT(dev_data->async.rx_dma_params.dma_channel)); return; } } @@ -1486,7 +1483,6 @@ static void uart_ns16550_async_rx_flush(const struct device *dev) static int uart_ns16550_rx_disable(const struct device *dev) { - const struct uart_ns16550_device_config * const config = dev->config; struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; k_spinlock_key_t key = k_spin_lock(&data->lock); @@ -1519,10 +1515,6 @@ static int uart_ns16550_rx_disable(const struct device *dev) async_user_callback(dev, &event); - if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) { - ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(dma_params->dma_channel)); - } - out: k_spin_unlock(&data->lock, key); return ret; @@ -1538,7 +1530,7 @@ static void prepare_rx_dma_block_config(const struct device *dev) struct dma_block_config *head_block_config = &rx_dma_params->active_dma_block; - head_block_config->dest_address = (uint64_t)rx_dma_params->buf; + head_block_config->dest_address = (uintptr_t)rx_dma_params->buf; head_block_config->source_address = data->phys_addr; head_block_config->block_size = rx_dma_params->buf_len; } @@ -1568,7 +1560,7 @@ static void dma_callback(const struct device *dev, void *user_data, uint32_t cha if (rx_params->buf != NULL && rx_params->buf_len > 0) { dma_reload(dev, rx_params->dma_channel, data->phys_addr, - (uint64_t)rx_params->buf, rx_params->buf_len); + (uintptr_t)rx_params->buf, rx_params->buf_len); dma_start(dev, rx_params->dma_channel); async_evt_rx_buf_request(uart_dev); } else { @@ -1603,7 +1595,7 @@ static int uart_ns16550_tx(const struct device *dev, const uint8_t *buf, size_t tx_params->buf = buf; tx_params->buf_len = len; - tx_params->active_dma_block.source_address = (uint64_t)buf; + tx_params->active_dma_block.source_address = (uintptr_t)buf; tx_params->active_dma_block.dest_address = data->phys_addr; tx_params->active_dma_block.block_size = len; tx_params->active_dma_block.next_block = NULL; @@ -1681,13 +1673,13 @@ static int uart_ns16550_rx_enable(const struct device *dev, uint8_t *buf, const rx_dma_params->buf = buf; rx_dma_params->buf_len = len; - if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) { - ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(DMA_INTEL_LPSS_RX_CHAN)); - } else { - ns16550_outbyte(config, IER(dev), - (ns16550_inbyte(config, IER(dev)) | IER_RXRDY)); - ns16550_outbyte(config, FCR(dev), FCR_FIFO); - } +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) + ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(rx_dma_params->dma_channel)); +#else + ns16550_outbyte(config, IER(dev), + (ns16550_inbyte(config, IER(dev)) | IER_RXRDY)); + ns16550_outbyte(config, FCR(dev), FCR_FIFO); +#endif prepare_rx_dma_block_config(dev); dma_config(rx_dma_params->dma_dev, rx_dma_params->dma_channel, From e76ace4647362ec3a770f6c0aa5f3a8394f09dc2 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Fri, 24 Nov 2023 00:49:40 +0530 Subject: [PATCH 0946/1049] drivers: serial: ns16550: Condition added for dma_callback Enable a condition as define dma_callback function only if any one instance of ns16550 has dmas parameter in dts. This resolves conflict of dma_callback function defined but not used warning in case of UART_ASYNC_API enabled but dmas parameter is not provided to any ns16550 UARTs dts instances. Signed-off-by: Anisetti Avinash Krishna --- drivers/serial/uart_ns16550.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index e0c9ccebd03f8b2..665b44062accb80 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -45,6 +45,7 @@ LOG_MODULE_REGISTER(uart_ns16550, CONFIG_UART_LOG_LEVEL); #define UART_NS16550_PCP_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(pcp) #define UART_NS16550_DLF_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(dlf) +#define UART_NS16550_DMAS_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(dmas) #if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); @@ -1402,6 +1403,7 @@ static void async_user_callback(const struct device *dev, struct uart_event *evt } } +#if UART_NS16550_DMAS_ENABLED static void async_evt_tx_done(struct device *dev) { struct uart_ns16550_dev_data *data = dev->data; @@ -1420,6 +1422,7 @@ static void async_evt_tx_done(struct device *dev) async_user_callback(dev, &event); } +#endif static void async_evt_rx_rdy(const struct device *dev) { @@ -1535,6 +1538,7 @@ static void prepare_rx_dma_block_config(const struct device *dev) head_block_config->block_size = rx_dma_params->buf_len; } +#if UART_NS16550_DMAS_ENABLED static void dma_callback(const struct device *dev, void *user_data, uint32_t channel, int status) { @@ -1568,6 +1572,7 @@ static void dma_callback(const struct device *dev, void *user_data, uint32_t cha } } } +#endif static int uart_ns16550_callback_set(const struct device *dev, uart_callback_t callback, void *user_data) From 5afaa38e671af7b10513eab6aa2c4a665d7a824f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Sat, 28 Oct 2023 18:55:41 +0100 Subject: [PATCH 0947/1049] drivers: led_strip: ws2812: Remove scratch selection for non-GPIO The WS2812 LED strip driver does not use a scratch byte, therefore free up a byte per pixel which was unused except in the GPIO-based driver whereby it is used Signed-off-by: Jamie McCrae --- drivers/led_strip/Kconfig.ws2812 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/led_strip/Kconfig.ws2812 b/drivers/led_strip/Kconfig.ws2812 index fc91250c2f221de..7682ba4be87d509 100644 --- a/drivers/led_strip/Kconfig.ws2812 +++ b/drivers/led_strip/Kconfig.ws2812 @@ -9,7 +9,6 @@ menuconfig WS2812_STRIP bool "WS2812 (and compatible) LED strip driver" - select LED_STRIP_RGB_SCRATCH help Enable LED strip driver for daisy chains of WS2812-ish (or WS2812B, WS2813, SK6812, Everlight B1414, or compatible) devices. @@ -39,6 +38,7 @@ config WS2812_STRIP_GPIO # Only an Cortex-M0 inline assembly implementation for the nRF51 # is supported currently. depends on SOC_SERIES_NRF51X + select LED_STRIP_RGB_SCRATCH help The GPIO driver does bit-banging with inline assembly, and is not available on all SoCs. From cce77c8902e112da97c6fb00d0ca39f15a435923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Nov 2023 14:33:32 +0100 Subject: [PATCH 0948/1049] doc: latex: enable pdflscape package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable the pdflscape package (available in the Latex distros recommended for Zephyr) to allow for some pages to be rendered in landscape mode. Signed-off-by: Benjamin Cabé --- doc/_static/latex/preamble.tex | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/_static/latex/preamble.tex b/doc/_static/latex/preamble.tex index 3213c955bdbd608..50ef29d4d2bc0dd 100644 --- a/doc/_static/latex/preamble.tex +++ b/doc/_static/latex/preamble.tex @@ -5,6 +5,7 @@ \usepackage[some]{background} \usepackage{sectsty} +\usepackage{pdflscape} \definecolor{bg-color}{HTML}{333f67} From 2a9f914db250e2e9180c11e534d42a46efbf681a Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 14 Nov 2023 09:54:39 +0000 Subject: [PATCH 0949/1049] doc: mgmt: mcumgr: Add list of libraries/tools Adds a list of tools and libraries that are available Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/mcumgr.rst | 82 ++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/doc/services/device_mgmt/mcumgr.rst b/doc/services/device_mgmt/mcumgr.rst index f16a77d43a9654f..0b21ce0771a3231 100644 --- a/doc/services/device_mgmt/mcumgr.rst +++ b/doc/services/device_mgmt/mcumgr.rst @@ -34,6 +34,85 @@ the Zephyr tree. Additionally, there is a :zephyr:code-sample:`sample ` sample that provides management functionality over BLE and serial. +.. _mcumgr_tools_libraries: + +Tools/libraries +*************** + +There are various tools and libraries available which enable usage of MCUmgr functionality on a +device which are listed below. Note that these tools are not part of or related to the Zephyr +project. + +.. only:: html + + .. table:: Tools and Libraries for MCUmgr + :align: center + + +--------------------------------------------------------------------------------+-------------------------------------------+--------------------------+--------------------------------------------------+---------------+------------+---------+ + | Name | OS support | Transports | Groups | Type | Language | License | + | +---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+ | | | + | | Windows | Linux | mac | Mobile | Embedded | Serial | Bluetooth | UDP | OS | IMG | Stat | Settings | FS | Shell | Zephyr | | | | + +================================================================================+=========+=======+=====+========+==========+========+===========+=====+====+=====+======+==========+====+=======+========+===============+============+=========+ + | `AuTerm `_ | ✓ | ✓ | ✓ | ✕ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Application | C++ (Qt) | GPLv3 | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | `mcumgr-client `_ | ✓ | ✓ | ✓ | ✕ | ✕ | ✓ | ✕ | ✕ | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Application | Rust | BSD | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | `mcumgr-web `_ | ✓ | ✓ | ✓ | ✕ | ✕ | ✕ | ✓ | ✕ | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Web page | Javascript | MIT | + | | | | | | | | | | | | | | | | | (chrome only) | | | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | nRF Connect Device Manager: |br| | | | | | | | | | | | | | | | | | | | + | `Android | ✕ | ✕ | ✕ | ✓ | ✕ | ✕ | ✓ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Library and | Java, | Apache | + | `_ | | | | | | | | | | | | | | | | application | Kotlin, | | + | and `iOS | | | | | | | | | | | | | | | | | Swift | | + | `_ | | | | | | | | | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | Zephyr MCUmgr client (in-tree) | ✕ | ✓ | ✕ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Library | C | Apache | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + +.. only:: latex + + .. raw:: latex + + \begin{landscape} + + .. table:: Tools and Libraries for MCUmgr + :align: center + + +--------------------------------------------------------------------------------+---------------+-----------------+--------------------------------------------------+---------------+------------+ + | Name | OS support | Transports | Groups | Type | Language | + | | | +----+-----+------+----------+----+-------+--------+ | | + | | | | OS | IMG | Stat | Settings | FS | Shell | Zephyr | | | + +================================================================================+===============+=================+====+=====+======+==========+====+=======+========+===============+============+ + | `AuTerm `_ | Windows, |br| | Serial, |br| | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | App | C++ (Qt) | + | | Linux, |br| | Bluetooth, |br| | | | | | | | | | | + | | macOS | UDP | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | `mcumgr-client `_ | Windows, |br| | Serial | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | App | Rust | + | | Linux, |br| | | | | | | | | | | | + | | macOS | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | `mcumgr-web `_ | Windows, |br| | Bluetooth | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Web (chrome | Javascript | + | | Linux, |br| | | | | | | | | | only) | | + | | macOS | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | nRF Connect Device Manager: |br| | iOS, |br| | Bluetooth | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Library, App | Java, | + | `Android | Android | | | | | | | | | | Kotlin, | + | `_ | | | | | | | | | | | Swift | + | and `iOS | | | | | | | | | | | | + | `_ | | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | Zephyr MCUmgr client (in-tree) | Linux, |br| | Serial, |br| | ✓ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Library | C | + | | Zephyr | Bluetooth, |br| | | | | | | | | | | + | | | UDP | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + + .. raw:: latex + + \end{landscape} + +Note that a tick for a particular group indicates basic support for that group in the code, it is +possible that not all commands/features of a group are supported by the implementation. + .. _mcumgr_cli: Command-line Tool @@ -49,7 +128,8 @@ The tool is written in the Go programming language. aborting will, in some circumstances, sit in an endless loop of sending the same command over and over again. A universal replacement for this tool is currently in development and once released, support for the go tool will be - dropped entirely. + dropped entirely. It is recommended that usage of tools listed above in the + :ref:`mcumgr_tools_libraries` section are used instead of the go client. To install the tool: From f9a547558aab6148fa1ee7824da2618e3a6f0a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 09:40:44 +0100 Subject: [PATCH 0950/1049] sys: cbprintf: Add macro for validating strings for packaging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When cbprintf package is created statically then only argument types are taken into account and not the format string. It means that a character pointer is always interpreted as %s and not %p. When %s is found then string from rw location is copied into the package. Copying unexpected data may lead to memory faults so it must be avoided. User shall cast an argument to a pointer of a different type. Patch adds macros which can at compile time determine if %p is used with char *. Result cannot be passed to static assert because compiler sees it as non-constant (even though calculated at compile time) but a runtime logging error message can be added instead of original message. Z_CBPRINTF_NONE_CHAR_PTR_COUNT counts number of none character pointers in the arguments list. Z_CBPRINTF_P_COUNT counts number of %p occurrences in the format string. If results of both macros are equal it means that string is ok. Signed-off-by: Krzysztof Chruściński --- include/zephyr/sys/cbprintf_cxx.h | 109 ++++++++ include/zephyr/sys/cbprintf_internal.h | 350 +++++++++++++++++++++++++ 2 files changed, 459 insertions(+) diff --git a/include/zephyr/sys/cbprintf_cxx.h b/include/zephyr/sys/cbprintf_cxx.h index 3b65b2295179fb0..1930e18b7d40653 100644 --- a/include/zephyr/sys/cbprintf_cxx.h +++ b/include/zephyr/sys/cbprintf_cxx.h @@ -139,6 +139,115 @@ static inline int z_cbprintf_cxx_is_word_num(T arg) _Pragma("GCC diagnostic pop") } +/* C++ version for determining if argument is a none character pointer. */ +static inline int z_cbprintf_cxx_is_none_char_ptr(char) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned char) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(short) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned short) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(int) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned int) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(long long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned long long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(float) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(double) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(volatile char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const volatile char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(volatile unsigned char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const unsigned char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const volatile unsigned char *) +{ + return 0; +} + +template < typename T > +static inline int z_cbprintf_cxx_is_none_char_ptr(T arg) +{ + ARG_UNUSED(arg); + + return 1; +} + /* C++ version for calculating argument size. */ static inline size_t z_cbprintf_cxx_arg_size(float f) { diff --git a/include/zephyr/sys/cbprintf_internal.h b/include/zephyr/sys/cbprintf_internal.h index eed2bbc3944917b..51b99494b962b7f 100644 --- a/include/zephyr/sys/cbprintf_internal.h +++ b/include/zephyr/sys/cbprintf_internal.h @@ -138,6 +138,356 @@ extern "C" { 0) #endif +/** @brief Check if argument is a none character pointer. + * + * @note Macro triggers a pointer arithmetic warning and usage shall be wrapped in + * the pragma that suppresses this warning. + * + * @param x Input argument. + * + * @retval 1 if variable is a none character pointer. + * @retval 0 if variable is of different type. + */ +#ifdef __cplusplus +#define Z_CBPRINTF_IS_NONE_CHAR_PTR(x) z_cbprintf_cxx_is_none_char_ptr(x) +#else +#define Z_CBPRINTF_IS_NONE_CHAR_PTR(x) \ + _Generic((x) + 0, \ + char * : 0, \ + volatile char * : 0, \ + const char * : 0, \ + const volatile char * : 0, \ + unsigned char * : 0, \ + volatile unsigned char * : 0, \ + const unsigned char * : 0, \ + const volatile unsigned char * : 0, \ + char: 0, \ + unsigned char: 0, \ + short: 0, \ + unsigned short: 0, \ + int: 0, \ + unsigned int: 0,\ + long: 0, \ + unsigned long: 0,\ + long long: 0, \ + unsigned long long: 0, \ + float: 0, \ + double: 0, \ + default : \ + 1) +#endif + +/** @brief Get number of none character pointers in the string with at least 1 argument. + * + * @param ... String with at least 1 argument. + * + * @return Number of none character pointer arguments. + */ +#define Z_CBPRINTF_NONE_CHAR_PTR_ARGS(...) \ + (FOR_EACH(Z_CBPRINTF_IS_NONE_CHAR_PTR, (+), __VA_ARGS__)) \ + +/** @brief Get number of none character pointers in the string argument list. + * + * @param ... Format string with arguments. + * + * @return Number of none character pointer arguments. + */ +#define Z_CBPRINTF_NONE_CHAR_PTR_COUNT(...) \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \ + (0), \ + (Z_CBPRINTF_NONE_CHAR_PTR_ARGS(GET_ARGS_LESS_N(1, __VA_ARGS__)))) + +/** @brief Calculate number of pointer format specifiers in the string. + * + * If constant string is provided then result is calculated at compile time + * however for it is not consider constant by the compiler, e.g. can not be + * used in the static assert. + * + * String length is limited to 256. + * + * @param fmt Format string. + * @param ... String arguments. + * + * @return Number of %p format specifiers in the string. + */ +#define Z_CBPRINTF_P_COUNT(fmt, ...) \ + ((sizeof(fmt) >= 2 && fmt[0] == '%' && fmt[1] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 3 && fmt[0] != '%' && fmt[1] == '%' && fmt[2] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 4 && fmt[1] != '%' && fmt[2] == '%' && fmt[3] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 5 && fmt[2] != '%' && fmt[3] == '%' && fmt[4] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 6 && fmt[3] != '%' && fmt[4] == '%' && fmt[5] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 7 && fmt[4] != '%' && fmt[5] == '%' && fmt[6] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 8 && fmt[5] != '%' && fmt[6] == '%' && fmt[7] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 9 && fmt[6] != '%' && fmt[7] == '%' && fmt[8] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 10 && fmt[7] != '%' && fmt[8] == '%' && fmt[9] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 11 && fmt[8] != '%' && fmt[9] == '%' && fmt[10] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 12 && fmt[9] != '%' && fmt[10] == '%' && fmt[11] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 13 && fmt[10] != '%' && fmt[11] == '%' && fmt[12] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 14 && fmt[11] != '%' && fmt[12] == '%' && fmt[13] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 15 && fmt[12] != '%' && fmt[13] == '%' && fmt[14] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 16 && fmt[13] != '%' && fmt[14] == '%' && fmt[15] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 17 && fmt[14] != '%' && fmt[15] == '%' && fmt[16] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 18 && fmt[15] != '%' && fmt[16] == '%' && fmt[17] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 19 && fmt[16] != '%' && fmt[17] == '%' && fmt[18] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 20 && fmt[17] != '%' && fmt[18] == '%' && fmt[19] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 21 && fmt[18] != '%' && fmt[19] == '%' && fmt[20] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 22 && fmt[19] != '%' && fmt[20] == '%' && fmt[21] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 23 && fmt[20] != '%' && fmt[21] == '%' && fmt[22] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 24 && fmt[21] != '%' && fmt[22] == '%' && fmt[23] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 25 && fmt[22] != '%' && fmt[23] == '%' && fmt[24] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 26 && fmt[23] != '%' && fmt[24] == '%' && fmt[25] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 27 && fmt[24] != '%' && fmt[25] == '%' && fmt[26] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 28 && fmt[25] != '%' && fmt[26] == '%' && fmt[27] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 29 && fmt[26] != '%' && fmt[27] == '%' && fmt[28] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 30 && fmt[27] != '%' && fmt[28] == '%' && fmt[29] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 31 && fmt[28] != '%' && fmt[29] == '%' && fmt[30] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 32 && fmt[29] != '%' && fmt[30] == '%' && fmt[31] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 33 && fmt[30] != '%' && fmt[31] == '%' && fmt[32] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 34 && fmt[31] != '%' && fmt[32] == '%' && fmt[33] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 35 && fmt[32] != '%' && fmt[33] == '%' && fmt[34] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 36 && fmt[33] != '%' && fmt[34] == '%' && fmt[35] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 37 && fmt[34] != '%' && fmt[35] == '%' && fmt[36] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 38 && fmt[35] != '%' && fmt[36] == '%' && fmt[37] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 39 && fmt[36] != '%' && fmt[37] == '%' && fmt[38] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 40 && fmt[37] != '%' && fmt[38] == '%' && fmt[39] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 41 && fmt[38] != '%' && fmt[39] == '%' && fmt[40] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 42 && fmt[39] != '%' && fmt[40] == '%' && fmt[41] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 43 && fmt[40] != '%' && fmt[41] == '%' && fmt[42] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 44 && fmt[41] != '%' && fmt[42] == '%' && fmt[43] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 45 && fmt[42] != '%' && fmt[43] == '%' && fmt[44] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 46 && fmt[43] != '%' && fmt[44] == '%' && fmt[45] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 47 && fmt[44] != '%' && fmt[45] == '%' && fmt[46] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 48 && fmt[45] != '%' && fmt[46] == '%' && fmt[47] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 49 && fmt[46] != '%' && fmt[47] == '%' && fmt[48] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 50 && fmt[47] != '%' && fmt[48] == '%' && fmt[49] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 51 && fmt[48] != '%' && fmt[49] == '%' && fmt[50] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 52 && fmt[49] != '%' && fmt[50] == '%' && fmt[51] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 53 && fmt[50] != '%' && fmt[51] == '%' && fmt[52] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 54 && fmt[51] != '%' && fmt[52] == '%' && fmt[53] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 55 && fmt[52] != '%' && fmt[53] == '%' && fmt[54] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 56 && fmt[53] != '%' && fmt[54] == '%' && fmt[55] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 57 && fmt[54] != '%' && fmt[55] == '%' && fmt[56] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 58 && fmt[55] != '%' && fmt[56] == '%' && fmt[57] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 59 && fmt[56] != '%' && fmt[57] == '%' && fmt[58] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 60 && fmt[57] != '%' && fmt[58] == '%' && fmt[59] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 61 && fmt[58] != '%' && fmt[59] == '%' && fmt[60] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 62 && fmt[59] != '%' && fmt[60] == '%' && fmt[61] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 63 && fmt[60] != '%' && fmt[61] == '%' && fmt[62] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 64 && fmt[61] != '%' && fmt[62] == '%' && fmt[63] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 65 && fmt[62] != '%' && fmt[63] == '%' && fmt[64] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 66 && fmt[63] != '%' && fmt[64] == '%' && fmt[65] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 67 && fmt[64] != '%' && fmt[65] == '%' && fmt[66] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 68 && fmt[65] != '%' && fmt[66] == '%' && fmt[67] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 69 && fmt[66] != '%' && fmt[67] == '%' && fmt[68] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 70 && fmt[67] != '%' && fmt[68] == '%' && fmt[69] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 71 && fmt[68] != '%' && fmt[69] == '%' && fmt[70] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 72 && fmt[69] != '%' && fmt[70] == '%' && fmt[71] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 73 && fmt[70] != '%' && fmt[71] == '%' && fmt[72] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 74 && fmt[71] != '%' && fmt[72] == '%' && fmt[73] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 75 && fmt[72] != '%' && fmt[73] == '%' && fmt[74] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 76 && fmt[73] != '%' && fmt[74] == '%' && fmt[75] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 77 && fmt[74] != '%' && fmt[75] == '%' && fmt[76] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 78 && fmt[75] != '%' && fmt[76] == '%' && fmt[77] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 79 && fmt[76] != '%' && fmt[77] == '%' && fmt[78] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 80 && fmt[77] != '%' && fmt[78] == '%' && fmt[79] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 81 && fmt[78] != '%' && fmt[79] == '%' && fmt[80] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 82 && fmt[79] != '%' && fmt[80] == '%' && fmt[81] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 83 && fmt[80] != '%' && fmt[81] == '%' && fmt[82] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 84 && fmt[81] != '%' && fmt[82] == '%' && fmt[83] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 85 && fmt[82] != '%' && fmt[83] == '%' && fmt[84] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 86 && fmt[83] != '%' && fmt[84] == '%' && fmt[85] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 87 && fmt[84] != '%' && fmt[85] == '%' && fmt[86] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 88 && fmt[85] != '%' && fmt[86] == '%' && fmt[87] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 89 && fmt[86] != '%' && fmt[87] == '%' && fmt[88] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 90 && fmt[87] != '%' && fmt[88] == '%' && fmt[89] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 91 && fmt[88] != '%' && fmt[89] == '%' && fmt[90] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 92 && fmt[89] != '%' && fmt[90] == '%' && fmt[91] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 93 && fmt[90] != '%' && fmt[91] == '%' && fmt[92] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 94 && fmt[91] != '%' && fmt[92] == '%' && fmt[93] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 95 && fmt[92] != '%' && fmt[93] == '%' && fmt[94] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 96 && fmt[93] != '%' && fmt[94] == '%' && fmt[95] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 97 && fmt[94] != '%' && fmt[95] == '%' && fmt[96] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 98 && fmt[95] != '%' && fmt[96] == '%' && fmt[97] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 99 && fmt[96] != '%' && fmt[97] == '%' && fmt[98] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 100 && fmt[97] != '%' && fmt[98] == '%' && fmt[99] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 101 && fmt[98] != '%' && fmt[99] == '%' && fmt[100] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 102 && fmt[99] != '%' && fmt[100] == '%' && fmt[101] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 103 && fmt[100] != '%' && fmt[101] == '%' && fmt[102] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 104 && fmt[101] != '%' && fmt[102] == '%' && fmt[103] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 105 && fmt[102] != '%' && fmt[103] == '%' && fmt[104] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 106 && fmt[103] != '%' && fmt[104] == '%' && fmt[105] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 107 && fmt[104] != '%' && fmt[105] == '%' && fmt[106] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 108 && fmt[105] != '%' && fmt[106] == '%' && fmt[107] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 109 && fmt[106] != '%' && fmt[107] == '%' && fmt[108] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 110 && fmt[107] != '%' && fmt[108] == '%' && fmt[109] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 111 && fmt[108] != '%' && fmt[109] == '%' && fmt[110] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 112 && fmt[109] != '%' && fmt[110] == '%' && fmt[111] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 113 && fmt[110] != '%' && fmt[111] == '%' && fmt[112] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 114 && fmt[111] != '%' && fmt[112] == '%' && fmt[113] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 115 && fmt[112] != '%' && fmt[113] == '%' && fmt[114] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 116 && fmt[113] != '%' && fmt[114] == '%' && fmt[115] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 117 && fmt[114] != '%' && fmt[115] == '%' && fmt[116] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 118 && fmt[115] != '%' && fmt[116] == '%' && fmt[117] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 119 && fmt[116] != '%' && fmt[117] == '%' && fmt[118] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 120 && fmt[117] != '%' && fmt[118] == '%' && fmt[119] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 121 && fmt[118] != '%' && fmt[119] == '%' && fmt[120] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 122 && fmt[119] != '%' && fmt[120] == '%' && fmt[121] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 123 && fmt[120] != '%' && fmt[121] == '%' && fmt[122] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 124 && fmt[121] != '%' && fmt[122] == '%' && fmt[123] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 125 && fmt[122] != '%' && fmt[123] == '%' && fmt[124] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 126 && fmt[123] != '%' && fmt[124] == '%' && fmt[125] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 127 && fmt[124] != '%' && fmt[125] == '%' && fmt[126] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 128 && fmt[125] != '%' && fmt[126] == '%' && fmt[127] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 129 && fmt[126] != '%' && fmt[127] == '%' && fmt[128] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 130 && fmt[127] != '%' && fmt[128] == '%' && fmt[129] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 131 && fmt[128] != '%' && fmt[129] == '%' && fmt[130] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 132 && fmt[129] != '%' && fmt[130] == '%' && fmt[131] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 133 && fmt[130] != '%' && fmt[131] == '%' && fmt[132] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 134 && fmt[131] != '%' && fmt[132] == '%' && fmt[133] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 135 && fmt[132] != '%' && fmt[133] == '%' && fmt[134] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 136 && fmt[133] != '%' && fmt[134] == '%' && fmt[135] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 137 && fmt[134] != '%' && fmt[135] == '%' && fmt[136] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 138 && fmt[135] != '%' && fmt[136] == '%' && fmt[137] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 139 && fmt[136] != '%' && fmt[137] == '%' && fmt[138] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 140 && fmt[137] != '%' && fmt[138] == '%' && fmt[139] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 141 && fmt[138] != '%' && fmt[139] == '%' && fmt[140] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 142 && fmt[139] != '%' && fmt[140] == '%' && fmt[141] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 143 && fmt[140] != '%' && fmt[141] == '%' && fmt[142] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 144 && fmt[141] != '%' && fmt[142] == '%' && fmt[143] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 145 && fmt[142] != '%' && fmt[143] == '%' && fmt[144] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 146 && fmt[143] != '%' && fmt[144] == '%' && fmt[145] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 147 && fmt[144] != '%' && fmt[145] == '%' && fmt[146] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 148 && fmt[145] != '%' && fmt[146] == '%' && fmt[147] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 149 && fmt[146] != '%' && fmt[147] == '%' && fmt[148] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 150 && fmt[147] != '%' && fmt[148] == '%' && fmt[149] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 151 && fmt[148] != '%' && fmt[149] == '%' && fmt[150] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 152 && fmt[149] != '%' && fmt[150] == '%' && fmt[151] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 153 && fmt[150] != '%' && fmt[151] == '%' && fmt[152] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 154 && fmt[151] != '%' && fmt[152] == '%' && fmt[153] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 155 && fmt[152] != '%' && fmt[153] == '%' && fmt[154] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 156 && fmt[153] != '%' && fmt[154] == '%' && fmt[155] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 157 && fmt[154] != '%' && fmt[155] == '%' && fmt[156] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 158 && fmt[155] != '%' && fmt[156] == '%' && fmt[157] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 159 && fmt[156] != '%' && fmt[157] == '%' && fmt[158] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 160 && fmt[157] != '%' && fmt[158] == '%' && fmt[159] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 161 && fmt[158] != '%' && fmt[159] == '%' && fmt[160] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 162 && fmt[159] != '%' && fmt[160] == '%' && fmt[161] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 163 && fmt[160] != '%' && fmt[161] == '%' && fmt[162] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 164 && fmt[161] != '%' && fmt[162] == '%' && fmt[163] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 165 && fmt[162] != '%' && fmt[163] == '%' && fmt[164] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 166 && fmt[163] != '%' && fmt[164] == '%' && fmt[165] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 167 && fmt[164] != '%' && fmt[165] == '%' && fmt[166] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 168 && fmt[165] != '%' && fmt[166] == '%' && fmt[167] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 169 && fmt[166] != '%' && fmt[167] == '%' && fmt[168] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 170 && fmt[167] != '%' && fmt[168] == '%' && fmt[169] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 171 && fmt[168] != '%' && fmt[169] == '%' && fmt[170] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 172 && fmt[169] != '%' && fmt[170] == '%' && fmt[171] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 173 && fmt[170] != '%' && fmt[171] == '%' && fmt[172] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 174 && fmt[171] != '%' && fmt[172] == '%' && fmt[173] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 175 && fmt[172] != '%' && fmt[173] == '%' && fmt[174] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 176 && fmt[173] != '%' && fmt[174] == '%' && fmt[175] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 177 && fmt[174] != '%' && fmt[175] == '%' && fmt[176] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 178 && fmt[175] != '%' && fmt[176] == '%' && fmt[177] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 179 && fmt[176] != '%' && fmt[177] == '%' && fmt[178] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 180 && fmt[177] != '%' && fmt[178] == '%' && fmt[179] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 181 && fmt[178] != '%' && fmt[179] == '%' && fmt[180] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 182 && fmt[179] != '%' && fmt[180] == '%' && fmt[181] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 183 && fmt[180] != '%' && fmt[181] == '%' && fmt[182] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 184 && fmt[181] != '%' && fmt[182] == '%' && fmt[183] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 185 && fmt[182] != '%' && fmt[183] == '%' && fmt[184] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 186 && fmt[183] != '%' && fmt[184] == '%' && fmt[185] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 187 && fmt[184] != '%' && fmt[185] == '%' && fmt[186] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 188 && fmt[185] != '%' && fmt[186] == '%' && fmt[187] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 189 && fmt[186] != '%' && fmt[187] == '%' && fmt[188] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 190 && fmt[187] != '%' && fmt[188] == '%' && fmt[189] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 191 && fmt[188] != '%' && fmt[189] == '%' && fmt[190] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 192 && fmt[189] != '%' && fmt[190] == '%' && fmt[191] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 193 && fmt[190] != '%' && fmt[191] == '%' && fmt[192] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 194 && fmt[191] != '%' && fmt[192] == '%' && fmt[193] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 195 && fmt[192] != '%' && fmt[193] == '%' && fmt[194] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 196 && fmt[193] != '%' && fmt[194] == '%' && fmt[195] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 197 && fmt[194] != '%' && fmt[195] == '%' && fmt[196] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 198 && fmt[195] != '%' && fmt[196] == '%' && fmt[197] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 199 && fmt[196] != '%' && fmt[197] == '%' && fmt[198] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 200 && fmt[197] != '%' && fmt[198] == '%' && fmt[199] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 201 && fmt[198] != '%' && fmt[199] == '%' && fmt[200] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 202 && fmt[199] != '%' && fmt[200] == '%' && fmt[201] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 203 && fmt[200] != '%' && fmt[201] == '%' && fmt[202] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 204 && fmt[201] != '%' && fmt[202] == '%' && fmt[203] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 205 && fmt[202] != '%' && fmt[203] == '%' && fmt[204] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 206 && fmt[203] != '%' && fmt[204] == '%' && fmt[205] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 207 && fmt[204] != '%' && fmt[205] == '%' && fmt[206] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 208 && fmt[205] != '%' && fmt[206] == '%' && fmt[207] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 209 && fmt[206] != '%' && fmt[207] == '%' && fmt[208] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 210 && fmt[207] != '%' && fmt[208] == '%' && fmt[209] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 211 && fmt[208] != '%' && fmt[209] == '%' && fmt[210] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 212 && fmt[209] != '%' && fmt[210] == '%' && fmt[211] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 213 && fmt[210] != '%' && fmt[211] == '%' && fmt[212] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 214 && fmt[211] != '%' && fmt[212] == '%' && fmt[213] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 215 && fmt[212] != '%' && fmt[213] == '%' && fmt[214] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 216 && fmt[213] != '%' && fmt[214] == '%' && fmt[215] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 217 && fmt[214] != '%' && fmt[215] == '%' && fmt[216] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 218 && fmt[215] != '%' && fmt[216] == '%' && fmt[217] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 219 && fmt[216] != '%' && fmt[217] == '%' && fmt[218] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 220 && fmt[217] != '%' && fmt[218] == '%' && fmt[219] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 221 && fmt[218] != '%' && fmt[219] == '%' && fmt[220] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 222 && fmt[219] != '%' && fmt[220] == '%' && fmt[221] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 223 && fmt[220] != '%' && fmt[221] == '%' && fmt[222] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 224 && fmt[221] != '%' && fmt[222] == '%' && fmt[223] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 225 && fmt[222] != '%' && fmt[223] == '%' && fmt[224] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 226 && fmt[223] != '%' && fmt[224] == '%' && fmt[225] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 227 && fmt[224] != '%' && fmt[225] == '%' && fmt[226] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 228 && fmt[225] != '%' && fmt[226] == '%' && fmt[227] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 229 && fmt[226] != '%' && fmt[227] == '%' && fmt[228] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 230 && fmt[227] != '%' && fmt[228] == '%' && fmt[229] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 231 && fmt[228] != '%' && fmt[229] == '%' && fmt[230] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 232 && fmt[229] != '%' && fmt[230] == '%' && fmt[231] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 233 && fmt[230] != '%' && fmt[231] == '%' && fmt[232] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 234 && fmt[231] != '%' && fmt[232] == '%' && fmt[233] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 235 && fmt[232] != '%' && fmt[233] == '%' && fmt[234] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 236 && fmt[233] != '%' && fmt[234] == '%' && fmt[235] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 237 && fmt[234] != '%' && fmt[235] == '%' && fmt[236] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 238 && fmt[235] != '%' && fmt[236] == '%' && fmt[237] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 239 && fmt[236] != '%' && fmt[237] == '%' && fmt[238] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 240 && fmt[237] != '%' && fmt[238] == '%' && fmt[239] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 241 && fmt[238] != '%' && fmt[239] == '%' && fmt[240] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 242 && fmt[239] != '%' && fmt[240] == '%' && fmt[241] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 243 && fmt[240] != '%' && fmt[241] == '%' && fmt[242] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 244 && fmt[241] != '%' && fmt[242] == '%' && fmt[243] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 245 && fmt[242] != '%' && fmt[243] == '%' && fmt[244] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 246 && fmt[243] != '%' && fmt[244] == '%' && fmt[245] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 247 && fmt[244] != '%' && fmt[245] == '%' && fmt[246] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 248 && fmt[245] != '%' && fmt[246] == '%' && fmt[247] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 249 && fmt[246] != '%' && fmt[247] == '%' && fmt[248] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 250 && fmt[247] != '%' && fmt[248] == '%' && fmt[249] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 251 && fmt[248] != '%' && fmt[249] == '%' && fmt[250] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 252 && fmt[249] != '%' && fmt[250] == '%' && fmt[251] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 253 && fmt[250] != '%' && fmt[251] == '%' && fmt[252] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 254 && fmt[251] != '%' && fmt[252] == '%' && fmt[253] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 255 && fmt[252] != '%' && fmt[253] == '%' && fmt[254] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 256 && fmt[253] != '%' && fmt[254] == '%' && fmt[255] == 'p') ? 1 : 0) + +/** @brief Determine if all %p arguments are none character pointer arguments. + * + * Static package creation relies on the assumption that character pointers are + * only using %s arguments. To not confuse it with %p, any character pointer + * that is used with %p should be casted to a pointer of a different type, e.g. + * void *. This macro can be used to determine, at compile time, if such casting + * is missing. It is determined at compile time but cannot be used for static + * assertion so only runtime error reporting can be added. + * + * @note Macro triggers a pointer arithmetic warning and usage shall be wrapped in + * the pragma that suppresses this warning. + * + * @param ... Format string with arguments. + * + * @retval True if string is okay. + * @retval False if casting is missing. + */ +#define Z_CBPRINTF_POINTERS_VALIDATE(...) \ + (Z_CBPRINTF_NONE_CHAR_PTR_COUNT(__VA_ARGS__) == \ + Z_CBPRINTF_P_COUNT(GET_ARG_N(1, __VA_ARGS__))) + /* @brief Check if argument is a certain type of char pointer. What exectly is checked * depends on @p flags. If flags is 0 then 1 is returned if @p x is a char pointer. * From aa2e315ab0bdc259e5835d14f280036815f0eaf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 09:46:00 +0100 Subject: [PATCH 0951/1049] tests: unit: cbprintf: Add tests for string validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for Z_CBPRINTF_NONE_CHAR_PTR_COUNT, Z_CBPRINTF_P_COUNT and Z_CBPRINTF_POINTERS_VALIDATE. Signed-off-by: Krzysztof Chruściński --- tests/unit/cbprintf/main.c | 99 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/tests/unit/cbprintf/main.c b/tests/unit/cbprintf/main.c index 3d618bb9300715f..ace6aa6ff254b20 100644 --- a/tests/unit/cbprintf/main.c +++ b/tests/unit/cbprintf/main.c @@ -1338,6 +1338,105 @@ ZTEST(prf, test_nop) { } +ZTEST(prf, test_is_none_char_ptr) +{ + char c = 0; + const char cc = 0; + volatile char vc = 0; + volatile const char vcc = 0; + + unsigned char uc = 0; + const unsigned char cuc = 0; + volatile unsigned char vuc = 0; + volatile const unsigned char vcuc = 0; + + short s = 0; + unsigned short us = 0; + + int i = 0; + unsigned int ui = 0; + + long l = 0; + unsigned long ul = 0; + + long long ll = 0; + unsigned long long ull = 0; + + float f = 0.1; + double d = 0.1; + + _Pragma("GCC diagnostic push") + _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(c), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(cc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vcc), 0); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&c), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&cc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vcc), 0); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(uc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(cuc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vuc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vcuc), 0); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&uc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&cuc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vuc), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vcuc), 0); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(s), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(us), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&s), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&us), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(i), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ui), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&i), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ui), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(l), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ul), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&l), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ul), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ll), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ull), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ll), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ull), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(f), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(d), 0); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&f), 1); + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&d), 1); + + zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR((void *)&c), 1); + + _Pragma("GCC diagnostic pop") +} + +ZTEST(prf, test_p_count) +{ + zassert_equal(Z_CBPRINTF_P_COUNT("no pointers"), 0); + zassert_equal(Z_CBPRINTF_P_COUNT("no %%p pointers"), 0); + + zassert_equal(Z_CBPRINTF_P_COUNT("%d %%p %x %s %p %f"), 1); + zassert_equal(Z_CBPRINTF_P_COUNT("%p %p %llx %p "), 3); +} + +ZTEST(prf, test_pointers_validate) +{ + _Pragma("GCC diagnostic push") + _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") + zassert_equal(Z_CBPRINTF_POINTERS_VALIDATE("no arguments"), true); + /* const char fails validation */ + zassert_equal(Z_CBPRINTF_POINTERS_VALIDATE("%p", "string"), false); + zassert_equal(Z_CBPRINTF_POINTERS_VALIDATE("%p", (void *)"string"), true); + _Pragma("GCC diagnostic pop") +} + static void *cbprintf_setup(void) { if (sizeof(int) == 4) { From 465446e5aab7722b5c048280e140ae4968f06229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Tue, 21 Nov 2023 09:50:52 +0100 Subject: [PATCH 0952/1049] logging: Add string validation to detect %p misuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Logging shall not use character pointers with %p because in certain configurations it may lead to memory faults. A compile time detection is added. If faulty usage is detected then message is replaced with error message which indicates which message failed and what shall be done (casting to a pointer of different type). Validation is enabled only for configurations which remove strings from binary as otherwise it may impact CI execution time. Signed-off-by: Krzysztof Chruściński --- include/zephyr/logging/log_core.h | 30 ++++++++++++++++++++++++++++++ subsys/logging/Kconfig.misc | 9 +++++++++ 2 files changed, 39 insertions(+) diff --git a/include/zephyr/logging/log_core.h b/include/zephyr/logging/log_core.h index bc4cb2d8f362015..b18fe00c09ec7c9 100644 --- a/include/zephyr/logging/log_core.h +++ b/include/zephyr/logging/log_core.h @@ -190,6 +190,30 @@ static inline char z_log_minimal_level_to_char(int level) #define Z_LOG_INST(_inst) COND_CODE_1(CONFIG_LOG, (_inst), NULL) +/* If strings are removed from the binary then there is a risk of creating invalid + * cbprintf package if %p is used with character pointer which is interpreted as + * string. A compile time check is performed (since format string is known at + * compile time) and check fails logging message is not created but error is + * emitted instead. String check may increase compilation time so it is not + * always performed (could significantly increase CI time). + */ +#if CONFIG_LOG_FMT_STRING_VALIDATE +#define LOG_STRING_WARNING(_mode, _src, ...) \ + Z_LOG_MSG_CREATE(UTIL_NOT(IS_ENABLED(CONFIG_USERSPACE)), _mode, \ + Z_LOG_LOCAL_DOMAIN_ID, _src, LOG_LEVEL_ERR, NULL, 0, \ + "char pointer used for %%p, cast to void *:\"%s\"", \ + GET_ARG_N(1, __VA_ARGS__)) + +#define LOG_POINTERS_VALIDATE(string_ok, ...) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") \ + string_ok = Z_CBPRINTF_POINTERS_VALIDATE(__VA_ARGS__); \ + _Pragma("GCC diagnostic pop") +#else +#define LOG_POINTERS_VALIDATE(string_ok, ...) string_ok = true +#define LOG_STRING_WARNING(_mode, _src, ...) +#endif + /*****************************************************************************/ /****************** Macros for standard logging ******************************/ /*****************************************************************************/ @@ -234,6 +258,12 @@ static inline char z_log_minimal_level_to_char(int level) int _mode; \ void *_src = IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) ? \ (void *)_dsource : (void *)_source; \ + bool string_ok; \ + LOG_POINTERS_VALIDATE(string_ok, __VA_ARGS__); \ + if (!string_ok) { \ + LOG_STRING_WARNING(_mode, _src, __VA_ARGS__); \ + break; \ + } \ Z_LOG_MSG_CREATE(UTIL_NOT(IS_ENABLED(CONFIG_USERSPACE)), _mode, \ Z_LOG_LOCAL_DOMAIN_ID, _src, _level, NULL,\ 0, __VA_ARGS__); \ diff --git a/subsys/logging/Kconfig.misc b/subsys/logging/Kconfig.misc index ce34bdae0a03d33..4b2d9fa143cf5d3 100644 --- a/subsys/logging/Kconfig.misc +++ b/subsys/logging/Kconfig.misc @@ -70,6 +70,15 @@ config LOG_FMT_SECTION_STRIP depends on LOG_FMT_SECTION depends on LINKER_DEVNULL_SUPPORT imply LINKER_DEVNULL_MEMORY + imply LOG_FMT_STRING_VALIDATE + +config LOG_FMT_STRING_VALIDATE + bool "Validate logging strings" + help + Logging strings cannot use %p with character pointers. They should be + casted to the pointer of another type (e.g. void *). With this feature + enabled, at compile time, the preprocessor detects strings with %p + without casting and reports an error at runtime. config LOG_USE_TAGGED_ARGUMENTS bool "Using tagged arguments for packaging" From 8342d87478b55cb10bc10cdcd4128f9dc02da29a Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 22 Nov 2023 22:10:15 +0800 Subject: [PATCH 0953/1049] drivers: intc: plic: brackets for if-conds & use explicit comparison if-conditionals should have brackets according to Zephyr's coding standard, and explicitly compares `edge_irq` against 0. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 51ce17693969335..c41610a46d00d5d 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -271,8 +271,9 @@ static void plic_irq_handler(const struct device *dev) * If the IRQ is out of range, call z_irq_spurious. * A call to z_irq_spurious will not return. */ - if (local_irq == 0U || local_irq >= config->num_irqs) + if (local_irq == 0U || local_irq >= config->num_irqs) { z_irq_spurious(NULL); + } edge_irq = riscv_plic_is_edge_irq(dev, local_irq); @@ -281,8 +282,9 @@ static void plic_irq_handler(const struct device *dev) * to indicate to the PLIC controller that the IRQ has been handled * for edge triggered interrupts. */ - if (edge_irq) + if (edge_irq != 0) { sys_write32(local_irq, claim_complete_addr); + } const uint32_t parent_irq = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), (z_get_sw_isr_irq_from_device(dev)), (0U)); @@ -300,8 +302,9 @@ static void plic_irq_handler(const struct device *dev) * PLIC controller that the IRQ has been handled * for level triggered interrupts. */ - if (!edge_irq) + if (edge_irq == 0) { sys_write32(local_irq, claim_complete_addr); + } } /** From e9fa6f8b4a339bb0b6e89ed90b3d103d9ce05284 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 21 Nov 2023 22:53:01 +0800 Subject: [PATCH 0954/1049] drivers: intc: plic: add shell cmd to get irq stats for debugging Introduced `CONFIG_PLIC_SHELL` to enable the build of shell debugging command to get the hit count of each interrupt controller's IRQ line. This is especially useful when working with dynamically installed ISRs, which will be the case for `plic_sw`. Example usage: ``` uart:~$ plic stats get interrupt-controller@c000000 IRQ Hits ================== 10 177 uart:~$ plic stats get interrupt-controller@c000000 IRQ Hits ================== 10 236 uart:~$ plic stats clear interrupt-controller@c000000 Cleared stats of interrupt-controller@c000000. uart:~$ plic stats get interrupt-controller@c000000 IRQ Hits ================== 10 90 ``` Signed-off-by: Yong Cong Sin Signed-off-by: Maxim Adelman --- drivers/interrupt_controller/CMakeLists.txt | 7 + drivers/interrupt_controller/Kconfig.plic | 11 ++ drivers/interrupt_controller/intc_plic.c | 148 +++++++++++++++++++- 3 files changed, 165 insertions(+), 1 deletion(-) diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 5598d038940a802..7ef0a5e161e9c45 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -42,4 +42,11 @@ if(CONFIG_INTEL_VTD_ICTL) zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include) endif() +if(CONFIG_PLIC_SHELL) + message(WARNING " + WARNING: `CONFIG_PLIC_SHELL` is enabled. + This can use quite a bit of RAM (PLICs * IRQs * sizeof(uint16_t))" + ) +endif() + zephyr_library_include_directories(${ZEPHYR_BASE}/arch/common/include) diff --git a/drivers/interrupt_controller/Kconfig.plic b/drivers/interrupt_controller/Kconfig.plic index c1e16c7c1c554d6..d4f91a3fbd22f20 100644 --- a/drivers/interrupt_controller/Kconfig.plic +++ b/drivers/interrupt_controller/Kconfig.plic @@ -10,3 +10,14 @@ config PLIC help Platform Level Interrupt Controller provides support for external interrupt lines defined by the RISC-V SoC. + +if PLIC + +config PLIC_SHELL + bool "PLIC shell commands" + depends on SHELL + help + Enable additional shell commands useful for debugging. + Caution: This can use quite a bit of RAM (PLICs * IRQs * sizeof(uint16_t)). + +endif # PLIC diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index c41610a46d00d5d..d05d28b88340534 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -13,11 +13,14 @@ * for RISC-V processors */ +#include + #include "sw_isr_common.h" #include #include #include +#include #include #include @@ -62,6 +65,14 @@ struct plic_config { riscv_plic_irq_config_func_t irq_config_func; }; +struct plic_stats { + uint16_t *irq_count; +}; + +struct plic_data { + struct plic_stats stats; +}; + static uint32_t save_irq; static const struct device *save_dev; @@ -258,6 +269,16 @@ static void plic_irq_handler(const struct device *dev) /* Get the IRQ number generating the interrupt */ const uint32_t local_irq = sys_read32(claim_complete_addr); +#ifdef CONFIG_PLIC_SHELL + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; + + /* Cap the count at __UINT16_MAX__ */ + if (stat.irq_count[local_irq] != __UINT16_MAX__) { + stat.irq_count[local_irq]++; + } +#endif /* CONFIG_PLIC_SHELL */ + /* * Save IRQ in save_irq. To be used, if need be, by * subsequent handlers registered in the _sw_isr_table table, @@ -340,6 +361,130 @@ static int plic_init(const struct device *dev) return 0; } +#ifdef CONFIG_PLIC_SHELL +static inline int parse_device(const struct shell *sh, size_t argc, char *argv[], + const struct device **plic) +{ + ARG_UNUSED(argc); + + *plic = device_get_binding(argv[1]); + if (*plic == NULL) { + shell_error(sh, "PLIC device (%s) not found!\n", argv[1]); + return -ENODEV; + } + + return 0; +} + +static int cmd_get_stats(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret = parse_device(sh, argc, argv, &dev); + uint16_t min_hit = 0; + + if (ret != 0) { + return ret; + } + + const struct plic_config *config = dev->config; + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; + + if (argc > 2) { + min_hit = (uint16_t)atoi(argv[2]); + shell_print(sh, "IRQ line with > %d hits:", min_hit); + } + + shell_print(sh, " IRQ\t Hits"); + shell_print(sh, "=================="); + for (size_t i = 0; i < MIN(config->num_irqs, CONFIG_MAX_IRQ_PER_AGGREGATOR); i++) { + if (stat.irq_count[i] > min_hit) { + shell_print(sh, "%6d\t%10d", i, stat.irq_count[i]); + } + } + shell_print(sh, ""); + + return 0; +} + +static int cmd_clear_stats(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret = parse_device(sh, argc, argv, &dev); + + if (ret != 0) { + return ret; + } + + const struct plic_config *config = dev->config; + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; + + memset(stat.irq_count, 0, + MIN(config->num_irqs, CONFIG_MAX_IRQ_PER_AGGREGATOR) * sizeof(uint16_t)); + + shell_print(sh, "Cleared stats of %s.\n", dev->name); + + return 0; +} + +/* Device name autocompletion support */ +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, NULL); + + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); + +SHELL_STATIC_SUBCMD_SET_CREATE(plic_stats_cmds, + SHELL_CMD_ARG(get, &dsub_device_name, + "Read PLIC's stats.\n" + "Usage: plic stats get [minimum hits]", + cmd_get_stats, 2, 1), + SHELL_CMD_ARG(clear, &dsub_device_name, + "Reset PLIC's stats.\n" + "Usage: plic stats clear ", + cmd_clear_stats, 2, 0), + SHELL_SUBCMD_SET_END +); + +SHELL_STATIC_SUBCMD_SET_CREATE(plic_cmds, + SHELL_CMD_ARG(stats, &plic_stats_cmds, "PLIC stats", NULL, 3, 0), + SHELL_SUBCMD_SET_END +); + +static int cmd_plic(const struct shell *sh, size_t argc, char **argv) +{ + shell_error(sh, "%s:unknown parameter: %s", argv[0], argv[1]); + return -EINVAL; +} + +SHELL_CMD_ARG_REGISTER(plic, &plic_cmds, "PLIC shell commands", + cmd_plic, 2, 0); + +#define PLIC_INTC_IRQ_COUNT_BUF_DEFINE(n) \ + static uint16_t local_irq_count_##n[MIN(DT_INST_PROP(n, riscv_ndev), \ + CONFIG_MAX_IRQ_PER_AGGREGATOR)]; + +#define PLIC_INTC_DATA_INIT(n) \ + PLIC_INTC_IRQ_COUNT_BUF_DEFINE(n); \ + static struct plic_data plic_data_##n = { \ + .stats = { \ + .irq_count = local_irq_count_##n, \ + }, \ + }; + +#define PLIC_INTC_DATA(n) &plic_data_##n +#else +#define PLIC_INTC_DATA_INIT(...) +#define PLIC_INTC_DATA(n) (NULL) +#endif + #define PLIC_INTC_IRQ_FUNC_DECLARE(n) static void plic_irq_config_func_##n(void) #define PLIC_INTC_IRQ_FUNC_DEFINE(n) \ @@ -364,8 +509,9 @@ static int plic_init(const struct device *dev) #define PLIC_INTC_DEVICE_INIT(n) \ PLIC_INTC_CONFIG_INIT(n) \ + PLIC_INTC_DATA_INIT(n) \ DEVICE_DT_INST_DEFINE(n, &plic_init, NULL, \ - NULL, &plic_config_##n, \ + PLIC_INTC_DATA(n), &plic_config_##n, \ PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, \ NULL); From 88d91fb82f3891c4efe661b0430522442ac2f936 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Tue, 21 Nov 2023 17:01:01 +0100 Subject: [PATCH 0955/1049] drivers/sensor: lsm6dsv16x: fix DT configuration read for int1/int2 Since lsm6dsv16x may be multi-instantiated, triggers must be enabled and configured on DT basis and not only thru CONFIG_LSM6DSV16X_TRIGGER macro; if either int1-gpios of int2-gpios (or both) are configured in DT, the flag trig_enable is set to 'true' for that instance. The previous implentation was lacking the check of those two Device Tree properties, so trig_enabled was always true for all instances. Signed-off-by: Armando Visconti --- drivers/sensor/lsm6dsv16x/lsm6dsv16x.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c index f7d53bc0b9362d4..e507a2165b0d964 100644 --- a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c @@ -923,6 +923,7 @@ static int lsm6dsv16x_init(const struct device *dev) .trig_enabled = true, \ .int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, { 0 }), \ .int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, { 0 }), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ .drdy_pin = DT_INST_PROP(inst, drdy_pin) #else #define LSM6DSV16X_CFG_IRQ(inst) @@ -938,8 +939,9 @@ static int lsm6dsv16x_init(const struct device *dev) .accel_range = DT_INST_PROP(inst, accel_range), \ .gyro_odr = DT_INST_PROP(inst, gyro_odr), \ .gyro_range = DT_INST_PROP(inst, gyro_range), \ - .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ - LSM6DSV16X_CFG_IRQ(inst) + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LSM6DSV16X_CFG_IRQ(inst))) #define LSM6DSV16X_CONFIG_SPI(inst) \ { \ From 05df6830b73dc2c36212929f9e9577c54d310dba Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Wed, 15 Nov 2023 17:47:31 -0300 Subject: [PATCH 0956/1049] boards: dts: add missing code partition into ESP32 based boards zephyr,code-partition added to ESP32 based board files Signed-off-by: Marcio Ribeiro --- boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts | 1 + boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts | 1 + boards/riscv/icev_wireless/icev_wireless.dts | 1 + boards/riscv/stamp_c3/stamp_c3.dts | 1 + boards/riscv/xiao_esp32c3/xiao_esp32c3.dts | 1 + boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts | 1 + boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts | 1 + boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts | 1 + boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts | 1 + boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts | 1 + boards/xtensa/esp32s2_saola/esp32s2_saola.dts | 1 + boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts | 1 + boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts | 1 + boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts | 1 + boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts | 1 + .../heltec_wireless_stick_lite_v3.dts | 1 + boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts | 1 + boards/xtensa/m5stickc_plus/m5stickc_plus.dts | 1 + boards/xtensa/odroid_go/odroid_go.dts | 1 + boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts | 1 + boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts | 1 + boards/xtensa/yd_esp32/yd_esp32.dts | 1 + 22 files changed, 22 insertions(+) diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts index 60cfdea523a2ed8..6c390956e4894aa 100644 --- a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts +++ b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts @@ -19,6 +19,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts b/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts index 5a74be9984ec804..00a6983355781fd 100644 --- a/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts +++ b/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts @@ -14,5 +14,6 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/riscv/icev_wireless/icev_wireless.dts b/boards/riscv/icev_wireless/icev_wireless.dts index 998ce4c0bc3d3c7..1e5719fe2aaa109 100644 --- a/boards/riscv/icev_wireless/icev_wireless.dts +++ b/boards/riscv/icev_wireless/icev_wireless.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/riscv/stamp_c3/stamp_c3.dts b/boards/riscv/stamp_c3/stamp_c3.dts index 029ae49b1987f68..56353da3d8135cf 100644 --- a/boards/riscv/stamp_c3/stamp_c3.dts +++ b/boards/riscv/stamp_c3/stamp_c3.dts @@ -19,6 +19,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts index 45823b069c8b8a4..5cea1004af625ef 100644 --- a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts +++ b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,canbus = &twai; }; diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts index 6fa0bf47f61d5d2..ef6d619676cc130 100644 --- a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts @@ -34,6 +34,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts index 43218f3e81ffda5..d4cbdce3d901eeb 100644 --- a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts @@ -34,6 +34,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts index 3139e8beaa30aa7..50b01b88b2f58ff 100644 --- a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts +++ b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts @@ -22,6 +22,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts index 66c8560609747bb..2ce35ee55342831 100644 --- a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts +++ b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts @@ -25,6 +25,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { diff --git a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts index 9f90447560b39b7..3ce00f8bdb8c223 100644 --- a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts +++ b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts @@ -25,6 +25,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { diff --git a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts index 7a5c4fb087a551d..61787f0051a0cb7 100644 --- a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts +++ b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts @@ -25,6 +25,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; gpio_keys { diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts index f7c75b120176e51..5d80b0619e92edc 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts @@ -23,6 +23,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts b/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts index 89bebe9018cb54d..fea76fca3b7a010 100644 --- a/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts +++ b/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts @@ -25,5 +25,6 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts index 54ded2ac1b345cd..f5d366e0313c591 100644 --- a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts +++ b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts @@ -32,6 +32,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,display = &ili9341; }; diff --git a/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts b/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts index 5fd323082a30f6f..636f1afd3543179 100644 --- a/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts +++ b/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts @@ -54,6 +54,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts index c91564a303f5d35..9a23a008c2f2453 100644 --- a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts @@ -71,6 +71,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts index abbff8bbbfdab46..72ebd81b42fe94a 100644 --- a/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,display = &st7789v; }; diff --git a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts index 8cdd4170ba5ebd0..6737973adae5102 100644 --- a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts +++ b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts @@ -27,6 +27,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { diff --git a/boards/xtensa/odroid_go/odroid_go.dts b/boards/xtensa/odroid_go/odroid_go.dts index 0a868adc2a3a92f..458a8251b1c79c8 100644 --- a/boards/xtensa/odroid_go/odroid_go.dts +++ b/boards/xtensa/odroid_go/odroid_go.dts @@ -18,6 +18,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,display = &ili9341; }; diff --git a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts index 0abf7d7128ef2be..11747f1a7b6e91a 100644 --- a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts +++ b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts @@ -19,6 +19,7 @@ zephyr,shell-uart = &uart0; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts index ecd7814bb6b5312..a4592b26bce2a91 100644 --- a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/xtensa/yd_esp32/yd_esp32.dts b/boards/xtensa/yd_esp32/yd_esp32.dts index 3995788beb27a30..9442e5009e45cfd 100644 --- a/boards/xtensa/yd_esp32/yd_esp32.dts +++ b/boards/xtensa/yd_esp32/yd_esp32.dts @@ -34,6 +34,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; From 86cf5829a49085a3a58426054cce5639833810ff Mon Sep 17 00:00:00 2001 From: Martin Gritzan Date: Wed, 22 Nov 2023 09:25:37 +0100 Subject: [PATCH 0957/1049] dts: arm: stm32: add stm32f303xb bindings The STM32F303xB is very similar to the xC, the only difference being the RAM and flash sizes. Signed-off-by: Martin Gritzan --- dts/arm/st/f3/stm32f303Xb.dtsi | 45 +++++++++++++++++++ dts/arm/st/f3/stm32f303Xc.dtsi | 43 +++--------------- .../stm32f3/Kconfig.defconfig.stm32f303x(b-c) | 16 +++++++ .../stm32f3/Kconfig.defconfig.stm32f303xc | 14 ------ soc/arm/st_stm32/stm32f3/Kconfig.soc | 4 ++ 5 files changed, 72 insertions(+), 50 deletions(-) create mode 100644 dts/arm/st/f3/stm32f303Xb.dtsi create mode 100644 soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) delete mode 100644 soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc diff --git a/dts/arm/st/f3/stm32f303Xb.dtsi b/dts/arm/st/f3/stm32f303Xb.dtsi new file mode 100644 index 000000000000000..040566c0b2298fb --- /dev/null +++ b/dts/arm/st/f3/stm32f303Xb.dtsi @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Martin Gritzan + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + ccm0: memory@10000000 { + compatible = "zephyr,memory-region", "st,stm32-ccm"; + reg = <0x10000000 DT_SIZE_K(8)>; + zephyr,memory-region = "CCM"; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(128)>; + }; + }; + + dma2: dma@40020400 { + compatible = "st,stm32-dma-v2bis"; + #dma-cells = <2>; + reg = <0x40020400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x2>; + interrupts = <56 0 57 0 58 0 59 0 60 0>; + status = "disabled"; + }; + + rtc@40002800 { + bbram: backup_regs { + compatible = "st,stm32-bbram"; + st,backup-regs = <16>; + status = "disabled"; + }; + }; + }; +}; diff --git a/dts/arm/st/f3/stm32f303Xc.dtsi b/dts/arm/st/f3/stm32f303Xc.dtsi index fd857c1a8fde941..76131f723490cc6 100644 --- a/dts/arm/st/f3/stm32f303Xc.dtsi +++ b/dts/arm/st/f3/stm32f303Xc.dtsi @@ -1,45 +1,16 @@ /* - * Copyright (c) 2018 Linaro Limited + * Copyright (c) 2023 Martin Gritzan * * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include -/ { - ccm0: memory@10000000 { - compatible = "zephyr,memory-region", "st,stm32-ccm"; - reg = <0x10000000 DT_SIZE_K(8)>; - zephyr,memory-region = "CCM"; - }; - - sram0: memory@20000000 { - reg = <0x20000000 DT_SIZE_K(40)>; - }; - - soc { - flash-controller@40022000 { - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(256)>; - }; - }; - - dma2: dma@40020400 { - compatible = "st,stm32-dma-v2bis"; - #dma-cells = <2>; - reg = <0x40020400 0x400>; - clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x2>; - interrupts = <56 0 57 0 58 0 59 0 60 0>; - status = "disabled"; - }; +&sram0 { + reg = <0x20000000 DT_SIZE_K(40)>; +}; - rtc@40002800 { - bbram: backup_regs { - compatible = "st,stm32-bbram"; - st,backup-regs = <16>; - status = "disabled"; - }; - }; - }; +&flash0 { + reg = <0x08000000 DT_SIZE_K(256)>; }; diff --git a/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) b/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) new file mode 100644 index 000000000000000..752bef896908127 --- /dev/null +++ b/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) @@ -0,0 +1,16 @@ +# ST Microelectronics STM32F303XC MCU + +# Copyright (c) 2016 RnDity Sp. z o.o. +# SPDX-License-Identifier: Apache-2.0 + +# The HAL expects STM32F302XC to be defined for both the xB and xC variants (only RAM- and Flash- +# size differ). +if SOC_STM32F303XB || SOC_STM32F303XC + +config SOC + default "stm32f303xc" + +config NUM_IRQS + default 82 + +endif # SOC_STM32F303XB || SOC_STM32F303XC diff --git a/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc b/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc deleted file mode 100644 index 875ed373a69624a..000000000000000 --- a/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc +++ /dev/null @@ -1,14 +0,0 @@ -# ST Microelectronics STM32F303XC MCU - -# Copyright (c) 2016 RnDity Sp. z o.o. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_STM32F303XC - -config SOC - default "stm32f303xc" - -config NUM_IRQS - default 82 - -endif # SOC_STM32F303XC diff --git a/soc/arm/st_stm32/stm32f3/Kconfig.soc b/soc/arm/st_stm32/stm32f3/Kconfig.soc index 6dde4dfd8cfad13..20af2538ba52720 100644 --- a/soc/arm/st_stm32/stm32f3/Kconfig.soc +++ b/soc/arm/st_stm32/stm32f3/Kconfig.soc @@ -17,6 +17,10 @@ config SOC_STM32F302XC config SOC_STM32F303X8 bool "STM32F303X8" +config SOC_STM32F303XB + bool "STM32F303XB" + select CPU_HAS_ARM_MPU + config SOC_STM32F303XC bool "STM32F303XC" select CPU_HAS_ARM_MPU From 0bad09c7faec98ccfb01326896fc3032f466147c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Ciupis?= Date: Wed, 22 Nov 2023 09:56:03 +0100 Subject: [PATCH 0958/1049] drivers: ieee802154: nrf5: support raw mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_IEEE802154_RAW_MODE is set there is no network interface that could provide pointer to the device the interface is running on top of. The current implementation of nRF5 ieee802154 driver implicitly assumes that such an interface is always present, which leads to crashes when raw mode is enabled. This commit adds support for IEEE802154_RAW_MODE in nRF5 ieee802154 driver by latching pointer to the ieee802154 device on initialization if needed so that it doesn't have to be retrieved using the network interface in run-time. Signed-off-by: Jędrzej Ciupis --- drivers/ieee802154/ieee802154_nrf5.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 2b7d9b8fb6d3a1f..dd32f6333649287 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -57,6 +57,9 @@ struct nrf5_802154_config { }; static struct nrf5_802154_data nrf5_data; +#if defined(CONFIG_IEEE802154_RAW_MODE) +static const struct device *nrf5_dev; +#endif #define DRX_SLOT_RX 0 /* Delayed reception window ID */ @@ -95,6 +98,15 @@ static struct nrf5_802154_data nrf5_data; #define IEEE802154_NRF5_VENDOR_OUI (uint32_t)0xF4CE36 #endif +static inline const struct device *nrf5_get_device(void) +{ +#if defined(CONFIG_IEEE802154_RAW_MODE) + return nrf5_dev; +#else + return net_if_get_device(nrf5_data.iface); +#endif +} + static void nrf5_get_eui64(uint8_t *mac) { uint64_t factoryAddress; @@ -726,6 +738,9 @@ static int nrf5_init(const struct device *dev) { const struct nrf5_802154_config *nrf5_radio_cfg = NRF5_802154_CFG(dev); struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); +#if defined(CONFIG_IEEE802154_RAW_MODE) + nrf5_dev = dev; +#endif k_fifo_init(&nrf5_radio->rx_fifo); k_sem_init(&nrf5_radio->tx_wait, 0, 1); @@ -1046,7 +1061,7 @@ void nrf_802154_received_timestamp_raw(uint8_t *data, int8_t power, uint8_t lqi, void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { - const struct device *dev = net_if_get_device(nrf5_data.iface); + const struct device *dev = nrf5_get_device(); #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) if (id == DRX_SLOT_RX) { @@ -1165,7 +1180,7 @@ void nrf_802154_energy_detected(const nrf_802154_energy_detected_t *result) energy_scan_done_cb_t callback = nrf5_data.energy_scan_done; nrf5_data.energy_scan_done = NULL; - callback(net_if_get_device(nrf5_data.iface), result->ed_dbm); + callback(nrf5_get_device(), result->ed_dbm); } } @@ -1175,7 +1190,7 @@ void nrf_802154_energy_detection_failed(nrf_802154_ed_error_t error) energy_scan_done_cb_t callback = nrf5_data.energy_scan_done; nrf5_data.energy_scan_done = NULL; - callback(net_if_get_device(nrf5_data.iface), SHRT_MAX); + callback(nrf5_get_device(), SHRT_MAX); } } From 1378c90a938e651bd3f000505d3388a4134f2a9f Mon Sep 17 00:00:00 2001 From: Arnaud MAZIN Date: Wed, 22 Nov 2023 10:07:21 +0100 Subject: [PATCH 0959/1049] driver: display: sdl: Introduce SDL_DISPLAY_ZOOM_PCT This option modifies SDL window size and help with readability of very small screens Signed-off-by: Arnaud MAZIN --- drivers/display/Kconfig.sdl | 7 +++++++ drivers/display/display_sdl.c | 6 ++++-- drivers/display/display_sdl_bottom.c | 6 +++--- drivers/display/display_sdl_bottom.h | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/display/Kconfig.sdl b/drivers/display/Kconfig.sdl index a06b143f31ed4df..5bf18115a3389c7 100644 --- a/drivers/display/Kconfig.sdl +++ b/drivers/display/Kconfig.sdl @@ -39,4 +39,11 @@ choice SDL_DISPLAY_DEFAULT_PIXEL_FORMAT endchoice +config SDL_DISPLAY_ZOOM_PCT + int "Default zoom percentage" + default 100 + range 10 10000 + help + SDL window zoom percentage to adjust readability on small screens + endif # SDL_DISPLAY diff --git a/drivers/display/display_sdl.c b/drivers/display/display_sdl.c index 2a457249edede40..b813ee348722181 100644 --- a/drivers/display/display_sdl.c +++ b/drivers/display/display_sdl.c @@ -54,8 +54,10 @@ static int sdl_display_init(const struct device *dev) #endif /* SDL_DISPLAY_DEFAULT_PIXEL_FORMAT */ ; - int rc = sdl_display_init_bottom(config->height, config->width, &disp_data->window, - &disp_data->renderer, &disp_data->texture); + int rc = sdl_display_init_bottom(config->height, config->width, + CONFIG_SDL_DISPLAY_ZOOM_PCT, + &disp_data->window, &disp_data->renderer, + &disp_data->texture); if (rc != 0) { LOG_ERR("Failed to create SDL display"); diff --git a/drivers/display/display_sdl_bottom.c b/drivers/display/display_sdl_bottom.c index a7ad1929f4ea969..92c09f36fcd9b64 100644 --- a/drivers/display/display_sdl_bottom.c +++ b/drivers/display/display_sdl_bottom.c @@ -11,12 +11,12 @@ #include #include "nsi_tracing.h" -int sdl_display_init_bottom(uint16_t height, uint16_t width, +int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, void **window, void **renderer, void **texture) { *window = SDL_CreateWindow("Zephyr Display", SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, width, - height, SDL_WINDOW_SHOWN); + SDL_WINDOWPOS_UNDEFINED, width * zoom_pct / 100, + height * zoom_pct / 100, SDL_WINDOW_SHOWN); if (*window == NULL) { nsi_print_warning("Failed to create SDL window: %s", SDL_GetError()); return -1; diff --git a/drivers/display/display_sdl_bottom.h b/drivers/display/display_sdl_bottom.h index 91ea890c13b4d9c..d60c8b15f403288 100644 --- a/drivers/display/display_sdl_bottom.h +++ b/drivers/display/display_sdl_bottom.h @@ -20,7 +20,7 @@ extern "C" { /* Note: None of these functions are public interfaces. But internal to the SDL display driver */ -int sdl_display_init_bottom(uint16_t height, uint16_t width, +int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, void **window, void **renderer, void **texture); void sdl_display_write_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, From d1fc5fe2aeb20bcecfe55734be3c989c220ed56f Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 22 Nov 2023 18:12:06 +0800 Subject: [PATCH 0960/1049] boards: riscv: hifive_unmatched: add Renode simulation support Add Renode simulation support for `hifive_unmatched`, the script is basically copied over from `hifive_unleashed`, with very minor edits. Signed-off-by: Yong Cong Sin --- boards/riscv/hifive_unmatched/board.cmake | 4 +++ .../support/hifive_unmatched.resc | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 boards/riscv/hifive_unmatched/support/hifive_unmatched.resc diff --git a/boards/riscv/hifive_unmatched/board.cmake b/boards/riscv/hifive_unmatched/board.cmake index c985f2d7bcafce8..56fe497dd2a3e3c 100644 --- a/boards/riscv/hifive_unmatched/board.cmake +++ b/boards/riscv/hifive_unmatched/board.cmake @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 +set(SUPPORTED_EMU_PLATFORMS renode) +set(RENODE_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/support/hifive_unmatched.resc) +set(RENODE_UART sysbus.uart0) + set(OPENOCD_USE_LOAD_IMAGE NO) board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_hifive_unmatched.cfg") diff --git a/boards/riscv/hifive_unmatched/support/hifive_unmatched.resc b/boards/riscv/hifive_unmatched/support/hifive_unmatched.resc new file mode 100644 index 000000000000000..535bb06c69cea31 --- /dev/null +++ b/boards/riscv/hifive_unmatched/support/hifive_unmatched.resc @@ -0,0 +1,25 @@ +:description: This script is prepared to run Zephyr on SiFive-FU740 board. +:name: SiFive-FU740 + +$name?="SiFive-FU740" + +using sysbus +mach create $name + +set platform +""" +using "platforms/cpus/sifive-fu740.repl" + +clint: + frequency: 10000000 +""" + +machine LoadPlatformDescriptionFromString $platform +machine PyDevFromFile @scripts/pydev/flipflop.py 0x10000000 0x100 True +showAnalyzer uart0 + +macro reset +""" + sysbus LoadELF $bin +""" +runMacro $reset From b39816a1117157733ff64b213184e74d6bf45194 Mon Sep 17 00:00:00 2001 From: Wojciech Slenska Date: Wed, 22 Nov 2023 14:00:54 +0100 Subject: [PATCH 0961/1049] drivers: i2c: stm32: fix compilation for PM_DEVICE_RUNTIME Added clk variable which is needed when CONFIG_PM_DEVICE_RUNTIME is enabled. Signed-off-by: Wojciech Slenska --- drivers/i2c/i2c_ll_stm32.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c index 2fcb1f8e931ba59..552acfb6ab2ec37 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -62,20 +62,19 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config) { const struct i2c_stm32_config *cfg = dev->config; struct i2c_stm32_data *data = dev->data; + const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); I2C_TypeDef *i2c = cfg->i2c; uint32_t i2c_clock = 0U; int ret; if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) { - if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t)&cfg->pclken[1], + if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1], &i2c_clock) < 0) { LOG_ERR("Failed call clock_control_get_rate(pclken[1])"); return -EIO; } } else { - if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t) &cfg->pclken[0], + if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0], &i2c_clock) < 0) { LOG_ERR("Failed call clock_control_get_rate(pclken[0])"); return -EIO; From 60dc8dd410de079cce76f6708f5afa2422811095 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Wed, 22 Nov 2023 14:37:03 +0100 Subject: [PATCH 0962/1049] boards: Use unique names for boards in the YAML files There are duplicated names specified in per-board YAML files. This change will allow distinguishing boards in software that presents the pretty names and not the raw names of boards. Signed-off-by: Wojciech Sipak --- boards/arc/emsdp/emsdp.yaml | 2 +- boards/arc/emsdp/emsdp_em4.yaml | 2 +- boards/arc/emsdp/emsdp_em5d.yaml | 2 +- boards/arc/emsdp/emsdp_em6.yaml | 2 +- boards/arc/emsdp/emsdp_em7d.yaml | 2 +- boards/arc/emsdp/emsdp_em7d_esp.yaml | 2 +- boards/arc/emsdp/emsdp_em9d.yaml | 2 +- boards/arc/nsim/nsim_em7d_v22.yaml | 2 +- boards/arc/nsim/nsim_hs5x_smp_12cores.yaml | 2 +- boards/arc/nsim/nsim_hs6x_smp_12cores.yaml | 2 +- boards/arc/nsim/nsim_hs_flash_xip.yaml | 2 +- boards/arc/nsim/nsim_hs_sram.yaml | 2 +- boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml | 2 +- boards/arc/qemu_arc/qemu_arc_hs6x.yaml | 2 +- boards/arc/qemu_arc/qemu_arc_hs_xip.yaml | 2 +- .../fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml | 2 +- boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml | 2 +- boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml | 2 +- .../fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml | 2 +- boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml | 2 +- boards/mips/qemu_malta/qemu_malta.yaml | 2 +- boards/mips/qemu_malta/qemu_malta_be.yaml | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/boards/arc/emsdp/emsdp.yaml b/boards/arc/emsdp/emsdp.yaml index b6fa38fb5153d64..c5a9afc8da410c2 100644 --- a/boards/arc/emsdp/emsdp.yaml +++ b/boards/arc/emsdp/emsdp.yaml @@ -1,5 +1,5 @@ identifier: emsdp -name: EM Software Development Platform +name: EM Software Development Platform (EM11D) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em4.yaml b/boards/arc/emsdp/emsdp_em4.yaml index a146eb72bff46cb..9be5bbca31b830e 100644 --- a/boards/arc/emsdp/emsdp_em4.yaml +++ b/boards/arc/emsdp/emsdp_em4.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em4 -name: EM Software Development Platform +name: EM Software Development Platform (EM4) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em5d.yaml b/boards/arc/emsdp/emsdp_em5d.yaml index d0117790975a736..80cbc08e0661529 100644 --- a/boards/arc/emsdp/emsdp_em5d.yaml +++ b/boards/arc/emsdp/emsdp_em5d.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em5d -name: EM Software Development Platform +name: EM Software Development Platform (EM5D) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em6.yaml b/boards/arc/emsdp/emsdp_em6.yaml index 2584fb8a953ee50..ce15754d7be645e 100644 --- a/boards/arc/emsdp/emsdp_em6.yaml +++ b/boards/arc/emsdp/emsdp_em6.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em6 -name: EM Software Development Platform +name: EM Software Development Platform (EM6) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em7d.yaml b/boards/arc/emsdp/emsdp_em7d.yaml index 57f78c3c7e766e4..e3591d300f54401 100644 --- a/boards/arc/emsdp/emsdp_em7d.yaml +++ b/boards/arc/emsdp/emsdp_em7d.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em7d -name: EM Software Development Platform +name: EM Software Development Platform (EM7D) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em7d_esp.yaml b/boards/arc/emsdp/emsdp_em7d_esp.yaml index e3387d647988be1..2b8cc296bb893a5 100644 --- a/boards/arc/emsdp/emsdp_em7d_esp.yaml +++ b/boards/arc/emsdp/emsdp_em7d_esp.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em7d_esp -name: EM Software Development Platform +name: EM Software Development Platform (EM7D_ESP) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em9d.yaml b/boards/arc/emsdp/emsdp_em9d.yaml index 7bdf0340232be42..f20f29d18d01126 100644 --- a/boards/arc/emsdp/emsdp_em9d.yaml +++ b/boards/arc/emsdp/emsdp_em9d.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em9d -name: EM Software Development Platform +name: EM Software Development Platform (EM9D) type: mcu arch: arc toolchain: diff --git a/boards/arc/nsim/nsim_em7d_v22.yaml b/boards/arc/nsim/nsim_em7d_v22.yaml index 036e9b37baef299..bd2069c83590192 100644 --- a/boards/arc/nsim/nsim_em7d_v22.yaml +++ b/boards/arc/nsim/nsim_em7d_v22.yaml @@ -1,5 +1,5 @@ identifier: nsim_em7d_v22 -name: EM Nsim simulator +name: EM nSIM simulator (EM7D_v22) type: sim simulation: nsim simulation_exec: nsimdrv diff --git a/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml b/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml index 416dcd2133db0b8..f7f9fa1ec7201e1 100644 --- a/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml +++ b/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs5x_smp_12cores -name: Multi-core HS5x nSIM simulator +name: Multi-core HS5x nSIM simulator (12 cores) type: sim simulation: mdb-nsim simulation_exec: mdb diff --git a/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml b/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml index 3113b84e8d69938..9abea29aabc83e5 100644 --- a/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml +++ b/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs6x_smp_12cores -name: Multi-core HS6x nSIM simulator +name: Multi-core HS6x nSIM simulator (12 cores) type: sim simulation: mdb-nsim simulation_exec: mdb diff --git a/boards/arc/nsim/nsim_hs_flash_xip.yaml b/boards/arc/nsim/nsim_hs_flash_xip.yaml index 02da85f586408c3..eabe0c9cd846aa4 100644 --- a/boards/arc/nsim/nsim_hs_flash_xip.yaml +++ b/boards/arc/nsim/nsim_hs_flash_xip.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs_flash_xip -name: HS nSIM simulator +name: HS nSIM simulator (FLASH XIP) type: sim simulation: nsim simulation_exec: nsimdrv diff --git a/boards/arc/nsim/nsim_hs_sram.yaml b/boards/arc/nsim/nsim_hs_sram.yaml index 7a99a91ceff4169..cfbf02d60238841 100644 --- a/boards/arc/nsim/nsim_hs_sram.yaml +++ b/boards/arc/nsim/nsim_hs_sram.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs_sram -name: HS nSIM simulator +name: HS nSIM simulator (SRAM) type: sim simulation: nsim simulation_exec: nsimdrv diff --git a/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml b/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml index 45949212a00220a..13a48179fd5efb1 100644 --- a/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml +++ b/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml @@ -1,5 +1,5 @@ identifier: nsim_sem_mpu_stack_guard -name: SEM Nsim simulator +name: SEM nSIM simulator (stack guard) type: sim arch: arc simulation: nsim diff --git a/boards/arc/qemu_arc/qemu_arc_hs6x.yaml b/boards/arc/qemu_arc/qemu_arc_hs6x.yaml index 5346dbc12510d32..ed5425cc5654f90 100644 --- a/boards/arc/qemu_arc/qemu_arc_hs6x.yaml +++ b/boards/arc/qemu_arc/qemu_arc_hs6x.yaml @@ -1,5 +1,5 @@ identifier: qemu_arc_hs6x -name: QEMU Emulation for ARC HS +name: QEMU Emulation for ARC HS6x type: qemu simulation: qemu arch: arc diff --git a/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml b/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml index 829045078d26645..4f7b9cee45d3c78 100644 --- a/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml +++ b/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml @@ -1,5 +1,5 @@ identifier: qemu_arc_hs_xip -name: QEMU Emulation for ARC HS +name: QEMU Emulation for ARC HS (XIP) type: qemu simulation: qemu arch: arc diff --git a/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml index 08d01e51ec483c1..0ecd14f9076d122 100644 --- a/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml +++ b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: fvp_baser_aemv8r_aarch32_smp -name: FVP Emulation FVP_BaseR_AEMv8R AArch32 +name: FVP Emulation FVP_BaseR_AEMv8R AArch32 (SMP) arch: arm type: sim toolchain: diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml index 063ea90c351ee82..481ce3e63b25237 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: s32z270dc2_rtu0_r52@D -name: NXP X-S32Z270-DC (DC2) on RTU0 Cortex-R52 cores +name: NXP X-S32Z270-DC (DC2) on RTU0 Cortex-R52 cores (rev. D) type: mcu arch: arm ram: 1024 diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml index 70a37261c8e6730..9f0a55547c11737 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: s32z270dc2_rtu1_r52@D -name: NXP X-S32Z270-DC (DC2) on RTU1 Cortex-R52 cores +name: NXP X-S32Z270-DC (DC2) on RTU1 Cortex-R52 cores (rev. D) type: mcu arch: arm ram: 1024 diff --git a/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml b/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml index 68ef6a664e89fb4..b6e39f0dab35502 100644 --- a/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml +++ b/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: fvp_base_revc_2xaemv8a_smp_ns -name: FVP Emulation FVP_Base_RevC-2xAEMvA +name: FVP Emulation FVP_Base_RevC-2xAEMvA (SMP) arch: arm64 type: sim toolchain: diff --git a/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml b/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml index 1e0dfa4a9b2ff0c..ed63f35d1012fa7 100644 --- a/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml +++ b/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: fvp_baser_aemv8r_smp -name: FVP Emulation FVP_BaseR_AEMv8R +name: FVP Emulation FVP_BaseR_AEMv8R (SMP) arch: arm64 type: sim toolchain: diff --git a/boards/mips/qemu_malta/qemu_malta.yaml b/boards/mips/qemu_malta/qemu_malta.yaml index 3749da567ea10e1..083fb0e93b11bf9 100644 --- a/boards/mips/qemu_malta/qemu_malta.yaml +++ b/boards/mips/qemu_malta/qemu_malta.yaml @@ -1,5 +1,5 @@ identifier: qemu_malta -name: QEMU emulation for MIPS +name: QEMU emulation for MIPS (little endian) type: qemu simulation: qemu arch: mips diff --git a/boards/mips/qemu_malta/qemu_malta_be.yaml b/boards/mips/qemu_malta/qemu_malta_be.yaml index 80eab182050dac5..91a9444d00b24ec 100644 --- a/boards/mips/qemu_malta/qemu_malta_be.yaml +++ b/boards/mips/qemu_malta/qemu_malta_be.yaml @@ -1,5 +1,5 @@ identifier: qemu_malta_be -name: QEMU emulation for MIPS +name: QEMU emulation for MIPS (big endian) type: qemu simulation: qemu arch: mips From 3d37549bac90f2008c5e7cfc41ec79c553dbe99a Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Wed, 22 Nov 2023 16:24:48 +0100 Subject: [PATCH 0963/1049] Bluetooth: Mesh: allocate mesh max required buffer number Since sending of public key was moved into system work (https://github.com/zephyrproject-rtos/zephyr/pull/62331) it uses the same context as a Host Tx buffer allocator for gatt sending. Host cannot wait for free buffer anymore. Mesh requires 4 buffers to send max size frame(public key) during provisioning. Signed-off-by: Aleksandr Khromykh --- subsys/bluetooth/common/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index bf4aee75e48da33..7b6bc839b89c4dd 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -33,6 +33,7 @@ config BT_BUF_ACL_TX_SIZE config BT_BUF_ACL_TX_COUNT int "Number of outgoing ACL data buffers" default 7 if BT_HCI_RAW + default 4 if BT_MESH_GATT default 3 range 1 255 help From 108f7bde83c3c0490f8ffd41385212d75fbe93ed Mon Sep 17 00:00:00 2001 From: Jonas Remmert Date: Wed, 22 Nov 2023 16:43:17 +0100 Subject: [PATCH 0964/1049] tests: build_all: sensor: fix i2c duplicate address Fix address for hs300x driver in dts file for test. Signed-off-by: Jonas Remmert --- tests/drivers/build_all/sensor/i2c.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 6ad5ac8703e7e66..4e79590ce99f0ce 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -854,7 +854,7 @@ test_i2c_lps22df: lps22df@79 { avg = ; }; -test_i2c_hs300x: hs300x@79 { +test_i2c_hs300x: hs300x@7a { compatible = "renesas,hs300x"; - reg = <0x79>; + reg = <0x7a>; }; From 20acd64a1bb76ff2504101efb13bf0d1ecd7d058 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 22 Nov 2023 19:00:03 +0100 Subject: [PATCH 0965/1049] doc: zbus: fix msg subscriber thread signatures Fix the thread function signatures to match k_thread_entry_t. Signed-off-by: Bartosz Bilas --- doc/services/zbus/index.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/services/zbus/index.rst b/doc/services/zbus/index.rst index 59d45317a7b2c2c..6f9378ba5c3607a 100644 --- a/doc/services/zbus/index.rst +++ b/doc/services/zbus/index.rst @@ -424,8 +424,11 @@ exchanges accelerometer data, for example. K_THREAD_DEFINE(subscriber_task_id, 512, subscriber_task, NULL, NULL, NULL, 3, 0, 0); ZBUS_MSG_SUBSCRIBER_DEFINE(my_msg_subscriber); - static void msg_subscriber_task(void *sub) + static void msg_subscriber_task(void *ptr1, void *ptr2, void *ptr3) { + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); const struct zbus_channel *chan; struct acc_msg acc = {0}; From 13f3c6d0bda59855b8928fb510cb1cd3687c4dce Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Thu, 23 Nov 2023 12:54:12 +0100 Subject: [PATCH 0966/1049] sysbuild: introduce Kconfig setting for controlling HCI IPC inclusion Follow-up: #64704 Introducing NET_CORE_IMAGE_HCI_IPC Kconfig setting to control inclusion of HCI IPC image when building through sysbuild. This allows users with custom netcore applications to avoid inclusion of the default HCI IPC image. Signed-off-by: Torsten Rasmussen --- samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild | 5 +++++ samples/bluetooth/broadcast_audio_sink/sysbuild.cmake | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild b/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild index 37a6b66c7f4d873..f434010f81d27ce 100644 --- a/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild +++ b/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild @@ -8,3 +8,8 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake index c150913cc551373..ed30d7f31f3d7f6 100644 --- a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) From ecb2df0444f10bd21dbdd1220cbe353655cab5cc Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 24 Nov 2023 11:15:53 +0800 Subject: [PATCH 0967/1049] scripts/checkpatch: add `__unused` to the `$Attribute` list Add `__unused` to the `$Attribute` family along with its `__maybe_unused`, `__always_unused` & `__used` brothers, so that: ```c __unused int ret; ``` is recognized as variable declaration, and doesn't raise `LINE_SPACING` warning in CI. Signed-off-by: Yong Cong Sin --- scripts/checkpatch.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 544fc4ea0e46907..fd82a880c1fe42f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -389,6 +389,7 @@ sub hash_show_words { __always_unused| __noreturn| __used| + __unused| __cold| __pure| __noclone| From 199743de0118077df2183d9bed0f9e322f2cfb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 24 Nov 2023 11:21:21 +0100 Subject: [PATCH 0968/1049] ci: hotfix: Use latest version of greetings action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug with the action's Docker container apparently not being able to run Node correctly anymore... Signed-off-by: Benjamin Cabé --- .github/workflows/greet_first_time_contributor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greet_first_time_contributor.yml b/.github/workflows/greet_first_time_contributor.yml index 5984b29fe1f37a4..13584774a54175a 100644 --- a/.github/workflows/greet_first_time_contributor.yml +++ b/.github/workflows/greet_first_time_contributor.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: zephyrproject-rtos/action-first-interaction@v1.1.1-zephyr-4 + - uses: zephyrproject-rtos/action-first-interaction@v1.1.1-zephyr-5 with: repo-token: ${{ secrets.GITHUB_TOKEN }} From 05025e6b7c47bc0acf7815f56b66d5fecea1262e Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Fri, 3 Nov 2023 13:29:42 +0100 Subject: [PATCH 0969/1049] cmake: add initlevels to usage Fix missing `initlevels` entry in the `usage` command. Signed-off-by: Jeppe Odgaard --- cmake/usage/usage.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/usage/usage.cmake b/cmake/usage/usage.cmake index 9472f2fa9bb0c5a..2f4b0b76ddd3b2e 100644 --- a/cmake/usage/usage.cmake +++ b/cmake/usage/usage.cmake @@ -27,6 +27,7 @@ message(" debugserver - Run \"west debugserver\" (or start GDB server on port message(" attach - Run \"west attach\"") message(" ram_report - Build and create RAM usage report") message(" rom_report - Build and create ROM usage report") +message(" initlevels - Display the initialization sequence") message(" boards - Display supported boards") message(" shields - Display supported shields") message(" usage - Display this text") From 10a167f6c1f1ab4850f3bf1f8007826bff6f5285 Mon Sep 17 00:00:00 2001 From: Lukas Streitenberger Date: Thu, 16 Nov 2023 15:52:51 +0100 Subject: [PATCH 0970/1049] Bluetooth: TBS: Added missing callState notifications Changes of call state were not notified. Fixed by calling notify_calls in respective functions. Signed-off-by: Lukas Streitenberger --- subsys/bluetooth/audio/tbs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index 86588c11c7140d0..06b5d7d2e3c074c 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -1836,6 +1836,8 @@ int bt_tbs_hold(uint8_t call_index) status = tbs_hold_call(inst, &ccp); } + notify_calls(inst); + return status; } @@ -1852,6 +1854,8 @@ int bt_tbs_retrieve(uint8_t call_index) status = retrieve_call(inst, &ccp); } + notify_calls(inst); + return status; } @@ -1869,6 +1873,8 @@ int bt_tbs_terminate(uint8_t call_index) BT_TBS_REASON_SERVER_ENDED_CALL); } + notify_calls(inst); + return status; } @@ -2028,6 +2034,8 @@ int bt_tbs_remote_terminate(uint8_t call_index) BT_TBS_REASON_REMOTE_ENDED_CALL); } + notify_calls(inst); + return status; } From 74f07b04ff4f72a46b3b6064ecd61cb4a14b2297 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Fri, 10 Nov 2023 10:38:21 +0800 Subject: [PATCH 0971/1049] soc: npcx: shi: add new registers for npcx4 Add the SHI enhanced buffer mode register definition for npcx4. Signed-off-by: Jun Lin --- soc/arm/nuvoton_npcx/common/reg/reg_def.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index e9ef3460e63cce2..21c0d99a87f87f0 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -1619,7 +1619,11 @@ struct shi_reg { volatile uint8_t EVSTAT2; /* 0x010: Event Enable 2 */ volatile uint8_t EVENABLE2; - volatile uint8_t reserved4[15]; + /* 0x011: SHI Configuration 6 - only in chips which support enhanced buffer mode */ + volatile uint8_t SHICFG6; + /* 0x012: Single Byte Output Buffer - only in chips which support enhanced buffer mode */ + volatile uint8_t SBOBUF; + volatile uint8_t reserved4[13]; /* 0x20~0x9F: Output Buffer */ volatile uint8_t OBUF[128]; /* 0xA0~0x11F: Input Buffer */ @@ -1670,5 +1674,7 @@ struct shi_reg { #define NPCX_EVENABLE2_IBHF2EN 0 #define NPCX_EVENABLE2_CSNREEN 1 #define NPCX_EVENABLE2_CSNFEEN 2 +#define NPCX_SHICFG6_EBUFMD 0 +#define NPCX_SHICFG6_OBUF_SL 1 #endif /* _NUVOTON_NPCX_REG_DEF_H */ From ba38a54faa03249dae7847eb51921be2e043c8b9 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Fri, 10 Nov 2023 10:40:41 +0800 Subject: [PATCH 0972/1049] dts: npcx: shi: support two version of shi hardware The shi module in npcx4 supports the enhanced buffer mode. Add a new compatible string "nuvoton,npcx-shi-enhanced" for it. Then the shi driver can determine if it should use the enhanced buffer mode based on the compatiable string. Signed-off-by: Jun Lin --- dts/arm/nuvoton/npcx/npcx.dtsi | 10 ---------- dts/arm/nuvoton/npcx/npcx4.dtsi | 11 +++++++++++ dts/arm/nuvoton/npcx/npcx7.dtsi | 11 +++++++++++ dts/arm/nuvoton/npcx/npcx9.dtsi | 11 +++++++++++ dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml | 8 ++++++++ 5 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml diff --git a/dts/arm/nuvoton/npcx/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi index c1a77c4fe699290..28a491de16fc8a3 100644 --- a/dts/arm/nuvoton/npcx/npcx.dtsi +++ b/dts/arm/nuvoton/npcx/npcx.dtsi @@ -376,16 +376,6 @@ status = "disabled"; }; - shi0: shi@4000f000 { - compatible = "nuvoton,npcx-shi"; - reg = <0x4000f000 0x120>; - interrupts = <18 1>; - clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; - status = "disabled"; - buffer-rx-size = <128>; - buffer-tx-size = <128>; - }; - host_sub: lpc@400c1000 { compatible = "nuvoton,npcx-host-sub"; /* host sub-module register address & size */ diff --git a/dts/arm/nuvoton/npcx/npcx4.dtsi b/dts/arm/nuvoton/npcx/npcx4.dtsi index a01d5d69abffb19..36f6bb579b8a70e 100644 --- a/dts/arm/nuvoton/npcx/npcx4.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4.dtsi @@ -295,6 +295,17 @@ context-buffer-size = <228>; status = "disabled"; }; + + shi0: shi@4000f000 { + compatible = "nuvoton,npcx-shi-enhanced"; + reg = <0x4000f000 0x120>; + interrupts = <18 1>; + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; + status = "disabled"; + buffer-rx-size = <128>; + buffer-tx-size = <128>; + shi-cs-wui =<&wui_io53>; + }; }; soc-if { diff --git a/dts/arm/nuvoton/npcx/npcx7.dtsi b/dts/arm/nuvoton/npcx/npcx7.dtsi index 529d5bdef3537d7..29be4fcc1f3fb99 100644 --- a/dts/arm/nuvoton/npcx/npcx7.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7.dtsi @@ -244,6 +244,17 @@ qspi_fiu0: quadspi@40020000 { clocks = <&pcc NPCX_CLOCK_BUS_FIU NPCX_PWDWN_CTL1 2>; }; + + shi0: shi@4000f000 { + compatible = "nuvoton,npcx-shi"; + reg = <0x4000f000 0x120>; + interrupts = <18 1>; + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; + status = "disabled"; + buffer-rx-size = <128>; + buffer-tx-size = <128>; + shi-cs-wui =<&wui_io53>; + }; }; soc-id { diff --git a/dts/arm/nuvoton/npcx/npcx9.dtsi b/dts/arm/nuvoton/npcx/npcx9.dtsi index 4d0cb7dc69e3dd0..f4716d7947eb7c4 100644 --- a/dts/arm/nuvoton/npcx/npcx9.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9.dtsi @@ -272,6 +272,17 @@ context-buffer-size = <212>; status = "disabled"; }; + + shi0: shi@4000f000 { + compatible = "nuvoton,npcx-shi"; + reg = <0x4000f000 0x120>; + interrupts = <18 1>; + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; + status = "disabled"; + buffer-rx-size = <128>; + buffer-tx-size = <128>; + shi-cs-wui =<&wui_io53>; + }; }; soc-id { diff --git a/dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml b/dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml new file mode 100644 index 000000000000000..dc197fb6fd8237b --- /dev/null +++ b/dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NPCX Serial Host Interface (SHI) node + +compatible: "nuvoton,npcx-shi-enhanced" + +include: [pinctrl-device.yaml, shi-device.yaml, "nuvoton,npcx-shi.yaml"] From 717a7835bbf22a04ad62bab09f508346f09650b9 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Fri, 17 Nov 2023 17:57:49 +0800 Subject: [PATCH 0973/1049] mgmt: ec_host_cmd: shi_npcx: add pm_policy lock Implement the pm_policy lock to prevent the chip enters the deep slepp mode while shi transaction is ongoing. Signed-off-by: Jun Lin --- .../backends/ec_host_cmd_backend_shi_npcx.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c index f98f3bf758490af..e5294e0f6097573 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -95,6 +96,11 @@ enum shi_npcx_state { SHI_STATE_BAD_RECEIVED_DATA, }; +enum shi_npcx_pm_policy_state_flag { + SHI_NPCX_PM_POLICY_FLAG, + SHI_NPCX_PM_POLICY_FLAG_COUNT, +}; + /* Device config */ struct shi_npcx_config { /* Serial Host Interface (SHI) base address */ @@ -127,6 +133,7 @@ struct shi_npcx_data { SHI_OUT_END_PAD] __aligned(4); uint8_t *const out_msg; uint8_t in_msg[CONFIG_EC_HOST_CMD_BACKEND_SHI_MAX_REQUEST] __aligned(4); + ATOMIC_DEFINE(pm_policy_state_flag, SHI_NPCX_PM_POLICY_FLAG_COUNT); }; struct ec_host_cmd_shi_npcx_ctx { @@ -144,6 +151,22 @@ struct ec_host_cmd_shi_npcx_ctx { /* Forward declaration */ static void shi_npcx_reset_prepare(const struct device *dev); +static void shi_npcx_pm_policy_state_lock_get(struct shi_npcx_data *data, + enum shi_npcx_pm_policy_state_flag flag) +{ + if (atomic_test_and_set_bit(data->pm_policy_state_flag, flag) == 0) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + } +} + +static void shi_npcx_pm_policy_state_lock_put(struct shi_npcx_data *data, + enum shi_npcx_pm_policy_state_flag flag) +{ + if (atomic_test_and_clear_bit(data->pm_policy_state_flag, flag) == 1) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + } +} + /* Read pointer of input or output buffer by consecutive reading */ static uint32_t shi_npcx_read_buf_pointer(struct shi_reg *const inst) { @@ -495,6 +518,8 @@ static void shi_npcx_handle_cs_assert(const struct device *dev) * irrelevant now that CS is re-asserted. */ inst->EVSTAT = BIT(NPCX_EVSTAT_EOR); + + shi_npcx_pm_policy_state_lock_get(data, SHI_NPCX_PM_POLICY_FLAG); } static void shi_npcx_handle_cs_deassert(const struct device *dev) @@ -712,6 +737,8 @@ static void shi_npcx_reset_prepare(const struct device *dev) shi_npcx_sec_ibf_int_enable(inst, 1); irq_enable(DT_INST_IRQN(0)); + shi_npcx_pm_policy_state_lock_put(data, SHI_NPCX_PM_POLICY_FLAG); + LOG_DBG("RDY-"); } @@ -769,6 +796,12 @@ static int shi_npcx_disable(const struct device *dev) return ret; } + /* + * Allow deep sleep again in case CS dropped before ec was + * informed in hook function and turn off SHI's interrupt in time. + */ + shi_npcx_pm_policy_state_lock_put(data, SHI_NPCX_PM_POLICY_FLAG); + return 0; } From 3f9d24e4c01ba282a73d774c28639761118ec9c7 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Mon, 20 Nov 2023 11:06:05 +0800 Subject: [PATCH 0974/1049] mgmt: ec_host_cmd: shi_npcx: support the enhanced mode The original SHI module only has one output FIFO buffer. It costs a lot when the driver has to send/change the protocol control code because it must fill out all 128 bytes of output FIFO. In npcx4, we introduce another output buffer in 1-byte depth. These two buffers can switch back and forth during the transaction. We can use the single-byte buffer to send the control code and the 128-byte FIFO to send the data payload. It helps improve the SHI driver's efficiency. Signed-off-by: Jun Lin --- soc/arm/nuvoton_npcx/common/reg/reg_def.h | 2 + subsys/mgmt/ec_host_cmd/backends/Kconfig | 10 +- .../backends/ec_host_cmd_backend_shi_npcx.c | 121 ++++++++++++++---- 3 files changed, 109 insertions(+), 24 deletions(-) diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index 21c0d99a87f87f0..d6b081533df52a6 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -1677,4 +1677,6 @@ struct shi_reg { #define NPCX_SHICFG6_EBUFMD 0 #define NPCX_SHICFG6_OBUF_SL 1 +#define IBF_IBHF_EN_MASK (BIT(NPCX_EVENABLE_IBFEN) | BIT(NPCX_EVENABLE_IBHFEN)) + #endif /* _NUVOTON_NPCX_REG_DEF_H */ diff --git a/subsys/mgmt/ec_host_cmd/backends/Kconfig b/subsys/mgmt/ec_host_cmd/backends/Kconfig index d1482fe7976fdea..de9ec920560ae33 100644 --- a/subsys/mgmt/ec_host_cmd/backends/Kconfig +++ b/subsys/mgmt/ec_host_cmd/backends/Kconfig @@ -53,7 +53,8 @@ choice EC_HOST_CMD_BACKEND_SHI_DRIVER config EC_HOST_CMD_BACKEND_SHI_NPCX bool "SHI by Nuvoton" - depends on DT_HAS_NUVOTON_NPCX_SHI_ENABLED + depends on DT_HAS_NUVOTON_NPCX_SHI_ENABLED || \ + DT_HAS_NUVOTON_NPCX_SHI_ENHANCED_ENABLED help This option enables the driver for SHI backend in the Nuvoton NPCX chip. @@ -67,6 +68,13 @@ config EC_HOST_CMD_BACKEND_SHI_ITE endchoice +config EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE + def_bool DT_HAS_NUVOTON_NPCX_SHI_ENHANCED_ENABLED + help + In this mode, besides the original 128-bytes FIFO, an additional + single-byte output buffer can be selected/switched to generate a + response to simultaneous Read/Write transactions. + config EC_HOST_CMD_BACKEND_SHI_MAX_REQUEST int "Max data size for the version 3 request packet" default 544 if EC_HOST_CMD_BACKEND_SHI_NPCX diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c index e5294e0f6097573..a5bb9adadde2927 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT nuvoton_npcx_shi - #include "ec_host_cmd_backend_shi.h" #include @@ -19,7 +17,14 @@ #include +#if DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_shi) +#define DT_DRV_COMPAT nuvoton_npcx_shi +#elif DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_shi_enhanced) +#define DT_DRV_COMPAT nuvoton_npcx_shi_enhanced +#endif BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "Invalid number of NPCX SHI peripherals"); +BUILD_ASSERT(!(DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_shi) && + DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_shi_enhanced))); LOG_MODULE_REGISTER(host_cmd_shi_npcx, CONFIG_EC_HC_LOG_LEVEL); @@ -152,7 +157,7 @@ struct ec_host_cmd_shi_npcx_ctx { static void shi_npcx_reset_prepare(const struct device *dev); static void shi_npcx_pm_policy_state_lock_get(struct shi_npcx_data *data, - enum shi_npcx_pm_policy_state_flag flag) + enum shi_npcx_pm_policy_state_flag flag) { if (atomic_test_and_set_bit(data->pm_policy_state_flag, flag) == 0) { pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); @@ -160,7 +165,7 @@ static void shi_npcx_pm_policy_state_lock_get(struct shi_npcx_data *data, } static void shi_npcx_pm_policy_state_lock_put(struct shi_npcx_data *data, - enum shi_npcx_pm_policy_state_flag flag) + enum shi_npcx_pm_policy_state_flag flag) { if (atomic_test_and_clear_bit(data->pm_policy_state_flag, flag) == 1) { pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); @@ -180,13 +185,40 @@ static uint32_t shi_npcx_read_buf_pointer(struct shi_reg *const inst) return (uint32_t)stat; } +/* + * Write pointer of output buffer by consecutive reading + * Note: this function (OBUFSTAT) should only be usd in Enhanced Buffer Mode. + */ +static uint32_t shi_npcx_write_buf_pointer(struct shi_reg *const inst) +{ + uint8_t stat; + + /* Wait for two consecutive equal values are read */ + do { + stat = inst->OBUFSTAT; + } while (stat != inst->OBUFSTAT); + + return stat; +} + /* * Valid offset of SHI output buffer to write. - * When SIMUL bit is set, IBUFPTR can be used instead of OBUFPTR + * - In Simultaneous Standard FIFO Mode (SIMUL = 1 and EBUFMD = 0): + * OBUFPTR cannot be used. IBUFPTR can be used instead because it points to + * the same location as OBUFPTR. + * - In Simultaneous Enhanced FIFO Mode (SIMUL = 1 and EBUFMD = 1): + * IBUFPTR may not point to the same location as OBUFPTR. + * In this case OBUFPTR reflects the 128-byte payload buffer pointer only + * during the SPI transaction. */ static uint32_t shi_npcx_valid_obuf_offset(struct shi_reg *const inst) { - return (shi_npcx_read_buf_pointer(inst) + EC_SHI_OUT_PREAMBLE_LENGTH) % SHI_OBUF_FULL_SIZE; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + return shi_npcx_write_buf_pointer(inst) % SHI_OBUF_FULL_SIZE; + } else { + return (shi_npcx_read_buf_pointer(inst) + EC_SHI_OUT_PREAMBLE_LENGTH) % + SHI_OBUF_FULL_SIZE; + } } /* @@ -246,6 +278,16 @@ static void shi_npcx_fill_out_status(struct shi_reg *const inst, uint8_t status) volatile uint8_t *fill_end; volatile uint8_t *obuf_end; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + /* + * In Enhanced Buffer Mode, SHI module outputs the status code + * in SBOBUF repeatedly. + */ + inst->SBOBUF = status; + + return; + } + /* * Disable interrupts in case the interfere by the other interrupts. * Use __disable_irq/__enable_irq instead of using irq_lock/irq_unlock @@ -282,6 +324,10 @@ static void shi_npcx_bad_received_data(const struct device *dev) struct shi_npcx_data *data = dev->data; struct shi_reg *const inst = HAL_INSTANCE(dev); + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + inst->EVENABLE &= ~IBF_IBHF_EN_MASK; + } + /* State machine mismatch, timeout, or protocol we can't handle. */ shi_npcx_fill_out_status(inst, EC_SHI_RX_BAD_DATA); data->state = SHI_STATE_BAD_RECEIVED_DATA; @@ -367,6 +413,10 @@ static void shi_npcx_handle_host_package(const struct device *dev) data->state = SHI_STATE_PROCESSING; LOG_DBG("PRC-"); + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + inst->EVENABLE &= ~IBF_IBHF_EN_MASK; + } + /* Fill output buffer to indicate we`re processing request */ shi_npcx_fill_out_status(inst, EC_SHI_PROCESSING); data->out_msg[0] = EC_SHI_FRAME_START; @@ -719,14 +769,20 @@ static void shi_npcx_reset_prepare(const struct device *dev) data->sz_request = 0; data->sz_response = 0; - /* - * Fill output buffer to indicate we`re - * ready to receive next transaction. - */ - for (i = 1; i < SHI_OBUF_FULL_SIZE; i++) { - inst->OBUF[i] = EC_SHI_RECEIVING; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + inst->SBOBUF = EC_SHI_RX_READY; + inst->SBOBUF = EC_SHI_RECEIVING; + inst->EVENABLE |= IBF_IBHF_EN_MASK; + inst->EVENABLE &= ~(BIT(NPCX_EVENABLE_OBEEN) | BIT(NPCX_EVENABLE_OBHEEN)); + } else { + /* + * Fill output buffer to indicate we`re ready to receive next transaction. + */ + for (i = 1; i < SHI_OBUF_FULL_SIZE; i++) { + inst->OBUF[i] = EC_SHI_RECEIVING; + } + inst->OBUF[0] = EC_SHI_RX_READY; } - inst->OBUF[0] = EC_SHI_RX_READY; /* SHI/Host Write/input buffer wrap-around enable */ inst->SHICFG1 = BIT(NPCX_SHICFG1_IWRAP) | BIT(NPCX_SHICFG1_WEN) | BIT(NPCX_SHICFG1_EN); @@ -861,8 +917,7 @@ static int shi_npcx_init_registers(const struct device *dev) * [1] - OBHEEN = 0: Output Buffer Half Empty Interrupt Enable * [0] - OBEEN = 0: Output Buffer Empty Interrupt Enable */ - inst->EVENABLE = - BIT(NPCX_EVENABLE_EOREN) | BIT(NPCX_EVENABLE_IBHFEN) | BIT(NPCX_EVENABLE_IBFEN); + inst->EVENABLE = BIT(NPCX_EVENABLE_EOREN) | IBF_IBHF_EN_MASK; /* * EVENABLE2 (Event Enable 2) setting @@ -875,6 +930,10 @@ static int shi_npcx_init_registers(const struct device *dev) /* Clear SHI events status register */ inst->EVSTAT = 0xff; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + inst->SHICFG6 |= BIT(NPCX_SHICFG6_EBUFMD); + } + npcx_miwu_interrupt_configure(&config->shi_cs_wui, NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_LOW); /* SHI interrupt installation */ @@ -928,13 +987,15 @@ static int shi_npcx_backend_send(const struct ec_host_cmd_backend *backend) struct shi_npcx_data *data = hc_shi->dev->data; uint8_t *out_buf = data->out_msg + EC_SHI_FRAME_START_LENGTH; - /* - * Disable interrupts. This routine is not called from interrupt context and buffer - * underrun will likely occur if it is preempted after writing its initial reply byte. - * Also, we must be sure our state doesn't unexpectedly change, in case we're expected - * to take RESP_NOT_RDY actions. - */ - __disable_irq(); + if (!IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + /* + * Disable interrupts. This routine is not called from interrupt context and buffer + * underrun will likely occur if it is preempted after writing its initial reply + * byte. Also, we must be sure our state doesn't unexpectedly change, in case we're + * expected to take RESP_NOT_RDY actions. + */ + __disable_irq(); + } if (data->state == SHI_STATE_PROCESSING) { /* Append our past-end byte, which we reserved space for. */ @@ -948,6 +1009,17 @@ static int shi_npcx_backend_send(const struct ec_host_cmd_backend *backend) /* Transmit the reply */ data->state = SHI_STATE_SENDING; + if (IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + struct shi_reg *const inst = HAL_INSTANCE(hc_shi->dev); + + /* + * Enable output buffer half/full empty interrupt and + * switch output mode from the repeated single byte mode + * to FIFO mode. + */ + inst->EVENABLE |= BIT(NPCX_EVENABLE_OBEEN) | BIT(NPCX_EVENABLE_OBHEEN); + inst->SHICFG6 |= BIT(NPCX_SHICFG6_OBUF_SL); + } LOG_DBG("SND-"); } else if (data->state == SHI_STATE_CNL_RESP_NOT_RDY) { /* @@ -961,7 +1033,10 @@ static int shi_npcx_backend_send(const struct ec_host_cmd_backend *backend) LOG_ERR("Unexpected state %d in response handler", data->state); } - __enable_irq(); + if (!IS_ENABLED(CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE)) { + __enable_irq(); + } + return 0; } From f89c5ddd1aaf0e4a5b6fd0a1397c5a72f1cba388 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Nov 2023 17:29:40 +0200 Subject: [PATCH 0975/1049] samples: chre: Fix format strings for size_t types The correct printf format specifier for size_t is %zu. Without this change the sample generates warnings like this: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'size_t' {aka 'long unsigned int'} [-Wformat=] Signed-off-by: Johan Hedberg --- samples/modules/chre/src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/modules/chre/src/main.cpp b/samples/modules/chre/src/main.cpp index f9b2b16cb52f327..675e57e89324280 100644 --- a/samples/modules/chre/src/main.cpp +++ b/samples/modules/chre/src/main.cpp @@ -37,12 +37,12 @@ int main(void) k_msleep(100); } printk("Starting EchoApp... %s\n", boolToString(eventLoop.startNanoapp(echo_app))); - printk("Nanoapp count=%u\n", eventLoop.getNanoappCount()); + printk("Nanoapp count=%zu\n", eventLoop.getNanoappCount()); printk("Finding instance ID... %s\n", boolToString(eventLoop.findNanoappInstanceIdByAppId(1, &instanceId))); - printk("Nanoapp count=%u\n", eventLoop.getNanoappCount()); + printk("Nanoapp count=%zu\n", eventLoop.getNanoappCount()); printk("Instance ID: %u\n", instanceId); - printk("Sending event %u...\n", eventLoop.getNanoappCount()); + printk("Sending event %zu...\n", eventLoop.getNanoappCount()); eventLoop.postEventOrDie(CHRE_EVENT_MESSAGE_FROM_HOST, nullptr, [](uint16_t eventType, void *eventData) { printk("Event (%u) complete!\n", eventType); }); From 2abf0314c27f83001434c0a009c33eba7205d3c0 Mon Sep 17 00:00:00 2001 From: Igor Druzhinin Date: Fri, 29 Sep 2023 15:04:32 +0100 Subject: [PATCH 0976/1049] toolchain: gcc: fix GCC < 11.0.0 build with -Wundef When building using GCC version < 11.0.0, TOOLCHAIN_CLANG_VERSION is not yet defined in gcc.h. Nevertheless, it's still needed due to reuse of gcc.h in llvm.h. Guard access to TOOLCHAIN_CLANG_VERSION to fix that. Signed-off-by: Igor Druzhinin --- include/zephyr/toolchain/gcc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/zephyr/toolchain/gcc.h b/include/zephyr/toolchain/gcc.h index d3dce3b253f3f31..e086c644e879654 100644 --- a/include/zephyr/toolchain/gcc.h +++ b/include/zephyr/toolchain/gcc.h @@ -648,7 +648,8 @@ do { \ * * @note Only supported for GCC >= 11.0.0 or Clang >= 7. */ -#if (TOOLCHAIN_GCC_VERSION >= 110000) || (TOOLCHAIN_CLANG_VERSION >= 70000) +#if (TOOLCHAIN_GCC_VERSION >= 110000) || \ + (defined(TOOLCHAIN_CLANG_VERSION) && (TOOLCHAIN_CLANG_VERSION >= 70000)) #define FUNC_NO_STACK_PROTECTOR __attribute__((no_stack_protector)) #else #define FUNC_NO_STACK_PROTECTOR From 897b300b2e516c733ffa6df45a77948996a563dd Mon Sep 17 00:00:00 2001 From: Dean Sellers Date: Thu, 23 Nov 2023 09:28:16 +1000 Subject: [PATCH 0977/1049] drivers: spi: esp32xx: Fix CS reset over split transaction In the case where a transaction is spilt due to the rx buff len being longer than the tx or the transaction buffer exceeding the size of the requested buffer with non gpio CS, the chip select would be de-asserted/asserted in the middle of the transaction. Fixes: #57577 Signed-off-by: Dean Sellers --- drivers/spi/spi_esp32_spim.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi_esp32_spim.c b/drivers/spi/spi_esp32_spim.c index a6ace4f263f0cfb..0bfed3fc8be3e50 100644 --- a/drivers/spi/spi_esp32_spim.c +++ b/drivers/spi/spi_esp32_spim.c @@ -71,7 +71,8 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) size_t max_buf_sz = cfg->dma_enabled ? SPI_DMA_MAX_BUFFER_SIZE : SOC_SPI_MAXIMUM_BUFFER_SIZE; size_t transfer_len_bytes = MIN(chunk_len_bytes, max_buf_sz); - size_t bit_len = transfer_len_bytes << 3; + size_t transfer_len_frames = transfer_len_bytes / data->dfs; + size_t bit_len = transfer_len_bytes << 3; uint8_t *rx_temp = NULL; uint8_t *tx_temp = NULL; uint8_t dma_len_tx = MIN(ctx->tx_len * data->dfs, SPI_DMA_MAX_BUFFER_SIZE); @@ -90,7 +91,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) memcpy(tx_temp, &ctx->tx_buf[0], dma_len_tx); } if (ctx->rx_buf && (!esp_ptr_dma_capable((uint32_t *)&ctx->rx_buf[0]) || - ((int)&ctx->rx_buf[0] % 4 != 0) || (dma_len_tx % 4 != 0))) { + ((int)&ctx->rx_buf[0] % 4 != 0) || (dma_len_rx % 4 != 0))) { /* The rx buffer need to be length of * multiples of 32 bits to avoid heap * corruption. @@ -112,9 +113,11 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) hal_trans->tx_bitlen = bit_len; hal_trans->rx_bitlen = bit_len; - /* keep cs line active ultil last transmission */ + /* keep cs line active until last transmission */ hal_trans->cs_keep_active = - (!ctx->num_cs_gpios && (ctx->rx_count > 1 || ctx->tx_count > 1)); + (!ctx->num_cs_gpios && + (ctx->rx_count > 1 || ctx->tx_count > 1 || ctx->rx_len > transfer_len_frames || + ctx->tx_len > transfer_len_frames)); /* configure SPI */ spi_hal_setup_trans(hal, hal_dev, hal_trans); @@ -122,7 +125,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) /* send data */ spi_hal_user_start(hal); - spi_context_update_tx(&data->ctx, data->dfs, transfer_len_bytes/data->dfs); + spi_context_update_tx(&data->ctx, data->dfs, transfer_len_frames); while (!spi_hal_usr_is_done(hal)) { /* nop */ @@ -135,7 +138,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) memcpy(&ctx->rx_buf[0], rx_temp, transfer_len_bytes); } - spi_context_update_rx(&data->ctx, data->dfs, transfer_len_bytes/data->dfs); + spi_context_update_rx(&data->ctx, data->dfs, transfer_len_frames); k_free(tx_temp); k_free(rx_temp); From e3f5c966675b0c2d8b5f53562750834a74635d55 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 15 Nov 2023 16:37:18 +0100 Subject: [PATCH 0978/1049] modules: nanopb: Let Nanopb search for protoc The Nanopb cmake locates the protoc executable, verify the result instead of doing it ourselves. Signed-off-by: Pieter De Gendt --- modules/nanopb/nanopb.cmake | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/nanopb/nanopb.cmake b/modules/nanopb/nanopb.cmake index ddcdb5f61d195c5..24263c825e44d4f 100644 --- a/modules/nanopb/nanopb.cmake +++ b/modules/nanopb/nanopb.cmake @@ -6,14 +6,15 @@ include_guard(GLOBAL) list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_NANOPB_MODULE_DIR}/extra) -find_program(PROTOC protoc) -if(NOT PROTOC) +find_package(Nanopb REQUIRED) + +if(NOT PROTOBUF_PROTOC_EXECUTABLE) message(FATAL_ERROR "'protoc' not found, please ensure protoc is installed\ and in path. See https://docs.zephyrproject.org/latest/samples/modules/nanopb/README.html") +else() + message(STATUS "Found protoc: ${PROTOBUF_PROTOC_EXECUTABLE}") endif() -find_package(Nanopb REQUIRED) - # Usage: # list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_BASE}/modules/nanopb) # include(nanopb) From a89fa32dac0de646a69ee916570f0a010fb9e6c6 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 11:42:50 -0500 Subject: [PATCH 0979/1049] posix: pthread: ensure pthread_key_delete() removes correct key Previously, `pthread_key_delete()` was only ever deleting key 0 rather than the key corresponding to the provided argument. Signed-off-by: Christopher Friedt --- lib/posix/key.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/posix/key.c b/lib/posix/key.c index 03d03eed84a3a56..1a3f2b92a133288 100644 --- a/lib/posix/key.c +++ b/lib/posix/key.c @@ -10,6 +10,7 @@ #include #include #include +#include struct pthread_key_data { sys_snode_t node; @@ -120,6 +121,8 @@ int pthread_key_create(pthread_key_t *key, */ int pthread_key_delete(pthread_key_t key) { + size_t bit; + __unused int ret; pthread_key_obj *key_obj; struct pthread_key_data *key_data; sys_snode_t *node_l, *next_node_l; @@ -145,7 +148,9 @@ int pthread_key_delete(pthread_key_t key) k_free((void *)key_data); } - (void)sys_bitarray_free(&posix_key_bitarray, 1, 0); + bit = posix_key_to_offset(key_obj); + ret = sys_bitarray_free(&posix_key_bitarray, 1, bit); + __ASSERT_NO_MSG(ret == 0); k_spin_unlock(&pthread_key_lock, key_key); From 0e11bcf5a0e748c29925199d9cbb634979e495d1 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 11:47:21 -0500 Subject: [PATCH 0980/1049] tests: posix: add tests to ensure pthread_key_delete() works Ensure that the correct key is deleted via pthread_key_delete(). Signed-off-by: Christopher Friedt --- tests/posix/common/src/key.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/posix/common/src/key.c b/tests/posix/common/src/key.c index ff01617f6985fd4..eeadf8f00587529 100644 --- a/tests/posix/common/src/key.c +++ b/tests/posix/common/src/key.c @@ -213,3 +213,34 @@ ZTEST(posix_apis, test_key_Nto1_thread) } printk("\n"); } + +ZTEST(posix_apis, test_key_resource_leak) +{ + pthread_key_t key; + + for (size_t i = 0; i < CONFIG_MAX_PTHREAD_KEY_COUNT; ++i) { + zassert_ok(pthread_key_create(&key, NULL), "failed to create key %zu", i); + zassert_ok(pthread_key_delete(key), "failed to delete key %zu", i); + } +} + +ZTEST(posix_apis, test_correct_key_is_deleted) +{ + pthread_key_t key; + size_t j = CONFIG_MAX_PTHREAD_KEY_COUNT - 1; + pthread_key_t keys[CONFIG_MAX_PTHREAD_KEY_COUNT]; + + for (size_t i = 0; i < ARRAY_SIZE(keys); ++i) { + zassert_ok(pthread_key_create(&keys[i], NULL), "failed to create key %zu", i); + } + + key = keys[j]; + zassert_ok(pthread_key_delete(keys[j])); + zassert_ok(pthread_key_create(&keys[j], NULL), "failed to create key %zu", j); + + zassert_equal(key, keys[j], "deleted key %x instead of key %x", keys[j], key); + + for (size_t i = 0; i < ARRAY_SIZE(keys); ++i) { + zassert_ok(pthread_key_delete(keys[i]), "failed to delete key %zu", i); + } +} From cc6bf663452936f1460314f3e5140cdb4b645553 Mon Sep 17 00:00:00 2001 From: Shahar Hadas Date: Sun, 29 Oct 2023 00:24:02 +0300 Subject: [PATCH 0981/1049] auxdisplay: Enhance SerLCD auxdisplay driver Added export of command and special command delays as configurable options. Signed-off-by: Shahar Hadas --- drivers/auxdisplay/auxdisplay_serlcd.c | 25 +++++++++----------- dts/bindings/auxdisplay/sparkfun,serlcd.yaml | 22 +++++++++++++++++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/auxdisplay/auxdisplay_serlcd.c b/drivers/auxdisplay/auxdisplay_serlcd.c index f3c0e76486932c2..19c7154de293c9e 100644 --- a/drivers/auxdisplay/auxdisplay_serlcd.c +++ b/drivers/auxdisplay/auxdisplay_serlcd.c @@ -28,16 +28,6 @@ LOG_MODULE_REGISTER(auxdisplay_serlcd, CONFIG_AUXDISPLAY_LOG_LEVEL); */ #define SERLCD_BEGIN_SPECIAL_COMMAND 0xFE -/* - * delay in milliseconds after a normal command was sent - */ -#define SERLCD_COMMAND_DELAY_MS 10 - -/* - * delay in milliseconds after a special command was sent - */ -#define SERLCD_SPECIAL_COMMAND_DELAY_MS 50 - /* * maximum amount of custom chars the display supports */ @@ -89,6 +79,8 @@ struct auxdisplay_serlcd_data { struct auxdisplay_serlcd_config { struct auxdisplay_capabilities capabilities; struct i2c_dt_spec bus; + uint16_t command_delay_ms; + uint16_t special_command_delay_ms; }; enum auxdisplay_serlcd_command { @@ -111,7 +103,7 @@ static int auxdisplay_serlcd_send_command(const struct device *dev, int rc = i2c_write_dt(&config->bus, buffer, sizeof(buffer)); - k_sleep(K_MSEC(SERLCD_COMMAND_DELAY_MS)); + k_sleep(K_MSEC(config->command_delay_ms)); return rc; } @@ -124,7 +116,7 @@ auxdisplay_serlcd_send_special_command(const struct device *dev, int rc = i2c_write_dt(&config->bus, buffer, sizeof(buffer)); - k_sleep(K_MSEC(SERLCD_SPECIAL_COMMAND_DELAY_MS)); + k_sleep(K_MSEC(config->special_command_delay_ms)); return rc; } @@ -269,9 +261,11 @@ static int auxdisplay_serlcd_capabilities_get(const struct device *dev, static int auxdisplay_serlcd_clear(const struct device *dev) { + const struct auxdisplay_serlcd_config *config = dev->config; + int rc = auxdisplay_serlcd_send_command(dev, SERLCD_COMMAND_CLEAR); - k_sleep(K_MSEC(SERLCD_COMMAND_DELAY_MS)); + k_sleep(K_MSEC(config->command_delay_ms)); return rc; } @@ -425,7 +419,10 @@ static const struct auxdisplay_driver_api auxdisplay_serlcd_auxdisplay_api = { .custom_character_width = SERLCD_CUSTOM_CHAR_WIDTH, \ .custom_character_height = SERLCD_CUSTOM_CHAR_HEIGHT, \ }, \ - .bus = I2C_DT_SPEC_INST_GET(inst)}; \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .command_delay_ms = DT_INST_PROP(inst, command_delay_ms), \ + .special_command_delay_ms = DT_INST_PROP(inst, special_command_delay_ms), \ + }; \ \ static struct auxdisplay_serlcd_data auxdisplay_serlcd_data_##inst; \ \ diff --git a/dts/bindings/auxdisplay/sparkfun,serlcd.yaml b/dts/bindings/auxdisplay/sparkfun,serlcd.yaml index 1a4d5734f369ad8..60c17fc7860ba4e 100644 --- a/dts/bindings/auxdisplay/sparkfun,serlcd.yaml +++ b/dts/bindings/auxdisplay/sparkfun,serlcd.yaml @@ -11,6 +11,8 @@ description: | reg = <0x72>; columns = <16>; rows = <2>; + command-delay = <10>; + special-command-delay = <50>; }; }; @@ -32,3 +34,23 @@ properties: enum: - 2 - 4 + + command-delay-ms: + type: int + default: 10 + description: | + Delay in milliseconds (defaults to 10ms if not set) after a normal command was sent. + The default value is based on the original SparkFun SerLCD library + implementation which assumes 100 kbps I2C configuration. This value + might require tweaking if using I2C at a higher bitrare and/or relativily + high update frequency of the display. + + special-command-delay-ms: + type: int + default: 50 + description: | + Delay in milliseconds (defaults to 50ms if not set) after a special command was sent. + The default value is based on the original SparkFun SerLCD library + implementation which assumes 100 kbps I2C configuration. This value + might require tweaking if using I2C at a higher bitrare and/or relativily + high update frequency of the display. From ad5441bbdde5ee3534e74c732004973d2d9a363d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 21:23:53 -0500 Subject: [PATCH 0982/1049] posix: pthread: move pthread_equal() closer to pthread_self() * "identity" functions grouped more closely * posix_thread_pool_init() should be adjacent to the SYS_INIT() Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index c5c00a53491b7a3..5566fc6616b2343 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -135,6 +135,11 @@ pthread_t pthread_self(void) return mark_pthread_obj_initialized(bit); } +int pthread_equal(pthread_t pt1, pthread_t pt2) +{ + return (pt1 == pt2); +} + static bool is_posix_policy_prio_valid(uint32_t priority, int policy) { if (priority >= sched_get_priority_min(policy) && @@ -973,10 +978,4 @@ static int posix_thread_pool_init(void) return 0; } - -int pthread_equal(pthread_t pt1, pthread_t pt2) -{ - return (pt1 == pt2); -} - SYS_INIT(posix_thread_pool_init, PRE_KERNEL_1, 0); From 131220cb95d6742bd3b20bc6bb04f2b2c6deafab Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:02:21 -0500 Subject: [PATCH 0983/1049] tests: posix: headers: check pthread_spin_lock() et al exist The simple header test was not updated to verify that the following functions were implemented even though they were implemented some time ago. * pthread_spin_destroy() * pthread_spin_init() * pthread_spin_lock() * pthread_spin_trylock() * pthread_spin_unlock() Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index b249c337c18c207..0ff56ea7cf054f4 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -152,10 +152,11 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_setschedparam); /* zassert_not_null(pthread_setschedprio); */ /* not implemented */ zassert_not_null(pthread_setspecific); - /* zassert_not_null(pthread_spin_destroy); */ /* not implemented */ - /* zassert_not_null(pthread_spin_init); */ /* not implemented */ - /* zassert_not_null(pthread_spin_lock); */ /* not implemented */ - /* zassert_not_null(pthread_spin_unlock); */ /* not implemented */ + zassert_not_null(pthread_spin_destroy); + zassert_not_null(pthread_spin_init); + zassert_not_null(pthread_spin_lock); + zassert_not_null(pthread_spin_trylock); + zassert_not_null(pthread_spin_unlock); /* zassert_not_null(pthread_testcancel); */ /* not implemented */ } } From 505e9be2e1ed8df662ba7a9c96e5d0503a6852d1 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:07:42 -0500 Subject: [PATCH 0984/1049] tests: posix: headers: ensure pthread_condattr_getclock() exist These calls were added some time ago, so ensure they are checked for existence. * pthread_condattr_getclock() * pthread_condattr_setclock() Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 0ff56ea7cf054f4..08cf465a82382bb 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -94,10 +94,10 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_cond_timedwait); zassert_not_null(pthread_cond_wait); zassert_not_null(pthread_condattr_destroy); - /* zassert_not_null(pthread_condattr_getclock); */ /* not implemented */ + zassert_not_null(pthread_condattr_getclock); /* zassert_not_null(pthread_condattr_getpshared); */ /* not implemented */ zassert_not_null(pthread_condattr_init); - /* zassert_not_null(pthread_condattr_setclock); */ /* not implemented */ + zassert_not_null(pthread_condattr_setclock); /* zassert_not_null(pthread_condattr_setpshared); */ /* not implemented */ zassert_not_null(pthread_create); zassert_not_null(pthread_detach); From 19ef279dc3bd6365b8e8b538b2a5f9270764fc9b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:12:54 -0500 Subject: [PATCH 0985/1049] posix: define PTHREAD_CANCELED globally Move the definition of PTHREAD_CANCELED from pthread.c to pthread.h. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 1 + lib/posix/pthread.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 2f942f6553cb2a8..c8c1f16f2925816 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -30,6 +30,7 @@ extern "C" { #define PTHREAD_PROCESS_SHARED 1 /* Pthread cancellation */ +#define PTHREAD_CANCELED ((void *)-1) #define _PTHREAD_CANCEL_POS 0 #define PTHREAD_CANCEL_ENABLE (0U << _PTHREAD_CANCEL_POS) #define PTHREAD_CANCEL_DISABLE BIT(_PTHREAD_CANCEL_POS) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 5566fc6616b2343..686b4195f9cf8dc 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -25,8 +25,7 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #define DYNAMIC_STACK_SIZE 0 #endif -#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE -#define PTHREAD_CANCELED ((void *) -1) +#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE enum posix_thread_qid { /* ready to be started via pthread_create() */ From d2e729233db6b9316fbe66b9f41b35494f584bda Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:13:49 -0500 Subject: [PATCH 0986/1049] tests: posix: headers: add verification tests for more constants Ensure that the "headers" test checks that the following constants are defined: * PTHREAD_PROCESS_SHARED * PTHREAD_PROCESS_PRIVATE * PTHREAD_COND_INITIALIZER * PTHREAD_MUTEX_INITIALIZER * PTHREAD_CANCELED They were already defined by previous commits, but the test had not been updated. Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 08cf465a82382bb..51452d88de55d6f 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -28,7 +28,7 @@ ZTEST(posix_headers, test_pthread_h) /* zassert_not_equal(-1, PTHREAD_CANCEL_DEFERRED); */ /* not implemented */ zassert_not_equal(-1, PTHREAD_CANCEL_DISABLE); - /* zassert_not_equal(-1, PTHREAD_CANCELED); */ /* not implemented */ + zassert_not_equal((void *)-42, PTHREAD_CANCELED); zassert_not_equal(-1, PTHREAD_CREATE_DETACHED); zassert_not_equal(-1, PTHREAD_CREATE_JOINABLE); @@ -49,14 +49,14 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_equal(-1, PTHREAD_PRIO_NONE); /* zassert_not_equal(-1, PTHREAD_PRIO_PROTECT); */ /* not implemented */ - /* zassert_not_equal(-1, PTHREAD_PROCESS_SHARED); */ /* not implemented */ - /* zassert_not_equal(-1, PTHREAD_PROCESS_PRIVATE); */ /* not implemented */ + zassert_not_equal(-1, PTHREAD_PROCESS_SHARED); + zassert_not_equal(-1, PTHREAD_PROCESS_PRIVATE); /* zassert_not_equal(-1, PTHREAD_SCOPE_PROCESS); */ /* not implemented */ /* zassert_not_equal(-1, PTHREAD_SCOPE_SYSTEM); */ /* not implemented */ - /* pthread_cond_t cond = PTHREAD_COND_INITIALIZER; */ /* not implemented */ - /* pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; */ /* not implemented */ + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; /* pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; */ /* not implemented */ if (IS_ENABLED(CONFIG_POSIX_API)) { From 87635dd34ae095ebd7cdc4c754c998c7d3768e8c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 22:23:44 -0500 Subject: [PATCH 0987/1049] posix: do not define _PTHREAD_CANCEL_POS _PTHREAD_CANCEL_POS is an implementation detail and should not be defined in the global scope. Furthermore, _PTHREAD_CANCEL_POS uses a reserved identifier (underscore followed by capital letter). Adjust definitions so that the implementation detail is only used in the implementation and not in the interface. Additionally, modify naming so that the non-standard macro does not use a reserved identifier. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 7 +++---- lib/posix/pthread.c | 5 ++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index c8c1f16f2925816..c7909d40ae2c6bd 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -30,10 +30,9 @@ extern "C" { #define PTHREAD_PROCESS_SHARED 1 /* Pthread cancellation */ -#define PTHREAD_CANCELED ((void *)-1) -#define _PTHREAD_CANCEL_POS 0 -#define PTHREAD_CANCEL_ENABLE (0U << _PTHREAD_CANCEL_POS) -#define PTHREAD_CANCEL_DISABLE BIT(_PTHREAD_CANCEL_POS) +#define PTHREAD_CANCELED ((void *)-1) +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 /* Passed to pthread_once */ #define PTHREAD_ONCE_INIT \ diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 686b4195f9cf8dc..e96cfc287e00be2 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -16,6 +16,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); @@ -25,6 +26,8 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #define DYNAMIC_STACK_SIZE 0 #endif +#define _pthread_cancel_pos LOG2(PTHREAD_CANCEL_DISABLE) + #define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE enum posix_thread_qid { @@ -406,7 +409,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou sys_dlist_append(&run_q, &t->q_node); t->qid = POSIX_THREAD_RUN_Q; t->detachstate = attr->detachstate; - if ((BIT(_PTHREAD_CANCEL_POS) & attr->flags) != 0) { + if ((BIT(_pthread_cancel_pos) & attr->flags) != 0) { t->cancel_state = PTHREAD_CANCEL_ENABLE; } t->cancel_pending = false; From ca45155a23f7ad32bb0b2492ee8c70def1efd9bf Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 20 Nov 2023 10:03:16 +0100 Subject: [PATCH 0988/1049] Bluetooth: Controller: Fix NULL pointer dereferencing in Sync ISO Fix NULL pointer dereferencing when Host supplies an out of bounds BIG handle. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_sync_iso.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 513ee3cdbed4b49..2287a2bc3566ee9 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -91,6 +91,16 @@ uint8_t ll_big_sync_create(uint8_t big_handle, uint16_t sync_handle, } sync_iso = sync_iso_get(big_handle); + if (!sync_iso) { + /* Host requested more than supported number of ISO Synchronized + * Receivers. + * Or probably HCI handles where not translated to zero-indexed + * controller handles? + */ + return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + } + + /* Check if this ISO already is associated with a Periodic Sync */ if (sync_iso->sync) { return BT_HCI_ERR_CMD_DISALLOWED; } From 6c7c5bd5dd1ce6450ae3017cf5e5e10b323e9351 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 22 Nov 2023 10:43:23 +0100 Subject: [PATCH 0989/1049] Bluetooth: Controller: Fix uninitialized ad_len_chain variable Fix uninitialized ad_len_chain variable. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/ll_sw/ull_adv_sync.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 5fec8a37534c377..897a39ce65f6aa9 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -403,6 +403,14 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, /* No AD data overflow */ ad_len_overflow = 0U; + + /* No chain PDU. + * Note: Not required to assign as referencing + * is guarded by the fact that ad_len_overflow + * is zero; having the below to make compilers + * not complain of uninitialized variable. + */ + ad_len_chain = 0U; } } } else { @@ -484,7 +492,16 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, /* Proceed to add chain PDU */ err = 0U; } else { + /* No AD data overflow */ ad_len_overflow = 0U; + + /* No chain PDU. + * Note: Not required to assign as referencing is + * guarded by the fact that ad_len_overflow is zero; + * having the below to make compilers not complain of + * uninitialized variable. + */ + ad_len_chain = 0U; } #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */ } From 4cb194f3e8f64908f9e2f7d08a08fbca71cb73bc Mon Sep 17 00:00:00 2001 From: Nikolay Agishev Date: Fri, 17 Nov 2023 13:27:46 +0300 Subject: [PATCH 0990/1049] ARC: MWDT: Force cleanup .device_states section This PR fixes https://github.com/zephyrproject-rtos/zephyr/issues/64268 MWDT supposes .device_states section as BSS because .device_states variables defined as uninitialized. This causes the section marked as NOLOAD section and OpenOCD does not take it in account while flashing it into board memory. Finally .device_states variables becomes initialized with garbage from RAM. In this PR it's suggested to clean .device_states in early init stage. Signed-off-by: Nikolay Agishev --- arch/arc/core/prep_c.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/arc/core/prep_c.c b/arch/arc/core/prep_c.c index 8bf481c86b29128..f0b31a2bb36ff98 100644 --- a/arch/arc/core/prep_c.c +++ b/arch/arc/core/prep_c.c @@ -23,7 +23,6 @@ #include #include - /* XXX - keep for future use in full-featured cache APIs */ #if 0 /** @@ -67,6 +66,21 @@ static void invalidate_dcache(void) } #endif +#ifdef __CCAC__ +extern char __device_states_start[]; +extern char __device_states_end[]; +/** + * @brief Clear device_states section + * + * This routine clears the device_states section, + * as MW compiler marks the section with NOLOAD flag. + */ +static void dev_state_zero(void) +{ + z_early_memset(__device_states_start, 0, __device_states_end - __device_states_start); +} +#endif + extern FUNC_NORETURN void z_cstart(void); /** * @brief Prepare to and run C code @@ -77,6 +91,9 @@ extern FUNC_NORETURN void z_cstart(void); void _PrepC(void) { z_bss_zero(); +#ifdef __CCAC__ + dev_state_zero(); +#endif z_data_copy(); z_cstart(); CODE_UNREACHABLE; From 2ba6bcf90612fe8267eea5821c3449bd0ee647b5 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 22 Nov 2023 16:30:10 -0500 Subject: [PATCH 0991/1049] twister: measure build time and report it in json output Measure both cmake and make/ninja build times and log them in debug mode and additionally put the result in the json report for tracking build times. Cleanup what build/cmake function return and remove unused keys in the result map. Remove some excessive logging of launched jobs or default platforms that gets in the way when in debug mode. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/reports.py | 1 + scripts/pylib/twister/twisterlib/runner.py | 66 ++++++++++--------- .../pylib/twister/twisterlib/testinstance.py | 1 + scripts/pylib/twister/twisterlib/testplan.py | 1 - 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/reports.py b/scripts/pylib/twister/twisterlib/reports.py index be1bbb4dbd7e56c..4895fdfe170dac7 100644 --- a/scripts/pylib/twister/twisterlib/reports.py +++ b/scripts/pylib/twister/twisterlib/reports.py @@ -304,6 +304,7 @@ def json_report(self, filename, version="NA"): if instance.status is not None: suite["execution_time"] = f"{float(handler_time):.2f}" + suite["build_time"] = f"{float(instance.build_time):.2f}" testcases = [] diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index 3471f6bf702d3d9..e3e6562d43751ca 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -263,27 +263,31 @@ def run_build(self, args=[]): if self.cwd: kwargs['cwd'] = self.cwd + start_time = time.time() if sys.platform == 'linux': p = self.jobserver.popen(cmd, **kwargs) else: p = subprocess.Popen(cmd, **kwargs) + logger.debug(f'Running {"".join(cmd)}') out, _ = p.communicate() - results = {} + ret = {} + duration = time.time() - start_time + self.instance.build_time += duration if p.returncode == 0: - msg = "Finished building %s for %s" % (self.source_dir, self.platform.name) + msg = f"Finished building {self.source_dir} for {self.platform.name} in {duration:.2f} seconds" + logger.debug(msg) self.instance.status = "passed" if not self.instance.run: self.instance.add_missing_case_status("skipped", "Test was built only") - results = {'msg': msg, "returncode": p.returncode, "instance": self.instance} + ret = {"returncode": p.returncode} if out: log_msg = out.decode(self.default_encoding) with open(os.path.join(self.build_dir, self.log), "a", encoding=self.default_encoding) as log: log.write(log_msg) - else: return None else: @@ -310,12 +314,11 @@ def run_build(self, args=[]): self.instance.status = "error" self.instance.reason = "Build failure" - results = { - "returncode": p.returncode, - "instance": self.instance, + ret = { + "returncode": p.returncode } - return results + return ret def run_cmake(self, args="", filter_stages=[]): @@ -384,18 +387,24 @@ def run_cmake(self, args="", filter_stages=[]): if self.cwd: kwargs['cwd'] = self.cwd + start_time = time.time() if sys.platform == 'linux': p = self.jobserver.popen(cmd, **kwargs) else: p = subprocess.Popen(cmd, **kwargs) out, _ = p.communicate() + duration = time.time() - start_time + self.instance.build_time += duration + if p.returncode == 0: filter_results = self.parse_generated(filter_stages) - msg = "Finished building %s for %s" % (self.source_dir, self.platform.name) + msg = f"Finished running cmake {self.source_dir} for {self.platform.name} in {duration:.2f} seconds" logger.debug(msg) - results = {'msg': msg, 'filter': filter_results} - + ret = { + 'returncode': p.returncode, + 'filter': filter_results + } else: self.instance.status = "error" self.instance.reason = "Cmake build failure" @@ -404,7 +413,7 @@ def run_cmake(self, args="", filter_stages=[]): tc.status = self.instance.status logger.error("Cmake build failure: %s for %s" % (self.source_dir, self.platform.name)) - results = {"returncode": p.returncode} + ret = {"returncode": p.returncode} if out: os.makedirs(self.build_dir, exist_ok=True) @@ -412,7 +421,7 @@ def run_cmake(self, args="", filter_stages=[]): log_msg = out.decode(self.default_encoding) log.write(log_msg) - return results + return ret class FilterBuilder(CMake): @@ -502,14 +511,14 @@ def parse_generated(self, filter_stages=[]): edt = pickle.load(f) else: edt = None - res = expr_parser.parse(self.testsuite.filter, filter_data, edt) + ret = expr_parser.parse(self.testsuite.filter, filter_data, edt) except (ValueError, SyntaxError) as se: sys.stderr.write( "Failed processing %s\n" % self.testsuite.yamlfile) raise se - if not res: + if not ret: return {os.path.join(self.platform.name, self.testsuite.name): True} else: return {os.path.join(self.platform.name, self.testsuite.name): False} @@ -584,12 +593,12 @@ def process(self, pipeline, done, message, lock, results): self.instance.setup_handler(self.env) if op == "filter": - res = self.cmake(filter_stages=self.instance.filter_stages) + ret = self.cmake(filter_stages=self.instance.filter_stages) if self.instance.status in ["failed", "error"]: pipeline.put({"op": "report", "test": self.instance}) else: # Here we check the dt/kconfig filter results coming from running cmake - if self.instance.name in res['filter'] and res['filter'][self.instance.name]: + if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: logger.debug("filtering %s" % self.instance.name) self.instance.status = "filtered" self.instance.reason = "runtime filter" @@ -600,8 +609,8 @@ def process(self, pipeline, done, message, lock, results): pipeline.put({"op": "cmake", "test": self.instance}) # The build process, call cmake and build with configured generator - if op == "cmake": - res = self.cmake() + elif op == "cmake": + ret = self.cmake() if self.instance.status in ["failed", "error"]: pipeline.put({"op": "report", "test": self.instance}) elif self.options.cmake_only: @@ -610,7 +619,7 @@ def process(self, pipeline, done, message, lock, results): pipeline.put({"op": "report", "test": self.instance}) else: # Here we check the runtime filter results coming from running cmake - if self.instance.name in res['filter'] and res['filter'][self.instance.name]: + if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: logger.debug("filtering %s" % self.instance.name) self.instance.status = "filtered" self.instance.reason = "runtime filter" @@ -622,8 +631,8 @@ def process(self, pipeline, done, message, lock, results): elif op == "build": logger.debug("build test: %s" % self.instance.name) - res = self.build() - if not res: + ret = self.build() + if not ret: self.instance.status = "error" self.instance.reason = "Build Failure" pipeline.put({"op": "report", "test": self.instance}) @@ -634,7 +643,7 @@ def process(self, pipeline, done, message, lock, results): results.skipped_runtime += 1 self.instance.add_missing_case_status("skipped", self.instance.reason) - if res.get('returncode', 1) > 0: + if ret.get('returncode', 1) > 0: self.instance.add_missing_case_status("blocked", self.instance.reason) pipeline.put({"op": "report", "test": self.instance}) else: @@ -1040,13 +1049,10 @@ def cmake(self, filter_stages=[]): self.options.extra_args, # CMake extra args self.instance.build_dir, ) - - res = self.run_cmake(args,filter_stages) - return res + return self.run_cmake(args,filter_stages) def build(self): - res = self.run_build(['--build', self.build_dir]) - return res + return self.run_build(['--build', self.build_dir]) def run(self): @@ -1289,11 +1295,11 @@ def execute(self, pipeline, done): processes = [] - for job in range(self.jobs): - logger.debug(f"Launch process {job}") + for _ in range(self.jobs): p = Process(target=self.pipeline_mgr, args=(pipeline, done, lock, self.results, )) processes.append(p) p.start() + logger.debug(f"Launched {self.jobs} jobs") try: for p in processes: diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index 958019b411a344c..d3cbbaf4986f5d4 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -50,6 +50,7 @@ def __init__(self, testsuite, platform, outdir): self.handler = None self.outdir = outdir self.execution_time = 0 + self.build_time = 0 self.retries = 0 self.name = os.path.join(platform.name, testsuite.name) diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 930d4573b19dcf4..64de886471150ab 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -416,7 +416,6 @@ def add_configurations(self): self.platforms.append(platform) if not platform_config.get('override_default_platforms', False): if platform.default: - logger.debug(f"adding {platform.name} to default platforms") self.default_platforms.append(platform.name) else: if platform.name in platform_config.get('default_platforms', []): From c696344f0d55009e05f049fe5a597a886dde16bd Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 23 Nov 2023 07:32:27 -0500 Subject: [PATCH 0992/1049] twister: tests: adapt tests for new behaviour in runner class We have removed some return data and added build time to instance class. Signed-off-by: Anas Nashif --- scripts/tests/twister/test_runner.py | 40 +++++++++------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/scripts/tests/twister/test_runner.py b/scripts/tests/twister/test_runner.py index f0c2cbb50cf1355..e4d886191fd60d9 100644 --- a/scripts/tests/twister/test_runner.py +++ b/scripts/tests/twister/test_runner.py @@ -250,20 +250,20 @@ def test_cmake_parse_generated(mocked_jobserver): ] TESTDATA_1_2 = [ (0, False, 'dummy out', - True, True, True, True, 'passed', None, False, True), + True, True, 'passed', None, False, True), (0, True, '', - False, False, False, False, 'passed', None, False, False), + False, False, 'passed', None, False, False), (1, True, 'ERROR: region `FLASH\' overflowed by 123 MB', - False, True, True, True, 'skipped', 'FLASH overflow', True, False), + True, True, 'skipped', 'FLASH overflow', True, False), (1, True, 'Error: Image size (99 B) + trailer (1 B) exceeds requested size', - False, True, True, True, 'skipped', 'imgtool overflow', True, False), + True, True, 'skipped', 'imgtool overflow', True, False), (1, True, 'mock.ANY', - False, True, True, True, 'error', 'Build failure', False, False) + True, True, 'error', 'Build failure', False, False) ] @pytest.mark.parametrize( - 'return_code, is_instance_run, p_out, expect_msg, expect_returncode,' \ - ' expect_instance, expect_writes, expected_status, expected_reason,' \ + 'return_code, is_instance_run, p_out, expect_returncode,' \ + ' expect_writes, expected_status, expected_reason,' \ ' expected_change_skip, expected_add_missing', TESTDATA_1_2, ids=['no error, no instance run', 'no error, instance run', @@ -275,9 +275,7 @@ def test_cmake_run_build( return_code, is_instance_run, p_out, - expect_msg, expect_returncode, - expect_instance, expect_writes, expected_status, expected_reason, @@ -303,6 +301,7 @@ def mock_popen(*args, **kwargs): popen=mock.Mock(side_effect=mock_popen) ) instance_mock = mock.Mock(add_missing_case_status=mock.Mock()) + instance_mock.build_time = 0 instance_mock.run = is_instance_run instance_mock.status = None instance_mock.reason = None @@ -328,14 +327,8 @@ def mock_popen(*args, **kwargs): result = cmake.run_build(args=['arg1', 'arg2']) expected_results = {} - if expect_msg: - expected_results['msg'] = 'Finished building %s for %s' % \ - (os.path.join('source', 'dir'), \ - '') if expect_returncode: expected_results['returncode'] = return_code - if expect_instance: - expected_results['instance'] = instance_mock if expected_results == {}: expected_results = None @@ -369,7 +362,7 @@ def mock_popen(*args, **kwargs): TESTDATA_2_2 = [ (True, ['dummy_stage_1', 'ds2'], 0, False, '', - True, False, True, False, + True, True, False, None, None, [os.path.join('dummy', 'cmake'), '-B' + os.path.join('build', 'dir'), '-DTC_RUNID=1', @@ -383,7 +376,7 @@ def mock_popen(*args, **kwargs): '-Pzephyr_base/cmake/package_helper.cmake']), (False, [], 1, True, 'ERROR: region `FLASH\' overflowed by 123 MB', - False, True, False, True, + True, False, True, 'error', 'Cmake build failure', [os.path.join('dummy', 'cmake'), '-B' + os.path.join('build', 'dir'), '-DTC_RUNID=1', @@ -398,7 +391,7 @@ def mock_popen(*args, **kwargs): @pytest.mark.parametrize( 'error_warns, f_stages,' \ - ' return_code, is_instance_run, p_out, expect_msg, expect_returncode,' \ + ' return_code, is_instance_run, p_out, expect_returncode,' \ ' expect_filter, expect_writes, expected_status, expected_reason,' \ ' expected_cmd', TESTDATA_2_2, @@ -412,7 +405,6 @@ def test_cmake_run_cmake( return_code, is_instance_run, p_out, - expect_msg, expect_returncode, expect_filter, expect_writes, @@ -442,6 +434,7 @@ def mock_popen(*args, **kwargs): instance_mock = mock.Mock(add_missing_case_status=mock.Mock()) instance_mock.run = is_instance_run instance_mock.run_id = 1 + instance_mock.build_time = 0 instance_mock.status = None instance_mock.reason = None instance_mock.testsuite = mock.Mock() @@ -476,10 +469,6 @@ def mock_popen(*args, **kwargs): result = cmake.run_cmake(args=['arg1', 'arg2'], filter_stages=f_stages) expected_results = {} - if expect_msg: - expected_results['msg'] = 'Finished building %s for %s' % \ - (os.path.join('source', 'dir'), \ - '') if expect_returncode: expected_results['returncode'] = return_code if expect_filter: @@ -2650,11 +2639,6 @@ def mock_join(): with mock.patch('twisterlib.runner.Process', process_mock): tr.execute(pipeline_mock, done_mock) - assert 'Launch process 0' in caplog.text - assert 'Launch process 1' in caplog.text - assert 'Launch process 2' in caplog.text - assert 'Launch process 3' in caplog.text - assert 'Launch process 4' in caplog.text assert 'Execution interrupted' in caplog.text assert len(process_mock().start.call_args_list) == 5 From eb879413be488d441ea2e48084dc77852045b2df Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Mon, 17 Jul 2023 15:43:05 +0200 Subject: [PATCH 0993/1049] drivers: gpio: rcar: Add R-Car Gen4 support Renesas Gen4 SoCs GPIO IPs are using one more register comparing to Gen3 SoCs. The new "INEN" register is used to enable general input. Signed-off-by: Aymeric Aillet --- drivers/gpio/gpio_rcar.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_rcar.c b/drivers/gpio/gpio_rcar.c index 820db5fc76cfc8c..f60112427bc80a4 100644 --- a/drivers/gpio/gpio_rcar.c +++ b/drivers/gpio/gpio_rcar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 IoT.bzh + * Copyright (c) 2020-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ @@ -52,6 +52,7 @@ struct gpio_rcar_data { #define FILONOFF 0x28 /* Chattering Prevention On/Off Register */ #define OUTDTSEL 0x40 /* Output Data Select Register */ #define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */ +#define INEN 0x50 /* General Input Enable Register */ static inline uint32_t gpio_rcar_read(const struct device *dev, uint32_t offs) { @@ -106,6 +107,11 @@ static void gpio_rcar_config_general_input_output_mode( /* Configure positive logic in POSNEG */ gpio_rcar_modify_bit(dev, POSNEG, gpio, false); + /* Select "Input Enable/Disable" in INEN for Gen4 SoCs */ +#ifdef CONFIG_SOC_SERIES_RCAR_GEN4 + gpio_rcar_modify_bit(dev, INEN, gpio, !output); +#endif + /* Select "General Input/Output Mode" in IOINTSEL */ gpio_rcar_modify_bit(dev, IOINTSEL, gpio, false); @@ -223,6 +229,11 @@ static int gpio_rcar_pin_interrupt_configure(const struct device *dev, gpio_rcar_modify_bit(dev, BOTHEDGE, pin, true); } + /* Select "Input Enable" in INEN for Gen4 SoCs */ +#ifdef CONFIG_SOC_SERIES_RCAR_GEN4 + gpio_rcar_modify_bit(dev, INEN, pin, true); +#endif + gpio_rcar_modify_bit(dev, IOINTSEL, pin, true); if (mode == GPIO_INT_MODE_EDGE) { From 1738543c5d15d31be4d98f952a23395f23e27fa5 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Tue, 18 Jul 2023 13:53:24 +0200 Subject: [PATCH 0994/1049] drivers: pinctrl: Add R-Car Gen4 support Renesas R-Car Gen4 is different from Gen3 regarding pinmux. While Gen3 had only one base address to manage all pins, Gen4 has one set of pinmux registers per GPIO banks. We could expose one pinmux register per GPIO controllers, but that would break potential compatibility with Linux Device tree. Instead create a reg_base array to parse all reg base from device tree and identify proper base address based on the pin definition. This imply to add a pfc_base parameter to most of the pfc_rcar function. Signed-off-by: Julien Massot Signed-off-by: Pierre Marzin Signed-off-by: Aymeric Aillet --- drivers/pinctrl/pfc_rcar.c | 95 ++++++++++----- drivers/pinctrl/pfc_rcar.h | 26 ++++ .../pinctrl/renesas/pinctrl-rcar-common.h | 34 +++++- soc/arm/renesas_rcar/CMakeLists.txt | 1 + soc/arm/renesas_rcar/common/pinctrl_rcar.h | 115 ++++++++++++++++++ soc/arm/renesas_rcar/gen3/pfc_r8a77951.c | 10 +- soc/arm/renesas_rcar/gen3/pinctrl_soc.h | 109 +---------------- soc/arm/renesas_rcar/gen4/CMakeLists.txt | 2 + soc/arm/renesas_rcar/gen4/pinctrl_soc.h | 12 ++ soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c | 7 ++ soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c | 7 ++ soc/arm64/renesas_rcar/gen3/pinctrl_soc.h | 3 - 12 files changed, 281 insertions(+), 140 deletions(-) create mode 100644 drivers/pinctrl/pfc_rcar.h create mode 100644 soc/arm/renesas_rcar/common/pinctrl_rcar.h create mode 100644 soc/arm/renesas_rcar/gen4/CMakeLists.txt create mode 100644 soc/arm/renesas_rcar/gen4/pinctrl_soc.h diff --git a/drivers/pinctrl/pfc_rcar.c b/drivers/pinctrl/pfc_rcar.c index 17705e0a8635174..26c5d08c20bbb2d 100644 --- a/drivers/pinctrl/pfc_rcar.c +++ b/drivers/pinctrl/pfc_rcar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 * @@ -7,6 +7,7 @@ #define DT_DRV_COMPAT renesas_rcar_pfc +#include "pfc_rcar.h" #include #include #include @@ -14,12 +15,25 @@ #include #include -DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); - -#define PFC_REG_BASE DEVICE_MMIO_TOPLEVEL_GET(pfc) #define PFC_RCAR_PMMR 0x0 + +/* Gen3 only has one base address, Gen4 has one per GPIO controller */ +#if defined(CONFIG_SOC_SERIES_RCAR_GEN3) #define PFC_RCAR_GPSR 0x100 #define PFC_RCAR_IPSR 0x200 +DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); +static uintptr_t reg_base[1]; +#elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) +#define PFC_RCAR_GPSR 0x040 +#define PFC_RCAR_IPSR 0x060 +/* swap both arguments */ +#define PFC_REG_ADDRESS(idx, node_id) DT_REG_ADDR_BY_IDX(node_id, idx) +static const uintptr_t reg_base[] = { + LISTIFY(DT_NUM_REGS(DT_DRV_INST(0)), PFC_REG_ADDRESS, (,), DT_DRV_INST(0)) +}; +#else +#error Unsupported SoC Series +#endif /* * Each drive step is either encoded in 2 or 3 bits. @@ -33,18 +47,25 @@ DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); /* Some registers such as IPSR GPSR or DRVCTRL are protected and * must be preceded to a write to PMMR with the inverse value. */ -static void pfc_rcar_write(uint32_t offs, uint32_t val) +static void pfc_rcar_write(uintptr_t pfc_base, uint32_t offs, uint32_t val) { - sys_write32(~val, PFC_REG_BASE + PFC_RCAR_PMMR); - sys_write32(val, PFC_REG_BASE + offs); + sys_write32(~val, pfc_base + PFC_RCAR_PMMR); + sys_write32(val, pfc_base + offs); } /* Set the pin either in gpio or peripheral */ -static void pfc_rcar_set_gpsr(uint16_t pin, bool peripheral) +static void pfc_rcar_set_gpsr(uintptr_t pfc_base, + uint16_t pin, bool peripheral) { +#if defined(CONFIG_SOC_SERIES_RCAR_GEN3) + /* On Gen3 we have multiple GPSR at one base address */ uint8_t bank = pin / 32; +#elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) + /* On Gen4 we have one GPSR at multiple base address */ + uint8_t bank = 0; +#endif uint8_t bit = pin % 32; - uint32_t val = sys_read32(PFC_REG_BASE + PFC_RCAR_GPSR + + uint32_t val = sys_read32(pfc_base + PFC_RCAR_GPSR + bank * sizeof(uint32_t)); if (peripheral) { @@ -52,18 +73,19 @@ static void pfc_rcar_set_gpsr(uint16_t pin, bool peripheral) } else { val &= ~BIT(bit); } - pfc_rcar_write(PFC_RCAR_GPSR + bank * sizeof(uint32_t), val); + pfc_rcar_write(pfc_base, PFC_RCAR_GPSR + bank * sizeof(uint32_t), val); } /* Set peripheral function */ -static void pfc_rcar_set_ipsr(const struct rcar_pin_func *rcar_func) +static void pfc_rcar_set_ipsr(uintptr_t pfc_base, + const struct rcar_pin_func *rcar_func) { uint16_t reg_offs = PFC_RCAR_IPSR + rcar_func->bank * sizeof(uint32_t); - uint32_t val = sys_read32(PFC_REG_BASE + reg_offs); + uint32_t val = sys_read32(pfc_base + reg_offs); val &= ~(0xFU << rcar_func->shift); val |= (rcar_func->func << rcar_func->shift); - pfc_rcar_write(reg_offs, val); + pfc_rcar_write(pfc_base, reg_offs, val); } static uint32_t pfc_rcar_get_drive_reg(uint16_t pin, uint8_t *offset, @@ -90,7 +112,8 @@ static uint32_t pfc_rcar_get_drive_reg(uint16_t pin, uint8_t *offset, * using DRVCTRLx registers, some pins have 8 steps (3 bits size encoded) * some have 4 steps (2 bits size encoded). */ -static int pfc_rcar_set_drive_strength(uint16_t pin, uint8_t strength) +static int pfc_rcar_set_drive_strength(uintptr_t pfc_base, uint16_t pin, + uint8_t strength) { uint8_t offset, size, step; uint32_t reg, val; @@ -110,11 +133,11 @@ static int pfc_rcar_set_drive_strength(uint16_t pin, uint8_t strength) */ strength = (strength / step) - 1U; /* clear previous drive strength value */ - val = sys_read32(PFC_REG_BASE + reg); + val = sys_read32(pfc_base + reg); val &= ~GENMASK(offset + size - 1U, offset); val |= strength << offset; - pfc_rcar_write(reg, val); + pfc_rcar_write(pfc_base, reg, val); return 0; } @@ -138,7 +161,7 @@ static const struct pfc_bias_reg *pfc_rcar_get_bias_reg(uint16_t pin, return NULL; } -int pfc_rcar_set_bias(uint16_t pin, uint16_t flags) +int pfc_rcar_set_bias(uintptr_t pfc_base, uint16_t pin, uint16_t flags) { uint32_t val; uint8_t bit; @@ -149,19 +172,19 @@ int pfc_rcar_set_bias(uint16_t pin, uint16_t flags) } /* pull enable/disable*/ - val = sys_read32(PFC_REG_BASE + bias_reg->puen); + val = sys_read32(pfc_base + bias_reg->puen); if ((flags & RCAR_PIN_FLAGS_PUEN) == 0U) { - sys_write32(val & ~BIT(bit), PFC_REG_BASE + bias_reg->puen); + sys_write32(val & ~BIT(bit), pfc_base + bias_reg->puen); return 0; } - sys_write32(val | BIT(bit), PFC_REG_BASE + bias_reg->puen); + sys_write32(val | BIT(bit), pfc_base + bias_reg->puen); /* pull - up/down */ - val = sys_read32(PFC_REG_BASE + bias_reg->pud); + val = sys_read32(pfc_base + bias_reg->pud); if (flags & RCAR_PIN_FLAGS_PUD) { - sys_write32(val | BIT(bit), PFC_REG_BASE + bias_reg->pud); + sys_write32(val | BIT(bit), pfc_base + bias_reg->pud); } else { - sys_write32(val & ~BIT(bit), PFC_REG_BASE + bias_reg->pud); + sys_write32(val & ~BIT(bit), pfc_base + bias_reg->pud); } return 0; } @@ -169,10 +192,23 @@ int pfc_rcar_set_bias(uint16_t pin, uint16_t flags) int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) { int ret = 0; + uint8_t reg_index; + uintptr_t pfc_base; + + ret = pfc_rcar_get_reg_index(pin->pin, ®_index); + if (ret) { + return ret; + } + + if (reg_index >= ARRAY_SIZE(reg_base)) { + return -EINVAL; + } + + pfc_base = reg_base[reg_index]; /* Set pin as GPIO if capable */ if (RCAR_IS_GP_PIN(pin->pin)) { - pfc_rcar_set_gpsr(pin->pin, false); + pfc_rcar_set_gpsr(pfc_base, pin->pin, false); } else if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) == 0U) { /* A function must be set for non GPIO capable pin */ return -EINVAL; @@ -180,14 +216,14 @@ int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) /* Select function for pin */ if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) != 0U) { - pfc_rcar_set_ipsr(&pin->func); + pfc_rcar_set_ipsr(pfc_base, &pin->func); if (RCAR_IS_GP_PIN(pin->pin)) { - pfc_rcar_set_gpsr(pin->pin, true); + pfc_rcar_set_gpsr(pfc_base, pin->pin, true); } if ((pin->flags & RCAR_PIN_FLAGS_PULL_SET) != 0U) { - ret = pfc_rcar_set_bias(pin->pin, pin->flags); + ret = pfc_rcar_set_bias(pfc_base, pin->pin, pin->flags); if (ret < 0) { return ret; } @@ -195,7 +231,7 @@ int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) } if (pin->drive_strength != 0U) { - ret = pfc_rcar_set_drive_strength(pin->pin, + ret = pfc_rcar_set_drive_strength(pfc_base, pin->pin, pin->drive_strength); } @@ -218,10 +254,13 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, return ret; } +#if defined(CONFIG_SOC_SERIES_RCAR_GEN3) __boot_func static int pfc_rcar_driver_init(void) { DEVICE_MMIO_TOPLEVEL_MAP(pfc, K_MEM_CACHE_NONE); + reg_base[0] = DEVICE_MMIO_TOPLEVEL_GET(pfc); return 0; } SYS_INIT(pfc_rcar_driver_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif diff --git a/drivers/pinctrl/pfc_rcar.h b/drivers/pinctrl/pfc_rcar.h new file mode 100644 index 000000000000000..cbef35ff76bc91f --- /dev/null +++ b/drivers/pinctrl/pfc_rcar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_PINCTRL_PFC_RCAR_H_ +#define ZEPHYR_DRIVERS_PINCTRL_PFC_RCAR_H_ + +#include +#include + +const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void); +const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void); + +/** + * @brief set the register index for a given pin + * + * @param the pin + * @param pointer for the resulting register index + * @return 0 if the register index is found, negative + * errno otherwise. + */ +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index); + +#endif /* ZEPHYR_DRIVERS_PINCTRL_PFC_RCAR_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h index fc8d5090e84b280..504ee2a4d554476 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ @@ -40,4 +40,36 @@ */ #define RCAR_NOGP_PIN(pin) (PIN_NOGPSR_START + pin) +/* Renesas Gen4 has IPSR registers at different base address + * reg is here an index for the base address. + * Each base address has 4 IPSR banks. + */ +#define IPnSR(bank, reg, shift, func) \ + IPSR(((reg) << 4U) | (bank), shift, func) + +#define IP0SR0(shift, func) IPnSR(0, 0, shift, func) +#define IP1SR0(shift, func) IPnSR(1, 0, shift, func) +#define IP2SR0(shift, func) IPnSR(2, 0, shift, func) +#define IP3SR0(shift, func) IPnSR(3, 0, shift, func) +#define IP0SR1(shift, func) IPnSR(0, 1, shift, func) +#define IP1SR1(shift, func) IPnSR(1, 1, shift, func) +#define IP2SR1(shift, func) IPnSR(2, 1, shift, func) +#define IP3SR1(shift, func) IPnSR(3, 1, shift, func) +#define IP0SR2(shift, func) IPnSR(0, 2, shift, func) +#define IP1SR2(shift, func) IPnSR(1, 2, shift, func) +#define IP2SR2(shift, func) IPnSR(2, 2, shift, func) +#define IP3SR2(shift, func) IPnSR(3, 2, shift, func) +#define IP0SR3(shift, func) IPnSR(0, 3, shift, func) +#define IP1SR3(shift, func) IPnSR(1, 3, shift, func) +#define IP2SR3(shift, func) IPnSR(2, 3, shift, func) +#define IP3SR3(shift, func) IPnSR(3, 3, shift, func) +#define IP0SR4(shift, func) IPnSR(0, 4, shift, func) +#define IP1SR4(shift, func) IPnSR(1, 4, shift, func) +#define IP2SR4(shift, func) IPnSR(2, 4, shift, func) +#define IP3SR4(shift, func) IPnSR(3, 4, shift, func) +#define IP0SR5(shift, func) IPnSR(0, 5, shift, func) +#define IP1SR5(shift, func) IPnSR(1, 5, shift, func) +#define IP2SR5(shift, func) IPnSR(2, 5, shift, func) +#define IP3SR5(shift, func) IPnSR(3, 5, shift, func) + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_RCAR_COMMON_H_ */ diff --git a/soc/arm/renesas_rcar/CMakeLists.txt b/soc/arm/renesas_rcar/CMakeLists.txt index 226f3bd626f6119..20bed32f36af328 100644 --- a/soc/arm/renesas_rcar/CMakeLists.txt +++ b/soc/arm/renesas_rcar/CMakeLists.txt @@ -1,3 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 add_subdirectory(${SOC_SERIES}) +zephyr_include_directories(common) diff --git a/soc/arm/renesas_rcar/common/pinctrl_rcar.h b/soc/arm/renesas_rcar/common/pinctrl_rcar.h new file mode 100644 index 000000000000000..0533649d413d002 --- /dev/null +++ b/soc/arm/renesas_rcar/common/pinctrl_rcar.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RCAR_COMMON_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RCAR_COMMON_PINCTRL_SOC_H_ + +#include +#include +#include +#include + +struct rcar_pin_func { + uint8_t bank:5; /* bank number 0 - 18 */ + uint8_t shift:5; /* bit shift 0 - 28 */ + uint8_t func:4; /* choice from 0x0 to 0xF */ +}; + +/** Pull-up, pull-down, or bias disable is requested */ +#define RCAR_PIN_FLAGS_PULL_SET BIT(0) +/** Performs on/off control of the pull resistors */ +#define RCAR_PIN_FLAGS_PUEN BIT(1) +/** Select pull-up resistor if set pull-down otherwise */ +#define RCAR_PIN_FLAGS_PUD BIT(2) +/** Alternate function for the pin is requested */ +#define RCAR_PIN_FLAGS_FUNC_SET BIT(3) + +#define RCAR_PIN_PULL_UP (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN | RCAR_PIN_FLAGS_PUD) +#define RCAR_PIN_PULL_DOWN (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN) +#define RCAR_PIN_PULL_DISABLE RCAR_PIN_FLAGS_PULL_SET + +/** Type for R-Car pin. */ +typedef struct pinctrl_soc_pin { + uint16_t pin; + struct rcar_pin_func func; + uint8_t flags; + uint8_t drive_strength; +} pinctrl_soc_pin_t; + +#define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) +#define RCAR_HAS_IPSR(node_id) DT_PROP_HAS_IDX(node_id, pin, 1) + +/* Offsets are defined in dt-bindings pinctrl-rcar-common.h */ +#define RCAR_PIN_FUNC(node_id) \ + { \ + ((RCAR_IPSR(node_id) >> 10U) & 0x1FU), \ + ((RCAR_IPSR(node_id) >> 4U) & 0x1FU), \ + ((RCAR_IPSR(node_id) & 0xFU)) \ + } + +#define RCAR_PIN_FLAGS(node_id) \ + DT_PROP(node_id, bias_pull_up) * RCAR_PIN_PULL_UP | \ + DT_PROP(node_id, bias_pull_down) * RCAR_PIN_PULL_DOWN | \ + DT_PROP(node_id, bias_disable) * RCAR_PIN_PULL_DISABLE | \ + RCAR_HAS_IPSR(node_id) * RCAR_PIN_FLAGS_FUNC_SET + +#define RCAR_DT_PIN(node_id) \ + { \ + .pin = DT_PROP_BY_IDX(node_id, pin, 0), \ + .func = COND_CODE_1(RCAR_HAS_IPSR(node_id), \ + (RCAR_PIN_FUNC(node_id)), {0}), \ + .flags = RCAR_PIN_FLAGS(node_id), \ + .drive_strength = \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ + (DT_PROP(node_id, drive_strength)), (0)), \ + }, + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param state_prop State property name. + * @param idx State property entry index. + */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, state_prop, idx) \ + RCAR_DT_PIN(DT_PROP_BY_IDX(node_id, state_prop, idx)) + +/** + * @brief Utility macro to initialize state pins contained in a given property. + * + * @param node_id Node identifier. + * @param prop Property name describing state pins. + */ +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } + +struct pfc_drive_reg_field { + uint16_t pin; + uint8_t offset; + uint8_t size; +}; + +struct pfc_drive_reg { + uint32_t reg; + const struct pfc_drive_reg_field fields[8]; +}; + +struct pfc_bias_reg { + uint32_t puen; /** Pull-enable or pull-up control register */ + uint32_t pud; /** Pull-up/down or pull-down control register */ + const uint16_t pins[32]; +}; + +/** + * @brief Utility macro to check if a pin is GPIO capable + * + * @param pin + * @return true if pin is GPIO capable false otherwise + */ +#define RCAR_IS_GP_PIN(pin) (pin < PIN_NOGPSR_START) + +#endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_COMMON_PINCTRL_SOC_H_ */ diff --git a/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c b/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c index c59be6cfe6fdf4f..c5fb3ab967b246c 100644 --- a/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c +++ b/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 * @@ -528,6 +528,7 @@ const struct pfc_bias_reg pfc_bias_regs[] = { } }, { /* sentinel */ }, }; + const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void) { return pfc_bias_regs; @@ -536,3 +537,10 @@ const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) { return pfc_drive_regs; } + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + /* There is only one register on Gen 3 */ + *reg_index = 0; + return 0; +} diff --git a/soc/arm/renesas_rcar/gen3/pinctrl_soc.h b/soc/arm/renesas_rcar/gen3/pinctrl_soc.h index 92f7aa507a44f37..b4f5da3bff0fdbb 100644 --- a/soc/arm/renesas_rcar/gen3/pinctrl_soc.h +++ b/soc/arm/renesas_rcar/gen3/pinctrl_soc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 * @@ -7,111 +7,6 @@ #ifndef ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ #define ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ - -#include -#include -#include -#include - -struct rcar_pin_func { - uint8_t bank:5; /* bank number 0 - 18 */ - uint8_t shift:5; /* bit shift 0 - 28 */ - uint8_t func:4; /* choice from 0x0 to 0xF */ -}; -/** Pull-up, pull-down, or bias disable is requested */ -#define RCAR_PIN_FLAGS_PULL_SET BIT(0) -/** Performs on/off control of the pull resistors */ -#define RCAR_PIN_FLAGS_PUEN BIT(1) -/** Select pull-up resistor if set pull-down otherwise */ -#define RCAR_PIN_FLAGS_PUD BIT(2) -/** Alternate function for the pin is requested */ -#define RCAR_PIN_FLAGS_FUNC_SET BIT(3) - -#define RCAR_PIN_PULL_UP (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN | RCAR_PIN_FLAGS_PUD) -#define RCAR_PIN_PULL_DOWN (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN) -#define RCAR_PIN_PULL_DISABLE RCAR_PIN_FLAGS_PULL_SET - -/** Type for R-Car pin. */ -typedef struct pinctrl_soc_pin { - uint16_t pin; - struct rcar_pin_func func; - uint8_t flags; - uint8_t drive_strength; -} pinctrl_soc_pin_t; - -#define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) -#define RCAR_HAS_IPSR(node_id) DT_PROP_HAS_IDX(node_id, pin, 1) - -/* Offsets are defined in dt-bindings pinctrl-rcar-common.h */ -#define RCAR_PIN_FUNC(node_id) \ - { \ - ((RCAR_IPSR(node_id) >> 10U) & 0x1FU), \ - ((RCAR_IPSR(node_id) >> 4U) & 0x1FU), \ - ((RCAR_IPSR(node_id) & 0xFU)) \ - } - -#define RCAR_PIN_FLAGS(node_id) \ - DT_PROP(node_id, bias_pull_up) * RCAR_PIN_PULL_UP | \ - DT_PROP(node_id, bias_pull_down) * RCAR_PIN_PULL_DOWN | \ - DT_PROP(node_id, bias_disable) * RCAR_PIN_PULL_DISABLE | \ - RCAR_HAS_IPSR(node_id) * RCAR_PIN_FLAGS_FUNC_SET - -#define RCAR_DT_PIN(node_id) \ - { \ - .pin = DT_PROP_BY_IDX(node_id, pin, 0), \ - .func = COND_CODE_1(RCAR_HAS_IPSR(node_id), \ - (RCAR_PIN_FUNC(node_id)), (0)), \ - .flags = RCAR_PIN_FLAGS(node_id), \ - .drive_strength = \ - COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ - (DT_PROP(node_id, drive_strength)), (0)), \ - }, - -/** - * @brief Utility macro to initialize each pin. - * - * @param node_id Node identifier. - * @param state_prop State property name. - * @param idx State property entry index. - */ -#define Z_PINCTRL_STATE_PIN_INIT(node_id, state_prop, idx) \ - RCAR_DT_PIN(DT_PROP_BY_IDX(node_id, state_prop, idx)) - -/** - * @brief Utility macro to initialize state pins contained in a given property. - * - * @param node_id Node identifier. - * @param prop Property name describing state pins. - */ -#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ - { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } - -struct pfc_drive_reg_field { - uint16_t pin; - uint8_t offset; - uint8_t size; -}; - -struct pfc_drive_reg { - uint32_t reg; - const struct pfc_drive_reg_field fields[8]; -}; - -struct pfc_bias_reg { - uint32_t puen; /** Pull-enable or pull-up control register */ - uint32_t pud; /** Pull-up/down or pull-down control register */ - const uint16_t pins[32]; -}; - -const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void); -const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void); - -/** - * @brief Utility macro to check if a pin is GPIO capable - * - * @param pin - * @return true if pin is GPIO capable false otherwise - */ -#define RCAR_IS_GP_PIN(pin) (pin < PIN_NOGPSR_START) +#include #endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ */ diff --git a/soc/arm/renesas_rcar/gen4/CMakeLists.txt b/soc/arm/renesas_rcar/gen4/CMakeLists.txt new file mode 100644 index 000000000000000..3315eaa55eb90eb --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/CMakeLists.txt @@ -0,0 +1,2 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 diff --git a/soc/arm/renesas_rcar/gen4/pinctrl_soc.h b/soc/arm/renesas_rcar/gen4/pinctrl_soc.h new file mode 100644 index 000000000000000..f55b114cddba3be --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/pinctrl_soc.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN4_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN4_PINCTRL_SOC_H_ +#include + +#endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN4_PINCTRL_SOC_H_ */ diff --git a/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c b/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c index c59be6cfe6fdf4f..2d5c02316efcedc 100644 --- a/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c +++ b/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c @@ -536,3 +536,10 @@ const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) { return pfc_drive_regs; } + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + /* There is only one register on Gen 3 */ + *reg_index = 0; + return 0; +} diff --git a/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c b/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c index c130dd510a83406..b219e626e440fd5 100644 --- a/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c +++ b/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c @@ -144,3 +144,10 @@ const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) { return pfc_drive_regs; } + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + /* There is only one register on Gen 3 */ + *reg_index = 0; + return 0; +} diff --git a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h index 92f7aa507a44f37..72c07ae9a4f3b64 100644 --- a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h +++ b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h @@ -103,9 +103,6 @@ struct pfc_bias_reg { const uint16_t pins[32]; }; -const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void); -const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void); - /** * @brief Utility macro to check if a pin is GPIO capable * From 6033db5360f9320065f4df25806be1a45fdc980c Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Tue, 21 Mar 2023 18:07:11 +0100 Subject: [PATCH 0995/1049] drivers: pinctrl: rcar: Add r8a779f0 support Enable PFC controller for r8a779f0 SoC. Declare pin list for r8a779f0 SoC. Signed-off-by: Aymeric Aillet --- .../pinctrl/renesas/pinctrl-r8a779f0.h | 536 ++++++++++++++++ soc/arm/renesas_rcar/gen4/CMakeLists.txt | 2 + soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c | 604 ++++++++++++++++++ 3 files changed, 1142 insertions(+) create mode 100644 include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h create mode 100644 soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h new file mode 100644 index 000000000000000..50e8a3580070fe2 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A779F0_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A779F0_H_ + +#include "pinctrl-rcar-common.h" + +/* Pins declaration */ +#define PIN_NONE -1 +#define PIN_SCIF_CLK RCAR_GP_PIN(0, 0) +#define PIN_HSCK0 RCAR_GP_PIN(0, 1) +#define PIN_HRX0 RCAR_GP_PIN(0, 2) +#define PIN_HTX0 RCAR_GP_PIN(0, 3) +#define PIN_HCTS0_N RCAR_GP_PIN(0, 4) +#define PIN_HRTS0_N RCAR_GP_PIN(0, 5) +#define PIN_RX0 RCAR_GP_PIN(0, 6) +#define PIN_TX0 RCAR_GP_PIN(0, 7) +#define PIN_SCK0 RCAR_GP_PIN(0, 8) +#define PIN_RTS0_N RCAR_GP_PIN(0, 9) +#define PIN_CTS0_N RCAR_GP_PIN(0, 10) +#define PIN_MSIOF0_SYNC RCAR_GP_PIN(0, 11) +#define PIN_MSIOF0_RXD RCAR_GP_PIN(0, 12) +#define PIN_MSIOF0_TXD RCAR_GP_PIN(0, 13) +#define PIN_MSIOF0_SCK RCAR_GP_PIN(0, 14) +#define PIN_MSIOF0_SS1 RCAR_GP_PIN(0, 15) +#define PIN_MSIOF0_SS2 RCAR_GP_PIN(0, 16) +#define PIN_IRQ0 RCAR_GP_PIN(0, 17) +#define PIN_IRQ1 RCAR_GP_PIN(0, 18) +#define PIN_IRQ2 RCAR_GP_PIN(0, 19) +#define PIN_IRQ3 RCAR_GP_PIN(0, 20) +#define PIN_GP1_00 RCAR_GP_PIN(1, 0) +#define PIN_GP1_01 RCAR_GP_PIN(1, 1) +#define PIN_GP1_02 RCAR_GP_PIN(1, 2) +#define PIN_GP1_03 RCAR_GP_PIN(1, 3) +#define PIN_GP1_04 RCAR_GP_PIN(1, 4) +#define PIN_GP1_05 RCAR_GP_PIN(1, 5) +#define PIN_GP1_06 RCAR_GP_PIN(1, 6) +#define PIN_GP1_07 RCAR_GP_PIN(1, 7) +#define PIN_GP1_08 RCAR_GP_PIN(1, 8) +#define PIN_GP1_09 RCAR_GP_PIN(1, 9) +#define PIN_GP1_10 RCAR_GP_PIN(1, 10) +#define PIN_GP1_11 RCAR_GP_PIN(1, 11) +#define PIN_MMC_SD_CLK RCAR_GP_PIN(1, 12) +#define PIN_MMC_SD_D0 RCAR_GP_PIN(1, 13) +#define PIN_MMC_SD_D1 RCAR_GP_PIN(1, 14) +#define PIN_MMC_SD_D2 RCAR_GP_PIN(1, 15) +#define PIN_MMC_SD_D3 RCAR_GP_PIN(1, 16) +#define PIN_MMC_D5 RCAR_GP_PIN(1, 17) +#define PIN_MMC_D4 RCAR_GP_PIN(1, 18) +#define PIN_MMC_D6 RCAR_GP_PIN(1, 19) +#define PIN_MMC_DS RCAR_GP_PIN(1, 20) +#define PIN_MMC_D7 RCAR_GP_PIN(1, 21) +#define PIN_MMC_SD_CMD RCAR_GP_PIN(1, 22) +#define PIN_SD_CD RCAR_GP_PIN(1, 23) +#define PIN_SD_WP RCAR_GP_PIN(1, 24) +#define PIN_RPC_INT_N RCAR_GP_PIN(2, 0) +#define PIN_RPC_WP_N RCAR_GP_PIN(2, 1) +#define PIN_RPC_RESET_N RCAR_GP_PIN(2, 2) +#define PIN_QSPI1_SSL RCAR_GP_PIN(2, 3) +#define PIN_QSPI1_IO3 RCAR_GP_PIN(2, 4) +#define PIN_QSPI1_MISO_IO1 RCAR_GP_PIN(2, 5) +#define PIN_QSPI1_IO2 RCAR_GP_PIN(2, 6) +#define PIN_QSPI1_MOSI_IO0 RCAR_GP_PIN(2, 7) +#define PIN_QSPI1_SPCLK RCAR_GP_PIN(2, 8) +#define PIN_QSPI0_MOSI_IO0 RCAR_GP_PIN(2, 9) +#define PIN_QSPI0_SPCLK RCAR_GP_PIN(2, 10) +#define PIN_QSPI0_IO2 RCAR_GP_PIN(2, 11) +#define PIN_QSPI0_MISO_IO1 RCAR_GP_PIN(2, 12) +#define PIN_QSPI0_SSL RCAR_GP_PIN(2, 13) +#define PIN_QSPI0_IO3 RCAR_GP_PIN(2, 14) +#define PIN_PCIE0_CLKREQ_N RCAR_GP_PIN(2, 15) +#define PIN_PCIE1_CLKREQ_N RCAR_GP_PIN(2, 16) +#define PIN_TSN1_MDIO RCAR_GP_PIN(3, 0) +#define PIN_TSN2_MDIO RCAR_GP_PIN(3, 1) +#define PIN_TSN0_MDIO RCAR_GP_PIN(3, 2) +#define PIN_TSN2_MDC RCAR_GP_PIN(3, 3) +#define PIN_TSN0_MDC RCAR_GP_PIN(3, 4) +#define PIN_TSN1_MDC RCAR_GP_PIN(3, 5) +#define PIN_TSN1_LINK RCAR_GP_PIN(3, 6) +#define PIN_TSN2_LINK RCAR_GP_PIN(3, 7) +#define PIN_TSN0_LINK RCAR_GP_PIN(3, 8) +#define PIN_TSN2_PHY_INT RCAR_GP_PIN(3, 9) +#define PIN_TSN0_PHY_INT RCAR_GP_PIN(3, 10) +#define PIN_TSN1_PHY_INT RCAR_GP_PIN(3, 11) +#define PIN_TSN0_MAGIC RCAR_GP_PIN(3, 12) +#define PIN_TSN1_AVTP_PPS RCAR_GP_PIN(3, 13) +#define PIN_TSN1_AVTP_MATCH RCAR_GP_PIN(3, 14) +#define PIN_TSN1_AVTP_CAPTURE RCAR_GP_PIN(3, 15) +#define PIN_TSN0_AVTP_PPS RCAR_GP_PIN(3, 16) +#define PIN_TSN0_AVTP_MATCH RCAR_GP_PIN(3, 17) +#define PIN_TSN0_AVTP_CAPTURE RCAR_GP_PIN(3, 18) +#define PIN_GP4_00 RCAR_GP_PIN(4, 0) +#define PIN_GP4_01 RCAR_GP_PIN(4, 1) +#define PIN_GP4_02 RCAR_GP_PIN(4, 2) +#define PIN_GP4_03 RCAR_GP_PIN(4, 3) +#define PIN_GP4_04 RCAR_GP_PIN(4, 4) +#define PIN_GP4_05 RCAR_GP_PIN(4, 5) +#define PIN_GP4_06 RCAR_GP_PIN(4, 6) +#define PIN_GP4_07 RCAR_GP_PIN(4, 7) +#define PIN_GP4_08 RCAR_GP_PIN(4, 8) +#define PIN_GP4_09 RCAR_GP_PIN(4, 9) +#define PIN_GP4_10 RCAR_GP_PIN(4, 10) +#define PIN_GP4_11 RCAR_GP_PIN(4, 11) +#define PIN_GP4_12 RCAR_GP_PIN(4, 12) +#define PIN_GP4_13 RCAR_GP_PIN(4, 13) +#define PIN_GP4_14 RCAR_GP_PIN(4, 14) +#define PIN_GP4_15 RCAR_GP_PIN(4, 15) +#define PIN_GP4_16 RCAR_GP_PIN(4, 16) +#define PIN_GP4_17 RCAR_GP_PIN(4, 17) +#define PIN_GP4_18 RCAR_GP_PIN(4, 18) +#define PIN_GP4_19 RCAR_GP_PIN(4, 19) +#define PIN_MSPI0SC RCAR_GP_PIN(4, 20) +#define PIN_MSPI0SI RCAR_GP_PIN(4, 21) +#define PIN_MSPI0SO_MSPI0DCS RCAR_GP_PIN(4, 22) +#define PIN_MSPI0CSS1 RCAR_GP_PIN(4, 23) +#define PIN_MSPI0CSS0 RCAR_GP_PIN(4, 24) +#define PIN_MSPI1SI RCAR_GP_PIN(4, 25) +#define PIN_MSPI1SO_MSPI1DCS RCAR_GP_PIN(4, 26) +#define PIN_MSPI1CSS0 RCAR_GP_PIN(4, 27) +#define PIN_MSPI1SC RCAR_GP_PIN(4, 28) +#define PIN_MSPI1CSS2 RCAR_GP_PIN(4, 29) +#define PIN_MSPI1CSS1 RCAR_GP_PIN(4, 30) +#define PIN_RIIC0SCL RCAR_GP_PIN(5, 0) +#define PIN_RIIC0SDA RCAR_GP_PIN(5, 1) +#define PIN_ETNB0MD RCAR_GP_PIN(5, 2) +#define PIN_ETNB0WOL RCAR_GP_PIN(5, 3) +#define PIN_ETNB0LINKSTA RCAR_GP_PIN(5, 4) +#define PIN_ETNB0MDC RCAR_GP_PIN(5, 5) +#define PIN_ETNB0RXER RCAR_GP_PIN(5, 6) +#define PIN_ETNB0RXD3 RCAR_GP_PIN(5, 7) +#define PIN_ETNB0RXD1 RCAR_GP_PIN(5, 8) +#define PIN_ETNB0RXD2 RCAR_GP_PIN(5, 9) +#define PIN_ETNB0RXDV RCAR_GP_PIN(5, 10) +#define PIN_ETNB0RXD0 RCAR_GP_PIN(5, 11) +#define PIN_ETNB0RXCLK RCAR_GP_PIN(5, 12) +#define PIN_ETNB0TXER RCAR_GP_PIN(5, 13) +#define PIN_ETNB0TXD3 RCAR_GP_PIN(5, 14) +#define PIN_ETNB0TXCLK RCAR_GP_PIN(5, 15) +#define PIN_ETNB0TXD1 RCAR_GP_PIN(5, 16) +#define PIN_ETNB0TXD2 RCAR_GP_PIN(5, 17) +#define PIN_ETNB0TXEN RCAR_GP_PIN(5, 18) +#define PIN_ETNB0TXD0 RCAR_GP_PIN(5, 19) +#define PIN_RLIN37TX RCAR_GP_PIN(6, 0) +#define PIN_RLIN37RX_INTP23 RCAR_GP_PIN(6, 1) +#define PIN_RLIN36TX RCAR_GP_PIN(6, 2) +#define PIN_RLIN36RX_INTP22 RCAR_GP_PIN(6, 3) +#define PIN_RLIN35TX RCAR_GP_PIN(6, 4) +#define PIN_RLIN35RX_INTP21 RCAR_GP_PIN(6, 5) +#define PIN_RLIN34TX RCAR_GP_PIN(6, 6) +#define PIN_RLIN34RX_INTP20 RCAR_GP_PIN(6, 7) +#define PIN_RLIN33TX RCAR_GP_PIN(6, 8) +#define PIN_RLIN33RX_INTP19 RCAR_GP_PIN(6, 9) +#define PIN_RLIN32TX RCAR_GP_PIN(6, 10) +#define PIN_RLIN32RX_INTP18 RCAR_GP_PIN(6, 11) +#define PIN_RLIN31TX RCAR_GP_PIN(6, 12) +#define PIN_RLIN31RX_INTP17 RCAR_GP_PIN(6, 13) +#define PIN_RLIN30TX RCAR_GP_PIN(6, 14) +#define PIN_RLIN30RX_INTP16 RCAR_GP_PIN(6, 15) +#define PIN_INTP37 RCAR_GP_PIN(6, 16) +#define PIN_INTP36 RCAR_GP_PIN(6, 17) +#define PIN_INTP35 RCAR_GP_PIN(6, 18) +#define PIN_INTP34 RCAR_GP_PIN(6, 19) +#define PIN_INTP33 RCAR_GP_PIN(6, 20) +#define PIN_INTP32 RCAR_GP_PIN(6, 21) +#define PIN_NMI1 RCAR_GP_PIN(6, 22) +#define PIN_PRESETOUT1_N RCAR_GP_PIN(6, 31) +#define PIN_CAN0TX RCAR_GP_PIN(7, 0) +#define PIN_CAN0RX_INTP0 RCAR_GP_PIN(7, 1) +#define PIN_CAN1TX RCAR_GP_PIN(7, 2) +#define PIN_CAN1RX_INTP1 RCAR_GP_PIN(7, 3) +#define PIN_CAN2TX RCAR_GP_PIN(7, 4) +#define PIN_CAN2RX_INTP2 RCAR_GP_PIN(7, 5) +#define PIN_CAN3TX RCAR_GP_PIN(7, 6) +#define PIN_CAN3RX_INTP3 RCAR_GP_PIN(7, 7) +#define PIN_CAN4TX RCAR_GP_PIN(7, 8) +#define PIN_CAN4RX_INTP4 RCAR_GP_PIN(7, 9) +#define PIN_CAN5TX RCAR_GP_PIN(7, 10) +#define PIN_CAN5RX_INTP5 RCAR_GP_PIN(7, 11) +#define PIN_CAN6TX RCAR_GP_PIN(7, 12) +#define PIN_CAN6RX_INTP6 RCAR_GP_PIN(7, 13) +#define PIN_CAN7TX RCAR_GP_PIN(7, 14) +#define PIN_CAN7RX_INTP7 RCAR_GP_PIN(7, 15) +#define PIN_CAN8TX RCAR_GP_PIN(7, 16) +#define PIN_CAN8RX_INTP8 RCAR_GP_PIN(7, 17) +#define PIN_CAN9TX RCAR_GP_PIN(7, 18) +#define PIN_CAN9RX_INTP9 RCAR_GP_PIN(7, 19) +#define PIN_CAN10TX RCAR_GP_PIN(7, 20) +#define PIN_CAN10RX_INTP10 RCAR_GP_PIN(7, 21) +#define PIN_CAN11TX RCAR_GP_PIN(7, 22) +#define PIN_CAN11RX_INTP11 RCAR_GP_PIN(7, 23) +#define PIN_CAN12TX RCAR_GP_PIN(7, 24) +#define PIN_CAN12RX_INTP12 RCAR_GP_PIN(7, 25) +#define PIN_CAN13TX RCAR_GP_PIN(7, 26) +#define PIN_CAN13RX_INTP13 RCAR_GP_PIN(7, 27) +#define PIN_CAN14TX RCAR_GP_PIN(7, 28) +#define PIN_CAN14RX_INTP14 RCAR_GP_PIN(7, 29) +#define PIN_CAN15TX RCAR_GP_PIN(7, 30) +#define PIN_CAN15RX_INTP15 RCAR_GP_PIN(7, 31) + +/* Pinmux function declarations */ +#define FUNC_SCIF_CLK IP0SR0(0, 0) +#define FUNC_HSCK0 IP0SR0(4, 0) +#define FUNC_SCK3 IP0SR0(4, 1) +#define FUNC_MSIOF3_SCK IP0SR0(4, 2) +#define FUNC_TSN0_AVTP_CAPTURE_A IP0SR0(4, 5) +#define FUNC_HRX0 IP0SR0(8, 0) +#define FUNC_RX3 IP0SR0(8, 1) +#define FUNC_MSIOF3_RXD IP0SR0(8, 2) +#define FUNC_TSN0_AVTP_MATCH_A IP0SR0(8, 5) +#define FUNC_HTX0 IP0SR0(12, 0) +#define FUNC_TX3 IP0SR0(12, 1) +#define FUNC_MSIOF3_TXD IP0SR0(12, 2) +#define FUNC_HCTS0_N IP0SR0(16, 0) +#define FUNC_CTS3_N IP0SR0(16, 1) +#define FUNC_MSIOF3_SS1 IP0SR0(16, 2) +#define FUNC_TSN0_MDC_A IP0SR0(16, 5) +#define FUNC_HRTS0_N IP0SR0(20, 0) +#define FUNC_RTS3_N IP0SR0(20, 1) +#define FUNC_MSIOF3_SS2 IP0SR0(20, 2) +#define FUNC_TSN0_MDIO_A IP0SR0(20, 5) +#define FUNC_RX0 IP0SR0(24, 0) +#define FUNC_HRX1 IP0SR0(24, 1) +#define FUNC_MSIOF1_RXD IP0SR0(24, 3) +#define FUNC_TSN1_AVTP_MATCH_A IP0SR0(24, 5) +#define FUNC_TX0 IP0SR0(28, 0) +#define FUNC_HTX1 IP0SR0(28, 1) +#define FUNC_MSIOF1_TXD IP0SR0(28, 3) +#define FUNC_TSN1_AVTP_CAPTURE_A IP0SR0(28, 5) +#define FUNC_SCK0 IP1SR0(0, 0) +#define FUNC_HSCK1 IP1SR0(0, 1) +#define FUNC_MSIOF1_SCK IP1SR0(0, 3) +#define FUNC_RTS0_N IP1SR0(4, 0) +#define FUNC_HRTS1_N IP1SR0(4, 1) +#define FUNC_MSIOF3_SYNC IP1SR0(4, 2) +#define FUNC_TSN1_MDIO_A IP1SR0(4, 5) +#define FUNC_CTS0_N IP1SR0(8, 0) +#define FUNC_HCTS1_N IP1SR0(8, 1) +#define FUNC_MSIOF1_SYNC IP1SR0(8, 3) +#define FUNC_TSN1_MDC_A IP1SR0(8, 5) +#define FUNC_MSIOF0_SYNC IP1SR0(12, 0) +#define FUNC_HCTS3_N IP1SR0(12, 1) +#define FUNC_CTS1_N IP1SR0(12, 2) +#define FUNC_IRQ4 IP1SR0(12, 3) +#define FUNC_TSN0_LINK_A IP1SR0(12, 5) +#define FUNC_MSIOF0_RXD IP1SR0(16, 0) +#define FUNC_HRX3 IP1SR0(16, 1) +#define FUNC_RX1 IP1SR0(16, 2) +#define FUNC_MSIOF0_TXD IP1SR0(20, 0) +#define FUNC_HTX3 IP1SR0(20, 1) +#define FUNC_TX1 IP1SR0(20, 2) +#define FUNC_MSIOF0_SCK IP1SR0(24, 0) +#define FUNC_HSCK3 IP1SR0(24, 1) +#define FUNC_SCK1 IP1SR0(24, 2) +#define FUNC_MSIOF0_SS1 IP1SR0(28, 0) +#define FUNC_HRTS3_N IP1SR0(28, 1) +#define FUNC_RTS1_N IP1SR0(28, 2) +#define FUNC_IRQ5 IP1SR0(28, 3) +#define FUNC_TSN1_LINK_A IP1SR0(28, 5) +#define FUNC_MSIOF0_SS2 IP2SR0(0, 0) +#define FUNC_TSN2_LINK_A IP2SR0(0, 5) +#define FUNC_IRQ0 IP2SR0(4, 0) +#define FUNC_MSIOF1_SS1 IP2SR0(4, 3) +#define FUNC_TSN0_MAGIC_A IP2SR0(4, 5) +#define FUNC_IRQ1 IP2SR0(8, 0) +#define FUNC_MSIOF1_SS2 IP2SR0(8, 3) +#define FUNC_TSN0_PHY_INT_A IP2SR0(8, 5) +#define FUNC_IRQ2 IP2SR0(12, 0) +#define FUNC_TSN1_PHY_INT_A IP2SR0(12, 5) +#define FUNC_IRQ3 IP2SR0(16, 0) +#define FUNC_TSN2_PHY_INT_A IP2SR0(16, 5) +#define FUNC_GP1_00 IP0SR1(0, 0) +#define FUNC_TCLK1 IP0SR1(0, 1) +#define FUNC_HSCK2 IP0SR1(0, 2) +#define FUNC_GP1_01 IP0SR1(4, 0) +#define FUNC_TCLK4 IP0SR1(4, 1) +#define FUNC_HRX2 IP0SR1(4, 2) +#define FUNC_GP1_02 IP0SR1(8, 0) +#define FUNC_HTX2 IP0SR1(8, 2) +#define FUNC_MSIOF2_SS1 IP0SR1(8, 3) +#define FUNC_TSN2_MDC_A IP0SR1(8, 5) +#define FUNC_GP1_03 IP0SR1(12, 0) +#define FUNC_TCLK2 IP0SR1(12, 1) +#define FUNC_HCTS2_N IP0SR1(12, 2) +#define FUNC_MSIOF2_SS2 IP0SR1(12, 3) +#define FUNC_CTS4_N IP0SR1(12, 4) +#define FUNC_TSN2_MDIO_A IP0SR1(12, 5) +#define FUNC_GP1_04 IP0SR1(16, 0) +#define FUNC_TCLK3 IP0SR1(16, 1) +#define FUNC_HRTS2_N IP0SR1(16, 2) +#define FUNC_MSIOF2_SYNC IP0SR1(16, 3) +#define FUNC_RTS4_N IP0SR1(16, 4) +#define FUNC_GP1_05 IP0SR1(20, 0) +#define FUNC_MSIOF2_SCK IP0SR1(20, 1) +#define FUNC_SCK4 IP0SR1(20, 2) +#define FUNC_GP1_06 IP0SR1(24, 0) +#define FUNC_MSIOF2_RXD IP0SR1(24, 1) +#define FUNC_RX4 IP0SR1(24, 2) +#define FUNC_GP1_07 IP0SR1(28, 0) +#define FUNC_MSIOF2_TXD IP0SR1(28, 1) +#define FUNC_TX4 IP0SR1(28, 2) +#define FUNC_GP4_00 IP0SR4(0, 0) +#define FUNC_MSPI4SC IP0SR4(0, 1) +#define FUNC_TAUD0I2 IP0SR4(0, 3) +#define FUNC_TAUD0O2 IP0SR4(0, 4) +#define FUNC_GP4_01 IP0SR4(4, 0) +#define FUNC_MSPI4SI IP0SR4(4, 1) +#define FUNC_TAUD0I4 IP0SR4(4, 3) +#define FUNC_TAUD0O4 IP0SR4(4, 4) +#define FUNC_GP4_02 IP0SR4(8, 0) +#define FUNC_MSPI4SO_MSPI4DCS IP0SR4(8, 1) +#define FUNC_TAUD0I3 IP0SR4(8, 3) +#define FUNC_TAUD0O3 IP0SR4(8, 4) +#define FUNC_GP4_03 IP0SR4(12, 0) +#define FUNC_MSPI4CSS1 IP0SR4(12, 1) +#define FUNC_TAUD0I6 IP0SR4(12, 3) +#define FUNC_TAUD0O6 IP0SR4(12, 4) +#define FUNC_GP4_04 IP0SR4(16, 0) +#define FUNC_MSPI4CSS0 IP0SR4(16, 1) +#define FUNC_MSPI4SSI_N IP0SR4(16, 2) +#define FUNC_TAUD0I5 IP0SR4(16, 3) +#define FUNC_TAUD0O5 IP0SR4(16, 4) +#define FUNC_GP4_05 IP0SR4(20, 0) +#define FUNC_MSPI4CSS3 IP0SR4(20, 1) +#define FUNC_TAUD0I8 IP0SR4(20, 3) +#define FUNC_TAUD0O8 IP0SR4(20, 4) +#define FUNC_GP4_06 IP0SR4(24, 0) +#define FUNC_MSPI4CSS2 IP0SR4(24, 1) +#define FUNC_TAUD0I7 IP0SR4(24, 3) +#define FUNC_TAUD0O7 IP0SR4(24, 4) +#define FUNC_GP4_07 IP0SR4(28, 0) +#define FUNC_MSPI4CSS5 IP0SR4(28, 1) +#define FUNC_TAUD0I10 IP0SR4(28, 3) +#define FUNC_TAUD0O10 IP0SR4(28, 4) +#define FUNC_GP4_08 IP1SR4(0, 0) +#define FUNC_MSPI4CSS4 IP1SR4(0, 1) +#define FUNC_TAUD0I9 IP1SR4(0, 3) +#define FUNC_TAUD0O9 IP1SR4(0, 4) +#define FUNC_GP4_09 IP1SR4(4, 0) +#define FUNC_MSPI4CSS7 IP1SR4(4, 1) +#define FUNC_TAUD0I12 IP1SR4(4, 3) +#define FUNC_TAUD0O12 IP1SR4(4, 4) +#define FUNC_GP4_10 IP1SR4(8, 0) +#define FUNC_MSPI4CSS6 IP1SR4(8, 1) +#define FUNC_TAUD0I11 IP1SR4(8, 3) +#define FUNC_TAUD0O11 IP1SR4(8, 4) +#define FUNC_GP4_11 IP1SR4(12, 0) +#define FUNC_ERRORIN0_N IP1SR4(12, 1) +#define FUNC_TAUD0I14 IP1SR4(12, 3) +#define FUNC_TAUD0O14 IP1SR4(12, 4) +#define FUNC_GP4_12 IP1SR4(16, 0) +#define FUNC_ERROROUT_C_N IP1SR4(16, 1) +#define FUNC_TAUD0I13 IP1SR4(16, 3) +#define FUNC_TAUD0O13 IP1SR4(16, 4) +#define FUNC_GP4_13 IP1SR4(20, 0) +#define FUNC_GP4_14 IP1SR4(24, 0) +#define FUNC_ERRORIN1_N IP1SR4(24, 1) +#define FUNC_TAUD0I15 IP1SR4(24, 3) +#define FUNC_TAUD0O15 IP1SR4(24, 4) +#define FUNC_GP4_15 IP1SR4(28, 0) +#define FUNC_MSPI1CSS3 IP1SR4(28, 1) +#define FUNC_TAUD1I1 IP1SR4(28, 3) +#define FUNC_TAUD1O1 IP1SR4(28, 4) +#define FUNC_GP4_16 IP2SR4(0, 0) +#define FUNC_TAUD1I0 IP2SR4(0, 3) +#define FUNC_TAUD1O0 IP2SR4(0, 4) +#define FUNC_GP4_17 IP2SR4(4, 0) +#define FUNC_MSPI1CSS5 IP2SR4(4, 1) +#define FUNC_TAUD1I3 IP2SR4(4, 3) +#define FUNC_TAUD1O3 IP2SR4(4, 4) +#define FUNC_GP4_18 IP2SR4(8, 0) +#define FUNC_MSPI1CSS4 IP2SR4(8, 1) +#define FUNC_TAUD1I2 IP2SR4(8, 3) +#define FUNC_TAUD1O2 IP2SR4(8, 4) +#define FUNC_GP4_19 IP2SR4(12, 0) +#define FUNC_MSPI1CSS6 IP2SR4(12, 1) +#define FUNC_TAUD1I4 IP2SR4(12, 3) +#define FUNC_TAUD1O4 IP2SR4(12, 4) +#define FUNC_MSPI0SC IP2SR4(16, 0) +#define FUNC_MSPI1CSS7 IP2SR4(16, 1) +#define FUNC_TAUD1I5 IP2SR4(16, 3) +#define FUNC_TAUD1O5 IP2SR4(16, 4) +#define FUNC_MSPI0SI IP2SR4(20, 0) +#define FUNC_TAUD1I7 IP2SR4(20, 3) +#define FUNC_TAUD1O7 IP2SR4(20, 4) +#define FUNC_MSPI0SO_MSPI0DCS IP2SR4(24, 0) +#define FUNC_TAUD1I6 IP2SR4(24, 3) +#define FUNC_TAUD1O6 IP2SR4(24, 4) +#define FUNC_MSPI0CSS1 IP2SR4(28, 0) +#define FUNC_TAUD1I9 IP2SR4(28, 3) +#define FUNC_TAUD1O9 IP2SR4(28, 4) +#define FUNC_MSPI0CSS0 IP3SR4(0, 0) +#define FUNC_MSPI0SSI_N IP3SR4(0, 1) +#define FUNC_TAUD1I8 IP3SR4(0, 3) +#define FUNC_TAUD1O8 IP3SR4(0, 4) +#define FUNC_MSPI1SO_MSPI1DCS IP3SR4(8, 0) +#define FUNC_MSPI0CSS3 IP3SR4(8, 2) +#define FUNC_TAUD1I11 IP3SR4(8, 3) +#define FUNC_TAUD1O11 IP3SR4(8, 4) +#define FUNC_MSPI1SC IP3SR4(16, 0) +#define FUNC_MSPI0CSS2 IP3SR4(16, 2) +#define FUNC_TAUD1I10 IP3SR4(16, 3) +#define FUNC_TAUD1O10 IP3SR4(16, 4) +#define FUNC_RIIC0SCL IP0SR5(0, 0) +#define FUNC_TAUD0I0 IP0SR5(0, 3) +#define FUNC_TAUD0O0 IP0SR5(0, 4) +#define FUNC_RIIC0SDA IP0SR5(4, 0) +#define FUNC_TAUD0I1 IP0SR5(4, 3) +#define FUNC_TAUD0O1 IP0SR5(4, 4) +#define FUNC_ETNB0MD IP0SR5(8, 0) +#define FUNC_ETNB0WOL IP0SR5(12, 0) +#define FUNC_ETNB0LINKSTA IP0SR5(16, 0) +#define FUNC_ETNB0MDC IP0SR5(20, 0) +#define FUNC_ETNB0RXCLK IP0SR5(24, 0) +#define FUNC_ETNB0CRS_DV IP0SR5(24, 1) +#define FUNC_ETNB0TXCLK IP0SR5(28, 0) +#define FUNC_ETNB0REFCLK IP0SR5(28, 1) +#define FUNC_RLIN33TX IP1SR6(0, 0) +#define FUNC_TAUJ3O3 IP1SR6(0, 3) +#define FUNC_TAUJ3I3 IP1SR6(0, 4) +#define FUNC_NMI1 IP1SR6(0, 5) +#define FUNC_RLIN33RX_INTP19 IP1SR6(4, 0) +#define FUNC_TAUJ3O2 IP1SR6(4, 3) +#define FUNC_TAUJ3I2 IP1SR6(4, 4) +#define FUNC_RLIN32TX IP1SR6(8, 0) +#define FUNC_TAUJ3O1 IP1SR6(8, 3) +#define FUNC_TAUJ3I1 IP1SR6(8, 4) +#define FUNC_RLIN32RX_INTP18 IP1SR6(12, 0) +#define FUNC_TAUJ3O0 IP1SR6(12, 3) +#define FUNC_TAUJ3I0 IP1SR6(12, 4) +#define FUNC_INTP35 IP1SR6(12, 5) +#define FUNC_RLIN31TX IP1SR6(16, 0) +#define FUNC_TAUJ1I3 IP1SR6(16, 3) +#define FUNC_TAUJ1O3 IP1SR6(16, 4) +#define FUNC_INTP34 IP1SR6(16, 5) +#define FUNC_RLIN31RX_INTP17 IP1SR6(20, 0) +#define FUNC_TAUJ1I2 IP1SR6(20, 3) +#define FUNC_TAUJ1O2 IP1SR6(20, 4) +#define FUNC_INTP33 IP1SR6(20, 5) +#define FUNC_RLIN30TX IP1SR6(24, 0) +#define FUNC_TAUJ1I1 IP1SR6(24, 3) +#define FUNC_TAUJ1O1 IP1SR6(24, 4) +#define FUNC_RLIN30RX_INTP16 IP1SR6(28, 0) +#define FUNC_TAUJ1I0 IP1SR6(28, 3) +#define FUNC_TAUJ1O0 IP1SR6(28, 4) +#define FUNC_FLXA0STPWT IP2SR6(8, 2) +#define FUNC_CAN0TX IP0SR7(0, 0) +#define FUNC_RSENT0SPCO IP0SR7(0, 1) +#define FUNC_MSPI2SO_MSPI2DCS IP0SR7(0, 3) +#define FUNC_CAN0RX_INTP0 IP0SR7(4, 0) +#define FUNC_RSENT0RX IP0SR7(4, 1) +#define FUNC_RSENT0RX_RSENT0SPCO IP0SR7(4, 2) +#define FUNC_MSPI2SC IP0SR7(4, 3) +#define FUNC_CAN1TX IP0SR7(8, 0) +#define FUNC_RSENT1SPCO IP0SR7(8, 1) +#define FUNC_MSPI2SSI_N IP0SR7(8, 3) +#define FUNC_MSPI2CSS0 IP0SR7(8, 4) +#define FUNC_CAN1RX_INTP1 IP0SR7(12, 0) +#define FUNC_RSENT1RX IP0SR7(12, 1) +#define FUNC_RSENT1RX_RSENT1SPCO IP0SR7(12, 2) +#define FUNC_MSPI2SI IP0SR7(12, 3) +#define FUNC_CAN2TX IP0SR7(16, 0) +#define FUNC_RSENT2SPCO IP0SR7(16, 1) +#define FUNC_MSPI2CSS2 IP0SR7(16, 4) +#define FUNC_CAN2RX_INTP2 IP0SR7(20, 0) +#define FUNC_RSENT2RX IP0SR7(20, 1) +#define FUNC_RSENT2RX_RSENT2SPCO IP0SR7(20, 2) +#define FUNC_MSPI2CSS1 IP0SR7(20, 4) +#define FUNC_CAN3TX IP0SR7(24, 0) +#define FUNC_RSENT3SPCO IP0SR7(24, 1) +#define FUNC_MSPI2CSS4 IP0SR7(24, 4) +#define FUNC_CAN3RX_INTP3 IP0SR7(28, 0) +#define FUNC_RSENT3RX IP0SR7(28, 1) +#define FUNC_RSENT3RX_RSENT3SPCO IP0SR7(28, 2) +#define FUNC_MSPI2CSS3 IP0SR7(28, 4) +#define FUNC_CAN4TX IP1SR7(0, 0) +#define FUNC_RSENT4SPCO IP1SR7(0, 1) +#define FUNC_MSPI2CSS6 IP1SR7(0, 4) +#define FUNC_CAN4RX_INTP4 IP1SR7(4, 0) +#define FUNC_RSENT4RX IP1SR7(4, 1) +#define FUNC_RSENT4RX_RSENT4SPCO IP1SR7(4, 2) +#define FUNC_MSPI2CSS5 IP1SR7(4, 4) +#define FUNC_CAN5TX IP1SR7(8, 0) +#define FUNC_RSENT5SPCO IP1SR7(8, 1) +#define FUNC_CAN5RX_INTP5 IP1SR7(12, 0) +#define FUNC_RSENT5RX IP1SR7(12, 1) +#define FUNC_RSENT5RX_RSENT5SPCO IP1SR7(12, 2) +#define FUNC_MSPI2CSS7 IP1SR7(12, 4) +#define FUNC_CAN6TX IP1SR7(16, 0) +#define FUNC_RSENT6SPCO IP1SR7(16, 1) +#define FUNC_MSPI3SO_MSPI3DCS IP1SR7(16, 3) +#define FUNC_CAN6RX_INTP6 IP1SR7(20, 0) +#define FUNC_RSENT6RX IP1SR7(20, 1) +#define FUNC_RSENT6RX_RSENT6SPCO IP1SR7(20, 2) +#define FUNC_MSPI3SC IP1SR7(20, 3) +#define FUNC_CAN7TX IP1SR7(24, 0) +#define FUNC_RSENT7SPCO IP1SR7(24, 1) +#define FUNC_MSPI3SSI_N IP1SR7(24, 3) +#define FUNC_CAN7RX_INTP7 IP1SR7(28, 0) +#define FUNC_RSENT7RX IP1SR7(28, 1) +#define FUNC_RSENT7RX_RSENT7SPCO IP1SR7(28, 2) +#define FUNC_MSPI3SI IP1SR7(28, 3) +#define FUNC_CAN8TX IP2SR7(0, 0) +#define FUNC_RLIN38TX IP2SR7(0, 1) +#define FUNC_MSPI3CSS1 IP2SR7(0, 3) +#define FUNC_CAN8RX_INTP8 IP2SR7(4, 0) +#define FUNC_RLIN38RX_INTP24 IP2SR7(4, 1) +#define FUNC_MSPI3CSS0 IP2SR7(4, 3) +#define FUNC_CAN9TX IP2SR7(8, 0) +#define FUNC_RLIN39TX IP2SR7(8, 1) +#define FUNC_MSPI3CSS3 IP2SR7(8, 3) +#define FUNC_CAN9RX_INTP9 IP2SR7(12, 0) +#define FUNC_RLIN39RX_INTP25 IP2SR7(12, 1) +#define FUNC_MSPI3CSS2 IP2SR7(12, 3) +#define FUNC_CAN10TX IP2SR7(16, 0) +#define FUNC_RLIN310TX IP2SR7(16, 1) +#define FUNC_MSPI3CSS5 IP2SR7(16, 3) +#define FUNC_CAN10RX_INTP10 IP2SR7(20, 0) +#define FUNC_RLIN310RX_INTP26 IP2SR7(20, 1) +#define FUNC_MSPI3CSS4 IP2SR7(20, 3) +#define FUNC_CAN11TX IP2SR7(24, 0) +#define FUNC_RLIN311TX IP2SR7(24, 1) +#define FUNC_MSPI3CSS7 IP2SR7(24, 3) +#define FUNC_CAN11RX_INTP11 IP2SR7(28, 0) +#define FUNC_RLIN311RX_INTP27 IP2SR7(28, 1) +#define FUNC_MSPI3CSS6 IP2SR7(28, 3) +#define FUNC_FLXA0RXDB IP3SR7(8, 2) +#define FUNC_FLXA0RXDA IP3SR7(12, 2) +#define FUNC_FLXA0TXDB IP3SR7(16, 2) +#define FUNC_FLXA0TXDA IP3SR7(20, 2) +#define FUNC_FLXA0TXENB IP3SR7(24, 2) +#define FUNC_FLXA0TXENA IP3SR7(28, 2) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A779F0_H_ */ diff --git a/soc/arm/renesas_rcar/gen4/CMakeLists.txt b/soc/arm/renesas_rcar/gen4/CMakeLists.txt index 3315eaa55eb90eb..906bfdecfba748b 100644 --- a/soc/arm/renesas_rcar/gen4/CMakeLists.txt +++ b/soc/arm/renesas_rcar/gen4/CMakeLists.txt @@ -1,2 +1,4 @@ # Copyright (c) 2023 IoT.bzh # SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_SOC_R8A779F0 pfc_r8a779f0.c) diff --git a/soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c b/soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c new file mode 100644 index 000000000000000..25eba334d77f9e1 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include "pinctrl_soc.h" +#include + +const struct pfc_drive_reg pfc_drive_regs[] = { + /* DRV0CTRL0 */ + { 0x80, { + { RCAR_GP_PIN(0, 7), 28, 3 }, /* TX0 */ + { RCAR_GP_PIN(0, 6), 24, 3 }, /* RX0 */ + { RCAR_GP_PIN(0, 5), 20, 3 }, /* HRTS0_N */ + { RCAR_GP_PIN(0, 4), 16, 3 }, /* HCTS0_N */ + { RCAR_GP_PIN(0, 3), 12, 3 }, /* HTX0 */ + { RCAR_GP_PIN(0, 2), 8, 3 }, /* HRX0 */ + { RCAR_GP_PIN(0, 1), 4, 3 }, /* HSCK0 */ + { RCAR_GP_PIN(0, 0), 0, 3 }, /* SCIF_CLK */ + } }, + /* DRV1CTRL0 */ + { 0x84, { + { RCAR_GP_PIN(0, 15), 28, 3 }, /* MSIOF0_SS1 */ + { RCAR_GP_PIN(0, 14), 24, 3 }, /* MSIOF0_SCK */ + { RCAR_GP_PIN(0, 13), 20, 3 }, /* MSIOF0_TXD */ + { RCAR_GP_PIN(0, 12), 16, 3 }, /* MSIOF0_RXD */ + { RCAR_GP_PIN(0, 11), 12, 3 }, /* MSIOF0_SYNC */ + { RCAR_GP_PIN(0, 10), 8, 3 }, /* CTS0_N */ + { RCAR_GP_PIN(0, 9), 4, 3 }, /* RTS0_N */ + { RCAR_GP_PIN(0, 8), 0, 3 }, /* SCK0 */ + } }, + /* DRV2CTRL0 */ + { 0x88, { + { RCAR_GP_PIN(0, 20), 16, 3 }, /* IRQ3 */ + { RCAR_GP_PIN(0, 19), 12, 3 }, /* IRQ2 */ + { RCAR_GP_PIN(0, 18), 8, 3 }, /* IRQ1 */ + { RCAR_GP_PIN(0, 17), 4, 3 }, /* IRQ0 */ + { RCAR_GP_PIN(0, 16), 0, 3 }, /* MSIOF0_SS2 */ + } }, + /* DRV3CTRL0 is empty */ + /* DRV0CTRL1 */ + { 0x80, { + { RCAR_GP_PIN(1, 7), 28, 3 }, /* GP1_07 */ + { RCAR_GP_PIN(1, 6), 24, 3 }, /* GP1_06 */ + { RCAR_GP_PIN(1, 5), 20, 3 }, /* GP1_05 */ + { RCAR_GP_PIN(1, 4), 16, 3 }, /* GP1_04 */ + { RCAR_GP_PIN(1, 3), 12, 3 }, /* GP1_03 */ + { RCAR_GP_PIN(1, 2), 8, 3 }, /* GP1_02 */ + { RCAR_GP_PIN(1, 1), 4, 3 }, /* GP1_01 */ + { RCAR_GP_PIN(1, 0), 0, 3 }, /* GP1_00 */ + } }, + /* DRV1CTRL1 */ + { 0x84, { + { RCAR_GP_PIN(1, 15), 28, 3 }, /* MMC_SD_D2 */ + { RCAR_GP_PIN(1, 14), 24, 3 }, /* MMC_SD_D1 */ + { RCAR_GP_PIN(1, 13), 20, 3 }, /* MMC_SD_D0 */ + { RCAR_GP_PIN(1, 12), 16, 3 }, /* MMC_SD_CLK */ + { RCAR_GP_PIN(1, 11), 12, 3 }, /* GP1_11 */ + { RCAR_GP_PIN(1, 10), 8, 3 }, /* GP1_10 */ + { RCAR_GP_PIN(1, 9), 4, 3 }, /* GP1_09 */ + { RCAR_GP_PIN(1, 8), 0, 3 }, /* GP1_08 */ + } }, + /* DRV2CTRL1 */ + { 0x88, { + { RCAR_GP_PIN(1, 23), 28, 3 }, /* SD_CD */ + { RCAR_GP_PIN(1, 22), 24, 3 }, /* MMC_SD_CMD */ + { RCAR_GP_PIN(1, 21), 20, 3 }, /* MMC_D7 */ + { RCAR_GP_PIN(1, 20), 16, 3 }, /* MMC_DS */ + { RCAR_GP_PIN(1, 19), 12, 3 }, /* MMC_D6 */ + { RCAR_GP_PIN(1, 18), 8, 3 }, /* MMC_D4 */ + { RCAR_GP_PIN(1, 17), 4, 3 }, /* MMC_D5 */ + { RCAR_GP_PIN(1, 16), 0, 3 }, /* MMC_SD_D3 */ + } }, + /* DRV3CTRL1 */ + { 0x8c, { + { RCAR_GP_PIN(1, 24), 0, 3 }, /* SD_WP */ + } }, + /* DRV0CTRL2 */ + { 0x80, { + { RCAR_GP_PIN(2, 7), 28, 2 }, /* QSPI1_MOSI_IO0 */ + { RCAR_GP_PIN(2, 6), 24, 2 }, /* QSPI1_IO2 */ + { RCAR_GP_PIN(2, 5), 20, 2 }, /* QSPI1_MISO_IO1 */ + { RCAR_GP_PIN(2, 4), 16, 2 }, /* QSPI1_IO3 */ + { RCAR_GP_PIN(2, 3), 12, 2 }, /* QSPI1_SSL */ + { RCAR_GP_PIN(2, 2), 8, 2 }, /* RPC_RESET_N */ + { RCAR_GP_PIN(2, 1), 4, 2 }, /* RPC_WP_N */ + { RCAR_GP_PIN(2, 0), 0, 2 }, /* RPC_INT_N */ + } }, + /* DRV1CTRL2 */ + { 0x84, { + { RCAR_GP_PIN(2, 15), 28, 3 }, /* PCIE0_CLKREQ_N */ + { RCAR_GP_PIN(2, 14), 24, 2 }, /* QSPI0_IO3 */ + { RCAR_GP_PIN(2, 13), 20, 2 }, /* QSPI0_SSL */ + { RCAR_GP_PIN(2, 12), 16, 2 }, /* QSPI0_MISO_IO1 */ + { RCAR_GP_PIN(2, 11), 12, 2 }, /* QSPI0_IO2 */ + { RCAR_GP_PIN(2, 10), 8, 2 }, /* QSPI0_SPCLK */ + { RCAR_GP_PIN(2, 9), 4, 2 }, /* QSPI0_MOSI_IO0 */ + { RCAR_GP_PIN(2, 8), 0, 2 }, /* QSPI1_SPCLK */ + } }, + /* DRV2CTRL2 */ + { 0x88, { + { RCAR_GP_PIN(2, 16), 0, 3 }, /* PCIE1_CLKREQ_N */ + } }, + /* DRV3CTRL2 is empty */ + /* DRV0CTRL3 */ + { 0x80, { + { RCAR_GP_PIN(3, 7), 28, 3 }, /* TSN2_LINK_B */ + { RCAR_GP_PIN(3, 6), 24, 3 }, /* TSN1_LINK_B */ + { RCAR_GP_PIN(3, 5), 20, 3 }, /* TSN1_MDC_B */ + { RCAR_GP_PIN(3, 4), 16, 3 }, /* TSN0_MDC_B */ + { RCAR_GP_PIN(3, 3), 12, 3 }, /* TSN2_MDC_B */ + { RCAR_GP_PIN(3, 2), 8, 3 }, /* TSN0_MDIO_B */ + { RCAR_GP_PIN(3, 1), 4, 3 }, /* TSN2_MDIO_B */ + { RCAR_GP_PIN(3, 0), 0, 3 }, /* TSN1_MDIO_B */ + } }, + /* DRV1CTRL3 */ + { 0x84, { + { RCAR_GP_PIN(3, 15), 28, 3 }, /* TSN1_AVTP_CAPTURE_B */ + { RCAR_GP_PIN(3, 14), 24, 3 }, /* TSN1_AVTP_MATCH_B */ + { RCAR_GP_PIN(3, 13), 20, 3 }, /* TSN1_AVTP_PPS */ + { RCAR_GP_PIN(3, 12), 16, 3 }, /* TSN0_MAGIC_B */ + { RCAR_GP_PIN(3, 11), 12, 3 }, /* TSN1_PHY_INT_B */ + { RCAR_GP_PIN(3, 10), 8, 3 }, /* TSN0_PHY_INT_B */ + { RCAR_GP_PIN(3, 9), 4, 3 }, /* TSN2_PHY_INT_B */ + { RCAR_GP_PIN(3, 8), 0, 3 }, /* TSN0_LINK_B */ + } }, + /* DRV2CTRL3 */ + { 0x88, { + { RCAR_GP_PIN(3, 18), 8, 3 }, /* TSN0_AVTP_CAPTURE_B */ + { RCAR_GP_PIN(3, 17), 4, 3 }, /* TSN0_AVTP_MATCH_B */ + { RCAR_GP_PIN(3, 16), 0, 3 }, /* TSN0_AVTP_PPS */ + } }, + /* DRV3CTRL3 is empty */ + /* DRV0CTRL4 */ + { 0x80, { + { RCAR_GP_PIN(4, 7), 28, 3 }, /* GP4_07 */ + { RCAR_GP_PIN(4, 6), 24, 3 }, /* GP4_06 */ + { RCAR_GP_PIN(4, 5), 20, 3 }, /* GP4_05 */ + { RCAR_GP_PIN(4, 4), 16, 3 }, /* GP4_04 */ + { RCAR_GP_PIN(4, 3), 12, 3 }, /* GP4_03 */ + { RCAR_GP_PIN(4, 2), 8, 3 }, /* GP4_02 */ + { RCAR_GP_PIN(4, 1), 4, 3 }, /* GP4_01 */ + { RCAR_GP_PIN(4, 0), 0, 3 }, /* GP4_00 */ + } }, + /* DRV1CTRL4 */ + { 0x84, { + { RCAR_GP_PIN(4, 15), 28, 3 }, /* GP4_15 */ + { RCAR_GP_PIN(4, 14), 24, 3 }, /* GP4_14 */ + { RCAR_GP_PIN(4, 13), 20, 3 }, /* GP4_13 */ + { RCAR_GP_PIN(4, 12), 16, 3 }, /* GP4_12 */ + { RCAR_GP_PIN(4, 11), 12, 3 }, /* GP4_11 */ + { RCAR_GP_PIN(4, 10), 8, 3 }, /* GP4_10 */ + { RCAR_GP_PIN(4, 9), 4, 3 }, /* GP4_09 */ + { RCAR_GP_PIN(4, 8), 0, 3 }, /* GP4_08 */ + } }, + /* DRV2CTRL4 */ + { 0x88, { + { RCAR_GP_PIN(4, 23), 28, 3 }, /* MSPI0CSS1 */ + { RCAR_GP_PIN(4, 22), 24, 3 }, /* MPSI0SO/MSPI0DCS */ + { RCAR_GP_PIN(4, 21), 20, 3 }, /* MPSI0SI */ + { RCAR_GP_PIN(4, 20), 16, 3 }, /* MSPI0SC */ + { RCAR_GP_PIN(4, 19), 12, 3 }, /* GP4_19 */ + { RCAR_GP_PIN(4, 18), 8, 3 }, /* GP4_18 */ + { RCAR_GP_PIN(4, 17), 4, 3 }, /* GP4_17 */ + { RCAR_GP_PIN(4, 16), 0, 3 }, /* GP4_16 */ + } }, + /* DRV3CTRL4 */ + { 0x8c, { + { RCAR_GP_PIN(4, 30), 24, 3 }, /* MSPI1CSS1 */ + { RCAR_GP_PIN(4, 29), 20, 3 }, /* MSPI1CSS2 */ + { RCAR_GP_PIN(4, 28), 16, 3 }, /* MSPI1SC */ + { RCAR_GP_PIN(4, 27), 12, 3 }, /* MSPI1CSS0 */ + { RCAR_GP_PIN(4, 26), 8, 3 }, /* MPSI1SO/MSPI1DCS */ + { RCAR_GP_PIN(4, 25), 4, 3 }, /* MSPI1SI */ + { RCAR_GP_PIN(4, 24), 0, 3 }, /* MSPI0CSS0 */ + } }, + /* DRV0CTRL5 */ + { 0x80, { + { RCAR_GP_PIN(5, 7), 28, 3 }, /* ETNB0RXD3 */ + { RCAR_GP_PIN(5, 6), 24, 3 }, /* ETNB0RXER */ + { RCAR_GP_PIN(5, 5), 20, 3 }, /* ETNB0MDC */ + { RCAR_GP_PIN(5, 4), 16, 3 }, /* ETNB0LINKSTA */ + { RCAR_GP_PIN(5, 3), 12, 3 }, /* ETNB0WOL */ + { RCAR_GP_PIN(5, 2), 8, 3 }, /* ETNB0MD */ + { RCAR_GP_PIN(5, 1), 4, 3 }, /* RIIC0SDA */ + { RCAR_GP_PIN(5, 0), 0, 3 }, /* RIIC0SCL */ + } }, + /* DRV1CTRL5 */ + { 0x84, { + { RCAR_GP_PIN(5, 15), 28, 3 }, /* ETNB0TXCLK */ + { RCAR_GP_PIN(5, 14), 24, 3 }, /* ETNB0TXD3 */ + { RCAR_GP_PIN(5, 13), 20, 3 }, /* ETNB0TXER */ + { RCAR_GP_PIN(5, 12), 16, 3 }, /* ETNB0RXCLK */ + { RCAR_GP_PIN(5, 11), 12, 3 }, /* ETNB0RXD0 */ + { RCAR_GP_PIN(5, 10), 8, 3 }, /* ETNB0RXDV */ + { RCAR_GP_PIN(5, 9), 4, 3 }, /* ETNB0RXD2 */ + { RCAR_GP_PIN(5, 8), 0, 3 }, /* ETNB0RXD1 */ + } }, + /* DRV2CTRL5 */ + { 0x88, { + { RCAR_GP_PIN(5, 19), 12, 3 }, /* ETNB0TXD0 */ + { RCAR_GP_PIN(5, 18), 8, 3 }, /* ETNB0TXEN */ + { RCAR_GP_PIN(5, 17), 4, 3 }, /* ETNB0TXD2 */ + { RCAR_GP_PIN(5, 16), 0, 3 }, /* ETNB0TXD1 */ + } }, + /* DRV3CTRL5 is empty */ + /* DRV0CTRL6 */ + { 0x80, { + { RCAR_GP_PIN(6, 7), 28, 3 }, /* RLIN34RX/INTP20 */ + { RCAR_GP_PIN(6, 6), 24, 3 }, /* RLIN34TX */ + { RCAR_GP_PIN(6, 5), 20, 3 }, /* RLIN35RX/INTP21 */ + { RCAR_GP_PIN(6, 4), 16, 3 }, /* RLIN35TX */ + { RCAR_GP_PIN(6, 3), 12, 3 }, /* RLIN36RX/INTP22 */ + { RCAR_GP_PIN(6, 2), 8, 3 }, /* RLIN36TX */ + { RCAR_GP_PIN(6, 1), 4, 3 }, /* RLIN37RX/INTP23 */ + { RCAR_GP_PIN(6, 0), 0, 3 }, /* RLIN37TX */ + } }, + /* DRV1CTRL6 */ + { 0x84, { + { RCAR_GP_PIN(6, 15), 28, 3 }, /* RLIN30RX/INTP16 */ + { RCAR_GP_PIN(6, 14), 24, 3 }, /* RLIN30TX */ + { RCAR_GP_PIN(6, 13), 20, 3 }, /* RLIN31RX/INTP17 */ + { RCAR_GP_PIN(6, 12), 16, 3 }, /* RLIN31TX */ + { RCAR_GP_PIN(6, 11), 12, 3 }, /* RLIN32RX/INTP18 */ + { RCAR_GP_PIN(6, 10), 8, 3 }, /* RLIN32TX */ + { RCAR_GP_PIN(6, 9), 4, 3 }, /* RLIN33RX/INTP19 */ + { RCAR_GP_PIN(6, 8), 0, 3 }, /* RLIN33TX */ + } }, + /* DRV2CTRL6 */ + { 0x88, { + { RCAR_GP_PIN(6, 22), 24, 3 }, /* NMI1 */ + { RCAR_GP_PIN(6, 21), 20, 3 }, /* INTP32 */ + { RCAR_GP_PIN(6, 20), 16, 3 }, /* INTP33 */ + { RCAR_GP_PIN(6, 19), 12, 3 }, /* INTP34 */ + { RCAR_GP_PIN(6, 18), 8, 3 }, /* INTP35 */ + { RCAR_GP_PIN(6, 17), 4, 3 }, /* INTP36 */ + { RCAR_GP_PIN(6, 16), 0, 3 }, /* INTP37 */ + } }, + /* DRV3CTRL6 */ + { 0x8c, { + { RCAR_GP_PIN(6, 31), 28, 3 }, /* PRESETOUT1# */ + } }, + /* DRV0CTRL7 */ + { 0x80, { + { RCAR_GP_PIN(7, 7), 28, 3 }, /* CAN3RX/INTP3 */ + { RCAR_GP_PIN(7, 6), 24, 3 }, /* CAN3TX */ + { RCAR_GP_PIN(7, 5), 20, 3 }, /* CAN2RX/INTP2 */ + { RCAR_GP_PIN(7, 4), 16, 3 }, /* CAN2TX */ + { RCAR_GP_PIN(7, 3), 12, 3 }, /* CAN1RX/INTP1 */ + { RCAR_GP_PIN(7, 2), 8, 3 }, /* CAN1TX */ + { RCAR_GP_PIN(7, 1), 4, 3 }, /* CAN0RX/INTP0 */ + { RCAR_GP_PIN(7, 0), 0, 3 }, /* CAN0TX */ + } }, + /* DRV1CTRL7 */ + { 0x84, { + { RCAR_GP_PIN(7, 15), 28, 3 }, /* CAN7RX/INTP7 */ + { RCAR_GP_PIN(7, 14), 24, 3 }, /* CAN7TX */ + { RCAR_GP_PIN(7, 13), 20, 3 }, /* CAN6RX/INTP6 */ + { RCAR_GP_PIN(7, 12), 16, 3 }, /* CAN6TX */ + { RCAR_GP_PIN(7, 11), 12, 3 }, /* CAN5RX/INTP5 */ + { RCAR_GP_PIN(7, 10), 8, 3 }, /* CAN5TX */ + { RCAR_GP_PIN(7, 9), 4, 3 }, /* CAN4RX/INTP4 */ + { RCAR_GP_PIN(7, 8), 0, 3 }, /* CAN4TX */ + } }, + /* DRV2CTRL7 */ + { 0x88, { + { RCAR_GP_PIN(7, 23), 28, 3 }, /* CAN11RX/INTP11 */ + { RCAR_GP_PIN(7, 22), 24, 3 }, /* CAN11TX */ + { RCAR_GP_PIN(7, 21), 20, 3 }, /* CAN10RX/INTP10 */ + { RCAR_GP_PIN(7, 20), 16, 3 }, /* CAN10TX */ + { RCAR_GP_PIN(7, 19), 12, 3 }, /* CAN9RX/INTP9 */ + { RCAR_GP_PIN(7, 18), 8, 3 }, /* CAN9TX */ + { RCAR_GP_PIN(7, 17), 4, 3 }, /* CAN8RX/INTP8 */ + { RCAR_GP_PIN(7, 16), 0, 3 }, /* CAN8TX */ + } }, + /* DRV3CTRL7 */ + { 0x8c, { + { RCAR_GP_PIN(7, 31), 28, 3 }, /* CAN15RX/INTP15 */ + { RCAR_GP_PIN(7, 30), 24, 3 }, /* CAN15TX */ + { RCAR_GP_PIN(7, 29), 20, 3 }, /* CAN14RX/INTP14 */ + { RCAR_GP_PIN(7, 28), 16, 3 }, /* CAN14TX */ + { RCAR_GP_PIN(7, 27), 12, 3 }, /* CAN13RX/INTP13 */ + { RCAR_GP_PIN(7, 26), 8, 3 }, /* CAN13TX */ + { RCAR_GP_PIN(7, 25), 4, 3 }, /* CAN12RX/INTP12 */ + { RCAR_GP_PIN(7, 24), 0, 3 }, /* CAN12TX */ + } }, + /* DRV0CTRLSYS0 */ + { 0x80, { + { RCAR_GP_PIN(8, 0), 0, 3 }, /* PRESETOUT0# */ + } }, + /* DRV1CTRLSYS0 */ + { 0x84, { + { RCAR_GP_PIN(8, 12), 16, 2 }, /* DCUTCK0 */ + { RCAR_GP_PIN(8, 11), 12, 2 }, /* DCUTDO0 */ + { RCAR_GP_PIN(8, 10), 8, 2 }, /* DCUTDI0 */ + { RCAR_GP_PIN(8, 9), 4, 2 }, /* DCUTDY0# */ + { RCAR_GP_PIN(8, 8), 0, 2 }, /* DCUTMS0 */ + } }, + { }, +}; + +#define PFC_BIAS_REG(r1, r2) \ + .puen = r1, \ + .pud = r2, \ + .pins = + +const struct pfc_bias_reg pfc_bias_regs[] = { + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN0, PUD0 */ + [0] = RCAR_GP_PIN(0, 0), /* SCIF_CLK */ + [1] = RCAR_GP_PIN(0, 1), /* HSCK0 */ + [2] = RCAR_GP_PIN(0, 2), /* HRX0 */ + [3] = RCAR_GP_PIN(0, 3), /* HTX0 */ + [4] = RCAR_GP_PIN(0, 4), /* HCTS0_N */ + [5] = RCAR_GP_PIN(0, 5), /* HRTS0_N */ + [6] = RCAR_GP_PIN(0, 6), /* RX0 */ + [7] = RCAR_GP_PIN(0, 7), /* TX0 */ + [8] = RCAR_GP_PIN(0, 8), /* SCK0 */ + [9] = RCAR_GP_PIN(0, 9), /* RTS0_N */ + [10] = RCAR_GP_PIN(0, 10), /* CTS0_N */ + [11] = RCAR_GP_PIN(0, 11), /* MSIOF0_SYNC */ + [12] = RCAR_GP_PIN(0, 12), /* MSIOF0_RXD */ + [13] = RCAR_GP_PIN(0, 13), /* MSIOF0_TXD */ + [14] = RCAR_GP_PIN(0, 14), /* MSIOF0_SCK */ + [15] = RCAR_GP_PIN(0, 15), /* MSIOF0_SS1 */ + [16] = RCAR_GP_PIN(0, 16), /* MSIOF0_SS2 */ + [17] = RCAR_GP_PIN(0, 17), /* IRQ0 */ + [18] = RCAR_GP_PIN(0, 18), /* IRQ1 */ + [19] = RCAR_GP_PIN(0, 19), /* IRQ2 */ + [20] = RCAR_GP_PIN(0, 20), /* IRQ3 */ + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN1, PUD1 */ + [0] = RCAR_GP_PIN(1, 0), /* GP1_00 */ + [1] = RCAR_GP_PIN(1, 1), /* GP1_01 */ + [2] = RCAR_GP_PIN(1, 2), /* GP1_02 */ + [3] = RCAR_GP_PIN(1, 3), /* GP1_03 */ + [4] = RCAR_GP_PIN(1, 4), /* GP1_04 */ + [5] = RCAR_GP_PIN(1, 5), /* GP1_05 */ + [6] = RCAR_GP_PIN(1, 6), /* GP1_06 */ + [7] = RCAR_GP_PIN(1, 7), /* GP1_07 */ + [8] = RCAR_GP_PIN(1, 8), /* GP1_08 */ + [9] = RCAR_GP_PIN(1, 9), /* GP1_09 */ + [10] = RCAR_GP_PIN(1, 10), /* GP1_10 */ + [11] = RCAR_GP_PIN(1, 11), /* GP1_11 */ + [12] = RCAR_GP_PIN(1, 12), /* MMC_SD_CLK */ + [13] = RCAR_GP_PIN(1, 13), /* MMC_SD_D0 */ + [14] = RCAR_GP_PIN(1, 14), /* MMC_SD_D1 */ + [15] = RCAR_GP_PIN(1, 15), /* MMC_SD_D2 */ + [16] = RCAR_GP_PIN(1, 16), /* MMC_SD_D3 */ + [17] = RCAR_GP_PIN(1, 17), /* MMC_D5 */ + [18] = RCAR_GP_PIN(1, 18), /* MMC_D4 */ + [19] = RCAR_GP_PIN(1, 19), /* MMC_D6 */ + [20] = RCAR_GP_PIN(1, 20), /* MMC_DS */ + [21] = RCAR_GP_PIN(1, 21), /* MMC_D7 */ + [22] = RCAR_GP_PIN(1, 22), /* MMC_SD_CMD */ + [23] = RCAR_GP_PIN(1, 23), /* SD_CD */ + [24] = RCAR_GP_PIN(1, 24), /* SD_WP */ + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN2, PUD2 */ + [0] = RCAR_GP_PIN(2, 0), /* RPC_INT_N */ + [1] = RCAR_GP_PIN(2, 1), /* RPC_WP_N */ + [2] = RCAR_GP_PIN(2, 2), /* RPC_RESET_N */ + [3] = RCAR_GP_PIN(2, 3), /* QSPI1_SSL */ + [4] = RCAR_GP_PIN(2, 4), /* QSPI1_IO3 */ + [5] = RCAR_GP_PIN(2, 5), /* QSPI1_MISO_IO1 */ + [6] = RCAR_GP_PIN(2, 6), /* QSPI1_IO2 */ + [7] = RCAR_GP_PIN(2, 7), /* QSPI1_MOSI_IO0 */ + [8] = RCAR_GP_PIN(2, 8), /* QSPI1_SPCLK */ + [9] = RCAR_GP_PIN(2, 9), /* QSPI0_MOSI_IO0 */ + [10] = RCAR_GP_PIN(2, 10), /* QSPI0_SPCLK */ + [11] = RCAR_GP_PIN(2, 11), /* QSPI0_IO2 */ + [12] = RCAR_GP_PIN(2, 12), /* QSPI0_MISO_IO1 */ + [13] = RCAR_GP_PIN(2, 13), /* QSPI0_SSL */ + [14] = RCAR_GP_PIN(2, 14), /* QSPI0_IO3 */ + [15] = RCAR_GP_PIN(2, 15), /* PCIE0_CLKREQ_N */ + [16] = RCAR_GP_PIN(2, 16), /* PCIE1_CLKREQ_N */ + [17] = PIN_NONE, + [18] = PIN_NONE, + [19] = PIN_NONE, + [20] = PIN_NONE, + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN3, PUD3 */ + [0] = RCAR_GP_PIN(3, 0), /* TSN1_MDIO_B */ + [1] = RCAR_GP_PIN(3, 1), /* TSN2_MDIO_B */ + [2] = RCAR_GP_PIN(3, 2), /* TSN0_MDIO_B */ + [3] = RCAR_GP_PIN(3, 3), /* TSN2_MDC_B */ + [4] = RCAR_GP_PIN(3, 4), /* TSN0_MDC_B */ + [5] = RCAR_GP_PIN(3, 5), /* TSN1_MDC_B */ + [6] = RCAR_GP_PIN(3, 6), /* TSN1_LINK_B */ + [7] = RCAR_GP_PIN(3, 7), /* TSN2_LINK_B */ + [8] = RCAR_GP_PIN(3, 8), /* TSN0_LINK_B */ + [9] = RCAR_GP_PIN(3, 9), /* TSN2_PHY_INT_B */ + [10] = RCAR_GP_PIN(3, 10), /* TSN0_PHY_INT_B */ + [11] = RCAR_GP_PIN(3, 11), /* TSN1_PHY_INT_B */ + [12] = RCAR_GP_PIN(3, 12), /* TSN0_MAGIC_B */ + [13] = RCAR_GP_PIN(3, 13), /* TSN1_AVTP_PPS */ + [14] = RCAR_GP_PIN(3, 14), /* TSN1_AVTP_MATCH_B */ + [15] = RCAR_GP_PIN(3, 15), /* TSN1_AVTP_CAPTURE_B */ + [16] = RCAR_GP_PIN(3, 16), /* TSN0_AVTP_PPS */ + [17] = RCAR_GP_PIN(3, 17), /* TSN0_AVTP_MATCH_B */ + [18] = RCAR_GP_PIN(3, 18), /* TSN0_AVTP_CAPTURE_B */ + [19] = PIN_NONE, + [20] = PIN_NONE, + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN4, PUD4 */ + [0] = RCAR_GP_PIN(4, 0), /* GP4_00 */ + [1] = RCAR_GP_PIN(4, 1), /* GP4_01 */ + [2] = RCAR_GP_PIN(4, 2), /* GP4_02 */ + [3] = RCAR_GP_PIN(4, 3), /* GP4_03 */ + [4] = RCAR_GP_PIN(4, 4), /* GP4_04 */ + [5] = RCAR_GP_PIN(4, 5), /* GP4_05 */ + [6] = RCAR_GP_PIN(4, 6), /* GP4_06 */ + [7] = RCAR_GP_PIN(4, 7), /* GP4_07 */ + [8] = RCAR_GP_PIN(4, 8), /* GP4_08 */ + [9] = RCAR_GP_PIN(4, 9), /* GP4_09 */ + [10] = RCAR_GP_PIN(4, 10), /* GP4_10 */ + [11] = RCAR_GP_PIN(4, 11), /* GP4_11 */ + [12] = RCAR_GP_PIN(4, 12), /* GP4_12 */ + [13] = RCAR_GP_PIN(4, 13), /* GP4_13 */ + [14] = RCAR_GP_PIN(4, 14), /* GP4_14 */ + [15] = RCAR_GP_PIN(4, 15), /* GP4_15 */ + [16] = RCAR_GP_PIN(4, 16), /* GP4_16 */ + [17] = RCAR_GP_PIN(4, 17), /* GP4_17 */ + [18] = RCAR_GP_PIN(4, 18), /* GP4_18 */ + [19] = RCAR_GP_PIN(4, 19), /* GP4_19 */ + [20] = RCAR_GP_PIN(4, 20), /* MSPI0SC */ + [21] = RCAR_GP_PIN(4, 21), /* MSPI0SI */ + [22] = RCAR_GP_PIN(4, 22), /* MSPI0SO/MSPI0DCS */ + [23] = RCAR_GP_PIN(4, 23), /* MSPI0CSS1 */ + [24] = RCAR_GP_PIN(4, 24), /* MSPI0CSS0 */ + [25] = RCAR_GP_PIN(4, 25), /* MSPI1SI */ + [26] = RCAR_GP_PIN(4, 26), /* MSPI1SO/MSPI1DCS */ + [27] = RCAR_GP_PIN(4, 27), /* MSPI1CSS0 */ + [28] = RCAR_GP_PIN(4, 28), /* MSPI1SC */ + [29] = RCAR_GP_PIN(4, 29), /* MSPI1CSS2 */ + [30] = RCAR_GP_PIN(4, 30), /* MSPI1CSS1 */ + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN5, PUD5 */ + [0] = RCAR_GP_PIN(5, 0), /* RIIC0SCL */ + [1] = RCAR_GP_PIN(5, 1), /* RIIC0SDA */ + [2] = RCAR_GP_PIN(5, 2), /* ETNB0MD */ + [3] = RCAR_GP_PIN(5, 3), /* ETNB0WOL */ + [4] = RCAR_GP_PIN(5, 4), /* ETNB0LINKSTA */ + [5] = RCAR_GP_PIN(5, 5), /* ETNB0MDC */ + [6] = RCAR_GP_PIN(5, 6), /* ETNB0RXER */ + [7] = RCAR_GP_PIN(5, 7), /* ETNB0RXD3 */ + [8] = RCAR_GP_PIN(5, 8), /* ETNB0RXD1 */ + [9] = RCAR_GP_PIN(5, 9), /* ETNB0RXD2 */ + [10] = RCAR_GP_PIN(5, 10), /* ETNB0RXDV */ + [11] = RCAR_GP_PIN(5, 11), /* ETNB0RXD0 */ + [12] = RCAR_GP_PIN(5, 12), /* ETNB0RXCLK */ + [13] = RCAR_GP_PIN(5, 13), /* ETNB0TXER */ + [14] = RCAR_GP_PIN(5, 14), /* ETNB0TXD3 */ + [15] = RCAR_GP_PIN(5, 15), /* ETNB0TXCLK */ + [16] = RCAR_GP_PIN(5, 16), /* ETNB0TXD1 */ + [17] = RCAR_GP_PIN(5, 17), /* ETNB0TXD2 */ + [18] = RCAR_GP_PIN(5, 18), /* ETNB0TXEN */ + [19] = RCAR_GP_PIN(5, 19), /* ETNB0TXD0 */ + [20] = PIN_NONE, + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN6, PUD6 */ + [0] = RCAR_GP_PIN(6, 0), /* RLIN37TX */ + [1] = RCAR_GP_PIN(6, 1), /* RLIN37RX/INTP23 */ + [2] = RCAR_GP_PIN(6, 2), /* RLIN36TX */ + [3] = RCAR_GP_PIN(6, 3), /* RLIN36RX/INTP22 */ + [4] = RCAR_GP_PIN(6, 4), /* RLIN35TX */ + [5] = RCAR_GP_PIN(6, 5), /* RLIN35RX/INTP21 */ + [6] = RCAR_GP_PIN(6, 6), /* RLIN34TX */ + [7] = RCAR_GP_PIN(6, 7), /* RLIN34RX/INTP20 */ + [8] = RCAR_GP_PIN(6, 8), /* RLIN33TX */ + [9] = RCAR_GP_PIN(6, 9), /* RLIN33RX/INTP19 */ + [10] = RCAR_GP_PIN(6, 10), /* RLIN32TX */ + [11] = RCAR_GP_PIN(6, 11), /* RLIN32RX/INTP18 */ + [12] = RCAR_GP_PIN(6, 12), /* RLIN31TX */ + [13] = RCAR_GP_PIN(6, 13), /* RLIN31RX/INTP17 */ + [14] = RCAR_GP_PIN(6, 14), /* RLIN30TX */ + [15] = RCAR_GP_PIN(6, 15), /* RLIN30RX/INTP16 */ + [16] = RCAR_GP_PIN(6, 16), /* INTP37 */ + [17] = RCAR_GP_PIN(6, 17), /* INTP36 */ + [18] = RCAR_GP_PIN(6, 18), /* INTP35 */ + [19] = RCAR_GP_PIN(6, 19), /* INTP34 */ + [20] = RCAR_GP_PIN(6, 20), /* INTP33 */ + [21] = RCAR_GP_PIN(6, 21), /* INTP32 */ + [22] = RCAR_GP_PIN(6, 22), /* NMI1 */ + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN7, PUD7 */ + [0] = RCAR_GP_PIN(7, 0), /* CAN0TX */ + [1] = RCAR_GP_PIN(7, 1), /* CAN0RX/INTP0 */ + [2] = RCAR_GP_PIN(7, 2), /* CAN1TX */ + [3] = RCAR_GP_PIN(7, 3), /* CAN1RX/INTP1 */ + [4] = RCAR_GP_PIN(7, 4), /* CAN2TX */ + [5] = RCAR_GP_PIN(7, 5), /* CAN2RX/INTP2 */ + [6] = RCAR_GP_PIN(7, 6), /* CAN3TX */ + [7] = RCAR_GP_PIN(7, 7), /* CAN3RX/INTP3 */ + [8] = RCAR_GP_PIN(7, 8), /* CAN4TX */ + [9] = RCAR_GP_PIN(7, 9), /* CAN4RX/INTP4 */ + [10] = RCAR_GP_PIN(7, 10), /* CAN5TX */ + [11] = RCAR_GP_PIN(7, 11), /* CAN5RX/INTP5 */ + [12] = RCAR_GP_PIN(7, 12), /* CAN6TX */ + [13] = RCAR_GP_PIN(7, 13), /* CAN6RX/INTP6 */ + [14] = RCAR_GP_PIN(7, 14), /* CAN7TX */ + [15] = RCAR_GP_PIN(7, 15), /* CAN7RX/INTP7 */ + [16] = RCAR_GP_PIN(7, 16), /* CAN8TX */ + [17] = RCAR_GP_PIN(7, 17), /* CAN8RX/INTP8 */ + [18] = RCAR_GP_PIN(7, 18), /* CAN9TX */ + [19] = RCAR_GP_PIN(7, 19), /* CAN9RX/INTP9 */ + [20] = RCAR_GP_PIN(7, 20), /* CAN10TX */ + [21] = RCAR_GP_PIN(7, 21), /* CAN10RX/INTP10 */ + [22] = RCAR_GP_PIN(7, 22), /* CAN11TX */ + [23] = RCAR_GP_PIN(7, 23), /* CAN11RX/INTP11 */ + [24] = RCAR_GP_PIN(7, 24), /* CAN12TX */ + [25] = RCAR_GP_PIN(7, 25), /* CAN12RX/INTP12 */ + [26] = RCAR_GP_PIN(7, 26), /* CAN13TX */ + [27] = RCAR_GP_PIN(7, 27), /* CAN13RX/INTP13 */ + [28] = RCAR_GP_PIN(7, 28), /* CAN14TX */ + [29] = RCAR_GP_PIN(7, 29), /* CAN14RX/INTP14 */ + [30] = RCAR_GP_PIN(7, 30), /* CAN15TX */ + [31] = RCAR_GP_PIN(7, 31), /* CAN15RX/INTP15 */ + } }, + { /* sentinel */ }, +}; + +const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void) +{ + return pfc_bias_regs; +} + +const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) +{ + return pfc_drive_regs; +} + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + if (RCAR_IS_GP_PIN(pin) == false) + return -EINVAL; + + *reg_index = pin / 32; + + return 0; +} From 5461917952cc714cd0a9f7fb37266a560210dcfe Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Thu, 20 Jul 2023 17:06:58 +0200 Subject: [PATCH 0996/1049] drivers: clock: rcar: Add r8a779f0 support Add support of r8a779f0 cpg driver. r8a779f0 soc has its own clock tree. Gen4 SoCs common registers addresses have been added in header. Signed-off-by: Mykola Kvach Signed-off-by: Aymeric Aillet --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig.rcar | 4 +- .../clock_control_r8a779f0_cpg_mssr.c | 186 ++++++++++++++++++ .../clock_control_renesas_cpg_mssr.h | 30 ++- .../clock/renesas,r8a779f0-cpg-mssr.yaml | 8 + .../dt-bindings/clock/r8a779f0_cpg_mssr.h | 67 +++++++ 6 files changed, 293 insertions(+), 3 deletions(-) create mode 100644 drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c create mode 100644 dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml create mode 100644 include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index a1f553fc1348084..219aac76b970cd2 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -71,6 +71,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AGILEX5 clock_control_agilex5. if(CONFIG_CLOCK_CONTROL_RCAR_CPG_MSSR) zephyr_library_sources(clock_control_renesas_cpg_mssr.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_RENESAS_R8A7795_CPG_MSSR_ENABLED clock_control_r8a7795_cpg_mssr.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_RENESAS_R8A779F0_CPG_MSSR_ENABLED clock_control_r8a779f0_cpg_mssr.c) endif() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c) diff --git a/drivers/clock_control/Kconfig.rcar b/drivers/clock_control/Kconfig.rcar index b4a69a47e355e22..0caa072355456c6 100644 --- a/drivers/clock_control/Kconfig.rcar +++ b/drivers/clock_control/Kconfig.rcar @@ -1,9 +1,9 @@ -# Copyright (c) 2021-2022 IoT.bzh +# Copyright (c) 2021-2023 IoT.bzh # SPDX-License-Identifier: Apache-2.0 config CLOCK_CONTROL_RCAR_CPG_MSSR bool "RCar CPG MSSR driver" default y - depends on DT_HAS_RENESAS_R8A7795_CPG_MSSR_ENABLED + depends on SOC_FAMILY_RCAR help Enable support for Renesas RCar CPG MSSR driver. diff --git a/drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c b/drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c new file mode 100644 index 000000000000000..c0d9f15cd581c27 --- /dev/null +++ b/drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 EPAM Systems + * Copyright (c) 2023 IoT.bzh + * + * r8a779f0 Clock Pulse Generator / Module Standby and Software Reset + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_r8a779f0_cpg_mssr + +#include +#include +#include +#include +#include +#include +#include +#include "clock_control_renesas_cpg_mssr.h" + +#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL +#include +LOG_MODULE_DECLARE(clock_control_rcar); + +struct r8a779f0_cpg_mssr_cfg { + DEVICE_MMIO_ROM; /* Must be first */ +}; + +struct r8a779f0_cpg_mssr_data { + struct rcar_cpg_mssr_data cmn; /* Must be first */ +}; + +/* NOTE: the array MUST be sorted by module field */ +static struct cpg_clk_info_table core_props[] = { + RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_S0D12_PER, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(66660)), + + RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_CL16M, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(16660)), +}; + +/* NOTE: the array MUST be sorted by module field */ +static struct cpg_clk_info_table mod_props[] = { + RCAR_MOD_CLK_INFO_ITEM(702, R8A779F0_CLK_S0D12_PER), + RCAR_MOD_CLK_INFO_ITEM(704, R8A779F0_CLK_S0D12_PER), + + RCAR_MOD_CLK_INFO_ITEM(915, R8A779F0_CLK_CL16M), +}; + +static int r8a779f0_cpg_enable_disable_core(const struct device *dev, + struct cpg_clk_info_table *clk_info, uint32_t enable) +{ + ARG_UNUSED(dev); + ARG_UNUSED(clk_info); + ARG_UNUSED(enable); + + return -ENOTSUP; +} + +static int r8a779f0_cpg_core_clock_endisable(const struct device *dev, struct rcar_cpg_clk *clk, + bool enable) +{ + struct cpg_clk_info_table *clk_info; + struct r8a779f0_cpg_mssr_data *data = dev->data; + k_spinlock_key_t key; + + clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module); + if (!clk_info) { + return -EINVAL; + } + + if (enable) { + if (clk->rate > 0) { + int ret; + uintptr_t rate = clk->rate; + + ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk, + (clock_control_subsys_rate_t)rate); + if (ret < 0) { + return ret; + } + } + } + + key = k_spin_lock(&data->cmn.lock); + r8a779f0_cpg_enable_disable_core(dev, clk_info, enable); + k_spin_unlock(&data->cmn.lock, key); + + return 0; +} + +int r8a779f0_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys, bool enable) +{ + struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; + int ret; + + if (!dev || !sys) { + return -EINVAL; + } + + if (clk->domain == CPG_MOD) { + struct r8a779f0_cpg_mssr_data *data = dev->data; + k_spinlock_key_t key; + + key = k_spin_lock(&data->cmn.lock); + ret = rcar_cpg_mstp_clock_endisable(DEVICE_MMIO_GET(dev), clk->module, enable); + k_spin_unlock(&data->cmn.lock, key); + } else if (clk->domain == CPG_CORE) { + ret = r8a779f0_cpg_core_clock_endisable(dev, clk, enable); + } else { + ret = -EINVAL; + } + + return ret; +} + +static uint32_t r8a779f0_get_div_helper(uint32_t reg_val, uint32_t module) +{ + switch (module) { + case R8A779F0_CLK_S0D12_PER: + case R8A779F0_CLK_CL16M: + return 1; + default: + return RCAR_CPG_NONE; + } +} + +static int r8a779f0_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t *div_mask) +{ + ARG_UNUSED(module); + ARG_UNUSED(divider); + ARG_UNUSED(div_mask); + + return -ENOTSUP; +} + +static int r8a779f0_cpg_mssr_start(const struct device *dev, clock_control_subsys_t sys) +{ + return r8a779f0_cpg_mssr_start_stop(dev, sys, true); +} + +static int r8a779f0_cpg_mssr_stop(const struct device *dev, clock_control_subsys_t sys) +{ + return r8a779f0_cpg_mssr_start_stop(dev, sys, false); +} + +static int r8a779f0_cpg_mssr_init(const struct device *dev) +{ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + rcar_cpg_build_clock_relationship(dev); + rcar_cpg_update_all_in_out_freq(dev); + return 0; +} + +static const struct clock_control_driver_api r8a779f0_cpg_mssr_api = { + .on = r8a779f0_cpg_mssr_start, + .off = r8a779f0_cpg_mssr_stop, + .get_rate = rcar_cpg_get_rate, + .set_rate = rcar_cpg_set_rate, +}; + +#define R8A779F0_MSSR_INIT(inst) \ + static struct r8a779f0_cpg_mssr_cfg cpg_mssr##inst##_cfg = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ + }; \ + \ + static struct r8a779f0_cpg_mssr_data cpg_mssr##inst##_data = { \ + .cmn.clk_info_table[CPG_CORE] = core_props, \ + .cmn.clk_info_table_size[CPG_CORE] = ARRAY_SIZE(core_props), \ + .cmn.clk_info_table[CPG_MOD] = mod_props, \ + .cmn.clk_info_table_size[CPG_MOD] = ARRAY_SIZE(mod_props), \ + .cmn.get_div_helper = r8a779f0_get_div_helper, \ + .cmn.set_rate_helper = r8a779f0_set_rate_helper \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, \ + &r8a779f0_cpg_mssr_init, \ + NULL, \ + &cpg_mssr##inst##_data, \ + &cpg_mssr##inst##_cfg, \ + PRE_KERNEL_1, \ + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ + &r8a779f0_cpg_mssr_api); + +DT_INST_FOREACH_STATUS_OKAY(R8A779F0_MSSR_INIT) diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.h b/drivers/clock_control/clock_control_renesas_cpg_mssr.h index d616567763e47f2..5850d6f12dbe4b5 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.h +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 IoT.bzh + * Copyright (c) 2022-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ @@ -109,6 +109,34 @@ static const uint16_t srcr[] = { /* Peripherals Clocks */ #define S3D4_CLK_RATE 66600000 /* SCIF */ #define S0D12_CLK_RATE 66600000 /* PWM */ +#elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) +/* Software Reset Clearing Register offsets */ +#define SRSTCLR(i) (0x2C80 + (i) * 4) + +/* CPG write protect offset */ +#define CPGWPR 0x0 + +/* Realtime Module Stop Control Register offsets */ +static const uint16_t mstpcr[] = { + 0x2D00, 0x2D04, 0x2D08, 0x2D0C, + 0x2D10, 0x2D14, 0x2D18, 0x2D1C, + 0x2D20, 0x2D24, 0x2D28, 0x2D2C, + 0x2D30, 0x2D34, 0x2D38, 0x2D3C, + 0x2D40, 0x2D44, 0x2D48, 0x2D4C, + 0x2D50, 0x2D54, 0x2D58, 0x2D5C, + 0x2D60, 0x2D64, 0x2D68, 0x2D6C, +}; + +/* Software Reset Register offsets */ +static const uint16_t srcr[] = { + 0x2C00, 0x2C04, 0x2C08, 0x2C0C, + 0x2C10, 0x2C14, 0x2C18, 0x2C1C, + 0x2C20, 0x2C24, 0x2C28, 0x2C2C, + 0x2C30, 0x2C34, 0x2C38, 0x2C3C, + 0x2C40, 0x2C44, 0x2C48, 0x2C4C, + 0x2C50, 0x2C54, 0x2C58, 0x2C5C, + 0x2C60, 0x2C64, 0x2C68, 0x2C6C, +}; #endif /* CONFIG_SOC_SERIES_RCAR_GEN3 */ void rcar_cpg_write(uint32_t base_address, uint32_t reg, uint32_t val); diff --git a/dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml b/dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml new file mode 100644 index 000000000000000..89d3fa6fdfeff49 --- /dev/null +++ b/dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas R8A779F0 SoC Clock Pulse Generator / Module Standby and Software Reset + +compatible: "renesas,r8a779f0-cpg-mssr" + +include: renesas,rcar-cpg-mssr.yaml diff --git a/include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h b/include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h new file mode 100644 index 000000000000000..d0f01809795c9a5 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_CLOCK_R8A779F0_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_CLOCK_R8A779F0_H_ + +#include "renesas_cpg_mssr.h" + +/* r8a779f0 CPG Core Clocks */ +#define R8A779F0_CLK_Z0 0 +#define R8A779F0_CLK_Z1 1 +#define R8A779F0_CLK_ZR 2 +#define R8A779F0_CLK_ZX 3 +#define R8A779F0_CLK_ZS 4 +#define R8A779F0_CLK_ZT 5 +#define R8A779F0_CLK_ZTR 6 +#define R8A779F0_CLK_S0D2 7 +#define R8A779F0_CLK_S0D3 8 +#define R8A779F0_CLK_S0D4 9 +#define R8A779F0_CLK_S0D2_MM 10 +#define R8A779F0_CLK_S0D3_MM 11 +#define R8A779F0_CLK_S0D4_MM 12 +#define R8A779F0_CLK_S0D2_RT 13 +#define R8A779F0_CLK_S0D3_RT 14 +#define R8A779F0_CLK_S0D4_RT 15 +#define R8A779F0_CLK_S0D6_RT 16 +#define R8A779F0_CLK_S0D3_PER 17 +#define R8A779F0_CLK_S0D6_PER 18 +#define R8A779F0_CLK_S0D12_PER 19 +#define R8A779F0_CLK_S0D24_PER 20 +#define R8A779F0_CLK_S0D2_HSC 21 +#define R8A779F0_CLK_S0D3_HSC 22 +#define R8A779F0_CLK_S0D4_HSC 23 +#define R8A779F0_CLK_S0D6_HSC 24 +#define R8A779F0_CLK_S0D12_HSC 25 +#define R8A779F0_CLK_S0D2_CC 26 +#define R8A779F0_CLK_CL 27 +#define R8A779F0_CLK_CL16M 28 +#define R8A779F0_CLK_CL16M_MM 29 +#define R8A779F0_CLK_CL16M_RT 30 +#define R8A779F0_CLK_CL16M_PER 31 +#define R8A779F0_CLK_CL16M_HSC 32 +#define R8A779F0_CLK_ZB3 33 +#define R8A779F0_CLK_ZB3D2 34 +#define R8A779F0_CLK_ZB3D4 35 +#define R8A779F0_CLK_SD0H 36 +#define R8A779F0_CLK_SD0 37 +#define R8A779F0_CLK_RPC 38 +#define R8A779F0_CLK_RPCD2 39 +#define R8A779F0_CLK_MSO 40 +#define R8A779F0_CLK_POST 41 +#define R8A779F0_CLK_POST2 42 +#define R8A779F0_CLK_SASYNCRT 43 +#define R8A779F0_CLK_SASYNCPERD1 44 +#define R8A779F0_CLK_SASYNCPERD2 45 +#define R8A779F0_CLK_SASYNCPERD4 46 +#define R8A779F0_CLK_DBGSOC_HSC 47 +#define R8A779F0_CLK_RSW2 48 +#define R8A779F0_CLK_CPEX 49 +#define R8A779F0_CLK_CBFUSA 50 +#define R8A779F0_CLK_R 51 +#define R8A779F0_CLK_OSC 52 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_CLOCK_R8A779F0_H_ */ From cfb93c1c82932c4c64aa65533b35ea386ed70e7c Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 27 Jul 2022 15:13:07 +0200 Subject: [PATCH 0997/1049] dts: arm: Add Renesas r8a779f0 support r8a779f0 is also know as S4, this SoC is part of the Gen4 SoC series, has 8 Cortex-A55 and a dual core lockstep Cortex-R52 processor. SCIF0 is dedicated to Zephyr and SCIF3 to Linux. **Control Domains** IMPORTANT: This SoC is divided into two "domains": - Application domain contains some peripherals as well as A55 & R52 cores. - Control domain that contain a G4MH/RH850 MCU and other peripherals. In order to access control domain peripherals such as gpio4-7 and CAN-FD from application domain, the G4MH MCU has to unlock a protection mechanism from control domain buses. "Protected" controllers will be flagged in gen4 device trees, warning users that they need to flash a custom G4MH firmware to unlock access to these controllers. **Clock controller** This SoC clock controller is offering "domains" for each world (Zephyr/Linux). These domains are several "entry points" to the clock controller which are arbitrated to avoid a world from turning off a clock needed by another one. We decided to use the same domain as Linux because the security mechanism as to be implemented before accessing another domain. Signed-off-by: Aymeric Aillet --- dts/arm/renesas/rcar/gen4/r8a779f0.dtsi | 70 +++++++++++++++++++ dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi | 68 ++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 dts/arm/renesas/rcar/gen4/r8a779f0.dtsi create mode 100644 dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi diff --git a/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi b/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi new file mode 100644 index 000000000000000..0b1667aa4a1b75d --- /dev/null +++ b/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + soc { + /* The last four registers of this controller are + * located in the control domain + * A custom G4MH/RH850 µC firmware has to be flashed to access them + */ + pfc: pin-controller@e6050000 { + compatible = "renesas,rcar-pfc"; + reg = <0xe6050000 0x16c>, <0xe6050800 0x16c>, + <0xe6051000 0x16c>, <0xe6051800 0x16c>, + <0xdfd90000 0x16c>, <0xdfd90800 0x16c>, + <0xdfd91000 0x16c>, <0xdfd91800 0x16c>; + }; + + /* Clock controller + * Using domain 0 as Linux + */ + cpg: clock-controller@e6150000 { + compatible = "renesas,r8a779f0-cpg-mssr"; + reg = <0xe6150000 0x4000>; + #clock-cells = <2>; + }; + + gpio0: gpio@e6050180 { + compatible = "renesas,rcar-gpio"; + reg = <0xe6050180 0x54>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + clocks = <&cpg CPG_MOD 915>; + status = "disabled"; + }; + + /* + * Control domain security has to be released to access gpio4 controller + * A custom G4MH/RH850 µC firmware has to be flashed to do that + */ + gpio4: gpio@dfd90180 { + compatible = "renesas,rcar-gpio"; + reg = <0xdfd90180 0x54>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + clocks = <&cpg CPG_MOD 915>; + status = "disabled"; + }; + + /* Zephyr console */ + scif0: serial@e6e60000 { + interrupts = ; + clocks = <&cpg CPG_MOD 702>, <&cpg CPG_CORE R8A779F0_CLK_S0D12_PER>; + }; + + /* Linux console */ + scif3: serial@e6c50000 { + interrupts = ; + clocks = <&cpg CPG_MOD 704>, <&cpg CPG_CORE R8A779F0_CLK_S0D12_PER>; + }; + }; +}; diff --git a/dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi b/dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi new file mode 100644 index 000000000000000..1ce2ec9151c61b2 --- /dev/null +++ b/dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-r52"; + reg = <0>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + soc { + interrupt-parent = <&gic>; + + sram0: memory@40040000 { + compatible = "mmio-sram"; + reg = <0x40040000 0x100000>; + }; + + gic: interrupt-controller@f0000000 { + compatible = "arm,gic-v3", "arm,gic"; + reg = <0xf0000000 0x1000>, + <0xf0100000 0x20000>; + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + }; + + scif0: serial@e6e60000 { + compatible = "renesas,rcar-scif"; + reg = <0xe6e60000 0x64>; + current-speed = <115200>; + status = "disabled"; + }; + + scif3: serial@e6c50000 { + compatible = "renesas,rcar-scif"; + reg = <0xe6c50000 0x64>; + current-speed = <115200>; + status = "disabled"; + }; + }; +}; From f2061a073af483452a9fa6486e8c0bc5926d18f8 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Tue, 21 Mar 2023 18:09:44 +0100 Subject: [PATCH 0998/1049] soc: arm: reneas: Add r8a779f0 support r8a779f0 SoC is part of the Renesas R-Car Gen4 SoC series. This SoC has a dual core lockstep Cortex-R52 CPU. Signed-off-by: Aymeric Aillet --- .../gen4/Kconfig.defconfig.r8a779f0 | 15 +++++++++++++++ .../renesas_rcar/gen4/Kconfig.defconfig.series | 13 +++++++++++++ soc/arm/renesas_rcar/gen4/Kconfig.series | 13 +++++++++++++ soc/arm/renesas_rcar/gen4/Kconfig.soc | 11 +++++++++++ soc/arm/renesas_rcar/gen4/linker.ld | 7 +++++++ soc/arm/renesas_rcar/gen4/soc.h | 18 ++++++++++++++++++ 6 files changed, 77 insertions(+) create mode 100644 soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 create mode 100644 soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series create mode 100644 soc/arm/renesas_rcar/gen4/Kconfig.series create mode 100644 soc/arm/renesas_rcar/gen4/Kconfig.soc create mode 100644 soc/arm/renesas_rcar/gen4/linker.ld create mode 100644 soc/arm/renesas_rcar/gen4/soc.h diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 new file mode 100644 index 000000000000000..6da34845bf95f08 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 @@ -0,0 +1,15 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +if SOC_R8A779F0 + +config SOC + default "r8a779f0" + +config NUM_IRQS + default 1216 #960 SPI + 256 LPI + +config PINCTRL + default y + +endif # SOC_R8A779F0 diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series new file mode 100644 index 000000000000000..36218fe504fa3a0 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series @@ -0,0 +1,13 @@ +# Renesas R-Car Gen4 SoC line + +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RCAR_GEN4 + +source "soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779*" + +config SOC_SERIES + default "gen4" + +endif # SOC_SERIES_RCAR_GEN4 diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.series b/soc/arm/renesas_rcar/gen4/Kconfig.series new file mode 100644 index 000000000000000..606b2c50e43a9e5 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.series @@ -0,0 +1,13 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RCAR_GEN4 + bool "Renesas R-Car Gen4 Cortex R52" + select ARM + select CPU_CORTEX_R52 + select GIC_SINGLE_SECURITY_STATE + select SOC_FAMILY_RCAR + select CLOCK_CONTROL_RCAR_CPG_MSSR if CLOCK_CONTROL + select ARM_ARCH_TIMER + help + Enable support for Renesas R-Car Gen4 SoC series diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.soc b/soc/arm/renesas_rcar/gen4/Kconfig.soc new file mode 100644 index 000000000000000..5c443d6101e73e6 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Renesas RCar SoC Selection" + depends on SOC_SERIES_RCAR_GEN4 + +config SOC_R8A779F0 + bool "r8a779f0" + +endchoice diff --git a/soc/arm/renesas_rcar/gen4/linker.ld b/soc/arm/renesas_rcar/gen4/linker.ld new file mode 100644 index 000000000000000..a51ff84991f8992 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/linker.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/arm/renesas_rcar/gen4/soc.h b/soc/arm/renesas_rcar/gen4/soc.h new file mode 100644 index 000000000000000..3717fb8a8a8a440 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/soc.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +/* Define CMSIS configurations */ +#define __CR_REV 1U + +/* Do not let CMSIS to handle GIC and Timer */ +#define __GIC_PRESENT 0 +#define __TIM_PRESENT 0 + +#endif /* _SOC__H_ */ From cf4ab0e907b3586761c1806dc07fe597f02abe72 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Wed, 27 Jul 2022 16:24:51 +0200 Subject: [PATCH 0999/1049] boards: arm: Add Renesas Spider support Renesas Spider board use a S4 SoC (r8a779f0). Add basic support for UART, GPIO and clock control. We are using SCIF0 as SCIF3 is used by Linux. Signed-off-by: Aymeric Aillet --- boards/arm/rcar_spider/Kconfig.board | 6 ++ boards/arm/rcar_spider/Kconfig.defconfig | 9 +++ boards/arm/rcar_spider/board.cmake | 3 + .../rcar_spider/rcar_spider_cr52-pinctrl.dtsi | 25 ++++++++ boards/arm/rcar_spider/rcar_spider_cr52.dts | 58 +++++++++++++++++++ boards/arm/rcar_spider/rcar_spider_cr52.yaml | 11 ++++ .../rcar_spider/rcar_spider_cr52_defconfig | 13 +++++ boards/arm/rcar_spider/support/openocd.cfg | 27 +++++++++ 8 files changed, 152 insertions(+) create mode 100644 boards/arm/rcar_spider/Kconfig.board create mode 100644 boards/arm/rcar_spider/Kconfig.defconfig create mode 100644 boards/arm/rcar_spider/board.cmake create mode 100644 boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi create mode 100644 boards/arm/rcar_spider/rcar_spider_cr52.dts create mode 100644 boards/arm/rcar_spider/rcar_spider_cr52.yaml create mode 100644 boards/arm/rcar_spider/rcar_spider_cr52_defconfig create mode 100644 boards/arm/rcar_spider/support/openocd.cfg diff --git a/boards/arm/rcar_spider/Kconfig.board b/boards/arm/rcar_spider/Kconfig.board new file mode 100644 index 000000000000000..1ff4c7e794d4589 --- /dev/null +++ b/boards/arm/rcar_spider/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RCAR_SPIDER_CR52 + bool "Cortex-R52 for Renesas Spider" + depends on SOC_R8A779F0 diff --git a/boards/arm/rcar_spider/Kconfig.defconfig b/boards/arm/rcar_spider/Kconfig.defconfig new file mode 100644 index 000000000000000..b2a590250f9bd76 --- /dev/null +++ b/boards/arm/rcar_spider/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_RCAR_SPIDER_CR52 + +config BOARD + default "rcar_spider_cr52" + +endif # BOARD_RCAR_SPIDER_CR52 diff --git a/boards/arm/rcar_spider/board.cmake b/boards/arm/rcar_spider/board.cmake new file mode 100644 index 000000000000000..b106c562c540b17 --- /dev/null +++ b/boards/arm/rcar_spider/board.cmake @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 +board_runner_args(openocd "--use-elf") +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi b/boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi new file mode 100644 index 000000000000000..b164961271a5230 --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pfc { + scif0_data_tx_default: scif0_data_tx_default { + pin = ; + }; + + scif0_data_rx_default: scif0_data_rx_default { + pin = ; + }; + + scif3_data_tx_default: scif3_data_tx_default { + pin = ; + }; + + scif3_data_rx_default: scif3_data_rx_default { + pin = ; + }; +}; diff --git a/boards/arm/rcar_spider/rcar_spider_cr52.dts b/boards/arm/rcar_spider/rcar_spider_cr52.dts new file mode 100644 index 000000000000000..6d89b3ede94d530 --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52.dts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include +#include "rcar_spider_cr52-pinctrl.dtsi" +#include + +/ { + model = "Renesas Spider board"; + compatible = "renesas,spider-cr52"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &scif0; + zephyr,shell-uart = &scif0; + }; + + leds { + compatible = "gpio-leds"; + user_led: led_8 { + gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + label = "User LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: sw10 { + gpios = <&gpio4 13 GPIO_ACTIVE_LOW>; + label = "User switch"; + zephyr,code = ; + }; + }; + + aliases { + led0 = &user_led; + sw0 = &user_button; + }; +}; + +&scif0 { + pinctrl-0 = <&scif0_data_tx_default &scif0_data_rx_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio4 { + status = "okay"; +}; diff --git a/boards/arm/rcar_spider/rcar_spider_cr52.yaml b/boards/arm/rcar_spider/rcar_spider_cr52.yaml new file mode 100644 index 000000000000000..6dea2b344b70cb6 --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52.yaml @@ -0,0 +1,11 @@ +identifier: rcar_spider_cr52 +name: Cortex r52 for Renesas Spider +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - clock_control + - uart diff --git a/boards/arm/rcar_spider/rcar_spider_cr52_defconfig b/boards/arm/rcar_spider/rcar_spider_cr52_defconfig new file mode 100644 index 000000000000000..7eea72fd80a52fd --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52_defconfig @@ -0,0 +1,13 @@ +CONFIG_SOC_R8A779F0=y +CONFIG_SOC_SERIES_RCAR_GEN4=y +CONFIG_BOARD_RCAR_SPIDER_CR52=y +CONFIG_CLOCK_CONTROL=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=12500000 +CONFIG_CONSOLE=y +CONFIG_RAM_CONSOLE=y +CONFIG_FLASH_SIZE=0 +CONFIG_FLASH_BASE_ADDRESS=0 +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_GPIO=y diff --git a/boards/arm/rcar_spider/support/openocd.cfg b/boards/arm/rcar_spider/support/openocd.cfg new file mode 100644 index 000000000000000..518b63c7f48bdba --- /dev/null +++ b/boards/arm/rcar_spider/support/openocd.cfg @@ -0,0 +1,27 @@ +# Renesas R-Car Spider S4 Cortex-R52 Board Config + +source [find interface/ftdi/olimex-arm-usb-ocd-h.cfg] +source [find target/renesas_rcar_reset_common.cfg] + +set _CHIPNAME r8a779f0 +set _CORE_NAME r52 +set _TARGETNAME $_CHIPNAME.$_CORE_NAME +set _CTINAME $_TARGETNAME.cti +set _DAPNAME $_CHIPNAME.dap +set DAP_TAPID 0x5ba00477 + +set CR52_DBGBASE 0x80c10000 +set CR52_CTIBASE 0x80c20000 + +adapter srst delay 1000 +adapter speed 20000 +global $_CHIPNAME +transport select jtag + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $DAP_TAPID +dap create $_DAPNAME -chain-position $_CHIPNAME.cpu + +cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $CR52_CTIBASE +target create $_TARGETNAME armv8r -dap $_DAPNAME -ap-num 1 -dbgbase $CR52_DBGBASE -cti $_CTINAME + +$_TARGETNAME configure -rtos auto From 36f2627363f4c0f4374a759f587456967815316b Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Tue, 21 Mar 2023 16:12:51 +0100 Subject: [PATCH 1000/1049] doc: Add Renesas Spider board documentation Adding Spider board documentation based on Renesas official documentation and following Zephyr guideline. The documentation is describing the board and its current Zephyr support. Signed-off-by: Aymeric Aillet --- .../doc/img/rcar_s4_block_diagram.jpg | Bin 0 -> 95075 bytes .../doc/img/rcar_s4_spider_full.jpg | Bin 0 -> 82817 bytes boards/arm/rcar_spider/doc/rcar_spider.rst | 200 ++++++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 boards/arm/rcar_spider/doc/img/rcar_s4_block_diagram.jpg create mode 100644 boards/arm/rcar_spider/doc/img/rcar_s4_spider_full.jpg create mode 100644 boards/arm/rcar_spider/doc/rcar_spider.rst diff --git a/boards/arm/rcar_spider/doc/img/rcar_s4_block_diagram.jpg b/boards/arm/rcar_spider/doc/img/rcar_s4_block_diagram.jpg new file mode 100644 index 0000000000000000000000000000000000000000..76bda515cfb8363cea03e4f3363cf40228ef2087 GIT binary patch literal 95075 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
dm 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

Vd(E$R8vs*)2qLz-Uo;#e8apfKMFni;e3ZGg0D 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 literal 0 HcmV?d00001 diff --git a/boards/arm/rcar_spider/doc/rcar_spider.rst b/boards/arm/rcar_spider/doc/rcar_spider.rst new file mode 100644 index 000000000000000..33deb1f27a8d1b8 --- /dev/null +++ b/boards/arm/rcar_spider/doc/rcar_spider.rst @@ -0,0 +1,200 @@ +.. _rcar_spider_boards: + +Renesas R-Car Spider +#################### + +Overview +******** + +| R-Car S4 enables the launch of Car Server/CoGW with high performance, high-speed networking, +| high security and high functional safety levels that are required as E/E architectures +| evolve into domains and zones. + +| The R-Car S4 solution allows designers to re-use up to 88 percent of software code developed +| for 3rd generation R-Car SoCs and RH850 MCU applications.\ +| The software package supports the real-time cores with various drivers and basic software +| such as Linux BSP and hypervisors. + +The Renesas R-Car Spider board is the Renesas R-Car S4 reference board and is designed for +evaluating features and performance of this SoC. + +.. figure:: img/rcar_s4_spider_full.jpg + :align: center + :alt: R-Car S4 Spider + +More information about the board can be found at `Renesas R-Car S4 Spider`_ website. + +Hardware +******** + +Hardware capabilities for the S4 Spider board can be found on the `eLinux S4 Spider`_ page. + +.. figure:: img/rcar_s4_block_diagram.jpg + :align: center + :alt: R-Car S4 Spider block diagram + +.. note:: We support Zephyr running on the CR52 processor that is provided for RTOS purpose. + +More information about the SoC that equips the board can be found here: + +- `Renesas R-Car S4 chip`_ + +Supported Features +================== + +Here are the current supported features when running Zephyr Project on the R-Car S4 Spider CR52: + ++-----------+------------------------------+--------------------------------+ +| Interface | Driver/components | Support level | ++===========+==============================+================================+ +| PINMUX | pinmux | | ++-----------+------------------------------+--------------------------------+ +| CLOCK | clock_control | | ++-----------+------------------------------+--------------------------------+ +| GPIO | gpio | | ++-----------+------------------------------+--------------------------------+ +| UART | uart | serial port-polling | ++ + + + +| | FT232RQ | serial port-interrupt | ++-----------+------------------------------+--------------------------------+ +| I2C | i2c | interrupt driven | ++-----------+------------------------------+--------------------------------+ +| PWM | pwm | All channels | ++-----------+------------------------------+--------------------------------+ + +It is also currently possible to write on the ram console. + +More features will be supported soon. + +Connections and IOs +=================== + +| The "Spider board" consists of a CPU board and a Breakout board. +| The CPU board is stuck on top of the Breakout board. + +Here are the official IOs figures from eLinux for S4 board: + +`S4 Spider CPU board IOs`_ + +`S4 Spider breakout board IOs`_ + +GPIO +---- + +By running Zephyr on S4 Spider, the software controllable LED 'LED8' can be used as output. + +UART +---- + +Here is information about both serial ports provided on the S4 Spider board : + ++--------------------+----------+--------------------+-------------+------------------------+ +| Physical Interface | Location | Software Interface | Converter | Further Information | ++====================+==========+====================+=============+========================+ +| CN20 USB Port | CPU Board| SCIF0/HSCIF1 | FT232HQ | Default Zephyr serial | ++--------------------+----------+--------------------+-------------+------------------------+ +| CN21 USB Port | CPU Board| SCIF3/HSCIF0 | FT2232H-56Q | Used by U-BOOT & Linux | ++--------------------+----------+--------------------+-------------+------------------------+ + +.. note:: + The Zephyr console output is assigned to SCIF0 (CN20 USB Port) with settings: + 115200 8N1 without hardware flow control by default. + +I2C +--- + +I2C is mainly used to manage and power-on some onboard chips on the S4 Spider board. + +Embedded I2C devices and I/O expanders are not yet supported. +The current I2C support therefore does not make any devices available to the user at this time. + +Programming and Debugging +************************* + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Supported Debug Probe +===================== + +| The "Olimex ARM-USB-OCD-H" probe is the only officially supported probe. +| This probe is supported by OpenOCD that is shipped with the Zephyr SDK. + +The "Olimex ARM-USB-OCD-H" probe needs to be connected with a "Coresight 20 pins" +adapter to CN1 connector on Spider board. + +Configuring a Console +===================== + +Connect a USB cable from your PC to CN20 USB port of your Spider board. + +Use the following settings with your serial terminal of choice (minicom, putty, +etc.): + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Flashing +======== + +First of all, open your serial terminal. + +Applications for the ``rcar_spider_cr52`` board configuration can be built in the +usual way (see :ref:`build_an_application` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: rcar_spider_cr52 + :goals: flash + +You should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v3.3.0-rc2 *** + Hello World! rcar_spider_cr52 + +Debugging +========= + +First of all, open your serial terminal. + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: rcar_spider_cr52 + :goals: debug + +You will then get access to a GDB session for debugging. + +By continuing the app, you should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v3.3.0-rc2 *** + Hello World! rcar_spider_cr52 + +References +********** + +- `Renesas R-Car S4 Spider`_ +- `Renesas R-Car S4 chip`_ +- `eLinux S4 Spider`_ + +.. _Renesas R-Car S4 Spider: + https://www.renesas.com/us/en/products/automotive-products/automotive-system-chips-socs/rtp8a779f0askb0sp2s-r-car-s4-reference-boardspider + +.. _Renesas R-Car S4 chip: + https://www.renesas.com/us/en/products/automotive-products/automotive-system-chips-socs/r-car-s4-automotive-system-chip-soc-car-servercommunication-gateway + +.. _eLinux S4 Spider: + https://elinux.org/R-Car/Boards/Spider + +.. _S4 Spider CPU board IOs: + https://elinux.org/images/6/6d/Rcar_s4_spider_cpu_board.jpg + +.. _S4 Spider breakout board IOs: + https://elinux.org/images/2/29/Rcar_s4_spider_breakout_board.jpg From cb10e94799d72991ff34b64ceb3538b5a38549b2 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 23 Nov 2023 16:23:58 +0800 Subject: [PATCH 1001/1049] drivers: intc: plic: minor code refactor The `riscv_plic_irq_enable` & `riscv_plic_irq_disable` are very similar, refactor them out into `plic_irq_enable_set_state`. Signed-off-by: Yong Cong Sin --- drivers/interrupt_controller/intc_plic.c | 42 ++++++++++-------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index d05d28b88340534..c579d28dad2e5a3 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -142,17 +142,7 @@ static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq) return sys_read32(trig_addr) & BIT(local_irq); } -/** - * @brief Enable a riscv PLIC-specific interrupt line - * - * This routine enables a RISCV PLIC-specific interrupt line. - * riscv_plic_irq_enable is called by SOC_FAMILY_RISCV_PRIVILEGED - * arch_irq_enable function to enable external interrupts for - * IRQS level == 2, whenever CONFIG_RISCV_HAS_PLIC variable is set. - * - * @param irq IRQ number to enable - */ -void riscv_plic_irq_enable(uint32_t irq) +static void plic_irq_enable_set_state(uint32_t irq, bool enable) { const struct device *dev = get_plic_dev_from_irq(irq); const struct plic_config *config = dev->config; @@ -163,11 +153,26 @@ void riscv_plic_irq_enable(uint32_t irq) key = irq_lock(); en_value = sys_read32(en_addr); - WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, true); + WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, enable); sys_write32(en_value, en_addr); irq_unlock(key); } +/** + * @brief Enable a riscv PLIC-specific interrupt line + * + * This routine enables a RISCV PLIC-specific interrupt line. + * riscv_plic_irq_enable is called by SOC_FAMILY_RISCV_PRIVILEGED + * arch_irq_enable function to enable external interrupts for + * IRQS level == 2, whenever CONFIG_RISCV_HAS_PLIC variable is set. + * + * @param irq IRQ number to enable + */ +void riscv_plic_irq_enable(uint32_t irq) +{ + plic_irq_enable_set_state(irq, true); +} + /** * @brief Disable a riscv PLIC-specific interrupt line * @@ -180,18 +185,7 @@ void riscv_plic_irq_enable(uint32_t irq) */ void riscv_plic_irq_disable(uint32_t irq) { - const struct device *dev = get_plic_dev_from_irq(irq); - const struct plic_config *config = dev->config; - const uint32_t local_irq = irq_from_level_2(irq); - mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq); - uint32_t en_value; - uint32_t key; - - key = irq_lock(); - en_value = sys_read32(en_addr); - WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, false); - sys_write32(en_value, en_addr); - irq_unlock(key); + plic_irq_enable_set_state(irq, false); } /** From 13e5c6359b126edca81857ea654ec8be2ee14462 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Fri, 24 Nov 2023 10:24:31 +0100 Subject: [PATCH 1002/1049] maintainers: correct user name Update user name from semihalf-niedzwiecki-dawid to niedzwiecki-dawid. Signed-off-by: Dawid Niedzwiecki --- MAINTAINERS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 8a514d236c221bf..7309472c27446d8 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1602,7 +1602,7 @@ Release Notes: EC Host Commands: status: maintained maintainers: - - semihalf-niedzwiecki-dawid + - niedzwiecki-dawid files: - subsys/mgmt/ec_host_cmd/ - include/zephyr/mgmt/ec_host_cmd/ From 8b9537662547730e5b6e878c4f157786e1541adb Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 23 Nov 2023 18:16:17 +1000 Subject: [PATCH 1003/1049] bluetooth: hci: increase SPI driver stack size Increase the SPI RX driver stack size by 128 bytes. Overflows have previously been observed on real hardware at the default stack size of 512. Signed-off-by: Jordan Yates --- drivers/bluetooth/hci/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 0f792b58b0821b3..60326ec7cf8b1fa 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -185,7 +185,7 @@ config BT_DRV_TX_STACK_SIZE config BT_DRV_RX_STACK_SIZE int - default 512 if BT_SPI + default 640 if BT_SPI default BT_RX_STACK_SIZE if (BT_H4 || BT_HCI_RAW_H4) default BT_STM32_IPM_RX_STACK_SIZE if BT_STM32_IPM default 256 From e1cd9f335d32b3b3809f63eb7c69dd18638b1921 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 23 Nov 2023 18:19:54 +1000 Subject: [PATCH 1004/1049] bluetooth: hci: spi: handle interrupt return code Handle the GPIO module failing to configure the interrupt line. Fixes #65583 Signed-off-by: Jordan Yates --- drivers/bluetooth/hci/spi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 32b50ea191ff0f9..a61920b0745eee9 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -493,7 +493,10 @@ static int bt_spi_open(void) } /* Enable the interrupt line */ - gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + err = gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + if (err) { + return err; + } /* Take BLE out of reset */ k_sleep(K_MSEC(DT_INST_PROP_OR(0, reset_assert_duration_ms, 0))); From af671a41bbab8f32d77edd68c6de92a2412c6a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 09:33:51 +0100 Subject: [PATCH 1005/1049] drivers: display: doc: Add missing Doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added proper doxygen comments where they were missing. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/display.h | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/include/zephyr/drivers/display.h b/include/zephyr/drivers/display.h index a72534b4e50b816..ae879401dd5a0a4 100644 --- a/include/zephyr/drivers/display.h +++ b/include/zephyr/drivers/display.h @@ -38,12 +38,12 @@ extern "C" { * big endian. */ enum display_pixel_format { - PIXEL_FORMAT_RGB_888 = BIT(0), - PIXEL_FORMAT_MONO01 = BIT(1), /* 0=Black 1=White */ - PIXEL_FORMAT_MONO10 = BIT(2), /* 1=Black 0=White */ - PIXEL_FORMAT_ARGB_8888 = BIT(3), - PIXEL_FORMAT_RGB_565 = BIT(4), - PIXEL_FORMAT_BGR_565 = BIT(5), + PIXEL_FORMAT_RGB_888 = BIT(0), /**< 24-bit RGB */ + PIXEL_FORMAT_MONO01 = BIT(1), /**< Monochrome (0=Black 1=White) */ + PIXEL_FORMAT_MONO10 = BIT(2), /**< Monochrome (1=Black 0=White) */ + PIXEL_FORMAT_ARGB_8888 = BIT(3), /**< 32-bit ARGB */ + PIXEL_FORMAT_RGB_565 = BIT(4), /**< 16-bit RGB */ + PIXEL_FORMAT_BGR_565 = BIT(5), /**< 16-bit BGR */ }; /** @@ -61,6 +61,9 @@ enum display_pixel_format { (((fmt & PIXEL_FORMAT_RGB_565) >> 4) * 16U) + \ (((fmt & PIXEL_FORMAT_BGR_565) >> 5) * 16U)) +/** + * @brief Display screen information + */ enum display_screen_info { /** * If selected, one octet represents 8 pixels ordered vertically, @@ -87,15 +90,13 @@ enum display_screen_info { }; /** - * @enum display_orientation * @brief Enumeration with possible display orientation - * */ enum display_orientation { - DISPLAY_ORIENTATION_NORMAL, - DISPLAY_ORIENTATION_ROTATED_90, - DISPLAY_ORIENTATION_ROTATED_180, - DISPLAY_ORIENTATION_ROTATED_270, + DISPLAY_ORIENTATION_NORMAL, /**< No rotation */ + DISPLAY_ORIENTATION_ROTATED_90, /**< Rotated 90 degrees clockwise */ + DISPLAY_ORIENTATION_ROTATED_180, /**< Rotated 180 degrees clockwise */ + DISPLAY_ORIENTATION_ROTATED_270, /**< Rotated 270 degrees clockwise */ }; /** @brief Structure holding display capabilities. */ From 12cefe1027013f73ce916586524b6ebc0098e7f6 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 20 Nov 2023 10:08:46 +0100 Subject: [PATCH 1006/1049] Bluetooth: Controller: Fix compiler warning when RL_SIZE=1 Fix compiler warning when BT_CTLR_RL_SIZE=1. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_filter.c b/subsys/bluetooth/controller/ll_sw/ull_filter.c index 341b729651522a2..5d6e68238aed14c 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_filter.c +++ b/subsys/bluetooth/controller/ll_sw/ull_filter.c @@ -390,7 +390,7 @@ uint8_t ll_rl_remove(bt_addr_le_t *id_addr) /* Swap with last item */ uint8_t pi = rl[i].pirk_idx, pj = peer_irk_count - 1; - if (pj && pi != pj) { + if (pj && (pj < ARRAY_SIZE(peer_irks)) && (pi != pj)) { (void)memcpy(peer_irks[pi], peer_irks[pj], IRK_SIZE); for (k = 0U; From 0b39da6869dff49da135f8a63cda290e6830eca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 14:02:19 +0100 Subject: [PATCH 1007/1049] doc: Do not fail when manually authored doc file is not tracked by git MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug where a newly created documentation file not yet tracked by git would cause the documentation generation to fail. Signed-off-by: Benjamin Cabé --- doc/_extensions/zephyr/gh_utils.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index 6ba75ce5ab7c12e..38c5cff316ea650 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -173,7 +173,8 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: Returns: Optional[Tuple[str, str]] -- Tuple with the date and SHA1 of the last commit made to the - page, or None if the page is not in the repo. + page, or None if the page is not in the repo (generated file, or manually authored file not + yet tracked by git). """ page_prefix = get_page_prefix(app, pagename) @@ -186,6 +187,15 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: app.env.doc2path(pagename, False), ) + # Check if the file is tracked by git + try: + subprocess.check_output( + ["git", "ls-files", "--error-unmatch", orig_path], + stderr=subprocess.STDOUT, + ) + except subprocess.CalledProcessError: + return None + try: date_and_sha1 = ( subprocess.check_output( @@ -212,7 +222,6 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: except subprocess.CalledProcessError: return None - def add_jinja_filter(app: Sphinx): if app.builder.format != "html": return From 20979f80a659c9734c2c13a68c4cb85a29e21f77 Mon Sep 17 00:00:00 2001 From: Marco Widmer Date: Thu, 23 Nov 2023 17:46:44 +0100 Subject: [PATCH 1008/1049] drivers: uart: esp32: use config from device tree The parity, stop bits and data bits config was hard-coded instead of taken from the device tree. Signed-off-by: Marco Widmer --- drivers/serial/uart_esp32.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index 6608d91a44ade37..8a7a2f336af6223 100644 --- a/drivers/serial/uart_esp32.c +++ b/drivers/serial/uart_esp32.c @@ -999,9 +999,11 @@ static const DRAM_ATTR struct uart_driver_api uart_esp32_api = { \ static struct uart_esp32_data uart_esp32_data_##idx = { \ .uart_config = {.baudrate = DT_INST_PROP(idx, current_speed), \ - .parity = UART_CFG_PARITY_NONE, \ - .stop_bits = UART_CFG_STOP_BITS_1, \ - .data_bits = UART_CFG_DATA_BITS_8, \ + .parity = DT_INST_ENUM_IDX_OR(idx, parity, UART_CFG_PARITY_NONE), \ + .stop_bits = DT_INST_ENUM_IDX_OR(idx, stop_bits, \ + UART_CFG_STOP_BITS_1), \ + .data_bits = DT_INST_ENUM_IDX_OR(idx, data_bits, \ + UART_CFG_DATA_BITS_8), \ .flow_ctrl = MAX(COND_CODE_1(DT_INST_PROP(idx, hw_rs485_hd_mode), \ (UART_CFG_FLOW_CTRL_RS485), \ (UART_CFG_FLOW_CTRL_NONE)), \ From 1e7eb7a6da62a20cb2d8f72022523a4dc5eb6271 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 23:09:57 -0500 Subject: [PATCH 1009/1049] posix: pthread: support for pthread_setcanceltype() pthread_setcanceltype() is required by the POSIX_THREADS_BASE Option Group as detailed in Section E.1 of IEEE-1003.1-2017. The POSIX_THREADS_BASE Option Group is required for PSE51, PSE52, PSE53, and PSE54 conformance, and is otherwise mandatory for any POSIX conforming system as per Section A.2.1.3 of IEEE-1003-1.2017. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 3 +++ lib/posix/posix_internal.h | 1 + lib/posix/pthread.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index c7909d40ae2c6bd..a7feef8bc7e3740 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -33,6 +33,8 @@ extern "C" { #define PTHREAD_CANCELED ((void *)-1) #define PTHREAD_CANCEL_ENABLE 0 #define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 /* Passed to pthread_once */ #define PTHREAD_ONCE_INIT \ @@ -452,6 +454,7 @@ int pthread_detach(pthread_t thread); int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, void *(*threadroutine)(void *), void *arg); int pthread_setcancelstate(int state, int *oldstate); +int pthread_setcanceltype(int type, int *oldtype); int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *schedparam); int pthread_setschedparam(pthread_t pthread, int policy, diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 39c64c53331c158..4ce000e51471808 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -38,6 +38,7 @@ struct posix_thread { /* Pthread cancellation */ uint8_t cancel_state; + uint8_t cancel_type; bool cancel_pending; /* Detach state */ diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index e96cfc287e00be2..d00d5564c73f310 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -500,6 +500,34 @@ int pthread_setcancelstate(int state, int *oldstate) return 0; } +/** + * @brief Set cancelability Type. + * + * See IEEE 1003.1 + */ +int pthread_setcanceltype(int type, int *oldtype) +{ + k_spinlock_key_t key; + struct posix_thread *t; + + if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) { + LOG_ERR("Invalid pthread cancel type %d", type); + return EINVAL; + } + + t = to_posix_thread(pthread_self()); + if (t == NULL) { + return EINVAL; + } + + key = k_spin_lock(&pthread_pool_lock); + *oldtype = t->cancel_type; + t->cancel_type = type; + k_spin_unlock(&pthread_pool_lock, key); + + return 0; +} + /** * @brief Cancel execution of a thread. * From 5f64a47d524b6d1e51537c2d51aac54653cf3bdb Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 23:17:53 -0500 Subject: [PATCH 1010/1049] tests: posix: headers: support pthread_setcancelstate() / type() The function pthread_setcancelstate() has been supported for some time already in Zephyr. For some reason, it was not being checked in the "headers" testsuite. Additionally, check for pthread_setcanceltype() since it was added in a prior commit. Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 51452d88de55d6f..444a487f85c2e09 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -23,9 +23,10 @@ ZTEST(posix_headers, test_pthread_h) { zassert_not_equal(-1, PTHREAD_BARRIER_SERIAL_THREAD); - /* zassert_not_equal(-1, PTHREAD_CANCEL_ASYNCHRONOUS); */ /* not implemented */ + zassert_not_equal(-1, PTHREAD_CANCEL_ASYNCHRONOUS); + zassert_not_equal(-1, PTHREAD_CANCEL_DEFERRED); + zassert_not_equal(-1, PTHREAD_CANCEL_ENABLE); - /* zassert_not_equal(-1, PTHREAD_CANCEL_DEFERRED); */ /* not implemented */ zassert_not_equal(-1, PTHREAD_CANCEL_DISABLE); zassert_not_equal((void *)-42, PTHREAD_CANCELED); @@ -146,8 +147,8 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_rwlockattr_init); /* zassert_not_null(pthread_rwlockattr_setpshared); */ /* not implemented */ zassert_not_null(pthread_self); - /* zassert_not_null(pthread_setcancelstate); */ /* not implemented */ - /* zassert_not_null(pthread_setcanceltype); */ /* not implemented */ + zassert_not_null(pthread_setcancelstate); + zassert_not_null(pthread_setcanceltype); /* zassert_not_null(pthread_setconcurrency); */ /* not implemented */ zassert_not_null(pthread_setschedparam); /* zassert_not_null(pthread_setschedprio); */ /* not implemented */ From ecd2961160644823d9924c9360030a9f712f561b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 22 Nov 2023 23:20:43 -0500 Subject: [PATCH 1011/1049] doc: services: portability: posix: add pthread_setcanceltype() The function pthread_setcanceltype() is supported and mandatory for conforming implementations. Mark it as supported since the preceding commit. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index e151788586de4ad..eb623f0e626109e 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -61,7 +61,7 @@ multiple processes. pthread_once(),yes pthread_self(),yes pthread_setcancelstate(),yes - pthread_setcanceltype(), + pthread_setcanceltype(),yes pthread_setspecific(),yes pthread_sigmask(), pthread_testcancel(), From 4d8442d3a5827ef928447846c7dc9b7529622371 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 24 Nov 2023 21:02:33 -0500 Subject: [PATCH 1012/1049] docs: posix: update the XSI_THREADS_EXT option group Previously pthread_attr_getguardsize() and pthread_attr_setguardsize() were part of the XSI_THREADS_EXT option group. That is no longer the case. In IEEE 1003.1-2017 they are part of the POSIX_THREADS_EXT option group. Signed-off-by: Christopher Friedt --- .../portability/posix/option_groups/index.rst | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index eb623f0e626109e..fe1f7aa95b6d328 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -66,6 +66,22 @@ multiple processes. pthread_sigmask(), pthread_testcancel(), +.. _posix_option_group_posix_threads_ext: + +POSIX_THREADS_EXT +================= + +This table lists service support status in Zephyr: + +.. csv-table:: POSIX_THREADS_EXT + :header: API, Supported + :widths: 50,10 + + pthread_attr_getguardsize(), + pthread_attr_setguardsize(), + pthread_mutexattr_gettype(),yes + pthread_mutexattr_settype(),yes + .. _posix_option_group_xsi_thread_ext: XSI_THREAD_EXT @@ -81,9 +97,7 @@ This table lists service support status in Zephyr: :header: API, Supported :widths: 50,10 - pthread_attr_getguardsize(), pthread_attr_getstack(),yes - pthread_attr_setguardsize(), pthread_attr_setstack(),yes pthread_getconcurrency(), pthread_setconcurrency() From 5da13ea30a6a1b1beef19466a4f2211f34b4d61c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 24 Nov 2023 21:15:34 -0500 Subject: [PATCH 1013/1049] docs: posix: correct spelling of XSI_THREADS_EXT The option group includes a trailing S Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index fe1f7aa95b6d328..97d7ce226a83fff 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -82,10 +82,10 @@ This table lists service support status in Zephyr: pthread_mutexattr_gettype(),yes pthread_mutexattr_settype(),yes -.. _posix_option_group_xsi_thread_ext: +.. _posix_option_group_xsi_threads_ext: -XSI_THREAD_EXT -============== +XSI_THREADS_EXT +=============== The XSI_THREADS_EXT option group is required because it provides functions to control a thread's stack. This is considered useful for any @@ -93,7 +93,7 @@ real-time application. This table lists service support status in Zephyr: -.. csv-table:: XSI_THREAD_EXT +.. csv-table:: XSI_THREADS_EXT :header: API, Supported :widths: 50,10 From b58a1f15af95ce586331fad02e860f31a50d45ca Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 15 Nov 2023 13:37:48 +0100 Subject: [PATCH 1014/1049] kernel: sanitize thread options Some thread options were made architecture specific, i.e. K_ARC_DSP_IDX. We have other architectures with similar functionality and we need to be architecture agnostic at this level. Changed the option to be more generic. The option is now called K_DSP_IDX. Also remove multiple level of ifdefs and guards around those defines to allow for documentation to be published and added a note about required configs in the docstring. Signed-off-by: Anas Nashif --- include/zephyr/kernel.h | 22 +++---------------- .../arc/arc_dsp_sharing/src/test_common.h | 2 +- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index d2b912f6d46e13f..1ea059e5df41555 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -171,7 +171,6 @@ void k_thread_foreach_unlocked( * */ #define K_ESSENTIAL (BIT(0)) -#if defined(CONFIG_FPU_SHARING) /** * @brief FPU registers are managed by context switch * @@ -183,7 +182,6 @@ void k_thread_foreach_unlocked( */ #define K_FP_IDX 1 #define K_FP_REGS (BIT(K_FP_IDX)) -#endif /** * @brief user mode thread @@ -214,10 +212,6 @@ void k_thread_foreach_unlocked( */ #define K_CALLBACK_STATE (BIT(4)) -#ifdef CONFIG_ARC -/* ARC processor Bitmask definitions for threads user options */ - -#if defined(CONFIG_ARC_DSP_SHARING) /** * @brief DSP registers are managed by context switch * @@ -225,13 +219,11 @@ void k_thread_foreach_unlocked( * This option indicates that the thread uses the CPU's DSP registers. * This instructs the kernel to take additional steps to save and * restore the contents of these registers when scheduling the thread. - * No effect if @kconfig{CONFIG_ARC_DSP_SHARING} is not enabled. + * No effect if @kconfig{CONFIG_DSP_SHARING} is not enabled. */ #define K_DSP_IDX 6 -#define K_ARC_DSP_REGS (BIT(K_DSP_IDX)) -#endif +#define K_DSP_REGS (BIT(K_DSP_IDX)) -#if defined(CONFIG_ARC_AGU_SHARING) /** * @brief AGU registers are managed by context switch * @@ -241,14 +233,8 @@ void k_thread_foreach_unlocked( * No effect if @kconfig{CONFIG_ARC_AGU_SHARING} is not enabled. */ #define K_AGU_IDX 7 -#define K_ARC_AGU_REGS (BIT(K_AGU_IDX)) -#endif -#endif - -#ifdef CONFIG_X86 -/* x86 Bitmask definitions for threads user options */ +#define K_AGU_REGS (BIT(K_AGU_IDX)) -#if defined(CONFIG_FPU_SHARING) && defined(CONFIG_X86_SSE) /** * @brief FP and SSE registers are managed by context switch on x86 * @@ -259,8 +245,6 @@ void k_thread_foreach_unlocked( * the thread. No effect if @kconfig{CONFIG_X86_SSE} is not enabled. */ #define K_SSE_REGS (BIT(7)) -#endif -#endif /* end - thread options */ diff --git a/tests/arch/arc/arc_dsp_sharing/src/test_common.h b/tests/arch/arc/arc_dsp_sharing/src/test_common.h index f64c652b59ed1b0..a38c3a59ed8d0f1 100644 --- a/tests/arch/arc/arc_dsp_sharing/src/test_common.h +++ b/tests/arch/arc/arc_dsp_sharing/src/test_common.h @@ -14,4 +14,4 @@ #define THREAD_HIGH_PRIORITY 5 #define THREAD_LOW_PRIORITY 10 -#define THREAD_DSP_FLAGS (K_ARC_DSP_REGS | K_ARC_AGU_REGS) +#define THREAD_DSP_FLAGS (K_DSP_REGS | K_AGU_REGS) From aed0c451f8f68e1ced4fe1cdf75b281e3aa6106b Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 16 Nov 2023 09:16:42 -0500 Subject: [PATCH 1015/1049] arch: introduce DSP_SHARING and CPU_HAS_DSP configs introduce global DSP_SHARING and CPU_HAS_DSP to be used by all architectures and change existing usage in ARC to use those global configs. Signed-off-by: Anas Nashif --- arch/Kconfig | 16 ++++++++++++++++ arch/arc/core/dsp/Kconfig | 11 +++-------- arch/arc/core/dsp/dsp_offsets.c | 2 +- arch/arc/core/dsp/swap_dsp_macros.h | 4 ++-- arch/arc/core/offsets/offsets.c | 2 +- arch/arc/core/thread.c | 6 +++--- arch/arc/include/kernel_arch_data.h | 2 +- soc/arc/snps_arc_hsdk4xd/Kconfig.soc | 2 +- soc/arc/snps_nsim/Kconfig | 2 +- tests/arch/arc/arc_dsp_sharing/prj.conf | 2 +- tests/arch/arc/arc_dsp_sharing/src/main.c | 2 +- tests/arch/arc/arc_dsp_sharing/testcase.yaml | 4 ++-- 12 files changed, 33 insertions(+), 22 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index cc9925e77747c95..2884540ef37aa50 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -656,6 +656,11 @@ config CPU_HAS_FPU This option is enabled when the CPU has hardware floating point unit. +config CPU_HAS_DSP + bool + help + This option is enabled when the CPU has hardware DSP unit. + config CPU_HAS_FPU_DOUBLE_PRECISION bool select CPU_HAS_FPU @@ -820,6 +825,17 @@ config CODE_DATA_RELOCATION the target regions should be specified in CMakeLists.txt using zephyr_code_relocate(). +menu "DSP Options" + +config DSP_SHARING + bool "DSP register sharing" + depends on CPU_HAS_DSP + help + This option enables preservation of the hardware DSP registers + across context switches to allow multiple threads to perform concurrent + DSP operations. +endmenu + menu "Floating Point Options" config FPU diff --git a/arch/arc/core/dsp/Kconfig b/arch/arc/core/dsp/Kconfig index 396f9c6840e34fa..48a910198ecd501 100644 --- a/arch/arc/core/dsp/Kconfig +++ b/arch/arc/core/dsp/Kconfig @@ -3,13 +3,8 @@ # Copyright (c) 2022 Synopsys # SPDX-License-Identifier: Apache-2.0 -config ARC_HAS_DSP - bool - help - This option is enabled when the ARC CPU has hardware DSP unit. - menu "ARC DSP Options" -depends on ARC_HAS_DSP +depends on CPU_HAS_DSP config ARC_DSP bool "digital signal processing (DSP)" @@ -22,7 +17,7 @@ config ARC_DSP_TURNED_OFF help This option disables DSP block via resetting DSP_CRTL register. -config ARC_DSP_SHARING +config DSP_SHARING bool "DSP register sharing" depends on ARC_DSP && MULTITHREADING select ARC_HAS_ACCL_REGS @@ -49,7 +44,7 @@ config ARC_XY_ENABLE config ARC_AGU_SHARING bool "ARC address generation unit register sharing" depends on ARC_XY_ENABLE && MULTITHREADING - default y if ARC_DSP_SHARING + default y if DSP_SHARING help This option enables preservation of the hardware AGU registers across context switches to allow multiple threads to perform concurrent diff --git a/arch/arc/core/dsp/dsp_offsets.c b/arch/arc/core/dsp/dsp_offsets.c index bc606c9c26e6bb4..77db2d82c1fae12 100644 --- a/arch/arc/core/dsp/dsp_offsets.c +++ b/arch/arc/core/dsp/dsp_offsets.c @@ -9,7 +9,7 @@ * @brief ARCv2 DSP and AGU structure member offset definition file * */ -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING GEN_OFFSET_SYM(_callee_saved_stack_t, dsp_ctrl); GEN_OFFSET_SYM(_callee_saved_stack_t, acc0_glo); GEN_OFFSET_SYM(_callee_saved_stack_t, acc0_ghi); diff --git a/arch/arc/core/dsp/swap_dsp_macros.h b/arch/arc/core/dsp/swap_dsp_macros.h index 0d322fa28fcf032..07615286683fb4f 100644 --- a/arch/arc/core/dsp/swap_dsp_macros.h +++ b/arch/arc/core/dsp/swap_dsp_macros.h @@ -10,7 +10,7 @@ * */ .macro _save_dsp_regs -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING ld_s r13, [r2, ___thread_base_t_user_options_OFFSET] bbit0 r13, K_DSP_IDX, dsp_skip_save lr r13, [_ARC_V2_DSP_CTRL] @@ -136,7 +136,7 @@ agu_skip_save : .endm .macro _load_dsp_regs -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING ld_s r13, [r2, ___thread_base_t_user_options_OFFSET] bbit0 r13, K_DSP_IDX, dsp_skip_load ld_s r13, [sp, ___callee_saved_stack_t_dsp_ctrl_OFFSET] diff --git a/arch/arc/core/offsets/offsets.c b/arch/arc/core/offsets/offsets.c index 450a6d23047bdbf..855270fa3ab72f6 100644 --- a/arch/arc/core/offsets/offsets.c +++ b/arch/arc/core/offsets/offsets.c @@ -26,7 +26,7 @@ #include #include #include -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING #include "../dsp/dsp_offsets.c" #endif diff --git a/arch/arc/core/thread.c b/arch/arc/core/thread.c index eeb12d45f6a8ec9..563401201433e85 100644 --- a/arch/arc/core/thread.c +++ b/arch/arc/core/thread.c @@ -19,7 +19,7 @@ #include #endif -#if defined(CONFIG_ARC_DSP) && defined(CONFIG_ARC_DSP_SHARING) +#if defined(CONFIG_ARC_DSP) && defined(CONFIG_DSP_SHARING) #include static struct k_spinlock lock; #endif @@ -297,7 +297,7 @@ FUNC_NORETURN void z_arc_switch_to_main_no_multithreading(k_thread_entry_t main_ } #endif /* !CONFIG_MULTITHREADING */ -#if defined(CONFIG_ARC_DSP) && defined(CONFIG_ARC_DSP_SHARING) +#if defined(CONFIG_ARC_DSP) && defined(CONFIG_DSP_SHARING) void arc_dsp_disable(struct k_thread *thread, unsigned int options) { /* Ensure a preemptive context switch does not occur */ @@ -319,4 +319,4 @@ void arc_dsp_enable(struct k_thread *thread, unsigned int options) k_spin_unlock(&lock, key); } -#endif /* CONFIG_ARC_DSP && CONFIG_ARC_DSP_SHARING */ +#endif /* CONFIG_ARC_DSP && CONFIG_DSP_SHARING */ diff --git a/arch/arc/include/kernel_arch_data.h b/arch/arc/include/kernel_arch_data.h index 14f7869763fa94d..efe2bd7d1c6585b 100644 --- a/arch/arc/include/kernel_arch_data.h +++ b/arch/arc/include/kernel_arch_data.h @@ -160,7 +160,7 @@ struct _callee_saved_stack { #endif #endif -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING #ifdef CONFIG_ARC_DSP_BFLY_SHARING uintptr_t dsp_fft_ctrl; uintptr_t dsp_bfly0; diff --git a/soc/arc/snps_arc_hsdk4xd/Kconfig.soc b/soc/arc/snps_arc_hsdk4xd/Kconfig.soc index be4331ad48bfd48..6354c659d30bfdb 100644 --- a/soc/arc/snps_arc_hsdk4xd/Kconfig.soc +++ b/soc/arc/snps_arc_hsdk4xd/Kconfig.soc @@ -5,4 +5,4 @@ config SOC_ARC_HSDK4XD bool "Synopsys ARC HSDK4XD SoC" select ARC select CPU_HAS_FPU - select ARC_HAS_DSP + select CPU_HAS_DSP diff --git a/soc/arc/snps_nsim/Kconfig b/soc/arc/snps_nsim/Kconfig index 62b74e8a7436de7..cdf2ec69cae16da 100644 --- a/soc/arc/snps_nsim/Kconfig +++ b/soc/arc/snps_nsim/Kconfig @@ -18,7 +18,7 @@ config SOC_NSIM_EM7D_V22 config SOC_NSIM_EM11D bool "Synopsys ARC EM11D in nSIM" select CPU_HAS_MPU - select ARC_HAS_DSP + select CPU_HAS_DSP config SOC_NSIM_SEM bool "Synopsys ARC SEM in nSIM" diff --git a/tests/arch/arc/arc_dsp_sharing/prj.conf b/tests/arch/arc/arc_dsp_sharing/prj.conf index f3be5294428aa18..0215be6e34d3a53 100644 --- a/tests/arch/arc/arc_dsp_sharing/prj.conf +++ b/tests/arch/arc/arc_dsp_sharing/prj.conf @@ -1,5 +1,5 @@ CONFIG_ZTEST=y CONFIG_ARC_DSP=y -CONFIG_ARC_DSP_SHARING=y +CONFIG_DSP_SHARING=y CONFIG_MAIN_STACK_SIZE=1024 CONFIG_ARC_DSP_BFLY_SHARING=y diff --git a/tests/arch/arc/arc_dsp_sharing/src/main.c b/tests/arch/arc/arc_dsp_sharing/src/main.c index 9367cc54875dc00..641e6c01b7455d2 100644 --- a/tests/arch/arc/arc_dsp_sharing/src/main.c +++ b/tests/arch/arc/arc_dsp_sharing/src/main.c @@ -11,7 +11,7 @@ #error Rebuild with the ARC_DSP config option enabled #endif -#ifndef CONFIG_ARC_DSP_SHARING +#ifndef CONFIG_DSP_SHARING #error Rebuild with the ARC_DSP_SHARING config option enabled #endif diff --git a/tests/arch/arc/arc_dsp_sharing/testcase.yaml b/tests/arch/arc/arc_dsp_sharing/testcase.yaml index 21cb221e059be06..c2149b0570e8fe7 100644 --- a/tests/arch/arc/arc_dsp_sharing/testcase.yaml +++ b/tests/arch/arc/arc_dsp_sharing/testcase.yaml @@ -1,8 +1,8 @@ tests: arch.arc.dsp_sharing.test_load_store: - filter: CONFIG_ISA_ARCV2 and CONFIG_ARC_HAS_DSP + filter: CONFIG_ISA_ARCV2 and CONFIG_CPU_HAS_DSP platform_allow: nsim_em11d arch.arc.dsp_sharing.test_calculation: - filter: CONFIG_ISA_ARCV2 and CONFIG_ARC_HAS_DSP + filter: CONFIG_ISA_ARCV2 and CONFIG_CPU_HAS_DSP toolchain_allow: arcmwdt platform_allow: nsim_em11d From 9f1b1bbba436e29af026bbf99ee8db26dcaab342 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Wed, 22 Nov 2023 07:34:27 +0900 Subject: [PATCH 1016/1049] boards: arm: rpi_pico: add pyocd runner configuration Adding configuration for support pyocd. Signed-off-by: TOKITA Hiroshi --- boards/arm/rpi_pico/board.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boards/arm/rpi_pico/board.cmake b/boards/arm/rpi_pico/board.cmake index 07a128fad7bfa33..e9cd4edc18f594b 100644 --- a/boards/arm/rpi_pico/board.cmake +++ b/boards/arm/rpi_pico/board.cmake @@ -27,8 +27,10 @@ board_runner_args(openocd --cmd-pre-init "set_adapter_speed_if_not_set 2000") board_runner_args(jlink "--device=RP2040_M0_0") board_runner_args(uf2 "--board-id=RPI-RP2") +board_runner_args(pyocd "--target=rp2040") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/uf2.board.cmake) include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) From 1b364c1422010dd450146510237d11779395b85c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 22 Nov 2023 12:21:30 +0000 Subject: [PATCH 1017/1049] drivers: console: uart_mcumgr: Skip reading FIFO during setup Drops calling the UART FIFO read function during the setup function (when not in async mode) which could cause issues on some devices since this function is not called in an ISR. Signed-off-by: Jamie McCrae --- drivers/console/uart_mcumgr.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/console/uart_mcumgr.c b/drivers/console/uart_mcumgr.c index 30b0c7be7180a9a..2b068e6810c4b05 100644 --- a/drivers/console/uart_mcumgr.c +++ b/drivers/console/uart_mcumgr.c @@ -228,16 +228,9 @@ static void uart_mcumgr_setup(const struct device *uart) #else static void uart_mcumgr_setup(const struct device *uart) { - uint8_t c; - uart_irq_rx_disable(uart); uart_irq_tx_disable(uart); - /* Drain the fifo */ - while (uart_fifo_read(uart, &c, 1)) { - continue; - } - uart_irq_callback_set(uart, uart_mcumgr_isr); uart_irq_rx_enable(uart); From 5ae648d4173354191142898da2493cc23dfad38a Mon Sep 17 00:00:00 2001 From: Joseph Yates Date: Fri, 14 Jul 2023 08:36:41 +0100 Subject: [PATCH 1018/1049] boards: shields: Adding support for the waveshare pico ups-b shield Adding support for the Waveshare pico ups-b shield with documentation Signed-off-by: Joseph Yates --- boards/arm/rpi_pico/rpi_pico-common.dtsi | 9 ++ boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi | 8 + boards/shields/waveshare_ups/Kconfig.shield | 5 + .../waveshare_ups/boards/rpi_pico.overlay | 18 +++ boards/shields/waveshare_ups/doc/index.rst | 141 ++++++++++++++++++ .../doc/waveshare_pico_ups_b.jpg | Bin 0 -> 39292 bytes .../waveshare_pico_ups_b.overlay | 19 +++ 7 files changed, 200 insertions(+) create mode 100644 boards/shields/waveshare_ups/Kconfig.shield create mode 100644 boards/shields/waveshare_ups/boards/rpi_pico.overlay create mode 100644 boards/shields/waveshare_ups/doc/index.rst create mode 100644 boards/shields/waveshare_ups/doc/waveshare_pico_ups_b.jpg create mode 100644 boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay diff --git a/boards/arm/rpi_pico/rpi_pico-common.dtsi b/boards/arm/rpi_pico/rpi_pico-common.dtsi index 54f12e53843e0e4..680d20324494e39 100644 --- a/boards/arm/rpi_pico/rpi_pico-common.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-common.dtsi @@ -112,6 +112,13 @@ pinctrl-names = "default"; }; +&i2c1 { + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + status = "disabled"; + clock-frequency = ; +}; + &spi0 { clock-frequency = ; status = "okay"; @@ -149,3 +156,5 @@ zephyr_udc0: &usbd { }; pico_spi: &spi0 {}; +pico_i2c0: &i2c0 {}; +pico_i2c1: &i2c1 {}; diff --git a/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi index 93790191e6e9d7c..747b0d04e409581 100644 --- a/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi @@ -24,6 +24,14 @@ }; }; + i2c1_default: i2c1_default { + group1 { + pinmux = , ; + input-enable; + input-schmitt-enable; + }; + }; + spi0_default: spi0_default { group1 { pinmux = , , ; diff --git a/boards/shields/waveshare_ups/Kconfig.shield b/boards/shields/waveshare_ups/Kconfig.shield new file mode 100644 index 000000000000000..38da89750c4b919 --- /dev/null +++ b/boards/shields/waveshare_ups/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Joseph Yates +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_WAVESHARE_PICO_UPS_B + def_bool $(shields_list_contains,waveshare_pico_ups_b) diff --git a/boards/shields/waveshare_ups/boards/rpi_pico.overlay b/boards/shields/waveshare_ups/boards/rpi_pico.overlay new file mode 100644 index 000000000000000..e8fe6525af1c9b6 --- /dev/null +++ b/boards/shields/waveshare_ups/boards/rpi_pico.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Joseph Yates + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +&pinctrl { + i2c1_default: i2c1_default { + group1 { + bias-pull-up; + }; + }; +}; + +&pico_i2c1 { + status = "okay"; +}; diff --git a/boards/shields/waveshare_ups/doc/index.rst b/boards/shields/waveshare_ups/doc/index.rst new file mode 100644 index 000000000000000..4fc35403b4675ea --- /dev/null +++ b/boards/shields/waveshare_ups/doc/index.rst @@ -0,0 +1,141 @@ +.. _waveshare_pico_ups_b_shield: + +Waveshare Pico UPS-B shield +########################### + +Overview +******** + +The Waveshare Pico UPS-B shield is an uninterruptible Power supply (UPS) +module designed for the Raspberry Pi Pico which uses the Texas Instruments' INA219 +current/power Monitor. It communicates with the Raspberry Pi Pico over I2C + +.. figure:: waveshare_pico_ups_b.jpg + :align: center + :alt: Waveshare Pico UPS-B shield + + Waveshare Pico UPS-B shield + +Hardware +-------- + +- INA219 + + - Senses bus voltages from 0 to 26 V + - Reports current, voltage and power + - 16 Programmable Addresses + - SOT23-8 and SOIC-8 packages + - Calibration registers + +- ETA6003 + + - Switching charger with power path management + - Up to 95% DC-DC efficiency + - 0mΩ power path MOSFET + - Up to 2.5A max charging current + +- Connectivity + + - Raspberry Pi Pico compatible (I2C) + - 2 pin jst header for Li-po battery + +-------+-----------------------+---------------------------+ +| Name | Function | Usage | ++=======+=======================+===========================+ +| GP0 | None | | ++-------+-----------------------+---------------------------+ +| GP1 | None | | ++-------+-----------------------+---------------------------+ +| GP2 | None | | ++-------+-----------------------+---------------------------+ +| GP3 | None | | ++-------+-----------------------+---------------------------+ +| GP4 | None | | ++-------+-----------------------+---------------------------+ +| GP5 | None | | ++-------+-----------------------+---------------------------+ +| GP6 | I2C1_SDA ACTIVE_LOW | INA219 | ++-------+-----------------------+---------------------------+ +| GP7 | I2C1_SCL ACTIVE_LOW | INA219 | ++-------+-----------------------+---------------------------+ +| GP8 | None | | ++-------+-----------------------+---------------------------+ +| GP9 | None | | ++-------+-----------------------+---------------------------+ +| GP10 | None | | ++-------+-----------------------+---------------------------+ +| GP11 | None | | ++-------+-----------------------+---------------------------+ +| GP12 | None | | ++-------+-----------------------+---------------------------+ +| GP13 | None | | ++-------+-----------------------+---------------------------+ +| GP14 | None | | ++-------+-----------------------+---------------------------+ +| GP15 | None | | ++-------+-----------------------+---------------------------+ +| GP16 | None | | ++-------+-----------------------+---------------------------+ +| GP17 | None | | ++-------+-----------------------+---------------------------+ +| GP18 | None | | ++-------+-----------------------+---------------------------+ +| GP19 | None | | ++-------+-----------------------+---------------------------+ +| GP20 | None | | ++-------+-----------------------+---------------------------+ +| GP21 | None | | ++-------+-----------------------+---------------------------+ +| GP22 | None | | ++-------+-----------------------+---------------------------+ +| GP23 | None | | ++-------+-----------------------+---------------------------+ +| GP24 | None | | ++-------+-----------------------+---------------------------+ +| GP25 | None | | ++-------+-----------------------+---------------------------+ +| GP26 | None | | ++-------+-----------------------+---------------------------+ +| GP27 | None | | ++-------+-----------------------+---------------------------+ +| GP28 | None | | ++-------+-----------------------+---------------------------+ + + +- Power Supply + + - 3.3V ~ 5V + +- Components + + - Power switch + - Power LED + - Charging LED + +For more information about the Waveshare Pico UPS-B: + +- `Waveshare Pico UPS website`_ +- `INA219 data sheet`_ +- `ETA6003 data sheet`_ + +Programming +*********** + +Set ``-DSHIELD=waveshare_pico_ups_b`` when you invoke ``west build`` or ``cmake`` in your Zephyr application. For +example: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/ina219 + :tool: all + :board: rpi_pico + :shield: waveshare_pico_ups_b + :goals: build flash + +.. _Waveshare Pico UPS website: + https://www.waveshare.com/wiki/Pico-UPS-B + +.. _INA219 data sheet: + https://www.ti.com/lit/ds/symlink/ina219.pdf + +.. _ETA6003 data sheet: + https://www.waveshare.com/w/upload/3/3f/ETA6003.pdf diff --git a/boards/shields/waveshare_ups/doc/waveshare_pico_ups_b.jpg b/boards/shields/waveshare_ups/doc/waveshare_pico_ups_b.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53f1191db5a035b7a22bee4285f4375acd7f3c07 GIT binary patch literal 39292 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 F|Jg=(l5hY3 literal 0 HcmV?d00001 diff --git a/boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay b/boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay new file mode 100644 index 000000000000000..381bce67c742d7a --- /dev/null +++ b/boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Joseph Yates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pico_i2c1 { + waveshare_pico_ups: ina219@43 { + status = "okay"; + compatible = "ti,ina219"; + reg = <0x43>; + brng = <1>; + pg = <3>; + sadc = <12>; + badc = <12>; + shunt-milliohm = <100>; + lsb-microamp = <20>; + }; +}; From ec7bdde22b6af9d57018e142fd68b12212270d15 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 31 Oct 2023 20:14:09 +0100 Subject: [PATCH 1019/1049] Bluetooth: Controller: Improve preempt timeout req/ack counting Improve preempt timeout request and acknowledge counting. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index db8f25a374ca3dc..6d51b63ecbbb370 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -832,7 +832,7 @@ static void ticker_stop_op_cb(uint32_t status, void *param) ARG_UNUSED(status); LL_ASSERT(preempt_stop_req != preempt_stop_ack); - preempt_stop_ack++; + preempt_stop_ack = preempt_stop_req; preempt_req = preempt_ack; } @@ -852,7 +852,7 @@ static void ticker_start_op_cb(uint32_t status, void *param) * start operation has been handled. */ LL_ASSERT(preempt_start_req != preempt_start_ack); - preempt_start_ack++; + preempt_start_ack = preempt_start_req; } static uint32_t preempt_ticker_start(struct lll_event *first, @@ -974,7 +974,7 @@ static void preempt_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t ret; LL_ASSERT(preempt_ack != preempt_req); - preempt_ack++; + preempt_ack = preempt_req; mfy.param = param; ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, From b444dc442b8c7ead81bf27a07168047c70602f15 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 31 Oct 2023 20:33:31 +0100 Subject: [PATCH 1020/1049] Bluetooth: Controller: Minor re-arrange advanced feature Kconfig Minor refactor of Kconfig order such that the advanced feature Kconfig is just above the enabling/visible of the advanced features menu. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/Kconfig.ll_sw_split | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 2b9e33ef82d7d8c..7cef480413d20d6 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -240,11 +240,6 @@ config BT_CTLR_CONN_ISO_AVOID_SEGMENTATION interface, the config provides a way to force the Max_PDU to Max_SDU + 5 (header + offset). -config BT_CTLR_ADVANCED_FEATURES - bool "Show advanced features" - help - Makes advanced features visible to controller developers. - choice prompt "CIS Creation Policy Selection" default BT_CTLR_CONN_ISO_RELIABILITY_POLICY @@ -272,6 +267,11 @@ config BT_CTLR_TEST help Run in-system unit tests +config BT_CTLR_ADVANCED_FEATURES + bool "Show advanced features" + help + Makes advanced features visible to controller developers. + menu "Advanced features" visible if BT_CTLR_ADVANCED_FEATURES From d573951f0daf5f541703293256885fe0e93b7799 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 31 Oct 2023 20:17:11 +0100 Subject: [PATCH 1021/1049] Bluetooth: Controller: Revert back early abort of previous prepare Revert back to implementation that did early abort of previous prepare when a short prepare is enqueued. Adds back implementation deleted in commit 7f388bb70a3d ("Bluetooth: Controller: Fix short prepare when many enqueued in pipeline"). Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/Kconfig.ll_sw_split | 7 +++++++ .../controller/ll_sw/nordic/lll/lll.c | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 7cef480413d20d6..0e2685f29ca2900 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -961,6 +961,13 @@ config BT_CTLR_SCAN_UNRESERVED Scanner will not use time space reservation for scan window when in continuous scan mode. +config BT_CTLR_EARLY_ABORT_PREVIOUS_PREPARE + bool "Early abort previous prepare" + default y + help + Early abort previous prepare present before a short prepare is + enqueued in the prepare pipeline. + config BT_MAYFLY_YIELD_AFTER_CALL bool "Yield from mayfly thread after first call" default y diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index 6d51b63ecbbb370..473282eb61832e8 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -906,6 +906,26 @@ static uint32_t preempt_ticker_start(struct lll_event *first, LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || (ret == TICKER_STATUS_BUSY)); +#if defined(CONFIG_BT_CTLR_EARLY_ABORT_PREVIOUS_PREPARE) + /* FIXME: Prepare pipeline is not a ordered list implementation, + * and for short prepare being enqueued, ideally the + * pipeline has to be implemented as ordered list. + * Until then a workaround to abort a prepare present + * before the short prepare being enqueued is implemented + * below. + * A proper solution will be to re-design the pipeline + * as a ordered list, instead of the current FIFO. + */ + /* Set early as we get called again through the call to + * abort_cb(). + */ + ticks_at_preempt = ticks_at_preempt_new; + + /* Abort previous prepare that set the preempt timeout */ + prev->is_aborted = 1U; + prev->abort_cb(&prev->prepare_param, prev->prepare_param.param); +#endif /* CONFIG_BT_CTLR_EARLY_ABORT_PREVIOUS_PREPARE */ + /* Schedule short preempt timeout */ first = next; } else { From d36e085eccedcf6a053016badeb267ea0f5c3cd2 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 31 Oct 2023 20:17:34 +0100 Subject: [PATCH 1022/1049] Bluetooth: Controller: Fix scan aux context leak Fix scan aux context leak under BT_CTLR_SCAN_UNRESERVED. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c index c8188d87cb61fca..57132835fba6646 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c @@ -632,6 +632,7 @@ static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) static void abort_cb(struct lll_prepare_param *prepare_param, void *param) { + struct event_done_extra *e; int err; /* NOTE: This is not a prepare being cancelled */ @@ -651,6 +652,9 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) err = lll_hfclock_off(); LL_ASSERT(err >= 0); + e = ull_done_extra_type_set(EVENT_DONE_EXTRA_TYPE_SCAN_AUX); + LL_ASSERT(e); + lll_done(param); } From 64cc0764ee2247c014a851453d0be9c8153cdf46 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Sun, 12 Nov 2023 10:29:36 +1300 Subject: [PATCH 1023/1049] drivers: virtualization: Map ivshmem-v2 sections individually Recent changes to the arm64 MMU code mean that you can no longer map R/O memory as R/W. Mapping R/W memory now causes a cache invalidation instruction (DC IVAC) that requires write permissions or else a fault is generated. Modify ivshmem-v2 to map each R/O and R/W section individually Signed-off-by: Grant Ramsay --- drivers/virtualization/Kconfig | 6 ++ drivers/virtualization/virt_ivshmem.c | 59 ++++++++++++++----- drivers/virtualization/virt_ivshmem.h | 5 +- .../zephyr/drivers/virtualization/ivshmem.h | 6 ++ 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/drivers/virtualization/Kconfig b/drivers/virtualization/Kconfig index 4f32552f09aeef4..f439f5ba97d07e9 100644 --- a/drivers/virtualization/Kconfig +++ b/drivers/virtualization/Kconfig @@ -66,4 +66,10 @@ config IVSHMEM_V2 Enable ivshmem-v2 support. ivshmem-v2 is primarily used for IPC in the Jailhouse hypervisor. +config IVSHMEM_V2_MAX_PEERS + int "Maximum number of ivshmem-v2 peers" + depends on IVSHMEM_V2 + default 2 + range 2 65536 + endif # VIRTUALIZATION diff --git a/drivers/virtualization/virt_ivshmem.c b/drivers/virtualization/virt_ivshmem.c index 6e8258f1dadc82c..f620ab473f9e066 100644 --- a/drivers/virtualization/virt_ivshmem.c +++ b/drivers/virtualization/virt_ivshmem.c @@ -198,7 +198,7 @@ static bool ivshmem_configure(const struct device *dev) (volatile struct ivshmem_v2_reg *)DEVICE_MMIO_GET(dev); data->max_peers = regs->max_peers; - if (!IN_RANGE(data->max_peers, 2, 0x10000)) { + if (!IN_RANGE(data->max_peers, 2, CONFIG_IVSHMEM_V2_MAX_PEERS)) { LOG_ERR("Invalid max peers %u", data->max_peers); return false; } @@ -211,26 +211,49 @@ static bool ivshmem_configure(const struct device *dev) shmem_phys_addr = pcie_conf_read_u64(data->pcie->bdf, cap_pos); } + /* State table R/O */ cap_pos = vendor_cap + IVSHMEM_CFG_STATE_TAB_SZ / 4; size_t state_table_size = pcie_conf_read(data->pcie->bdf, cap_pos); - LOG_INF("State table size 0x%zX", state_table_size); if (state_table_size < sizeof(uint32_t) * data->max_peers) { LOG_ERR("Invalid state table size %zu", state_table_size); return false; } + z_phys_map((uint8_t **)&data->state_table_shmem, + shmem_phys_addr, state_table_size, + K_MEM_CACHE_WB | K_MEM_PERM_USER); + /* R/W section (optional) */ cap_pos = vendor_cap + IVSHMEM_CFG_RW_SECTION_SZ / 4; data->rw_section_size = pcie_conf_read_u64(data->pcie->bdf, cap_pos); - data->rw_section_offset = state_table_size; + size_t rw_section_offset = state_table_size; LOG_INF("RW section size 0x%zX", data->rw_section_size); + if (data->rw_section_size > 0) { + z_phys_map((uint8_t **)&data->rw_section_shmem, + shmem_phys_addr + rw_section_offset, data->rw_section_size, + K_MEM_CACHE_WB | K_MEM_PERM_RW | K_MEM_PERM_USER); + } + /* Output sections */ cap_pos = vendor_cap + IVSHMEM_CFG_OUTPUT_SECTION_SZ / 4; data->output_section_size = pcie_conf_read_u64(data->pcie->bdf, cap_pos); - data->output_section_offset = data->rw_section_offset + data->rw_section_size; + size_t output_section_offset = rw_section_offset + data->rw_section_size; LOG_INF("Output section size 0x%zX", data->output_section_size); + for (uint32_t i = 0; i < data->max_peers; i++) { + uintptr_t phys_addr = shmem_phys_addr + + output_section_offset + + (data->output_section_size * i); + uint32_t flags = K_MEM_CACHE_WB | K_MEM_PERM_USER; + + /* Only your own output section is R/W */ + if (i == regs->id) { + flags |= K_MEM_PERM_RW; + } + z_phys_map((uint8_t **)&data->output_section_shmem[i], + phys_addr, data->output_section_size, flags); + } - data->size = data->output_section_offset + + data->size = output_section_offset + data->output_section_size * data->max_peers; /* Ensure one-shot ISR mode is disabled */ @@ -249,11 +272,11 @@ static bool ivshmem_configure(const struct device *dev) } data->size = mbar_shmem.size; - } - z_phys_map((uint8_t **)&data->shmem, - shmem_phys_addr, data->size, - K_MEM_CACHE_WB | K_MEM_PERM_RW | K_MEM_PERM_USER); + z_phys_map((uint8_t **)&data->shmem, + shmem_phys_addr, data->size, + K_MEM_CACHE_WB | K_MEM_PERM_RW | K_MEM_PERM_USER); + } if (msi_x_bar_present) { if (!ivshmem_configure_msi_x_interrupts(dev)) { @@ -284,6 +307,13 @@ static size_t ivshmem_api_get_mem(const struct device *dev, { struct ivshmem *data = dev->data; +#ifdef CONFIG_IVSHMEM_V2 + if (data->ivshmem_v2) { + *memmap = 0; + return 0; + } +#endif + *memmap = data->shmem; return data->size; @@ -389,11 +419,11 @@ static size_t ivshmem_api_get_rw_mem_section(const struct device *dev, struct ivshmem *data = dev->data; if (!data->ivshmem_v2) { - memmap = NULL; + *memmap = 0; return 0; } - *memmap = data->shmem + data->rw_section_offset; + *memmap = data->rw_section_shmem; return data->rw_section_size; } @@ -405,12 +435,11 @@ static size_t ivshmem_api_get_output_mem_section(const struct device *dev, struct ivshmem *data = dev->data; if (!data->ivshmem_v2 || peer_id >= data->max_peers) { - memmap = NULL; + *memmap = 0; return 0; } - *memmap = data->shmem + data->output_section_offset + - data->output_section_size * peer_id; + *memmap = data->output_section_shmem[peer_id]; return data->output_section_size; } @@ -425,7 +454,7 @@ static uint32_t ivshmem_api_get_state(const struct device *dev, } const volatile uint32_t *state_table = - (const volatile uint32_t *)data->shmem; + (const volatile uint32_t *)data->state_table_shmem; return state_table[peer_id]; } diff --git a/drivers/virtualization/virt_ivshmem.h b/drivers/virtualization/virt_ivshmem.h index e64394087872207..8a7ae11c3646e84 100644 --- a/drivers/virtualization/virt_ivshmem.h +++ b/drivers/virtualization/virt_ivshmem.h @@ -57,9 +57,10 @@ struct ivshmem { bool ivshmem_v2; uint32_t max_peers; size_t rw_section_size; - size_t rw_section_offset; size_t output_section_size; - size_t output_section_offset; + uintptr_t state_table_shmem; + uintptr_t rw_section_shmem; + uintptr_t output_section_shmem[CONFIG_IVSHMEM_V2_MAX_PEERS]; #endif }; diff --git a/include/zephyr/drivers/virtualization/ivshmem.h b/include/zephyr/drivers/virtualization/ivshmem.h index 0507eb6ae1af547..20bd1e42336eb17 100644 --- a/include/zephyr/drivers/virtualization/ivshmem.h +++ b/include/zephyr/drivers/virtualization/ivshmem.h @@ -84,6 +84,12 @@ __subsystem struct ivshmem_driver_api { /** * @brief Get the inter-VM shared memory * + * Note: This API is not supported for ivshmem-v2, as + * the R/W and R/O areas may not be mapped contiguously. + * For ivshmem-v2, use the ivshmem_get_rw_mem_section, + * ivshmem_get_output_mem_section and ivshmem_get_state + * APIs to access the shared memory. + * * @param dev Pointer to the device structure for the driver instance * @param memmap A pointer to fill in with the memory address * From 82644a31c28991e4d586563fe43bd0d6a6c09df2 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Sun, 12 Nov 2023 10:39:00 +1300 Subject: [PATCH 1024/1049] drivers: ethernet: Fix eth_ivshmem shared memory mapping This driver assumed the ivshmem-v2 output sections would be mapped contiguously, which is no longer true. Modify eth_ivshmem to treat each output section independently Signed-off-by: Grant Ramsay --- drivers/ethernet/eth_ivshmem.c | 11 ++++++----- drivers/ethernet/eth_ivshmem_priv.h | 4 ++-- drivers/ethernet/eth_ivshmem_queue.c | 14 ++++---------- .../ethernet/eth_ivshmem_queue/src/main.c | 19 ++++++++++++------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/ethernet/eth_ivshmem.c b/drivers/ethernet/eth_ivshmem.c index eb869261cbcca2e..0d2c104359a7a78 100644 --- a/drivers/ethernet/eth_ivshmem.c +++ b/drivers/ethernet/eth_ivshmem.c @@ -297,14 +297,15 @@ int eth_ivshmem_initialize(const struct device *dev) } dev_data->peer_id = (id == 0) ? 1 : 0; - bool tx_buffer_first = id == 0; - uintptr_t output_section_addr; + uintptr_t output_sections[2]; size_t output_section_size = ivshmem_get_output_mem_section( - cfg_data->ivshmem, 0, &output_section_addr); + cfg_data->ivshmem, 0, &output_sections[0]); + ivshmem_get_output_mem_section( + cfg_data->ivshmem, 1, &output_sections[1]); res = eth_ivshmem_queue_init( - &dev_data->ivshmem_queue, output_section_addr, - output_section_size, tx_buffer_first); + &dev_data->ivshmem_queue, output_sections[id], + output_sections[dev_data->peer_id], output_section_size); if (res != 0) { LOG_ERR("Failed to init ivshmem queue"); return res; diff --git a/drivers/ethernet/eth_ivshmem_priv.h b/drivers/ethernet/eth_ivshmem_priv.h index b5769a31f03541c..f537d3be295824b 100644 --- a/drivers/ethernet/eth_ivshmem_priv.h +++ b/drivers/ethernet/eth_ivshmem_priv.h @@ -40,8 +40,8 @@ struct eth_ivshmem_queue { }; int eth_ivshmem_queue_init( - struct eth_ivshmem_queue *q, uintptr_t shmem, - size_t shmem_section_size, bool tx_buffer_first); + struct eth_ivshmem_queue *q, uintptr_t tx_shmem, + uintptr_t rx_shmem, size_t shmem_section_size); void eth_ivshmem_queue_reset(struct eth_ivshmem_queue *q); int eth_ivshmem_queue_tx_get_buff(struct eth_ivshmem_queue *q, void **data, size_t len); int eth_ivshmem_queue_tx_commit_buff(struct eth_ivshmem_queue *q); diff --git a/drivers/ethernet/eth_ivshmem_queue.c b/drivers/ethernet/eth_ivshmem_queue.c index d5b5b29a7353d13..3301dd72a35d96d 100644 --- a/drivers/ethernet/eth_ivshmem_queue.c +++ b/drivers/ethernet/eth_ivshmem_queue.c @@ -28,8 +28,8 @@ static int tx_clean_used(struct eth_ivshmem_queue *q); static int get_rx_avail_desc_idx(struct eth_ivshmem_queue *q, uint16_t *avail_desc_idx); int eth_ivshmem_queue_init( - struct eth_ivshmem_queue *q, uintptr_t shmem, - size_t shmem_section_size, bool tx_buffer_first) + struct eth_ivshmem_queue *q, uintptr_t tx_shmem, + uintptr_t rx_shmem, size_t shmem_section_size) { memset(q, 0, sizeof(*q)); @@ -44,14 +44,8 @@ int eth_ivshmem_queue_init( q->desc_max_len = vring_desc_len; q->vring_data_max_len = shmem_section_size - vring_header_size; q->vring_header_size = vring_header_size; - - if (tx_buffer_first) { - q->tx.shmem = (void *)shmem; - q->rx.shmem = (void *)(shmem + shmem_section_size); - } else { - q->rx.shmem = (void *)shmem; - q->tx.shmem = (void *)(shmem + shmem_section_size); - } + q->tx.shmem = (void *)tx_shmem; + q->rx.shmem = (void *)rx_shmem; /* Init vrings */ vring_init(&q->tx.vring, vring_desc_len, q->tx.shmem, ETH_IVSHMEM_VRING_ALIGNMENT); diff --git a/tests/drivers/ethernet/eth_ivshmem_queue/src/main.c b/tests/drivers/ethernet/eth_ivshmem_queue/src/main.c index 53c65e39e16ffab..2c268a274d159ad 100644 --- a/tests/drivers/ethernet/eth_ivshmem_queue/src/main.c +++ b/tests/drivers/ethernet/eth_ivshmem_queue/src/main.c @@ -16,16 +16,21 @@ #define VRING_DATA_MAX_LEN 2304 static struct eth_ivshmem_queue q1, q2; -static uint8_t shmem_buff[SHMEM_SECTION_SIZE * 2]; +static uint8_t shmem_buff[2][SHMEM_SECTION_SIZE] __aligned(KB(4)); static const void *rx_message; static size_t rx_len; static void test_init_queues(void) { - int res = eth_ivshmem_queue_init(&q1, (uintptr_t)shmem_buff, SHMEM_SECTION_SIZE, true); + int res; + res = eth_ivshmem_queue_init( + &q1, (uintptr_t)shmem_buff[0], + (uintptr_t)shmem_buff[1], SHMEM_SECTION_SIZE); zassert_ok(res); - res = eth_ivshmem_queue_init(&q2, (uintptr_t)shmem_buff, SHMEM_SECTION_SIZE, false); + res = eth_ivshmem_queue_init( + &q2, (uintptr_t)shmem_buff[1], + (uintptr_t)shmem_buff[0], SHMEM_SECTION_SIZE); zassert_ok(res); } @@ -55,10 +60,10 @@ ZTEST(eth_ivshmem_queue_tests, test_init) zassert_equal(q1.desc_max_len, VRING_DESC_LEN); zassert_equal(q1.vring_header_size, VRING_HEADER_SIZE); zassert_equal(q1.vring_data_max_len, VRING_DATA_MAX_LEN); - zassert_equal_ptr(q1.tx.shmem, shmem_buff); - zassert_equal_ptr(q1.rx.shmem, shmem_buff + SHMEM_SECTION_SIZE); - zassert_equal_ptr(q2.tx.shmem, shmem_buff + SHMEM_SECTION_SIZE); - zassert_equal_ptr(q2.rx.shmem, shmem_buff); + zassert_equal_ptr(q1.tx.shmem, shmem_buff[0]); + zassert_equal_ptr(q1.rx.shmem, shmem_buff[1]); + zassert_equal_ptr(q2.tx.shmem, shmem_buff[1]); + zassert_equal_ptr(q2.rx.shmem, shmem_buff[0]); } ZTEST(eth_ivshmem_queue_tests, test_simple_send_receive) From a1614e8c955ebbcdbece8ad8feb4260edc47fb7c Mon Sep 17 00:00:00 2001 From: Minho Jin Date: Tue, 14 Nov 2023 16:50:38 +0900 Subject: [PATCH 1025/1049] driver: counter: rpi_pico_timer: fix counter cancel alarm setting function checks channel callback and it returns -EBUSY if callback is registered. but alarm cancel function doesn't clear callback function. this prevents from alarm setting after alarm cancel Signed-off-by: Minho Jin --- drivers/counter/counter_rpi_pico_timer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/counter/counter_rpi_pico_timer.c b/drivers/counter/counter_rpi_pico_timer.c index 3e1a1dcbb0bd403..40a5aadd4918215 100644 --- a/drivers/counter/counter_rpi_pico_timer.c +++ b/drivers/counter/counter_rpi_pico_timer.c @@ -106,6 +106,11 @@ static int counter_rpi_pico_timer_set_alarm(const struct device *dev, uint8_t id static int counter_rpi_pico_timer_cancel_alarm(const struct device *dev, uint8_t id) { + struct counter_rpi_pico_timer_data *data = dev->data; + struct counter_rpi_pico_timer_ch_data *chdata = &data->ch_data[id]; + + chdata->callback = NULL; + chdata->user_data = NULL; hardware_alarm_cancel(id); return 0; From 637b4b62ee233cb4e3733b0bf65e4b415e41daa1 Mon Sep 17 00:00:00 2001 From: Juha Ylinen Date: Mon, 20 Nov 2023 13:40:55 +0200 Subject: [PATCH 1026/1049] samples: lwm2m: Add support for Connection Manager Using Connection Manager, it's easy to run lwm2m sample on devices supporting different connectivity technologies (for example, Wi-Fi and LTE). Signed-off-by: Juha Ylinen --- samples/net/lwm2m_client/src/lwm2m-client.c | 78 +++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index 748f654d9eed78d..a120506639d6ae5 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -16,6 +16,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include +#include #include "modules.h" #define APP_BANNER "Run LWM2M client" @@ -29,6 +31,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define CLIENT_FIRMWARE_VER "1.0" #define CLIENT_HW_VER "1.0.1" +/* Macros used to subscribe to specific Zephyr NET management events. */ +#define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) +#define CONN_LAYER_EVENT_MASK (NET_EVENT_CONN_IF_FATAL_ERROR) + static uint8_t bat_idx = LWM2M_DEVICE_PWR_SRC_TYPE_BAT_INT; static int bat_mv = 3800; static int bat_ma = 125; @@ -52,6 +58,12 @@ BUILD_ASSERT(sizeof(endpoint) <= CONFIG_LWM2M_SECURITY_KEY_SIZE, static struct k_sem quit_lock; +/* Zephyr NET management event callback structures. */ +static struct net_mgmt_event_callback l4_cb; +static struct net_mgmt_event_callback conn_cb; + +static K_SEM_DEFINE(network_connected_sem, 0, 1); + static int device_reboot_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) { @@ -265,6 +277,47 @@ static void observe_cb(enum lwm2m_observe_event event, } } +static void on_net_event_l4_disconnected(void) +{ + LOG_INF("Disconnected from network"); + lwm2m_engine_pause(); +} + +static void on_net_event_l4_connected(void) +{ + LOG_INF("Connected to network"); + k_sem_give(&network_connected_sem); + lwm2m_engine_resume(); +} + +static void l4_event_handler(struct net_mgmt_event_callback *cb, + uint32_t event, + struct net_if *iface) +{ + switch (event) { + case NET_EVENT_L4_CONNECTED: + LOG_INF("IP Up"); + on_net_event_l4_connected(); + break; + case NET_EVENT_L4_DISCONNECTED: + LOG_INF("IP down"); + on_net_event_l4_disconnected(); + break; + default: + break; + } +} + +static void connectivity_event_handler(struct net_mgmt_event_callback *cb, + uint32_t event, + struct net_if *iface) +{ + if (event == NET_EVENT_CONN_IF_FATAL_ERROR) { + LOG_ERR("Fatal error received from the connectivity layer"); + return; + } +} + int main(void) { uint32_t flags = IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) ? @@ -275,6 +328,31 @@ int main(void) k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT); + if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { + /* Setup handler for Zephyr NET Connection Manager events. */ + net_mgmt_init_event_callback(&l4_cb, l4_event_handler, L4_EVENT_MASK); + net_mgmt_add_event_callback(&l4_cb); + + /* Setup handler for Zephyr NET Connection Manager Connectivity layer. */ + net_mgmt_init_event_callback(&conn_cb, connectivity_event_handler, + CONN_LAYER_EVENT_MASK); + net_mgmt_add_event_callback(&conn_cb); + + ret = net_if_up(net_if_get_default()); + + if (ret < 0 && ret != -EALREADY) { + LOG_ERR("net_if_up, error: %d", ret); + return ret; + } + + ret = conn_mgr_if_connect(net_if_get_default()); + /* Ignore errors from interfaces not requiring connectivity */ + if (ret == 0) { + LOG_INF("Connecting to network"); + k_sem_take(&network_connected_sem, K_FOREVER); + } + } + ret = lwm2m_setup(); if (ret < 0) { LOG_ERR("Cannot setup LWM2M fields (%d)", ret); From b37307927523ac4a38b4e81c50baebff37b8b5c5 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 21 Nov 2023 12:45:10 +0100 Subject: [PATCH 1027/1049] Bluetooth: audio: ascs: Remove spurious error message This removes spurious error message printed when CIS has been disconnected and it was not used by any of the endpoints. This case is valid and may happen on Connection Timeout when the controller reports ACL Disconnection first. When the CIS Disconnection is reported after, the ASE is already in idle state and the referenece to CIS has been already removed (on ACL disconnection). Fixes: #64896 Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 116071d4c0f661c..e30c467df49767c 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -944,7 +944,6 @@ static void ascs_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan); if (iso->rx.ep == NULL && iso->tx.ep == NULL) { - LOG_ERR("iso %p not bound with ep", chan); return; } From 65068fb4dfbc4b0d5d8f0bbfbeef299bf7a9d20e Mon Sep 17 00:00:00 2001 From: Tim Woolliscroft Date: Fri, 24 Nov 2023 10:10:03 +0000 Subject: [PATCH 1028/1049] drivers: i2c: stm32: Fix routing of secondary target address Fixes the routing of the events associated with a secondary i2c target address being routed to the primary config. The i2c_target_config/slave_cfg was being selected from the driver address match but then over written by the primary. This change fully implements the if/else of 10bit addressing and includes a assert if the slave_cfg is NULL, and explains why dual 10bit addresses on STM32 won't work. Signed-off-by: Tim Woolliscroft --- drivers/i2c/i2c_ll_stm32_v2.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c_ll_stm32_v2.c b/drivers/i2c/i2c_ll_stm32_v2.c index c75d68e4f19a900..8292b2f6738f6f7 100644 --- a/drivers/i2c/i2c_ll_stm32_v2.c +++ b/drivers/i2c/i2c_ll_stm32_v2.c @@ -142,9 +142,19 @@ static void stm32_i2c_slave_event(const struct device *dev) __ASSERT_NO_MSG(0); return; } + } else { + /* On STM32 the LL_I2C_GetAddressMatchCode & (ISR register) returns + * only 7bits of address match so 10 bit dual addressing is broken. + * Revert to assuming single address match. + */ + if (data->slave_cfg != NULL) { + slave_cfg = data->slave_cfg; + } else { + __ASSERT_NO_MSG(0); + return; + } } - slave_cfg = data->slave_cfg; slave_cb = slave_cfg->callbacks; if (LL_I2C_IsActiveFlag_TXIS(i2c)) { From 06e8d01e9311ac67fa3f24084cc1d8f9d6ad80e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 07:52:07 +0100 Subject: [PATCH 1029/1049] drivers: led: Fix doxygen comments for led_info struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed improperly commented struct. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/led.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/zephyr/drivers/led.h b/include/zephyr/drivers/led.h index b9dd8cc2775d7ba..cb178a9442dd517 100644 --- a/include/zephyr/drivers/led.h +++ b/include/zephyr/drivers/led.h @@ -32,16 +32,15 @@ extern "C" { * @brief LED information structure * * This structure gathers useful information about LED controller. - * - * @param label LED label. - * @param num_colors Number of colors per LED. - * @param index Index of the LED on the controller. - * @param color_mapping Mapping of the LED colors. */ struct led_info { + /** LED label */ const char *label; + /** Number of colors per LED */ uint32_t index; + /** Index of the LED on the controller */ uint8_t num_colors; + /** Mapping of the LED colors */ const uint8_t *color_mapping; }; From e4993fcc5bfb8e46629414b7c6811dc3b2b199dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 23 Nov 2023 08:21:32 +0100 Subject: [PATCH 1030/1049] drivers: spi: doc: Doxygen cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixed a few improperly formatted struct - Marked some mask definitions as internal when macros abstracting them out already exist - Fixed a few code blocks to add proper syntax highlightingy Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/spi.h | 65 +++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index fa3b8834c9e2c33..44863f49acd1539 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -37,9 +37,12 @@ extern "C" { * @name SPI operational mode * @{ */ -#define SPI_OP_MODE_MASTER 0U -#define SPI_OP_MODE_SLAVE BIT(0) +#define SPI_OP_MODE_MASTER 0U /**< Master mode. */ +#define SPI_OP_MODE_SLAVE BIT(0) /**< Slave mode. */ +/** @cond INTERNAL_HIDDEN */ #define SPI_OP_MODE_MASK 0x1U +/** @endcond */ +/** Get SPI operational mode. */ #define SPI_OP_MODE_GET(_operation_) ((_operation_) & SPI_OP_MODE_MASK) /** @} */ @@ -70,8 +73,10 @@ extern "C" { * support this, and can be used for testing purposes only. */ #define SPI_MODE_LOOP BIT(3) - +/** @cond INTERNAL_HIDDEN */ #define SPI_MODE_MASK (0xEU) +/** @endcond */ +/** Get SPI polarity and phase mode bits. */ #define SPI_MODE_GET(_mode_) \ ((_mode_) & SPI_MODE_MASK) @@ -81,19 +86,22 @@ extern "C" { * @name SPI Transfer modes (host controller dependent) * @{ */ -#define SPI_TRANSFER_MSB (0U) -#define SPI_TRANSFER_LSB BIT(4) +#define SPI_TRANSFER_MSB (0U) /**< Most significant bit first. */ +#define SPI_TRANSFER_LSB BIT(4) /**< Least significant bit first. */ /** @} */ /** * @name SPI word size * @{ */ +/** @cond INTERNAL_HIDDEN */ #define SPI_WORD_SIZE_SHIFT (5U) #define SPI_WORD_SIZE_MASK (0x3FU << SPI_WORD_SIZE_SHIFT) +/** @endcond */ +/** Get SPI word size. */ #define SPI_WORD_SIZE_GET(_operation_) \ (((_operation_) & SPI_WORD_SIZE_MASK) >> SPI_WORD_SIZE_SHIFT) - +/** Set SPI word size. */ #define SPI_WORD_SET(_word_size_) \ ((_word_size_) << SPI_WORD_SIZE_SHIFT) /** @} */ @@ -102,16 +110,16 @@ extern "C" { * @name Specific SPI devices control bits * @{ */ -/* Requests - if possible - to keep CS asserted after the transaction */ +/** Requests - if possible - to keep CS asserted after the transaction */ #define SPI_HOLD_ON_CS BIT(12) -/* Keep the device locked after the transaction for the current config. +/** Keep the device locked after the transaction for the current config. * Use this with extreme caution (see spi_release() below) as it will * prevent other callers to access the SPI device until spi_release() is * properly called. */ #define SPI_LOCK_ON BIT(13) -/* Active high logic on CS - Usually, and by default, CS logic is active +/** Active high logic on CS. Usually, and by default, CS logic is active * low. However, some devices may require the reverse logic: active high. * This bit will request the controller to use that logic. Note that not * all controllers are able to handle that natively. In this case deferring @@ -130,12 +138,13 @@ extern "C" { * Without @kconfig{CONFIG_SPI_EXTENDED_MODES} being enabled, single is the * only supported one. */ -#define SPI_LINES_SINGLE (0U << 16) -#define SPI_LINES_DUAL (1U << 16) -#define SPI_LINES_QUAD (2U << 16) -#define SPI_LINES_OCTAL (3U << 16) +#define SPI_LINES_SINGLE (0U << 16) /**< Single line */ +#define SPI_LINES_DUAL (1U << 16) /**< Dual lines */ +#define SPI_LINES_QUAD (2U << 16) /**< Quad lines */ +#define SPI_LINES_OCTAL (3U << 16) /**< Octal lines */ + +#define SPI_LINES_MASK (0x3U << 16) /**< Mask for MISO lines in spi_operation_t */ -#define SPI_LINES_MASK (0x3U << 16) /** @} */ /** @@ -225,22 +234,28 @@ struct spi_cs_control { * * Example devicetree fragment: * - * spi@... { + * @code{.devicetree} + * spi@abcd0001 { * cs-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; * spidev: spi-device@0 { ... }; * }; + * @endcode * * Example usage: * + * @code{.c} * struct spi_cs_control ctrl = * SPI_CS_CONTROL_INIT(DT_NODELABEL(spidev), 2); + * @endcode * * This example is equivalent to: * + * @code{.c} * struct spi_cs_control ctrl = { * .gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(spidev)), * .delay = 2, * }; + * @endcode * * @param node_id Devicetree node identifier for a device on a SPI bus * @param delay_ The @p delay field to set in the @p spi_cs_control @@ -356,12 +371,11 @@ struct spi_config { /** * @brief Complete SPI DT information - * - * @param bus is the SPI bus - * @param config is the slave specific configuration */ struct spi_dt_spec { + /** SPI bus */ const struct device *bus; + /** Slave specific configuration */ struct spi_config config; }; @@ -405,25 +419,24 @@ struct spi_dt_spec { /** * @brief SPI buffer structure - * - * @param buf is a valid pointer on a data buffer, or NULL otherwise. - * @param len is the length of the buffer or, if buf is NULL, will be the - * length which as to be sent as dummy bytes (as TX buffer) or - * the length of bytes that should be skipped (as RX buffer). */ struct spi_buf { + /** Valid pointer to a data buffer, or NULL otherwise */ void *buf; + /** Length of the buffer @a buf. + * If @a buf is NULL, length which as to be sent as dummy bytes (as TX + * buffer) or the length of bytes that should be skipped (as RX buffer). + */ size_t len; }; /** * @brief SPI buffer array structure - * - * @param buffers is a valid pointer on an array of spi_buf, or NULL. - * @param count is the length of the array pointed by buffers. */ struct spi_buf_set { + /** Pointer to an array of spi_buf, or NULL */ const struct spi_buf *buffers; + /** Length of the array pointed by @a buffers */ size_t count; }; From cd5f88e8d30007bafad70ac99ce3fb666d39cf89 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 09:13:18 +0100 Subject: [PATCH 1031/1049] boards native_posix/sim: Define native_posix DTS from native_sim's Get the native_posix DTS from native_sim instead of the oposite. As native_sim is now the default test platform. Note this commit is practically just swapping files. There is no changes to the DTS content, beyond changing the board name. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_posix/native_posix.dts | 216 +-------------------- boards/posix/native_sim/native_sim.dts | 216 ++++++++++++++++++++- 2 files changed, 216 insertions(+), 216 deletions(-) diff --git a/boards/posix/native_posix/native_posix.dts b/boards/posix/native_posix/native_posix.dts index 75af8bdb1fd2f9f..74a3c30049b5c6c 100644 --- a/boards/posix/native_posix/native_posix.dts +++ b/boards/posix/native_posix/native_posix.dts @@ -1,219 +1,7 @@ /* - * Copyright (c) 2019 Jan Van Winkel (jan.van_winkel@dxplore.eu) + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ -/dts-v1/; -#include -#include -#include -#include - -/ { - model = "Native POSIX Board"; - compatible = "zephyr,posix"; - - chosen { - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,uart-mcumgr = &uart0; - zephyr,flash = &flash0; - zephyr,entropy = &rng; - zephyr,flash-controller = &flashcontroller0; - zephyr,display = &sdl_dc; - zephyr,canbus = &can_loopback0; - }; - - aliases { - eeprom-0 = &eeprom0; - i2c-0 = &i2c0; - spi-0 = &spi0; - led0 = &led0; - rtc = &rtc; - }; - - leds { - compatible = "gpio-leds"; - led0: led_0 { - gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; - label = "Green LED"; - }; - }; - - lvgl_pointer { - compatible = "zephyr,lvgl-pointer-input"; - input = <&input_sdl_touch>; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu0: cpu@0 { - compatible = "zephyr,native-posix-cpu"; - reg = <0>; - }; - }; - - flashcontroller0: flash-controller@0 { - compatible = "zephyr,sim-flash"; - reg = <0x00000000 DT_SIZE_K(2048)>; - - #address-cells = <1>; - #size-cells = <1>; - erase-value = <0xff>; - - flash0: flash@0 { - status = "okay"; - compatible = "soc-nv-flash"; - erase-block-size = <4096>; - write-block-size = <1>; - reg = <0x00000000 DT_SIZE_K(2048)>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x0000C000>; - }; - slot0_partition: partition@c000 { - label = "image-0"; - reg = <0x0000C000 0x00069000>; - }; - slot1_partition: partition@75000 { - label = "image-1"; - reg = <0x00075000 0x00069000>; - }; - scratch_partition: partition@de000 { - label = "image-scratch"; - reg = <0x000de000 0x0001e000>; - }; - storage_partition: partition@fc000 { - label = "storage"; - reg = <0x000fc000 0x00004000>; - }; - }; - }; - }; - - eeprom0: eeprom { - status = "okay"; - compatible = "zephyr,sim-eeprom"; - size = ; - }; - - i2c0: i2c@100 { - status = "okay"; - compatible = "zephyr,i2c-emul-controller"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x100 4>; - }; - - spi0: spi@200 { - status = "okay"; - compatible = "zephyr,spi-emul-controller"; - clock-frequency = <50000000>; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x200 4>; - }; - - espi0: espi@300 { - status = "okay"; - compatible = "zephyr,espi-emul-controller"; - reg = <0x300 4>; - #address-cells = <1>; - #size-cells = <0>; - }; - - uart0: uart { - status = "okay"; - compatible = "zephyr,native-posix-uart"; - /* Dummy current-speed entry to comply with serial - * DTS binding - */ - current-speed = <0>; - }; - - uart1: uart_1 { - status = "okay"; - compatible = "zephyr,native-posix-uart"; - /* Dummy current-speed entry to comply with serial - * DTS binding - */ - current-speed = <0>; - }; - - rng: rng { - status = "okay"; - compatible = "zephyr,native-posix-rng"; - }; - - counter0: counter { - status = "okay"; - compatible = "zephyr,native-posix-counter"; - }; - - gpio0: gpio@800 { - status = "okay"; - compatible = "zephyr,gpio-emul"; - reg = <0x800 0x4>; - rising-edge; - falling-edge; - high-level; - low-level; - gpio-controller; - #gpio-cells = <2>; - }; - - zephyr_udc0: udc0 { - compatible = "zephyr,native-posix-udc"; - }; - - sdl_dc: sdl_dc { - compatible = "zephyr,sdl-dc"; - height = <240>; - width = <320>; - }; - - input_sdl_touch: input-sdl-touch { - compatible = "zephyr,input-sdl-touch"; - }; - - can_loopback0: can_loopback0 { - status = "okay"; - compatible = "zephyr,can-loopback"; - sample-point = <875>; - bus-speed = <125000>; - }; - - can0: can { - status = "disabled"; - compatible = "zephyr,native-posix-linux-can"; - /* adjust zcan0 to desired host interface or create an alternative - * name, e.g.: sudo ip link property add dev vcan0 altname zcan0 - */ - host-interface = "zcan0"; - sample-point = <875>; - bus-speed = <125000>; - }; - - rtc: rtc { - status = "okay"; - compatible = "zephyr,rtc-emul"; - alarms-count = <2>; - }; - - adc0: adc { - compatible = "zephyr,adc-emul"; - nchannels = <2>; - #io-channel-cells = <1>; - status = "okay"; - }; -}; +#include "../native_sim/native_sim.dts" diff --git a/boards/posix/native_sim/native_sim.dts b/boards/posix/native_sim/native_sim.dts index b27a9bd540d2d02..73c703ece0be5ed 100644 --- a/boards/posix/native_sim/native_sim.dts +++ b/boards/posix/native_sim/native_sim.dts @@ -1,7 +1,219 @@ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2019 Jan Van Winkel (jan.van_winkel@dxplore.eu) * * SPDX-License-Identifier: Apache-2.0 */ -#include "../native_posix/native_posix.dts" +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "Native Sim Board"; + compatible = "zephyr,posix"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,flash = &flash0; + zephyr,entropy = &rng; + zephyr,flash-controller = &flashcontroller0; + zephyr,display = &sdl_dc; + zephyr,canbus = &can_loopback0; + }; + + aliases { + eeprom-0 = &eeprom0; + i2c-0 = &i2c0; + spi-0 = &spi0; + led0 = &led0; + rtc = &rtc; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + }; + + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&input_sdl_touch>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "zephyr,native-posix-cpu"; + reg = <0>; + }; + }; + + flashcontroller0: flash-controller@0 { + compatible = "zephyr,sim-flash"; + reg = <0x00000000 DT_SIZE_K(2048)>; + + #address-cells = <1>; + #size-cells = <1>; + erase-value = <0xff>; + + flash0: flash@0 { + status = "okay"; + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <1>; + reg = <0x00000000 DT_SIZE_K(2048)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000C000>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000C000 0x00069000>; + }; + slot1_partition: partition@75000 { + label = "image-1"; + reg = <0x00075000 0x00069000>; + }; + scratch_partition: partition@de000 { + label = "image-scratch"; + reg = <0x000de000 0x0001e000>; + }; + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 0x00004000>; + }; + }; + }; + }; + + eeprom0: eeprom { + status = "okay"; + compatible = "zephyr,sim-eeprom"; + size = ; + }; + + i2c0: i2c@100 { + status = "okay"; + compatible = "zephyr,i2c-emul-controller"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x100 4>; + }; + + spi0: spi@200 { + status = "okay"; + compatible = "zephyr,spi-emul-controller"; + clock-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x200 4>; + }; + + espi0: espi@300 { + status = "okay"; + compatible = "zephyr,espi-emul-controller"; + reg = <0x300 4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + uart0: uart { + status = "okay"; + compatible = "zephyr,native-posix-uart"; + /* Dummy current-speed entry to comply with serial + * DTS binding + */ + current-speed = <0>; + }; + + uart1: uart_1 { + status = "okay"; + compatible = "zephyr,native-posix-uart"; + /* Dummy current-speed entry to comply with serial + * DTS binding + */ + current-speed = <0>; + }; + + rng: rng { + status = "okay"; + compatible = "zephyr,native-posix-rng"; + }; + + counter0: counter { + status = "okay"; + compatible = "zephyr,native-posix-counter"; + }; + + gpio0: gpio@800 { + status = "okay"; + compatible = "zephyr,gpio-emul"; + reg = <0x800 0x4>; + rising-edge; + falling-edge; + high-level; + low-level; + gpio-controller; + #gpio-cells = <2>; + }; + + zephyr_udc0: udc0 { + compatible = "zephyr,native-posix-udc"; + }; + + sdl_dc: sdl_dc { + compatible = "zephyr,sdl-dc"; + height = <240>; + width = <320>; + }; + + input_sdl_touch: input-sdl-touch { + compatible = "zephyr,input-sdl-touch"; + }; + + can_loopback0: can_loopback0 { + status = "okay"; + compatible = "zephyr,can-loopback"; + sample-point = <875>; + bus-speed = <125000>; + }; + + can0: can { + status = "disabled"; + compatible = "zephyr,native-posix-linux-can"; + /* adjust zcan0 to desired host interface or create an alternative + * name, e.g.: sudo ip link property add dev vcan0 altname zcan0 + */ + host-interface = "zcan0"; + sample-point = <875>; + bus-speed = <125000>; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + alarms-count = <2>; + }; + + adc0: adc { + compatible = "zephyr,adc-emul"; + nchannels = <2>; + #io-channel-cells = <1>; + status = "okay"; + }; +}; From 7ed88f169bb0ac0ec1d0e4d7af407c6fffba213d Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 23 Nov 2023 18:43:54 +0800 Subject: [PATCH 1032/1049] drivers: intc: stm32: fix a minor copy paste error The description of `STM32_EXTI_TRIG_FALLING` got copied into the `STM32_EXTI_TRIG_BOTH` as well, fix that. Signed-off-by: Yong Cong Sin --- include/zephyr/drivers/interrupt_controller/exti_stm32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/drivers/interrupt_controller/exti_stm32.h b/include/zephyr/drivers/interrupt_controller/exti_stm32.h index 2bd41415983cab7..0bd808f921c6263 100644 --- a/include/zephyr/drivers/interrupt_controller/exti_stm32.h +++ b/include/zephyr/drivers/interrupt_controller/exti_stm32.h @@ -49,7 +49,7 @@ enum stm32_exti_trigger { STM32_EXTI_TRIG_RISING = 0x1, /* trigger on falling edge */ STM32_EXTI_TRIG_FALLING = 0x2, - /* trigger on falling edge */ + /* trigger on both rising & falling edge */ STM32_EXTI_TRIG_BOTH = 0x3, }; From bec7789862ea5449a63626de9c943678c95a13e8 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 23 Nov 2023 12:18:17 +0100 Subject: [PATCH 1033/1049] tests: modem: backend: uart: Add fixture to test suite Add fixture to test suite to allow for and signal that the test must be run on real hardware. Signed-off-by: Bjarki Arge Andreasen --- .../uart/boards/b_u585i_iot02a.overlay | 35 +++------------- .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 42 ++++++++----------- tests/subsys/modem/backends/uart/src/main.c | 2 +- .../subsys/modem/backends/uart/testcase.yaml | 18 ++++---- 4 files changed, 33 insertions(+), 64 deletions(-) diff --git a/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay b/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay index 394facef7bb29c7..30402e6e9d2795c 100644 --- a/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay +++ b/tests/subsys/modem/backends/uart/boards/b_u585i_iot02a.overlay @@ -1,34 +1,11 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + /* - * Pins 2 and 3 must be connected to each other on the STMOD+1 connector to - * loopback RX/TX. + * The Arduino D0 and D1 must be connected to each other to loopback RX/TX. */ -/ { - aliases { - test-uart = &usart2; - }; -}; - -&gpioh { - misc_fixed_usart2 { - gpio-hog; - gpios = <13 GPIO_ACTIVE_HIGH>; - output-high; - }; -}; - -&gpdma1 { - status = "okay"; -}; - -&usart2 { - pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3 &usart2_rts_pa1 &usart2_cts_pa0>; - pinctrl-names = "default"; - current-speed = <115200>; - - dmas = <&gpdma1 0 27 STM32_DMA_PERIPH_TX - &gpdma1 1 26 STM32_DMA_PERIPH_RX>; +dut: &usart3 { + dmas = <&gpdma1 0 29 STM32_DMA_PERIPH_TX + &gpdma1 1 28 STM32_DMA_PERIPH_RX>; dma-names = "tx", "rx"; - - status = "okay"; }; diff --git a/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay b/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay index 2d47b0f0744291d..777aebd8d3b9d81 100644 --- a/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/tests/subsys/modem/backends/uart/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -1,37 +1,31 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + /* - * Pins P1.10 and P1.11 must be connected to each other to loopback RX/TX. + * Pins P0.4 and P0.5 must be connected to each other to loopback RX/TX. */ -/ { - aliases { - test-uart = &uart1; - }; -}; - -&uart1 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart1_default>; - pinctrl-1 = <&uart1_sleep>; - hw-flow-control; - pinctrl-names = "default", "sleep"; -}; - &pinctrl { - uart1_default: uart1_default { + uart1_default_alt: uart1_default_alt { group1 { - psels = ; - }; - group2 { - psels = ; + psels = , + ; }; }; - uart1_sleep: uart1_sleep { + uart1_sleep_alt: uart1_sleep_alt { group1 { - psels = , - ; + psels = , + ; low-power-enable; }; }; }; + +dut: &uart1 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart1_default_alt>; + pinctrl-1 = <&uart1_sleep_alt>; + pinctrl-names = "default", "sleep"; +}; diff --git a/tests/subsys/modem/backends/uart/src/main.c b/tests/subsys/modem/backends/uart/src/main.c index 8a6c4c2813a7ab8..dffc203bb213aab 100644 --- a/tests/subsys/modem/backends/uart/src/main.c +++ b/tests/subsys/modem/backends/uart/src/main.c @@ -28,7 +28,7 @@ /*************************************************************************************************/ /* Mock pipe */ /*************************************************************************************************/ -static const struct device *uart = DEVICE_DT_GET(DT_ALIAS(test_uart)); +static const struct device *uart = DEVICE_DT_GET(DT_NODELABEL(dut)); static struct modem_backend_uart uart_backend; static struct modem_pipe *pipe; K_SEM_DEFINE(receive_ready_sem, 0, 1); diff --git a/tests/subsys/modem/backends/uart/testcase.yaml b/tests/subsys/modem/backends/uart/testcase.yaml index 626ca639f757baa..54d8a6b94703e5c 100644 --- a/tests/subsys/modem/backends/uart/testcase.yaml +++ b/tests/subsys/modem/backends/uart/testcase.yaml @@ -1,21 +1,19 @@ # Copyright (c) 2023 Trackunit Corporation # SPDX-License-Identifier: Apache-2.0 +common: + harness: ztest + harness_config: + fixture: gpio_loopback + platform_allow: + - b_u585i_iot02a + - nrf5340dk_nrf5340_cpuapp + tests: modem.backends.uart.async: - tags: modem_backend - harness: ztest - platform_allow: - - b_u585i_iot02a - - nrf5340dk_nrf5340_cpuapp extra_configs: - CONFIG_UART_ASYNC_API=y modem.backends.uart.isr: - tags: modem_backend - harness: ztest - platform_allow: - - b_u585i_iot02a - - nrf5340dk_nrf5340_cpuapp extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=y From 8146fe4f6603f11d3ab4022c6646b3b365a7af29 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 23 Nov 2023 14:22:35 +0100 Subject: [PATCH 1034/1049] dts: bindings: stm32 lptimer has no divider on the clock source freq Revert "dts: bindings: LPtimer of stm32 has a x2 factor on its clock" The stm32u5 lptim clock source has no prescaler to divide the the LPTIM input clock frequency : no property required. This reverts commit 572b286010b4219c6146dc8d9cde36d1cbc50c74. Signed-off-by: Francois Ramu --- dts/bindings/timer/st,stm32-lptim.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dts/bindings/timer/st,stm32-lptim.yaml b/dts/bindings/timer/st,stm32-lptim.yaml index a13deb1f7940902..90db9084800505b 100644 --- a/dts/bindings/timer/st,stm32-lptim.yaml +++ b/dts/bindings/timer/st,stm32-lptim.yaml @@ -39,11 +39,3 @@ properties: - 32 - 64 - 128 - - st,static-prescaler: - type: boolean - description: | - Clock x2 factor at the input of the LPTIM, - depending on the serie. - For example, stm32U5x have a x2-factor for LPTIM1,3,4. - To be adapted once the value is selectable. From f1af7f13eb938452a891591f1615ac047194ef91 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 23 Nov 2023 14:26:10 +0100 Subject: [PATCH 1035/1049] drivers: timer: stm32 lptimer revert static-prescaler Revert "drivers: timer: lptim timer clock on stm32u5 has a prescaler" This reverts commit c14670abea4412fbf1e54996807b6ebb67eb98b6. Signed-off-by: Francois Ramu --- drivers/timer/stm32_lptim_timer.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index aaf83c300570754..ffda551524de9d7 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -387,19 +387,6 @@ static int sys_clock_driver_init(void) return -EIO; } - if (IS_ENABLED(DT_PROP(DT_DRV_INST(0), st_static_prescaler))) { - /* - * LPTIM of the stm32, like stm32U5, which has a clock source x2. - * A full 16bit LPTIM counter is counting 4s at 2 * 1/32768 (with LSE) - * Time base = (4s * freq) - 1 - */ - lptim_clock_freq = lptim_clock_freq / 2; - } - /* - * Else, a full 16bit LPTIM counter is counting 2s at 1/32768 (with LSE) - * Time base = (2s * freq) - 1 - */ - /* Actual lptim clock freq when the clock source is reduced by the prescaler */ lptim_clock_freq = lptim_clock_freq / LPTIM_CLOCK_RATIO; From c3940cb4f7c6ab5b85b5bc8556faacc1e9908a2b Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 23 Nov 2023 14:34:18 +0100 Subject: [PATCH 1036/1049] Revert "dts: arm: stm32u5 family has a x2 factor on its LPTIM clock" This reverts commit 823b0e6016b99e49050f65e84515ef9ac76084f7. Signed-off-by: Francois Ramu --- dts/arm/st/u5/stm32u5.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 7363181e6631872..ae9dd9d9c8cd7ac 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -434,7 +434,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>; interrupts = <67 1>; interrupt-names = "wakeup"; - st,static-prescaler; status = "disabled"; }; @@ -446,7 +445,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000020>; interrupts = <68 0>; interrupt-names = "global"; - st,static-prescaler; status = "disabled"; }; @@ -458,7 +456,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00001000>; interrupts = <98 0>; interrupt-names = "global"; - st,static-prescaler; status = "disabled"; }; @@ -470,7 +467,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00002000>; interrupts = <110 0>; interrupt-names = "global"; - st,static-prescaler; status = "disabled"; }; From 9bb708eb7ddbde2c5579450e111a099f39ea5e45 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 15:27:09 +0100 Subject: [PATCH 1037/1049] init_priorities: Fix for native_simulator based targets Fix the init_prioties related cmake targets so they also work with native_simulator based build targets. Mostly this consists of pointing to the right file (final build result instead of intermediate elf library) and setting the dependency to that final build result. Note that for the native_simulator based targets the init priorities check can only be run on build if we are building the final image (not just a partial prelinked library), and we are not assembling several images together into one executable. Signed-off-by: Alberto Escolar Piedras --- CMakeLists.txt | 35 +++++++++++++++++++++++------------ Kconfig.zephyr | 4 +++- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 164d82fde0e8ad9..3b0af4e34a3f90a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1751,7 +1751,6 @@ if(CONFIG_BUILD_OUTPUT_EXE) post_build_byproducts ${KERNEL_EXE_NAME} ) - set(BYPRODUCT_KERNEL_EXE_NAME "${PROJECT_BINARY_DIR}/${KERNEL_EXE_NAME}" CACHE FILEPATH "Kernel exe file" FORCE) else() if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") set(MAKE "${CMAKE_MAKE_PROGRAM}" CACHE FILEPATH "cmake defined make") @@ -1768,6 +1767,7 @@ if(CONFIG_BUILD_OUTPUT_EXE) BYPRODUCTS ${KERNEL_EXE_NAME} ) endif() + set(BYPRODUCT_KERNEL_EXE_NAME "${PROJECT_BINARY_DIR}/${KERNEL_EXE_NAME}" CACHE FILEPATH "Kernel exe file" FORCE) endif() if(CONFIG_BUILD_OUTPUT_INFO_HEADER) @@ -1784,21 +1784,32 @@ if(CONFIG_BUILD_OUTPUT_INFO_HEADER) ) endif() -if(CONFIG_CHECK_INIT_PRIORITIES) - list(APPEND - post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py - --elf-file=${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} +if(NOT CMAKE_C_COMPILER_ID STREQUAL "ARMClang") + set(check_init_priorities_input + $,${BYPRODUCT_KERNEL_EXE_NAME},${BYPRODUCT_KERNEL_ELF_NAME}> + ) + set(check_init_priorities_command + ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py + --elf-file=${check_init_priorities_input} + ) + set(check_init_priorities_dependencies + ${logical_target_for_zephyr_elf} + $<$:native_runner_executable> + ) + + if(CONFIG_CHECK_INIT_PRIORITIES) + add_custom_target( + check_init_priorities + ALL + COMMAND ${check_init_priorities_command} + DEPENDS ${check_init_priorities_dependencies} ) -endif() + endif() -if(NOT CMAKE_C_COMPILER_ID STREQUAL "ARMClang") add_custom_target( initlevels - COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py - --elf-file=${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} - --initlevels - DEPENDS ${logical_target_for_zephyr_elf} + COMMAND ${check_init_priorities_command} --initlevels + DEPENDS ${check_init_priorities_dependencies} USES_TERMINAL ) endif() diff --git a/Kconfig.zephyr b/Kconfig.zephyr index c484898206b713b..e16941730487d5f 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -777,7 +777,9 @@ config BUILD_OUTPUT_STRIP_PATHS config CHECK_INIT_PRIORITIES bool "Build time initialization priorities check" default y - depends on !NATIVE_LIBRARY + # If we are building a native_simulator target, we can only check the init priorities + # if we are building the final output but we are not assembling several images together + depends on !(NATIVE_LIBRARY && (!BUILD_OUTPUT_EXE || NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS != "")) depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "armclang" help Check the build for initialization priority issues by comparing the From 9aafc832a2eb3a6e530a221f642512eed9cd9958 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 23 Nov 2023 13:31:06 +0100 Subject: [PATCH 1038/1049] tests/misc/check_init_priorities: Fix for native_sim Fix this test for the native_simulator, and add it as a default test target. Also be a bit clearer in stdout about the test having passed or not. Signed-off-by: Alberto Escolar Piedras --- .../misc/check_init_priorities/CMakeLists.txt | 6 ++- .../boards/native_posix.overlay | 33 +--------------- .../boards/native_sim.overlay | 38 +++++++++++++++++++ ...posix_64.overlay => native_sim_64.overlay} | 2 +- .../misc/check_init_priorities/testcase.yaml | 6 ++- .../validate_check_init_priorities_output.py | 2 + 6 files changed, 51 insertions(+), 36 deletions(-) create mode 100644 tests/misc/check_init_priorities/boards/native_sim.overlay rename tests/misc/check_init_priorities/boards/{native_posix_64.overlay => native_sim_64.overlay} (70%) diff --git a/tests/misc/check_init_priorities/CMakeLists.txt b/tests/misc/check_init_priorities/CMakeLists.txt index 8803b2fa651463a..9a615977d5d777a 100644 --- a/tests/misc/check_init_priorities/CMakeLists.txt +++ b/tests/misc/check_init_priorities/CMakeLists.txt @@ -8,10 +8,12 @@ set(output_file ${PROJECT_BINARY_DIR}/check_init_priorities_output.txt) add_custom_command( COMMENT "Running check_init_priorities.py" OUTPUT ${output_file} - DEPENDS ${BYPRODUCT_KERNEL_ELF_NAME} + DEPENDS + ${logical_target_for_zephyr_elf} + $<$:native_runner_executable> COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py + --elf-file=$,${BYPRODUCT_KERNEL_EXE_NAME},${BYPRODUCT_KERNEL_ELF_NAME}> --verbose - --elf-file=${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} --output ${output_file} --always-succeed COMMAND ${PYTHON_EXECUTABLE} ${APPLICATION_SOURCE_DIR}/validate_check_init_priorities_output.py diff --git a/tests/misc/check_init_priorities/boards/native_posix.overlay b/tests/misc/check_init_priorities/boards/native_posix.overlay index 0f32c8121a89402..1cf720283b3957b 100644 --- a/tests/misc/check_init_priorities/boards/native_posix.overlay +++ b/tests/misc/check_init_priorities/boards/native_posix.overlay @@ -4,35 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -/ { - test_gpio_0: gpio@ffff { - gpio-controller; - #gpio-cells = <0x2>; - compatible = "vnd,gpio-device"; - status = "okay"; - reg = <0xffff 0x1000>; - }; - - test_i2c: i2c@11112222 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "vnd,i2c"; - status = "okay"; - reg = <0x11112222 0x1000>; - clock-frequency = <100000>; - - test_dev_a: test-i2c-dev@10 { - compatible = "vnd,i2c-device"; - status = "okay"; - reg = <0x10>; - supply-gpios = <&test_gpio_0 1 0>; - }; - - test_dev_b: test-i2c-dev@11 { - compatible = "vnd,i2c-device"; - status = "okay"; - reg = <0x11>; - supply-gpios = <&test_gpio_0 2 0>; - }; - }; -}; +#include "native_sim.overlay" diff --git a/tests/misc/check_init_priorities/boards/native_sim.overlay b/tests/misc/check_init_priorities/boards/native_sim.overlay new file mode 100644 index 000000000000000..0f32c8121a89402 --- /dev/null +++ b/tests/misc/check_init_priorities/boards/native_sim.overlay @@ -0,0 +1,38 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test_gpio_0: gpio@ffff { + gpio-controller; + #gpio-cells = <0x2>; + compatible = "vnd,gpio-device"; + status = "okay"; + reg = <0xffff 0x1000>; + }; + + test_i2c: i2c@11112222 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,i2c"; + status = "okay"; + reg = <0x11112222 0x1000>; + clock-frequency = <100000>; + + test_dev_a: test-i2c-dev@10 { + compatible = "vnd,i2c-device"; + status = "okay"; + reg = <0x10>; + supply-gpios = <&test_gpio_0 1 0>; + }; + + test_dev_b: test-i2c-dev@11 { + compatible = "vnd,i2c-device"; + status = "okay"; + reg = <0x11>; + supply-gpios = <&test_gpio_0 2 0>; + }; + }; +}; diff --git a/tests/misc/check_init_priorities/boards/native_posix_64.overlay b/tests/misc/check_init_priorities/boards/native_sim_64.overlay similarity index 70% rename from tests/misc/check_init_priorities/boards/native_posix_64.overlay rename to tests/misc/check_init_priorities/boards/native_sim_64.overlay index 166e6f02e82d5b0..a906fce7488c3fc 100644 --- a/tests/misc/check_init_priorities/boards/native_posix_64.overlay +++ b/tests/misc/check_init_priorities/boards/native_sim_64.overlay @@ -3,4 +3,4 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include "native_posix.overlay" +#include "native_sim.overlay" diff --git a/tests/misc/check_init_priorities/testcase.yaml b/tests/misc/check_init_priorities/testcase.yaml index e136e4ae3899914..1484ae9c100b4aa 100644 --- a/tests/misc/check_init_priorities/testcase.yaml +++ b/tests/misc/check_init_priorities/testcase.yaml @@ -3,6 +3,10 @@ tests: init.check_init_priorities: build_only: true - platform_allow: native_posix native_posix_64 + platform_allow: + - native_sim + - native_sim_64 + - native_posix integration_platforms: + - native_sim - native_posix diff --git a/tests/misc/check_init_priorities/validate_check_init_priorities_output.py b/tests/misc/check_init_priorities/validate_check_init_priorities_output.py index 714976e1a09417e..f5d322164c6f665 100755 --- a/tests/misc/check_init_priorities/validate_check_init_priorities_output.py +++ b/tests/misc/check_init_priorities/validate_check_init_priorities_output.py @@ -34,6 +34,8 @@ print() print("got:") print("\n".join(sorted(output))) + print("TEST FAILED") sys.exit(1) +print("TEST PASSED") sys.exit(0) From 084b8e4f9725323c13fe512b01b15bcfec9b42a6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 24 Nov 2023 13:38:02 +0200 Subject: [PATCH 1039/1049] x86: Only enable EFI_CONSOLE if UART console is not enabled Most x86 build configurations enable the UART console. Since EFI console has also defaulted to enabled, this means that the EFI covers the early part of the boot until UART takes over. This is all fine, except that enabling EFI console has the effect of disabling PRINTK_SYNC. This in turn has the effect of causing garbled output over UART, which has led to several bug reports on x86 platforms (in particular on up_squared). Since EFI console should really only be used for early platform bringup and debugging purposes, it's not really ideal to unconditionally have it enabled by default. Instead, change the default enabling to be conditional to the UART console being disabled. Fixes #54861 Fixes #55071 Signed-off-by: Johan Hedberg --- arch/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index d7ccfca7ecdc56c..7f852742fb88a2a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -472,7 +472,7 @@ config X86_EFI_CONSOLE bool depends on X86_EFI && X86_64 && !X86_VERY_EARLY_CONSOLE select EFI_CONSOLE - default y + default y if !UART_CONSOLE help This enables the use of the UEFI console device as the Zephyr printk handler. It requires that no interferences From 8f78b7148ce5234aa877b2653ae99ddcab3a5c75 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 24 Nov 2023 12:45:11 +0100 Subject: [PATCH 1040/1049] samples/bluetooth: sysbuild: Add Kconfig setting for HCI IPC inclusion Introduce NET_CORE_IMAGE_HCI_IPC Kconfig setting to control inclusion of HCI IPC image when building through sysbuild. This allows users with custom netcore applications to avoid inclusion of the default HCI IPC image. Signed-off-by: Alberto Escolar Piedras --- samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild | 5 +++++ samples/bluetooth/broadcast_audio_source/sysbuild.cmake | 2 +- samples/bluetooth/unicast_audio_client/Kconfig.sysbuild | 5 +++++ samples/bluetooth/unicast_audio_client/sysbuild.cmake | 2 +- samples/bluetooth/unicast_audio_server/Kconfig.sysbuild | 5 +++++ samples/bluetooth/unicast_audio_server/sysbuild.cmake | 2 +- 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild b/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild index 37a6b66c7f4d873..f434010f81d27ce 100644 --- a/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild +++ b/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild @@ -8,3 +8,8 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake index c150913cc551373..ed30d7f31f3d7f6 100644 --- a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake +++ b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) diff --git a/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild b/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild index 37a6b66c7f4d873..f434010f81d27ce 100644 --- a/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild +++ b/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild @@ -8,3 +8,8 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/unicast_audio_client/sysbuild.cmake b/samples/bluetooth/unicast_audio_client/sysbuild.cmake index c150913cc551373..ed30d7f31f3d7f6 100644 --- a/samples/bluetooth/unicast_audio_client/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_client/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) diff --git a/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild b/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild index 37a6b66c7f4d873..f434010f81d27ce 100644 --- a/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild +++ b/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild @@ -8,3 +8,8 @@ config NET_CORE_BOARD default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/unicast_audio_server/sysbuild.cmake b/samples/bluetooth/unicast_audio_server/sysbuild.cmake index c150913cc551373..ed30d7f31f3d7f6 100644 --- a/samples/bluetooth/unicast_audio_server/sysbuild.cmake +++ b/samples/bluetooth/unicast_audio_server/sysbuild.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) # For builds in the nrf5340, we build the netcore image with the controller set(NET_APP hci_ipc) From 82d7535b1904253913a73a7245378207bcf6696c Mon Sep 17 00:00:00 2001 From: Kacper Dalach Date: Sat, 25 Nov 2023 11:32:04 +0100 Subject: [PATCH 1041/1049] dts: st: Add cpu node labels After porting from h5 to f7 i noticed that not all mcus have cpu node labels. Added cpu0 node labels to all stm32 dts. Signed-off-by: Kacper Dalach --- dts/arm/st/f0/stm32f0.dtsi | 2 +- dts/arm/st/f1/stm32f1.dtsi | 2 +- dts/arm/st/f2/stm32f2.dtsi | 2 +- dts/arm/st/f3/stm32f3.dtsi | 2 +- dts/arm/st/f7/stm32f7.dtsi | 2 +- dts/arm/st/g4/stm32g4.dtsi | 2 +- dts/arm/st/l1/stm32l1.dtsi | 2 +- dts/arm/st/mp1/stm32mp157.dtsi | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dts/arm/st/f0/stm32f0.dtsi b/dts/arm/st/f0/stm32f0.dtsi index e9e521cd47e70c3..3a7e5dac8ce328b 100644 --- a/dts/arm/st/f0/stm32f0.dtsi +++ b/dts/arm/st/f0/stm32f0.dtsi @@ -26,7 +26,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m0"; reg = <0>; diff --git a/dts/arm/st/f1/stm32f1.dtsi b/dts/arm/st/f1/stm32f1.dtsi index b70130db3089dc1..d3eb976b5663766 100644 --- a/dts/arm/st/f1/stm32f1.dtsi +++ b/dts/arm/st/f1/stm32f1.dtsi @@ -26,7 +26,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; reg = <0>; diff --git a/dts/arm/st/f2/stm32f2.dtsi b/dts/arm/st/f2/stm32f2.dtsi index 845cd6fb5a21790..7cef6f2428a50f1 100644 --- a/dts/arm/st/f2/stm32f2.dtsi +++ b/dts/arm/st/f2/stm32f2.dtsi @@ -27,7 +27,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; reg = <0>; diff --git a/dts/arm/st/f3/stm32f3.dtsi b/dts/arm/st/f3/stm32f3.dtsi index a426a84ea3ea1aa..5f5099a90d68c8b 100644 --- a/dts/arm/st/f3/stm32f3.dtsi +++ b/dts/arm/st/f3/stm32f3.dtsi @@ -25,7 +25,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index 2df24d0c8d2080f..6569d35c49f8b07 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -30,7 +30,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m7"; reg = <0>; diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index feec71388aa9ac0..4cc6c26fc029282 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -28,7 +28,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; diff --git a/dts/arm/st/l1/stm32l1.dtsi b/dts/arm/st/l1/stm32l1.dtsi index 0203f740c8310ce..2f08501a2c10962 100644 --- a/dts/arm/st/l1/stm32l1.dtsi +++ b/dts/arm/st/l1/stm32l1.dtsi @@ -26,7 +26,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; reg = <0>; diff --git a/dts/arm/st/mp1/stm32mp157.dtsi b/dts/arm/st/mp1/stm32mp157.dtsi index f70a96b6ead4575..1877301b9f25fbd 100644 --- a/dts/arm/st/mp1/stm32mp157.dtsi +++ b/dts/arm/st/mp1/stm32mp157.dtsi @@ -22,7 +22,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4"; reg = <0>; From db1c21bfd75f9915d2d829f3c38f70ff65ae07f8 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Sat, 25 Nov 2023 16:07:24 +0200 Subject: [PATCH 1042/1049] drivers: sensor: adxl367: Add missing breaks Fix missing breaks errors. Signed-off-by: Andrei Emeltchenko --- drivers/sensor/adxl367/adxl367.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/sensor/adxl367/adxl367.c b/drivers/sensor/adxl367/adxl367.c index f63b8f73a321077..1d5c31ad0210161 100644 --- a/drivers/sensor/adxl367/adxl367.c +++ b/drivers/sensor/adxl367/adxl367.c @@ -287,16 +287,22 @@ int adxl367_self_test(const struct device *dev) switch (cfg->odr) { case ADXL367_ODR_12P5HZ: st_delay_ms = 320; + break; case ADXL367_ODR_25HZ: st_delay_ms = 160; + break; case ADXL367_ODR_50HZ: st_delay_ms = 80; + break; case ADXL367_ODR_100HZ: st_delay_ms = 40; + break; case ADXL367_ODR_200HZ: st_delay_ms = 20; + break; case ADXL367_ODR_400HZ: st_delay_ms = 10; + break; default: return -EINVAL; } From 08a4829682b3df44c671fc0db5b575be53ab4886 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Sat, 25 Nov 2023 17:29:54 +0100 Subject: [PATCH 1043/1049] drivers: ethernet: esp32: fix Kconfig Add the missing dependency of the node status value and enable the driver by default when they are met. Signed-off-by: Bartosz Bilas --- drivers/ethernet/Kconfig.esp32 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ethernet/Kconfig.esp32 b/drivers/ethernet/Kconfig.esp32 index 8adb24cfb7716bb..35c07860f4ef336 100644 --- a/drivers/ethernet/Kconfig.esp32 +++ b/drivers/ethernet/Kconfig.esp32 @@ -5,7 +5,9 @@ menuconfig ETH_ESP32 bool "ESP32 Ethernet driver" + default y depends on SOC_SERIES_ESP32 + depends on DT_HAS_ESPRESSIF_ESP32_ETH_ENABLED select MDIO help Enable ESP32 Ethernet driver. From 0b76b4f0161481bbc0539278e7092ba20a0cfc51 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Sat, 25 Nov 2023 17:28:42 +0100 Subject: [PATCH 1044/1049] drivers: mdio: esp32: add dependency of node status MDIO driver should be available and enabled only when mdio node has status okay. Signed-off-by: Bartosz Bilas --- drivers/mdio/Kconfig.esp32 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mdio/Kconfig.esp32 b/drivers/mdio/Kconfig.esp32 index bdc8fb1221eee82..9c4d8f8bae55fec 100644 --- a/drivers/mdio/Kconfig.esp32 +++ b/drivers/mdio/Kconfig.esp32 @@ -3,7 +3,8 @@ config MDIO_ESP32 bool "ESP32 MDIO driver" - depends on SOC_SERIES_ESP32 default y + depends on SOC_SERIES_ESP32 + depends on DT_HAS_ESPRESSIF_ESP32_MDIO_ENABLED help Enable ESP32 MCU Family MDIO driver. From e3520c681386fbb2ba64a65c456a84b7f9ff07f8 Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Sun, 26 Nov 2023 22:53:41 +0200 Subject: [PATCH 1045/1049] dts: rp2040: Fix num-irq-priority-bits The number of IRQ priority bits was incorrectly set to 3 instead of 2, which is the correct number for Cortex-M0+. Signed-off-by: Yonatan Schachter --- dts/arm/rpi_pico/rp2040.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index fd83297fa5a2943..1e4211075f893a5 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -255,5 +255,5 @@ }; &nvic { - arm,num-irq-priority-bits = <3>; + arm,num-irq-priority-bits = <2>; }; From e49ae776cc2c3354b3bacc875edeb77c8a886c7b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 01:13:43 -0500 Subject: [PATCH 1046/1049] posix: pthread: implement pthread_getconcurrency() Zephyr must support all functionality of the XSI_THREADS_EXT subprofiling option group in order to claim it supports that subprofiling option group. The XSI_THREADS_EXT option group is critical to be able to run POSIX threads with statically allocated thread stacks, which has been a feature of the implementation since it was initially added. The pthread_getconcurrency() and pthread_setconcurrency() functions are the only remaining, unimplemented functions of the XSI_THREADS_EXT option group. Implement pthread_getconcurrency() and pthread_setconcurrency() via the more "posixly correct" interpretation of the specification. I.e. as the pthread_t:k_thread relationship is 1:1 and not M:N, Zephyr does not support multiplexing of user threads on top of schedulable kernel entities (i.e. "user threads" are directly mapped to native threads, just like linuxthreads or NPTL are in Linux). For that reason, to be "posixly correct", we should save the provided value via pthread_setconcurrency(), in the absense of errors, and also return that same value back via pthread_getconcurrency(), even though that serves zero purpose in Zephyr for the foreseeable future. Note: the specification also states "an implementation can always ignore any calls to pthread_setconcurrency() and return a constant for pthread_getconcurrency()." For that reason, the implementation may be revisited at a later time when when considering optimizations and when there is a better system in place for documenting deviations. Any such optimization should be explicitly controlled via Kconfig. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 2 ++ lib/posix/pthread.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index a7feef8bc7e3740..d61c46c5116d76c 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -477,6 +477,8 @@ int pthread_key_delete(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); void *pthread_getspecific(pthread_key_t key); int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); +int pthread_getconcurrency(void); +int pthread_setconcurrency(int new_level); /* Glibc / Oracle Extension Functions */ diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index d00d5564c73f310..3cc4413949b9bd4 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -51,7 +51,7 @@ static sys_dlist_t run_q = SYS_DLIST_STATIC_INIT(&run_q); static sys_dlist_t done_q = SYS_DLIST_STATIC_INIT(&done_q); static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT]; static struct k_spinlock pthread_pool_lock; - +static int pthread_concurrency; static K_MUTEX_DEFINE(pthread_once_lock); static const struct pthread_attr init_pthread_attrs = { @@ -466,6 +466,34 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou return 0; } +int pthread_getconcurrency(void) +{ + int ret; + + K_SPINLOCK(&pthread_pool_lock) { + ret = pthread_concurrency; + } + + return ret; +} + +int pthread_setconcurrency(int new_level) +{ + if (new_level < 0) { + return EINVAL; + } + + if (new_level > CONFIG_MP_MAX_NUM_CPUS) { + return EAGAIN; + } + + K_SPINLOCK(&pthread_pool_lock) { + pthread_concurrency = new_level; + } + + return 0; +} + /** * @brief Set cancelability State. * From c0f2038c262792a92f8d53ea5ed4dbc975bf942e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 01:16:58 -0500 Subject: [PATCH 1047/1049] tests: posix: headers: check for pthread_getconcurrency() Check for the existence of pthread_getconcurrency() and pthread_setconcurrency(). Signed-off-by: Christopher Friedt --- tests/posix/headers/src/pthread_h.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/posix/headers/src/pthread_h.c b/tests/posix/headers/src/pthread_h.c index 444a487f85c2e09..354a79dbfdf7266 100644 --- a/tests/posix/headers/src/pthread_h.c +++ b/tests/posix/headers/src/pthread_h.c @@ -104,7 +104,7 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_detach); zassert_not_null(pthread_equal); zassert_not_null(pthread_exit); - /* zassert_not_null(pthread_getconcurrency); */ /* not implemented */ + zassert_not_null(pthread_getconcurrency); /* zassert_not_null(pthread_getcpuclockid); */ /* not implemented */ zassert_not_null(pthread_getschedparam); zassert_not_null(pthread_getspecific); @@ -149,7 +149,7 @@ ZTEST(posix_headers, test_pthread_h) zassert_not_null(pthread_self); zassert_not_null(pthread_setcancelstate); zassert_not_null(pthread_setcanceltype); - /* zassert_not_null(pthread_setconcurrency); */ /* not implemented */ + zassert_not_null(pthread_setconcurrency); zassert_not_null(pthread_setschedparam); /* zassert_not_null(pthread_setschedprio); */ /* not implemented */ zassert_not_null(pthread_setspecific); From caf72569a995ca6eb09d31f1ab055e22da7ba83d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 24 Nov 2023 09:36:49 -0500 Subject: [PATCH 1048/1049] tests: posix: common: test pthread_getconcurrency() Add functional tests for pthread_getconcurrency() and pthread_setconcurrency(). Note: the specification explicitly says > an implementation can always ignore any calls to > pthread_setconcurrency() and return a constant for > pthread_getconcurrency() The implementation and tests could be up for revision at a future time when optimizations are considered and there is a better system in placeo for documenting POSIX options and deviations. Any such optimizations should be explicitly controlled via Kconfig. Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 6b7cb25616e33d4..0276afd60450f8c 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -882,3 +882,26 @@ ZTEST(posix_apis, test_pthread_join_detached) /* need to allow this thread to be clean-up by the recycler */ k_msleep(500); } + +ZTEST(posix_apis, test_pthread_set_get_concurrency) +{ + /* EINVAL if the value specified by new_level is negative */ + zassert_equal(EINVAL, pthread_setconcurrency(-42)); + + /* + * Note: the special value 0 indicates the implementation will + * maintain the concurrency level at its own discretion. + * + * pthread_getconcurrency() should return a value of 0 on init. + */ + zassert_equal(0, pthread_getconcurrency()); + + for (int i = 0; i <= CONFIG_MP_MAX_NUM_CPUS; ++i) { + zassert_ok(pthread_setconcurrency(i)); + /* verify parameter is saved */ + zassert_equal(i, pthread_getconcurrency()); + } + + /* EAGAIN if the a system resource to be exceeded */ + zassert_equal(EAGAIN, pthread_setconcurrency(CONFIG_MP_MAX_NUM_CPUS + 1)); +} From 5bfed9ef6b27b225ace044807fbad3a5d68b598c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 23 Nov 2023 01:17:53 -0500 Subject: [PATCH 1049/1049] doc: posix; mark pthread_getconcurrency() supported Mark pthread_getconcurrency() and pthread_setconcurrency() as supported in documentation. Signed-off-by: Christopher Friedt --- doc/services/portability/posix/option_groups/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 97d7ce226a83fff..65b96a4d201922e 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -99,8 +99,8 @@ This table lists service support status in Zephyr: pthread_attr_getstack(),yes pthread_attr_setstack(),yes - pthread_getconcurrency(), - pthread_setconcurrency() + pthread_getconcurrency(),yes + pthread_setconcurrency(),yes .. _posix_option_group_c_lang_support: