[PATCH v4 1/2] 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 --- v2: Add this commit to the series v3: Fix typo & reordering commits for good bisectabilit v4: Wait for transfer completion before baudrate change as well
drivers/serial/serial_mxc.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index 82c0d84628..9e5b987994 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,

Instead of waiting for empty FIFO condition before writing a character, wait for non-full FIFO condition.
This helps in saving several tens of milliseconds during boot (depending verbosity).
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 --- v2: fixing transfert abort & char corruption commit v3: Reordering commits for good bisectability v4: no code change
drivers/serial/serial_mxc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index 9e5b987994..cac1922354 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -240,11 +240,11 @@ static void mxc_serial_putc(const char c) if (c == '\n') serial_putc('\r');
- writel(c, &mxc_base->txd); - /* wait for transmitter to be ready */ - while (!(readl(&mxc_base->ts) & UTS_TXEMPTY)) + while (readl(&mxc_base->ts) & UTS_TXFULL) schedule(); + + writel(c, &mxc_base->txd); }
/* Test whether a character is in the RX buffer */ @@ -335,7 +335,7 @@ static int mxc_serial_putc(struct udevice *dev, const char ch) struct mxc_serial_plat *plat = dev_get_plat(dev); struct mxc_uart *const uart = plat->reg;
- if (!(readl(&uart->ts) & UTS_TXEMPTY)) + if (readl(&uart->ts) & UTS_TXFULL) return -EAGAIN;
writel(ch, &uart->txd);

On Thu, Jan 12, 2023 at 2:19 PM Loic Poulain loic.poulain@linaro.org wrote:
Instead of waiting for empty FIFO condition before writing a character, wait for non-full FIFO condition.
This helps in saving several tens of milliseconds during boot (depending verbosity).
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

On Thu, Jan 12, 2023 at 2:52 PM Fabio Estevam festevam@gmail.com wrote:
On Thu, Jan 12, 2023 at 2:19 PM Loic Poulain loic.poulain@linaro.org wrote:
Instead of waiting for empty FIFO condition before writing a character, wait for non-full FIFO condition.
This helps in saving several tens of milliseconds during boot (depending verbosity).
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
Also tested on an imx8mm-evk board by printing inside board_init().
No more corruption is seen like the one we observed during Johannes' attempt last time:
Tested-by: Fabio Estevam festevam@denx.de
Nice work, Loic!

Instead of waiting for empty FIFO condition before writing a character, wait for non-full FIFO condition. This helps in saving several tens of milliseconds during boot (depending verbosity). 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 Tested-by: Fabio Estevam festevam@denx.de
Applied to u-boot-imx, master, thanks !
Best regards, Stefano Babic

On Thursday 12 January 2023 18:19:50 Loic Poulain wrote:
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
v2: Add this commit to the series v3: Fix typo & reordering commits for good bisectabilit v4: Wait for transfer completion before baudrate change as well
drivers/serial/serial_mxc.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index 82c0d84628..9e5b987994 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,
-- 2.34.1

On Thu, Jan 12, 2023 at 2:19 PM Loic Poulain loic.poulain@linaro.org wrote:
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
Reviewed-by: Fabio Estevam festevam@denx.de

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
Applied to u-boot-imx, master, thanks !
Best regards, Stefano Babic
participants (4)
-
Fabio Estevam
-
Loic Poulain
-
Pali Rohár
-
sbabic@denx.de