diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 274afcbabf79..b973ce9fd7af 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -111,19 +111,31 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL); #include /* Macro must resolve to literal 0 or 1 */ -#define INSTANCE_IS_FAST(unused, prefix, idx, _) \ +#define INSTANCE_IS_FAST_PD(unused, prefix, idx, _) \ COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(UARTE(idx)), \ (COND_CODE_1(DT_NODE_HAS_PROP(UARTE(idx), power_domains), \ (IS_EQ(DT_PHA(UARTE(idx), power_domains, id), NRF_GPD_FAST_ACTIVE1)), \ (0))), (0)) -#if UARTE_FOR_EACH_INSTANCE(INSTANCE_IS_FAST, (||), (0)) -/* Fast instance requires special PM treatment so device runtime PM must be enabled. */ +#if UARTE_FOR_EACH_INSTANCE(INSTANCE_IS_FAST_PD, (||), (0)) +/* Instance in fast power domain (PD) requires special PM treatment so device runtime PM must + * be enabled. + */ BUILD_ASSERT(IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)); -#define UARTE_ANY_FAST 1 +#define UARTE_ANY_FAST_PD 1 #endif #endif +#define INSTANCE_IS_HIGH_SPEED(unused, prefix, idx, _) \ + COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(UARTE(prefix##idx)), \ + ((NRF_PERIPH_GET_FREQUENCY(UARTE(prefix##idx)) > NRF_UARTE_BASE_FREQUENCY_16MHZ)), \ + (0)) + +/* Macro determines if there is any high speed instance (instance that is driven using + * clock that is faster than 16 MHz). + */ +#define UARTE_ANY_HIGH_SPEED (UARTE_FOR_EACH_INSTANCE(INSTANCE_IS_HIGH_SPEED, (||), (0))) + #ifdef UARTE_ANY_CACHE /* uart120 instance does not retain BAUDRATE register when ENABLE=0. When this instance * is used then baudrate must be set after enabling the peripheral and not before. @@ -254,6 +266,17 @@ struct uarte_nrfx_data { /* If enabled then UARTE peripheral is using memory which is cacheable. */ #define UARTE_CFG_FLAG_CACHEABLE BIT(3) +/* Formula for getting the baudrate settings is following: + * 2^12 * (2^20 / (f_PCLK / desired_baudrate)) where f_PCLK is a frequency that + * drives the UARTE. + * + * @param f_pclk Frequency of the clock that drives the peripheral. + * @param baudrate Desired baudrate. + * + * @return Baudrate setting to be written to the BAUDRATE register + */ +#define UARTE_GET_CUSTOM_BAUDRATE(f_pclk, baudrate) ((BIT(20) / (f_pclk / baudrate)) << 12) + /* 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. @@ -293,7 +316,7 @@ struct uarte_nrfx_data { * @retval false if device PM is not ISR safe. */ #define IS_PM_ISR_SAFE(dev) \ - (!IS_ENABLED(UARTE_ANY_FAST) ||\ + (!IS_ENABLED(UARTE_ANY_FAST_PD) ||\ COND_CODE_1(CONFIG_PM_DEVICE,\ ((dev->pm_base->flags & BIT(PM_DEVICE_FLAG_ISR_SAFE))), \ (0))) @@ -309,7 +332,7 @@ struct uarte_nrfx_config { #ifdef CONFIG_HAS_NORDIC_DMM void *mem_reg; #endif -#ifdef UARTE_ANY_FAST +#ifdef UARTE_ANY_FAST_PD const struct device *clk_dev; struct nrf_clock_spec clk_spec; #endif @@ -493,18 +516,19 @@ static void uarte_nrfx_isr_int(const void *arg) static int baudrate_set(const struct device *dev, uint32_t baudrate) { const struct uarte_nrfx_config *config = dev->config; + nrf_uarte_baudrate_t nrf_baudrate; + /* calculated baudrate divisor */ - nrf_uarte_baudrate_t nrf_baudrate = NRF_BAUDRATE(baudrate); + if (UARTE_ANY_HIGH_SPEED && (config->clock_freq > NRF_UARTE_BASE_FREQUENCY_16MHZ)) { + nrf_baudrate = UARTE_GET_CUSTOM_BAUDRATE(config->clock_freq, baudrate); + } else { + nrf_baudrate = NRF_BAUDRATE(baudrate); + } if (nrf_baudrate == 0) { return -EINVAL; } - /* scale baudrate setting */ - if (config->clock_freq > 0U) { - nrf_baudrate /= config->clock_freq / NRF_UARTE_BASE_FREQUENCY_16MHZ; - } - #ifdef UARTE_BAUDRATE_RETENTION_WORKAROUND struct uarte_nrfx_data *data = dev->data; @@ -662,7 +686,7 @@ static void uarte_periph_enable(const struct device *dev) struct uarte_nrfx_data *data = dev->data; (void)data; -#ifdef UARTE_ANY_FAST +#ifdef UARTE_ANY_FAST_PD if (config->clk_dev) { int err; @@ -1141,6 +1165,14 @@ static int uarte_nrfx_rx_enable(const struct device *dev, uint8_t *buf, nrf_uarte_rx_buffer_set(uarte, buf, len); + if (IS_ENABLED(UARTE_ANY_FAST_PD) && (cfg->flags & UARTE_CFG_FLAG_CACHEABLE)) { + /* Spurious RXTO event was seen on fast instance (UARTE120) thus + * RXTO interrupt is kept enabled only when RX is active. + */ + nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXTO); + nrf_uarte_int_enable(uarte, NRF_UARTE_INT_RXTO_MASK); + } + nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX); nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED); @@ -1613,6 +1645,12 @@ static void rxto_isr(const struct device *dev) #ifdef CONFIG_UART_NRFX_UARTE_ENHANCED_RX NRF_UARTE_Type *uarte = get_uarte_instance(dev); + if (IS_ENABLED(UARTE_ANY_FAST_PD) && (config->flags & UARTE_CFG_FLAG_CACHEABLE)) { + /* Spurious RXTO event was seen on fast instance (UARTE120) thus + * RXTO interrupt is kept enabled only when RX is active. + */ + nrf_uarte_int_disable(uarte, NRF_UARTE_INT_RXTO_MASK); + } #ifdef UARTE_HAS_FRAME_TIMEOUT nrf_uarte_shorts_disable(uarte, NRF_UARTE_SHORT_FRAME_TIMEOUT_STOPRX); #endif @@ -2218,7 +2256,7 @@ static void uarte_pm_suspend(const struct device *dev) struct uarte_nrfx_data *data = dev->data; (void)data; -#ifdef UARTE_ANY_FAST +#ifdef UARTE_ANY_FAST_PD if (cfg->clk_dev) { int err; @@ -2411,29 +2449,33 @@ static int uarte_instance_init(const struct device *dev, #define UARTE_DISABLE_RX_INIT(node_id) \ .disable_rx = DT_PROP(node_id, disable_rx) -/* Get frequency of the clock that driver the UARTE peripheral. Clock node can - * have fixed or variable frequency. For fast UARTE use highest supported frequency. - */ -#define UARTE_GET_BAUDRATE_DIV(idx) \ - (NRF_PERIPH_GET_FREQUENCY(UARTE(idx)) / NRF_UARTE_BASE_FREQUENCY_16MHZ) +/* Get frequency divider that is used to adjust the BAUDRATE value. */ +#define UARTE_GET_BAUDRATE_DIV(f_pclk) (f_pclk / NRF_UARTE_BASE_FREQUENCY_16MHZ) /* When calculating baudrate we need to take into account that high speed instances * must have baudrate adjust to the ratio between UARTE clocking frequency and 16 MHz. + * Additionally, >1Mbaud speeds are calculated using a formula. */ +#define UARTE_GET_BAUDRATE2(f_pclk, current_speed) \ + ((f_pclk > NRF_UARTE_BASE_FREQUENCY_16MHZ) && (current_speed > 1000000)) ? \ + UARTE_GET_CUSTOM_BAUDRATE(f_pclk, current_speed) : \ + (NRF_BAUDRATE(current_speed) / UARTE_GET_BAUDRATE_DIV(f_pclk)) + +/* Convert DT current-speed to a value that is written to the BAUDRATE register. */ #define UARTE_GET_BAUDRATE(idx) \ - (NRF_BAUDRATE(UARTE_PROP(idx, current_speed)) / UARTE_GET_BAUDRATE_DIV(idx)) + UARTE_GET_BAUDRATE2(NRF_PERIPH_GET_FREQUENCY(UARTE(idx)), UARTE_PROP(idx, current_speed)) /* Get initialization level of an instance. Instances that requires clock control * which is using nrfs (IPC) are initialized later. */ #define UARTE_INIT_LEVEL(idx) \ - COND_CODE_1(INSTANCE_IS_FAST(_, /*empty*/, idx, _), (POST_KERNEL), (PRE_KERNEL_1)) + COND_CODE_1(INSTANCE_IS_FAST_PD(_, /*empty*/, idx, _), (POST_KERNEL), (PRE_KERNEL_1)) /* Get initialization priority of an instance. Instances that requires clock control * which is using nrfs (IPC) are initialized later. */ #define UARTE_INIT_PRIO(idx) \ - COND_CODE_1(INSTANCE_IS_FAST(_, /*empty*/, idx, _), \ + COND_CODE_1(INSTANCE_IS_FAST_PD(_, /*empty*/, idx, _), \ (UTIL_INC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY)), \ (CONFIG_SERIAL_INIT_PRIORITY)) @@ -2486,12 +2528,11 @@ static int uarte_instance_init(const struct device *dev, (.int_driven = &uarte##idx##_int_driven,)) \ }; \ COND_CODE_1(CONFIG_UART_USE_RUNTIME_CONFIGURE, (), \ - (BUILD_ASSERT(NRF_BAUDRATE(UARTE_PROP(idx, current_speed)) > 0,\ - "Unsupported baudrate");)) \ + (BUILD_ASSERT(UARTE_GET_BAUDRATE(idx) > 0, \ + "Unsupported baudrate");)) \ static const struct uarte_nrfx_config uarte_##idx##z_config = { \ COND_CODE_1(CONFIG_UART_USE_RUNTIME_CONFIGURE, \ - (IF_ENABLED(DT_CLOCKS_HAS_IDX(UARTE(idx), 0), \ - (.clock_freq = NRF_PERIPH_GET_FREQUENCY(UARTE(idx)),))), \ + (.clock_freq = NRF_PERIPH_GET_FREQUENCY(UARTE(idx)),), \ (IF_ENABLED(UARTE_HAS_FRAME_TIMEOUT, \ (.baudrate = UARTE_PROP(idx, current_speed),)) \ .nrf_baudrate = UARTE_GET_BAUDRATE(idx), \ @@ -2518,7 +2559,7 @@ static int uarte_instance_init(const struct device *dev, IF_ENABLED(CONFIG_UART_##idx##_NRF_HW_ASYNC, \ (.timer = NRFX_TIMER_INSTANCE( \ CONFIG_UART_##idx##_NRF_HW_ASYNC_TIMER),)) \ - IF_ENABLED(INSTANCE_IS_FAST(_, /*empty*/, idx, _), \ + IF_ENABLED(INSTANCE_IS_FAST_PD(_, /*empty*/, idx, _), \ (.clk_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(UARTE(idx))), \ .clk_spec = { \ .frequency = NRF_PERIPH_GET_FREQUENCY(UARTE(idx)),\ @@ -2537,7 +2578,7 @@ static int uarte_instance_init(const struct device *dev, } \ \ PM_DEVICE_DT_DEFINE(UARTE(idx), uarte_nrfx_pm_action, \ - COND_CODE_1(INSTANCE_IS_FAST(_, /*empty*/, idx, _),\ + COND_CODE_1(INSTANCE_IS_FAST_PD(_, /*empty*/, idx, _),\ (0), (PM_DEVICE_ISR_SAFE))); \ \ DEVICE_DT_DEFINE(UARTE(idx), \ diff --git a/dts/bindings/serial/nordic,nrf-uart-common.yaml b/dts/bindings/serial/nordic,nrf-uart-common.yaml index d4061be7aabc..425430deb147 100644 --- a/dts/bindings/serial/nordic,nrf-uart-common.yaml +++ b/dts/bindings/serial/nordic,nrf-uart-common.yaml @@ -43,3 +43,6 @@ properties: - 460800 - 921600 - 1000000 + - 2000000 + - 4000000 + - 8000000 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 9902d733d357..068bc6e57ba3 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 @@ -50,6 +50,6 @@ dut2: &uart120 { pinctrl-0 = <&uart120_default_alt>; pinctrl-1 = <&uart120_sleep_alt>; pinctrl-names = "default", "sleep"; - current-speed = <115200>; + current-speed = <4000000>; zephyr,pm-device-runtime-auto; }; 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 dd87afbdd153..364284794178 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 @@ -592,6 +592,9 @@ static void *read_abort_setup(void) ZTEST_USER(uart_async_read_abort, test_read_abort) { + struct uart_config cfg; + int err; + uint32_t t_us; #if NOCACHE_MEM static __aligned(32) uint8_t rx_buf[100] __used __NOCACHE; static __aligned(32) uint8_t tx_buf[100] __used __NOCACHE; @@ -603,17 +606,26 @@ ZTEST_USER(uart_async_read_abort, test_read_abort) memset(rx_buf, 0, sizeof(rx_buf)); memset(tx_buf, 1, sizeof(tx_buf)); - uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), 50 * USEC_PER_MSEC); + err = uart_config_get(uart_dev, &cfg); + zassert_equal(err, 0); + + /* Lets aim to abort after transmitting ~20 bytes (200 bauds) */ + t_us = (20 * 10 * 1000000) / cfg.baudrate; + + err = uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), 50 * USEC_PER_MSEC); + zassert_equal(err, 0); k_sem_give(&rx_buf_coherency); - uart_tx(uart_dev, tx_buf, 5, 100 * USEC_PER_MSEC); + err = uart_tx(uart_dev, tx_buf, 5, 100 * USEC_PER_MSEC); + zassert_equal(err, 0); zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); zassert_equal(memcmp(tx_buf, rx_buf, 5), 0, "Buffers not equal"); - uart_tx(uart_dev, tx_buf, 95, 100 * USEC_PER_MSEC); + err = uart_tx(uart_dev, tx_buf, 95, 100 * USEC_PER_MSEC); + zassert_equal(err, 0); - k_timer_start(&read_abort_timer, K_USEC(300), K_NO_WAIT); + k_timer_start(&read_abort_timer, K_USEC(t_us), K_NO_WAIT); /* RX will be aborted from k_timer timeout */