BUG: imx: initial UART receive causes IO errors

Stefan Wahren stefan.wahren at i2se.com
Tue Nov 17 03:14:29 EST 2020


Hi,

we are using a Modbus application on our customer i.MX6ULL board (RS-485
in hardware, no DMA). While porting the board support package to a
Mainline kernel, we noticed that after boot the initial UART receive
causes IO errors, which breaks our application (tested with Mainline
4.9, 4.19, 5.7, 5.9 but without success). The ancient vendor kernel
(imx-4.9.11) we are still using isn't affect by this issue.

So i bisected the vendor tree and found this huge patch which fixed the
issue [1]. After that i was able to narrow down the fix to the following
patch against Mainline Linux 5.9 (successful tested on i.MX6ULL):

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 07974f2..3004b5c 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1289,6 +1289,7 @@ static void imx_uart_clear_rx_errors(struct
imx_port *sport)
 
 #define TXTL_DEFAULT 2 /* reset default */
 #define RXTL_DEFAULT 1 /* reset default */
+#define RXTL_UART 16 /* For UART */
 #define TXTL_DMA 8 /* DMA burst setting */
 #define RXTL_DMA 9 /* DMA burst setting */
 
@@ -1415,6 +1416,7 @@ static int imx_uart_startup(struct uart_port *port)
     unsigned long flags;
     int dma_is_inited = 0;
     u32 ucr1, ucr2, ucr3, ucr4;
+    unsigned char rx_fifo_trig;
 
     retval = clk_prepare_enable(sport->clk_per);
     if (retval)
@@ -1425,7 +1427,12 @@ static int imx_uart_startup(struct uart_port *port)
         return retval;
     }
 
-    imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+    if (uart_console(&sport->port))
+        rx_fifo_trig = RXTL_DEFAULT;
+    else
+        rx_fifo_trig = RXTL_UART;
+
+    imx_uart_setup_ufcr(sport, TXTL_DEFAULT, rx_fifo_trig);
 
     /* disable the DREN bit (Data Ready interrupt enable) before
      * requesting IRQs
@@ -1674,7 +1681,7 @@ imx_uart_set_termios(struct uart_port *port,
struct ktermios *termios,
      * except those we will or may need to preserve.
      */
     old_ucr2 = imx_uart_readl(sport, UCR2);
-    ucr2 = old_ucr2 & (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN | UCR2_CTS);
+    ucr2 = old_ucr2 & (UCR2_TXEN | UCR2_RXEN | UCR2_CTS);
 
     ucr2 |= UCR2_SRST | UCR2_IRTS;
     if ((termios->c_cflag & CSIZE) == CS8)
@@ -1795,6 +1802,9 @@ imx_uart_set_termios(struct uart_port *port,
struct ktermios *termios,
     if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
         imx_uart_enable_ms(&sport->port);
 
+    ucr2 = imx_uart_readl(sport, UCR2);
+    imx_uart_writel(sport, ucr2 | UCR2_ATEN, UCR2);
+
     spin_unlock_irqrestore(&sport->port.lock, flags);
 }

So i someone with a deeper insight can fix this properly.

Thanks Stefan

[1] -
https://source.codeaurora.org/external/imx/linux-imx/commit/drivers/tty/serial/imx.c?h=imx_4.9.11_1.0.0_ga&id=e287334648e0a0f6a76f3d9615eada6cd590cbd9





More information about the linux-arm-kernel mailing list