diff --git a/Documentation/devicetree/bindings/serial/of-serial.txt b/Documentation/devicetree/bindings/serial/of-serial.txt index 1928a3e83cd0413262de68c036242cb0b92b08fa..77054772a8f4fe46cb57ba461544e8de606d337c 100644 --- a/Documentation/devicetree/bindings/serial/of-serial.txt +++ b/Documentation/devicetree/bindings/serial/of-serial.txt @@ -37,6 +37,7 @@ Optional properties: - auto-flow-control: one way to enable automatic flow control support. The driver is allowed to detect support for the capability even without this property. +- has-hw-flow-control: the hardware has flow control capability. Example: diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 111ee8acb07ea437cb145d3a43f48c94d11a2494..65556fc57d5606259d343f458d367e50660f8f1d 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -2333,9 +2333,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * the trigger, or the MCR RTS bit is cleared. In the case where * the remote UART is not using CTS auto flow control, we must * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. + * UART to respond. IOW, at least 32 bytes of FIFO. Also enable + * AFE if hw flow control is supported */ - if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { + if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) || + (port->flags & UPF_HARD_FLOW)) { up->mcr &= ~UART_MCR_AFE; if (termios->c_cflag & CRTSCTS) up->mcr |= UART_MCR_AFE; diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 99246606a256b71cbef9272b1402afc4bdcf1009..77ec6a147522394423c7cf7478402d931edd5ba9 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -182,6 +182,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev) "auto-flow-control")) port8250.capabilities |= UART_CAP_AFE; + if (of_property_read_bool(ofdev->dev.of_node, + "has-hw-flow-control")) + port8250.port.flags |= UPF_HARD_FLOW; + ret = serial8250_register_8250_port(&port8250); break; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 9a01ee4dda6df1fc1427e761a0b015d455cb12fb..fbf6c5ad222f55015d79598ff4295723dd396456 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -174,8 +174,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, if (tty->termios.c_cflag & CBAUD) uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); } - - if (tty_port_cts_enabled(port)) { + /* + * if hw support flow control without software intervention, + * then skip the below check + */ + if (tty_port_cts_enabled(port) && + !(uport->flags & UPF_HARD_FLOW)) { spin_lock_irq(&uport->lock); if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) tty->hw_stopped = 1; @@ -2775,7 +2779,9 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status) uport->icount.cts++; - if (tty_port_cts_enabled(port)) { + /* skip below code if the hw flow control is supported */ + if (tty_port_cts_enabled(port) && + !(uport->flags & UPF_HARD_FLOW)) { if (tty->hw_stopped) { if (status) { tty->hw_stopped = 0;