From 4e7470cc09447a9ca2f354d81b06ffa9d9bd0e9a Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Wed, 12 Jun 2024 12:56:22 +0200 Subject: [PATCH] drivers: add eGPIO SHIM Signed-off-by: Magdalena Pastula Signed-off-by: Jakub Zymelka --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 1 + drivers/gpio/Kconfig.nrfe | 10 + drivers/gpio/gpio_nrfe.c | 267 ++++++++++++++++++++++++ dts/bindings/gpio/nordic,nrf-egpio.yaml | 61 ++++++ modules/hal_nordic/CMakeLists.txt | 1 + modules/hal_nordic/Kconfig | 1 + modules/hal_nordic/nrfe/CMakeLists.txt | 15 ++ modules/hal_nordic/nrfe/Kconfig | 18 ++ soc/nordic/common/Kconfig.peripherals | 3 + soc/nordic/common/vpr/Kconfig | 1 + soc/nordic/nrf54l/Kconfig | 1 + 12 files changed, 380 insertions(+) create mode 100644 drivers/gpio/Kconfig.nrfe create mode 100644 drivers/gpio/gpio_nrfe.c create mode 100644 dts/bindings/gpio/nordic,nrf-egpio.yaml create mode 100644 modules/hal_nordic/nrfe/CMakeLists.txt create mode 100644 modules/hal_nordic/nrfe/Kconfig diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index e150c8c8ea3b1b1..9d284c1cc78c620 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 e6aac9e04ceb5f9..02e338c0d55760b 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -145,6 +145,7 @@ source "drivers/gpio/Kconfig.npcx" source "drivers/gpio/Kconfig.npm1300" source "drivers/gpio/Kconfig.npm6001" source "drivers/gpio/Kconfig.nrfx" +source "drivers/gpio/Kconfig.nrfe" source "drivers/gpio/Kconfig.numaker" source "drivers/gpio/Kconfig.numicro" source "drivers/gpio/Kconfig.nxp_s32" diff --git a/drivers/gpio/Kconfig.nrfe b/drivers/gpio/Kconfig.nrfe new file mode 100644 index 000000000000000..ad0071ad8b08093 --- /dev/null +++ b/drivers/gpio/Kconfig.nrfe @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menuconfig 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 000000000000000..3c4b39d1a0eca0f --- /dev/null +++ b/drivers/gpio/gpio_nrfe.c @@ -0,0 +1,267 @@ +/* + * 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); +K_SEM_DEFINE(confirm_sem, 0, 1); +#else +volatile uint32_t bound_sem = 1; +volatile uint32_t confirm_sem = 1; +#endif + +static void ep_bound(void *priv) +{ +#ifdef CONFIG_MULTITHREADING + k_sem_give(&bound_sem); +#else + bound_sem = 0; +#endif + printk("Ep bounded\n"); +} + +static void ep_recv(const void *data, size_t len, void *priv) +{ + struct nrfe_gpio_data_packet_t *packet = (struct nrfe_gpio_data_packet_t *)data; + + switch (packet->opcode) { + case NRFE_GPIO_CONFIRM: + { +#ifdef CONFIG_MULTITHREADING + k_sem_give(&confirm_sem); +#else + confirm_sem = 0; +#endif + break; + } + + default: + break; + } +} + +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) +{ + struct nrfe_gpio_data_packet_t msg = {.opcode = NRFE_GPIO_CONFIGURE, + .pin = pin, + .port = get_port_cfg(port)->port_num, + .flags = flags}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(struct nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + +#ifdef CONFIG_MULTITHREADING + k_sem_take(&confirm_sem, K_FOREVER); +#else + while (confirm_sem != 0) { + }; +#endif + + 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; + + struct nrfe_gpio_data_packet_t msg = { + .opcode = NRFE_GPIO_SET, .pin = set_mask, .port = get_port_cfg(port)->port_num}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(struct nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + +#ifdef CONFIG_MULTITHREADING + k_sem_take(&confirm_sem, K_FOREVER); +#else + while (confirm_sem != 0) { + }; +#endif + + msg.opcode = NRFE_GPIO_CLEAR; + msg.pin = clear_mask; + + ret = ipc_service_send(&ep, (void *)(&msg), sizeof(struct nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + +#ifdef CONFIG_MULTITHREADING + k_sem_take(&confirm_sem, K_FOREVER); +#else + while (confirm_sem != 0) { + }; +#endif + + return ret; +} + +static int gpio_nrfx_port_set_bits_raw(const struct device *port, gpio_port_pins_t mask) +{ + struct nrfe_gpio_data_packet_t msg = { + .opcode = NRFE_GPIO_SET, .pin = mask, .port = get_port_cfg(port)->port_num}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(struct nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + +#ifdef CONFIG_MULTITHREADING + k_sem_take(&confirm_sem, K_FOREVER); +#else + while (confirm_sem != 0) { + }; +#endif + + return ret; +} + +static int gpio_nrfx_port_clear_bits_raw(const struct device *port, gpio_port_pins_t mask) +{ + struct nrfe_gpio_data_packet_t msg = { + .opcode = NRFE_GPIO_CLEAR, .pin = mask, .port = get_port_cfg(port)->port_num}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(struct nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + +#ifdef CONFIG_MULTITHREADING + k_sem_take(&confirm_sem, K_FOREVER); +#else + while (confirm_sem != 0) { + }; +#endif + + return ret; +} + +static int gpio_nrfx_port_toggle_bits(const struct device *port, gpio_port_pins_t mask) +{ + struct nrfe_gpio_data_packet_t msg = { + .opcode = NRFE_GPIO_TOGGLE, .pin = mask, .port = get_port_cfg(port)->port_num}; + + int ret = ipc_service_send(&ep, (void *)(&msg), sizeof(struct nrfe_gpio_data_packet_t)); + + if (ret < 0) { + return ret; + } + +#ifdef CONFIG_MULTITHREADING + k_sem_take(&confirm_sem, K_FOREVER); +#else + while (confirm_sem != 0) { + }; +#endif + + 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)) { + printk("ipc_service_open_instance() failure\n"); + return ret; + } + + ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); + if (ret < 0) { + printk("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 + + 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, +}; + +/* 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_GPIO_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 000000000000000..a72f3dc60680bb6 --- /dev/null +++ b/dts/bindings/gpio/nordic,nrf-egpio.yaml @@ -0,0 +1,61 @@ +# 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. + Pins not included in the mask use GPIOTE channels in the event mode. + + 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/modules/hal_nordic/CMakeLists.txt b/modules/hal_nordic/CMakeLists.txt index ac9b3f8ce4c6c98..6512fc44264a742 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 13ab8d9cd2f9c54..0d4148ccc8cf85c 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 000000000000000..259a0c8b9bf6163 --- /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 000000000000000..c35a821c4141b95 --- /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/soc/nordic/common/Kconfig.peripherals b/soc/nordic/common/Kconfig.peripherals index a6d730804b824d9..99fb74a125eb754 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 c2abfbb18b1f035..d3a8b7f52614330 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 18e315078e9daae..02b410fc9bb7b2a 100644 --- a/soc/nordic/nrf54l/Kconfig +++ b/soc/nordic/nrf54l/Kconfig @@ -5,6 +5,7 @@ config SOC_SERIES_NRF54LX select SOC_COMPATIBLE_NRF54LX + select HAS_NRFE select HAS_NRFX select HAS_NORDIC_DRIVERS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE