Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 69 additions & 28 deletions drivers/serial/uart_nrfx_uarte.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,19 +111,31 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL);
#include <nrf/gpd.h>

/* 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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)))
Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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), \
Expand All @@ -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)),\
Expand All @@ -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), \
Expand Down
3 changes: 3 additions & 0 deletions dts/bindings/serial/nordic,nrf-uart-common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@ properties:
- 460800
- 921600
- 1000000
- 2000000
- 4000000
- 8000000
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
20 changes: 16 additions & 4 deletions tests/drivers/uart/uart_async_api/src/test_uart_async.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 */

Expand Down
Loading