Skip to content

Commit

Permalink
Copy LCR from star64e
Browse files Browse the repository at this point in the history
  • Loading branch information
lupyuen committed Aug 3, 2023
1 parent 0cb8fdf commit 1c3a4f2
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 12 deletions.
9 changes: 9 additions & 0 deletions drivers/serial/Kconfig-16550
Original file line number Diff line number Diff line change
Expand Up @@ -519,4 +519,13 @@ config 16550_ADDRWIDTH
Default: 8
Note: 0 means auto detect address size (uintptr_t)

config 16550_WAIT_LCR
bool "Wait for UART before setting LCR"
default n
---help---
Before setting the Line Control Register (LCR), wait until UART is
not busy. This is required for Synopsys DesignWare 8250, which
will trigger spurious interrupts when setting the LCR without
waiting. Default: n

endif # 16550_UART
74 changes: 74 additions & 0 deletions drivers/serial/uart_16550.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@

#ifdef CONFIG_16550_UART

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

/* Timeout for UART Busy Wait, in milliseconds */

#define UART_TIMEOUT_MS 100

/****************************************************************************
* Private Types
****************************************************************************/
Expand Down Expand Up @@ -622,6 +630,43 @@ static inline void u16550_serialout(FAR struct u16550_s *priv, int offset,
#endif
}

#ifdef CONFIG_16550_WAIT_LCR
/****************************************************************************
* Name: u16550_wait
*
* Description:
* Wait until UART is not busy. This is needed before writing to LCR.
* Otherwise we will get spurious interrupts on Synopsys DesignWare 8250.
*
* Input Parameters:
* priv: UART Struct
*
* Returned Value:
* Zero (OK) on success; ERROR if timeout.
*
****************************************************************************/

static int u16550_wait(FAR struct u16550_s *priv)
{
int i;

for (i = 0; i < UART_TIMEOUT_MS; i++)
{
uint32_t status = u16550_serialin(priv, UART_USR_OFFSET);

if ((status & UART_USR_BUSY) == 0)
{
return OK;
}

up_mdelay(1);
}

_err("UART timeout\n");
return ERROR;
}
#endif /* CONFIG_16550_WAIT_LCR */

/****************************************************************************
* Name: u16550_disableuartint
****************************************************************************/
Expand Down Expand Up @@ -667,6 +712,15 @@ static inline void u16550_enablebreaks(FAR struct u16550_s *priv,
lcr &= ~UART_LCR_BRK;
}

#ifdef CONFIG_16550_WAIT_LCR
/* Wait till UART is not busy before setting LCR */

if (u16550_wait(priv) < 0)
{
_err("UART wait failed\n");
}
#endif /* CONFIG_16550_WAIT_LCR */

u16550_serialout(priv, UART_LCR_OFFSET, lcr);
}

Expand Down Expand Up @@ -761,6 +815,16 @@ static int u16550_setup(FAR struct uart_dev_s *dev)
lcr |= (UART_LCR_PEN | UART_LCR_EPS);
}

#ifdef CONFIG_16550_WAIT_LCR
/* Wait till UART is not busy before setting LCR */

if (u16550_wait(priv) < 0)
{
_err("UART wait failed\n");
return ERROR;
}
#endif /* CONFIG_16550_WAIT_LCR */

/* Enter DLAB=1 */

u16550_serialout(priv, UART_LCR_OFFSET, (lcr | UART_LCR_DLAB));
Expand All @@ -771,6 +835,16 @@ static int u16550_setup(FAR struct uart_dev_s *dev)
u16550_serialout(priv, UART_DLM_OFFSET, div >> 8);
u16550_serialout(priv, UART_DLL_OFFSET, div & 0xff);

#ifdef CONFIG_16550_WAIT_LCR
/* Wait till UART is not busy before setting LCR */

if (u16550_wait(priv) < 0)
{
_err("UART wait failed\n");
return ERROR;
}
#endif /* CONFIG_16550_WAIT_LCR */

/* Clear DLAB */

u16550_serialout(priv, UART_LCR_OFFSET, lcr);
Expand Down
30 changes: 18 additions & 12 deletions include/nuttx/serial/uart_16550.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 *************************************************/

Expand Down Expand Up @@ -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
****************************************************************************/
Expand Down

0 comments on commit 1c3a4f2

Please sign in to comment.