Received: by 2002:a05:6a10:c7c6:0:0:0:0 with SMTP id h6csp1682221pxy; Mon, 2 Aug 2021 07:47:39 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzFLq2Bx9xsAwNWf3yum3XL0sNm0jbRG4umUNKCDWQYAPmfP5mGgCtwXgezF+lUceJpSESA X-Received: by 2002:a92:8707:: with SMTP id m7mr252770ild.177.1627915659352; Mon, 02 Aug 2021 07:47:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1627915659; cv=none; d=google.com; s=arc-20160816; b=ew6bZ9vse96lYKONPmB1DkrpHwSEqmXUFxnQDiecMdfprQG0LbEtBp+qXyr81Vr3zP 2vJ1fBGRi4qtNN25O1EJSsBhtKoS6WGmyjNcqzQ7slhH0NuaXfpK1xDyjSwNwtHX7vIf ddJPmpOkztP+O/NGcFw6QerOQw88pHpw5j2YcRRBjKI/0mWpt+Ch0FRzhhLSvOUTJRnP bYyIr+tmLKH9cKjKMj0x4WG/Jd+7Ub3rl5qVyJ0XmYKUybS6rImSbcz1k1PF51glLYCf jtOrrSx/lmSZybQWptwWcYyB/FZ16lhMj4ncpb9LJq5fjGeT52NKHbZmDjoQA7prvjln OvqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=n/b4K7F8osuGympBrL3yLmtKO9d1V0dfNddu7hAhiYE=; b=O3m3RZF8rERjpVeT+vExDPH+couDTXwPeFRmt2rKjq0HFk0rjV2DSE7P31S7I6GOp2 C4XNbFZNr/+VEkOn+pR2KrTu9eyPwLX3K+FJxgVSZseFgbRX+vAxARgdznBCTIgIB7G6 4uOOGJB91ERhPs9UcJQt1SzzKWE0RQoMrPgTmR1zmW63kqCqny6YHumIiddFWcoRUv5M 2cU5Fp4vlz+HVt93HtB7yVOZP3c9ewVfXgPh1zTpcmp7WBBCKUkGfe8x6nLmRgqWNaJG hfy7E14WkRG4NPl2D8PM57564ygDrptREjt8xVpo1tavWLodnymbnj65K29yuLBlwtE2 Muhg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=GCShe9a0; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id z7si12564816ilq.32.2021.08.02.07.47.27; Mon, 02 Aug 2021 07:47:39 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=GCShe9a0; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234626AbhHBOqX (ORCPT + 99 others); Mon, 2 Aug 2021 10:46:23 -0400 Received: from mail.kernel.org ([198.145.29.99]:49006 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234534AbhHBOqH (ORCPT ); Mon, 2 Aug 2021 10:46:07 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 47CFD610CC; Mon, 2 Aug 2021 14:45:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1627915557; bh=YCFy1J2Y2QsNsPSVYSAN99rjizBKWXJw6JQNinsDlbo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GCShe9a0v2LUh2rAYwRWh3Ai2nVtK853cge7lwIPVEuTagZFxjLR1KuJDS1Urf/9o 9phLDDYIcDjmiPFW0ovwlH4GgZwwgrfnJ/m/X2woCaUhqiglAGXmxp972nqU+B33Ym 6MZthfARwtw1K09t7IKpQtByCsR7TkwK3KTtfiQsmAudiYCdvcv5IZBCxKwirZxy9y xFMudN+mdgT84sDSwwVl7fCbydhURJwwBeF+ypiocddJiWrWBrdi3a/Dq2W4lcqEKx d8v8DZ7urjuoN66NbFPk8J0/fu+hnPHUbYrTY77RkrPagS0mwzsjHBqu8vGScI7+7Q wf8w41M1nrtIw== Received: by pali.im (Postfix) id 07C40B98; Mon, 2 Aug 2021 16:45:57 +0200 (CEST) From: =?UTF-8?q?Pali=20Roh=C3=A1r?= To: Michael Turquette , Stephen Boyd , Rob Herring , Greg Kroah-Hartman Cc: Andrew Lunn , Gregory Clement , Sebastian Hesselbarth , Vladimir Vid , =?UTF-8?q?Marek=20Beh=C3=BAn?= , linux-clk@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v4 6/6] serial: mvebu-uart: implement support for baudrates higher than 230400 Date: Mon, 2 Aug 2021 16:45:29 +0200 Message-Id: <20210802144529.1520-7-pali@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210802144529.1520-1-pali@kernel.org> References: <20210624224909.6350-1-pali@kernel.org> <20210802144529.1520-1-pali@kernel.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This change implements simple usage of fractional divisor. When main divisor D is too large to represent requested baudrate then use divisor M from fractional divisor feature. All the M prescalers are set to same and maximal value 63, so fractional part is not used at all. Tests showed that UART at 1500000 baudrate via this configuration is stable and usable. So there is no need to implement complicated calculation of fractional coefficients yet. To use this feature with higher baudrates, it is required to use UART clock provided by UART clock driver. Default boot xtal clock is not capable of higher baudrates and this change also contains code for determining upper limit of possible baudrate. Signed-off-by: Pali Rohár --- drivers/tty/serial/mvebu-uart.c | 79 ++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index a31235add99f..0fe251b8627b 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -99,6 +99,7 @@ #define UART_OSAMP 0x14 #define OSAMP_DEFAULT_DIVISOR 16 #define OSAMP_DIVISORS_MASK 0x3F3F3F3F +#define OSAMP_MAX_DIVISOR 63 #define MVEBU_NR_UARTS 2 @@ -479,18 +480,59 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) return -EOPNOTSUPP; /* - * The baudrate is derived from the UART clock thanks to two divisors: - * > D ("baud generator"): can divide the clock from 2 to 2^10 - 1. - * > M ("fractional divisor"): allows a better accuracy for - * baudrates higher than 230400. + * The baudrate is derived from the UART clock thanks to divisors: + * > d1 * d2 ("TBG divisors"): can divide only TBG clock from 1 to 6 + * > D ("baud generator"): can divide the clock from 1 to 1023 + * > M ("fractional divisor"): allows a better accuracy (from 1 to 63) * - * As the derivation of M is rather complicated, the code sticks to its - * default value (x16) when all the prescalers are zeroed, and only - * makes use of D to configure the desired baudrate. + * Exact formulas for calculating baudrate: + * + * with default x16 scheme: + * baudrate = xtal / (d * 16) + * baudrate = tbg / (d1 * d2 * d * 16) + * + * with fractional divisor: + * baudrate = 10 * xtal / (d * (3 * (m1 + m2) + 2 * (m3 + m4))) + * baudrate = 10 * tbg / (d1*d2 * d * (3 * (m1 + m2) + 2 * (m3 + m4))) + * + * Oversampling value: + * osamp = (m1 << 0) | (m2 << 8) | (m3 << 16) | (m4 << 24); + * + * Where m1 controls number of clock cycles per bit for bits 1,2,3; + * m2 for bits 4,5,6; m3 for bits 7,8 and m4 for bits 9,10. + * + * To simplify baudrate setup set all the M prescalers to same value. + * For 9600 baudrate and higher it is enough to use just default (x16) + * divisor or fractional divisor with M = 63, so there is no need to + * use real fractional support (when the M prescalers are not equal). + * + * When all the M prescalers are zeroed then default (x16) divisor is + * used. Default x16 scheme is more stable than M (fractional divisor), + * so use M only when D divisor is not enough to derivate baudrate. + * + * Member port->uartclk is either xtal clock rate or TBG clock rate + * divided by (d1 * d2). So UART clock driver already sets d1 and d2 + * divisors and UART driver cannot change them. Moreover they are + * shared with both UARTs. */ + m_divisor = OSAMP_DEFAULT_DIVISOR; d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor); + if (d_divisor > BRDV_BAUD_MAX) { + /* + * Experiments showed that small M divisors are unstable. + * So use maximal possible M = 63 and calculate D divisor. + */ + m_divisor = OSAMP_MAX_DIVISOR; + d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor); + } + + if (d_divisor < 1) + d_divisor = 1; + else if (d_divisor > BRDV_BAUD_MAX) + d_divisor = BRDV_BAUD_MAX; + spin_lock_irqsave(&mvebu_uart_lock, flags); brdv = readl(port->membase + UART_BRDV); brdv &= ~BRDV_BAUD_MASK; @@ -500,6 +542,9 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) osamp = readl(port->membase + UART_OSAMP); osamp &= ~OSAMP_DIVISORS_MASK; + if (m_divisor != OSAMP_DEFAULT_DIVISOR) + osamp |= (m_divisor << 0) | (m_divisor << 8) | + (m_divisor << 16) | (m_divisor << 24); writel(osamp, port->membase + UART_OSAMP); return 0; @@ -529,14 +574,14 @@ static void mvebu_uart_set_termios(struct uart_port *port, port->ignore_status_mask |= STAT_RX_RDY(port) | STAT_BRK_ERR; /* - * Maximal divisor is 1023 * 16 when using default (x16) scheme. - * 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. + * Maximal divisor is 1023 and maximal fractional divisor is 63. And + * experiments showed that baudrates above 1/80 of base clock are not + * stable and usable. So disallow baudrate above 1/80 of the base clock. + * When port->uartclk is not available then mvebu_uart_baud_rate_set() + * fails so values min_baud and max_baud in this case does not matter. */ - min_baud = DIV_ROUND_UP(port->uartclk, 1023 * 16); - max_baud = 230400; + min_baud = DIV_ROUND_UP(port->uartclk, BRDV_BAUD_MAX*OSAMP_MAX_DIVISOR); + max_baud = port->uartclk / 80; baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud); if (mvebu_uart_baud_rate_set(port, baud)) { @@ -1397,14 +1442,14 @@ static int mvebu_uart_clock_probe(struct platform_device *pdev) * Calculate the smallest TBG d1 and d2 divisors that * still can provide 9600 baudrate. */ - d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_DEFAULT_DIVISOR * + d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_MAX_DIVISOR * BRDV_BAUD_MAX); if (d1 < 1) d1 = 1; else if (d1 > CLK_TBG_DIV1_MAX) d1 = CLK_TBG_DIV1_MAX; - d2 = DIV_ROUND_UP(rate, 9600 * OSAMP_DEFAULT_DIVISOR * + d2 = DIV_ROUND_UP(rate, 9600 * OSAMP_MAX_DIVISOR * BRDV_BAUD_MAX * d1); if (d2 < 1) d2 = 1; @@ -1419,7 +1464,7 @@ static int mvebu_uart_clock_probe(struct platform_device *pdev) } /* Skip clock source which cannot provide 9600 baudrate */ - if (rate > 9600 * OSAMP_DEFAULT_DIVISOR * BRDV_BAUD_MAX * d1 * d2) + if (rate > 9600 * OSAMP_MAX_DIVISOR * BRDV_BAUD_MAX * d1 * d2) continue; /* -- 2.20.1