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...@bp.renesas.com> Tested-by: Chris Paterson <chris.paters...@renesas.com> # HiHope RZ/G2M board Tested-by: Marek Vasut <marek.vasut+rene...@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