[PATCH] serial: amba-pl011: keep transmitter enabled when disabling RS485

From: Nicolai Buchwitz

Date: Sun Oct 11 2026 - 15:49:37 EST


Disabling RS485 on an open port calls pl011_rs485_tx_stop(), which
turns off the transmitter. Only the RS485 TX path turns it back on, so
any later output stays queued and tcdrain() hangs until the port is
closed.

pl011_rs485_tx_stop() also checks only the hardware FIFO. If a DMA
transfer has started but has not filled the FIFO yet, the transmitter
is turned off under the transfer and the DMA channel never recovers.

When leaving RS485 mode, cancel any pending deferred stop and leave the
transmitter enabled.

Fixes: 8d479237727c ("serial: amba-pl011: add RS485 support")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Nicolai Buchwitz <nb@xxxxxxxxxxx>
---
Noticed while implementing a DMX master on a CM5 with its PL011.
Userspace turns RS485 mode off to send the break, and the port then
stopped transmitting.

Tested on that board with an RS485 transceiver at 9600, 115200 and
250000 baud.
---
drivers/tty/serial/amba-pl011.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index c4824c201e1c..d53dd934cc74 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2397,8 +2397,24 @@ static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);

- if (port->rs485.flags & SER_RS485_ENABLED)
+ if ((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(rs485->flags & SER_RS485_ENABLED)) {
+ u32 cr = pl011_read(uap, REG_CR);
+
+ /*
+ * Leaving RS485 mode, which only enables the transmitter while
+ * sending. Don't stop it, as that stalls a DMA transfer still
+ * in flight. Drop a pending deferred stop and keep it enabled.
+ */
+ hrtimer_try_to_cancel(&uap->trigger_start_tx);
+ hrtimer_try_to_cancel(&uap->trigger_stop_tx);
+ uap->rs485_tx_state = OFF;
+
+ cr |= UART011_CR_TXE | UART011_CR_RXE;
+ pl011_write(cr, uap, REG_CR);
+ } else if (port->rs485.flags & SER_RS485_ENABLED) {
pl011_rs485_tx_stop(uap);
+ }

/* Make sure auto RTS is disabled */
if (rs485->flags & SER_RS485_ENABLED) {

---
base-commit: a90ee4305c4a5df72c11b31dacfdc76e00fcf78a
change-id: 20261011-fix-pl011-rs485-txe-f61e1c969f9a

Best regards,
--
Nicolai Buchwitz <nb@xxxxxxxxxxx>