[PATCH v4 1/2] serial: sh: Fix error handling

Paul Barker paul.barker.ct at bp.renesas.com
Thu Oct 19 16:30:43 CEST 2023


The current SCIF error handling is broken for the RZ/G2L. After a break
condition has been triggered, the current code is unable to clear the
error and serial port output never resumes.

The RZ/G2L datasheet says that most error conditions are cleared by
resetting the relevant error bits in the FSR & LSR registers to zero.
To clear framing errors on SCIF ports, the invalid data also needs to be
read out of the receive FIFO.

After reviewing datasheets for RZ/G2{H,M,N,E}, R-Car Gen4, R-Car Gen3
and even SH7751 SoCs, it's clear that this is the way to clear errors
for all of these SoCs.

While we're here, annotate the handle_error() function with a couple of
comments as the reads and writes themselves don't immediately make it
clear what we're doing.

Signed-off-by: Paul Barker <paul.barker.ct at bp.renesas.com>
Tested-by: Chris Paterson <chris.paterson2 at renesas.com>
	# HiHope RZ/G2M board
Tested-by: Marek Vasut <marek.vasut+renesas at mailbox.org>
	# R-Car H3 Salvator-XS

v3->v4:
  * Don't assume that all the world is a SCIF - handle SCI ports
    correctly as well.
v2->v3:
  * Added Chris' and Marek's Tested-by.
v1->v2:
  * New patch after discussion with Marek & further investigation.
---
 drivers/serial/serial_sh.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c
index 36263109e6b8..9a698b19ccde 100644
--- a/drivers/serial/serial_sh.c
+++ b/drivers/serial/serial_sh.c
@@ -79,10 +79,22 @@ sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate)
 
 static void handle_error(struct uart_port *port)
 {
-	sci_in(port, SCxSR);
-	sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+	/*
+	 * Most errors are cleared by resetting the relevant error bits to zero
+	 * in the FSR & LSR registers. For each register, a read followed by a
+	 * write is needed according to the relevant datasheets.
+	 */
+	unsigned short status = sci_in(port, SCxSR);
+	sci_out(port, SCxSR, status & ~SCxSR_ERRORS(port));
 	sci_in(port, SCLSR);
 	sci_out(port, SCLSR, 0x00);
+
+	/*
+	 * To clear framing errors, we also need to read and discard a
+	 * character.
+	 */
+	if ((port->type != PORT_SCI) && (status & SCIF_FER))
+		sci_in(port, SCxRDR);
 }
 
 static int serial_raw_putc(struct uart_port *port, const char c)
-- 
2.39.2



More information about the U-Boot mailing list