Skip to content

Commit a3de3df

Browse files
erwangonashif
authored andcommitted
drivers/uart: stm32: Fix pm_constraint handling
Introduce new logic to set/release pm_constraint during serial TX transactions. First change is to introduce an internal flag and utility functions to control the set/release constraint balancing per uart device. This way, whatever the mix of transactions or API calls, we ensure a single uart device can only do 1 or 0 to the PM state constraint. Constraint can't then be set more than once, released w/o having been set or released more than it was set. The last part of the change reworks the triggers for constraints set/release operations. In order not to disturb driver operations, if irq driven mode or PM is enabled, don't enable TC interrupt handling by default. Instead, map the pm_constraint setting to the way TC flag is handled in normal mode of operations (irq driven or async). As a consequence, in irq driven mode, pm_constraint is set/released on tx_enable/tx_disable api calls, which gives API user full control on transaction protection vs low power operations. Finally, we emulate the same behavior on TX poll transaction, by enabling TC irq at the start of a stream and disabling TC irq once stream is completed. This is controlled with a dedicated device flag. Signed-off-by: Erwan Gouriou <[email protected]>
1 parent dc98629 commit a3de3df

File tree

2 files changed

+84
-25
lines changed

2 files changed

+84
-25
lines changed

drivers/serial/uart_stm32.c

Lines changed: 80 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,28 @@ LOG_MODULE_REGISTER(uart_stm32);
5353

5454
#define TIMEOUT 1000
5555

