[PATCH 1/2] serial: amba-pl011: finish a transmission still running when RS485 is enabled
From: Nicolai Buchwitz
Date: Fri Oct 16 2026 - 03:43:56 EST
Disabling RS485 keeps a transmission in progress running. If RS485 is
enabled again before it ends, the state is OFF while data is still
going out. The TX path does not stop a transmission in state OFF, so
nothing sets the idle RTS level once the data is out and the
transceiver keeps driving the bus.
Hand such a transmission back to RS485 when it is enabled. Assert RTS
and mark it as sending, so that the TX path ends it like any other.
With only the FIFO left the TX path is already done, so drain it from
trigger_stop_tx instead.
Fixes: 97f85204275a ("serial: amba-pl011: keep transmitter enabled when disabling RS485")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Nicolai Buchwitz <nb@xxxxxxxxxxx>
---
drivers/tty/serial/amba-pl011.c | 47 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 79776a882ae3..057bb74f3d85 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1734,6 +1734,18 @@ static unsigned int pl011_tx_empty(struct uart_port *port)
0 : TIOCSER_TEMT;
}
+/*
+ * Data still queued or on its way out. After RS485 was turned off and on
+ * again during a transmission, the state is OFF while this is true.
+ */
+static bool pl011_tx_pending(struct uart_amba_port *uap)
+{
+ struct tty_port *tport = &uap->port.state->port;
+
+ return !kfifo_is_empty(&tport->xmit_fifo) || pl011_dma_tx_queued(uap) ||
+ !pl011_tx_empty(&uap->port);
+}
+
static void pl011_maybe_set_bit(bool cond, unsigned int *ptr, unsigned int mask)
{
if (cond)
@@ -2454,6 +2466,38 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
return ret;
}
+/*
+ * RS485 is enabled while data sent before is still going out. Finish it as
+ * an RS485 transmission, so that its end sets the idle level.
+ */
+static void pl011_rs485_tx_resume(struct uart_amba_port *uap,
+ const struct serial_rs485 *rs485)
+{
+ struct tty_port *tport = &uap->port.state->port;
+ u32 cr = pl011_read(uap, REG_CR);
+
+ cr |= UART011_CR_TXE;
+ if (!(rs485->flags & SER_RS485_RX_DURING_TX))
+ cr &= ~UART011_CR_RXE;
+ if (rs485->flags & SER_RS485_RTS_ON_SEND)
+ cr &= ~UART011_CR_RTS;
+ else
+ cr |= UART011_CR_RTS;
+ pl011_write(cr, uap, REG_CR);
+
+ /*
+ * With only the FIFO left, the TX path does not stop the transmission.
+ * Drain it from the timer, which runs once the new settings are stored.
+ */
+ if (kfifo_is_empty(&tport->xmit_fifo) && !pl011_dma_tx_queued(uap)) {
+ uap->rs485_tx_state = WAIT_AFTER_SEND;
+ hrtimer_start(&uap->trigger_stop_tx, uap->rs485_tx_drain_interval,
+ HRTIMER_MODE_REL);
+ } else {
+ uap->rs485_tx_state = SEND;
+ }
+}
+
static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485)
{
@@ -2483,6 +2527,9 @@ static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
if (tx_pending && !uart_tx_stopped(port) &&
!pl011_dma_tx_start(uap))
pl011_start_tx_pio(uap);
+ } else if ((rs485->flags & SER_RS485_ENABLED) &&
+ uap->rs485_tx_state == OFF && pl011_tx_pending(uap)) {
+ pl011_rs485_tx_resume(uap, rs485);
} else if (port->rs485.flags & SER_RS485_ENABLED) {
pl011_rs485_tx_stop(uap);
}
--
2.53.0