From patchwork Thu Oct 27 16:04:06 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Richard Genoud X-Patchwork-Id: 9399845 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8135E60588 for ; Thu, 27 Oct 2016 16:06:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6CB3F2A2AE for ; Thu, 27 Oct 2016 16:06:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5DFE62A30E; Thu, 27 Oct 2016 16:06:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,FREEMAIL_FROM,RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id BE1A02A2AE for ; Thu, 27 Oct 2016 16:06:43 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bznAk-00077r-SF; Thu, 27 Oct 2016 16:04:54 +0000 Received: from mail-wm0-x244.google.com ([2a00:1450:400c:c09::244]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bznAb-0006yu-Bu for linux-arm-kernel@lists.infradead.org; Thu, 27 Oct 2016 16:04:47 +0000 Received: by mail-wm0-x244.google.com with SMTP id y138so3392057wme.1 for ; Thu, 27 Oct 2016 09:04:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=97OdiULxFNngpGudHcmWvK864T+ai+8WpGj7DlQATBw=; b=LMWaxpXME17idYk4JdfMoopkonuDC/ViC2WyyU0cj7Pbv0BKapdzCAcDWbG/4f8Bg5 AZcEG/64ukj9Ed1TcysT0j87GY0acJkZXgwF//cvoVkkf68zZ7SPancHPfOdi2OIyCrV nH4oiEwz6XNutZ+5CnwJ7Xc5DN0lUwdNBkFLroLzUvVaSRGETGiw0n5wJXiugjV6uy2O ORV6tixV9WUHtdp1PbgGrn6W4SGZPvUzOnNalkCragUqgVDJeD6xWHDLbyKaQIUNq5jC j1Q21Bh0vTswFrzV+g+Jh7+Ux13Xg1q5QzBrpqoeoGHsw3wrptrUB906MOD86mQEvkst vTow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=97OdiULxFNngpGudHcmWvK864T+ai+8WpGj7DlQATBw=; b=EjlyTmWBe6RI+UR8JG3T5pyOV8Rx5fCMEQp0jP0oZf7VwFt4K3okzFTGpTSkwf0OEl iNxBlFjYPxIp963Fo/gL+j/93BiIhrx2Lt9YbKgazRKADuPMrQcqW+DqXoCBLJeBVnCk nFNtusJdRyvTlojpn7t+D+B408RGIYNQTTqsBIEiUzFtVYLNRNaNN//R/HfWF2KmJap+ zIiTTDyirIo90PG+P8YFqHworIZ5rUa9HUnYKeZ176Rg7hfhlEaPJeroVFYe1lmBOgkj Vi//2Rsu0oSt5ammXJRzOrqUkJzGXvCT2csTbv5hmACUWT6ZEgMjyj7aOyq7DSSU10Vn Sz/A== X-Gm-Message-State: ABUngveVIsDK6W2jS27pgq6r4wE33rWaJGWwoaWNECRa8QMp2O0eIDzGHQBGJqwvtNbdUg== X-Received: by 10.28.32.132 with SMTP id g126mr9154096wmg.131.1477584263192; Thu, 27 Oct 2016 09:04:23 -0700 (PDT) Received: from localhost ([46.227.18.67]) by smtp.gmail.com with ESMTPSA id us3sm9215970wjb.32.2016.10.27.09.04.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 27 Oct 2016 09:04:22 -0700 (PDT) From: Richard Genoud To: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , Nicolas Ferre , Alexandre Belloni , Greg Kroah-Hartman , Cyrille Pitchen Subject: [PATCH v6] tty/serial: at91: fix hardware handshake on Atmel platforms Date: Thu, 27 Oct 2016 18:04:06 +0200 Message-Id: <20161027160406.25738-1-richard.genoud@gmail.com> X-Mailer: git-send-email 2.10.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161027_090445_627321_317D4B94 X-CRM114-Status: GOOD ( 21.56 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-arm-kernel@lists.infradead.org, Richard Genoud , "#4 . 4+" , linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP 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 Acked-by: Cyrille Pitchen Acked-by: Uwe Kleine-König --- 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 */