diff --git a/drivers/spi/Kconfig.nrfx b/drivers/spi/Kconfig.nrfx index 0ee1c03065b..870730769fa 100644 --- a/drivers/spi/Kconfig.nrfx +++ b/drivers/spi/Kconfig.nrfx @@ -51,6 +51,20 @@ config SPI_NRFX_SPIS select NRFX_SPIS1 if HAS_HW_NRF_SPIS1 select NRFX_SPIS2 if HAS_HW_NRF_SPIS2 select NRFX_SPIS3 if HAS_HW_NRF_SPIS3 + select NRFX_SPIS00 if HAS_HW_NRF_SPIS00 + select NRFX_SPIS20 if HAS_HW_NRF_SPIS20 + select NRFX_SPIS21 if HAS_HW_NRF_SPIS21 + select NRFX_SPIS22 if HAS_HW_NRF_SPIS22 + select NRFX_SPIS30 if HAS_HW_NRF_SPIS30 + select NRFX_SPIS120 if HAS_HW_NRF_SPIS120 + select NRFX_SPIS130 if HAS_HW_NRF_SPIS130 + select NRFX_SPIS131 if HAS_HW_NRF_SPIS131 + select NRFX_SPIS132 if HAS_HW_NRF_SPIS132 + select NRFX_SPIS133 if HAS_HW_NRF_SPIS133 + select NRFX_SPIS134 if HAS_HW_NRF_SPIS134 + select NRFX_SPIS135 if HAS_HW_NRF_SPIS135 + select NRFX_SPIS136 if HAS_HW_NRF_SPIS136 + select NRFX_SPIS137 if HAS_HW_NRF_SPIS137 config SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 depends on SOC_NRF52832 diff --git a/drivers/spi/spi_nrfx_spis.c b/drivers/spi/spi_nrfx_spis.c index d2a61530f00..78bcc9f84be 100644 --- a/drivers/spi/spi_nrfx_spis.c +++ b/drivers/spi/spi_nrfx_spis.c @@ -399,18 +399,9 @@ static int spi_nrfx_init(const struct device *dev) CONFIG_SPI_INIT_PRIORITY, \ &spi_nrfx_driver_api) -#ifdef CONFIG_HAS_HW_NRF_SPIS0 -SPI_NRFX_SPIS_DEFINE(0); -#endif - -#ifdef CONFIG_HAS_HW_NRF_SPIS1 -SPI_NRFX_SPIS_DEFINE(1); -#endif +/* Macro creates device instance if it is enabled in devicetree. */ +#define SPIS_DEVICE(periph, prefix, id, _) \ + IF_ENABLED(CONFIG_HAS_HW_NRF_SPIS##prefix##id, (SPI_NRFX_SPIS_DEFINE(prefix##id);)) -#ifdef CONFIG_HAS_HW_NRF_SPIS2 -SPI_NRFX_SPIS_DEFINE(2); -#endif - -#ifdef CONFIG_HAS_HW_NRF_SPIS3 -SPI_NRFX_SPIS_DEFINE(3); -#endif +/* Macro iterates over nrfx_spis instances enabled in the nrfx_config.h. */ +NRFX_FOREACH_ENABLED(SPIS, SPIS_DEVICE, (), (), _) diff --git a/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi index eb161844841..3e4d3641069 100644 --- a/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi @@ -24,6 +24,8 @@ spi00: spi@4a000 { interrupts = <74 NRF_DEFAULT_IRQ_PRIORITY>; max-frequency = ; easydma-maxcnt-bits = <16>; + rx-delay-supported; + rx-delay = <1>; status = "disabled"; }; @@ -124,6 +126,8 @@ spi20: spi@c6000 { interrupts = <198 NRF_DEFAULT_IRQ_PRIORITY>; max-frequency = ; easydma-maxcnt-bits = <16>; + rx-delay-supported; + rx-delay = <1>; status = "disabled"; }; @@ -159,6 +163,8 @@ spi21: spi@c7000 { interrupts = <199 NRF_DEFAULT_IRQ_PRIORITY>; max-frequency = ; easydma-maxcnt-bits = <16>; + rx-delay-supported; + rx-delay = <1>; status = "disabled"; }; @@ -194,6 +200,8 @@ spi22: spi@c8000 { interrupts = <200 NRF_DEFAULT_IRQ_PRIORITY>; max-frequency = ; easydma-maxcnt-bits = <16>; + rx-delay-supported; + rx-delay = <1>; status = "disabled"; }; @@ -391,6 +399,8 @@ spi30: spi@104000 { interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; max-frequency = ; easydma-maxcnt-bits = <16>; + rx-delay-supported; + rx-delay = <1>; status = "disabled"; }; diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index ec5c4cca14f..d3b6b20188f 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -362,6 +362,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; uart120: uart@8e6000 { @@ -380,6 +382,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; cpuppr_vpr: vpr@908000 { @@ -637,6 +641,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; uart130: uart@9a5000 { @@ -665,6 +671,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; uart131: uart@9a6000 { @@ -727,6 +735,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; uart132: uart@9b5000 { @@ -755,6 +765,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; uart133: uart@9b6000 { @@ -817,6 +829,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; uart134: uart@9c5000 { @@ -845,6 +859,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; uart135: uart@9c6000 { @@ -907,6 +923,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; uart136: uart@9d5000 { @@ -935,6 +953,8 @@ max-frequency = ; #address-cells = <1>; #size-cells = <0>; + rx-delay-supported; + rx-delay = <1>; }; uart137: uart@9d6000 { diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index c1138ab25a3..541d9fac5e7 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -441,6 +441,76 @@ config NRFX_SPIS3 depends on $(dt_nodelabel_has_compat,spi3,$(DT_COMPAT_NORDIC_NRF_SPIS)) select NRFX_SPIS +config NRFX_SPIS00 + bool "SPIS00 driver instance" + depends on $(dt_nodelabel_has_compat,spi00,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS20 + bool "SPIS20 driver instance" + depends on $(dt_nodelabel_has_compat,spi20,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS21 + bool "SPIS21 driver instance" + depends on $(dt_nodelabel_has_compat,spi21,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS22 + bool "SPIS22 driver instance" + depends on $(dt_nodelabel_has_compat,spi22,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS30 + bool "SPIS30 driver instance" + depends on $(dt_nodelabel_has_compat,spi30,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS120 + bool "SPIS120 driver instance" + depends on $(dt_nodelabel_has_compat,spi120,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS130 + bool "SPIS130 driver instance" + depends on $(dt_nodelabel_has_compat,spi130,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS131 + bool "SPIS131 driver instance" + depends on $(dt_nodelabel_has_compat,spi131,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS132 + bool "SPIS132 driver instance" + depends on $(dt_nodelabel_has_compat,spi132,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS133 + bool "SPIS133 driver instance" + depends on $(dt_nodelabel_has_compat,spi133,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS134 + bool "SPIS134 driver instance" + depends on $(dt_nodelabel_has_compat,spi134,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS135 + bool "SPIS135 driver instance" + depends on $(dt_nodelabel_has_compat,spi135,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS136 + bool "SPIS136 driver instance" + depends on $(dt_nodelabel_has_compat,spi136,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + +config NRFX_SPIS137 + bool "SPIS137 driver instance" + depends on $(dt_nodelabel_has_compat,spi137,$(DT_COMPAT_NORDIC_NRF_SPIS)) + select NRFX_SPIS + config NRFX_SYSTICK bool "SYSTICK driver" depends on CPU_CORTEX_M_HAS_SYSTICK diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index e99c80d43cd..9357bddab0a 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -381,8 +381,10 @@ #ifdef CONFIG_NRFX_SPIM4 #define NRFX_SPIM4_ENABLED 1 #endif -#if (DT_PROP(DT_NODELABEL(spi3), rx_delay_supported) || \ - DT_PROP(DT_NODELABEL(spi4), rx_delay_supported)) + +#define NRFX_SPIM_DT_HAS_RX_DELAY(node) DT_PROP(node, rx_delay_supported) + + +#if DT_FOREACH_STATUS_OKAY(nordic_nrf_spim, NRFX_SPIM_DT_HAS_RX_DELAY) 0 #define NRFX_SPIM_EXTENDED_ENABLED 1 #endif #ifdef CONFIG_NRFX_SPIM00 @@ -449,6 +451,48 @@ #ifdef CONFIG_NRFX_SPIS3 #define NRFX_SPIS3_ENABLED 1 #endif +#ifdef CONFIG_NRFX_SPIS00 +#define NRFX_SPIS00_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS20 +#define NRFX_SPIS20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS21 +#define NRFX_SPIS21_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS22 +#define NRFX_SPIS22_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS30 +#define NRFX_SPIS30_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS120 +#define NRFX_SPIS120_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS130 +#define NRFX_SPIS130_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS131 +#define NRFX_SPIS131_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS132 +#define NRFX_SPIS132_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS133 +#define NRFX_SPIS133_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS134 +#define NRFX_SPIS134_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS135 +#define NRFX_SPIS135_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS136 +#define NRFX_SPIS136_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIS137 +#define NRFX_SPIS130_ENABLED 1 +#endif #ifdef CONFIG_NRFX_SYSTICK #define NRFX_SYSTICK_ENABLED 1 diff --git a/soc/common/nordic_nrf/Kconfig.peripherals b/soc/common/nordic_nrf/Kconfig.peripherals index 39ed2e6432f..bc79b63d1d8 100644 --- a/soc/common/nordic_nrf/Kconfig.peripherals +++ b/soc/common/nordic_nrf/Kconfig.peripherals @@ -317,6 +317,48 @@ config HAS_HW_NRF_SPIS2 config HAS_HW_NRF_SPIS3 def_bool $(dt_nodelabel_enabled_with_compat,spi3,$(DT_COMPAT_NORDIC_NRF_SPIS)) +config HAS_HW_NRF_SPIS00 + def_bool $(dt_nodelabel_enabled_with_compat,spi00,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS20 + def_bool $(dt_nodelabel_enabled_with_compat,spi20,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS21 + def_bool $(dt_nodelabel_enabled_with_compat,spi21,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS22 + def_bool $(dt_nodelabel_enabled_with_compat,spi22,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS30 + def_bool $(dt_nodelabel_enabled_with_compat,spi30,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS120 + def_bool $(dt_nodelabel_enabled_with_compat,spi120,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS130 + def_bool $(dt_nodelabel_enabled_with_compat,spi130,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS131 + def_bool $(dt_nodelabel_enabled_with_compat,spi131,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS132 + def_bool $(dt_nodelabel_enabled_with_compat,spi132,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS133 + def_bool $(dt_nodelabel_enabled_with_compat,spi133,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS134 + def_bool $(dt_nodelabel_enabled_with_compat,spi134,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS135 + def_bool $(dt_nodelabel_enabled_with_compat,spi135,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS136 + def_bool $(dt_nodelabel_enabled_with_compat,spi136,$(DT_COMPAT_NORDIC_NRF_SPIS)) + +config HAS_HW_NRF_SPIS137 + def_bool $(dt_nodelabel_enabled_with_compat,spi137,$(DT_COMPAT_NORDIC_NRF_SPIS)) + config HAS_HW_NRF_SPU def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_SPU)) diff --git a/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..5ab0e84eeaa --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + spi130_default: spi130_default { + group1 { + psels = , + , + ; + }; + }; + + spi130_sleep: spi130_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +&spi130 { + status = "okay"; + pinctrl-0 = <&spi130_default>; + pinctrl-1 = <&spi130_sleep>; + pinctrl-names = "default", "sleep"; + overrun-character = <0x00>; + memory-regions = <&cpuapp_dma_region>; + slow@0 { + compatible = "test-spi-loopback-slow"; + reg = <0>; + spi-max-frequency = ; + }; + fast@0 { + compatible = "test-spi-loopback-fast"; + reg = <0>; + spi-max-frequency = ; + }; +}; diff --git a/tests/drivers/spi/spi_slave/CMakeLists.txt b/tests/drivers/spi/spi_slave/CMakeLists.txt new file mode 100644 index 00000000000..f9f7a6bdae4 --- /dev/null +++ b/tests/drivers/spi/spi_slave/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(spi_slave) + +FILE(GLOB app_sources src/*.c) + +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/spi/spi_slave/boards/nrf52840dk_nrf52840.overlay b/tests/drivers/spi/spi_slave/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000..477917e0ca7 --- /dev/null +++ b/tests/drivers/spi/spi_slave/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + spi3_default_alt: spi3_default_alt { + group1 { + psels = , + , + ; + }; + }; + + spi3_sleep_alt: spi3_sleep_alt { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + spi1_default_alt: spi1_default_alt { + group1 { + psels = , + , + , + ; + }; + }; + + spi1_sleep_alt: spi1_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + +}; + +&spi3 { + status = "okay"; + pinctrl-0 = <&spi3_default_alt>; + pinctrl-1 = <&spi3_sleep_alt>; + pinctrl-names = "default", "sleep"; + overrun-character = <0x00>; + cs-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; + dut_spi_dt: test-spi-dev@0 { + compatible = "vnd,spi-device"; + reg = <0>; + spi-max-frequency = <4000000>; + }; +}; + +dut_spis: &spi1 { + compatible = "nordic,nrf-spis"; + status = "okay"; + def-char = <0x00>; + pinctrl-0 = <&spi1_default_alt>; + pinctrl-1 = <&spi1_sleep_alt>; + pinctrl-names = "default", "sleep"; +}; diff --git a/tests/drivers/spi/spi_slave/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/spi/spi_slave/boards/nrf54h20dk_nrf54h20_common.dtsi new file mode 100644 index 00000000000..0a9425cc2f9 --- /dev/null +++ b/tests/drivers/spi/spi_slave/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + spi130_default_alt: spi130_default_alt { + group1 { + psels = , + , + ; + }; + }; + + spi130_sleep_alt: spi130_sleep_alt { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + spis131_default_alt: spis131_default_alt { + group1 { + psels = , + , + , + ; + }; + }; + + spis131_sleep_alt: spis131_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + +}; + +&gpio0 { + status = "okay"; +}; + +&gpiote130 { + status = "okay"; + owned-channels = <7>; +}; + +dut_spi: &spi130 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi130_default_alt>; + pinctrl-1 = <&spi130_sleep_alt>; + pinctrl-names = "default", "sleep"; + overrun-character = <0x00>; + cs-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; + dut_spi_dt: test-spi-dev@0 { + compatible = "vnd,spi-device"; + reg = <0>; + spi-max-frequency = <500000>; + }; +}; + +dut_spis: &spi131 { + compatible = "nordic,nrf-spis"; + status = "okay"; + def-char = <0x00>; + pinctrl-0 = <&spis131_default_alt>; + pinctrl-1 = <&spis131_sleep_alt>; + pinctrl-names = "default", "sleep"; + /delete-property/rx-delay-supported; + /delete-property/rx-delay; +}; diff --git a/tests/drivers/spi/spi_slave/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/spi/spi_slave/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..ff337ebdec4 --- /dev/null +++ b/tests/drivers/spi/spi_slave/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&dut_spi { + memory-regions = <&cpuapp_dma_region>; +}; + +&dut_spis { + memory-regions = <&cpuapp_dma_region>; +}; diff --git a/tests/drivers/spi/spi_slave/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/spi/spi_slave/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 00000000000..936bd5b15d5 --- /dev/null +++ b/tests/drivers/spi/spi_slave/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&dut_spi { + memory-regions = <&cpurad_dma_region>; +}; + +&dut_spis { + memory-regions = <&cpurad_dma_region>; +}; diff --git a/tests/drivers/spi/spi_slave/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/spi/spi_slave/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..d431f278337 --- /dev/null +++ b/tests/drivers/spi/spi_slave/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + spi22_default_alt: spi22_default_alt { + group1 { + psels = , + , + ; + }; + }; + + spi22_sleep_alt: spi22_sleep_alt { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + spi21_default_alt: spi21_default_alt { + group1 { + psels = , + , + , + ; + }; + }; + + spi21_sleep_alt: spi21_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + +}; + +&gpio2 { + status = "okay"; +}; + +&spi22 { + status = "okay"; + pinctrl-0 = <&spi22_default_alt>; + pinctrl-1 = <&spi22_sleep_alt>; + pinctrl-names = "default", "sleep"; + overrun-character = <0x00>; + cs-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; + dut_spi_dt: test-spi-dev@0 { + compatible = "vnd,spi-device"; + reg = <0>; + spi-max-frequency = <4000000>; + }; +}; + +dut_spis: &spi21 { + compatible = "nordic,nrf-spis"; + status = "okay"; + def-char = <0x00>; + pinctrl-0 = <&spi21_default_alt>; + pinctrl-1 = <&spi21_sleep_alt>; + pinctrl-names = "default", "sleep"; + /delete-property/rx-delay-supported; + /delete-property/rx-delay; +}; diff --git a/tests/drivers/spi/spi_slave/prj.conf b/tests/drivers/spi/spi_slave/prj.conf new file mode 100644 index 00000000000..840a8f87d9a --- /dev/null +++ b/tests/drivers/spi/spi_slave/prj.conf @@ -0,0 +1,6 @@ +CONFIG_SPI=y +CONFIG_SPI_SLAVE=y +CONFIG_GPIO=y +CONFIG_POLL=y +CONFIG_SPI_ASYNC=y +CONFIG_ZTEST=y diff --git a/tests/drivers/spi/spi_slave/src/main.c b/tests/drivers/spi/spi_slave/src/main.c new file mode 100644 index 00000000000..5f441480c12 --- /dev/null +++ b/tests/drivers/spi/spi_slave/src/main.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define SPI_MODE (SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_LINES_SINGLE) +#define SPIM_OP (SPI_OP_MODE_MASTER | SPI_MODE) +#define SPIS_OP (SPI_OP_MODE_SLAVE | SPI_MODE) + +static struct spi_dt_spec spim = SPI_DT_SPEC_GET(DT_NODELABEL(dut_spi_dt), SPIM_OP, 0); +static const struct device *spis_dev = DEVICE_DT_GET(DT_NODELABEL(dut_spis)); +static const struct spi_config spis_config = { + .operation = SPIS_OP +}; + +static struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig); +static struct k_poll_event async_evt = + K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &async_sig); + +#define MEMORY_SECTION(node) \ + COND_CODE_1(DT_NODE_HAS_PROP(node, memory_regions), \ + (__attribute__((__section__( \ + LINKER_DT_NODE_REGION_NAME(DT_PHANDLE(node, memory_regions)))))), \ + ()) + +static uint8_t spim_buffer[32] MEMORY_SECTION(DT_BUS(DT_NODELABEL(dut_spi_dt))); +static uint8_t spis_buffer[32] MEMORY_SECTION(DT_NODELABEL(dut_spis)); + +struct test_data { + struct k_work_delayable test_work; + struct k_sem sem; + int spim_alloc_idx; + int spis_alloc_idx; + struct spi_buf_set sets[4]; + struct spi_buf_set *mtx_set; + struct spi_buf_set *mrx_set; + struct spi_buf_set *stx_set; + struct spi_buf_set *srx_set; + struct spi_buf bufs[8]; +}; + +static struct test_data tdata; + +/* Allocate buffer from spim or spis space. */ +static uint8_t *buf_alloc(size_t len, bool spim) +{ + int *idx = spim ? &tdata.spim_alloc_idx : &tdata.spis_alloc_idx; + uint8_t *buf = spim ? spim_buffer : spis_buffer; + size_t total = spim ? sizeof(spim_buffer) : sizeof(spis_buffer); + uint8_t *rv; + + if (*idx + len > total) { + zassert_false(true); + + return NULL; + } + + rv = &buf[*idx]; + *idx += len; + + return rv; +} + +static void work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct test_data *td = CONTAINER_OF(dwork, struct test_data, test_work); + int rv; + + rv = spi_transceive_dt(&spim, td->mtx_set, td->mrx_set); + if (rv == 0) { + k_sem_give(&td->sem); + } +} + +/** Copies data from buffers in the set to a single buffer which makes it easier + * to compare transmitted and received data. + * + * @param buf Output buffer. + * @param len Buffer length. + * @param set Set of buffers. + * + * @return Number of bytes copied. + */ +static int cpy_data(uint8_t *buf, size_t len, struct spi_buf_set *set) +{ + int idx = 0; + + for (size_t i = 0; i < set->count; i++) { + size_t l = set->buffers[i].len; + + if (len - idx >= l) { + memcpy(&buf[idx], set->buffers[i].buf, l); + idx += l; + } else { + return -1; + } + } + + return idx; +} + +/** Compare two sets. + * + * @param tx_set TX set. + * @param rx_set RX set. + * @param same_size True if it is expected to have the same amount of data in both sets. + * + * @return 0 if data is the same and other value indicate that check failed. + */ +static int check_buffers(struct spi_buf_set *tx_set, struct spi_buf_set *rx_set, bool same_size) +{ + static uint8_t tx_data[256]; + static uint8_t rx_data[256]; + int rx_len; + int tx_len; + + if (!tx_set || !rx_set) { + return 0; + } + + rx_len = cpy_data(rx_data, sizeof(rx_data), rx_set); + tx_len = cpy_data(tx_data, sizeof(tx_data), tx_set); + if (same_size && (rx_len != tx_len)) { + return -1; + } + + return memcmp(tx_data, rx_data, rx_len); +} + +/** Calculate expected number of received bytes by the slave. + * + * It is used to check if SPI API call for slave returns correct value. + * @param tx_set TX set. + * @param rx_set RX set. + * + * @return Expected amount of received bytes. + */ +static int slave_rx_len(struct spi_buf_set *tx_set, struct spi_buf_set *rx_set) +{ + size_t tx_len = 0; + size_t rx_len = 0; + + if (!tx_set || !rx_set) { + return 0; + } + + for (size_t i = 0; i < tx_set->count; i++) { + tx_len += tx_set->buffers[i].len; + } + + for (size_t i = 0; i < rx_set->count; i++) { + rx_len += rx_set->buffers[i].len; + } + + return MIN(rx_len, tx_len); +} + +/** Generic function which runs the test with sets prepared in the test data structure. */ +static void run_test(bool m_same_size, bool s_same_size, bool async) +{ + int rv; + int slave_rv; + int srx_len; + + rv = k_work_schedule(&tdata.test_work, K_MSEC(10)); + zassert_equal(rv, 1); + + if (!async) { + slave_rv = spi_transceive(spis_dev, &spis_config, tdata.stx_set, tdata.srx_set); + if (slave_rv == -ENOTSUP) { + ztest_test_skip(); + } + } else { + rv = spi_transceive_signal(spis_dev, &spis_config, tdata.stx_set, tdata.srx_set, + &async_sig); + if (rv == -ENOTSUP) { + ztest_test_skip(); + } + zassert_equal(rv, 0); + + /* Transfer not finished yet */ + rv = k_sem_take(&tdata.sem, K_NO_WAIT); + zassert_equal(rv, -EBUSY); + + rv = k_poll(&async_evt, 1, K_MSEC(200)); + zassert_false(rv, "one or more events are not ready"); + + slave_rv = async_evt.signal->result; + + /* Reinitializing for next call */ + async_evt.signal->signaled = 0U; + async_evt.state = K_POLL_STATE_NOT_READY; + } + + rv = k_sem_take(&tdata.sem, K_MSEC(100)); + zassert_equal(rv, 0); + + srx_len = slave_rx_len(tdata.mtx_set, tdata.srx_set); + + zassert_equal(slave_rv, srx_len, "Got: %d but expected:%d", slave_rv, srx_len); + + rv = check_buffers(tdata.mtx_set, tdata.srx_set, m_same_size); + zassert_equal(rv, 0); + + rv = check_buffers(tdata.stx_set, tdata.mrx_set, s_same_size); + zassert_equal(rv, 0); +} + +/** Basic test where slave and master have RX and TX sets which contains only one + * same size buffer. + */ +static void test_basic(bool async) +{ + size_t len = 16; + + for (int i = 0; i < 4; i++) { + tdata.bufs[i].buf = buf_alloc(len, i < 2); + tdata.bufs[i].len = len; + tdata.sets[i].buffers = &tdata.bufs[i]; + tdata.sets[i].count = 1; + } + + tdata.mtx_set = &tdata.sets[0]; + tdata.mrx_set = &tdata.sets[1]; + tdata.stx_set = &tdata.sets[2]; + tdata.srx_set = &tdata.sets[3]; + + run_test(true, true, async); +} + +ZTEST(spi_slave, test_basic) +{ + test_basic(false); +} + +ZTEST(spi_slave, test_basic_async) +{ + test_basic(true); +} + +/** Setup a transfer where RX buffer on master and slave are shorter than + * TX buffers. RX buffers shall contain beginning of TX data and last TX + * bytes that did not fit in the RX buffers shall be lost. + */ +static void test_short_rx(bool async) +{ + size_t len = 16; + + tdata.bufs[0].buf = buf_alloc(len, true); + tdata.bufs[0].len = len; + tdata.bufs[1].buf = buf_alloc(len, true); + tdata.bufs[1].len = len - 3; /* RX buffer */ + tdata.bufs[2].buf = buf_alloc(len, false); + tdata.bufs[2].len = len; + tdata.bufs[3].buf = buf_alloc(len, false); + tdata.bufs[3].len = len - 4; /* RX buffer */ + + for (int i = 0; i < 4; i++) { + tdata.sets[i].buffers = &tdata.bufs[i]; + tdata.sets[i].count = 1; + } + + tdata.mtx_set = &tdata.sets[0]; + tdata.mrx_set = &tdata.sets[1]; + tdata.stx_set = &tdata.sets[2]; + tdata.srx_set = &tdata.sets[3]; + + run_test(false, false, async); +} + +ZTEST(spi_slave, test_short_rx) +{ + test_short_rx(false); +} + +ZTEST(spi_slave, test_short_rx_async) +{ + test_short_rx(true); +} + +/** Test where only master transmits. */ +static void test_only_tx(bool async) +{ + size_t len = 16; + + /* MTX buffer */ + tdata.bufs[0].buf = buf_alloc(len, true); + tdata.bufs[0].len = len; + tdata.sets[0].buffers = &tdata.bufs[0]; + tdata.sets[0].count = 1; + tdata.mtx_set = &tdata.sets[0]; + tdata.mrx_set = NULL; + + /* STX buffer */ + tdata.bufs[1].buf = buf_alloc(len, false); + tdata.bufs[1].len = len; + tdata.sets[1].buffers = &tdata.bufs[1]; + tdata.sets[1].count = 1; + tdata.srx_set = &tdata.sets[1]; + tdata.stx_set = NULL; + + run_test(true, true, async); +} + +ZTEST(spi_slave, test_only_tx) +{ + test_only_tx(false); +} + +ZTEST(spi_slave, test_only_tx_async) +{ + test_only_tx(true); +} + +/** Test where only master transmits and slave receives in chunks. */ +static void test_only_tx_in_chunks(bool async) +{ + size_t len1 = 7; + size_t len2 = 8; + + /* MTX buffer */ + tdata.bufs[0].buf = buf_alloc(len1 + len2, true); + tdata.bufs[0].len = len1 + len2; + tdata.sets[0].buffers = &tdata.bufs[0]; + tdata.sets[0].count = 1; + tdata.mtx_set = &tdata.sets[0]; + tdata.mrx_set = NULL; + + /* STX buffer */ + tdata.bufs[1].buf = buf_alloc(len1, false); + tdata.bufs[1].len = len1; + tdata.bufs[2].buf = buf_alloc(len2, false); + tdata.bufs[2].len = len2; + tdata.sets[1].buffers = &tdata.bufs[1]; + tdata.sets[1].count = 2; + tdata.srx_set = &tdata.sets[1]; + tdata.stx_set = NULL; + + run_test(true, true, async); +} + +ZTEST(spi_slave, test_only_tx_in_chunks) +{ + test_only_tx_in_chunks(false); +} + +ZTEST(spi_slave, test_only_tx_in_chunks_async) +{ + test_only_tx_in_chunks(true); +} + +/** Test where only slave transmits. */ +static void test_only_rx(bool async) +{ + size_t len = 16; + + /* MTX buffer */ + tdata.bufs[0].buf = buf_alloc(len, true); + tdata.bufs[0].len = len; + tdata.sets[0].buffers = &tdata.bufs[0]; + tdata.sets[0].count = 1; + tdata.mrx_set = &tdata.sets[0]; + tdata.mtx_set = NULL; + + /* STX buffer */ + tdata.bufs[1].buf = buf_alloc(len, false); + tdata.bufs[1].len = len; + tdata.sets[1].buffers = &tdata.bufs[1]; + tdata.sets[1].count = 1; + tdata.stx_set = &tdata.sets[1]; + tdata.srx_set = NULL; + + run_test(true, true, async); +} + +ZTEST(spi_slave, test_only_rx) +{ + test_only_rx(false); +} + +ZTEST(spi_slave, test_only_rx_async) +{ + test_only_rx(true); +} + +/** Test where only slave transmits in chunks. */ +static void test_only_rx_in_chunks(bool async) +{ + size_t len1 = 7; + size_t len2 = 9; + + /* MTX buffer */ + tdata.bufs[0].buf = buf_alloc(len1 + len2, true); + tdata.bufs[0].len = len1 + len2; + tdata.sets[0].buffers = &tdata.bufs[0]; + tdata.sets[0].count = 1; + tdata.mrx_set = &tdata.sets[0]; + tdata.mtx_set = NULL; + + /* STX buffer */ + tdata.bufs[1].buf = buf_alloc(len1, false); + tdata.bufs[1].len = len1; + tdata.bufs[2].buf = buf_alloc(len2, false); + tdata.bufs[2].len = len2; + tdata.sets[1].buffers = &tdata.bufs[1]; + tdata.sets[1].count = 2; + tdata.stx_set = &tdata.sets[1]; + tdata.srx_set = NULL; + + run_test(true, true, async); +} + +ZTEST(spi_slave, test_only_rx_in_chunks) +{ + test_only_rx_in_chunks(false); +} + +ZTEST(spi_slave, test_only_rx_in_chunks_async) +{ + test_only_rx_in_chunks(true); +} + +static void before(void *not_used) +{ + ARG_UNUSED(not_used); + + memset(&tdata, 0, sizeof(tdata)); + for (size_t i = 0; i < sizeof(spim_buffer); i++) { + spim_buffer[i] = (uint8_t)i; + } + for (size_t i = 0; i < sizeof(spis_buffer); i++) { + spis_buffer[i] = (uint8_t)(i + 0x80); + } + + k_work_init_delayable(&tdata.test_work, work_handler); + k_sem_init(&tdata.sem, 0, 1); +} + +static void *suite_setup(void) +{ + return NULL; +} + +ZTEST_SUITE(spi_slave, NULL, suite_setup, before, NULL, NULL); diff --git a/tests/drivers/spi/spi_slave/testcase.yaml b/tests/drivers/spi/spi_slave/testcase.yaml new file mode 100644 index 00000000000..2ad23f25d4f --- /dev/null +++ b/tests/drivers/spi/spi_slave/testcase.yaml @@ -0,0 +1,12 @@ +tests: + drivers.spi_slave.api: + depends_on: spi + tags: drivers spi + harness: ztest + harness_config: + fixture: gpio_spi_loopback + platform_allow: | + nrf52840dk_nrf52840 nrf54l15pdk_nrf54l15_cpuapp nrf54h20dk_nrf54h20_cpuapp + nrf54h20dk_nrf54h20_cpurad + integration_platforms: + - nrf52840dk_nrf52840