diff mbox series

[v4,1/2] serial: mxc: Wait for TX completion before reset

Message ID 20230112171951.2082899-1-loic.poulain@linaro.org
State Accepted
Commit 7150f56a85fd8d3b8ad162621026b0ba7bb6a367
Headers show
Series [v4,1/2] serial: mxc: Wait for TX completion before reset | expand

Commit Message

Loic Poulain Jan. 12, 2023, 5:19 p.m. UTC
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(-)

Comments

Pali Rohár Jan. 12, 2023, 5:51 p.m. UTC | #1
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
>
Fabio Estevam Jan. 12, 2023, 5:51 p.m. UTC | #2
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>
diff mbox series

Patch

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,