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: Sergey Organov <sorganov@gmail.com> Link: https://lore.kernel.org/r/1567017475-11919-5-git-send-email-sorganov@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
85f30fbf32
commit
d47bcb4a6c
1 changed files with 16 additions and 3 deletions
|
@ -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);
|
||||
|
||||
imx_uart_writel(sport, num, UBIR);
|
||||
imx_uart_writel(sport, denom, UBMR);
|
||||
/*
|
||||
* 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,
|
||||
|
|
Loading…
Reference in a new issue