summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoic Poulain <loic.poulain@linaro.org>2023-01-12 18:19:50 +0100
committerStefano Babic <sbabic@denx.de>2023-01-30 23:23:02 +0100
commit7150f56a85fd8d3b8ad162621026b0ba7bb6a367 (patch)
treee666ee09acee284d07d40b434cba5c90e6ac03de
parent068027b1a0c1f445d9f4da88ab74b165f902b206 (diff)
serial: mxc: Wait for TX completion before reset
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>
-rw-r--r--drivers/serial/serial_mxc.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c
index 8bcbbf2bbf..e4ffa9c3f6 100644
--- a/drivers/serial/serial_mxc.c
+++ b/drivers/serial/serial_mxc.c
@@ -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,