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: 48a6092fb4 ("serial: stm32-usart: Add STM32 USART Driver")
Signed-off-by: Erwan Le Ray <erwan.leray@st.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Erwan Le Ray 2019-05-21 17:45:42 +02:00 committed by Greg Kroah-Hartman
parent c8a9d04394
commit 4f01d833fd
2 changed files with 37 additions and 27 deletions

View File

@ -225,35 +225,51 @@ 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) {
port->icount.frame++;
/* 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)
flag = TTY_FRAME;
} else if (sr & USART_SR_FE) {
if (!c)
flag = TTY_BREAK;
else
flag = TTY_FRAME;
}
}
if (uart_handle_sysrq_char(port, c))
@ -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).

View File

@ -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 */