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: 48a6092fb41f ("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:
parent
c8a9d04394
commit
4f01d833fd
@ -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)) {
|
while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) {
|
||||||
sr |= USART_SR_DUMMY_RX;
|
sr |= USART_SR_DUMMY_RX;
|
||||||
c = stm32_get_char(port, &sr, &stm32_port->last_res);
|
|
||||||
flag = TTY_NORMAL;
|
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_ERR_MASK) {
|
||||||
if (sr & USART_SR_LBD) {
|
if (sr & USART_SR_ORE) {
|
||||||
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);
|
|
||||||
port->icount.overrun++;
|
port->icount.overrun++;
|
||||||
} else if (sr & USART_SR_PE) {
|
} else if (sr & USART_SR_PE) {
|
||||||
port->icount.parity++;
|
port->icount.parity++;
|
||||||
} else if (sr & USART_SR_FE) {
|
} 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;
|
sr &= port->read_status_mask;
|
||||||
|
|
||||||
if (sr & USART_SR_LBD)
|
if (sr & USART_SR_PE) {
|
||||||
flag = TTY_BREAK;
|
|
||||||
else if (sr & USART_SR_PE)
|
|
||||||
flag = TTY_PARITY;
|
flag = TTY_PARITY;
|
||||||
else if (sr & USART_SR_FE)
|
} else if (sr & USART_SR_FE) {
|
||||||
flag = TTY_FRAME;
|
if (!c)
|
||||||
|
flag = TTY_BREAK;
|
||||||
|
else
|
||||||
|
flag = TTY_FRAME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uart_handle_sysrq_char(port, c))
|
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)
|
if (termios->c_iflag & INPCK)
|
||||||
port->read_status_mask |= USART_SR_PE | USART_SR_FE;
|
port->read_status_mask |= USART_SR_PE | USART_SR_FE;
|
||||||
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
|
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
|
||||||
port->read_status_mask |= USART_SR_LBD;
|
port->read_status_mask |= USART_SR_FE;
|
||||||
|
|
||||||
/* Characters to ignore */
|
/* Characters to ignore */
|
||||||
port->ignore_status_mask = 0;
|
port->ignore_status_mask = 0;
|
||||||
if (termios->c_iflag & IGNPAR)
|
if (termios->c_iflag & IGNPAR)
|
||||||
port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
|
port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
|
||||||
if (termios->c_iflag & IGNBRK) {
|
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,
|
* If we're ignoring parity and break indicators,
|
||||||
* ignore overruns too (for real raw support).
|
* ignore overruns too (for real raw support).
|
||||||
|
@ -108,7 +108,6 @@ struct stm32_usart_info stm32h7_info = {
|
|||||||
#define USART_SR_RXNE BIT(5)
|
#define USART_SR_RXNE BIT(5)
|
||||||
#define USART_SR_TC BIT(6)
|
#define USART_SR_TC BIT(6)
|
||||||
#define USART_SR_TXE BIT(7)
|
#define USART_SR_TXE BIT(7)
|
||||||
#define USART_SR_LBD BIT(8)
|
|
||||||
#define USART_SR_CTSIF BIT(9)
|
#define USART_SR_CTSIF BIT(9)
|
||||||
#define USART_SR_CTS BIT(10) /* F7 */
|
#define USART_SR_CTS BIT(10) /* F7 */
|
||||||
#define USART_SR_RTOF BIT(11) /* 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_SBKF BIT(18) /* F7 */
|
||||||
#define USART_SR_WUF BIT(20) /* H7 */
|
#define USART_SR_WUF BIT(20) /* H7 */
|
||||||
#define USART_SR_TEACK BIT(21) /* F7 */
|
#define USART_SR_TEACK BIT(21) /* F7 */
|
||||||
#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
|
#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE)
|
||||||
USART_SR_FE | USART_SR_PE)
|
|
||||||
/* Dummy bits */
|
/* Dummy bits */
|
||||||
#define USART_SR_DUMMY_RX BIT(16)
|
#define USART_SR_DUMMY_RX BIT(16)
|
||||||
|
|
||||||
@ -168,8 +166,6 @@ struct stm32_usart_info stm32h7_info = {
|
|||||||
/* USART_CR2 */
|
/* USART_CR2 */
|
||||||
#define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */
|
#define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */
|
||||||
#define USART_CR2_ADDM7 BIT(4) /* F7 */
|
#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_LBCL BIT(8)
|
||||||
#define USART_CR2_CPHA BIT(9)
|
#define USART_CR2_CPHA BIT(9)
|
||||||
#define USART_CR2_CPOL BIT(10)
|
#define USART_CR2_CPOL BIT(10)
|
||||||
@ -226,12 +222,10 @@ struct stm32_usart_info stm32h7_info = {
|
|||||||
|
|
||||||
/* USART_ICR */
|
/* USART_ICR */
|
||||||
#define USART_ICR_PECF BIT(0) /* F7 */
|
#define USART_ICR_PECF BIT(0) /* F7 */
|
||||||
#define USART_ICR_FFECF BIT(1) /* F7 */
|
#define USART_ICR_FECF BIT(1) /* F7 */
|
||||||
#define USART_ICR_NCF BIT(2) /* F7 */
|
|
||||||
#define USART_ICR_ORECF BIT(3) /* F7 */
|
#define USART_ICR_ORECF BIT(3) /* F7 */
|
||||||
#define USART_ICR_IDLECF BIT(4) /* F7 */
|
#define USART_ICR_IDLECF BIT(4) /* F7 */
|
||||||
#define USART_ICR_TCCF BIT(6) /* 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_CTSCF BIT(9) /* F7 */
|
||||||
#define USART_ICR_RTOCF BIT(11) /* F7 */
|
#define USART_ICR_RTOCF BIT(11) /* F7 */
|
||||||
#define USART_ICR_EOBCF BIT(12) /* F7 */
|
#define USART_ICR_EOBCF BIT(12) /* F7 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user