diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index e150c8c8ea3b1b..9d284c1cc78c62 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -57,6 +57,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_NEORV32 gpio_neorv32.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NPCX gpio_npcx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NPM1300 gpio_npm1300.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NPM6001 gpio_npm6001.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NRFE gpio_nrfe.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NRFX gpio_nrfx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NUMAKER gpio_numaker.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NUMICRO gpio_numicro.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e6aac9e04ceb5f..ddfd0d8a7abf87 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -144,6 +144,7 @@ source "drivers/gpio/Kconfig.neorv32" source "drivers/gpio/Kconfig.npcx" source "drivers/gpio/Kconfig.npm1300" source "drivers/gpio/Kconfig.npm6001" +source "drivers/gpio/Kconfig.nrfe" source "drivers/gpio/Kconfig.nrfx" source "drivers/gpio/Kconfig.numaker" source "drivers/gpio/Kconfig.numicro" diff --git a/drivers/gpio/Kconfig.nrfe b/drivers/gpio/Kconfig.nrfe new file mode 100644 index 00000000000000..2366f93850614a --- /dev/null +++ b/drivers/gpio/Kconfig.nrfe @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_NRFE + bool "nRF eGPIO driver" + default y + depends on DT_HAS_NORDIC_NRF_EGPIO_ENABLED + select NRFE_GPIO2 if HAS_HW_NRF_EGPIO2 + help + Enable eGPIO driver for nRF line of MCUs. diff --git a/drivers/gpio/gpio_nrfe.c b/drivers/gpio/gpio_nrfe.c new file mode 100644 index 00000000000000..2b07f2ce160acb --- /dev/null +++ b/drivers/gpio/gpio_nrfe.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_nrf_egpio + +#include +#include +#include + +#include +#include + +#include + +#include + +#ifdef CONFIG_MULTITHREADING +K_SEM_DEFINE(bound_sem, 0, 1); +#else +volatile uint32_t bound_sem = 1; +#endif + +static void ep_bound(void *priv) +{ +#ifdef CONFIG_MULTITHREADING + k_sem_give(&bound_sem); +#else + bound_sem = 0; +#endif +} + +static void ep_recv(const void *data, size_t len, void *priv) +{ +} + +static struct ipc_ept_cfg ep_cfg = { + .cb = { + .bound = ep_bound, + .received = ep_recv, + }, +}; + +struct ipc_ept ep; + +struct gpio_nrfe_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; +}; + +struct gpio_nrfe_cfg { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + uint8_t port_num; +}; + +static inline const struct gpio_nrfe_cfg *get_port_cfg(const struct device *port) +{ + return port->config; +} + +static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) +{ + nrfe_gpio_data_packet_t msg = {.opcode = NRFE_GPIO_PIN_CONFIGURE, + .pin = pin, + .port = get_port_cfg(port)->port_num, + .flags = flags}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + + return 0; +} + +static int gpio_nrfx_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + + const uint32_t set_mask = value & mask; + const uint32_t clear_mask = (~set_mask) & mask; + + nrfe_gpio_data_packet_t msg = { + .opcode = NRFE_GPIO_PIN_SET, .pin = set_mask, .port = get_port_cfg(port)->port_num}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + + msg.opcode = NRFE_GPIO_PIN_CLEAR; + msg.pin = clear_mask; + + ret = ipc_service_send(&ep, (void *)(&msg), sizeof(nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + + return ret; +} + +static int gpio_nrfx_port_set_bits_raw(const struct device *port, gpio_port_pins_t mask) +{ + nrfe_gpio_data_packet_t msg = { + .opcode = NRFE_GPIO_PIN_SET, .pin = mask, .port = get_port_cfg(port)->port_num}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + + return ret; +} + +static int gpio_nrfx_port_clear_bits_raw(const struct device *port, gpio_port_pins_t mask) +{ + nrfe_gpio_data_packet_t msg = { + .opcode = NRFE_GPIO_PIN_CLEAR, .pin = mask, .port = get_port_cfg(port)->port_num}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + + return ret; +} + +static int gpio_nrfx_port_toggle_bits(const struct device *port, gpio_port_pins_t mask) +{ + nrfe_gpio_data_packet_t msg = { + .opcode = NRFE_GPIO_PIN_TOGGLE, .pin = mask, .port = get_port_cfg(port)->port_num}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + + return ret; +} + +static int gpio_nrfe_init(const struct device *port) +{ + const struct device *ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); + + int ret = ipc_service_open_instance(ipc0_instance); + + if ((ret < 0) && (ret != -EALREADY)) { + return ret; + } + + ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); + if (ret < 0) { + return ret; + } + + /* Wait for endpoint to be bound */ +#ifdef CONFIG_MULTITHREADING + k_sem_take(&bound_sem, K_FOREVER); +#else + while (bound_sem != 0) { + }; +#endif + + return 0; +} + +static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = { + .pin_configure = gpio_nrfx_pin_configure, + .port_set_masked_raw = gpio_nrfx_port_set_masked_raw, + .port_set_bits_raw = gpio_nrfx_port_set_bits_raw, + .port_clear_bits_raw = gpio_nrfx_port_clear_bits_raw, + .port_toggle_bits = gpio_nrfx_port_toggle_bits, +}; + +/* needs to be done after MBOX driver init, which is at + * POST_KERNEL:KERNEL_INIT_PRIORITY_DEFAULT. + */ +#define CONFIG_EGPIO_INIT_PRIORITY CONFIG_KERNEL_INIT_PRIORITY_DEVICE + +/* Device instantiation is done with node labels because 'port_num' is + * the peripheral number by SoC numbering. We therefore cannot use + * DT_INST APIs here without wider changes. + */ +#define EGPIO_NRF_DEVICE(id) \ + static const struct gpio_nrfe_cfg gpio_nrfx_p##id##_cfg = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \ + }, \ + .port_num = DT_INST_PROP(id, port), \ + }; \ + \ + static struct gpio_nrfe_data gpio_nrfx_p##id##_data; \ + \ + DEVICE_DT_INST_DEFINE(id, gpio_nrfe_init, NULL, &gpio_nrfx_p##id##_data, \ + &gpio_nrfx_p##id##_cfg, POST_KERNEL, CONFIG_EGPIO_INIT_PRIORITY, \ + &gpio_nrfx_drv_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(EGPIO_NRF_DEVICE) diff --git a/dts/bindings/gpio/nordic,nrf-egpio.yaml b/dts/bindings/gpio/nordic,nrf-egpio.yaml new file mode 100644 index 00000000000000..b0ba04ae63c5ad --- /dev/null +++ b/dts/bindings/gpio/nordic,nrf-egpio.yaml @@ -0,0 +1,60 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: NRF eGPIO node + +compatible: "nordic,nrf-egpio" + +include: [base.yaml] + +properties: + ngpios: + type: int + default: 32 + description: | + This property indicates the number of in-use slots of available slots + for GPIOs. The typical example is something like this: the hardware + register is 32 bits wide, but only 18 of the bits have a physical + counterpart. The driver is generally written so that all 32 bits can + be used, but the IP block is reused in a lot of designs, some using + all 32 bits, some using 18 and some using 12. In this case, setting + "ngpios = <18>;" informs the driver that only the first 18 GPIOs, at + local offset 0 .. 17, are in use. For cases in which there might be + holes in the slot range, this value should be the max slot number+1. + gpio-reserved-ranges: + type: array + description: | + If not all the GPIOs at offsets 0...N-1 are usable for ngpios = , then + this property contains an additional set of tuples which specify which GPIOs + are unusable. This property indicates the start and size of the GPIOs + that can't be used. + + For example, setting "gpio-reserved-ranges = <3 2>, <10 1>;" means that + GPIO offsets 3, 4, and 10 are not usable, even if ngpios = <18>. + + "#gpio-cells": + type: int + required: true + description: Number of items to expect in a GPIO specifier + const: 2 + + sense-edge-mask: + type: int + description: | + Mask of pins that use the GPIO sense mechanism for edge detection. + + port: + type: int + required: true + description: | + The GPIO port number. GPIO port P0 has: + + port = <0>; + + And P1 has: + + port = <1>; + +gpio-cells: + - pin + - flags diff --git a/include/zephyr/ipc/icmsg.h b/include/zephyr/ipc/icmsg.h index 80e3412095acb4..9a04aa980a031d 100644 --- a/include/zephyr/ipc/icmsg.h +++ b/include/zephyr/ipc/icmsg.h @@ -51,8 +51,10 @@ struct icmsg_data_t { /* General */ const struct icmsg_config_t *cfg; +#ifdef CONFIG_MULTITHREADING struct k_work_delayable notify_work; struct k_work mbox_work; +#endif atomic_t state; }; diff --git a/modules/hal_nordic/CMakeLists.txt b/modules/hal_nordic/CMakeLists.txt index ac9b3f8ce4c6c9..6512fc44264a74 100644 --- a/modules/hal_nordic/CMakeLists.txt +++ b/modules/hal_nordic/CMakeLists.txt @@ -7,6 +7,7 @@ endif (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) add_subdirectory_ifdef(CONFIG_HAS_NRFX nrfx) add_subdirectory_ifdef(CONFIG_HAS_NRFS nrfs) +add_subdirectory_ifdef(CONFIG_HAS_NRFE nrfe) if(CONFIG_NRF_REGTOOL_GENERATE_UICR) list(APPEND nrf_regtool_components GENERATE:UICR) diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index 13ab8d9cd2f9c5..0d4148ccc8cf85 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -237,4 +237,5 @@ endmenu # HAS_NORDIC_DRIVERS rsource "nrfs/Kconfig" rsource "nrfx/Kconfig" +rsource "nrfe/Kconfig" rsource "Kconfig.nrf_regtool" diff --git a/modules/hal_nordic/nrfe/CMakeLists.txt b/modules/hal_nordic/nrfe/CMakeLists.txt new file mode 100644 index 00000000000000..259a0c8b9bf616 --- /dev/null +++ b/modules/hal_nordic/nrfe/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +# The nrfe source directory can be override through the definition of the NRFE_DIR symbol +# during the invocation of the build system +if(NOT DEFINED NRFE_DIR) + set(NRFE_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/nrfe CACHE PATH "nrfe Directory") +endif() + +set(INC_DIR ${NRFE_DIR}/include) + +zephyr_include_directories(${NRFE_DIR}) +zephyr_include_directories(${INC_DIR}) diff --git a/modules/hal_nordic/nrfe/Kconfig b/modules/hal_nordic/nrfe/Kconfig new file mode 100644 index 00000000000000..c35a821c4141b9 --- /dev/null +++ b/modules/hal_nordic/nrfe/Kconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2016 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config HAS_NRFE + bool + +menu "nrfe drivers" + depends on HAS_NRFE + +config NRFE_GPIO + bool + +config NRFE_GPIO2 + bool "eGPIO2 driver instance" + depends on $(dt_nodelabel_has_compat,egpio2,$(DT_COMPAT_NORDIC_NRF_EGPIO)) + select NRFE_GPIO + +endmenu # "nrfe drivers" diff --git a/samples/basic/blinky/CMakeLists.txt b/samples/basic/blinky/CMakeLists.txt index 4de34fbd81e7dc..84e0afb794b32a 100644 --- a/samples/basic/blinky/CMakeLists.txt +++ b/samples/basic/blinky/CMakeLists.txt @@ -2,6 +2,13 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +if(NOT CONFIG_BOARD_NRF54L15PDK_NRF54L15_CPUAPP) + message(FATAL_ERROR "${BOARD} is not supported for this sample") +endif() + project(blinky) target_sources(app PRIVATE src/main.c) + +include(ExternalProject) diff --git a/samples/basic/blinky/Kconfig.sysbuild b/samples/basic/blinky/Kconfig.sysbuild new file mode 100644 index 00000000000000..70a2f7380e80b2 --- /dev/null +++ b/samples/basic/blinky/Kconfig.sysbuild @@ -0,0 +1,9 @@ +# Copyright 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config REMOTE_BOARD +string + default "nrf54l15pdk/nrf54l15/cpuflpr" if $(BOARD) = "nrf54l15pdk" diff --git a/samples/basic/blinky/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/samples/basic/blinky/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000000..f8a0ce62b769a0 --- /dev/null +++ b/samples/basic/blinky/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + + sram_rx: memory@20018000 { + reg = <0x20018000 0x0800>; + }; + + sram_tx: memory@20020000 { + reg = <0x20020000 0x0800>; + }; + }; + }; + + ipc { + ipc0: ipc0 { + compatible = "zephyr,ipc-icmsg"; + tx-region = <&sram_tx>; + rx-region = <&sram_rx>; + mboxes = <&cpuapp_vevif_rx 15>, <&cpuapp_vevif_tx 16>; + mbox-names = "rx", "tx"; + status = "okay"; + }; + }; + + leds { + compatible = "gpio-leds"; + led4: led_4 { + gpios = <&egpio2 7 GPIO_ACTIVE_HIGH>; + label = "Test LED 4"; + }; + }; + + aliases { + led4 = &led4; + }; + + egpio2: egpio2 { + compatible = "nordic,nrf-egpio"; + gpio-reserved-ranges = <0 6>, <8 4>; + #gpio-cells = <2>; + ngpios = <11>; + status = "okay"; + port = <2>; + }; +}; + +&cpuapp_vevif_rx { + status = "okay"; +}; + +&cpuapp_vevif_tx { + status = "okay"; +}; + +&gpio0 { + status = "disabled"; +}; + +&gpio1 { + status = "disabled"; +}; + +&gpio2 { + status = "disabled"; +}; + +&gpiote20 { + status = "disabled"; +}; + +&gpiote30 { + status = "disabled"; +}; diff --git a/samples/basic/blinky/prj.conf b/samples/basic/blinky/prj.conf index 91c3c15b37d1ee..676941b920efe1 100644 --- a/samples/basic/blinky/prj.conf +++ b/samples/basic/blinky/prj.conf @@ -1 +1,5 @@ CONFIG_GPIO=y + +CONFIG_IPC_SERVICE=y +CONFIG_IPC_SERVICE_BACKEND_ICMSG=y +CONFIG_MBOX=y diff --git a/samples/basic/blinky/remote/CMakeLists.txt b/samples/basic/blinky/remote/CMakeLists.txt new file mode 100644 index 00000000000000..ec6affa1e1a00d --- /dev/null +++ b/samples/basic/blinky/remote/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ipc_service_remote) + +target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../common) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/basic/blinky/remote/boards/nrf54l15pdk_nrf54l15_cpuflpr.conf b/samples/basic/blinky/remote/boards/nrf54l15pdk_nrf54l15_cpuflpr.conf new file mode 100644 index 00000000000000..6df52a25559ddb --- /dev/null +++ b/samples/basic/blinky/remote/boards/nrf54l15pdk_nrf54l15_cpuflpr.conf @@ -0,0 +1,46 @@ +# Single-threaded, no timer support in the kernel +CONFIG_MULTITHREADING=n +CONFIG_KERNEL_MEM_POOL=n +CONFIG_LOG=n + +# # Drivers and peripherals +CONFIG_I2C=n +CONFIG_WATCHDOG=n +CONFIG_GPIO=n +CONFIG_PINCTRL=n +CONFIG_SPI=n +CONFIG_SERIAL=n +CONFIG_FLASH=n + +# # Power management +CONFIG_PM=n + +# # Interrupts +CONFIG_DYNAMIC_INTERRUPTS=n +CONFIG_IRQ_OFFLOAD=n + +# # Memory protection +CONFIG_THREAD_STACK_INFO=n +CONFIG_THREAD_CUSTOM_DATA=n +CONFIG_FPU=n + +# # Boot +# CONFIG_BOOT_BANNER=n +# CONFIG_BOOT_DELAY=0 + +# # Console +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n +CONFIG_STDOUT_CONSOLE=n +CONFIG_PRINTK=n +CONFIG_EARLY_CONSOLE=n + +# # Build +CONFIG_SIZE_OPTIMIZATIONS=y + +# No timer support in the kernel +# CONFIG_SYS_CLOCK_EXISTS=n + +CONFIG_OUTPUT_DISASSEMBLY=y +# CONFIG_GEN_SW_ISR_TABLE=n +CONFIG_COMMON_LIBC_MALLOC=n diff --git a/samples/basic/blinky/remote/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay b/samples/basic/blinky/remote/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay new file mode 100644 index 00000000000000..f87d164072a7f7 --- /dev/null +++ b/samples/basic/blinky/remote/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + + sram_tx: memory@20018000 { + reg = <0x20018000 0x0800>; + }; + + sram_rx: memory@20020000 { + reg = <0x20020000 0x0800>; + }; + }; + }; + + ipc { + ipc0: ipc0 { + compatible = "zephyr,ipc-icmsg"; + tx-region = <&sram_tx>; + rx-region = <&sram_rx>; + mboxes = <&cpuflpr_vevif_rx 16>, <&cpuflpr_vevif_tx 15>; + mbox-names = "rx", "tx"; + status = "okay"; + }; + }; +}; + +&cpuflpr_vevif_rx { + status = "okay"; +}; + +&cpuflpr_vevif_tx { + status = "okay"; +}; + +&gpio0 { + status = "disabled"; +}; + +&gpio1 { + status = "disabled"; +}; + +&gpio2 { + status = "disabled"; +}; + +&gpiote20 { + status = "disabled"; +}; + +&gpiote30 { + status = "disabled"; +}; diff --git a/samples/basic/blinky/remote/prj.conf b/samples/basic/blinky/remote/prj.conf new file mode 100644 index 00000000000000..530e6ab8660420 --- /dev/null +++ b/samples/basic/blinky/remote/prj.conf @@ -0,0 +1,3 @@ +CONFIG_IPC_SERVICE=y +CONFIG_IPC_SERVICE_BACKEND_ICMSG=y +CONFIG_MBOX=y diff --git a/samples/basic/blinky/remote/src/main.c b/samples/basic/blinky/remote/src/main.c new file mode 100644 index 00000000000000..f92424dc59633a --- /dev/null +++ b/samples/basic/blinky/remote/src/main.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef CONFIG_MULTITHREADING +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct ipc_ept ep; + +#ifdef CONFIG_MULTITHREADING +K_SEM_DEFINE(bound_sem, 0, 1); +#else +volatile uint32_t bound_sem = 1; +#endif + +static void ep_bound(void *priv) +{ +#ifdef CONFIG_MULTITHREADING + k_sem_give(&bound_sem); +#else + bound_sem = 0; +#endif + printf("Ep bounded\n"); +} + +static nrf_gpio_pin_pull_t get_pull(gpio_flags_t flags) +{ + if (flags & GPIO_PULL_UP) { + return NRF_GPIO_PIN_PULLUP; + } else if (flags & GPIO_PULL_DOWN) { + return NRF_GPIO_PIN_PULLDOWN; + } + + return NRF_GPIO_PIN_NOPULL; +} + +static int gpio_nrfe_pin_configure(uint8_t port, uint16_t pin, uint32_t flags) +{ + if (port != 2) { + return -EINVAL; + } + + uint32_t abs_pin = NRF_GPIO_PIN_MAP(port, pin); + nrf_gpio_pin_pull_t pull = get_pull(flags); + nrf_gpio_pin_drive_t drive; + + switch (flags & (NRF_GPIO_DRIVE_MSK | GPIO_OPEN_DRAIN)) { + case NRF_GPIO_DRIVE_S0S1: + drive = NRF_GPIO_PIN_S0S1; + break; + case NRF_GPIO_DRIVE_S0H1: + drive = NRF_GPIO_PIN_S0H1; + break; + case NRF_GPIO_DRIVE_H0S1: + drive = NRF_GPIO_PIN_H0S1; + break; + case NRF_GPIO_DRIVE_H0H1: + drive = NRF_GPIO_PIN_H0H1; + break; + case NRF_GPIO_DRIVE_S0 | GPIO_OPEN_DRAIN: + drive = NRF_GPIO_PIN_S0D1; + break; + case NRF_GPIO_DRIVE_H0 | GPIO_OPEN_DRAIN: + drive = NRF_GPIO_PIN_H0D1; + break; + case NRF_GPIO_DRIVE_S1 | GPIO_OPEN_SOURCE: + drive = NRF_GPIO_PIN_D0S1; + break; + case NRF_GPIO_DRIVE_H1 | GPIO_OPEN_SOURCE: + drive = NRF_GPIO_PIN_D0H1; + break; + default: + return -EINVAL; + } + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + uint16_t outs = nrf_vpr_csr_vio_out_get(); + + nrf_vpr_csr_vio_out_set(outs | (BIT(pin))); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + uint16_t outs = nrf_vpr_csr_vio_out_get(); + + nrf_vpr_csr_vio_out_set(outs & ~(BIT(pin))); + } + + nrf_gpio_pin_dir_t dir = + (flags & GPIO_OUTPUT) ? NRF_GPIO_PIN_DIR_OUTPUT : NRF_GPIO_PIN_DIR_INPUT; + nrf_gpio_pin_input_t input = + (flags & GPIO_INPUT) ? NRF_GPIO_PIN_INPUT_CONNECT : NRF_GPIO_PIN_INPUT_DISCONNECT; + + /* Reconfigure the GPIO pin with the specified pull-up/pull-down configuration and drive + * strength. + */ + nrfy_gpio_reconfigure(abs_pin, &dir, &input, &pull, &drive, NULL); + + if (dir == NRF_GPIO_PIN_DIR_OUTPUT) { + nrf_vpr_csr_vio_dir_set(nrf_vpr_csr_vio_dir_get() | (BIT(pin))); + } + + /* Take control of the pin */ + nrfy_gpio_pin_control_select(abs_pin, NRF_GPIO_PIN_SEL_VPR); + + return 0; +} + +static void gpio_nrfe_port_set_bits_raw(uint16_t set_mask) +{ + uint16_t outs = nrf_vpr_csr_vio_out_get(); + + nrf_vpr_csr_vio_out_set(outs | set_mask); +} + +static void gpio_nrfe_port_clear_bits_raw(uint16_t clear_mask) +{ + uint16_t outs = nrf_vpr_csr_vio_out_get(); + + nrf_vpr_csr_vio_out_set(outs & ~clear_mask); +} + +static void gpio_nrfe_port_toggle_bits(uint16_t toggle_mask) +{ + nrf_vpr_csr_vio_out_toggle_set(toggle_mask); +} + +static void ep_recv(const void *data, size_t len, void *priv) +{ + nrfe_gpio_data_packet_t *packet = (nrfe_gpio_data_packet_t *)data; + if (packet->port != 2) { + printf("Invalid port. Only port 2 is supported\n"); + return; + } + + switch (packet->opcode) { + case NRFE_GPIO_PIN_CONFIGURE: { + printf("Configuring GPIO%d pin: %d\n", packet->port, packet->pin); + gpio_nrfe_pin_configure(packet->port, packet->pin, packet->flags); + break; + } + case NRFE_GPIO_PIN_CLEAR: { + printf("Clearing GPIO%d, pin 0x%04x\n", packet->port, packet->pin); + gpio_nrfe_port_clear_bits_raw(packet->pin); + break; + } + case NRFE_GPIO_PIN_SET: { + printf("Setting GPIO%d, pin 0x%04x\n", packet->port, packet->pin); + gpio_nrfe_port_set_bits_raw(packet->pin); + break; + } + case NRFE_GPIO_PIN_TOGGLE: { + printf("Toggling GPIO%d, pin 0x%04x\n", packet->port, packet->pin); + gpio_nrfe_port_toggle_bits(packet->pin); + break; + } + default: { + printf("Unknown opcode %d\n", packet->opcode); + break; + } + } +} + +static struct ipc_ept_cfg ep_cfg = { + .cb = { + .bound = ep_bound, + .received = ep_recv, + }, +}; + +int main(void) +{ + int ret; + const struct device *ipc0_instance; + + ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); + + ret = ipc_service_open_instance(ipc0_instance); + if ((ret < 0) && (ret != -EALREADY)) { + printf("ipc_service_open_instance() failure\n"); + return ret; + } + + ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); + if (ret < 0) { + printf("ipc_service_register_endpoint() failure\n"); + return ret; + } + + /* Wait for endpoint to be bound */ +#ifdef CONFIG_MULTITHREADING + k_sem_take(&bound_sem, K_FOREVER); +#else + while (bound_sem != 0) { + }; +#endif + + if (!nrf_vpr_csr_rtperiph_enable_check()) { + nrf_vpr_csr_rtperiph_enable_set(true); + } + + while (true) { + }; + + return 0; +} diff --git a/samples/basic/blinky/sample.yaml b/samples/basic/blinky/sample.yaml index de711910dad24d..661b71d24bf54a 100644 --- a/samples/basic/blinky/sample.yaml +++ b/samples/basic/blinky/sample.yaml @@ -10,3 +10,31 @@ tests: harness: led integration_platforms: - frdm_k64f + + sample.basic.blinky.egpio: + platform_allow: nrf54l15pdk/nrf54l15/cpuapp + integration_platforms: + - nrf54l15pdk/nrf54l15/cpuapp + tags: + - LED + - gpio + - ipc + filter: dt_enabled_alias_with_parent_compat("led4", "gpio-leds") + depends_on: gpio + harness: + - console + - led + harness_config: + type: multi_line + ordered: false + regex: + - "host: IPC-service HOST demo started" + - "host: Ep bounded" + - "host: Perform sends for" + - "host: Sent" + - "host: Received" + - "host: IPC-service HOST demo ended" + extra_args: + blinky_SNIPPET=nordic-flpr + remote_CONFIG_MULTITHREADING=n + sysbuild: true diff --git a/samples/basic/blinky/src/main.c b/samples/basic/blinky/src/main.c index 4cab4969d94b5f..671cc2c9aba99b 100644 --- a/samples/basic/blinky/src/main.c +++ b/samples/basic/blinky/src/main.c @@ -9,10 +9,10 @@ #include /* 1000 msec = 1 sec */ -#define SLEEP_TIME_MS 1000 +#define SLEEP_TIME_MS 1000 /* The devicetree node identifier for the "led0" alias. */ -#define LED0_NODE DT_ALIAS(led0) +#define LED0_NODE DT_ALIAS(led4) /* * A build error on this line means your board is unsupported. @@ -42,7 +42,11 @@ int main(void) led_state = !led_state; printf("LED state: %s\n", led_state ? "ON" : "OFF"); +#ifdef CONFIG_MULTITHREADING k_msleep(SLEEP_TIME_MS); +#else + k_busy_wait(SLEEP_TIME_MS * 1000); +#endif } return 0; } diff --git a/samples/basic/blinky/sysbuild.cmake b/samples/basic/blinky/sysbuild.cmake new file mode 100644 index 00000000000000..62c9e931d60f11 --- /dev/null +++ b/samples/basic/blinky/sysbuild.cmake @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if ("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") + message(FATAL_ERROR + "Target ${BOARD} not supported for this sample. " + "There is no remote board selected in Kconfig.sysbuild") +endif() + +ExternalZephyrProject_Add( + APPLICATION remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_REMOTE_BOARD} +) diff --git a/samples/drivers/mbox/remote/src/main.c b/samples/drivers/mbox/remote/src/main.c index 9fe6c1a79d5663..34d4789ced1747 100644 --- a/samples/drivers/mbox/remote/src/main.c +++ b/samples/drivers/mbox/remote/src/main.c @@ -24,7 +24,13 @@ int main(void) { int ret; - printk("Hello from REMOTE\n"); + printk("Hello from REMOTE - %s\n", +#ifdef CONFIG_MULTITHREADING + "MULTITHREADING" +#else + "SINGLETHREAD" +#endif + ); #ifdef CONFIG_RX_ENABLED const struct mbox_dt_spec rx_channel = MBOX_DT_SPEC_GET(DT_PATH(mbox_consumer), rx); @@ -46,6 +52,12 @@ int main(void) const struct mbox_dt_spec tx_channel = MBOX_DT_SPEC_GET(DT_PATH(mbox_consumer), tx); while (1) { +#if defined(CONFIG_MULTITHREADING) + k_sleep(K_MSEC(3000)); +#else + k_busy_wait(3000000); +#endif + printk("Ping (on channel %d)\n", tx_channel.channel_id); ret = mbox_send_dt(&tx_channel, NULL); @@ -53,10 +65,7 @@ int main(void) printk("Could not send (%d)\n", ret); return 0; } - - k_sleep(K_MSEC(3000)); } #endif /* CONFIG_TX_ENABLED */ - return 0; } diff --git a/samples/drivers/mbox/sample.yaml b/samples/drivers/mbox/sample.yaml index 8308e5907d8d38..95cbc6553d69dc 100644 --- a/samples/drivers/mbox/sample.yaml +++ b/samples/drivers/mbox/sample.yaml @@ -84,3 +84,21 @@ tests: regex: - "Ping \\(on channel 16\\)" - "Pong \\(on channel 15\\)" + + sample.drivers.mbox.nrf54l15_no_multithreading: + platform_allow: + - nrf54l15pdk/nrf54l15/cpuapp + integration_platforms: + - nrf54l15pdk/nrf54l15/cpuapp + extra_args: + mbox_SNIPPET=nordic-flpr + mbox_CONFIG_MULTITHREADING=n + remote_CONFIG_MULTITHREADING=n + sysbuild: true + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "Ping \\(on channel 16\\)" + - "Pong \\(on channel 15\\)" diff --git a/samples/drivers/mbox/src/main.c b/samples/drivers/mbox/src/main.c index 221d7bd474f104..b1b33358f2ac37 100644 --- a/samples/drivers/mbox/src/main.c +++ b/samples/drivers/mbox/src/main.c @@ -20,7 +20,13 @@ int main(void) { int ret; - printk("Hello from APP\n"); + printk("Hello from APP - %s\n", +#ifdef CONFIG_MULTITHREADING + "MULTITHREADING" +#else + "SINGLETHREAD" +#endif + ); #ifdef CONFIG_RX_ENABLED const struct mbox_dt_spec rx_channel = MBOX_DT_SPEC_GET(DT_PATH(mbox_consumer), rx); @@ -42,7 +48,11 @@ int main(void) const struct mbox_dt_spec tx_channel = MBOX_DT_SPEC_GET(DT_PATH(mbox_consumer), tx); while (1) { +#if defined(CONFIG_MULTITHREADING) k_sleep(K_MSEC(2000)); +#else + k_busy_wait(2000000); +#endif printk("Ping (on channel %d)\n", tx_channel.channel_id); diff --git a/samples/subsys/ipc/ipc_service/icmsg/remote/src/main.c b/samples/subsys/ipc/ipc_service/icmsg/remote/src/main.c index 5cabd03ac7705a..e4b51369cdc19f 100644 --- a/samples/subsys/ipc/ipc_service/icmsg/remote/src/main.c +++ b/samples/subsys/ipc/ipc_service/icmsg/remote/src/main.c @@ -14,26 +14,44 @@ #include LOG_MODULE_REGISTER(remote, LOG_LEVEL_INF); - +#if defined(CONFIG_MULTITHREADING) K_SEM_DEFINE(bound_sem, 0, 1); +#else +volatile uint32_t bound_sem = 1; +volatile uint32_t recv_sem = 1; +#endif + +static unsigned char expected_message = 'a'; +static size_t expected_len = PACKET_SIZE_START; +static size_t received; static void ep_bound(void *priv) { + received = 0; +#if defined(CONFIG_MULTITHREADING) k_sem_give(&bound_sem); +#else + bound_sem = 0; +#endif LOG_INF("Ep bounded"); } static void ep_recv(const void *data, size_t len, void *priv) { +#if defined(CONFIG_ASSERT) struct data_packet *packet = (struct data_packet *)data; - static unsigned char expected_message = 'a'; - static size_t expected_len = PACKET_SIZE_START; __ASSERT(packet->data[0] == expected_message, "Unexpected message. Expected %c, got %c", expected_message, packet->data[0]); __ASSERT(len == expected_len, "Unexpected length. Expected %zu, got %zu", expected_len, len); +#endif + +#ifndef CONFIG_MULTITHREADING + recv_sem = 0; +#endif + received += len; expected_message++; expected_len++; @@ -61,11 +79,17 @@ static int send_for_time(struct ipc_ept *ep, const int64_t sending_time_ms) ret = ipc_service_send(ep, &msg, mlen); if (ret == -ENOMEM) { /* No space in the buffer. Retry. */ + ret = 0; continue; } else if (ret < 0) { LOG_ERR("Failed to send (%c) failed with ret %d", msg.data[0], ret); break; } +#if !defined(CONFIG_MULTITHREADING) + else { + recv_sem = 1; + } +#endif msg.data[0]++; if (msg.data[0] > 'Z') { @@ -79,7 +103,12 @@ static int send_for_time(struct ipc_ept *ep, const int64_t sending_time_ms) mlen = PACKET_SIZE_START; } +#if defined(CONFIG_MULTITHREADING) k_usleep(1); +#else + while ((recv_sem != 0) && ((k_uptime_get() - start) < sending_time_ms)) { + }; +#endif } LOG_INF("Sent %zu [Bytes] over %lld [ms]", bytes_sent, sending_time_ms); @@ -111,12 +140,17 @@ int main(void) } ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); - if (ret != 0) { + if (ret < 0) { LOG_ERR("ipc_service_register_endpoint() failure"); return ret; } +#if defined(CONFIG_MULTITHREADING) k_sem_take(&bound_sem, K_FOREVER); +#else + while (bound_sem != 0) { + }; +#endif ret = send_for_time(&ep, SENDING_TIME_MS); if (ret < 0) { @@ -124,6 +158,7 @@ int main(void) return ret; } + LOG_INF("Received %zu [Bytes] in total", received); LOG_INF("IPC-service REMOTE demo ended"); return 0; diff --git a/samples/subsys/ipc/ipc_service/icmsg/sample.yaml b/samples/subsys/ipc/ipc_service/icmsg/sample.yaml index 298c41f56dbb23..3e57dfa7c31539 100644 --- a/samples/subsys/ipc/ipc_service/icmsg/sample.yaml +++ b/samples/subsys/ipc/ipc_service/icmsg/sample.yaml @@ -18,6 +18,7 @@ tests: - "host: Sent" - "host: Received" - "host: IPC-service HOST demo ended" + sample.ipc.icmsg.nrf54l15: platform_allow: nrf54l15pdk/nrf54l15/cpuapp integration_platforms: @@ -26,4 +27,38 @@ tests: extra_args: icmsg_SNIPPET=nordic-flpr sysbuild: true - harness: remote + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "host: IPC-service HOST demo started" + - "host: Ep bounded" + - "host: Perform sends for" + - "host: Sent" + - "host: Received" + - "host: IPC-service HOST demo ended" + + sample.ipc.icmsg.nrf54l15_no_multithreading: + platform_allow: nrf54l15pdk/nrf54l15/cpuapp + integration_platforms: + - nrf54l15pdk/nrf54l15/cpuapp + tags: ipc + extra_args: + icmsg_SNIPPET=nordic-flpr + icmsg_CONFIG_MULTITHREADING=n + icmsg_CONFIG_LOG_MODE_MINIMAL=y + remote_CONFIG_MULTITHREADING=n + remote_CONFIG_LOG_MODE_MINIMAL=y + sysbuild: true + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "host: IPC-service HOST demo started" + - "host: Ep bounded" + - "host: Perform sends for" + - "host: Sent" + - "host: Received" + - "host: IPC-service HOST demo ended" diff --git a/samples/subsys/ipc/ipc_service/icmsg/src/main.c b/samples/subsys/ipc/ipc_service/icmsg/src/main.c index 0b492ddd1c02d7..d8d98fe8ae21e6 100644 --- a/samples/subsys/ipc/ipc_service/icmsg/src/main.c +++ b/samples/subsys/ipc/ipc_service/icmsg/src/main.c @@ -18,29 +18,42 @@ #include LOG_MODULE_REGISTER(host, LOG_LEVEL_INF); - +#if defined(CONFIG_MULTITHREADING) K_SEM_DEFINE(bound_sem, 0, 1); +#else +volatile uint32_t bound_sem = 1; +volatile uint32_t recv_sem = 1; +#endif + static unsigned char expected_message = 'A'; static size_t expected_len = PACKET_SIZE_START; - static size_t received; static void ep_bound(void *priv) { received = 0; - +#if defined(CONFIG_MULTITHREADING) k_sem_give(&bound_sem); +#else + bound_sem = 0; +#endif LOG_INF("Ep bounded"); } static void ep_recv(const void *data, size_t len, void *priv) { +#if defined(CONFIG_ASSERT) struct data_packet *packet = (struct data_packet *)data; __ASSERT(packet->data[0] == expected_message, "Unexpected message. Expected %c, got %c", expected_message, packet->data[0]); __ASSERT(len == expected_len, "Unexpected length. Expected %zu, got %zu", expected_len, len); +#endif + +#ifndef CONFIG_MULTITHREADING + recv_sem = 0; +#endif received += len; expected_message++; @@ -76,6 +89,11 @@ static int send_for_time(struct ipc_ept *ep, const int64_t sending_time_ms) LOG_ERR("Failed to send (%c) failed with ret %d", msg.data[0], ret); break; } +#if !defined(CONFIG_MULTITHREADING) + else { + recv_sem = 1; + } +#endif msg.data[0]++; if (msg.data[0] > 'z') { @@ -89,7 +107,12 @@ static int send_for_time(struct ipc_ept *ep, const int64_t sending_time_ms) mlen = PACKET_SIZE_START; } +#if defined(CONFIG_MULTITHREADING) k_usleep(1); +#else + while ((recv_sem != 0) && ((k_uptime_get() - start) < sending_time_ms)) { + }; +#endif } LOG_INF("Sent %zu [Bytes] over %lld [ms]", bytes_sent, sending_time_ms); @@ -126,7 +149,12 @@ int main(void) return ret; } +#if defined(CONFIG_MULTITHREADING) k_sem_take(&bound_sem, K_FOREVER); +#else + while (bound_sem != 0) { + }; +#endif ret = send_for_time(&ep, SENDING_TIME_MS); if (ret < 0) { @@ -135,7 +163,11 @@ int main(void) } LOG_INF("Wait 500ms. Let remote core finish its sends"); +#if defined(CONFIG_MULTITHREADING) k_msleep(500); +#else + k_busy_wait(500000); +#endif LOG_INF("Received %zu [Bytes] in total", received); diff --git a/soc/nordic/common/Kconfig.peripherals b/soc/nordic/common/Kconfig.peripherals index a6d730804b824d..99fb74a125eb75 100644 --- a/soc/nordic/common/Kconfig.peripherals +++ b/soc/nordic/common/Kconfig.peripherals @@ -93,6 +93,9 @@ config HAS_HW_NRF_GPIOTE130 config HAS_HW_NRF_GPIOTE131 def_bool $(dt_nodelabel_enabled_with_compat,gpiote131,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) +config HAS_HW_NRF_EGPIO2 + def_bool $(dt_nodelabel_enabled_with_compat,egpio2,$(DT_COMPAT_NORDIC_NRF_EGPIO)) + config HAS_HW_NRF_GRTC def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_GRTC)) diff --git a/soc/nordic/common/vpr/Kconfig b/soc/nordic/common/vpr/Kconfig index c2abfbb18b1f03..d3a8b7f5261433 100644 --- a/soc/nordic/common/vpr/Kconfig +++ b/soc/nordic/common/vpr/Kconfig @@ -13,6 +13,7 @@ config RISCV_CORE_NORDIC_VPR select RISCV_ISA_EXT_M select RISCV_ISA_EXT_C select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI select RISCV_SOC_HAS_ISR_STACKING select RISCV_HAS_CLIC select RISCV_SOC_CONTEXT_SAVE diff --git a/soc/nordic/nrf54l/Kconfig b/soc/nordic/nrf54l/Kconfig index 18e315078e9daa..3a07ca007c8714 100644 --- a/soc/nordic/nrf54l/Kconfig +++ b/soc/nordic/nrf54l/Kconfig @@ -19,6 +19,7 @@ config SOC_NRF54L15_ENGA_CPUAPP select CPU_HAS_FPU select HAS_HW_NRF_RADIO_IEEE802154 select HAS_POWEROFF + select HAS_NRFE config SOC_NRF54L15_ENGA_CPUFLPR depends on RISCV_CORE_NORDIC_VPR diff --git a/subsys/ipc/ipc_service/lib/Kconfig.icmsg b/subsys/ipc/ipc_service/lib/Kconfig.icmsg index 39b8c8d0c75b83..7a9a93e86de99b 100644 --- a/subsys/ipc/ipc_service/lib/Kconfig.icmsg +++ b/subsys/ipc/ipc_service/lib/Kconfig.icmsg @@ -3,6 +3,7 @@ config IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC bool "Synchronize access to shared memory" + depends on MULTITHREADING default y help Provide synchronization access to shared memory at a library level. @@ -30,6 +31,7 @@ config IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS config IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE bool "Use dedicated workqueue" + depends on MULTITHREADING default y help Enable dedicated workqueue thread for the ICMsg backend. diff --git a/subsys/ipc/ipc_service/lib/icmsg.c b/subsys/ipc/ipc_service/lib/icmsg.c index 61fa03689f40f5..4e4f98b87bbdd1 100644 --- a/subsys/ipc/ipc_service/lib/icmsg.c +++ b/subsys/ipc/ipc_service/lib/icmsg.c @@ -15,10 +15,10 @@ #define BOND_NOTIFY_REPEAT_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS) #define SHMEM_ACCESS_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS) - static const uint8_t magic[] = {0x45, 0x6d, 0x31, 0x6c, 0x31, 0x4b, 0x30, 0x72, 0x6e, 0x33, 0x6c, 0x69, 0x34}; +#ifdef CONFIG_MULTITHREADING #if IS_ENABLED(CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_ENABLE) static K_THREAD_STACK_DEFINE(icmsg_stack, CONFIG_IPC_SERVICE_BACKEND_ICMSG_WQ_STACK_SIZE); static struct k_work_q icmsg_workq; @@ -26,6 +26,10 @@ static struct k_work_q *const workq = &icmsg_workq; #else static struct k_work_q *const workq = &k_sys_work_q; #endif +static void mbox_callback_process(struct k_work *item); +#else +static void mbox_callback_process(struct icmsg_data_t *dev_data); +#endif static int mbox_deinit(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data) @@ -42,12 +46,20 @@ static int mbox_deinit(const struct icmsg_config_t *conf, return err; } +#ifdef CONFIG_MULTITHREADING (void)k_work_cancel(&dev_data->mbox_work); (void)k_work_cancel_delayable(&dev_data->notify_work); +#endif return 0; } +static bool is_endpoint_ready(struct icmsg_data_t *dev_data) +{ + return atomic_get(&dev_data->state) == ICMSG_STATE_READY; +} + +#ifdef CONFIG_MULTITHREADING static void notify_process(struct k_work *item) { struct k_work_delayable *dwork = k_work_delayable_from_work(item); @@ -66,37 +78,47 @@ static void notify_process(struct k_work *item) (void)ret; } } - -static bool is_endpoint_ready(struct icmsg_data_t *dev_data) +#else +static void notify_process(struct icmsg_data_t *dev_data) { - return atomic_get(&dev_data->state) == ICMSG_STATE_READY; + (void)mbox_send_dt(&dev_data->cfg->mbox_tx, NULL); + int64_t start = k_uptime_get(); + + while (false == is_endpoint_ready(dev_data)) { + mbox_callback_process(dev_data); + + if ((k_uptime_get() - start) > CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS) { + (void)mbox_send_dt(&dev_data->cfg->mbox_tx, NULL); + start = k_uptime_get(); + }; + } } +#endif +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC static int reserve_tx_buffer_if_unused(struct icmsg_data_t *dev_data) { -#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC int ret = k_mutex_lock(&dev_data->tx_lock, SHMEM_ACCESS_TO); if (ret < 0) { return ret; } -#endif + return 0; } static int release_tx_buffer(struct icmsg_data_t *dev_data) { -#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC return k_mutex_unlock(&dev_data->tx_lock); -#endif - return 0; } +#endif static uint32_t data_available(struct icmsg_data_t *dev_data) { return pbuf_read(dev_data->rx_pb, NULL, 0); } +#ifdef CONFIG_MULTITHREADING static void submit_mbox_work(struct icmsg_data_t *dev_data) { if (k_work_submit_to_queue(workq, &dev_data->mbox_work) < 0) { @@ -121,10 +143,33 @@ static void submit_work_if_buffer_free_and_data_available( submit_mbox_work(dev_data); } +#else +static void submit_if_buffer_free(struct icmsg_data_t *dev_data) +{ + mbox_callback_process(dev_data); +} +static void submit_if_buffer_free_and_data_available( + struct icmsg_data_t *dev_data) +{ + + if (!data_available(dev_data)) { + return; + } + + mbox_callback_process(dev_data); +} +#endif + +#ifdef CONFIG_MULTITHREADING static void mbox_callback_process(struct k_work *item) +#else +static void mbox_callback_process(struct icmsg_data_t *dev_data) +#endif { +#ifdef CONFIG_MULTITHREADING struct icmsg_data_t *dev_data = CONTAINER_OF(item, struct icmsg_data_t, mbox_work); +#endif atomic_t state = atomic_get(&dev_data->state); @@ -141,8 +186,7 @@ static void mbox_callback_process(struct k_work *item) if (state == ICMSG_STATE_READY) { if (dev_data->cb->received) { - dev_data->cb->received(rx_buffer, len, - dev_data->ctx); + dev_data->cb->received(rx_buffer, len, dev_data->ctx); } } else { __ASSERT_NO_MSG(state == ICMSG_STATE_BUSY); @@ -162,15 +206,22 @@ static void mbox_callback_process(struct k_work *item) atomic_set(&dev_data->state, ICMSG_STATE_READY); } - +#ifdef CONFIG_MULTITHREADING submit_work_if_buffer_free_and_data_available(dev_data); +#else + submit_if_buffer_free_and_data_available(dev_data); +#endif } static void mbox_callback(const struct device *instance, uint32_t channel, void *user_data, struct mbox_msg *msg_data) { struct icmsg_data_t *dev_data = user_data; +#ifdef CONFIG_MULTITHREADING submit_work_if_buffer_free(dev_data); +#else + submit_if_buffer_free(dev_data); +#endif } static int mbox_init(const struct icmsg_config_t *conf, @@ -178,8 +229,10 @@ static int mbox_init(const struct icmsg_config_t *conf, { int err; +#ifdef CONFIG_MULTITHREADING k_work_init(&dev_data->mbox_work, mbox_callback_process); k_work_init_delayable(&dev_data->notify_work, notify_process); +#endif err = mbox_register_callback_dt(&conf->mbox_rx, mbox_callback, dev_data); if (err != 0) { @@ -233,12 +286,14 @@ int icmsg_open(const struct icmsg_config_t *conf, if (ret) { return ret; } - +#ifdef CONFIG_MULTITHREADING ret = k_work_schedule_for_queue(workq, &dev_data->notify_work, K_NO_WAIT); if (ret < 0) { return ret; } - +#else + notify_process(dev_data); +#endif return 0; } @@ -263,7 +318,9 @@ int icmsg_send(const struct icmsg_config_t *conf, { int ret; int write_ret; +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC int release_ret; +#endif int sent_bytes; if (!is_endpoint_ready(dev_data)) { @@ -275,14 +332,19 @@ int icmsg_send(const struct icmsg_config_t *conf, return -ENODATA; } +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC ret = reserve_tx_buffer_if_unused(dev_data); if (ret < 0) { return -ENOBUFS; } +#endif write_ret = pbuf_write(dev_data->tx_pb, msg, len); + +#ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC release_ret = release_tx_buffer(dev_data); __ASSERT_NO_MSG(!release_ret); +#endif if (write_ret < 0) { return write_ret; diff --git a/west.yml b/west.yml index a132bb5b360858..8fb2624518462e 100644 --- a/west.yml +++ b/west.yml @@ -23,6 +23,8 @@ manifest: url-base: https://github.com/zephyrproject-rtos - name: babblesim url-base: https://github.com/BabbleSim + - name: magp + url-base: https://github.com/magp-nordic group-filter: [-babblesim, -optional] @@ -188,7 +190,8 @@ manifest: groups: - hal - name: hal_nordic - revision: ab5cb2e2faeb1edfad7a25286dcb513929ae55da + remote: magp + revision: pull/1/head path: modules/hal/nordic groups: - hal