serial/uart_16550: Wait before setting Line Control Register (Synopsys DesignWare 8250)

Some UART Controllers (Synopsys DesignWare 8250) will trigger spurious interrupts when the Line Control Register (LCR) is set while the UART is busy. This patch provides the option (16550_WAIT_LCR) to wait for UART until it's not busy, before setting the LCR. (16550_WAIT_LCR is disabled by default)

This patch fixes the spurious UART interrupts for the upcoming port of NuttX to StarFive JH7110 SoC (with Synopsys DesignWare 8250 UART). [The patch is explained here](https://lupyuen.github.io/articles/plic#appendix-fix-the-spurious-uart-interrupts)

drivers/serial/uart_16550.c: If 16550_WAIT_LCR is enabled, wait until UART is not busy before setting LCR

include/nuttx/serial/uart_16550.h: Define the UART Status Register (USR) for checking if UART is busy

drivers/serial/Kconfig-16550: Added option 16550_WAIT_LCR to 16550 UART Config, disabled by default
This commit is contained in:
Lee Lup Yuen 2023-08-03 08:15:35 +08:00 • committed by Alin Jerpelea
parent 1adef07a79
commit b2c1930825
3 changed files with 101 additions and 12 deletions

View file

@ -172,18 +172,19 @@
/* Register offsets *********************************************************/
#define UART_RBR_INCR 0 /* (DLAB =0) Receiver Buffer Register */
#define UART_THR_INCR 0 /* (DLAB =0) Transmit Holding Register */
#define UART_DLL_INCR 0 /* (DLAB =1) Divisor Latch LSB */
#define UART_DLM_INCR 1 /* (DLAB =1) Divisor Latch MSB */
#define UART_IER_INCR 1 /* (DLAB =0) Interrupt Enable Register */
#define UART_IIR_INCR 2 /* Interrupt ID Register */
#define UART_FCR_INCR 2 /* FIFO Control Register */
#define UART_LCR_INCR 3 /* Line Control Register */
#define UART_MCR_INCR 4 /* Modem Control Register */
#define UART_LSR_INCR 5 /* Line Status Register */
#define UART_MSR_INCR 6 /* Modem Status Register */
#define UART_SCR_INCR 7 /* Scratch Pad Register */
#define UART_RBR_INCR 0 /* (DLAB =0) Receiver Buffer Register */
#define UART_THR_INCR 0 /* (DLAB =0) Transmit Holding Register */
#define UART_DLL_INCR 0 /* (DLAB =1) Divisor Latch LSB */
#define UART_DLM_INCR 1 /* (DLAB =1) Divisor Latch MSB */
#define UART_IER_INCR 1 /* (DLAB =0) Interrupt Enable Register */
#define UART_IIR_INCR 2 /* Interrupt ID Register */
#define UART_FCR_INCR 2 /* FIFO Control Register */
#define UART_LCR_INCR 3 /* Line Control Register */
#define UART_MCR_INCR 4 /* Modem Control Register */
#define UART_LSR_INCR 5 /* Line Status Register */
#define UART_MSR_INCR 6 /* Modem Status Register */
#define UART_SCR_INCR 7 /* Scratch Pad Register */
#define UART_USR_INCR 31 /* UART Status Register */
#define UART_RBR_OFFSET (CONFIG_16550_REGINCR*UART_RBR_INCR)
#define UART_THR_OFFSET (CONFIG_16550_REGINCR*UART_THR_INCR)
@ -197,6 +198,7 @@
#define UART_LSR_OFFSET (CONFIG_16550_REGINCR*UART_LSR_INCR)
#define UART_MSR_OFFSET (CONFIG_16550_REGINCR*UART_MSR_INCR)
#define UART_SCR_OFFSET (CONFIG_16550_REGINCR*UART_SCR_INCR)
#define UART_USR_OFFSET (CONFIG_16550_REGINCR*UART_USR_INCR)
/* Register bit definitions *************************************************/
@ -298,6 +300,10 @@
#define UART_SCR_MASK (0xff) /* Bits 0-7: SCR data */
/* USR UART Status Register */
#define UART_USR_BUSY (1 << 0) /* Bit 0: UART Busy */
/****************************************************************************
* Public Types
****************************************************************************/