From patchwork Fri Oct 6 10:13:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 9988909 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 CF4EC60247 for ; Fri, 6 Oct 2017 10:18:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C5D7528C2D for ; Fri, 6 Oct 2017 10:18:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BA7DD28C7B; Fri, 6 Oct 2017 10:18:06 +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.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id CACD928C2D for ; Fri, 6 Oct 2017 10:18:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=sjca9VHrwaYAZFXgATYu7Ph8MgwsFfuDBSJnG/MnHTo=; b=dDjiEjFhdojQtf87uIBV7kBEBC jDvaS0wJ+HV+c+j0VzGwAfvWcdvGOyBIjiQlvrqDGgklSJSutVXx5Uzk3nCqDV/fkmak92RArW7vW rmoVvEmysna/8PIQVSUxzgEChErmwShHP8Kje1GwrBm4zM7MLnGmoJ6bD3MFffBK+0uMw985Mk+sI zF8G1txDNRVBzV7teUtsxmTWwnq2fEHFoDJn0843EmU0PvyFrsx89x34Rinf/hxLGqtxmUdYTUeTc DLMr5lx5KeTFcd57/I8Ta5cDQDRl838qCPgnO8rD9lnBVA5Q9kwL1DM4pdhZh14Mm0AbuV7//ALj8 HtCF/UZg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1e0Pha-0004Sv-8z; Fri, 06 Oct 2017 10:17:54 +0000 Received: from mail.free-electrons.com ([62.4.15.54]) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1e0PeT-0000bd-6T for linux-arm-kernel@lists.infradead.org; Fri, 06 Oct 2017 10:14:57 +0000 Received: by mail.free-electrons.com (Postfix, from userid 110) id C36FC209B5; Fri, 6 Oct 2017 12:14:10 +0200 (CEST) Received: from localhost.localdomain (LStLambert-657-1-97-87.w90-63.abo.wanadoo.fr [90.63.216.87]) by mail.free-electrons.com (Postfix) with ESMTPSA id 4F0FE209B0; Fri, 6 Oct 2017 12:14:10 +0200 (CEST) From: Miquel Raynal To: Greg Kroah-Hartman , Linus Walleij , Jason Cooper , Andrew Lunn , Gregory Clement , Sebastian Hesselbarth , Jiri Slaby , Catalin Marinas , Will Deacon Subject: [PATCH 07/16] serial: mvebu-uart: add function to change baudrate Date: Fri, 6 Oct 2017 12:13:35 +0200 Message-Id: <20171006101344.15590-8-miquel.raynal@free-electrons.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171006101344.15590-1-miquel.raynal@free-electrons.com> References: <20171006101344.15590-1-miquel.raynal@free-electrons.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20171006_031442_185686_AD24D7DC X-CRM114-Status: GOOD ( 17.54 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Thomas Petazzoni , devicetree@vger.kernel.org, Allen Yan , Antoine Tenart , Nadav Haklai , linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org, Miquel Raynal , Wilson Ding , linux-arm-kernel@lists.infradead.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 From: Allen Yan Until now, the first UART port baudrate was set by the bootloader. Add a function allowing to change the baudrate. Changes may be done from userspace but also at probe time by the kernel. Use the simplest method: baudrate divisor. Works for all UART ports until 230400 baud. To achieve higher baudrates, software should implement the fractional divisor feature that allows more accuracy for higher rates. Signed-off-by: Allen Yan [: changed termios handling] Signed-off-by: Miquel Raynal Reviewed-by: Gregory CLEMENT --- drivers/tty/serial/mvebu-uart.c | 69 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index da756cfec0bb..81a3d2714fd3 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -72,6 +72,7 @@ | STAT_PAR_ERR | STAT_OVR_ERR) #define UART_BRDV 0x10 +#define BRDV_BAUD_MASK 0x3FF #define MVEBU_NR_UARTS 1 @@ -344,6 +345,31 @@ static void mvebu_uart_shutdown(struct uart_port *port) free_irq(port->irq, port); } +static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) +{ + struct mvebu_uart *mvuart = to_mvuart(port); + unsigned int baud_rate_div; + u32 brdv; + + if (IS_ERR(mvuart->clk)) + return -PTR_ERR(mvuart->clk); + + /* + * The UART clock is divided by the value of the divisor to generate + * UCLK_OUT clock, which is 16 times faster than the baudrate. + * This prescaler can achieve all standard baudrates until 230400. + * Higher baudrates could be achieved for the extended UART by using the + * programmable oversampling stack (also called fractional divisor). + */ + baud_rate_div = DIV_ROUND_UP(port->uartclk, baud * 16); + brdv = readl(port->membase + UART_BRDV); + brdv &= ~BRDV_BAUD_MASK; + brdv |= baud_rate_div; + writel(brdv, port->membase + UART_BRDV); + + return 0; +} + static void mvebu_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -367,11 +393,30 @@ static void mvebu_uart_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= STAT_RX_RDY(port) | STAT_BRK_ERR; - if (old) - tty_termios_copy_hw(termios, old); + /* + * Maximum achievable frequency with simple baudrate divisor is 230400. + * Since the error per bit frame would be of more than 15%, achieving + * higher frequencies would require to implement the fractional divisor + * feature. + */ + baud = uart_get_baud_rate(port, termios, old, 0, 230400); + if (mvebu_uart_baud_rate_set(port, baud)) { + /* No clock available, baudrate cannot be changed */ + if (old) + baud = uart_get_baud_rate(port, old, NULL, 0, 230400); + } else { + tty_termios_encode_baud_rate(termios, baud, baud); + uart_update_timeout(port, termios->c_cflag, baud); + } - baud = uart_get_baud_rate(port, termios, old, 0, 460800); - uart_update_timeout(port, termios->c_cflag, baud); + /* Only the following flag changes are supported */ + if (old) { + termios->c_iflag &= INPCK | IGNPAR; + termios->c_iflag |= old->c_iflag & ~(INPCK | IGNPAR); + termios->c_cflag &= CREAD | CBAUD; + termios->c_cflag |= old->c_cflag & ~(CREAD | CBAUD); + termios->c_lflag = old->c_lflag; + } spin_unlock_irqrestore(&port->lock, flags); } @@ -647,12 +692,28 @@ static int mvebu_uart_probe(struct platform_device *pdev) if (!mvuart) return -ENOMEM; + /* Get controller data depending on the compatible string */ mvuart->data = (struct mvebu_uart_driver_data *)match->data; mvuart->port = port; port->private_data = mvuart; platform_set_drvdata(pdev, mvuart); + /* Get fixed clock frequency */ + mvuart->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(mvuart->clk)) { + if (PTR_ERR(mvuart->clk) == -EPROBE_DEFER) + return PTR_ERR(mvuart->clk); + + if (IS_EXTENDED(port)) { + dev_err(&pdev->dev, "unable to get UART clock\n"); + return PTR_ERR(mvuart->clk); + } + } else { + if (!clk_prepare_enable(mvuart->clk)) + port->uartclk = clk_get_rate(mvuart->clk); + } + /* UART Soft Reset*/ writel(CTRL_SOFT_RST, port->membase + UART_CTRL(port)); udelay(1);