From ead2c40cd48eddc939d8707c1d7266b29d68577d Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Sun, 26 Aug 2018 11:37:16 -0600 Subject: [PATCH] Squashed commit of the following: drivers/serial/uart_16550.c: Support 16550 auto hardware flow control drivers/serial/uart_16550.c: Add configuration option CONFIG_16550_SUPRESS_INITIAL_CONFIG. This is identical to the standard configuration in arch/Kconfig CONFIG_SUPPRESS_UART_CONFIG, but with scope of only the 16550 driver. --- drivers/serial/Kconfig-16550 | 5 +++ drivers/serial/uart_16550.c | 74 ++++++++++++++++++++++++++++++- include/nuttx/serial/uart_16550.h | 3 +- 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/drivers/serial/Kconfig-16550 b/drivers/serial/Kconfig-16550 index f74d9cf5037..259240dfb77 100644 --- a/drivers/serial/Kconfig-16550 +++ b/drivers/serial/Kconfig-16550 @@ -312,6 +312,11 @@ endchoice # 16550 Serial Console config 16550_SUPRESS_CONFIG bool "Suppress 16550 configuration" default n + +config 16550_SUPRESS_INITIAL_CONFIG + bool "Suppress initial 16550 configuration" + depends on !16550_SUPRESS_CONFIG + default n ---help--- This option is useful, for example, if you are using a bootloader that configures the 16550_UART. In that case, you may want to diff --git a/drivers/serial/uart_16550.c b/drivers/serial/uart_16550.c index 4126048d229..23c79bfe9a2 100644 --- a/drivers/serial/uart_16550.c +++ b/drivers/serial/uart_16550.c @@ -80,6 +80,9 @@ struct u16550_s uint8_t parity; /* 0=none, 1=odd, 2=even */ uint8_t bits; /* Number of bits (7 or 8) */ bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + bool flow; /* flow control (RTS/CTS) enabled */ +#endif #endif }; @@ -96,6 +99,10 @@ static int u16550_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int u16550_receive(FAR struct uart_dev_s *dev, uint32_t *status); static void u16550_rxint(FAR struct uart_dev_s *dev, bool enable); static bool u16550_rxavailable(FAR struct uart_dev_s *dev); +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool u16550_rxflowcontrol(struct uart_dev_s *dev, unsigned int nbuffered, + bool upper); +#endif #ifdef CONFIG_SERIAL_DMA static void u16550_dmasend(FAR struct uart_dev_s *dev); static void u16550_dmareceive(FAR struct uart_dev_s *dev); @@ -122,7 +129,7 @@ static const struct uart_ops_s g_uart_ops = .rxint = u16550_rxint, .rxavailable = u16550_rxavailable, #ifdef CONFIG_SERIAL_IFLOWCONTROL - .rxflowcontrol = NULL, + .rxflowcontrol = u16550_rxflowcontrol, #endif #ifdef CONFIG_SERIAL_DMA .dmasend = u16550_dmasend, @@ -170,6 +177,9 @@ static struct u16550_s g_uart0priv = .parity = CONFIG_16550_UART0_PARITY, .bits = CONFIG_16550_UART0_BITS, .stopbits2 = CONFIG_16550_UART0_2STOP, +#if defined(CONFIG_16550_UART0_IFLOWCONTROL) || defined(CONFIG_16550_UART0_OFLOWCONTROL) + .flow = true, +#endif #endif }; @@ -205,6 +215,9 @@ static struct u16550_s g_uart1priv = .parity = CONFIG_16550_UART1_PARITY, .bits = CONFIG_16550_UART1_BITS, .stopbits2 = CONFIG_16550_UART1_2STOP, +#if defined(CONFIG_16550_UART1_IFLOWCONTROL) || defined(CONFIG_16551_UART1_OFLOWCONTROL) + .flow = true, +#endif #endif }; @@ -240,6 +253,9 @@ static struct u16550_s g_uart2priv = .parity = CONFIG_16550_UART2_PARITY, .bits = CONFIG_16550_UART2_BITS, .stopbits2 = CONFIG_16550_UART2_2STOP, +#if defined(CONFIG_16550_UART2_IFLOWCONTROL) || defined(CONFIG_16550_UART2_OFLOWCONTROL) + .flow = true, +#endif #endif }; @@ -275,6 +291,9 @@ static struct u16550_s g_uart3priv = .parity = CONFIG_16550_UART3_PARITY, .bits = CONFIG_16550_UART3_BITS, .stopbits2 = CONFIG_16550_UART3_2STOP, +#if defined(CONFIG_16550_UART3_IFLOWCONTROL) || defined(CONFIG_16550_UART3_OFLOWCONTROL) + .flow = true, +#endif #endif }; @@ -606,6 +625,9 @@ static int u16550_setup(FAR struct uart_dev_s *dev) FAR struct u16550_s *priv = (FAR struct u16550_s *)dev->priv; uint16_t div; uint32_t lcr; +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + uint32_t mcr; +#endif /* Clear fifos */ @@ -677,6 +699,23 @@ static int u16550_setup(FAR struct uart_dev_s *dev) u16550_serialout(priv, UART_FCR_OFFSET, (UART_FCR_RXTRIGGER_8 | UART_FCR_TXRST | UART_FCR_RXRST | UART_FCR_FIFOEN)); + + /* Set up the auto flow control */ + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + mcr = u16550_serialin(priv, UART_MCR_OFFSET); + if (priv->flow) + { + mcr |= UART_MCR_AFCE; + } + else + { + mcr &= ~UART_MCR_AFCE; + } + + u16550_serialout(priv, UART_MCR_OFFSET, mcr); +#endif /* defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) */ + #endif return OK; } @@ -934,6 +973,9 @@ static int u16550_ioctl(struct file *filep, int cmd, unsigned long arg) termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) | ((priv->parity == 1) ? PARODD : 0); termiosp->c_cflag |= (priv->stopbits2) ? CSTOPB : 0; +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + termiosp->c_cflag |= priv->flow ? CRTSCTS : 0; +#endif switch (priv->bits) { @@ -1003,6 +1045,9 @@ static int u16550_ioctl(struct file *filep, int cmd, unsigned long arg) priv->baud = cfgetispeed(termiosp); priv->stopbits2 = (termiosp->c_cflag & CSTOPB) != 0; +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + priv->flow = (termiosp->c_cflag & CRTSCTS) != 0; +#endif u16550_setup(dev); leave_critical_section(flags); @@ -1084,6 +1129,31 @@ static bool u16550_rxavailable(struct uart_dev_s *dev) * ****************************************************************************/ +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool u16550_rxflowcontrol(struct uart_dev_s *dev, unsigned int nbuffered, + bool upper) +{ +#ifndef CONFIG_16550_SUPRESS_CONFIG + FAR struct u16550_s *priv = (FAR struct u16550_s *)dev->priv; + + if (priv->flow) + { + /* Disable Rx interrupt to prevent more data being from + * peripheral if the RX buffer is near full. When hardware + * RTS is enabled, this will prevent more data from coming + * in. Otherwise, enable Rx interrupt to make sure that more + * input is received. + */ + + u16550_rxint(dev, !upper); + return true; + } +#endif + + return false; +} +#endif + #ifdef CONFIG_SERIAL_DMA static void u16550_dmasend(FAR struct uart_dev_s *dev) { @@ -1232,8 +1302,10 @@ void up_earlyserialinit(void) #ifdef CONSOLE_DEV CONSOLE_DEV.isconsole = true; +#ifndef CONFIG_16550_SUPRESS_INITIAL_CONFIG u16550_setup(&CONSOLE_DEV); #endif +#endif } /**************************************************************************** diff --git a/include/nuttx/serial/uart_16550.h b/include/nuttx/serial/uart_16550.h index f485c09d75f..ea84a245276 100644 --- a/include/nuttx/serial/uart_16550.h +++ b/include/nuttx/serial/uart_16550.h @@ -290,7 +290,8 @@ #define UART_MCR_OUT1 (1 << 2) /* Bit 2: Auxiliary user-defined output 1 */ #define UART_MCR_OUT2 (1 << 3) /* Bit 3: Auxiliary user-defined output 2 */ #define UART_MCR_LPBK (1 << 4) /* Bit 4: Loopback Mode Select */ - /* Bit 5-7: Reserved */ +#define UART_MCR_AFCE (1 << 5) /* Bit 5: Auto Flow Control Enable */ + /* Bit 6-7: Reserved */ /* LSR Line Status Register */