Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d47bcb4a authored by Sergey Organov's avatar Sergey Organov Committed by Greg Kroah-Hartman
Browse files

serial: imx: fix data breakage on termios change



imx_set_termios(): avoid writing baud rate divider registers when the
values to be written are the same as current. Any writing seems to
restart transmission/receiving logic in the hardware, that leads to
data breakage even when rate doesn't in fact change. E.g., user
switches RTS/CTS handshake and suddenly gets broken bytes.

Signed-off-by: default avatarSergey Organov <sorganov@gmail.com>
Link: https://lore.kernel.org/r/1567017475-11919-5-git-send-email-sorganov@gmail.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 85f30fbf
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -1545,7 +1545,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
	unsigned int baud, quot;
	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
	unsigned long div;
	unsigned long num, denom;
	unsigned long num, denom, old_ubir, old_ubmr;
	uint64_t tdiv64;

	/*
@@ -1670,8 +1670,21 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
	ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
	imx_uart_writel(sport, ufcr, UFCR);

	/*
	 *  Two registers below should always be written both and in this
	 *  particular order. One consequence is that we need to check if any of
	 *  them changes and then update both. We do need the check for change
	 *  as even writing the same values seem to "restart"
	 *  transmission/receiving logic in the hardware, that leads to data
	 *  breakage even when rate doesn't in fact change. E.g., user switches
	 *  RTS/CTS handshake and suddenly gets broken bytes.
	 */
	old_ubir = imx_uart_readl(sport, UBIR);
	old_ubmr = imx_uart_readl(sport, UBMR);
	if (old_ubir != num || old_ubmr != denom) {
		imx_uart_writel(sport, num, UBIR);
		imx_uart_writel(sport, denom, UBMR);
	}

	if (!imx_uart_is_imx1(sport))
		imx_uart_writel(sport, sport->port.uartclk / div / 1000,