diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 452307acaa83..c2bb35a82148 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -242,6 +242,9 @@ struct uarte_nrfx_data { /* If enabled then UARTE peripheral is using memory which is cacheable. */ #define UARTE_CFG_FLAG_CACHEABLE BIT(3) +/* If enabled then pins must be retained when UARTE is disabled. */ +#define UARTE_CFG_FLAG_RETAIN_PINS BIT(4) + /* Macro for converting numerical baudrate to register value. It is convenient * to use this approach because for constant input it can calculate nrf setting * at compile time. @@ -590,6 +593,11 @@ static void uarte_periph_enable(const struct device *dev) (void)data; nrf_uarte_enable(uarte); +#ifdef CONFIG_SOC_NRF54H20_GPD + if (config->flags & UARTE_CFG_FLAG_RETAIN_PINS) { + nrf_gpd_retain_pins_set(config->pcfg, false); + } +#endif #if UARTE_BAUDRATE_RETENTION_WORKAROUND nrf_uarte_baudrate_set(uarte, COND_CODE_1(CONFIG_UART_USE_RUNTIME_CONFIGURE, @@ -702,6 +710,13 @@ static void uarte_disable_locked(const struct device *dev, uint32_t dis_mask) } #endif +#ifdef CONFIG_SOC_NRF54H20_GPD + const struct uarte_nrfx_config *cfg = dev->config; + + if (cfg->flags & UARTE_CFG_FLAG_RETAIN_PINS) { + nrf_gpd_retain_pins_set(cfg->pcfg, true); + } +#endif nrf_uarte_disable(get_uarte_instance(dev)); } @@ -2103,9 +2118,6 @@ static void uarte_pm_resume(const struct device *dev) if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) || !LOW_POWER_ENABLED(cfg)) { uarte_periph_enable(dev); -#ifdef CONFIG_SOC_NRF54H20_GPD - nrf_gpd_retain_pins_set(cfg->pcfg, false); -#endif } } @@ -2169,7 +2181,9 @@ static void uarte_pm_suspend(const struct device *dev) } #ifdef CONFIG_SOC_NRF54H20_GPD - nrf_gpd_retain_pins_set(cfg->pcfg, true); + if (cfg->flags & UARTE_CFG_FLAG_RETAIN_PINS) { + nrf_gpd_retain_pins_set(cfg->pcfg, true); + } #endif nrf_uarte_disable(uarte); @@ -2383,6 +2397,8 @@ static int uarte_instance_init(const struct device *dev, (!IS_ENABLED(CONFIG_HAS_NORDIC_DMM) ? 0 : \ (UARTE_IS_CACHEABLE(idx) ? \ UARTE_CFG_FLAG_CACHEABLE : 0)) | \ + (UARTE_PROP(idx, pin_retention) ? \ + UARTE_CFG_FLAG_RETAIN_PINS : 0) | \ USE_LOW_POWER(idx), \ UARTE_DISABLE_RX_INIT(UARTE(idx)), \ .poll_out_byte = &uarte##idx##_poll_out_byte, \ diff --git a/dts/bindings/serial/nordic,nrf-uarte.yaml b/dts/bindings/serial/nordic,nrf-uarte.yaml index e6ba4c0b2147..6d1c0f70eab3 100644 --- a/dts/bindings/serial/nordic,nrf-uarte.yaml +++ b/dts/bindings/serial/nordic,nrf-uarte.yaml @@ -14,3 +14,9 @@ properties: type: boolean description: | UARTE has RX frame timeout HW feature. + pin-retention: + type: boolean + description: | + UARTE pin states must be retained when peripheral is disabled. + It is required when CTRLSEL is used to route UARTE pins. It is always the + case for fast peripheral and in special cases for slow peripherals. diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index b28ddb83fdb3..14d73f0eb3bf 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -669,6 +669,7 @@ power-domains = <&gpd NRF_GPD_FAST_ACTIVE1>; endtx-stoptx-supported; frame-timeout-supported; + pin-retention; }; spi121: spi@8e7000 { diff --git a/dts/common/nordic/nrf9280.dtsi b/dts/common/nordic/nrf9280.dtsi index 45b05f9262ee..9d00dddb052e 100644 --- a/dts/common/nordic/nrf9280.dtsi +++ b/dts/common/nordic/nrf9280.dtsi @@ -508,6 +508,7 @@ interrupts = <230 NRF_DEFAULT_IRQ_PRIORITY>; endtx-stoptx-supported; frame-timeout-supported; + pin-retention; }; spi121: spi@8e7000 { diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_common.dtsi index 9aa338deaad7..ecfbef2d9d63 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_common.dtsi +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -3,8 +3,11 @@ &pinctrl { uart137_default_alt: uart137_default_alt { group1 { - psels = , - ; + psels = ; + }; + group2 { + psels = ; + bias-pull-up; }; }; @@ -15,6 +18,23 @@ low-power-enable; }; }; + uart120_default_alt: uart120_default_alt { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart120_sleep_alt: uart120_sleep_alt { + group1 { + psels = , + ; + low-power-enable; + }; + }; }; dut: &uart137 { @@ -24,3 +44,11 @@ dut: &uart137 { pinctrl-names = "default", "sleep"; current-speed = <115200>; }; + +dut2: &uart120 { + status = "okay"; + pinctrl-0 = <&uart120_default_alt>; + pinctrl-1 = <&uart120_sleep_alt>; + pinctrl-names = "default", "sleep"; + current-speed = <115200>; +}; diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index be5897fd0516..386782a4e79e 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -5,3 +5,11 @@ &dut { memory-regions = <&cpuapp_dma_region>; }; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; + +&dma_fast_region { + status = "okay"; +}; diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay new file mode 100644 index 000000000000..8dd36819dff5 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +dut2: &uart120 { + status = "disabled"; +}; diff --git a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay index beca628a2f08..8881f7abc47f 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/tests/drivers/uart/uart_async_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -2,6 +2,18 @@ #include "nrf54h20dk_nrf54h20_common.dtsi" +&cpurad_dma_region { + reg = <0xe80 DT_SIZE_K(4)>; +}; + &dut { memory-regions = <&cpurad_dma_region>; }; + +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; 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 2feb201d94c6..e93850d2bc1d 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 @@ -24,25 +24,32 @@ K_SEM_DEFINE(rx_buf_coherency, 0, 255); K_SEM_DEFINE(rx_buf_released, 0, 1); K_SEM_DEFINE(rx_disabled, 0, 1); -ZTEST_BMEM volatile bool failed_in_isr; -static ZTEST_BMEM const struct device *const uart_dev = - DEVICE_DT_GET(UART_NODE); +static ZTEST_BMEM volatile bool failed_in_isr; -static void read_abort_timeout(struct k_timer *timer); -K_TIMER_DEFINE(read_abort_timer, read_abort_timeout, NULL); +struct dut_data { + const struct device *dev; + const char *name; +}; +ZTEST_DMEM struct dut_data duts[] = { + { + .dev = DEVICE_DT_GET(UART_NODE), + .name = DT_NODE_FULL_NAME(UART_NODE), + }, +#if DT_NODE_EXISTS(DT_NODELABEL(dut2)) && DT_NODE_HAS_STATUS(DT_NODELABEL(dut2), okay) + { + .dev = DEVICE_DT_GET(DT_NODELABEL(dut2)), + .name = DT_NODE_FULL_NAME(DT_NODELABEL(dut2)), + }, +#endif +}; + +static ZTEST_BMEM const struct device *uart_dev; +static ZTEST_BMEM const char *uart_name; + +static void read_abort_timeout(struct k_timer *timer); +static K_TIMER_DEFINE(read_abort_timer, read_abort_timeout, NULL); -static void init_test(void) -{ - __ASSERT_NO_MSG(device_is_ready(uart_dev)); - uart_rx_disable(uart_dev); - uart_tx_abort(uart_dev); - k_sem_reset(&tx_done); - k_sem_reset(&tx_aborted); - k_sem_reset(&rx_rdy); - k_sem_reset(&rx_buf_released); - k_sem_reset(&rx_disabled); -} #ifdef CONFIG_USERSPACE static void set_permissions(void) @@ -50,14 +57,22 @@ static void set_permissions(void) k_thread_access_grant(k_current_get(), &tx_done, &tx_aborted, &rx_rdy, &rx_buf_coherency, &rx_buf_released, &rx_disabled, uart_dev, &read_abort_timer); + + for (size_t i = 0; i < ARRAY_SIZE(duts); i++) { + k_thread_access_grant(k_current_get(), duts[i].dev); + } } #endif -static void uart_async_test_init(void) +static void uart_async_test_init(int idx) { static bool initialized; + uart_dev = duts[idx].dev; + uart_name = duts[idx].name; + __ASSERT_NO_MSG(device_is_ready(uart_dev)); + TC_PRINT("UART instance:%s\n", uart_name); uart_rx_disable(uart_dev); uart_tx_abort(uart_dev); k_sem_reset(&tx_done); @@ -79,7 +94,6 @@ static void uart_async_test_init(void) #endif if (!initialized) { - init_test(); initialized = true; #ifdef CONFIG_USERSPACE set_permissions(); @@ -100,7 +114,7 @@ struct test_data { #if NOCACHE_MEM static struct test_data tdata __used __NOCACHE; #else -ZTEST_BMEM struct test_data tdata; +static ZTEST_BMEM struct test_data tdata; #endif /* NOCACHE_MEM */ static void test_single_read_callback(const struct device *dev, @@ -143,11 +157,13 @@ static void test_single_read_callback(const struct device *dev, } } -ZTEST_BMEM volatile uint32_t tx_aborted_count; +static ZTEST_BMEM volatile uint32_t tx_aborted_count; static void *single_read_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); memset(&tdata, 0, sizeof(tdata)); tdata.supply_second_buffer = true; @@ -228,7 +244,9 @@ ZTEST_USER(uart_async_single_read, test_single_read) static void *multiple_rx_enable_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); memset(&tdata, 0, sizeof(tdata)); /* Reuse the callback from the single_read test case, as this test case @@ -330,10 +348,10 @@ static __aligned(32) uint8_t chained_cpy_buf[10] __used __NOCACHE; ZTEST_BMEM uint8_t chained_read_buf[2][8]; ZTEST_BMEM uint8_t chained_cpy_buf[10]; #endif /* NOCACHE_MEM */ -ZTEST_BMEM volatile uint8_t rx_data_idx; -ZTEST_BMEM uint8_t rx_buf_idx; +static ZTEST_BMEM volatile uint8_t rx_data_idx; +static ZTEST_BMEM uint8_t rx_buf_idx; -ZTEST_BMEM uint8_t *read_ptr; +static ZTEST_BMEM uint8_t *read_ptr; static void test_chained_read_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -369,7 +387,9 @@ static void test_chained_read_callback(const struct device *dev, static void *chained_read_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); uart_callback_set(uart_dev, test_chained_read_callback, NULL); @@ -417,9 +437,9 @@ ZTEST_USER(uart_async_chain_read, test_chained_read) #if NOCACHE_MEM static __aligned(32) uint8_t double_buffer[2][12] __used __NOCACHE; #else -ZTEST_BMEM uint8_t double_buffer[2][12]; +static ZTEST_BMEM uint8_t double_buffer[2][12]; #endif /* NOCACHE_MEM */ -ZTEST_DMEM uint8_t *next_buf = double_buffer[1]; +static ZTEST_DMEM uint8_t *next_buf = double_buffer[1]; static void test_double_buffer_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -450,7 +470,9 @@ static void test_double_buffer_callback(const struct device *dev, static void *double_buffer_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); uart_callback_set(uart_dev, test_double_buffer_callback, NULL); @@ -492,10 +514,11 @@ ZTEST_USER(uart_async_double_buf, test_double_buffer) static __aligned(32) uint8_t test_read_abort_rx_buf[2][100] __used __NOCACHE; static __aligned(32) uint8_t test_read_abort_read_buf[100] __used __NOCACHE; #else -ZTEST_BMEM uint8_t test_read_abort_rx_buf[2][100]; -ZTEST_BMEM uint8_t test_read_abort_read_buf[100]; +static ZTEST_BMEM uint8_t test_read_abort_rx_buf[2][100]; +static ZTEST_BMEM uint8_t test_read_abort_read_buf[100]; #endif /* NOCACHE_MEM */ -ZTEST_BMEM int test_read_abort_rx_cnt; +static ZTEST_BMEM int test_read_abort_rx_cnt; +static ZTEST_BMEM bool test_read_abort_rx_buf_req_once; static void test_read_abort_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -510,14 +533,12 @@ static void test_read_abort_callback(const struct device *dev, break; case UART_RX_BUF_REQUEST: { - static bool once; - - if (!once) { + if (!test_read_abort_rx_buf_req_once) { k_sem_give(&rx_buf_coherency); uart_rx_buf_rsp(dev, test_read_abort_rx_buf[1], sizeof(test_read_abort_rx_buf[1])); - once = true; + test_read_abort_rx_buf_req_once = true; } break; } @@ -553,8 +574,11 @@ static void read_abort_timeout(struct k_timer *timer) static void *read_abort_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); + test_read_abort_rx_buf_req_once = false; failed_in_isr = false; uart_callback_set(uart_dev, test_read_abort_callback, NULL); @@ -608,12 +632,12 @@ ZTEST_USER(uart_async_read_abort, test_read_abort) } -ZTEST_BMEM volatile size_t sent; -ZTEST_BMEM volatile size_t received; +static ZTEST_BMEM volatile size_t sent; +static ZTEST_BMEM volatile size_t received; #if NOCACHE_MEM static __aligned(32) uint8_t test_rx_buf[2][100] __used __NOCACHE; #else -ZTEST_BMEM uint8_t test_rx_buf[2][100]; +static ZTEST_BMEM uint8_t test_rx_buf[2][100]; #endif /* NOCACHE_MEM */ static void test_write_abort_callback(const struct device *dev, @@ -649,7 +673,9 @@ static void test_write_abort_callback(const struct device *dev, static void *write_abort_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); uart_callback_set(uart_dev, test_write_abort_callback, NULL); @@ -722,7 +748,9 @@ static void test_forever_timeout_callback(const struct device *dev, static void *forever_timeout_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); uart_callback_set(uart_dev, test_forever_timeout_callback, NULL); @@ -771,12 +799,12 @@ ZTEST_USER(uart_async_timeout, test_forever_timeout) #if NOCACHE_MEM -const uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; +static const uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; #else -ZTEST_DMEM uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; +static ZTEST_DMEM uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; #endif /* NOCACHE_MEM */ -ZTEST_DMEM bool chained_write_next_buf = true; -ZTEST_BMEM volatile uint8_t tx_sent; +static ZTEST_DMEM bool chained_write_next_buf = true; +static ZTEST_BMEM volatile uint8_t tx_sent; static void test_chained_write_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -811,8 +839,12 @@ static void test_chained_write_callback(const struct device *dev, static void *chained_write_setup(void) { - uart_async_test_init(); + static int idx; + + uart_async_test_init(idx++); + tx_sent = 0; + chained_write_next_buf = true; uart_callback_set(uart_dev, test_chained_write_callback, NULL); return NULL; @@ -862,13 +894,13 @@ ZTEST_BMEM uint8_t long_rx_buf[RX_LONG_BUFFER]; ZTEST_BMEM uint8_t long_rx_buf2[RX_LONG_BUFFER]; ZTEST_BMEM uint8_t long_tx_buf[TX_LONG_BUFFER]; #endif /* NOCACHE_MEM */ -ZTEST_BMEM volatile uint8_t evt_num; -ZTEST_BMEM size_t long_received[2]; +static ZTEST_BMEM volatile uint8_t evt_num; +static ZTEST_BMEM size_t long_received[2]; +static ZTEST_BMEM uint8_t *long_next_buffer; static void test_long_buffers_callback(const struct device *dev, struct uart_event *evt, void *user_data) { - static uint8_t *next_buffer = long_rx_buf2; switch (evt->type) { case UART_TX_DONE: @@ -890,8 +922,8 @@ static void test_long_buffers_callback(const struct device *dev, k_sem_give(&rx_disabled); break; case UART_RX_BUF_REQUEST: - uart_rx_buf_rsp(dev, next_buffer, RX_LONG_BUFFER); - next_buffer = (next_buffer == long_rx_buf2) ? long_rx_buf : long_rx_buf2; + uart_rx_buf_rsp(dev, long_next_buffer, RX_LONG_BUFFER); + long_next_buffer = (long_next_buffer == long_rx_buf2) ? long_rx_buf : long_rx_buf2; break; default: break; @@ -900,8 +932,12 @@ static void test_long_buffers_callback(const struct device *dev, static void *long_buffers_setup(void) { - uart_async_test_init(); + static int idx; + uart_async_test_init(idx++); + + evt_num = 0; + long_next_buffer = long_rx_buf2; uart_callback_set(uart_dev, test_long_buffers_callback, NULL); return NULL; @@ -983,3 +1019,12 @@ ZTEST_SUITE(uart_async_write_abort, NULL, write_abort_setup, ZTEST_SUITE(uart_async_timeout, NULL, forever_timeout_setup, NULL, NULL, NULL); + +void test_main(void) +{ + /* Run all suites for each dut UART. Setup function for each suite is picking + * next UART from the array. + */ + ztest_run_all(NULL, false, ARRAY_SIZE(duts), 1); + ztest_verify_all_test_suites_ran(); +} diff --git a/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 000000000000..a1b825882f50 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,6 @@ +#include "../../../boards/nrf54h20dk_nrf54h20_common.dtsi" + +&dut { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; diff --git a/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/prj.conf b/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/prj.conf new file mode 100644 index 000000000000..b2a4ba591044 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/sysbuild/vpr_launcher/prj.conf @@ -0,0 +1 @@ +# nothing here diff --git a/tests/drivers/uart/uart_async_dual/CMakeLists.txt b/tests/drivers/uart/uart_async_dual/CMakeLists.txt new file mode 100644 index 000000000000..8dcea87b6487 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/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(uart_async_dual) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/drivers/uart/uart_async_dual/Kconfig b/tests/drivers/uart/uart_async_dual/Kconfig new file mode 100644 index 000000000000..6e80ec3a7957 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/Kconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config UART_ASYNC_DUAL_TEST_TIMEOUT + int "Single test case length (in milliseconds)" + # For the simulated devices, which are run by default in CI, we set it to less to not spend too + # much CI time + default 500 if SOC_SERIES_BSIM_NRFXX + default 3000 + help + For how many loops will the stress test run. The higher this number the longer the + test and therefore the higher likelihood an unlikely race/event will be triggered. + +config PM_RUNTIME_IN_TEST + bool "Use runtime PM in the test" + select PM_DEVICE + select PM_DEVICE_RUNTIME + +# Include Zephyr's Kconfig +source "Kconfig" diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay new file mode 100644 index 000000000000..ddae6f682f97 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf52_bsim.overlay @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + , + , + ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; +}; + +dut: &uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; + zephyr,pm-device-runtime-auto; +}; + +&timer0 { + status = "okay"; + interrupts = <8 0>; +}; + +/ { + busy-sim { + compatible = "vnd,busy-sim"; + status = "okay"; + counter = <&timer0>; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi new file mode 100644 index 000000000000..28c3879984aa --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + uart134_alt_default: uart134_alt_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart134_alt_sleep: uart134_alt_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart137_alt_default: uart137_alt_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart137_alt_sleep: uart137_alt_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart120_default_alt: uart120_default_alt { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart120_sleep_alt: uart120_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; +}; + +dut: &uart134 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart134_alt_default>; + pinctrl-1 = <&uart134_alt_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; + zephyr,pm-device-runtime-auto; +}; + +dut_aux: &uart137 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart137_alt_default>; + pinctrl-1 = <&uart137_alt_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; + zephyr,pm-device-runtime-auto; +}; + +dut2: &uart120 { + status = "okay"; + pinctrl-0 = <&uart120_default_alt>; + pinctrl-1 = <&uart120_sleep_alt>; + pinctrl-names = "default", "sleep"; + current-speed = <115200>; + hw-flow-control; + zephyr,pm-device-runtime-auto; +}; + +&timer137 { + status = "okay"; + interrupts = <467 0>; +}; + +/ { + busy-sim { + compatible = "vnd,busy-sim"; + status = "okay"; + counter = <&timer137>; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 000000000000..97aee563c255 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1 @@ +CONFIG_UART_ASYNC_TX_CACHE_SIZE=64 diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 000000000000..23ab89a1b8b1 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&dut { + memory-regions = <&cpuapp_dma_region>; +}; + +&dut_aux { + memory-regions = <&cpuapp_dma_region>; +}; + +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay new file mode 100644 index 000000000000..1121082094b7 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&timer137 { + interrupts = <467 (NRF_DEFAULT_IRQ_PRIORITY + 1)>; +}; + +&dut2 { + status = "disabled"; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.conf b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.conf new file mode 100644 index 000000000000..033183df85dd --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.conf @@ -0,0 +1 @@ +CONFIG_UART_ASYNC_TX_CACHE_SIZE=16 diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 000000000000..b177bf8d102e --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&cpurad_dma_region { + compatible = "zephyr,memory-region"; + reg = <0x1e80 0x180>; +}; + +&dut { + memory-regions = <&cpurad_dma_region>; +}; + +&dut_aux { + memory-regions = <&cpurad_dma_region>; +}; + +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; + +&timer131 { + status = "okay"; + prescaler = <0>; +}; + +/ { + chosen { + zephyr,cpu-stats-counter = &timer131; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 000000000000..fe79690cbbad --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + uart21_default: uart21_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart21_sleep: uart21_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart22_default: uart22_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart22_sleep: uart22_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +dut: &uart21 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart21_default>; + pinctrl-1 = <&uart21_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; + zephyr,pm-device-runtime-auto; +}; + +dut_aux: &uart22 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart22_default>; + pinctrl-1 = <&uart22_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; + zephyr,pm-device-runtime-auto; +}; + +&timer20 { + status = "okay"; + interrupts = <202 0>; +}; + +/ { + busy-sim { + compatible = "vnd,busy-sim"; + status = "okay"; + counter = <&timer20>; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.conf b/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.conf new file mode 100644 index 000000000000..4da3788618f3 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.conf @@ -0,0 +1 @@ +CONFIG_UART_NRFX_UARTE_ENHANCED_RX=y diff --git a/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.overlay b/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.overlay new file mode 100644 index 000000000000..d47b0db3ad9c --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/boards/nrf9160dk_nrf9160.overlay @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + uart1_default: uart1_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart2_default: uart2_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart2_sleep: uart2_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +dut: &uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +dut_aux: &uart2 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart2_default>; + pinctrl-1 = <&uart2_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; + +&timer2 { + status = "okay"; + interrupts = <17 0>; +}; + +/ { + busy-sim { + compatible = "vnd,busy-sim"; + status = "okay"; + counter = <&timer2>; + }; +}; diff --git a/tests/drivers/uart/uart_async_dual/prj.conf b/tests/drivers/uart/uart_async_dual/prj.conf new file mode 100644 index 000000000000..8c564ed02b39 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/prj.conf @@ -0,0 +1,6 @@ +CONFIG_ZTEST=y +CONFIG_RING_BUFFER=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_SERIAL=y +CONFIG_UART_ASYNC_API=y +CONFIG_UART_USE_RUNTIME_CONFIGURE=y diff --git a/tests/drivers/uart/uart_async_dual/src/main.c b/tests/drivers/uart/uart_async_dual/src/main.c new file mode 100644 index 000000000000..02f148eef677 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/src/main.c @@ -0,0 +1,813 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(test); + +#if DT_NODE_EXISTS(DT_NODELABEL(dut)) +#define DUT_NODE DT_NODELABEL(dut) +#else +#error "dut not defined" +#endif + +#if DT_NODE_EXISTS(DT_NODELABEL(dut_aux)) +#define DUT_AUX_NODE DT_NODELABEL(dut_aux) +#else +#define DUT_AUX_NODE DT_NODELABEL(dut) +#endif + +#define TX_TIMEOUT 100000 +#define RX_TIMEOUT 2000 + +#define MAX_PACKET_LEN 128 + +struct dut_data { + const struct device *dev; + const struct device *dev_aux; + const char *name; + const char *name_aux; +}; + +ZTEST_DMEM struct dut_data duts[] = { + { + .dev = DEVICE_DT_GET(DUT_NODE), + .dev_aux = DT_SAME_NODE(DUT_NODE, DUT_AUX_NODE) ? + NULL : DEVICE_DT_GET(DUT_AUX_NODE), + .name = DT_NODE_FULL_NAME(DUT_NODE), + .name_aux = DT_SAME_NODE(DUT_NODE, DUT_AUX_NODE) ? + NULL : DT_NODE_FULL_NAME(DUT_AUX_NODE), + }, +#if DT_NODE_EXISTS(DT_NODELABEL(dut2)) && DT_NODE_HAS_STATUS(DT_NODELABEL(dut2), okay) + { + .dev = DEVICE_DT_GET(DT_NODELABEL(dut2)), + .name = DT_NODE_FULL_NAME(DT_NODELABEL(dut2)), +#if DT_NODE_EXISTS(DT_NODELABEL(dut_aux2)) && DT_NODE_HAS_STATUS(DT_NODELABEL(dut_aux2), okay) + .dev_aux = DEVICE_DT_GET(DT_NODELABEL(dut_aux2)), + .name_aux = DT_NODE_FULL_NAME(DT_NODELABEL(dut_aux2)), +#endif + }, +#endif +}; + +static void pm_check(const struct device *dev, const struct device *second_dev, bool exp_on, + int line) +{ + if (!IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + return; + } + + if (dev == second_dev) { + return; + } + + enum pm_device_state state; + int err; + int cnt; + + cnt = pm_device_runtime_usage(dev); + err = pm_device_state_get(dev, &state); + zassert_equal(err, 0); + + if (exp_on) { + zassert_not_equal(cnt, 0, "Wrong PM cnt:%d, line:%d", cnt, line); + zassert_equal(state, PM_DEVICE_STATE_ACTIVE, + "Wrong PM state %s, line:%d", pm_device_state_str(state), line); + return; + } + + /* Expect device to be off. */ + zassert_equal(cnt, 0, "Wrong PM count:%d, line:%d", cnt, line); + zassert_equal(state, PM_DEVICE_STATE_SUSPENDED, + "Wrong PM state %s, line:%d", pm_device_state_str(state), line); +} + +#define PM_CHECK(dev, second_dev, exp_on) pm_check(dev, second_dev, exp_on, __LINE__) + +static const struct device *rx_dev; +static const struct device *tx_dev; + +enum test_tx_mode { + TX_BULK, + TX_PACKETS, +}; + +struct test_tx_data { + uint8_t buf[512]; + struct ring_buf rbuf; + atomic_t busy; + uint8_t packet_len; + uint8_t cnt; + volatile bool cont; + volatile enum test_tx_mode mode; + struct k_sem sem; +}; + +enum test_rx_state { + RX_HDR, + RX_PAYLOAD +}; + +enum test_rx_mode { + RX_CONT, + RX_DIS, +}; + +struct test_rx_data { + uint8_t hdr[1]; + uint8_t buf[256]; + uint32_t rx_cnt; + enum test_rx_state state; + enum test_rx_mode mode; + volatile bool cont; + bool buf_req; + struct k_sem sem; +}; + +static struct test_tx_data tx_data; +static struct test_rx_data rx_data; + +static void fill_tx(struct test_tx_data *data) +{ + uint8_t *buf; + uint32_t len; + int err; + + if (data->mode == TX_PACKETS) { + err = k_sem_take(&data->sem, K_MSEC(100)); + if (err < 0 && !data->cont) { + return; + } + zassert_equal(err, 0); + + uint8_t len = sys_rand8_get(); + + len = len % MAX_PACKET_LEN; + len = MAX(2, len); + + data->packet_len = len; + for (int i = 0; i < len; i++) { + data->buf[i] = len - i; + } + + return; + } + + while ((len = ring_buf_put_claim(&data->rbuf, &buf, 255)) > 1) { + uint8_t r = (sys_rand8_get() % MAX_PACKET_LEN) % len; + uint8_t packet_len = MAX(r, 2); + uint8_t rem = len - packet_len; + + packet_len = (rem < 3) ? len : packet_len; + buf[0] = packet_len; + for (int i = 1; i < packet_len; i++) { + buf[i] = packet_len - i; + } + + ring_buf_put_finish(&data->rbuf, packet_len); + } +} + +static void try_tx(const struct device *dev, bool irq) +{ + uint8_t *buf; + uint32_t len; + int err; + + if (!tx_data.cont) { + rx_data.cont = false; + return; + } + + if ((tx_data.mode == TX_PACKETS) && (tx_data.packet_len > 0)) { + uint8_t len = tx_data.packet_len; + + tx_data.packet_len = 0; + err = uart_tx(dev, tx_data.buf, len, TX_TIMEOUT); + zassert_equal(err, 0, + "Unexpected err:%d irq:%d cont:%d\n", + err, irq, tx_data.cont); + return; + } + zassert_true(tx_data.mode == TX_BULK); + + if (!atomic_cas(&tx_data.busy, 0, 1)) { + return; + } + + len = ring_buf_get_claim(&tx_data.rbuf, &buf, 255); + if (len > 0) { + err = uart_tx(dev, buf, len, TX_TIMEOUT); + zassert_equal(err, 0, + "Unexpected err:%d irq:%d cont:%d\n", + err, irq, tx_data.cont); + } +} + +static void on_tx_done(const struct device *dev, struct uart_event *evt) +{ + if (tx_data.mode == TX_PACKETS) { + k_sem_give(&tx_data.sem); + return; + } + + /* Finish previous data chunk and start new if any pending. */ + ring_buf_get_finish(&tx_data.rbuf, evt->data.tx.len); + atomic_set(&tx_data.busy, 0); + try_tx(dev, true); +} + +static void on_rx_rdy(const struct device *dev, struct uart_event *evt) +{ + uint32_t len = evt->data.rx.len; + uint32_t off = evt->data.rx.offset; + int err; + + if (!rx_data.cont) { + return; + } + + rx_data.rx_cnt += evt->data.rx.len; + if (evt->data.rx.buf == rx_data.hdr) { + rx_data.state = RX_PAYLOAD; + if ((rx_data.mode == RX_CONT) && rx_data.buf_req) { + size_t l = rx_data.hdr[0] - 1; + + zassert_true(l > 0); + rx_data.buf_req = false; + err = uart_rx_buf_rsp(dev, rx_data.buf, rx_data.hdr[0] - 1); + } + } else { + /* Payload received */ + rx_data.state = RX_HDR; + zassert_equal(len, rx_data.hdr[0] - 1); + + for (int i = 0; i < len; i++) { + bool ok = evt->data.rx.buf[off + i] == (uint8_t)(len - i); + + if (!ok) { + LOG_ERR("Unexpected data at %d, exp:%02x got:%02x", + i, len - i, evt->data.rx.buf[off + i]); + } + + zassert_true(ok, "Unexpected data at %d, exp:%02x got:%02x", + i, len - i, evt->data.rx.buf[off + i]); + if (!ok) { + rx_data.cont = false; + tx_data.cont = false; + /* Avoid flood of errors as we are in the interrupt and ztest + * cannot abort from here. + */ + return; + } + } + if ((rx_data.mode == RX_CONT) && rx_data.buf_req) { + rx_data.buf_req = false; + err = uart_rx_buf_rsp(dev, rx_data.hdr, 1); + } + } +} + +static void on_rx_dis(const struct device *dev, struct uart_event *evt, void *user_data) +{ + ARG_UNUSED(evt); + struct test_rx_data *data = user_data; + int err; + uint8_t *buf = (data->state == RX_HDR) ? data->hdr : data->buf; + uint32_t len = (data->state == RX_HDR) ? 1 : (data->hdr[0] - 1); + + data->buf_req = false; + + if (!data->cont) { + return; + } + + + zassert_true(len > 0); + err = uart_rx_enable(dev, buf, len, RX_TIMEOUT); + zassert_equal(err, 0, "Unexpected err:%d", err); +} + +static void test_end(void) +{ + tx_data.cont = false; +} + +static void test_timeout(struct k_timer *timer) +{ + test_end(); +} + +static K_TIMER_DEFINE(test_timer, test_timeout, NULL); + +static void uart_callback(const struct device *dev, struct uart_event *evt, void *user_data) +{ + switch (evt->type) { + case UART_TX_DONE: + zassert_true(dev == tx_dev); + on_tx_done(dev, evt); + break; + case UART_TX_ABORTED: + zassert_true(dev == tx_dev); + zassert_false(tx_data.cont, + "Unexpected TX abort, receiver not reading data on time"); + break; + case UART_RX_RDY: + zassert_true(dev == rx_dev); + on_rx_rdy(dev, evt); + break; + case UART_RX_BUF_RELEASED: + zassert_true(dev == rx_dev); + break; + case UART_RX_BUF_REQUEST: + rx_data.buf_req = true; + zassert_true(dev == rx_dev); + break; + case UART_RX_DISABLED: + zassert_true(dev == rx_dev); + on_rx_dis(dev, evt, &rx_data); + break; + case UART_RX_STOPPED: + zassert_true(false); + break; + default: + zassert_true(false); + break; + } +} + +static void config_baudrate(uint32_t rate) +{ + struct uart_config config; + int err; + + err = uart_config_get(rx_dev, &config); + zassert_equal(err, 0, "Unexpected err:%d", err); + + config.baudrate = rate; + + err = uart_configure(rx_dev, &config); + zassert_equal(err, 0, "Unexpected err:%d", err); + + if (rx_dev != tx_dev) { + err = uart_configure(tx_dev, &config); + zassert_equal(err, 0, "Unexpected err:%d", err); + } +} + +/* Test is running following scenario. Transmitter is sending packets which + * has 1 byte header with length followed by the payload. Transmitter can send + * packets in two modes: bulk where data is send in chunks without gaps between + * packets or in packet mode where transmitter sends packet by packet. + * Receiver receives the header and sets reception of the payload based on the + * length in the header. It can also work in two modes: continuous (CONT) where new + * transfer is started from UART_RX_RDY event or slower mode (DIS) where reception is + * started from UART_RX_DISABLED event. + * + * Test has busy simulator running if it is enabled in the configuration. + */ +static void var_packet_hwfc(uint32_t baudrate, bool tx_packets, bool cont) +{ + int err; + + config_baudrate(baudrate); + + if (IS_ENABLED(CONFIG_TEST_BUSY_SIM)) { + uint32_t active_avg = (baudrate == 1000000) ? 5 : 30; + uint32_t active_delta = (baudrate == 1000000) ? 2 : 10; + + busy_sim_start(active_avg, active_delta, 100, 50, NULL); + } + + memset(&tx_data, 0, sizeof(tx_data)); + memset(&rx_data, 0, sizeof(rx_data)); + tx_data.cont = true; + tx_data.mode = tx_packets ? TX_PACKETS : TX_BULK; + k_sem_init(&tx_data.sem, tx_packets ? 1 : 0, 1); + + rx_data.cont = true; + rx_data.rx_cnt = 0; + rx_data.state = RX_HDR; + rx_data.mode = cont ? RX_CONT : RX_DIS; + + ring_buf_init(&tx_data.rbuf, sizeof(tx_data.buf), tx_data.buf); + + k_timer_start(&test_timer, K_MSEC(CONFIG_UART_ASYNC_DUAL_TEST_TIMEOUT), K_NO_WAIT); + + err = uart_callback_set(rx_dev, uart_callback, &rx_data); + zassert_equal(err, 0, "Unexpected err:%d", err); + + err = uart_callback_set(tx_dev, uart_callback, &tx_data); + zassert_equal(err, 0, "Unexpected err:%d", err); + + on_rx_dis(rx_dev, NULL, &rx_data); + + while (tx_data.cont || rx_data.cont) { + fill_tx(&tx_data); + k_msleep(1); + try_tx(tx_dev, false); + } + + if (IS_ENABLED(CONFIG_TEST_BUSY_SIM)) { + busy_sim_stop(); + } + + (void)uart_tx_abort(tx_dev); + (void)uart_rx_disable(rx_dev); + + /* Flush all TX data that may be already started. */ + k_msleep(10); + (void)uart_rx_enable(rx_dev, rx_data.buf, sizeof(rx_data.buf), RX_TIMEOUT); + k_msleep(10); + (void)uart_rx_disable(rx_dev); + k_msleep(10); + + TC_PRINT("Received %d bytes for %d ms\n", + rx_data.rx_cnt, CONFIG_UART_ASYNC_DUAL_TEST_TIMEOUT); + zassert_true(rx_data.rx_cnt > 1000, "Unexected RX cnt: %d", rx_data.rx_cnt); +} + +ZTEST(uart_async_dual, test_var_packets_tx_bulk_dis_hwfc) +{ + /* TX in bulk mode, RX in DIS mode, 115k2 */ + var_packet_hwfc(115200, false, false); +} + +ZTEST(uart_async_dual, test_var_packets_tx_bulk_cont_hwfc) +{ + /* TX in bulk mode, RX in CONT mode, 115k2 */ + var_packet_hwfc(115200, false, true); +} + +ZTEST(uart_async_dual, test_var_packets_tx_bulk_dis_hwfc_1m) +{ + /* TX in bulk mode, RX in DIS mode, 1M */ + var_packet_hwfc(1000000, false, false); +} + +ZTEST(uart_async_dual, test_var_packets_tx_bulk_cont_hwfc_1m) +{ + /* TX in bulk mode, RX in CONT mode, 1M */ + var_packet_hwfc(1000000, false, true); +} + +ZTEST(uart_async_dual, test_var_packets_dis_hwfc) +{ + /* TX in packet mode, RX in DIS mode, 115k2 */ + var_packet_hwfc(115200, true, false); +} + +ZTEST(uart_async_dual, test_var_packets_cont_hwfc) +{ + /* TX in packet mode, RX in CONT mode, 115k2 */ + var_packet_hwfc(115200, true, true); +} + +ZTEST(uart_async_dual, test_var_packets_dis_hwfc_1m) +{ + /* TX in packet mode, RX in DIS mode, 1M */ + var_packet_hwfc(1000000, true, false); +} + +ZTEST(uart_async_dual, test_var_packets_cont_hwfc_1m) +{ + /* TX in packet mode, RX in CONT mode, 1M */ + var_packet_hwfc(1000000, true, true); +} + +static void hci_like_callback(const struct device *dev, struct uart_event *evt, void *user_data) +{ + switch (evt->type) { + case UART_TX_DONE: + + zassert_true(dev == tx_dev); + if (IS_ENABLED(CONFIG_PM_RUNTIME_IN_TEST)) { + PM_CHECK(tx_dev, rx_dev, true); + pm_device_runtime_put(tx_dev); + } + PM_CHECK(tx_dev, rx_dev, false); + k_sem_give(&tx_data.sem); + break; + case UART_TX_ABORTED: + zassert_true(dev == tx_dev); + if (IS_ENABLED(CONFIG_PM_RUNTIME_IN_TEST)) { + pm_device_runtime_put(tx_dev); + } + zassert_false(tx_data.cont, + "Unexpected TX abort, receiver not reading data on time"); + break; + case UART_RX_RDY: + rx_data.rx_cnt += evt->data.rx.len; + zassert_true(dev == rx_dev); + break; + case UART_RX_BUF_RELEASED: + zassert_true(dev == rx_dev); + break; + case UART_RX_BUF_REQUEST: + zassert_true(dev == rx_dev); + break; + case UART_RX_DISABLED: + zassert_true(dev == rx_dev); + k_sem_give(&rx_data.sem); + break; + case UART_RX_STOPPED: + zassert_true(false); + break; + default: + zassert_true(false); + break; + } +} + +static bool rx(uint8_t *buf, size_t len) +{ + int err; + + err = uart_rx_enable(rx_dev, buf, len, RX_TIMEOUT); + zassert_equal(err, 0, "Unexpected err:%d", err); + + err = k_sem_take(&rx_data.sem, K_MSEC(100)); + if ((err < 0) || !tx_data.cont) { + zassert_false(tx_data.cont); + err = uart_rx_disable(rx_dev); + if (err == 0) { + err = k_sem_take(&rx_data.sem, K_MSEC(100)); + zassert_equal(err, 0, "Unexpected err:%d", err); + } + + return false; + } + + return true; +} + +static void check_pre_hdr(uint8_t *buf, uint8_t last_hdr) +{ + uint8_t exp_idx = (last_hdr + 1) & 0x7F; + + zassert_true(buf[0] & 0x80); + zassert_equal(exp_idx, buf[0] & 0x7F); +} + +static uint8_t get_len(uint8_t *buf) +{ + static const uint8_t exp_buf[] = {'a', 'b', 'c'}; + int rv; + + rv = memcmp(buf, exp_buf, sizeof(exp_buf)); + + zassert_equal(rv, 0, "exp: %02x %02x %02x, got: %02x %02x %02x", + exp_buf[0], exp_buf[1], exp_buf[2], buf[0], buf[1], buf[2]); + + return buf[sizeof(exp_buf)]; +} + +static void check_payload(uint8_t *buf, uint8_t len) +{ + for (int i = 0; i < len; i++) { + uint8_t exp_val = len - i; + bool ok = buf[i] == exp_val; + + zassert_true(ok, "Unexpected byte at %d, got:%02x exp:%02x", i, buf[i], exp_val); + if (!ok) { + test_end(); + return; + } + } +} + +static void hci_like_tx_prepare(struct test_tx_data *tx_data) +{ + int idx = tx_data->cnt & 0x1 ? sizeof(tx_data->buf) / 2 : 0; + uint8_t *buf = &tx_data->buf[idx]; + uint8_t len = sys_rand8_get() & 0x1F; + + len = MAX(1, len); + + *buf++ = 0x80 | (tx_data->cnt & 0x7F); + *buf++ = 'a'; + *buf++ = 'b'; + *buf++ = 'c'; + *buf++ = len; + + for (int i = 0; i < len; i++) { + *buf++ = len - i; + } + + tx_data->cnt++; +} + +static void hci_like_tx(struct test_tx_data *tx_data) +{ + int idx = tx_data->cnt & 0x1 ? 0 : sizeof(tx_data->buf) / 2; + uint8_t *buf = &tx_data->buf[idx]; + uint8_t len = buf[4] + 5; + int err; + + if (IS_ENABLED(CONFIG_PM_RUNTIME_IN_TEST)) { + pm_device_runtime_get(tx_dev); + } + + err = uart_tx(tx_dev, buf, len, TX_TIMEOUT); + zassert_equal(err, 0, "Unexpected err:%d", err); +} + +static void hci_like_tx_thread_entry(void *p1, void *p2, void *p3) +{ + int err; + + while (tx_data.cont) { + hci_like_tx_prepare(&tx_data); + + err = k_sem_take(&tx_data.sem, K_MSEC(500)); + if (err < 0) { + break; + } + zassert_equal(err, 0, "Unexpected err:%d", err); + + hci_like_tx(&tx_data); + } +} + + +static void hci_like_rx(void) +{ + uint8_t last_hdr = 0xff; + uint8_t len; + bool cont; + bool explicit_pm = IS_ENABLED(CONFIG_PM_RUNTIME_IN_TEST); + + while (1) { + if (explicit_pm) { + pm_device_runtime_get(rx_dev); + } + + cont = rx(rx_data.buf, 1); + if (!cont) { + if (explicit_pm) { + pm_device_runtime_put(rx_dev); + } + break; + } + check_pre_hdr(rx_data.buf, last_hdr); + last_hdr = rx_data.buf[0]; + + /* If explicitly requested device to stay on in should be on. + * If application did not touch PM, device should be off. + */ + PM_CHECK(rx_dev, tx_dev, explicit_pm); + + cont = rx(rx_data.buf, 4); + if (!cont) { + if (explicit_pm) { + pm_device_runtime_put(rx_dev); + } + break; + } + len = get_len(rx_data.buf); + + /* If explicitly requested device to stay on in should be on. + * If application did not touch PM, device should be off. + */ + PM_CHECK(rx_dev, tx_dev, explicit_pm); + + cont = rx(rx_data.buf, len); + if (!cont) { + if (explicit_pm) { + pm_device_runtime_put(rx_dev); + } + break; + } + + if (explicit_pm) { + pm_device_runtime_put(rx_dev); + } + + /* Device shall be released and off. */ + PM_CHECK(rx_dev, tx_dev, false); + + check_payload(rx_data.buf, len); + } +} + +#define HCI_LIKE_TX_STACK_SIZE 2048 +static K_THREAD_STACK_DEFINE(hci_like_tx_thread_stack, HCI_LIKE_TX_STACK_SIZE); +static struct k_thread hci_like_tx_thread; + +/* Test is emulating behavior that is implemented in the bluetooth HCI controller sample + * which is using UART asynchronous API. Each packet consists of 3 parts: 1 byte header + * indicating a type, 4 byte second header with length of the variable part which is + * a third part. + * + * Receiver sets reception of each part after receiver is disabled. + * + * If enabled, busy simulator is used in the test. + */ +static void hci_like_test(uint32_t baudrate) +{ + int err; + + config_baudrate(baudrate); + + if (IS_ENABLED(CONFIG_TEST_BUSY_SIM)) { + uint32_t active_avg = (baudrate == 1000000) ? 10 : 50; + uint32_t active_delta = (baudrate == 1000000) ? 5 : 20; + + busy_sim_start(active_avg, active_delta, 100, 50, NULL); + } + + memset(&tx_data, 0, sizeof(tx_data)); + memset(&rx_data, 0, sizeof(rx_data)); + tx_data.cnt = 0; + tx_data.cont = true; + rx_data.cont = true; + + k_sem_init(&tx_data.sem, 1, 1); + k_sem_init(&rx_data.sem, 0, 1); + + k_timer_start(&test_timer, K_MSEC(CONFIG_UART_ASYNC_DUAL_TEST_TIMEOUT), K_NO_WAIT); + + err = uart_callback_set(rx_dev, hci_like_callback, NULL); + zassert_equal(err, 0); + + err = uart_callback_set(tx_dev, hci_like_callback, NULL); + zassert_equal(err, 0); + + k_thread_create(&hci_like_tx_thread, hci_like_tx_thread_stack, + K_THREAD_STACK_SIZEOF(hci_like_tx_thread_stack), + hci_like_tx_thread_entry, NULL, NULL, NULL, + K_PRIO_COOP(7), 0, K_MSEC(10)); + + k_msleep(1); + + hci_like_rx(); + + if (IS_ENABLED(CONFIG_TEST_BUSY_SIM)) { + busy_sim_stop(); + } + + /* Flush data. */ + (void)uart_tx_abort(tx_dev); + k_msleep(10); + PM_CHECK(tx_dev, rx_dev, false); + + (void)uart_rx_enable(rx_dev, rx_data.buf, sizeof(rx_data.buf), RX_TIMEOUT); + k_msleep(1); + (void)uart_rx_disable(rx_dev); + + k_thread_abort(&hci_like_tx_thread); + k_msleep(10); + + TC_PRINT("Received %d bytes for %d ms\n", + rx_data.rx_cnt, CONFIG_UART_ASYNC_DUAL_TEST_TIMEOUT); +} + +ZTEST(uart_async_dual, test_hci_like_115k) +{ + /* HCI like test at 115k2 */ + hci_like_test(115200); +} + +ZTEST(uart_async_dual, test_hci_like_1M) +{ + /* HCI like test at 1M */ + hci_like_test(1000000); +} + +static void *setup(void) +{ + static int idx; + + rx_dev = duts[idx].dev; + if (duts[idx].dev_aux == NULL) { + TC_PRINT("Single UART test on instance:%s\n", duts[idx].name); + tx_dev = rx_dev; + } else { + TC_PRINT("Dual UART test on instances:%s and %s\n", + duts[idx].name, duts[idx].name_aux); + tx_dev = duts[idx].dev_aux; + } + idx++; + + zassert_true(device_is_ready(rx_dev)); + zassert_true(device_is_ready(tx_dev)); + + return NULL; +} + +ZTEST_SUITE(uart_async_dual, NULL, setup, NULL, NULL, NULL); + +void test_main(void) +{ + ztest_run_all(NULL, false, ARRAY_SIZE(duts), 1); + ztest_verify_all_test_suites_ran(); +} diff --git a/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 000000000000..fcdc838a54e4 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,11 @@ +#include "../../../boards/nrf54h20dk_nrf54h20_common.dtsi" + +&dut { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; + +&dut_aux { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; diff --git a/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/prj.conf b/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/prj.conf new file mode 100644 index 000000000000..b2a4ba591044 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/sysbuild/vpr_launcher/prj.conf @@ -0,0 +1 @@ +# nothing here diff --git a/tests/drivers/uart/uart_async_dual/testcase.yaml b/tests/drivers/uart/uart_async_dual/testcase.yaml new file mode 100644 index 000000000000..9c9b4fcde5a5 --- /dev/null +++ b/tests/drivers/uart/uart_async_dual/testcase.yaml @@ -0,0 +1,60 @@ +common: + tags: + - drivers + - uart + timeout: 120 +tests: + drivers.uart.async_dual: + harness: ztest + harness_config: + fixture: uart_loopback + depends_on: gpio + platform_allow: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad + - nrf54h20dk/nrf54h20/cpuppr + - nrf9160dk/nrf9160 + - nrf52_bsim + drivers.uart.async_dual.busy_sim: + harness: ztest + harness_config: + fixture: uart_loopback + depends_on: gpio + platform_allow: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad + - nrf9160dk/nrf9160 + - nrf52_bsim + extra_configs: + - CONFIG_TEST_BUSY_SIM=y + drivers.uart.async_dual.pm_runtime: + harness: ztest + harness_config: + fixture: uart_loopback + depends_on: gpio + platform_allow: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad + - nrf54h20dk/nrf54h20/cpuppr + - nrf9160dk/nrf9160 + - nrf52_bsim + extra_configs: + - CONFIG_PM_DEVICE_RUNTIME=y + - CONFIG_PM_DEVICE=y + drivers.uart.async_dual.pm_runtime.explicit: + harness: ztest + harness_config: + fixture: uart_loopback + depends_on: gpio + platform_allow: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad + - nrf54h20dk/nrf54h20/cpuppr + - nrf9160dk/nrf9160 + - nrf52_bsim + extra_configs: + - CONFIG_PM_RUNTIME_IN_TEST=y diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi index c102d617f900..7a76d46f3f07 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -19,6 +19,27 @@ low-power-enable; }; }; + uart120_default_alt: uart120_default_alt { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart120_sleep_alt: uart120_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; }; dut: &uart137 { @@ -30,7 +51,15 @@ dut: &uart137 { hw-flow-control; }; -/* Use timer137 as only this one can generate interrupts on cpusys. */ +dut2: &uart120 { + status = "okay"; + pinctrl-0 = <&uart120_default_alt>; + pinctrl-1 = <&uart120_sleep_alt>; + pinctrl-names = "default", "sleep"; + current-speed = <115200>; + hw-flow-control; +}; + counter_dev: &timer137 { status = "okay"; }; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index c6ff4eb77af3..18889762fb71 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -6,6 +6,14 @@ memory-regions = <&cpuapp_dma_region>; }; +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; + &grtc { interrupts = <109 2>; }; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay new file mode 100644 index 000000000000..d846a5debd78 --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuppr.overlay @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&timer137 { + interrupts = <467 (NRF_DEFAULT_IRQ_PRIORITY + 1)>; +}; + +&dut { + interrupts = <470 (NRF_DEFAULT_IRQ_PRIORITY + 1)>; +}; + +/* PPR cannot use that instance. */ +&uart120 { + status = "disabled" +}; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay index 0ded983c2af8..fb124227771b 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -6,6 +6,14 @@ memory-regions = <&cpurad_dma_region>; }; +&dma_fast_region { + status = "okay"; +}; + +&dut2 { + memory-regions = <&dma_fast_region>; +}; + &grtc { interrupts = <109 2>; }; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/prj.conf b/tests/drivers/uart/uart_mix_fifo_poll/prj.conf index fa22b3a47b89..41c7920a1f8a 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/prj.conf +++ b/tests/drivers/uart/uart_mix_fifo_poll/prj.conf @@ -1,11 +1,17 @@ CONFIG_SERIAL=y CONFIG_ZTEST=y -CONFIG_TEST_USERSPACE=y +CONFIG_TEST_USERSPACE=n CONFIG_ZTEST_THREAD_PRIORITY=5 CONFIG_MAIN_STACK_SIZE=2048 CONFIG_ZTEST_STACK_SIZE=2048 CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_COUNTER=y -# CONFIG_NO_OPTIMIZATIONS=y +CONFIG_OUTPUT_DISASSEMBLY=y +#CONFIG_NO_OPTIMIZATIONS=y # CONFIG_LOG_MODE_MINIMAL=n +#CONFIG_LOG=y +#CONFIG_LOG_BUFFER_SIZE=16384 +#CONFIG_TEST_LOGGING_DEFAULTS=n + +CONFIG_TEST_EXTRA_STACK_SIZE=2048 diff --git a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c index eaebe8e132e5..e3935372dce4 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c +++ b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c @@ -15,6 +15,8 @@ #include #include #include +#include +LOG_MODULE_REGISTER(test, 0); /* RX and TX pins have to be connected together*/ #if DT_NODE_EXISTS(DT_NODELABEL(dut)) @@ -40,6 +42,24 @@ struct rx_source { uint8_t prev; }; +struct dut_data { + const struct device *dev; + const char *name; +}; + +static struct dut_data duts[] = { + { + .dev = DEVICE_DT_GET(UART_NODE), + .name = DT_NODE_FULL_NAME(UART_NODE), + }, +#if DT_NODE_EXISTS(DT_NODELABEL(dut2)) + { + .dev = DEVICE_DT_GET(DT_NODELABEL(dut2)), + .name = DT_NODE_FULL_NAME(DT_NODELABEL(dut2)), + }, +#endif +}; + #define BUF_SIZE 16 /* Buffer used for polling. */ @@ -66,11 +86,11 @@ static struct test_data int_async_data; static const struct device *const counter_dev = DEVICE_DT_GET(COUNTER_NODE); -static const struct device *const uart_dev = - DEVICE_DT_GET(UART_NODE); +static const struct device *uart_dev; static bool async; static bool int_driven; +static volatile bool error_found; static volatile bool async_rx_enabled; static struct k_sem async_tx_sem; @@ -84,6 +104,10 @@ static void process_byte(uint8_t b) struct rx_source *src = &source[base]; bool ok; + if (error_found) { + return; + } + b &= 0x0F; src->cnt++; @@ -94,13 +118,21 @@ static void process_byte(uint8_t b) ok = ((b - src->prev) == 1) || (!b && (src->prev == 0x0F)); + if (!ok) { + error_found = true; + LOG_ERR("Unexpected byte received:0x%02x, prev:0x%02x", + (base << 4) | b, (base << 4) | src->prev); + }; + zassert_true(ok, "Unexpected byte received:0x%02x, prev:0x%02x", (base << 4) | b, (base << 4) | src->prev); src->prev = b; } +static volatile bool in_counter_isr; static void counter_top_handler(const struct device *dev, void *user_data) { + in_counter_isr = true; static bool enable = true; static uint8_t async_rx_buf[4]; @@ -126,9 +158,10 @@ static void counter_top_handler(const struct device *dev, void *user_data) process_byte(c); } } + in_counter_isr = false; } -static void init_test(void) +static void init_test(int idx) { int err; struct counter_top_cfg top_cfg = { @@ -137,6 +170,12 @@ static void init_test(void) .flags = 0 }; + memset(source, 0, sizeof(source)); + error_found = false; + async_rx_enabled = false; + uart_dev = duts[idx].dev; + TC_PRINT("UART instance:%s\n", duts[idx].name); + zassert_true(device_is_ready(uart_dev), "uart device is not ready"); if (uart_callback_set(uart_dev, async_callback, NULL) == 0) { @@ -224,6 +263,10 @@ static void bulk_poll_out(struct test_data *data, int wait_base, int wait_range) { for (int i = 0; i < data->max; i++) { + if (error_found) { + goto bail; + } + data->cnt++; uart_poll_out(uart_dev, data->buf[i % BUF_SIZE]); if (wait_base) { @@ -232,7 +275,7 @@ static void bulk_poll_out(struct test_data *data, int wait_base, int wait_range) k_sleep(K_USEC(wait_base + (r % wait_range))); } } - +bail: k_sem_give(&data->sem); } @@ -241,10 +284,10 @@ static void poll_out_thread(void *data, void *unused0, void *unused1) bulk_poll_out((struct test_data *)data, 200, 600); } -K_THREAD_STACK_DEFINE(high_poll_out_thread_stack, 1024); +K_THREAD_STACK_DEFINE(high_poll_out_thread_stack, 2048); static struct k_thread high_poll_out_thread; -K_THREAD_STACK_DEFINE(int_async_thread_stack, 1024); +K_THREAD_STACK_DEFINE(int_async_thread_stack, 2048); static struct k_thread int_async_thread; static void int_async_thread_func(void *p_data, void *base, void *range) @@ -255,7 +298,7 @@ static void int_async_thread_func(void *p_data, void *base, void *range) k_sem_init(&async_tx_sem, 1, 1); - while (data->cnt < data->max) { + while (!error_found && (data->cnt < data->max)) { if (async) { int err; @@ -287,7 +330,9 @@ static void poll_out_timer_handler(struct k_timer *timer) { struct test_data *data = k_timer_user_data_get(timer); - uart_poll_out(uart_dev, data->buf[data->cnt % BUF_SIZE]); + if (!error_found) { + uart_poll_out(uart_dev, data->buf[data->cnt % BUF_SIZE]); + } data->cnt++; if (data->cnt == data->max) { @@ -369,10 +414,21 @@ ZTEST(uart_mix_fifo_poll, test_mixed_uart_access) void *uart_mix_setup(void) { - init_test(); + static int idx; + + init_test(idx++); return NULL; } ZTEST_SUITE(uart_mix_fifo_poll, NULL, uart_mix_setup, NULL, NULL, NULL); + +void test_main(void) +{ + /* Run all suites for each dut UART. Setup function for each suite is picking + * next UART from the array. + */ + ztest_run_all(NULL, false, ARRAY_SIZE(duts), 1); + ztest_verify_all_test_suites_ran(); +} diff --git a/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 000000000000..9e38ed36b133 --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "../../../boards/nrf54h20dk_nrf54h20_common.dtsi" + +&dut { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; + +&timer137 { + status = "reserved"; + interrupt-parent = <&cpuppr_clic>; +}; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/prj.conf b/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/prj.conf new file mode 100644 index 000000000000..b2a4ba591044 --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/sysbuild/vpr_launcher/prj.conf @@ -0,0 +1 @@ +# nothing here diff --git a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml index 1b13bc571662..18056b7000d3 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml +++ b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml @@ -22,32 +22,22 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n drivers.uart.uart_mix_poll_fifo: extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n drivers.uart.uart_mix_poll_async_api: extra_configs: - CONFIG_UART_ASYNC_API=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=n - - CONFIG_UART_0_ASYNC=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n drivers.uart.uart_mix_poll_async_api_const: extra_args: TEST_CONST_BUFFER=1 extra_configs: - CONFIG_UART_ASYNC_API=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=n - - CONFIG_UART_0_ASYNC=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_0_TX_CACHE_SIZE=2 - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI # We skip a few tests to save CI time, as they give little extra coverage drivers.uart.uart_mix_poll_with_ppi: @@ -55,59 +45,28 @@ tests: - CONFIG_UART_INTERRUPT_DRIVEN=n - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=y - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n tags: bsim_skip_CI - - drivers.uart.uart_mix_poll_fifo_with_ppi: - extra_configs: - - CONFIG_UART_INTERRUPT_DRIVEN=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=y - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n - tags: bsim_skip_CI - - drivers.uart.uart_mix_poll_async_api_with_ppi: - extra_configs: - - CONFIG_UART_ASYNC_API=y - - CONFIG_UART_0_INTERRUPT_DRIVEN=n - - CONFIG_UART_0_ASYNC=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=y - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n - tags: bsim_skip_CI - - drivers.uart.legacy.uart_mix_poll: - extra_configs: - - CONFIG_UART_INTERRUPT_DRIVEN=n - - CONFIG_UART_ASYNC_API=n - - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y platform_exclude: - - nrf54l15dk/nrf54l15/cpuapp - nrf54h20dk/nrf54h20/cpuapp - nrf54h20dk/nrf54h20/cpurad - drivers.uart.legacy.uart_mix_poll_fifo: + drivers.uart.uart_mix_poll_fifo_with_ppi: extra_configs: - CONFIG_UART_INTERRUPT_DRIVEN=y - CONFIG_UART_0_INTERRUPT_DRIVEN=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + - CONFIG_UART_0_ENHANCED_POLL_OUT=y + tags: bsim_skip_CI platform_exclude: - - nrf54l15dk/nrf54l15/cpuapp - nrf54h20dk/nrf54h20/cpuapp - nrf54h20dk/nrf54h20/cpurad - drivers.uart.legacy.uart_mix_poll_async_api: + drivers.uart.uart_mix_poll_async_api_with_ppi: extra_configs: - CONFIG_UART_ASYNC_API=y - CONFIG_UART_0_INTERRUPT_DRIVEN=n - CONFIG_UART_0_ASYNC=y - - CONFIG_UART_0_ENHANCED_POLL_OUT=n - - CONFIG_UART_0_NRF_HW_ASYNC=y - - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - - CONFIG_NRFX_TIMER2=y - - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + - CONFIG_UART_0_ENHANCED_POLL_OUT=y + tags: bsim_skip_CI platform_exclude: - - nrf54l15dk/nrf54l15/cpuapp - nrf54h20dk/nrf54h20/cpuapp - nrf54h20dk/nrf54h20/cpurad