]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
serial: mxc: Wait for TX completion before reset
authorLoic Poulain <loic.poulain@linaro.org>
Thu, 12 Jan 2023 17:19:50 +0000 (18:19 +0100)
committerStefano Babic <sbabic@denx.de>
Mon, 30 Jan 2023 22:23:02 +0000 (23:23 +0100)
The u-boot console may show some corrupted characters when
printing in board_init() due to reset or baudrate change
of the UART (probe) before the TX FIFO has been completely
drained.

To fix this issue, and in case UART is still running, we now
try to flush the FIFO before proceeding to UART reinitialization.
For this we're waiting for Transmitter Complete bit, indicating
that the FIFO and the shift register are empty.

flushing has a 4ms timeout guard, which is normally more than
enough to consume the FIFO @ low baudrate (9600bps).

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
Tested-by: Lothar Waßmann <LW@KARO-electronics.de>
Acked-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Fabio Estevam <festevam@denx.de>
drivers/serial/serial_mxc.c

index 8bcbbf2bbfcba9ce52bf57ba012ff60e3455d800..e4ffa9c3f6b2682470f1e6b1925142a8952e8496 100644 (file)
@@ -13,6 +13,7 @@
 #include <dm/platform_data/serial_mxc.h>
 #include <serial.h>
 #include <linux/compiler.h>
+#include <linux/delay.h>
 
 /* UART Control Register Bit Fields.*/
 #define URXD_CHARRDY   (1<<15)
@@ -144,8 +145,22 @@ struct mxc_uart {
        u32 ts;
 };
 
+static void _mxc_serial_flush(struct mxc_uart *base)
+{
+       unsigned int timeout = 4000;
+
+       if (!(readl(&base->cr1) & UCR1_UARTEN) ||
+           !(readl(&base->cr2) & UCR2_TXEN))
+               return;
+
+       while (!(readl(&base->sr2) & USR2_TXDC) && --timeout)
+               udelay(1);
+}
+
 static void _mxc_serial_init(struct mxc_uart *base, int use_dte)
 {
+       _mxc_serial_flush(base);
+
        writel(0, &base->cr1);
        writel(0, &base->cr2);
 
@@ -169,6 +184,8 @@ static void _mxc_serial_setbrg(struct mxc_uart *base, unsigned long clk,
 {
        u32 tmp;
 
+       _mxc_serial_flush(base);
+
        tmp = RFDIV << UFCR_RFDIV_SHF;
        if (use_dte)
                tmp |= UFCR_DCEDTE;
@@ -252,10 +269,17 @@ static int mxc_serial_init(void)
        return 0;
 }
 
+static int mxc_serial_stop(void)
+{
+       _mxc_serial_flush(mxc_base);
+
+       return 0;
+}
+
 static struct serial_device mxc_serial_drv = {
        .name   = "mxc_serial",
        .start  = mxc_serial_init,
-       .stop   = NULL,
+       .stop   = mxc_serial_stop,
        .setbrg = mxc_serial_setbrg,
        .putc   = mxc_serial_putc,
        .puts   = default_serial_puts,