Patch "serial: 8250: 8250_omap: Avoid RS485 RTS glitch on ->set_termios()" has been added to the 4.19-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    serial: 8250: 8250_omap: Avoid RS485 RTS glitch on ->set_termios()

to the 4.19-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     serial-8250-8250_omap-avoid-rs485-rts-glitch-on-set_.patch
and it can be found in the queue-4.19 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit e9d5349fb1aa917e2fe91a53b4715d06198745b0
Author: Lukas Wunner <lukas@xxxxxxxxx>
Date:   Tue Sep 27 13:52:34 2022 +0200

    serial: 8250: 8250_omap: Avoid RS485 RTS glitch on ->set_termios()
    
    [ Upstream commit 038ee49fef18710bedd38b531d173ccd746b2d8d ]
    
    RS485-enabled UART ports on TI Sitara SoCs with active-low polarity
    exhibit a Transmit Enable glitch on ->set_termios():
    
    omap8250_restore_regs(), which is called from omap_8250_set_termios(),
    sets the TCRTLR bit in the MCR register and clears all other bits,
    including RTS.  If RTS uses active-low polarity, it is now asserted
    for no reason.
    
    The TCRTLR bit is subsequently cleared by writing up->mcr to the MCR
    register.  That variable is always zero, so the RTS bit is still cleared
    (incorrectly so if RTS is active-high).
    
    (up->mcr is not, as one might think, a cache of the MCR register's
    current value.  Rather, it only caches a single bit of that register,
    the AFE bit.  And it only does so if the UART supports the AFE bit,
    which OMAP does not.  For details see serial8250_do_set_termios() and
    serial8250_do_set_mctrl().)
    
    Finally at the end of omap8250_restore_regs(), the MCR register is
    restored (and RTS deasserted) by a call to up->port.ops->set_mctrl()
    (which equals serial8250_set_mctrl()) and serial8250_em485_stop_tx().
    
    So there's an RTS glitch between setting TCRTLR and calling
    serial8250_em485_stop_tx().  Avoid by using a read-modify-write
    when setting TCRTLR.
    
    While at it, drop a redundant initialization of up->mcr.  As explained
    above, the variable isn't used by the driver and it is already
    initialized to zero because it is part of the static struct
    serial8250_ports[] declared in 8250_core.c.  (Static structs are
    initialized to zero per section 6.7.8 nr. 10 of the C99 standard.)
    
    Cc: Jan Kiszka <jan.kiszka@xxxxxxxxxxx>
    Cc: Su Bao Cheng <baocheng.su@xxxxxxxxxxx>
    Tested-by: Matthias Schiffer <matthias.schiffer@xxxxxxxxxxxxxxx>
    Signed-off-by: Lukas Wunner <lukas@xxxxxxxxx>
    Link: https://lore.kernel.org/r/6554b0241a2c7fd50f32576fdbafed96709e11e8.1664278942.git.lukas@xxxxxxxxx
    Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 8cf4819312f5..b9352d3bb2ed 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -244,6 +244,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
 {
 	struct omap8250_priv *priv = up->port.private_data;
 	struct uart_8250_dma	*dma = up->dma;
+	u8 mcr = serial8250_in_MCR(up);
 
 	if (dma && dma->tx_running) {
 		/*
@@ -260,7 +261,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
 	serial_out(up, UART_EFR, UART_EFR_ECB);
 
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-	serial8250_out_MCR(up, UART_MCR_TCRTLR);
+	serial8250_out_MCR(up, mcr | UART_MCR_TCRTLR);
 	serial_out(up, UART_FCR, up->fcr);
 
 	omap8250_update_scr(up, priv);
@@ -276,7 +277,8 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
 	serial_out(up, UART_LCR, 0);
 
 	/* drop TCR + TLR access, we setup XON/XOFF later */
-	serial8250_out_MCR(up, up->mcr);
+	serial8250_out_MCR(up, mcr);
+
 	serial_out(up, UART_IER, up->ier);
 
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -585,7 +587,6 @@ static int omap_8250_startup(struct uart_port *port)
 
 	pm_runtime_get_sync(port->dev);
 
-	up->mcr = 0;
 	serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
 
 	serial_out(up, UART_LCR, UART_LCR_WLEN8);



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux