Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755607AbcJ0QIr (ORCPT ); Thu, 27 Oct 2016 12:08:47 -0400 Received: from eusmtp01.atmel.com ([212.144.249.242]:20229 "EHLO eusmtp01.atmel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752786AbcJ0QIn (ORCPT ); Thu, 27 Oct 2016 12:08:43 -0400 Subject: Re: [PATCH v6] tty/serial: at91: fix hardware handshake on Atmel platforms To: Richard Genoud , =?UTF-8?Q?Uwe_Kleine-K=c3=b6nig?= , "Alexandre Belloni" , Greg Kroah-Hartman , Cyrille Pitchen , References: <20161027160406.25738-1-richard.genoud@gmail.com> CC: , , "#4 . 4+" From: Nicolas Ferre Organization: atmel Message-ID: Date: Thu, 27 Oct 2016 18:08:35 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 MIME-Version: 1.0 In-Reply-To: <20161027160406.25738-1-richard.genoud@gmail.com> Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 8bit X-Originating-IP: [10.145.133.18] Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6601 Lines: 160 Le 27/10/2016 ? 18:04, Richard Genoud a ?crit : > After commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management > when hardware handshake is enabled"), the hardware handshake wasn't > functional anymore on Atmel platforms (beside SAMA5D2). > > To understand why, one has to understand the flag ATMEL_US_USMODE_HWHS > first: > Before commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management > when hardware handshake is enabled"), this flag was never set. > Thus, the CTS/RTS where only handled by serial_core (and everything > worked just fine). > > This commit introduced the use of the ATMEL_US_USMODE_HWHS flag, > enabling it for all boards when the user space enables flow control. > > When the ATMEL_US_USMODE_HWHS is set, the Atmel USART controller > handles a part of the flow control job: > - disable the transmitter when the CTS pin gets high. > - drive the RTS pin high when the DMA buffer transfer is completed or > PDC RX buffer full or RX FIFO is beyond threshold. (depending on the > controller version). > > NB: This feature is *not* mandatory for the flow control to work. > (Nevertheless, it's very useful if low latencies are needed.) > > Now, the specifics of the ATMEL_US_USMODE_HWHS flag: > > - For platforms with DMAC and no FIFOs (sam9x25, sam9x35, sama5D3, > sama5D4, sam9g15, sam9g25, sam9g35)* this feature simply doesn't work. > ( source: https://lkml.org/lkml/2016/9/7/598 ) > Tested it on sam9g35, the RTS pins always stays up, even when RXEN=1 > or a new DMA transfer descriptor is set. > => ATMEL_US_USMODE_HWHS must not be used for those platforms > > - For platforms with a PDC (sam926{0,1,3}, sam9g10, sam9g20, sam9g45, > sam9g46)*, there's another kind of problem. Once the flag > ATMEL_US_USMODE_HWHS is set, the RTS pin can't be driven anymore via > RTSEN/RTSDIS in USART Control Register. The RTS pin can only be driven > by enabling/disabling the receiver or setting RCR=RNCR=0 in the PDC > (Receive (Next) Counter Register). > => Doing this is beyond the scope of this patch and could add other > bugs, so the original (and working) behaviour should be set for those > platforms (meaning ATMEL_US_USMODE_HWHS flag should be unset). > > - For platforms with a FIFO (sama5d2)*, the RTS pin is driven according > to the RX FIFO thresholds, and can be also driven by RTSEN/RTSDIS in > USART Control Register. No problem here. > (This was the use case of commit 1cf6e8fc8341 ("tty/serial: at91: fix > RTS line management when hardware handshake is enabled")) > NB: If the CTS pin declared as a GPIO in the DTS, (for instance > cts-gpios = <&pioA PIN_PB31 GPIO_ACTIVE_LOW>), the transmitter will be > disabled. > => ATMEL_US_USMODE_HWHS flag can be set for this platform ONLY IF the > CTS pin is not a GPIO. > > So, the only case when ATMEL_US_USMODE_HWHS can be enabled is when > (atmel_use_fifo(port) && > !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) > > Tested on all Atmel USART controller flavours: > AT91SAM9G35-CM (DMAC flavour), AT91SAM9G20-EK (PDC flavour), > SAMA5D2xplained (FIFO flavour). > > * the list may not be exhaustive > > Cc: #4.4+ (beware, missing atmel_port variable) > Fixes: 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled") > Signed-off-by: Richard Genoud > Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre Thanks > --- > drivers/tty/serial/atmel_serial.c | 26 ++++++++++++++++++++++---- > 1 file changed, 22 insertions(+), 4 deletions(-) > > Note for -stable: > This patch will apply on 4.4.x/4.8.x but compilation will fail due to > a missing variable atmel_port (introduced in 4.9-rc1): > > static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, > struct ktermios *old) > { > + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); > unsigned long flags; > unsigned int old_mode, mode, imr, quot, baud; > > Changes since v5: > - fix typos > - increase commentary > > Changes since v4: > - the mctrl_gpio_use_rtscts() is gone since it was atmel_serial > specific. (so patch 1 is gone) > - patches 2 and 3 have been merged together since it didn't make > a lot of sense to correct the GPIO case in one separate patch. > - ATMEL_US_USMODE_HWHS is now unset for platform with PDC > > Changes since v3: > - remove superfluous #include (thanks to Uwe) > - rebase on next-20160930 > > Changes since v2: > - remove IS_ERR_OR_NULL() test in patch 1/3 as Uwe suggested. > - fix typos in patch 2/3 > - rebase on next-20160927 > - simplify the logic in patch 3/3. > > Changes since v1: > - Correct patch 1 with the error found by kbuild. > - Add Alexandre's Acked-by on patch 2 > - Rewrite patch 3 logic in the light of the on-going discussion > with Cyrille and Alexandre. > > > diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c > index fd8aa1f4ba78..168b10cad47b 100644 > --- a/drivers/tty/serial/atmel_serial.c > +++ b/drivers/tty/serial/atmel_serial.c > @@ -2132,11 +2132,29 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, > mode |= ATMEL_US_USMODE_RS485; > } else if (termios->c_cflag & CRTSCTS) { > /* RS232 with hardware handshake (RTS/CTS) */ > - if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) { > - dev_info(port->dev, "not enabling hardware flow control because DMA is used"); > - termios->c_cflag &= ~CRTSCTS; > - } else { > + if (atmel_use_fifo(port) && > + !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) { > + /* > + * with ATMEL_US_USMODE_HWHS set, the controller will > + * be able to drive the RTS pin high/low when the RX > + * FIFO is above RXFTHRES/below RXFTHRES2. > + * It will also disable the transmitter when the CTS > + * pin is high. > + * This mode is not activated if CTS pin is a GPIO > + * because in this case, the transmitter is always > + * disabled (there must be an internal pull-up > + * responsible for this behaviour). > + * If the RTS pin is a GPIO, the controller won't be > + * able to drive it according to the FIFO thresholds, > + * but it will be handled by the driver. > + */ > mode |= ATMEL_US_USMODE_HWHS; > + } else { > + /* > + * For platforms without FIFO, the flow control is > + * handled by the driver. > + */ > + mode |= ATMEL_US_USMODE_NORMAL; > } > } else { > /* RS232 without hadware handshake */ > -- Nicolas Ferre