Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f01d833 authored by Erwan Le Ray's avatar Erwan Le Ray Committed by Greg Kroah-Hartman
Browse files

serial: stm32: fix rx error handling



- Fixes parity and framing error bit by clearing parity and framing error
  flag. The current implementation doesn't clear the error bits when an
  error is detected.
- Fixes the incorrect name of framing error clearing flag in header file.
- Fixes misalignement between data frame and errors status. The status
  read for "n" frame was the status of "n+1" frame".
- Fixes break detection was not triggered by the expected register.

Fixes: 48a6092f ("serial: stm32-usart: Add STM32 USART Driver")
Signed-off-by: default avatarErwan Le Ray <erwan.leray@st.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c8a9d043
Loading
Loading
Loading
Loading
+35 −19
Original line number Diff line number Diff line
@@ -225,36 +225,52 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded)

	while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) {
		sr |= USART_SR_DUMMY_RX;
		c = stm32_get_char(port, &sr, &stm32_port->last_res);
		flag = TTY_NORMAL;
		port->icount.rx++;

		/*
		 * Status bits has to be cleared before reading the RDR:
		 * In FIFO mode, reading the RDR will pop the next data
		 * (if any) along with its status bits into the SR.
		 * Not doing so leads to misalignement between RDR and SR,
		 * and clear status bits of the next rx data.
		 *
		 * Clear errors flags for stm32f7 and stm32h7 compatible
		 * devices. On stm32f4 compatible devices, the error bit is
		 * cleared by the sequence [read SR - read DR].
		 */
		if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG)
			stm32_clr_bits(port, ofs->icr, USART_ICR_ORECF |
				       USART_ICR_PECF | USART_ICR_FECF);

		c = stm32_get_char(port, &sr, &stm32_port->last_res);
		port->icount.rx++;
		if (sr & USART_SR_ERR_MASK) {
			if (sr & USART_SR_LBD) {
				port->icount.brk++;
				if (uart_handle_break(port))
					continue;
			} else if (sr & USART_SR_ORE) {
				if (ofs->icr != UNDEF_REG)
					writel_relaxed(USART_ICR_ORECF,
						       port->membase +
						       ofs->icr);
			if (sr & USART_SR_ORE) {
				port->icount.overrun++;
			} else if (sr & USART_SR_PE) {
				port->icount.parity++;
			} else if (sr & USART_SR_FE) {
				/* Break detection if character is null */
				if (!c) {
					port->icount.brk++;
					if (uart_handle_break(port))
						continue;
				} else {
					port->icount.frame++;
				}
			}

			sr &= port->read_status_mask;

			if (sr & USART_SR_LBD)
				flag = TTY_BREAK;
			else if (sr & USART_SR_PE)
			if (sr & USART_SR_PE) {
				flag = TTY_PARITY;
			else if (sr & USART_SR_FE)
			} else if (sr & USART_SR_FE) {
				if (!c)
					flag = TTY_BREAK;
				else
					flag = TTY_FRAME;
			}
		}

		if (uart_handle_sysrq_char(port, c))
			continue;
@@ -721,14 +737,14 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
	if (termios->c_iflag & INPCK)
		port->read_status_mask |= USART_SR_PE | USART_SR_FE;
	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
		port->read_status_mask |= USART_SR_LBD;
		port->read_status_mask |= USART_SR_FE;

	/* Characters to ignore */
	port->ignore_status_mask = 0;
	if (termios->c_iflag & IGNPAR)
		port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
	if (termios->c_iflag & IGNBRK) {
		port->ignore_status_mask |= USART_SR_LBD;
		port->ignore_status_mask |= USART_SR_FE;
		/*
		 * If we're ignoring parity and break indicators,
		 * ignore overruns too (for real raw support).
+2 −8
Original line number Diff line number Diff line
@@ -108,7 +108,6 @@ struct stm32_usart_info stm32h7_info = {
#define USART_SR_RXNE		BIT(5)
#define USART_SR_TC		BIT(6)
#define USART_SR_TXE		BIT(7)
#define USART_SR_LBD		BIT(8)
#define USART_SR_CTSIF		BIT(9)
#define USART_SR_CTS		BIT(10)		/* F7 */
#define USART_SR_RTOF		BIT(11)		/* F7 */
@@ -120,8 +119,7 @@ struct stm32_usart_info stm32h7_info = {
#define USART_SR_SBKF		BIT(18)		/* F7 */
#define USART_SR_WUF		BIT(20)		/* H7 */
#define USART_SR_TEACK		BIT(21)		/* F7 */
#define USART_SR_ERR_MASK	(USART_SR_LBD | USART_SR_ORE | \
				 USART_SR_FE | USART_SR_PE)
#define USART_SR_ERR_MASK	(USART_SR_ORE | USART_SR_FE | USART_SR_PE)
/* Dummy bits */
#define USART_SR_DUMMY_RX	BIT(16)

@@ -168,8 +166,6 @@ struct stm32_usart_info stm32h7_info = {
/* USART_CR2 */
#define USART_CR2_ADD_MASK	GENMASK(3, 0)	/* F4 */
#define USART_CR2_ADDM7		BIT(4)		/* F7 */
#define USART_CR2_LBDL		BIT(5)
#define USART_CR2_LBDIE		BIT(6)
#define USART_CR2_LBCL		BIT(8)
#define USART_CR2_CPHA		BIT(9)
#define USART_CR2_CPOL		BIT(10)
@@ -226,12 +222,10 @@ struct stm32_usart_info stm32h7_info = {

/* USART_ICR */
#define USART_ICR_PECF		BIT(0)		/* F7 */
#define USART_ICR_FFECF		BIT(1)		/* F7 */
#define USART_ICR_NCF		BIT(2)		/* F7 */
#define USART_ICR_FECF		BIT(1)		/* F7 */
#define USART_ICR_ORECF		BIT(3)		/* F7 */
#define USART_ICR_IDLECF	BIT(4)		/* F7 */
#define USART_ICR_TCCF		BIT(6)		/* F7 */
#define USART_ICR_LBDCF		BIT(8)		/* F7 */
#define USART_ICR_CTSCF		BIT(9)		/* F7 */
#define USART_ICR_RTOCF		BIT(11)		/* F7 */
#define USART_ICR_EOBCF		BIT(12)		/* F7 */