From 0961f847b8dd87e70d7941f7dea9fc575d427145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 23 Jan 2025 16:33:29 +0100 Subject: [PATCH 1/6] [nrf fromtree] dts: bindings: serial: nordic,nrf-uart-common: Extend baudrate enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add faster baudrates (2M, 4M and 8M). Signed-off-by: Krzysztof Chruściński (cherry picked from commit e7378953686da28a19576c33bffa4679e88ef851) --- dts/bindings/serial/nordic,nrf-uart-common.yaml | 3 +++ 1 file changed, 3 insertions(+) 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 From bcf77765c79f7615db710475cab8a667ade0dbb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 24 Jan 2025 12:31:22 +0100 Subject: [PATCH 2/6] [nrf fromtree] drivers: serial: nrfx_uarte: Rename FAST to FAST_PD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename UARTE_ANY_FAST to UARTE_ANY_FAST_PD. There are 2 types of 'fast' UARTE instances. In nrf54h20 instance uart120 is in fast power domain that requires additional power and clock management of that domain. In nrf54lx fast uart00 instance does not require that. Add _PD to indicate fast power domain. Signed-off-by: Krzysztof Chruściński (cherry picked from commit 1573be5e9f8011c978044d9185d3decb74821bb5) --- drivers/serial/uart_nrfx_uarte.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 274afcbabf79..13336a093844 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -111,16 +111,18 @@ 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 @@ -293,7 +295,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 +311,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 @@ -662,7 +664,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; @@ -2218,7 +2220,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; @@ -2427,13 +2429,13 @@ static int uarte_instance_init(const struct device *dev, * 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)) @@ -2518,7 +2520,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 +2539,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), \ From e2311898b76a06a88c620f1ca48465cd920d9589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 24 Jan 2025 12:36:31 +0100 Subject: [PATCH 3/6] [nrf fromtree] drivers: serial: nrfx_uarte: Add support for higher baudrates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nrf54x devices have UARTE instance capable of using baudrate higher than 1M. Higher baudrates does not have predefined values for BAUDRATE register. A formula can be used to calculate BAUDRATE value that shall be used for desired baudrate. Add UARTE_ANY_HIGH_SPEED macro which is set when high speed is enabled (uart00 in nrf54lx or uart120 in nrf54h20). For high speed instance use formula for getting value that shall be written to BAUDRATE register. When runtime configuration is not used then same formula is used to calculate fixed BAUDRATE value. Signed-off-by: Krzysztof Chruściński (cherry picked from commit 972ec824f1e3bfa9599d84fe0f2f7b83dab0ae1f) --- drivers/serial/uart_nrfx_uarte.c | 57 +++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 13336a093844..0546ab2714f3 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -126,6 +126,16 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)); #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. @@ -256,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. @@ -495,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; @@ -2413,17 +2435,21 @@ 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. @@ -2488,12 +2514,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), \ From 17899861c0fb3528d663617278c2c656a91297e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 24 Jan 2025 12:41:32 +0100 Subject: [PATCH 4/6] [nrf fromtree] drivers: serial: nrfx_uarte: Fix spurious RXTO event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fast instance in nrf54h (uart120) can generate a spurious RXTO event some time after RXTO event that indicates that RX path is disabled. The time when event is generated depends on baudrate and when slower baudrates are used peripheral is disabled on time to not notice it in the test but with higher baudates issue become visible. In order to avoid spurious interrupt, RXTO interrupt is disabled during RXTO event handling and enabled when RX is enabled. This workaround is applied only for fast instance to avoid unnecessary register accesses for slower instances. Signed-off-by: Krzysztof Chruściński (cherry picked from commit e235e7b38475e3e7ac8a0b2d19aa413bc7e92b08) --- drivers/serial/uart_nrfx_uarte.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 0546ab2714f3..b973ce9fd7af 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -1165,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); @@ -1637,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 From bec7ff39d74189159b949cf337c3480bd848a731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 24 Jan 2025 12:42:56 +0100 Subject: [PATCH 5/6] [nrf fromtree] tests: drivers: uart: uart_async_api: Tweak test_read_abort test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test was staring a TX transfer and aborting it after 300 us from the timer handler. Test was assuming that ongoing transfer will not finish in those 300 us. This might not be true for higher baudrates. Instead of using fixed timeout, a value is calculated from the baudrate and targets to abort the transfer after approx. 20 bytes of 95 byte long transfer. Signed-off-by: Krzysztof Chruściński (cherry picked from commit 38c129da39f28b0d4b5e43ac84e99348312bc4ee) --- .../uart/uart_async_api/src/test_uart_async.c | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) 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 */ From abac7b330a7e6b283948910767630baa6a67461b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 24 Jan 2025 12:50:14 +0100 Subject: [PATCH 6/6] [nrf fromtree] tests: drivers: uart: uart_async_api: Use 4Mbaud for nrf54h20dk uart120 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use high baudrate when testing uart120 on nrf54h20dk/nrf54h20/cpuapp. Signed-off-by: Krzysztof Chruściński (cherry picked from commit fe6a4d0f932685df625d50b7a88a0e1d1daec7c4) --- .../uart/uart_async_api/boards/nrf54h20dk_nrf54h20_common.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; };