diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 8b139e99abc..437b546da40 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -110,6 +110,19 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL); #define UARTE_ANY_LOW_POWER 1 #endif +BUILD_ASSERT(NRF_GPD_FAST_ACTIVE1 == 0); +/* Macro must resolve to literal 0 or 1 */ +#define INSTANCE_IS_FAST(unused, prefix, idx, _) \ + COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(UARTE(idx)), \ + (COND_CODE_1(UTIL_AND(IS_ENABLED(CONFIG_SOC_NRF54H20_GPD), \ + DT_NODE_HAS_PROP(UARTE(idx), power_domains)), \ + (COND_CODE_0(DT_PHA(UARTE(idx), power_domains, id), (1), (0))),\ + (0))), (0)) + +#if UARTE_FOR_EACH_INSTANCE(INSTANCE_IS_FAST, (||), (0)) +#define UARTE_ANY_FAST 1 +#endif + #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. @@ -269,6 +282,21 @@ struct uarte_nrfx_data { (IS_ENABLED(UARTE_ANY_LOW_POWER) && \ !IS_ENABLED(CONFIG_PM_DEVICE) && \ (_config->flags & UARTE_CFG_FLAG_LOW_POWER)) + +/** @brief Check if device has PM that works in ISR safe mode. + * + * Only fast UARTE instance does not work in that mode so check PM configuration + * flags only if there is any fast instance present. + * + * @retval true if device PM is ISR safe. + * @retval false if device PM is not ISR safe. + */ +#define IS_PM_ISR_SAFE(dev) \ + (!IS_ENABLED(UARTE_ANY_FAST) ||\ + COND_CODE_1(CONFIG_PM_DEVICE,\ + ((dev->pm_base->flags & BIT(PM_DEVICE_FLAG_ISR_SAFE))), \ + (0))) + /** * @brief Structure for UARTE configuration. */ @@ -873,6 +901,20 @@ static int uarte_nrfx_tx(const struct device *dev, const uint8_t *buf, } if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + if (!IS_PM_ISR_SAFE(dev) && k_is_in_isr()) { + /* If instance does not support PM from ISR device shall + * already be turned on. + */ + enum pm_device_state state; + int err; + + err = pm_device_state_get(dev, &state); + (void)err; + __ASSERT_NO_MSG(err == 0); + if (state != PM_DEVICE_STATE_ACTIVE) { + return -ENOTSUP; + } + } pm_device_runtime_get(dev); } @@ -941,6 +983,10 @@ static void notify_rx_disable(const struct device *dev) }; user_callback(dev, (struct uart_event *)&evt); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put_async(dev, K_NO_WAIT); + } } #ifdef UARTE_HAS_FRAME_TIMEOUT @@ -1015,6 +1061,24 @@ static int uarte_nrfx_rx_enable(const struct device *dev, uint8_t *buf, async_rx->next_buf = NULL; async_rx->next_buf_len = 0; + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + if (!IS_PM_ISR_SAFE(dev) && k_is_in_isr()) { + /* If instance does not support PM from ISR device shall + * already be turned on. + */ + enum pm_device_state state; + int err; + + err = pm_device_state_get(dev, &state); + (void)err; + __ASSERT_NO_MSG(err == 0); + if (state != PM_DEVICE_STATE_ACTIVE) { + return -ENOTSUP; + } + } + pm_device_runtime_get(dev); + } + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) || LOW_POWER_ENABLED(cfg)) { if (async_rx->flush_cnt) { int cpy_len = MIN(len, async_rx->flush_cnt); @@ -1068,9 +1132,7 @@ static int uarte_nrfx_rx_enable(const struct device *dev, uint8_t *buf, async_rx->enabled = true; - if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_get(dev); - } else if (LOW_POWER_ENABLED(cfg)) { + if (LOW_POWER_ENABLED(cfg)) { unsigned int key = irq_lock(); uarte_enable_locked(dev, UARTE_FLAG_LOW_POWER_RX); @@ -1543,9 +1605,7 @@ static void rxto_isr(const struct device *dev) nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY); #endif - if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(dev); - } else if (LOW_POWER_ENABLED(config)) { + if (LOW_POWER_ENABLED(config)) { uint32_t key = irq_lock(); uarte_disable_locked(dev, UARTE_FLAG_LOW_POWER_RX); @@ -1570,7 +1630,7 @@ static void txstopped_isr(const struct device *dev) if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { nrf_uarte_int_disable(uarte, NRF_UARTE_INT_TXSTOPPED_MASK); if (data->flags & UARTE_FLAG_POLL_OUT) { - pm_device_runtime_put(dev); + pm_device_runtime_put_async(dev, K_NO_WAIT); data->flags &= ~UARTE_FLAG_POLL_OUT; } } else if (LOW_POWER_ENABLED(config)) { @@ -1633,11 +1693,11 @@ static void txstopped_isr(const struct device *dev) data->async->tx.buf = NULL; data->async->tx.len = 0; - if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { - pm_device_runtime_put(dev); - } - user_callback(dev, &evt); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put_async(dev, K_NO_WAIT); + } } static void rxdrdy_isr(const struct device *dev) @@ -1824,6 +1884,22 @@ static void uarte_nrfx_poll_out(const struct device *dev, unsigned char c) } if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + if (!IS_PM_ISR_SAFE(dev) && k_is_in_isr()) { + /* If instance does not support PM from ISR device shall + * already be turned on. + */ + enum pm_device_state state; + int err; + + err = pm_device_state_get(dev, &state); + (void)err; + __ASSERT_NO_MSG(err == 0); + if (state != PM_DEVICE_STATE_ACTIVE) { + irq_unlock(key); + return; + } + } + if (!(data->flags & UARTE_FLAG_POLL_OUT)) { data->flags |= UARTE_FLAG_POLL_OUT; pm_device_runtime_get(dev); @@ -2417,7 +2493,8 @@ static int uarte_instance_init(const struct device *dev, } \ \ PM_DEVICE_DT_DEFINE(UARTE(idx), uarte_nrfx_pm_action, \ - PM_DEVICE_ISR_SAFE); \ + COND_CODE_1(INSTANCE_IS_FAST(_, /*empty*/, idx, _),\ + (0), (PM_DEVICE_ISR_SAFE))); \ \ DEVICE_DT_DEFINE(UARTE(idx), \ uarte_##idx##_init, \