Skip to content

Commit 2474e05

Browse files
SherrySun5gregkh
authored andcommitted
tty: serial: fsl_lpuart: use UARTCTRL_TXINV to send break instead of UARTCTRL_SBK
LPUART IP now has two known bugs, one is that CTS has higher priority than the break signal, which causes the break signal sending through UARTCTRL_SBK may impacted by the CTS input if the HW flow control is enabled. It exists on all platforms we support in this driver. So we add a workaround patch for this issue: commit c4c81db ("tty: serial: fsl_lpuart: disable the CTS when send break signal"). Another IP bug is i.MX8QM LPUART may have an additional break character being sent after SBK was cleared. It may need to add some delay between clearing SBK and re-enabling CTS to ensure that the SBK latch are completely cleared. But we found that during the delay period before CTS is enabled, there is still a risk that Bluetooth data in TX FIFO may be sent out during this period because of break off and CTS disabled(even if BT sets CTS line deasserted, data is still sent to BT). Due to this risk, we have to drop the CTS-disabling workaround for SBK bugs, use TXINV seems to be a better way to replace SBK feature and avoid above risk. Also need to disable the transmitter to prevent any data from being sent out during break, then invert the TX line to send break. Then disable the TXINV when turn off break and re-enable transmitter. Fixes: c4c81db ("tty: serial: fsl_lpuart: disable the CTS when send break signal") Cc: stable <[email protected]> Signed-off-by: Sherry Sun <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 134f49d commit 2474e05

File tree

1 file changed

+23
-21
lines changed

1 file changed

+23
-21
lines changed

drivers/tty/serial/fsl_lpuart.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,34 +1495,36 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state)
14951495

14961496
static void lpuart32_break_ctl(struct uart_port *port, int break_state)
14971497
{
1498-
unsigned long temp, modem;
1499-
struct tty_struct *tty;
1500-
unsigned int cflag = 0;
1501-
1502-
tty = tty_port_tty_get(&port->state->port);
1503-
if (tty) {
1504-
cflag = tty->termios.c_cflag;
1505-
tty_kref_put(tty);
1506-
}
1498+
unsigned long temp;
15071499

1508-
temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK;
1509-
modem = lpuart32_read(port, UARTMODIR);
1500+
temp = lpuart32_read(port, UARTCTRL);
15101501

1502+
/*
1503+
* LPUART IP now has two known bugs, one is CTS has higher priority than the
1504+
* break signal, which causes the break signal sending through UARTCTRL_SBK
1505+
* may impacted by the CTS input if the HW flow control is enabled. It
1506+
* exists on all platforms we support in this driver.
1507+
* Another bug is i.MX8QM LPUART may have an additional break character
1508+
* being sent after SBK was cleared.
1509+
* To avoid above two bugs, we use Transmit Data Inversion function to send
1510+
* the break signal instead of UARTCTRL_SBK.
1511+
*/
15111512
if (break_state != 0) {
1512-
temp |= UARTCTRL_SBK;
15131513
/*
1514-
* LPUART CTS has higher priority than SBK, need to disable CTS before
1515-
* asserting SBK to avoid any interference if flow control is enabled.
1514+
* Disable the transmitter to prevent any data from being sent out
1515+
* during break, then invert the TX line to send break.
15161516
*/
1517-
if (cflag & CRTSCTS && modem & UARTMODIR_TXCTSE)
1518-
lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
1517+
temp &= ~UARTCTRL_TE;
1518+
lpuart32_write(port, temp, UARTCTRL);
1519+
temp |= UARTCTRL_TXINV;
1520+
lpuart32_write(port, temp, UARTCTRL);
15191521
} else {
1520-
/* Re-enable the CTS when break off. */
1521-
if (cflag & CRTSCTS && !(modem & UARTMODIR_TXCTSE))
1522-
lpuart32_write(port, modem | UARTMODIR_TXCTSE, UARTMODIR);
1522+
/* Disable the TXINV to turn off break and re-enable transmitter. */
1523+
temp &= ~UARTCTRL_TXINV;
1524+
lpuart32_write(port, temp, UARTCTRL);
1525+
temp |= UARTCTRL_TE;
1526+
lpuart32_write(port, temp, UARTCTRL);
15231527
}
1524-
1525-
lpuart32_write(port, temp, UARTCTRL);
15261528
}
15271529

15281530
static void lpuart_setup_watermark(struct lpuart_port *sport)

0 commit comments

Comments
 (0)