Skip to content

Commit c66349e

Browse files
committed
[nrf fromtree] drivers: serial: nrfx_uarte: Add support for non ISR PM mode
When fast UARTE instance is used (e.g. UARTE120 in nrf54h20), PM actions are not ISR safe because they include communication over IPC so they can only be called from the thread context. Extend driver to support both PM modes. When non ISR mode is used then uart_rx_enable() and uart_tx() will return error if they are called from ISR and resume operation would need to be called because device is suspended. On completion, driver is calling pm_device_runtime_put_async which can be called from the ISR context. Additionally, suspending in the TXSTOPPED and RXTO events has been moved after user callback. It allows to support the case where uart_rx_enable() or uart_tx() are called from that callback context. Since suspending is called after returning from the callback it will not trigger suspend action because API called in the callback context will increment the usage counter (when pm_device_runtime_get() is called). Signed-off-by: Krzysztof Chruściński <[email protected]> (cherry picked from commit c8d50e4)
1 parent 49b305d commit c66349e

File tree

1 file changed

+88
-11
lines changed

1 file changed

+88
-11
lines changed

drivers/serial/uart_nrfx_uarte.c

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,19 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL);
110110
#define UARTE_ANY_LOW_POWER 1
111111
#endif
112112

113+
BUILD_ASSERT(NRF_GPD_FAST_ACTIVE1 == 0);
114+
/* Macro must resolve to literal 0 or 1 */
115+
#define INSTANCE_IS_FAST(unused, prefix, idx, _) \
116+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(UARTE(idx)), \
117+
(COND_CODE_1(UTIL_AND(IS_ENABLED(CONFIG_SOC_NRF54H20_GPD), \
118+
DT_NODE_HAS_PROP(UARTE(idx), power_domains)), \
119+
(COND_CODE_0(DT_PHA(UARTE(idx), power_domains, id), (1), (0))),\
120+
(0))), (0))
121+
122+
#if UARTE_FOR_EACH_INSTANCE(INSTANCE_IS_FAST, (||), (0))
123+
#define UARTE_ANY_FAST 1
124+
#endif
125+
113126
#ifdef UARTE_ANY_CACHE
114127
/* uart120 instance does not retain BAUDRATE register when ENABLE=0. When this instance
115128
* is used then baudrate must be set after enabling the peripheral and not before.
@@ -269,6 +282,21 @@ struct uarte_nrfx_data {
269282
(IS_ENABLED(UARTE_ANY_LOW_POWER) && \
270283
!IS_ENABLED(CONFIG_PM_DEVICE) && \
271284
(_config->flags & UARTE_CFG_FLAG_LOW_POWER))
285+
286+
/** @brief Check if device has PM that works in ISR safe mode.
287+
*
288+
* Only fast UARTE instance does not work in that mode so check PM configuration
289+
* flags only if there is any fast instance present.
290+
*
291+
* @retval true if device PM is ISR safe.
292+
* @retval false if device PM is not ISR safe.
293+
*/
294+
#define IS_PM_ISR_SAFE(dev) \
295+
(!IS_ENABLED(UARTE_ANY_FAST) ||\
296+
COND_CODE_1(CONFIG_PM_DEVICE,\
297+
((dev->pm_base->flags & BIT(PM_DEVICE_FLAG_ISR_SAFE))), \
298+
(0)))
299+
272300
/**
273301
* @brief Structure for UARTE configuration.
274302
*/
@@ -873,6 +901,20 @@ static int uarte_nrfx_tx(const struct device *dev, const uint8_t *buf,
873901
}
874902

875903
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
904+
if (!IS_PM_ISR_SAFE(dev) && k_is_in_isr()) {
905+
/* If instance does not support PM from ISR device shall
906+
* already be turned on.
907+
*/
908+
enum pm_device_state state;
909+
int err;
910+
911+
err = pm_device_state_get(dev, &state);
912+
(void)err;
913+
__ASSERT_NO_MSG(err == 0);
914+
if (state != PM_DEVICE_STATE_ACTIVE) {
915+
return -ENOTSUP;
916+
}
917+
}
876918
pm_device_runtime_get(dev);
877919
}
878920

@@ -941,6 +983,10 @@ static void notify_rx_disable(const struct device *dev)
941983
};
942984

943985
user_callback(dev, (struct uart_event *)&evt);
986+
987+
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
988+
pm_device_runtime_put_async(dev, K_NO_WAIT);
989+
}
944990
}
945991

946992
#ifdef UARTE_HAS_FRAME_TIMEOUT
@@ -1015,6 +1061,24 @@ static int uarte_nrfx_rx_enable(const struct device *dev, uint8_t *buf,
10151061
async_rx->next_buf = NULL;
10161062
async_rx->next_buf_len = 0;
10171063

1064+
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
1065+
if (!IS_PM_ISR_SAFE(dev) && k_is_in_isr()) {
1066+
/* If instance does not support PM from ISR device shall
1067+
* already be turned on.
1068+
*/
1069+
enum pm_device_state state;
1070+
int err;
1071+
1072+
err = pm_device_state_get(dev, &state);
1073+
(void)err;
1074+
__ASSERT_NO_MSG(err == 0);
1075+
if (state != PM_DEVICE_STATE_ACTIVE) {
1076+
return -ENOTSUP;
1077+
}
1078+
}
1079+
pm_device_runtime_get(dev);
1080+
}
1081+
10181082
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) || LOW_POWER_ENABLED(cfg)) {
10191083
if (async_rx->flush_cnt) {
10201084
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,
10681132

10691133
async_rx->enabled = true;
10701134

1071-
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
1072-
pm_device_runtime_get(dev);
1073-
} else if (LOW_POWER_ENABLED(cfg)) {
1135+
if (LOW_POWER_ENABLED(cfg)) {
10741136
unsigned int key = irq_lock();
10751137

10761138
uarte_enable_locked(dev, UARTE_FLAG_LOW_POWER_RX);
@@ -1543,9 +1605,7 @@ static void rxto_isr(const struct device *dev)
15431605
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
15441606
#endif
15451607

1546-
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
1547-
pm_device_runtime_put(dev);
1548-
} else if (LOW_POWER_ENABLED(config)) {
1608+
if (LOW_POWER_ENABLED(config)) {
15491609
uint32_t key = irq_lock();
15501610

15511611
uarte_disable_locked(dev, UARTE_FLAG_LOW_POWER_RX);
@@ -1570,7 +1630,7 @@ static void txstopped_isr(const struct device *dev)
15701630
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
15711631
nrf_uarte_int_disable(uarte, NRF_UARTE_INT_TXSTOPPED_MASK);
15721632
if (data->flags & UARTE_FLAG_POLL_OUT) {
1573-
pm_device_runtime_put(dev);
1633+
pm_device_runtime_put_async(dev, K_NO_WAIT);
15741634
data->flags &= ~UARTE_FLAG_POLL_OUT;
15751635
}
15761636
} else if (LOW_POWER_ENABLED(config)) {
@@ -1633,11 +1693,11 @@ static void txstopped_isr(const struct device *dev)
16331693
data->async->tx.buf = NULL;
16341694
data->async->tx.len = 0;
16351695

1696+
user_callback(dev, &evt);
1697+
16361698
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
1637-
pm_device_runtime_put(dev);
1699+
pm_device_runtime_put_async(dev, K_NO_WAIT);
16381700
}
1639-
1640-
user_callback(dev, &evt);
16411701
}
16421702

16431703
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)
18241884
}
18251885

18261886
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
1887+
if (!IS_PM_ISR_SAFE(dev) && k_is_in_isr()) {
1888+
/* If instance does not support PM from ISR device shall
1889+
* already be turned on.
1890+
*/
1891+
enum pm_device_state state;
1892+
int err;
1893+
1894+
err = pm_device_state_get(dev, &state);
1895+
(void)err;
1896+
__ASSERT_NO_MSG(err == 0);
1897+
if (state != PM_DEVICE_STATE_ACTIVE) {
1898+
irq_unlock(key);
1899+
return;
1900+
}
1901+
}
1902+
18271903
if (!(data->flags & UARTE_FLAG_POLL_OUT)) {
18281904
data->flags |= UARTE_FLAG_POLL_OUT;
18291905
pm_device_runtime_get(dev);
@@ -2417,7 +2493,8 @@ static int uarte_instance_init(const struct device *dev,
24172493
} \
24182494
\
24192495
PM_DEVICE_DT_DEFINE(UARTE(idx), uarte_nrfx_pm_action, \
2420-
PM_DEVICE_ISR_SAFE); \
2496+
COND_CODE_1(INSTANCE_IS_FAST(_, /*empty*/, idx, _),\
2497+
(0), (PM_DEVICE_ISR_SAFE))); \
24212498
\
24222499
DEVICE_DT_DEFINE(UARTE(idx), \
24232500
uarte_##idx##_init, \

0 commit comments

Comments
 (0)