56+
#ifdef CONFIG_PM
57+
static void uart_stm32_pm_constraint_set(const struct device *dev)
58+
{
59+
struct uart_stm32_data *data = DEV_DATA(dev);
60+
61+
if (!data->pm_constraint_on) {
62+
data->pm_constraint_on = true;
63+
pm_constraint_set(PM_STATE_SUSPEND_TO_IDLE);
64+
}
65+
}
66+
67+
static void uart_stm32_pm_constraint_release(const struct device *dev)
68+
{
69+
struct uart_stm32_data *data = DEV_DATA(dev);
70+
71+
if (data->pm_constraint_on) {
72+
data->pm_constraint_on = false;
73+
pm_constraint_release(PM_STATE_SUSPEND_TO_IDLE);
74+
}
75+
}
76+
#endif /* CONFIG_PM */
77+
5678
static inline void uart_stm32_set_baudrate(const struct device *dev,
5779
uint32_t baud_rate)
5880
{
@@ -456,8 +478,23 @@ static void uart_stm32_poll_out(const struct device *dev,
456478
while (!LL_USART_IsActiveFlag_TXE(UartInstance)) {
457479
}
458480

459-
/* do not allow system to suspend until transmission has completed */
460-
pm_constraint_set(PM_STATE_SUSPEND_TO_IDLE);
481+
#ifdef CONFIG_PM
482+
struct uart_stm32_data *data = DEV_DATA(dev);
483+
484+
if (!data->tx_poll_stream_on) {
485+
data->tx_poll_stream_on = true;
486+
487+
/* Don't allow system to suspend until stream
488+
* transmission has completed
489+
*/
490+
uart_stm32_pm_constraint_set(dev);
491+
492+
/* Enable TC interrupt so we can release suspend
493+
* constraint when done
494+
*/
495+
LL_USART_EnableIT_TC(UartInstance);
496+
}
497+
#endif /* CONFIG_PM */
461498

462499
LL_USART_TransmitData8(UartInstance, (uint8_t)c);
463500
}
@@ -520,11 +557,6 @@ static int uart_stm32_fifo_fill(const struct device *dev,
520557
USART_TypeDef *UartInstance = UART_STRUCT(dev);
521558
uint8_t num_tx = 0U;
522559

523-
if ((size > 0) && LL_USART_IsActiveFlag_TXE(UartInstance)) {
524-
/* do not allow system to suspend until transmission has completed */
525-
pm_constraint_set(PM_STATE_SUSPEND_TO_IDLE);
526-
}
527-
528560
while ((size - num_tx > 0) &&
529561
LL_USART_IsActiveFlag_TXE(UartInstance)) {
530562
/* TXE flag will be cleared with byte write to DR|RDR register */
@@ -563,13 +595,21 @@ static void uart_stm32_irq_tx_enable(const struct device *dev)
563595
USART_TypeDef *UartInstance = UART_STRUCT(dev);
564596

565597
LL_USART_EnableIT_TC(UartInstance);
598+
599+
#ifdef CONFIG_PM
600+
uart_stm32_pm_constraint_set(dev);
601+
#endif
566602
}
567603

568604
static void uart_stm32_irq_tx_disable(const struct device *dev)
569605
{
570606
USART_TypeDef *UartInstance = UART_STRUCT(dev);
571607

572608
LL_USART_DisableIT_TC(UartInstance);
609+
610+
#ifdef CONFIG_PM
611+
uart_stm32_pm_constraint_release(dev);
612+
#endif
573613
}
574614

575615
static int uart_stm32_irq_tx_ready(const struct device *dev)
@@ -799,16 +839,30 @@ static void uart_stm32_dma_rx_flush(const struct device *dev)
799839
static void uart_stm32_isr(const struct device *dev)
800840
{
801841
struct uart_stm32_data *data = DEV_DATA(dev);
842+
#if defined(CONFIG_PM) || defined(CONFIG_UART_ASYNC_API)
802843
USART_TypeDef *UartInstance = UART_STRUCT(dev);
844+
#endif
803845

804-
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
805-
if (LL_USART_IsActiveFlag_TC(UartInstance)) {
806-
LL_USART_ClearFlag_TC(UartInstance);
807-
808-
/* allow system to suspend, UART has now finished */
809-
pm_constraint_release(PM_STATE_SUSPEND_TO_IDLE);
846+
#ifdef CONFIG_PM
847+
if (LL_USART_IsEnabledIT_TC(UartInstance) &&
848+
LL_USART_IsActiveFlag_TC(UartInstance)) {
849+
850+
if (data->tx_poll_stream_on) {
851+
/* A poll stream transmition just completed,
852+
* allow system to suspend
853+
*/
854+
LL_USART_DisableIT_TC(UartInstance);
855+
data->tx_poll_stream_on = false;
856+
uart_stm32_pm_constraint_release(dev);
857+
}
858+
/* Stream transmition was either async or IRQ based,
859+
* constraint will be released at the same time TC IT
860+
* is disabled
861+
*/
810862
}
863+
#endif
811864

865+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
812866
if (data->user_cb) {
813867
data->user_cb(dev, data->user_data);
814868
}
@@ -837,8 +891,9 @@ static void uart_stm32_isr(const struct device *dev)
837891
/* Generate TX_DONE event when transmission is done */
838892
async_evt_tx_done(data);
839893

840-
/* allow system to suspend, UART has now finished */
841-
pm_constraint_release(PM_STATE_SUSPEND_TO_IDLE);
894+
#ifdef CONFIG_PM
895+
uart_stm32_pm_constraint_release(dev);
896+
#endif
842897
}
843898

844899
/* Clear errors */
@@ -849,12 +904,18 @@ static void uart_stm32_isr(const struct device *dev)
849904
static void uart_stm32_isr(const struct device *dev)
850905
{
851906
USART_TypeDef *UartInstance = UART_STRUCT(dev);
907+
struct uart_stm32_data *data = DEV_DATA(dev);
852908

853909
if (LL_USART_IsActiveFlag_TC(UartInstance)) {
854910
LL_USART_ClearFlag_TC(UartInstance);
911+
LL_USART_DisableIT_TC(UartInstance);
912+
913+
__ASSERT_NO_MSG(data->tx_poll_stream_on);
914+
915+
data->tx_poll_stream_on = false;
855916

856917
/* allow system to suspend, UART has now finished */
857-
pm_constraint_release(PM_STATE_SUSPEND_TO_IDLE);
918+
uart_stm32_pm_constraint_release(dev);
858919
}
859920
}
860921
#endif /* (CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) */
@@ -1079,8 +1140,10 @@ static int uart_stm32_async_tx(const struct device *dev,
10791140
/* Start TX timer */
10801141
async_timer_start(&data->dma_tx.timeout_work, data->dma_tx.timeout);
10811142

1143+
#ifdef CONFIG_PM
10821144
/* do not allow system to suspend until transmission has completed */
1083-
pm_constraint_set(PM_STATE_SUSPEND_TO_IDLE);
1145+
uart_stm32_pm_constraint_set(dev);
1146+
#endif
10841147

10851148
/* Enable TX DMA requests */
10861149
uart_stm32_dma_tx_enable(dev);
@@ -1446,14 +1509,6 @@ static int uart_stm32_init(const struct device *dev)
14461509
config->irq_config_func(dev);
14471510
#endif /* defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) */
14481511

1449-
#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_PM)
1450-
/* Clear TC flag */
1451-
LL_USART_ClearFlag_TC(UartInstance);
1452-
1453-
/* Enable TC interrupt so we can release suspend constraint when done */
1454-
LL_USART_EnableIT_TC(UartInstance);
1455-
#endif /* defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_PM) */
1456-
14571512
#ifdef CONFIG_UART_ASYNC_API
14581513
return uart_stm32_async_init(dev);
14591514
#else

drivers/serial/uart_stm32.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ struct uart_stm32_data {
7272
uint8_t *rx_next_buffer;
7373
size_t rx_next_buffer_len;
7474
#endif
75+
#ifdef CONFIG_PM
76+
bool tx_poll_stream_on;
77+
bool pm_constraint_on;
78+
#endif
7579
};
7680

7781
#endif /* ZEPHYR_DRIVERS_SERIAL_UART_STM32_H_ */

0 commit comments

Comments
 (0)