linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates
@ 2021-06-24 22:48 Pali Rohár
  2021-06-24 22:49 ` [PATCH 01/10] serial: mvebu-uart: fix calculation of clock divisor Pali Rohár
                   ` (13 more replies)
  0 siblings, 14 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:48 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This patch series fixes mvebu-uart driver used on Marvell Armada 37xx
boards and add support for baudrates higher than 230400.

Pali Rohár (10):
  serial: mvebu-uart: fix calculation of clock divisor
  serial: mvebu-uart: do not allow changing baudrate when uartclk is not
    available
  serial: mvebu-uart: correctly calculate minimal possible baudrate
  dt-bindings: mvebu-uart: fix documentation
  arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART
  serial: mvebu-uart: remove unused member nb from struct mvebu_uart
  serial: mvebu-uart: implement UART clock driver for configuring UART
    base clock
  dt-bindings: mvebu-uart: document DT bindings for
    marvell,armada-3700-uart-clock
  arm64: dts: marvell: armada-37xx: add device node for UART clock and
    use it
  serial: mvebu-uart: implement support for baudrates higher than 230400

 .../bindings/clock/armada3700-uart-clock.txt  |  24 +
 .../devicetree/bindings/serial/mvebu-uart.txt |  15 +-
 .../arm64/boot/dts/marvell/armada-3720-db.dts |   4 +
 .../dts/marvell/armada-3720-espressobin.dtsi  |   4 +
 .../dts/marvell/armada-3720-turris-mox.dts    |   4 +
 .../boot/dts/marvell/armada-3720-uDPU.dts     |   4 +
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi  |  17 +-
 drivers/tty/serial/mvebu-uart.c               | 603 +++++++++++++++++-
 8 files changed, 645 insertions(+), 30 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt

-- 
2.20.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 01/10] serial: mvebu-uart: fix calculation of clock divisor
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-24 22:49 ` [PATCH 02/10] serial: mvebu-uart: do not allow changing baudrate when uartclk is not available Pali Rohár
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

The clock divisor should be rounded to the closest value.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: 68a0db1d7da2 ("serial: mvebu-uart: add function to change baudrate")
Cc: stable@vger.kernel.org # 0e4cf69ede87 ("serial: mvebu-uart: clarify the baud rate derivation")
---
 drivers/tty/serial/mvebu-uart.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index e0c00a1b0763..f81bfdaa608c 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -463,7 +463,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 	 * makes use of D to configure the desired baudrate.
 	 */
 	m_divisor = OSAMP_DEFAULT_DIVISOR;
-	d_divisor = DIV_ROUND_UP(port->uartclk, baud * m_divisor);
+	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
 
 	brdv = readl(port->membase + UART_BRDV);
 	brdv &= ~BRDV_BAUD_MASK;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 02/10] serial: mvebu-uart: do not allow changing baudrate when uartclk is not available
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
  2021-06-24 22:49 ` [PATCH 01/10] serial: mvebu-uart: fix calculation of clock divisor Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-24 22:49 ` [PATCH 03/10] serial: mvebu-uart: correctly calculate minimal possible baudrate Pali Rohár
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

Testing mvuart->clk for non-error is not enough as mvuart->clk may contain
valid clk pointer but when clk_prepare_enable(mvuart->clk) failed then
port->uartclk is zero.

When mvuart->clk is not available then port->uartclk is zero too.

Parent clock rate port->uartclk is needed to calculate UART clock divisor
and without it is not possible to change baudrate.

So fix test condition when it is possible to change baudrate.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: 68a0db1d7da2 ("serial: mvebu-uart: add function to change baudrate")
---
 drivers/tty/serial/mvebu-uart.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index f81bfdaa608c..dc0c26824ddb 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -445,12 +445,11 @@ static void mvebu_uart_shutdown(struct uart_port *port)
 
 static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
-	struct mvebu_uart *mvuart = to_mvuart(port);
 	unsigned int d_divisor, m_divisor;
 	u32 brdv, osamp;
 
-	if (IS_ERR(mvuart->clk))
-		return -PTR_ERR(mvuart->clk);
+	if (!port->uartclk)
+		return -EOPNOTSUPP;
 
 	/*
 	 * The baudrate is derived from the UART clock thanks to two divisors:
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 03/10] serial: mvebu-uart: correctly calculate minimal possible baudrate
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
  2021-06-24 22:49 ` [PATCH 01/10] serial: mvebu-uart: fix calculation of clock divisor Pali Rohár
  2021-06-24 22:49 ` [PATCH 02/10] serial: mvebu-uart: do not allow changing baudrate when uartclk is not available Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-24 22:49 ` [PATCH 04/10] dt-bindings: mvebu-uart: fix documentation Pali Rohár
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

For default (x16) scheme which is currently used by mvebu-uart.c driver,
maximal divisor of UART base clock is 1023*16. Therefore there is limit for
minimal supported baudrate. This change calculate it correctly and prevents
setting invalid divisor 0 into hardware registers.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: 68a0db1d7da2 ("serial: mvebu-uart: add function to change baudrate")
---
 drivers/tty/serial/mvebu-uart.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index dc0c26824ddb..f8b0016db847 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -481,7 +481,7 @@ static void mvebu_uart_set_termios(struct uart_port *port,
 				   struct ktermios *old)
 {
 	unsigned long flags;
-	unsigned int baud;
+	unsigned int baud, min_baud, max_baud;
 
 	spin_lock_irqsave(&port->lock, flags);
 
@@ -500,16 +500,21 @@ 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.
 	 */
-	baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+	min_baud = DIV_ROUND_UP(port->uartclk, 1023 * 16);
+	max_baud = 230400;
+
+	baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud);
 	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);
+			baud = uart_get_baud_rate(port, old, NULL,
+						  min_baud, max_baud);
 	} else {
 		tty_termios_encode_baud_rate(termios, baud, baud);
 		uart_update_timeout(port, termios->c_cflag, baud);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 04/10] dt-bindings: mvebu-uart: fix documentation
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (2 preceding siblings ...)
  2021-06-24 22:49 ` [PATCH 03/10] serial: mvebu-uart: correctly calculate minimal possible baudrate Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-24 22:49 ` [PATCH 05/10] arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART Pali Rohár
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

Both UARTs support higher baudrates and are not limited to baudrate 230400.
Only current kernel driver implementation has limitation for both UARTs in
maximal baudrate 230400. This limitation will be removed in next patches.
So remove incorrect information about (hardware) limitation from bindings.

UART1 (standard variant with DT node name 'uart0') has register space
0x12000-0x12018 and not whole size 0x200. So fix also this in example.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: d160c3413478 ("dt-bindings: mvebu-uart: update documentation with extended UART")
---
 Documentation/devicetree/bindings/serial/mvebu-uart.txt | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
index b7e0e32b9ac6..2d0dbdf32d1d 100644
--- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
@@ -5,10 +5,10 @@ Required properties:
 - compatible:
     - "marvell,armada-3700-uart" for the standard variant of the UART
       (32 bytes FIFO, no DMA, level interrupts, 8-bit access to the
-      FIFO, baudrate limited to 230400).
+      FIFO), called also UART1.
     - "marvell,armada-3700-uart-ext" for the extended variant of the
       UART (128 bytes FIFO, DMA, front interrupts, 8-bit or 32-bit
-      accesses to the FIFO, baudrate unlimited by the dividers).
+      accesses to the FIFO), called also UART2.
 - reg: offset and length of the register set for the device.
 - clocks: UART reference clock used to derive the baudrate. If no clock
       is provided (possible only with the "marvell,armada-3700-uart"
@@ -33,7 +33,7 @@ Required properties:
 Example:
 	uart0: serial@12000 {
 		compatible = "marvell,armada-3700-uart";
-		reg = <0x12000 0x200>;
+		reg = <0x12000 0x18>;
 		clocks = <&xtalclk>;
 		interrupts =
 		<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 05/10] arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (3 preceding siblings ...)
  2021-06-24 22:49 ` [PATCH 04/10] dt-bindings: mvebu-uart: fix documentation Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-24 22:49 ` [PATCH 06/10] serial: mvebu-uart: remove unused member nb from struct mvebu_uart Pali Rohár
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

UART1 (standard variant with DT node name 'uart0') has register space
0x12000-0x12018 and not whole size 0x200. So fix also this in example.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: c737abc193d1 ("arm64: dts: marvell: Fix A37xx UART0 register size")
---
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 6897f1f7a7f0..20dd9d9e9d58 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -134,7 +134,7 @@
 
 			uart0: serial@12000 {
 				compatible = "marvell,armada-3700-uart";
-				reg = <0x12000 0x200>;
+				reg = <0x12000 0x18>;
 				clocks = <&xtalclk>;
 				interrupts =
 				<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 06/10] serial: mvebu-uart: remove unused member nb from struct mvebu_uart
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (4 preceding siblings ...)
  2021-06-24 22:49 ` [PATCH 05/10] arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-24 22:49 ` [PATCH 07/10] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

Member nb in struct mvebu_uart is not set nor read. So remove it completely.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 drivers/tty/serial/mvebu-uart.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index f8b0016db847..414e92064ac6 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -128,7 +128,6 @@ struct mvebu_uart {
 	struct uart_port *port;
 	struct clk *clk;
 	int irq[UART_IRQ_COUNT];
-	unsigned char __iomem *nb;
 	struct mvebu_uart_driver_data *data;
 #if defined(CONFIG_PM)
 	struct mvebu_uart_pm_regs pm_regs;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 07/10] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (5 preceding siblings ...)
  2021-06-24 22:49 ` [PATCH 06/10] serial: mvebu-uart: remove unused member nb from struct mvebu_uart Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-24 22:49 ` [PATCH 08/10] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This patch implements a new device driver for controlling UART clocks on
Marvell Armada 3700 SoC. This device driver is loaded for devices which
match compatible string "marvell,armada-3700-uart-clock".

There are more pitfalls related to UART clocks. Both UARTs use same base
clock source. Also divisors for TBG base clock are shared between both
UARTs and are configured only from UART1 address space. Clocks can be
enabled / disabled separately for UART1 and UART2, but they are controlled
only from UART1 address space. Moreover Marvell Armada 3700 Functional
Specifications has swapped bits for enabling/disabling UART1 and UART2
clocks.

So driver for controlling UART2 needs to have access to UART1 address space
as UART1 address space contains some bits exclusively used by UART2 and
also bits which are shared for both UART1 and UART2.

For changing UART base clock (which controls both UARTs) during boot when
UART driver is not ready and only early console is active, is not simple
operation as it is required to also recalculate divisors to not change UART
baudrate used by early console. So for this operation UART1 clock driver
needs to access also into address space of UART2 where are registers for
UART2 divisors.

For these reasons, this new device driver for UART clocks does not use
ioremap_resource(), but only ioremap() to prevent resource conflicts
between UART clock driver and UART driver.

Shared between drivers are only two 4-bytes registers: UART Clock Control
and UART 2 Baud Rate Divisor. Access to these two registers are protected
by one spinlock to prevent any conflicts. Access is required only during
probe time, changing baudrate and during suspend/resume.

Hardware can be configured to use one of following clocks as UART base
clock: TBG-A-P, TBG-B-P, TBG-A-S, TBG-B-S, xtal. Not every clock is usable
for higher buadrates. In DT node can be specified any subset and kernel
choose the best one, which still supports required baudrate 9600. For
smooth boot log output it is needed to specify clock used by early console
otherwise garbage would be put on UART during probing for UART clock driver
and transitioning from early console to normal console.

This change is required to enable and configure TBG clock as a base clock
for UART. TBG clock is required to achieve higher baudrates than 230400.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 drivers/tty/serial/mvebu-uart.c | 517 +++++++++++++++++++++++++++++++-
 1 file changed, 515 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index 414e92064ac6..e51a84be1939 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -8,6 +8,7 @@
 */
 
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -68,8 +69,31 @@
 #define  STAT_BRK_ERR		(STAT_BRK_DET | STAT_FRM_ERR \
 				 | STAT_PAR_ERR | STAT_OVR_ERR)
 
+/*
+ * Marvell Armada 3700 Functional Specifications describes that bit 21 of UART
+ * Clock Control register controls UART1 and bit 20 controls UART2. But in
+ * reality bit 21 controls UART2 and bit 20 controls UART1. This seems to be a
+ * bug in Marvell documentation. Hence following CLK_DIS macros are swapped.
+ */
+
 #define UART_BRDV		0x10
+/* These bits are located in UART1 address space and control UART2 */
+#define  UART2_CLK_DIS		BIT(21)
+/* These bits are located in UART1 address space and control UART1 */
+#define  UART1_CLK_DIS		BIT(20)
+/* These bits are located in UART1 address space and control both UARTs */
+#define  CLK_NO_XTAL		BIT(19)
+#define  CLK_TBG_DIV1_SHIFT	15
+#define  CLK_TBG_DIV1_MASK	0x7
+#define  CLK_TBG_DIV1_MAX	6
+#define  CLK_TBG_DIV2_SHIFT	12
+#define  CLK_TBG_DIV2_MASK	0x7
+#define  CLK_TBG_DIV2_MAX	6
+#define  CLK_TBG_SEL_SHIFT	10
+#define  CLK_TBG_SEL_MASK	0x3
+/* These bits are located in both UARTs address space */
 #define  BRDV_BAUD_MASK         0x3FF
+#define  BRDV_BAUD_MAX		BRDV_BAUD_MASK
 
 #define UART_OSAMP		0x14
 #define  OSAMP_DEFAULT_DIVISOR	16
@@ -153,6 +177,8 @@ static struct mvebu_uart *to_mvuart(struct uart_port *port)
 
 static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
 
+static DEFINE_SPINLOCK(mvebu_uart_lock);
+
 /* Core UART Driver Operations */
 static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
 {
@@ -445,6 +471,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
 static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
 	unsigned int d_divisor, m_divisor;
+	unsigned long flags;
 	u32 brdv, osamp;
 
 	if (!port->uartclk)
@@ -463,10 +490,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 	m_divisor = OSAMP_DEFAULT_DIVISOR;
 	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
 
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	brdv = readl(port->membase + UART_BRDV);
 	brdv &= ~BRDV_BAUD_MASK;
 	brdv |= d_divisor;
 	writel(brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 
 	osamp = readl(port->membase + UART_OSAMP);
 	osamp &= ~OSAMP_DIVISORS_MASK;
@@ -762,6 +791,7 @@ static int mvebu_uart_suspend(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	uart_suspend_port(&mvebu_uart_driver, port);
 
@@ -770,7 +800,9 @@ static int mvebu_uart_suspend(struct device *dev)
 	mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port));
 	mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port));
 	mvuart->pm_regs.stat = readl(port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP);
 
 	device_set_wakeup_enable(dev, true);
@@ -782,13 +814,16 @@ static int mvebu_uart_resume(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port));
 	writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port));
 	writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port));
 	writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port));
 	writel(mvuart->pm_regs.stat, port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP);
 
 	uart_resume_port(&mvebu_uart_driver, port);
@@ -975,6 +1010,475 @@ static struct platform_driver mvebu_uart_platform_driver = {
 	},
 };
 
+/* This code is based on clk-fixed-factor.c driver and modified. */
+
+struct mvebu_uart_clock {
+	struct clk_hw clk_hw;
+	int clock_idx;
+	u32 pm_context_reg1;
+	u32 pm_context_reg2;
+};
+
+struct mvebu_uart_clock_base {
+	struct mvebu_uart_clock clocks[2];
+	unsigned int parent_rates[5];
+	int parent_idx;
+	unsigned int div;
+	void __iomem *reg1;
+	void __iomem *reg2;
+	bool configured;
+};
+
+#define PARENT_CLOCK_XTAL 4
+
+#define to_uart_clock(hw) container_of(hw, struct mvebu_uart_clock, clk_hw)
+#define to_uart_clock_base(uart_clock) container_of(uart_clock, \
+	struct mvebu_uart_clock_base, clocks[uart_clock->clock_idx])
+
+static int mvebu_uart_clock_prepare(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned int prev_clock_idx, prev_clock_rate, prev_d1d2;
+	unsigned int parent_clock_idx, parent_clock_rate;
+	unsigned int d1, d2, divisor;
+	unsigned long flags;
+	u32 val;
+
+	/*
+	 * This function just reconfigures UART Clock Control register (located
+	 * in UART1 address space which controls both UART1 and UART2) to
+	 * selected UART base clock and recalculate current UART1/UART2 divisors
+	 * in their address spaces, so final baudrate will not be changed by
+	 * switching UART base clock. This is required otherwise kernel boot log
+	 * stops working. It is needed to ensure that UART baudrate does not
+	 * change during this setup. It is one time operation, so based on
+	 * "configured" member this function is skipped on second call. Because
+	 * this UART Clock Control register (UART_BRDV) is shared between UART1
+	 * baudrate function, UART1 clock selector and UART2 clock selector,
+	 * every access to UART_BRDV (reg1) needs to be protected by lock.
+	 */
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	if (uart_clock_base->configured) {
+		spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+		return 0;
+	}
+
+	parent_clock_idx = uart_clock_base->parent_idx;
+	parent_clock_rate = uart_clock_base->parent_rates[parent_clock_idx];
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock_base->div > CLK_TBG_DIV1_MAX) {
+		d1 = CLK_TBG_DIV1_MAX;
+		d2 = uart_clock_base->div / CLK_TBG_DIV1_MAX;
+	} else {
+		d1 = uart_clock_base->div;
+		d2 = 1;
+	}
+
+	if (val & CLK_NO_XTAL) {
+		prev_clock_idx = (val >> CLK_TBG_SEL_SHIFT) & CLK_TBG_SEL_MASK;
+		prev_d1d2 = ((val >> CLK_TBG_DIV1_SHIFT) & CLK_TBG_DIV1_MASK)
+			  * ((val >> CLK_TBG_DIV2_SHIFT) & CLK_TBG_DIV2_MASK);
+	} else {
+		prev_clock_idx = PARENT_CLOCK_XTAL;
+		prev_d1d2 = 1;
+	}
+
+	/* Note that uart_clock_base->parent_rates[i] may not be available */
+	prev_clock_rate = uart_clock_base->parent_rates[prev_clock_idx];
+
+	/* Recalculate UART1 divisor so UART1 baudrate does not change */
+	if (prev_clock_rate) {
+		divisor = DIV_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+					    parent_clock_rate * prev_d1d2,
+					    (u64)prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+	}
+
+	if (parent_clock_idx != PARENT_CLOCK_XTAL) {
+		/* Do not use XTAL, select TBG clock and TBG d1 * d2 divisors */
+		val |= CLK_NO_XTAL;
+		val &= ~(CLK_TBG_DIV1_MASK << CLK_TBG_DIV1_SHIFT);
+		val |= d1 << CLK_TBG_DIV1_SHIFT;
+		val &= ~(CLK_TBG_DIV2_MASK << CLK_TBG_DIV2_SHIFT);
+		val |= d2 << CLK_TBG_DIV2_SHIFT;
+		val &= ~(CLK_TBG_SEL_MASK << CLK_TBG_SEL_SHIFT);
+		val |= parent_clock_idx << CLK_TBG_SEL_SHIFT;
+	} else {
+		/* Use XTAL, TBG bits are then ignored */
+		val &= ~CLK_NO_XTAL;
+	}
+
+	writel(val, uart_clock_base->reg1);
+
+	/* Recalculate UART2 divisor so UART2 baudrate does not change */
+	if (prev_clock_rate) {
+		val = readl(uart_clock_base->reg2);
+		divisor = DIV_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+					    parent_clock_rate * prev_d1d2,
+					    (u64)prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+		writel(val, uart_clock_base->reg2);
+	}
+
+	uart_clock_base->configured = true;
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static int mvebu_uart_clock_enable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val &= ~UART1_CLK_DIS;
+	else
+		val &= ~UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_disable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val |= UART1_CLK_DIS;
+	else
+		val |= UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static int mvebu_uart_clock_is_enabled(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	u32 val;
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		return !(val & UART1_CLK_DIS);
+	else
+		return !(val & UART2_CLK_DIS);
+}
+
+static int mvebu_uart_clock_save_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	uart_clock->pm_context_reg1 = readl(uart_clock_base->reg1);
+	uart_clock->pm_context_reg2 = readl(uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_restore_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	writel(uart_clock->pm_context_reg1, uart_clock_base->reg1);
+	writel(uart_clock->pm_context_reg2, uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return parent_rate / uart_clock_base->div;
+}
+
+static long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long *parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return *parent_rate / uart_clock_base->div;
+}
+
+static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	/*
+	 * We must report success but we can do so unconditionally because
+	 * mvebu_uart_clock_round_rate returns values that ensure this call is a
+	 * nop.
+	 */
+
+	return 0;
+}
+
+static const struct clk_ops mvebu_uart_clock_ops = {
+	.prepare = mvebu_uart_clock_prepare,
+	.enable = mvebu_uart_clock_enable,
+	.disable = mvebu_uart_clock_disable,
+	.is_enabled = mvebu_uart_clock_is_enabled,
+	.save_context = mvebu_uart_clock_save_context,
+	.restore_context = mvebu_uart_clock_restore_context,
+	.round_rate = mvebu_uart_clock_round_rate,
+	.set_rate = mvebu_uart_clock_set_rate,
+	.recalc_rate = mvebu_uart_clock_recalc_rate,
+};
+
+static int mvebu_uart_clock_register(struct device *dev,
+				     struct mvebu_uart_clock *uart_clock,
+				     const char *name,
+				     const char *parent_name)
+{
+	struct clk_init_data init = { };
+
+	uart_clock->clk_hw.init = &init;
+
+	init.name = name;
+	init.ops = &mvebu_uart_clock_ops;
+	init.flags = 0;
+	init.num_parents = 1;
+	init.parent_names = &parent_name;
+
+	return devm_clk_hw_register(dev, &uart_clock->clk_hw);
+}
+
+static int mvebu_uart_clock_probe(struct platform_device *pdev)
+{
+	static const char *const uart_clk_names[] = { "uart_1", "uart_2" };
+	static const char *const parent_clk_names[] = { "TBG-A-P", "TBG-B-P",
+							"TBG-A-S", "TBG-B-S",
+							"xtal" };
+	struct clk *parent_clks[ARRAY_SIZE(parent_clk_names)];
+	struct mvebu_uart_clock_base *uart_clock_base;
+	struct clk_hw_onecell_data *hw_clk_data;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int i, parent_clk_idx, ret;
+	unsigned long div, rate;
+	unsigned int d1, d2;
+
+	BUILD_BUG_ON(ARRAY_SIZE(uart_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->clocks));
+	BUILD_BUG_ON(ARRAY_SIZE(parent_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->parent_rates));
+
+	uart_clock_base = devm_kzalloc(dev,
+				       sizeof(*uart_clock_base),
+				       GFP_KERNEL);
+	if (!uart_clock_base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "Couldn't get first register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART Clock Control register (reg1 / UART_BRDV) is in address range
+	 * of UART1 (standard UART variant), controls clock source and dividers
+	 * for both UART1 and UART2 and is supplied via DT as first resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART1 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg1 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg1))
+		return PTR_ERR(uart_clock_base->reg1);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "Couldn't get second register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART 2 Baud Rate Divisor register (reg2 / UART_BRDV) is in address
+	 * range of UART2 (extended UART variant), controls only one UART2
+	 * specific divider and is supplied via DT as second resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART2 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg2 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg2))
+		return PTR_ERR(uart_clock_base->reg2);
+
+	hw_clk_data = devm_kzalloc(dev,
+				   struct_size(hw_clk_data, hws,
+					       ARRAY_SIZE(uart_clk_names)),
+				   GFP_KERNEL);
+	if (!hw_clk_data)
+		return -ENOMEM;
+
+	hw_clk_data->num = ARRAY_SIZE(uart_clk_names);
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		hw_clk_data->hws[i] = &uart_clock_base->clocks[i].clk_hw;
+		uart_clock_base->clocks[i].clock_idx = i;
+	}
+
+	parent_clk_idx = -1;
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		parent_clks[i] = devm_clk_get(dev, parent_clk_names[i]);
+		if (IS_ERR(parent_clks[i])) {
+			if (PTR_ERR(parent_clks[i]) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			dev_warn(dev, "Couldn't get the parent clock %s: %ld\n",
+				parent_clk_names[i], PTR_ERR(parent_clks[i]));
+			continue;
+		}
+
+		ret = clk_prepare_enable(parent_clks[i]);
+		if (ret) {
+			dev_warn(dev, "Couldn't enable parent clock %s: %d\n",
+				parent_clk_names[i], ret);
+			continue;
+		}
+		rate = clk_get_rate(parent_clks[i]);
+		uart_clock_base->parent_rates[i] = rate;
+
+		if (i != PARENT_CLOCK_XTAL) {
+			/*
+			 * Calculate the smallest TBG d1 and d2 divisors that
+			 * still can provide 9600 baudrate.
+			 */
+			d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_DEFAULT_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 *
+						BRDV_BAUD_MAX * d1);
+			if (d2 < 1)
+				d2 = 1;
+			else if (d2 > CLK_TBG_DIV2_MAX)
+				d2 = CLK_TBG_DIV2_MAX;
+		} else {
+			/*
+			 * When UART clock uses XTAL clock as a source then it
+			 * is not possible to use d1 and d2 divisors.
+			 */
+			d1 = d2 = 1;
+		}
+
+		/* Skip clock source which cannot provide 9600 baudrate */
+		if (rate > 9600 * OSAMP_DEFAULT_DIVISOR * BRDV_BAUD_MAX * d1 * d2)
+			continue;
+
+		/*
+		 * Choose TBG clock source with the smallest divisors. Use XTAL
+		 * clock source only in case TBG is not available as XTAL cannot
+		 * be used for baudrates higher than 230400.
+		 */
+		if (parent_clk_idx == -1 ||
+		    (i != PARENT_CLOCK_XTAL && div > d1 * d2)) {
+			parent_clk_idx = i;
+			div = d1 * d2;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		if (i == parent_clk_idx || IS_ERR(parent_clks[i]))
+			continue;
+		clk_disable_unprepare(parent_clks[i]);
+		devm_clk_put(dev, parent_clks[i]);
+	}
+
+	if (parent_clk_idx == -1) {
+		dev_err(dev, "No usable parent clock\n");
+		return -ENOENT;
+	}
+
+	uart_clock_base->parent_idx = parent_clk_idx;
+	uart_clock_base->div = div;
+
+	dev_notice(dev, "Using parent clock %s as base UART clock\n",
+		   __clk_get_name(parent_clks[parent_clk_idx]));
+
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		ret = mvebu_uart_clock_register(dev,
+				&uart_clock_base->clocks[i],
+				uart_clk_names[i],
+				__clk_get_name(parent_clks[parent_clk_idx]));
+		if (ret) {
+			dev_err(dev, "Can't register UART clock %d: %d\n",
+				i, ret);
+			return ret;
+		}
+	}
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+					   hw_clk_data);
+}
+
+static const struct of_device_id mvebu_uart_clock_of_match[] = {
+	{ .compatible = "marvell,armada-3700-uart-clock", },
+	{ }
+};
+
+static struct platform_driver mvebu_uart_clock_platform_driver = {
+	.probe = mvebu_uart_clock_probe,
+	.driver		= {
+		.name	= "mvebu-uart-clock",
+		.of_match_table = mvebu_uart_clock_of_match,
+	},
+};
+
 static int __init mvebu_uart_init(void)
 {
 	int ret;
@@ -983,10 +1487,19 @@ static int __init mvebu_uart_init(void)
 	if (ret)
 		return ret;
 
+	ret = platform_driver_register(&mvebu_uart_clock_platform_driver);
+	if (ret) {
+		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
+
 	ret = platform_driver_register(&mvebu_uart_platform_driver);
-	if (ret)
+	if (ret) {
+		platform_driver_unregister(&mvebu_uart_clock_platform_driver);
 		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
 
-	return ret;
+	return 0;
 }
 arch_initcall(mvebu_uart_init);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 08/10] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (6 preceding siblings ...)
  2021-06-24 22:49 ` [PATCH 07/10] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-24 22:49 ` [PATCH 09/10] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This change adds DT bindings documentation for device nodes with compatible
string "marvell,armada-3700-uart-clock".

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 .../bindings/clock/armada3700-uart-clock.txt  | 24 +++++++++++++++++++
 .../devicetree/bindings/serial/mvebu-uart.txt |  9 ++++---
 2 files changed, 30 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt

diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
new file mode 100644
index 000000000000..144bc6d7eae8
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
@@ -0,0 +1,24 @@
+* Marvell Armada 3720 UART clocks
+
+Required properties:
+- compatible: "marvell,armada-3700-uart-clock"
+- reg: two 4-bytes registers: UART Clock Control and UART 2 Baud Rate Divisor
+- #clock-cells : from common clock binding; shall be set to 1
+- clocks: List of parent clocks suitable for UART from following set:
+		"TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
+	UART clock can use one from this set and when more are provided
+	then kernel would choose and configure the most suitable one.
+	It is suggest to specify at least one TBG clock to achieve
+	baudrates above 230400 and also to specify clock which bootloader
+	used for UART (most probably xtal) for smooth boot log on UART.
+
+Example:
+	uartclk: uartclk@12000 {
+		compatible = "marvell,armada-3700-uart-clock";
+		reg = <0x12010 0x4>, <0x12210 0x4>;
+		clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
+			<&tbg 3>, <&xtalclk>;
+		clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S",
+			"TBG-B-S", "xtal";
+		#clock-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
index 2d0dbdf32d1d..463968e7e7f3 100644
--- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
@@ -14,7 +14,10 @@ Required properties:
       is provided (possible only with the "marvell,armada-3700-uart"
       compatible string for backward compatibility), it will only work
       if the baudrate was initialized by the bootloader and no baudrate
-      change will then be possible.
+      change will then be possible. When provided it should be UART1-clk
+      for standard variant of UART and UART2-clk for extended variant
+      of UART. TBG clock (with TBG divisors d1=d2=1) or xtal clock should
+      not be used and are supported only for backward compatibility.
 - interrupts:
     - Must contain three elements for the standard variant of the IP
       (marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx",
@@ -34,7 +37,7 @@ Example:
 	uart0: serial@12000 {
 		compatible = "marvell,armada-3700-uart";
 		reg = <0x12000 0x18>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 0>;
 		interrupts =
 		<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 		<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -45,7 +48,7 @@ Example:
 	uart1: serial@12200 {
 		compatible = "marvell,armada-3700-uart-ext";
 		reg = <0x12200 0x30>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 1>;
 		interrupts =
 		<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 		<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 09/10] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (7 preceding siblings ...)
  2021-06-24 22:49 ` [PATCH 08/10] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-24 22:49 ` [PATCH 10/10] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This change defines DT node for UART clock "marvell,armada-3700-uart-clock"
and use this UART clock as a base clock for all UART devices.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 arch/arm64/boot/dts/marvell/armada-3720-db.dts    |  4 ++++
 .../boot/dts/marvell/armada-3720-espressobin.dtsi |  4 ++++
 .../boot/dts/marvell/armada-3720-turris-mox.dts   |  4 ++++
 arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts  |  4 ++++
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi      | 15 +++++++++++++--
 5 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 3e5789f37206..accf014a6a1e 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -191,6 +191,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /*
  * Exported on the micro USB connector CON30(V2.0)/CON32(V1.4) through
  * an FTDI (also on CON24(V2.0)/CON26(V1.4)).
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
index 5fc613d24151..d03c7cdfbfb3 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
@@ -117,6 +117,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /* Exported on the micro USB connector J5 through an FTDI */
 &uart0 {
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
index 52070dd0b7ee..62d56951f5d6 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
@@ -167,6 +167,10 @@
 	status = "disabled";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
index 95d46e8d081c..c8217440b8dd 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
@@ -183,6 +183,10 @@
 	phy-names = "usb2-utmi-otg-phy";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 20dd9d9e9d58..d9bdd374cf45 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -132,10 +132,21 @@
 				reg = <0x11500 0x40>;
 			};
 
+			uartclk: uartclk@12000 {
+				compatible = "marvell,armada-3700-uart-clock";
+				reg = <0x12010 0x4>, <0x12210 0x4>;
+				clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
+					<&tbg 3>, <&xtalclk>;
+				clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S",
+					"TBG-B-S", "xtal";
+				#clock-cells = <1>;
+				status = "disabled";
+			};
+
 			uart0: serial@12000 {
 				compatible = "marvell,armada-3700-uart";
 				reg = <0x12000 0x18>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 0>;
 				interrupts =
 				<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -147,7 +158,7 @@
 			uart1: serial@12200 {
 				compatible = "marvell,armada-3700-uart-ext";
 				reg = <0x12200 0x30>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 1>;
 				interrupts =
 				<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 				<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 10/10] serial: mvebu-uart: implement support for baudrates higher than 230400
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (8 preceding siblings ...)
  2021-06-24 22:49 ` [PATCH 09/10] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
@ 2021-06-24 22:49 ` Pali Rohár
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-24 22:49 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

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 <pali@kernel.org>
---
 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 e51a84be1939..3373ce60c8c0 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -98,6 +98,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
 
@@ -478,18 +479,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;
@@ -499,6 +541,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;
@@ -528,14 +573,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)) {
@@ -1395,14 +1440,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;
@@ -1417,7 +1462,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


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (9 preceding siblings ...)
  2021-06-24 22:49 ` [PATCH 10/10] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
@ 2021-06-25 14:36 ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 01/11] serial: mvebu-uart: fix calculation of clock divisor Pali Rohár
                     ` (10 more replies)
  2021-07-17 12:38 ` [PATCH v3 0/5] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                   ` (2 subsequent siblings)
  13 siblings, 11 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

This patch series fixes mvebu-uart driver used on Marvell Armada 37xx
boards and add support for baudrates higher than 230400.

In v2 was added patch with DIV_U64_ROUND_CLOSEST helper and changed
patch "implement UART clock driver for configuring UART base clock" to
fix compile errors on 32-bit archs, including usage of new math helper.

Pali Rohár (11):
  serial: mvebu-uart: fix calculation of clock divisor
  serial: mvebu-uart: do not allow changing baudrate when uartclk is not
    available
  serial: mvebu-uart: correctly calculate minimal possible baudrate
  dt-bindings: mvebu-uart: fix documentation
  arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART
  serial: mvebu-uart: remove unused member nb from struct mvebu_uart
  math64: New DIV_U64_ROUND_CLOSEST helper
  serial: mvebu-uart: implement UART clock driver for configuring UART
    base clock
  dt-bindings: mvebu-uart: document DT bindings for
    marvell,armada-3700-uart-clock
  arm64: dts: marvell: armada-37xx: add device node for UART clock and
    use it
  serial: mvebu-uart: implement support for baudrates higher than 230400

 .../bindings/clock/armada3700-uart-clock.txt  |  24 +
 .../devicetree/bindings/serial/mvebu-uart.txt |  15 +-
 .../arm64/boot/dts/marvell/armada-3720-db.dts |   4 +
 .../dts/marvell/armada-3720-espressobin.dtsi  |   4 +
 .../dts/marvell/armada-3720-turris-mox.dts    |   4 +
 .../boot/dts/marvell/armada-3720-uDPU.dts     |   4 +
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi  |  17 +-
 drivers/tty/serial/Kconfig                    |   1 +
 drivers/tty/serial/mvebu-uart.c               | 605 +++++++++++++++++-
 include/linux/math64.h                        |  13 +
 10 files changed, 661 insertions(+), 30 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt

-- 
2.20.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH v2 01/11] serial: mvebu-uart: fix calculation of clock divisor
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 02/11] serial: mvebu-uart: do not allow changing baudrate when uartclk is not available Pali Rohár
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

The clock divisor should be rounded to the closest value.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: 68a0db1d7da2 ("serial: mvebu-uart: add function to change baudrate")
Cc: stable@vger.kernel.org # 0e4cf69ede87 ("serial: mvebu-uart: clarify the baud rate derivation")
---
 drivers/tty/serial/mvebu-uart.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index e0c00a1b0763..f81bfdaa608c 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -463,7 +463,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 	 * makes use of D to configure the desired baudrate.
 	 */
 	m_divisor = OSAMP_DEFAULT_DIVISOR;
-	d_divisor = DIV_ROUND_UP(port->uartclk, baud * m_divisor);
+	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
 
 	brdv = readl(port->membase + UART_BRDV);
 	brdv &= ~BRDV_BAUD_MASK;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 02/11] serial: mvebu-uart: do not allow changing baudrate when uartclk is not available
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 01/11] serial: mvebu-uart: fix calculation of clock divisor Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 03/11] serial: mvebu-uart: correctly calculate minimal possible baudrate Pali Rohár
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

Testing mvuart->clk for non-error is not enough as mvuart->clk may contain
valid clk pointer but when clk_prepare_enable(mvuart->clk) failed then
port->uartclk is zero.

When mvuart->clk is not available then port->uartclk is zero too.

Parent clock rate port->uartclk is needed to calculate UART clock divisor
and without it is not possible to change baudrate.

So fix test condition when it is possible to change baudrate.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: 68a0db1d7da2 ("serial: mvebu-uart: add function to change baudrate")
---
 drivers/tty/serial/mvebu-uart.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index f81bfdaa608c..dc0c26824ddb 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -445,12 +445,11 @@ static void mvebu_uart_shutdown(struct uart_port *port)
 
 static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
-	struct mvebu_uart *mvuart = to_mvuart(port);
 	unsigned int d_divisor, m_divisor;
 	u32 brdv, osamp;
 
-	if (IS_ERR(mvuart->clk))
-		return -PTR_ERR(mvuart->clk);
+	if (!port->uartclk)
+		return -EOPNOTSUPP;
 
 	/*
 	 * The baudrate is derived from the UART clock thanks to two divisors:
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 03/11] serial: mvebu-uart: correctly calculate minimal possible baudrate
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 01/11] serial: mvebu-uart: fix calculation of clock divisor Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 02/11] serial: mvebu-uart: do not allow changing baudrate when uartclk is not available Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 04/11] dt-bindings: mvebu-uart: fix documentation Pali Rohár
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

For default (x16) scheme which is currently used by mvebu-uart.c driver,
maximal divisor of UART base clock is 1023*16. Therefore there is limit for
minimal supported baudrate. This change calculate it correctly and prevents
setting invalid divisor 0 into hardware registers.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: 68a0db1d7da2 ("serial: mvebu-uart: add function to change baudrate")
---
 drivers/tty/serial/mvebu-uart.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index dc0c26824ddb..f8b0016db847 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -481,7 +481,7 @@ static void mvebu_uart_set_termios(struct uart_port *port,
 				   struct ktermios *old)
 {
 	unsigned long flags;
-	unsigned int baud;
+	unsigned int baud, min_baud, max_baud;
 
 	spin_lock_irqsave(&port->lock, flags);
 
@@ -500,16 +500,21 @@ 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.
 	 */
-	baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+	min_baud = DIV_ROUND_UP(port->uartclk, 1023 * 16);
+	max_baud = 230400;
+
+	baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud);
 	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);
+			baud = uart_get_baud_rate(port, old, NULL,
+						  min_baud, max_baud);
 	} else {
 		tty_termios_encode_baud_rate(termios, baud, baud);
 		uart_update_timeout(port, termios->c_cflag, baud);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 04/11] dt-bindings: mvebu-uart: fix documentation
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                     ` (2 preceding siblings ...)
  2021-06-25 14:36   ` [PATCH v2 03/11] serial: mvebu-uart: correctly calculate minimal possible baudrate Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 05/11] arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART Pali Rohár
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

Both UARTs support higher baudrates and are not limited to baudrate 230400.
Only current kernel driver implementation has limitation for both UARTs in
maximal baudrate 230400. This limitation will be removed in next patches.
So remove incorrect information about (hardware) limitation from bindings.

UART1 (standard variant with DT node name 'uart0') has register space
0x12000-0x12018 and not whole size 0x200. So fix also this in example.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: d160c3413478 ("dt-bindings: mvebu-uart: update documentation with extended UART")
---
 Documentation/devicetree/bindings/serial/mvebu-uart.txt | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
index b7e0e32b9ac6..2d0dbdf32d1d 100644
--- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
@@ -5,10 +5,10 @@ Required properties:
 - compatible:
     - "marvell,armada-3700-uart" for the standard variant of the UART
       (32 bytes FIFO, no DMA, level interrupts, 8-bit access to the
-      FIFO, baudrate limited to 230400).
+      FIFO), called also UART1.
     - "marvell,armada-3700-uart-ext" for the extended variant of the
       UART (128 bytes FIFO, DMA, front interrupts, 8-bit or 32-bit
-      accesses to the FIFO, baudrate unlimited by the dividers).
+      accesses to the FIFO), called also UART2.
 - reg: offset and length of the register set for the device.
 - clocks: UART reference clock used to derive the baudrate. If no clock
       is provided (possible only with the "marvell,armada-3700-uart"
@@ -33,7 +33,7 @@ Required properties:
 Example:
 	uart0: serial@12000 {
 		compatible = "marvell,armada-3700-uart";
-		reg = <0x12000 0x200>;
+		reg = <0x12000 0x18>;
 		clocks = <&xtalclk>;
 		interrupts =
 		<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 05/11] arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                     ` (3 preceding siblings ...)
  2021-06-25 14:36   ` [PATCH v2 04/11] dt-bindings: mvebu-uart: fix documentation Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 06/11] serial: mvebu-uart: remove unused member nb from struct mvebu_uart Pali Rohár
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

UART1 (standard variant with DT node name 'uart0') has register space
0x12000-0x12018 and not whole size 0x200. So fix also this in example.

Signed-off-by: Pali Rohár <pali@kernel.org>
Fixes: c737abc193d1 ("arm64: dts: marvell: Fix A37xx UART0 register size")
---
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 6897f1f7a7f0..20dd9d9e9d58 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -134,7 +134,7 @@
 
 			uart0: serial@12000 {
 				compatible = "marvell,armada-3700-uart";
-				reg = <0x12000 0x200>;
+				reg = <0x12000 0x18>;
 				clocks = <&xtalclk>;
 				interrupts =
 				<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 06/11] serial: mvebu-uart: remove unused member nb from struct mvebu_uart
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                     ` (4 preceding siblings ...)
  2021-06-25 14:36   ` [PATCH v2 05/11] arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

Member nb in struct mvebu_uart is not set nor read. So remove it completely.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 drivers/tty/serial/mvebu-uart.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index f8b0016db847..414e92064ac6 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -128,7 +128,6 @@ struct mvebu_uart {
 	struct uart_port *port;
 	struct clk *clk;
 	int irq[UART_IRQ_COUNT];
-	unsigned char __iomem *nb;
 	struct mvebu_uart_driver_data *data;
 #if defined(CONFIG_PM)
 	struct mvebu_uart_pm_regs pm_regs;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                     ` (5 preceding siblings ...)
  2021-06-25 14:36   ` [PATCH v2 06/11] serial: mvebu-uart: remove unused member nb from struct mvebu_uart Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 15:22     ` Geert Uytterhoeven
  2021-06-25 14:36   ` [PATCH v2 08/11] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
                     ` (3 subsequent siblings)
  10 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

Provide DIV_U64_ROUND_CLOSEST helper which uses div_u64 to perform
division rounded to the closest integer using unsigned 64bit
dividend and unsigned 32bit divisor.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 include/linux/math64.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/linux/math64.h b/include/linux/math64.h
index 66deb1fdc2ef..1cc61d748e1f 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -281,6 +281,19 @@ u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
 #define DIV64_U64_ROUND_CLOSEST(dividend, divisor)	\
 	({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); })
 
+/*
+ * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 32bit divisor
+ *
+ * Divide unsigned 64bit dividend by unsigned 32bit divisor
+ * and round to closest integer.
+ *
+ * Return: dividend / divisor rounded to nearest integer
+ */
+#define DIV_U64_ROUND_CLOSEST(dividend, divisor)	\
+	({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
+
 /*
  * DIV_S64_ROUND_CLOSEST - signed 64bit divide with 32bit divisor rounded to nearest integer
  * @dividend: signed 64bit dividend
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 08/11] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                     ` (6 preceding siblings ...)
  2021-06-25 14:36   ` [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 09/11] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

This patch implements a new device driver for controlling UART clocks on
Marvell Armada 3700 SoC. This device driver is loaded for devices which
match compatible string "marvell,armada-3700-uart-clock".

There are more pitfalls related to UART clocks. Both UARTs use same base
clock source. Also divisors for TBG base clock are shared between both
UARTs and are configured only from UART1 address space. Clocks can be
enabled / disabled separately for UART1 and UART2, but they are controlled
only from UART1 address space. Moreover Marvell Armada 3700 Functional
Specifications has swapped bits for enabling/disabling UART1 and UART2
clocks.

So driver for controlling UART2 needs to have access to UART1 address space
as UART1 address space contains some bits exclusively used by UART2 and
also bits which are shared for both UART1 and UART2.

For changing UART base clock (which controls both UARTs) during boot when
UART driver is not ready and only early console is active, is not simple
operation as it is required to also recalculate divisors to not change UART
baudrate used by early console. So for this operation UART1 clock driver
needs to access also into address space of UART2 where are registers for
UART2 divisors.

For these reasons, this new device driver for UART clocks does not use
ioremap_resource(), but only ioremap() to prevent resource conflicts
between UART clock driver and UART driver.

Shared between drivers are only two 4-bytes registers: UART Clock Control
and UART 2 Baud Rate Divisor. Access to these two registers are protected
by one spinlock to prevent any conflicts. Access is required only during
probe time, changing baudrate and during suspend/resume.

Hardware can be configured to use one of following clocks as UART base
clock: TBG-A-P, TBG-B-P, TBG-A-S, TBG-B-S, xtal. Not every clock is usable
for higher buadrates. In DT node can be specified any subset and kernel
choose the best one, which still supports required baudrate 9600. For
smooth boot log output it is needed to specify clock used by early console
otherwise garbage would be put on UART during probing for UART clock driver
and transitioning from early console to normal console.

This change is required to enable and configure TBG clock as a base clock
for UART. TBG clock is required to achieve higher baudrates than 230400.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 drivers/tty/serial/Kconfig      |   1 +
 drivers/tty/serial/mvebu-uart.c | 519 +++++++++++++++++++++++++++++++-
 2 files changed, 518 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 0c4cd4a348f4..b3726797a0f5 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1441,6 +1441,7 @@ config SERIAL_STM32_CONSOLE
 config SERIAL_MVEBU_UART
 	bool "Marvell EBU serial port support"
 	depends on ARCH_MVEBU || COMPILE_TEST
+	depends on COMMON_CLK
 	select SERIAL_CORE
 	help
 	  This driver is for Marvell EBU SoC's UART. If you have a machine
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index 414e92064ac6..a31235add99f 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -8,12 +8,14 @@
 */
 
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/math64.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
@@ -68,8 +70,31 @@
 #define  STAT_BRK_ERR		(STAT_BRK_DET | STAT_FRM_ERR \
 				 | STAT_PAR_ERR | STAT_OVR_ERR)
 
+/*
+ * Marvell Armada 3700 Functional Specifications describes that bit 21 of UART
+ * Clock Control register controls UART1 and bit 20 controls UART2. But in
+ * reality bit 21 controls UART2 and bit 20 controls UART1. This seems to be a
+ * bug in Marvell documentation. Hence following CLK_DIS macros are swapped.
+ */
+
 #define UART_BRDV		0x10
+/* These bits are located in UART1 address space and control UART2 */
+#define  UART2_CLK_DIS		BIT(21)
+/* These bits are located in UART1 address space and control UART1 */
+#define  UART1_CLK_DIS		BIT(20)
+/* These bits are located in UART1 address space and control both UARTs */
+#define  CLK_NO_XTAL		BIT(19)
+#define  CLK_TBG_DIV1_SHIFT	15
+#define  CLK_TBG_DIV1_MASK	0x7
+#define  CLK_TBG_DIV1_MAX	6
+#define  CLK_TBG_DIV2_SHIFT	12
+#define  CLK_TBG_DIV2_MASK	0x7
+#define  CLK_TBG_DIV2_MAX	6
+#define  CLK_TBG_SEL_SHIFT	10
+#define  CLK_TBG_SEL_MASK	0x3
+/* These bits are located in both UARTs address space */
 #define  BRDV_BAUD_MASK         0x3FF
+#define  BRDV_BAUD_MAX		BRDV_BAUD_MASK
 
 #define UART_OSAMP		0x14
 #define  OSAMP_DEFAULT_DIVISOR	16
@@ -153,6 +178,8 @@ static struct mvebu_uart *to_mvuart(struct uart_port *port)
 
 static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
 
+static DEFINE_SPINLOCK(mvebu_uart_lock);
+
 /* Core UART Driver Operations */
 static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
 {
@@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
 static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
 	unsigned int d_divisor, m_divisor;
+	unsigned long flags;
 	u32 brdv, osamp;
 
 	if (!port->uartclk)
@@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 	m_divisor = OSAMP_DEFAULT_DIVISOR;
 	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
 
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	brdv = readl(port->membase + UART_BRDV);
 	brdv &= ~BRDV_BAUD_MASK;
 	brdv |= d_divisor;
 	writel(brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 
 	osamp = readl(port->membase + UART_OSAMP);
 	osamp &= ~OSAMP_DIVISORS_MASK;
@@ -762,6 +792,7 @@ static int mvebu_uart_suspend(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	uart_suspend_port(&mvebu_uart_driver, port);
 
@@ -770,7 +801,9 @@ static int mvebu_uart_suspend(struct device *dev)
 	mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port));
 	mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port));
 	mvuart->pm_regs.stat = readl(port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP);
 
 	device_set_wakeup_enable(dev, true);
@@ -782,13 +815,16 @@ static int mvebu_uart_resume(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port));
 	writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port));
 	writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port));
 	writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port));
 	writel(mvuart->pm_regs.stat, port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP);
 
 	uart_resume_port(&mvebu_uart_driver, port);
@@ -975,6 +1011,476 @@ static struct platform_driver mvebu_uart_platform_driver = {
 	},
 };
 
+/* This code is based on clk-fixed-factor.c driver and modified. */
+
+struct mvebu_uart_clock {
+	struct clk_hw clk_hw;
+	int clock_idx;
+	u32 pm_context_reg1;
+	u32 pm_context_reg2;
+};
+
+struct mvebu_uart_clock_base {
+	struct mvebu_uart_clock clocks[2];
+	unsigned int parent_rates[5];
+	int parent_idx;
+	unsigned int div;
+	void __iomem *reg1;
+	void __iomem *reg2;
+	bool configured;
+};
+
+#define PARENT_CLOCK_XTAL 4
+
+#define to_uart_clock(hw) container_of(hw, struct mvebu_uart_clock, clk_hw)
+#define to_uart_clock_base(uart_clock) container_of(uart_clock, \
+	struct mvebu_uart_clock_base, clocks[uart_clock->clock_idx])
+
+static int mvebu_uart_clock_prepare(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned int prev_clock_idx, prev_clock_rate, prev_d1d2;
+	unsigned int parent_clock_idx, parent_clock_rate;
+	unsigned long flags;
+	unsigned int d1, d2;
+	u64 divisor;
+	u32 val;
+
+	/*
+	 * This function just reconfigures UART Clock Control register (located
+	 * in UART1 address space which controls both UART1 and UART2) to
+	 * selected UART base clock and recalculate current UART1/UART2 divisors
+	 * in their address spaces, so final baudrate will not be changed by
+	 * switching UART base clock. This is required otherwise kernel boot log
+	 * stops working. It is needed to ensure that UART baudrate does not
+	 * change during this setup. It is one time operation, so based on
+	 * "configured" member this function is skipped on second call. Because
+	 * this UART Clock Control register (UART_BRDV) is shared between UART1
+	 * baudrate function, UART1 clock selector and UART2 clock selector,
+	 * every access to UART_BRDV (reg1) needs to be protected by lock.
+	 */
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	if (uart_clock_base->configured) {
+		spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+		return 0;
+	}
+
+	parent_clock_idx = uart_clock_base->parent_idx;
+	parent_clock_rate = uart_clock_base->parent_rates[parent_clock_idx];
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock_base->div > CLK_TBG_DIV1_MAX) {
+		d1 = CLK_TBG_DIV1_MAX;
+		d2 = uart_clock_base->div / CLK_TBG_DIV1_MAX;
+	} else {
+		d1 = uart_clock_base->div;
+		d2 = 1;
+	}
+
+	if (val & CLK_NO_XTAL) {
+		prev_clock_idx = (val >> CLK_TBG_SEL_SHIFT) & CLK_TBG_SEL_MASK;
+		prev_d1d2 = ((val >> CLK_TBG_DIV1_SHIFT) & CLK_TBG_DIV1_MASK)
+			  * ((val >> CLK_TBG_DIV2_SHIFT) & CLK_TBG_DIV2_MASK);
+	} else {
+		prev_clock_idx = PARENT_CLOCK_XTAL;
+		prev_d1d2 = 1;
+	}
+
+	/* Note that uart_clock_base->parent_rates[i] may not be available */
+	prev_clock_rate = uart_clock_base->parent_rates[prev_clock_idx];
+
+	/* Recalculate UART1 divisor so UART1 baudrate does not change */
+	if (prev_clock_rate) {
+		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+						parent_clock_rate * prev_d1d2,
+						prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+	}
+
+	if (parent_clock_idx != PARENT_CLOCK_XTAL) {
+		/* Do not use XTAL, select TBG clock and TBG d1 * d2 divisors */
+		val |= CLK_NO_XTAL;
+		val &= ~(CLK_TBG_DIV1_MASK << CLK_TBG_DIV1_SHIFT);
+		val |= d1 << CLK_TBG_DIV1_SHIFT;
+		val &= ~(CLK_TBG_DIV2_MASK << CLK_TBG_DIV2_SHIFT);
+		val |= d2 << CLK_TBG_DIV2_SHIFT;
+		val &= ~(CLK_TBG_SEL_MASK << CLK_TBG_SEL_SHIFT);
+		val |= parent_clock_idx << CLK_TBG_SEL_SHIFT;
+	} else {
+		/* Use XTAL, TBG bits are then ignored */
+		val &= ~CLK_NO_XTAL;
+	}
+
+	writel(val, uart_clock_base->reg1);
+
+	/* Recalculate UART2 divisor so UART2 baudrate does not change */
+	if (prev_clock_rate) {
+		val = readl(uart_clock_base->reg2);
+		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+						parent_clock_rate * prev_d1d2,
+						prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+		writel(val, uart_clock_base->reg2);
+	}
+
+	uart_clock_base->configured = true;
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static int mvebu_uart_clock_enable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val &= ~UART1_CLK_DIS;
+	else
+		val &= ~UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_disable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val |= UART1_CLK_DIS;
+	else
+		val |= UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static int mvebu_uart_clock_is_enabled(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	u32 val;
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		return !(val & UART1_CLK_DIS);
+	else
+		return !(val & UART2_CLK_DIS);
+}
+
+static int mvebu_uart_clock_save_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	uart_clock->pm_context_reg1 = readl(uart_clock_base->reg1);
+	uart_clock->pm_context_reg2 = readl(uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_restore_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	writel(uart_clock->pm_context_reg1, uart_clock_base->reg1);
+	writel(uart_clock->pm_context_reg2, uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return parent_rate / uart_clock_base->div;
+}
+
+static long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long *parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return *parent_rate / uart_clock_base->div;
+}
+
+static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	/*
+	 * We must report success but we can do so unconditionally because
+	 * mvebu_uart_clock_round_rate returns values that ensure this call is a
+	 * nop.
+	 */
+
+	return 0;
+}
+
+static const struct clk_ops mvebu_uart_clock_ops = {
+	.prepare = mvebu_uart_clock_prepare,
+	.enable = mvebu_uart_clock_enable,
+	.disable = mvebu_uart_clock_disable,
+	.is_enabled = mvebu_uart_clock_is_enabled,
+	.save_context = mvebu_uart_clock_save_context,
+	.restore_context = mvebu_uart_clock_restore_context,
+	.round_rate = mvebu_uart_clock_round_rate,
+	.set_rate = mvebu_uart_clock_set_rate,
+	.recalc_rate = mvebu_uart_clock_recalc_rate,
+};
+
+static int mvebu_uart_clock_register(struct device *dev,
+				     struct mvebu_uart_clock *uart_clock,
+				     const char *name,
+				     const char *parent_name)
+{
+	struct clk_init_data init = { };
+
+	uart_clock->clk_hw.init = &init;
+
+	init.name = name;
+	init.ops = &mvebu_uart_clock_ops;
+	init.flags = 0;
+	init.num_parents = 1;
+	init.parent_names = &parent_name;
+
+	return devm_clk_hw_register(dev, &uart_clock->clk_hw);
+}
+
+static int mvebu_uart_clock_probe(struct platform_device *pdev)
+{
+	static const char *const uart_clk_names[] = { "uart_1", "uart_2" };
+	static const char *const parent_clk_names[] = { "TBG-A-P", "TBG-B-P",
+							"TBG-A-S", "TBG-B-S",
+							"xtal" };
+	struct clk *parent_clks[ARRAY_SIZE(parent_clk_names)];
+	struct mvebu_uart_clock_base *uart_clock_base;
+	struct clk_hw_onecell_data *hw_clk_data;
+	struct device *dev = &pdev->dev;
+	int i, parent_clk_idx, ret;
+	unsigned long div, rate;
+	struct resource *res;
+	unsigned int d1, d2;
+
+	BUILD_BUG_ON(ARRAY_SIZE(uart_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->clocks));
+	BUILD_BUG_ON(ARRAY_SIZE(parent_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->parent_rates));
+
+	uart_clock_base = devm_kzalloc(dev,
+				       sizeof(*uart_clock_base),
+				       GFP_KERNEL);
+	if (!uart_clock_base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "Couldn't get first register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART Clock Control register (reg1 / UART_BRDV) is in address range
+	 * of UART1 (standard UART variant), controls clock source and dividers
+	 * for both UART1 and UART2 and is supplied via DT as first resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART1 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg1 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg1))
+		return PTR_ERR(uart_clock_base->reg1);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "Couldn't get second register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART 2 Baud Rate Divisor register (reg2 / UART_BRDV) is in address
+	 * range of UART2 (extended UART variant), controls only one UART2
+	 * specific divider and is supplied via DT as second resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART2 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg2 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg2))
+		return PTR_ERR(uart_clock_base->reg2);
+
+	hw_clk_data = devm_kzalloc(dev,
+				   struct_size(hw_clk_data, hws,
+					       ARRAY_SIZE(uart_clk_names)),
+				   GFP_KERNEL);
+	if (!hw_clk_data)
+		return -ENOMEM;
+
+	hw_clk_data->num = ARRAY_SIZE(uart_clk_names);
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		hw_clk_data->hws[i] = &uart_clock_base->clocks[i].clk_hw;
+		uart_clock_base->clocks[i].clock_idx = i;
+	}
+
+	parent_clk_idx = -1;
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		parent_clks[i] = devm_clk_get(dev, parent_clk_names[i]);
+		if (IS_ERR(parent_clks[i])) {
+			if (PTR_ERR(parent_clks[i]) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			dev_warn(dev, "Couldn't get the parent clock %s: %ld\n",
+				parent_clk_names[i], PTR_ERR(parent_clks[i]));
+			continue;
+		}
+
+		ret = clk_prepare_enable(parent_clks[i]);
+		if (ret) {
+			dev_warn(dev, "Couldn't enable parent clock %s: %d\n",
+				parent_clk_names[i], ret);
+			continue;
+		}
+		rate = clk_get_rate(parent_clks[i]);
+		uart_clock_base->parent_rates[i] = rate;
+
+		if (i != PARENT_CLOCK_XTAL) {
+			/*
+			 * Calculate the smallest TBG d1 and d2 divisors that
+			 * still can provide 9600 baudrate.
+			 */
+			d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_DEFAULT_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 *
+						BRDV_BAUD_MAX * d1);
+			if (d2 < 1)
+				d2 = 1;
+			else if (d2 > CLK_TBG_DIV2_MAX)
+				d2 = CLK_TBG_DIV2_MAX;
+		} else {
+			/*
+			 * When UART clock uses XTAL clock as a source then it
+			 * is not possible to use d1 and d2 divisors.
+			 */
+			d1 = d2 = 1;
+		}
+
+		/* Skip clock source which cannot provide 9600 baudrate */
+		if (rate > 9600 * OSAMP_DEFAULT_DIVISOR * BRDV_BAUD_MAX * d1 * d2)
+			continue;
+
+		/*
+		 * Choose TBG clock source with the smallest divisors. Use XTAL
+		 * clock source only in case TBG is not available as XTAL cannot
+		 * be used for baudrates higher than 230400.
+		 */
+		if (parent_clk_idx == -1 ||
+		    (i != PARENT_CLOCK_XTAL && div > d1 * d2)) {
+			parent_clk_idx = i;
+			div = d1 * d2;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		if (i == parent_clk_idx || IS_ERR(parent_clks[i]))
+			continue;
+		clk_disable_unprepare(parent_clks[i]);
+		devm_clk_put(dev, parent_clks[i]);
+	}
+
+	if (parent_clk_idx == -1) {
+		dev_err(dev, "No usable parent clock\n");
+		return -ENOENT;
+	}
+
+	uart_clock_base->parent_idx = parent_clk_idx;
+	uart_clock_base->div = div;
+
+	dev_notice(dev, "Using parent clock %s as base UART clock\n",
+		   __clk_get_name(parent_clks[parent_clk_idx]));
+
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		ret = mvebu_uart_clock_register(dev,
+				&uart_clock_base->clocks[i],
+				uart_clk_names[i],
+				__clk_get_name(parent_clks[parent_clk_idx]));
+		if (ret) {
+			dev_err(dev, "Can't register UART clock %d: %d\n",
+				i, ret);
+			return ret;
+		}
+	}
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+					   hw_clk_data);
+}
+
+static const struct of_device_id mvebu_uart_clock_of_match[] = {
+	{ .compatible = "marvell,armada-3700-uart-clock", },
+	{ }
+};
+
+static struct platform_driver mvebu_uart_clock_platform_driver = {
+	.probe = mvebu_uart_clock_probe,
+	.driver		= {
+		.name	= "mvebu-uart-clock",
+		.of_match_table = mvebu_uart_clock_of_match,
+	},
+};
+
 static int __init mvebu_uart_init(void)
 {
 	int ret;
@@ -983,10 +1489,19 @@ static int __init mvebu_uart_init(void)
 	if (ret)
 		return ret;
 
+	ret = platform_driver_register(&mvebu_uart_clock_platform_driver);
+	if (ret) {
+		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
+
 	ret = platform_driver_register(&mvebu_uart_platform_driver);
-	if (ret)
+	if (ret) {
+		platform_driver_unregister(&mvebu_uart_clock_platform_driver);
 		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
 
-	return ret;
+	return 0;
 }
 arch_initcall(mvebu_uart_init);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 09/11] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                     ` (7 preceding siblings ...)
  2021-06-25 14:36   ` [PATCH v2 08/11] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 10/11] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 11/11] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

This change adds DT bindings documentation for device nodes with compatible
string "marvell,armada-3700-uart-clock".

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 .../bindings/clock/armada3700-uart-clock.txt  | 24 +++++++++++++++++++
 .../devicetree/bindings/serial/mvebu-uart.txt |  9 ++++---
 2 files changed, 30 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt

diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
new file mode 100644
index 000000000000..144bc6d7eae8
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
@@ -0,0 +1,24 @@
+* Marvell Armada 3720 UART clocks
+
+Required properties:
+- compatible: "marvell,armada-3700-uart-clock"
+- reg: two 4-bytes registers: UART Clock Control and UART 2 Baud Rate Divisor
+- #clock-cells : from common clock binding; shall be set to 1
+- clocks: List of parent clocks suitable for UART from following set:
+		"TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
+	UART clock can use one from this set and when more are provided
+	then kernel would choose and configure the most suitable one.
+	It is suggest to specify at least one TBG clock to achieve
+	baudrates above 230400 and also to specify clock which bootloader
+	used for UART (most probably xtal) for smooth boot log on UART.
+
+Example:
+	uartclk: uartclk@12000 {
+		compatible = "marvell,armada-3700-uart-clock";
+		reg = <0x12010 0x4>, <0x12210 0x4>;
+		clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
+			<&tbg 3>, <&xtalclk>;
+		clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S",
+			"TBG-B-S", "xtal";
+		#clock-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
index 2d0dbdf32d1d..463968e7e7f3 100644
--- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
@@ -14,7 +14,10 @@ Required properties:
       is provided (possible only with the "marvell,armada-3700-uart"
       compatible string for backward compatibility), it will only work
       if the baudrate was initialized by the bootloader and no baudrate
-      change will then be possible.
+      change will then be possible. When provided it should be UART1-clk
+      for standard variant of UART and UART2-clk for extended variant
+      of UART. TBG clock (with TBG divisors d1=d2=1) or xtal clock should
+      not be used and are supported only for backward compatibility.
 - interrupts:
     - Must contain three elements for the standard variant of the IP
       (marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx",
@@ -34,7 +37,7 @@ Example:
 	uart0: serial@12000 {
 		compatible = "marvell,armada-3700-uart";
 		reg = <0x12000 0x18>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 0>;
 		interrupts =
 		<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 		<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -45,7 +48,7 @@ Example:
 	uart1: serial@12200 {
 		compatible = "marvell,armada-3700-uart-ext";
 		reg = <0x12200 0x30>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 1>;
 		interrupts =
 		<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 		<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 10/11] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                     ` (8 preceding siblings ...)
  2021-06-25 14:36   ` [PATCH v2 09/11] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  2021-06-25 14:36   ` [PATCH v2 11/11] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

This change defines DT node for UART clock "marvell,armada-3700-uart-clock"
and use this UART clock as a base clock for all UART devices.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 arch/arm64/boot/dts/marvell/armada-3720-db.dts    |  4 ++++
 .../boot/dts/marvell/armada-3720-espressobin.dtsi |  4 ++++
 .../boot/dts/marvell/armada-3720-turris-mox.dts   |  4 ++++
 arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts  |  4 ++++
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi      | 15 +++++++++++++--
 5 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 3e5789f37206..accf014a6a1e 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -191,6 +191,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /*
  * Exported on the micro USB connector CON30(V2.0)/CON32(V1.4) through
  * an FTDI (also on CON24(V2.0)/CON26(V1.4)).
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
index 5fc613d24151..d03c7cdfbfb3 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
@@ -117,6 +117,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /* Exported on the micro USB connector J5 through an FTDI */
 &uart0 {
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
index 52070dd0b7ee..62d56951f5d6 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
@@ -167,6 +167,10 @@
 	status = "disabled";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
index 95d46e8d081c..c8217440b8dd 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
@@ -183,6 +183,10 @@
 	phy-names = "usb2-utmi-otg-phy";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 20dd9d9e9d58..d9bdd374cf45 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -132,10 +132,21 @@
 				reg = <0x11500 0x40>;
 			};
 
+			uartclk: uartclk@12000 {
+				compatible = "marvell,armada-3700-uart-clock";
+				reg = <0x12010 0x4>, <0x12210 0x4>;
+				clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
+					<&tbg 3>, <&xtalclk>;
+				clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S",
+					"TBG-B-S", "xtal";
+				#clock-cells = <1>;
+				status = "disabled";
+			};
+
 			uart0: serial@12000 {
 				compatible = "marvell,armada-3700-uart";
 				reg = <0x12000 0x18>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 0>;
 				interrupts =
 				<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -147,7 +158,7 @@
 			uart1: serial@12200 {
 				compatible = "marvell,armada-3700-uart-ext";
 				reg = <0x12200 0x30>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 1>;
 				interrupts =
 				<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 				<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v2 11/11] serial: mvebu-uart: implement support for baudrates higher than 230400
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                     ` (9 preceding siblings ...)
  2021-06-25 14:36   ` [PATCH v2 10/11] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
@ 2021-06-25 14:36   ` Pali Rohár
  10 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 14:36 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

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 <pali@kernel.org>
---
 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


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-06-25 14:36   ` [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
@ 2021-06-25 15:22     ` Geert Uytterhoeven
  2021-06-25 15:38       ` Pali Rohár
  0 siblings, 1 reply; 67+ messages in thread
From: Geert Uytterhoeven @ 2021-06-25 15:22 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk,
	open list:SERIAL DRIVERS, Linux Kernel Mailing List, Linux ARM

Hi Pali,

On Fri, Jun 25, 2021 at 4:37 PM Pali Rohár <pali@kernel.org> wrote:
> Provide DIV_U64_ROUND_CLOSEST helper which uses div_u64 to perform
> division rounded to the closest integer using unsigned 64bit
> dividend and unsigned 32bit divisor.
>
> Signed-off-by: Pali Rohár <pali@kernel.org>

Thanks for your patch!

> --- a/include/linux/math64.h
> +++ b/include/linux/math64.h
> @@ -281,6 +281,19 @@ u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
>  #define DIV64_U64_ROUND_CLOSEST(dividend, divisor)     \
>         ({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); })
>
> +/*
> + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
> + * @dividend: unsigned 64bit dividend
> + * @divisor: unsigned 32bit divisor
> + *
> + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> + * and round to closest integer.
> + *
> + * Return: dividend / divisor rounded to nearest integer
> + */
> +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \
> +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })

Given "dividend" should already be an unsigned 64-bit value, I don't
think the cast to "u64" is needed. Similar macros in this file also
don't have the cast.

> +
>  /*
>   * DIV_S64_ROUND_CLOSEST - signed 64bit divide with 32bit divisor rounded to nearest integer
>   * @dividend: signed 64bit dividend

With the above nit fixed:
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-06-25 15:22     ` Geert Uytterhoeven
@ 2021-06-25 15:38       ` Pali Rohár
  2021-06-25 15:50         ` Willy Tarreau
  2021-07-19 12:45         ` Andy Shevchenko
  0 siblings, 2 replies; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 15:38 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk,
	open list:SERIAL DRIVERS, Linux Kernel Mailing List, Linux ARM

On Friday 25 June 2021 17:22:31 Geert Uytterhoeven wrote:
> Hi Pali,
> 
> On Fri, Jun 25, 2021 at 4:37 PM Pali Rohár <pali@kernel.org> wrote:
> > Provide DIV_U64_ROUND_CLOSEST helper which uses div_u64 to perform
> > division rounded to the closest integer using unsigned 64bit
> > dividend and unsigned 32bit divisor.
> >
> > Signed-off-by: Pali Rohár <pali@kernel.org>
> 
> Thanks for your patch!
> 
> > --- a/include/linux/math64.h
> > +++ b/include/linux/math64.h
> > @@ -281,6 +281,19 @@ u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
> >  #define DIV64_U64_ROUND_CLOSEST(dividend, divisor)     \
> >         ({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); })
> >
> > +/*
> > + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
> > + * @dividend: unsigned 64bit dividend
> > + * @divisor: unsigned 32bit divisor
> > + *
> > + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> > + * and round to closest integer.
> > + *
> > + * Return: dividend / divisor rounded to nearest integer
> > + */
> > +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \
> > +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
> 
> Given "dividend" should already be an unsigned 64-bit value, I don't
> think the cast to "u64" is needed. Similar macros in this file also
> don't have the cast.

It is just to ensure that plus operation between dividend and _tmp is
evaluated in 64-bit context to prevent overflow. Just a case when user
calls this macro with 32-bit dividend param. As it is a macro (and not
inline function) type is not automatically enforced.

DIV_S64_ROUND_CLOSEST macro assigns its argument into temporary 64-bit
variable which then ensures usage of 64-bit arithmetic operations. Same
applies for DIV64_U64_ROUND_CLOSEST and DIV64_U64_ROUND_UP macros.

So this is reason why I added explicit cast to u64.

> 
> > +
> >  /*
> >   * DIV_S64_ROUND_CLOSEST - signed 64bit divide with 32bit divisor rounded to nearest integer
> >   * @dividend: signed 64bit dividend
> 
> With the above nit fixed:
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> -- 
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-06-25 15:38       ` Pali Rohár
@ 2021-06-25 15:50         ` Willy Tarreau
  2021-06-25 17:39           ` Geert Uytterhoeven
  2021-07-19 12:45         ` Andy Shevchenko
  1 sibling, 1 reply; 67+ messages in thread
From: Willy Tarreau @ 2021-06-25 15:50 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Geert Uytterhoeven, Michael Turquette, Stephen Boyd, Rob Herring,
	Greg Kroah-Hartman, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Vladimir Vid, Marek Behún, linux-clk,
	open list:SERIAL DRIVERS, Linux Kernel Mailing List, Linux ARM

On Fri, Jun 25, 2021 at 05:38:03PM +0200, Pali Rohár wrote:
> On Friday 25 June 2021 17:22:31 Geert Uytterhoeven wrote:
> > > +/*
> > > + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
> > > + * @dividend: unsigned 64bit dividend
> > > + * @divisor: unsigned 32bit divisor
> > > + *
> > > + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> > > + * and round to closest integer.
> > > + *
> > > + * Return: dividend / divisor rounded to nearest integer
> > > + */
> > > +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \
> > > +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
> > 
> > Given "dividend" should already be an unsigned 64-bit value, I don't
> > think the cast to "u64" is needed. Similar macros in this file also
> > don't have the cast.
> 
> It is just to ensure that plus operation between dividend and _tmp is
> evaluated in 64-bit context to prevent overflow. Just a case when user
> calls this macro with 32-bit dividend param. As it is a macro (and not
> inline function) type is not automatically enforced.

I agree, a large u32 argument added to _tmp/2 could overflow and remain
32 bits, yielding an incorrect result. The cast is mandatory here (and
will either emit no code, or be useful).

The only trap I'm seeing is if a negative signed int is passed in dividend,
it will be sign-extended and will give a large u64 value. A preliminary
u32 cast could avoid this but would break valid u64 arguments, and I'd
claim we never know what the user wants if this happens in the first place.

Willy

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-06-25 15:50         ` Willy Tarreau
@ 2021-06-25 17:39           ` Geert Uytterhoeven
  2021-06-25 17:44             ` Pali Rohár
  0 siblings, 1 reply; 67+ messages in thread
From: Geert Uytterhoeven @ 2021-06-25 17:39 UTC (permalink / raw)
  To: Willy Tarreau
  Cc: Pali Rohár, Michael Turquette, Stephen Boyd, Rob Herring,
	Greg Kroah-Hartman, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Vladimir Vid, Marek Behún, linux-clk,
	open list:SERIAL DRIVERS, Linux Kernel Mailing List, Linux ARM

Hi Willy,

On Fri, Jun 25, 2021 at 5:50 PM Willy Tarreau <w@1wt.eu> wrote:
> On Fri, Jun 25, 2021 at 05:38:03PM +0200, Pali Rohár wrote:
> > On Friday 25 June 2021 17:22:31 Geert Uytterhoeven wrote:
> > > > +/*
> > > > + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
> > > > + * @dividend: unsigned 64bit dividend
> > > > + * @divisor: unsigned 32bit divisor
> > > > + *
> > > > + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> > > > + * and round to closest integer.
> > > > + *
> > > > + * Return: dividend / divisor rounded to nearest integer
> > > > + */
> > > > +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \
> > > > +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
> > >
> > > Given "dividend" should already be an unsigned 64-bit value, I don't
> > > think the cast to "u64" is needed. Similar macros in this file also
> > > don't have the cast.
> >
> > It is just to ensure that plus operation between dividend and _tmp is
> > evaluated in 64-bit context to prevent overflow. Just a case when user
> > calls this macro with 32-bit dividend param. As it is a macro (and not
> > inline function) type is not automatically enforced.
>
> I agree, a large u32 argument added to _tmp/2 could overflow and remain
> 32 bits, yielding an incorrect result. The cast is mandatory here (and
> will either emit no code, or be useful).

Fair enough.
So we want to add a cast to DIV64_U64_ROUND_CLOSEST() above, too?

> The only trap I'm seeing is if a negative signed int is passed in dividend,
> it will be sign-extended and will give a large u64 value. A preliminary
> u32 cast could avoid this but would break valid u64 arguments, and I'd
> claim we never know what the user wants if this happens in the first place.

Yep.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-06-25 17:39           ` Geert Uytterhoeven
@ 2021-06-25 17:44             ` Pali Rohár
  2021-06-25 18:11               ` Geert Uytterhoeven
  0 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-06-25 17:44 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Willy Tarreau, Michael Turquette, Stephen Boyd, Rob Herring,
	Greg Kroah-Hartman, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Vladimir Vid, Marek Behún, linux-clk,
	open list:SERIAL DRIVERS, Linux Kernel Mailing List, Linux ARM

On Friday 25 June 2021 19:39:10 Geert Uytterhoeven wrote:
> Hi Willy,
> 
> On Fri, Jun 25, 2021 at 5:50 PM Willy Tarreau <w@1wt.eu> wrote:
> > On Fri, Jun 25, 2021 at 05:38:03PM +0200, Pali Rohár wrote:
> > > On Friday 25 June 2021 17:22:31 Geert Uytterhoeven wrote:
> > > > > +/*
> > > > > + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
> > > > > + * @dividend: unsigned 64bit dividend
> > > > > + * @divisor: unsigned 32bit divisor
> > > > > + *
> > > > > + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> > > > > + * and round to closest integer.
> > > > > + *
> > > > > + * Return: dividend / divisor rounded to nearest integer
> > > > > + */
> > > > > +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \
> > > > > +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
> > > >
> > > > Given "dividend" should already be an unsigned 64-bit value, I don't
> > > > think the cast to "u64" is needed. Similar macros in this file also
> > > > don't have the cast.
> > >
> > > It is just to ensure that plus operation between dividend and _tmp is
> > > evaluated in 64-bit context to prevent overflow. Just a case when user
> > > calls this macro with 32-bit dividend param. As it is a macro (and not
> > > inline function) type is not automatically enforced.
> >
> > I agree, a large u32 argument added to _tmp/2 could overflow and remain
> > 32 bits, yielding an incorrect result. The cast is mandatory here (and
> > will either emit no code, or be useful).
> 
> Fair enough.
> So we want to add a cast to DIV64_U64_ROUND_CLOSEST() above, too?

For DIV64_U64_ROUND_CLOSEST() it is not needed. divisor is copied into
u64 _tmp variable and therefore "(dividend) + _tmp / 2" is already
evaluated in 64-bit context even when dividend is only 32-bit.

The only trap is that negative value as written below.

> > The only trap I'm seeing is if a negative signed int is passed in dividend,
> > it will be sign-extended and will give a large u64 value. A preliminary
> > u32 cast could avoid this but would break valid u64 arguments, and I'd
> > claim we never know what the user wants if this happens in the first place.
> 
> Yep.
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> -- 
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-06-25 17:44             ` Pali Rohár
@ 2021-06-25 18:11               ` Geert Uytterhoeven
  0 siblings, 0 replies; 67+ messages in thread
From: Geert Uytterhoeven @ 2021-06-25 18:11 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Willy Tarreau, Michael Turquette, Stephen Boyd, Rob Herring,
	Greg Kroah-Hartman, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Vladimir Vid, Marek Behún, linux-clk,
	open list:SERIAL DRIVERS, Linux Kernel Mailing List, Linux ARM

Hi Pali,

On Fri, Jun 25, 2021 at 7:44 PM Pali Rohár <pali@kernel.org> wrote:
> On Friday 25 June 2021 19:39:10 Geert Uytterhoeven wrote:
> > On Fri, Jun 25, 2021 at 5:50 PM Willy Tarreau <w@1wt.eu> wrote:
> > > On Fri, Jun 25, 2021 at 05:38:03PM +0200, Pali Rohár wrote:
> > > > On Friday 25 June 2021 17:22:31 Geert Uytterhoeven wrote:
> > > > > > +/*
> > > > > > + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
> > > > > > + * @dividend: unsigned 64bit dividend
> > > > > > + * @divisor: unsigned 32bit divisor
> > > > > > + *
> > > > > > + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> > > > > > + * and round to closest integer.
> > > > > > + *
> > > > > > + * Return: dividend / divisor rounded to nearest integer
> > > > > > + */
> > > > > > +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \
> > > > > > +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
> > > > >
> > > > > Given "dividend" should already be an unsigned 64-bit value, I don't
> > > > > think the cast to "u64" is needed. Similar macros in this file also
> > > > > don't have the cast.
> > > >
> > > > It is just to ensure that plus operation between dividend and _tmp is
> > > > evaluated in 64-bit context to prevent overflow. Just a case when user
> > > > calls this macro with 32-bit dividend param. As it is a macro (and not
> > > > inline function) type is not automatically enforced.
> > >
> > > I agree, a large u32 argument added to _tmp/2 could overflow and remain
> > > 32 bits, yielding an incorrect result. The cast is mandatory here (and
> > > will either emit no code, or be useful).
> >
> > Fair enough.
> > So we want to add a cast to DIV64_U64_ROUND_CLOSEST() above, too?
>
> For DIV64_U64_ROUND_CLOSEST() it is not needed. divisor is copied into
> u64 _tmp variable and therefore "(dividend) + _tmp / 2" is already
> evaluated in 64-bit context even when dividend is only 32-bit.

Thanks, I stand corrected.  Time to enter weekend mode...

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH v3 0/5] serial: mvebu-uart: Support for higher baudrates
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (10 preceding siblings ...)
  2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
@ 2021-07-17 12:38 ` Pali Rohár
  2021-07-17 12:38   ` [PATCH v3 1/5] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
                     ` (4 more replies)
  2021-08-02 14:45 ` [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  13 siblings, 5 replies; 67+ messages in thread
From: Pali Rohár @ 2021-07-17 12:38 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

This patch series add support for baudrates higher than 230400 on
Marvell Armada 37xx boards.

This new version v3 is rebased on top of Linus master branch and all
already applied patches were dropped. There are no changes in patches
itself since v2.

Please review these patches as they touch both Device Tree bindings and
mvebu-uart.c driver.

Pali Rohár (5):
  math64: New DIV_U64_ROUND_CLOSEST helper
  serial: mvebu-uart: implement UART clock driver for configuring UART
    base clock
  dt-bindings: mvebu-uart: document DT bindings for
    marvell,armada-3700-uart-clock
  arm64: dts: marvell: armada-37xx: add device node for UART clock and
    use it
  serial: mvebu-uart: implement support for baudrates higher than 230400

 .../bindings/clock/armada3700-uart-clock.txt  |  24 +
 .../devicetree/bindings/serial/mvebu-uart.txt |   9 +-
 .../arm64/boot/dts/marvell/armada-3720-db.dts |   4 +
 .../dts/marvell/armada-3720-espressobin.dtsi  |   4 +
 .../dts/marvell/armada-3720-turris-mox.dts    |   4 +
 .../boot/dts/marvell/armada-3720-uDPU.dts     |   4 +
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi  |  15 +-
 drivers/tty/serial/Kconfig                    |   1 +
 drivers/tty/serial/mvebu-uart.c               | 592 +++++++++++++++++-
 include/linux/math64.h                        |  13 +
 10 files changed, 649 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt

-- 
2.20.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH v3 1/5] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-07-17 12:38 ` [PATCH v3 0/5] serial: mvebu-uart: Support for higher baudrates Pali Rohár
@ 2021-07-17 12:38   ` Pali Rohár
  2021-07-19 12:47     ` Andy Shevchenko
  2021-07-17 12:38   ` [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-07-17 12:38 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

Provide DIV_U64_ROUND_CLOSEST helper which uses div_u64 to perform
division rounded to the closest integer using unsigned 64bit
dividend and unsigned 32bit divisor.

Signed-off-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 include/linux/math64.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/linux/math64.h b/include/linux/math64.h
index 2928f03d6d46..a14f40de1dca 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -300,6 +300,19 @@ u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
 #define DIV64_U64_ROUND_CLOSEST(dividend, divisor)	\
 	({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); })
 
+/*
+ * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 32bit divisor
+ *
+ * Divide unsigned 64bit dividend by unsigned 32bit divisor
+ * and round to closest integer.
+ *
+ * Return: dividend / divisor rounded to nearest integer
+ */
+#define DIV_U64_ROUND_CLOSEST(dividend, divisor)	\
+	({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
+
 /*
  * DIV_S64_ROUND_CLOSEST - signed 64bit divide with 32bit divisor rounded to nearest integer
  * @dividend: signed 64bit dividend
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-07-17 12:38 ` [PATCH v3 0/5] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  2021-07-17 12:38   ` [PATCH v3 1/5] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
@ 2021-07-17 12:38   ` Pali Rohár
  2021-07-17 17:26     ` Andrew Lunn
  2021-07-17 12:38   ` [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-07-17 12:38 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

This patch implements a new device driver for controlling UART clocks on
Marvell Armada 3700 SoC. This device driver is loaded for devices which
match compatible string "marvell,armada-3700-uart-clock".

There are more pitfalls related to UART clocks. Both UARTs use same base
clock source. Also divisors for TBG base clock are shared between both
UARTs and are configured only from UART1 address space. Clocks can be
enabled / disabled separately for UART1 and UART2, but they are controlled
only from UART1 address space. Moreover Marvell Armada 3700 Functional
Specifications has swapped bits for enabling/disabling UART1 and UART2
clocks.

So driver for controlling UART2 needs to have access to UART1 address space
as UART1 address space contains some bits exclusively used by UART2 and
also bits which are shared for both UART1 and UART2.

For changing UART base clock (which controls both UARTs) during boot when
UART driver is not ready and only early console is active, is not simple
operation as it is required to also recalculate divisors to not change UART
baudrate used by early console. So for this operation UART1 clock driver
needs to access also into address space of UART2 where are registers for
UART2 divisors.

For these reasons, this new device driver for UART clocks does not use
ioremap_resource(), but only ioremap() to prevent resource conflicts
between UART clock driver and UART driver.

Shared between drivers are only two 4-bytes registers: UART Clock Control
and UART 2 Baud Rate Divisor. Access to these two registers are protected
by one spinlock to prevent any conflicts. Access is required only during
probe time, changing baudrate and during suspend/resume.

Hardware can be configured to use one of following clocks as UART base
clock: TBG-A-P, TBG-B-P, TBG-A-S, TBG-B-S, xtal. Not every clock is usable
for higher buadrates. In DT node can be specified any subset and kernel
choose the best one, which still supports required baudrate 9600. For
smooth boot log output it is needed to specify clock used by early console
otherwise garbage would be put on UART during probing for UART clock driver
and transitioning from early console to normal console.

This change is required to enable and configure TBG clock as a base clock
for UART. TBG clock is required to achieve higher baudrates than 230400.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 drivers/tty/serial/Kconfig      |   1 +
 drivers/tty/serial/mvebu-uart.c | 519 +++++++++++++++++++++++++++++++-
 2 files changed, 518 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 24282ad99d85..c5d81607e5d7 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1444,6 +1444,7 @@ config SERIAL_STM32_CONSOLE
 config SERIAL_MVEBU_UART
 	bool "Marvell EBU serial port support"
 	depends on ARCH_MVEBU || COMPILE_TEST
+	depends on COMMON_CLK
 	select SERIAL_CORE
 	help
 	  This driver is for Marvell EBU SoC's UART. If you have a machine
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index 231de29a6452..f3fb1f3718f2 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -8,12 +8,14 @@
 */
 
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/math64.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
@@ -68,8 +70,31 @@
 #define  STAT_BRK_ERR		(STAT_BRK_DET | STAT_FRM_ERR \
 				 | STAT_PAR_ERR | STAT_OVR_ERR)
 
+/*
+ * Marvell Armada 3700 Functional Specifications describes that bit 21 of UART
+ * Clock Control register controls UART1 and bit 20 controls UART2. But in
+ * reality bit 21 controls UART2 and bit 20 controls UART1. This seems to be a
+ * bug in Marvell documentation. Hence following CLK_DIS macros are swapped.
+ */
+
 #define UART_BRDV		0x10
+/* These bits are located in UART1 address space and control UART2 */
+#define  UART2_CLK_DIS		BIT(21)
+/* These bits are located in UART1 address space and control UART1 */
+#define  UART1_CLK_DIS		BIT(20)
+/* These bits are located in UART1 address space and control both UARTs */
+#define  CLK_NO_XTAL		BIT(19)
+#define  CLK_TBG_DIV1_SHIFT	15
+#define  CLK_TBG_DIV1_MASK	0x7
+#define  CLK_TBG_DIV1_MAX	6
+#define  CLK_TBG_DIV2_SHIFT	12
+#define  CLK_TBG_DIV2_MASK	0x7
+#define  CLK_TBG_DIV2_MAX	6
+#define  CLK_TBG_SEL_SHIFT	10
+#define  CLK_TBG_SEL_MASK	0x3
+/* These bits are located in both UARTs address space */
 #define  BRDV_BAUD_MASK         0x3FF
+#define  BRDV_BAUD_MAX		BRDV_BAUD_MASK
 
 #define UART_OSAMP		0x14
 #define  OSAMP_DEFAULT_DIVISOR	16
@@ -153,6 +178,8 @@ static struct mvebu_uart *to_mvuart(struct uart_port *port)
 
 static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
 
+static DEFINE_SPINLOCK(mvebu_uart_lock);
+
 /* Core UART Driver Operations */
 static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
 {
@@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
 static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
 	unsigned int d_divisor, m_divisor;
+	unsigned long flags;
 	u32 brdv, osamp;
 
 	if (!port->uartclk)
@@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 	m_divisor = OSAMP_DEFAULT_DIVISOR;
 	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
 
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	brdv = readl(port->membase + UART_BRDV);
 	brdv &= ~BRDV_BAUD_MASK;
 	brdv |= d_divisor;
 	writel(brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 
 	osamp = readl(port->membase + UART_OSAMP);
 	osamp &= ~OSAMP_DIVISORS_MASK;
@@ -762,6 +792,7 @@ static int mvebu_uart_suspend(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	uart_suspend_port(&mvebu_uart_driver, port);
 
@@ -770,7 +801,9 @@ static int mvebu_uart_suspend(struct device *dev)
 	mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port));
 	mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port));
 	mvuart->pm_regs.stat = readl(port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP);
 
 	device_set_wakeup_enable(dev, true);
@@ -782,13 +815,16 @@ static int mvebu_uart_resume(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port));
 	writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port));
 	writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port));
 	writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port));
 	writel(mvuart->pm_regs.stat, port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP);
 
 	uart_resume_port(&mvebu_uart_driver, port);
@@ -972,6 +1008,476 @@ static struct platform_driver mvebu_uart_platform_driver = {
 	},
 };
 
+/* This code is based on clk-fixed-factor.c driver and modified. */
+
+struct mvebu_uart_clock {
+	struct clk_hw clk_hw;
+	int clock_idx;
+	u32 pm_context_reg1;
+	u32 pm_context_reg2;
+};
+
+struct mvebu_uart_clock_base {
+	struct mvebu_uart_clock clocks[2];
+	unsigned int parent_rates[5];
+	int parent_idx;
+	unsigned int div;
+	void __iomem *reg1;
+	void __iomem *reg2;
+	bool configured;
+};
+
+#define PARENT_CLOCK_XTAL 4
+
+#define to_uart_clock(hw) container_of(hw, struct mvebu_uart_clock, clk_hw)
+#define to_uart_clock_base(uart_clock) container_of(uart_clock, \
+	struct mvebu_uart_clock_base, clocks[uart_clock->clock_idx])
+
+static int mvebu_uart_clock_prepare(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned int prev_clock_idx, prev_clock_rate, prev_d1d2;
+	unsigned int parent_clock_idx, parent_clock_rate;
+	unsigned long flags;
+	unsigned int d1, d2;
+	u64 divisor;
+	u32 val;
+
+	/*
+	 * This function just reconfigures UART Clock Control register (located
+	 * in UART1 address space which controls both UART1 and UART2) to
+	 * selected UART base clock and recalculate current UART1/UART2 divisors
+	 * in their address spaces, so final baudrate will not be changed by
+	 * switching UART base clock. This is required otherwise kernel boot log
+	 * stops working. It is needed to ensure that UART baudrate does not
+	 * change during this setup. It is one time operation, so based on
+	 * "configured" member this function is skipped on second call. Because
+	 * this UART Clock Control register (UART_BRDV) is shared between UART1
+	 * baudrate function, UART1 clock selector and UART2 clock selector,
+	 * every access to UART_BRDV (reg1) needs to be protected by lock.
+	 */
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	if (uart_clock_base->configured) {
+		spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+		return 0;
+	}
+
+	parent_clock_idx = uart_clock_base->parent_idx;
+	parent_clock_rate = uart_clock_base->parent_rates[parent_clock_idx];
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock_base->div > CLK_TBG_DIV1_MAX) {
+		d1 = CLK_TBG_DIV1_MAX;
+		d2 = uart_clock_base->div / CLK_TBG_DIV1_MAX;
+	} else {
+		d1 = uart_clock_base->div;
+		d2 = 1;
+	}
+
+	if (val & CLK_NO_XTAL) {
+		prev_clock_idx = (val >> CLK_TBG_SEL_SHIFT) & CLK_TBG_SEL_MASK;
+		prev_d1d2 = ((val >> CLK_TBG_DIV1_SHIFT) & CLK_TBG_DIV1_MASK)
+			  * ((val >> CLK_TBG_DIV2_SHIFT) & CLK_TBG_DIV2_MASK);
+	} else {
+		prev_clock_idx = PARENT_CLOCK_XTAL;
+		prev_d1d2 = 1;
+	}
+
+	/* Note that uart_clock_base->parent_rates[i] may not be available */
+	prev_clock_rate = uart_clock_base->parent_rates[prev_clock_idx];
+
+	/* Recalculate UART1 divisor so UART1 baudrate does not change */
+	if (prev_clock_rate) {
+		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+						parent_clock_rate * prev_d1d2,
+						prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+	}
+
+	if (parent_clock_idx != PARENT_CLOCK_XTAL) {
+		/* Do not use XTAL, select TBG clock and TBG d1 * d2 divisors */
+		val |= CLK_NO_XTAL;
+		val &= ~(CLK_TBG_DIV1_MASK << CLK_TBG_DIV1_SHIFT);
+		val |= d1 << CLK_TBG_DIV1_SHIFT;
+		val &= ~(CLK_TBG_DIV2_MASK << CLK_TBG_DIV2_SHIFT);
+		val |= d2 << CLK_TBG_DIV2_SHIFT;
+		val &= ~(CLK_TBG_SEL_MASK << CLK_TBG_SEL_SHIFT);
+		val |= parent_clock_idx << CLK_TBG_SEL_SHIFT;
+	} else {
+		/* Use XTAL, TBG bits are then ignored */
+		val &= ~CLK_NO_XTAL;
+	}
+
+	writel(val, uart_clock_base->reg1);
+
+	/* Recalculate UART2 divisor so UART2 baudrate does not change */
+	if (prev_clock_rate) {
+		val = readl(uart_clock_base->reg2);
+		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+						parent_clock_rate * prev_d1d2,
+						prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+		writel(val, uart_clock_base->reg2);
+	}
+
+	uart_clock_base->configured = true;
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static int mvebu_uart_clock_enable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val &= ~UART1_CLK_DIS;
+	else
+		val &= ~UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_disable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val |= UART1_CLK_DIS;
+	else
+		val |= UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static int mvebu_uart_clock_is_enabled(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	u32 val;
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		return !(val & UART1_CLK_DIS);
+	else
+		return !(val & UART2_CLK_DIS);
+}
+
+static int mvebu_uart_clock_save_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	uart_clock->pm_context_reg1 = readl(uart_clock_base->reg1);
+	uart_clock->pm_context_reg2 = readl(uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_restore_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	writel(uart_clock->pm_context_reg1, uart_clock_base->reg1);
+	writel(uart_clock->pm_context_reg2, uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return parent_rate / uart_clock_base->div;
+}
+
+static long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long *parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return *parent_rate / uart_clock_base->div;
+}
+
+static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	/*
+	 * We must report success but we can do so unconditionally because
+	 * mvebu_uart_clock_round_rate returns values that ensure this call is a
+	 * nop.
+	 */
+
+	return 0;
+}
+
+static const struct clk_ops mvebu_uart_clock_ops = {
+	.prepare = mvebu_uart_clock_prepare,
+	.enable = mvebu_uart_clock_enable,
+	.disable = mvebu_uart_clock_disable,
+	.is_enabled = mvebu_uart_clock_is_enabled,
+	.save_context = mvebu_uart_clock_save_context,
+	.restore_context = mvebu_uart_clock_restore_context,
+	.round_rate = mvebu_uart_clock_round_rate,
+	.set_rate = mvebu_uart_clock_set_rate,
+	.recalc_rate = mvebu_uart_clock_recalc_rate,
+};
+
+static int mvebu_uart_clock_register(struct device *dev,
+				     struct mvebu_uart_clock *uart_clock,
+				     const char *name,
+				     const char *parent_name)
+{
+	struct clk_init_data init = { };
+
+	uart_clock->clk_hw.init = &init;
+
+	init.name = name;
+	init.ops = &mvebu_uart_clock_ops;
+	init.flags = 0;
+	init.num_parents = 1;
+	init.parent_names = &parent_name;
+
+	return devm_clk_hw_register(dev, &uart_clock->clk_hw);
+}
+
+static int mvebu_uart_clock_probe(struct platform_device *pdev)
+{
+	static const char *const uart_clk_names[] = { "uart_1", "uart_2" };
+	static const char *const parent_clk_names[] = { "TBG-A-P", "TBG-B-P",
+							"TBG-A-S", "TBG-B-S",
+							"xtal" };
+	struct clk *parent_clks[ARRAY_SIZE(parent_clk_names)];
+	struct mvebu_uart_clock_base *uart_clock_base;
+	struct clk_hw_onecell_data *hw_clk_data;
+	struct device *dev = &pdev->dev;
+	int i, parent_clk_idx, ret;
+	unsigned long div, rate;
+	struct resource *res;
+	unsigned int d1, d2;
+
+	BUILD_BUG_ON(ARRAY_SIZE(uart_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->clocks));
+	BUILD_BUG_ON(ARRAY_SIZE(parent_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->parent_rates));
+
+	uart_clock_base = devm_kzalloc(dev,
+				       sizeof(*uart_clock_base),
+				       GFP_KERNEL);
+	if (!uart_clock_base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "Couldn't get first register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART Clock Control register (reg1 / UART_BRDV) is in address range
+	 * of UART1 (standard UART variant), controls clock source and dividers
+	 * for both UART1 and UART2 and is supplied via DT as first resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART1 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg1 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg1))
+		return PTR_ERR(uart_clock_base->reg1);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "Couldn't get second register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART 2 Baud Rate Divisor register (reg2 / UART_BRDV) is in address
+	 * range of UART2 (extended UART variant), controls only one UART2
+	 * specific divider and is supplied via DT as second resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART2 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg2 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg2))
+		return PTR_ERR(uart_clock_base->reg2);
+
+	hw_clk_data = devm_kzalloc(dev,
+				   struct_size(hw_clk_data, hws,
+					       ARRAY_SIZE(uart_clk_names)),
+				   GFP_KERNEL);
+	if (!hw_clk_data)
+		return -ENOMEM;
+
+	hw_clk_data->num = ARRAY_SIZE(uart_clk_names);
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		hw_clk_data->hws[i] = &uart_clock_base->clocks[i].clk_hw;
+		uart_clock_base->clocks[i].clock_idx = i;
+	}
+
+	parent_clk_idx = -1;
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		parent_clks[i] = devm_clk_get(dev, parent_clk_names[i]);
+		if (IS_ERR(parent_clks[i])) {
+			if (PTR_ERR(parent_clks[i]) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			dev_warn(dev, "Couldn't get the parent clock %s: %ld\n",
+				parent_clk_names[i], PTR_ERR(parent_clks[i]));
+			continue;
+		}
+
+		ret = clk_prepare_enable(parent_clks[i]);
+		if (ret) {
+			dev_warn(dev, "Couldn't enable parent clock %s: %d\n",
+				parent_clk_names[i], ret);
+			continue;
+		}
+		rate = clk_get_rate(parent_clks[i]);
+		uart_clock_base->parent_rates[i] = rate;
+
+		if (i != PARENT_CLOCK_XTAL) {
+			/*
+			 * Calculate the smallest TBG d1 and d2 divisors that
+			 * still can provide 9600 baudrate.
+			 */
+			d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_DEFAULT_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 *
+						BRDV_BAUD_MAX * d1);
+			if (d2 < 1)
+				d2 = 1;
+			else if (d2 > CLK_TBG_DIV2_MAX)
+				d2 = CLK_TBG_DIV2_MAX;
+		} else {
+			/*
+			 * When UART clock uses XTAL clock as a source then it
+			 * is not possible to use d1 and d2 divisors.
+			 */
+			d1 = d2 = 1;
+		}
+
+		/* Skip clock source which cannot provide 9600 baudrate */
+		if (rate > 9600 * OSAMP_DEFAULT_DIVISOR * BRDV_BAUD_MAX * d1 * d2)
+			continue;
+
+		/*
+		 * Choose TBG clock source with the smallest divisors. Use XTAL
+		 * clock source only in case TBG is not available as XTAL cannot
+		 * be used for baudrates higher than 230400.
+		 */
+		if (parent_clk_idx == -1 ||
+		    (i != PARENT_CLOCK_XTAL && div > d1 * d2)) {
+			parent_clk_idx = i;
+			div = d1 * d2;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		if (i == parent_clk_idx || IS_ERR(parent_clks[i]))
+			continue;
+		clk_disable_unprepare(parent_clks[i]);
+		devm_clk_put(dev, parent_clks[i]);
+	}
+
+	if (parent_clk_idx == -1) {
+		dev_err(dev, "No usable parent clock\n");
+		return -ENOENT;
+	}
+
+	uart_clock_base->parent_idx = parent_clk_idx;
+	uart_clock_base->div = div;
+
+	dev_notice(dev, "Using parent clock %s as base UART clock\n",
+		   __clk_get_name(parent_clks[parent_clk_idx]));
+
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		ret = mvebu_uart_clock_register(dev,
+				&uart_clock_base->clocks[i],
+				uart_clk_names[i],
+				__clk_get_name(parent_clks[parent_clk_idx]));
+		if (ret) {
+			dev_err(dev, "Can't register UART clock %d: %d\n",
+				i, ret);
+			return ret;
+		}
+	}
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+					   hw_clk_data);
+}
+
+static const struct of_device_id mvebu_uart_clock_of_match[] = {
+	{ .compatible = "marvell,armada-3700-uart-clock", },
+	{ }
+};
+
+static struct platform_driver mvebu_uart_clock_platform_driver = {
+	.probe = mvebu_uart_clock_probe,
+	.driver		= {
+		.name	= "mvebu-uart-clock",
+		.of_match_table = mvebu_uart_clock_of_match,
+	},
+};
+
 static int __init mvebu_uart_init(void)
 {
 	int ret;
@@ -980,10 +1486,19 @@ static int __init mvebu_uart_init(void)
 	if (ret)
 		return ret;
 
+	ret = platform_driver_register(&mvebu_uart_clock_platform_driver);
+	if (ret) {
+		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
+
 	ret = platform_driver_register(&mvebu_uart_platform_driver);
-	if (ret)
+	if (ret) {
+		platform_driver_unregister(&mvebu_uart_clock_platform_driver);
 		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
 
-	return ret;
+	return 0;
 }
 arch_initcall(mvebu_uart_init);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock
  2021-07-17 12:38 ` [PATCH v3 0/5] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  2021-07-17 12:38   ` [PATCH v3 1/5] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
  2021-07-17 12:38   ` [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
@ 2021-07-17 12:38   ` Pali Rohár
  2021-07-17 17:30     ` [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell, armada-3700-uart-clock Andrew Lunn
  2021-07-17 12:38   ` [PATCH v3 4/5] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
  2021-07-17 12:38   ` [PATCH v3 5/5] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
  4 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-07-17 12:38 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

This change adds DT bindings documentation for device nodes with compatible
string "marvell,armada-3700-uart-clock".

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 .../bindings/clock/armada3700-uart-clock.txt  | 24 +++++++++++++++++++
 .../devicetree/bindings/serial/mvebu-uart.txt |  9 ++++---
 2 files changed, 30 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt

diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
new file mode 100644
index 000000000000..144bc6d7eae8
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
@@ -0,0 +1,24 @@
+* Marvell Armada 3720 UART clocks
+
+Required properties:
+- compatible: "marvell,armada-3700-uart-clock"
+- reg: two 4-bytes registers: UART Clock Control and UART 2 Baud Rate Divisor
+- #clock-cells : from common clock binding; shall be set to 1
+- clocks: List of parent clocks suitable for UART from following set:
+		"TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
+	UART clock can use one from this set and when more are provided
+	then kernel would choose and configure the most suitable one.
+	It is suggest to specify at least one TBG clock to achieve
+	baudrates above 230400 and also to specify clock which bootloader
+	used for UART (most probably xtal) for smooth boot log on UART.
+
+Example:
+	uartclk: uartclk@12000 {
+		compatible = "marvell,armada-3700-uart-clock";
+		reg = <0x12010 0x4>, <0x12210 0x4>;
+		clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
+			<&tbg 3>, <&xtalclk>;
+		clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S",
+			"TBG-B-S", "xtal";
+		#clock-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
index 2d0dbdf32d1d..463968e7e7f3 100644
--- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
@@ -14,7 +14,10 @@ Required properties:
       is provided (possible only with the "marvell,armada-3700-uart"
       compatible string for backward compatibility), it will only work
       if the baudrate was initialized by the bootloader and no baudrate
-      change will then be possible.
+      change will then be possible. When provided it should be UART1-clk
+      for standard variant of UART and UART2-clk for extended variant
+      of UART. TBG clock (with TBG divisors d1=d2=1) or xtal clock should
+      not be used and are supported only for backward compatibility.
 - interrupts:
     - Must contain three elements for the standard variant of the IP
       (marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx",
@@ -34,7 +37,7 @@ Example:
 	uart0: serial@12000 {
 		compatible = "marvell,armada-3700-uart";
 		reg = <0x12000 0x18>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 0>;
 		interrupts =
 		<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 		<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -45,7 +48,7 @@ Example:
 	uart1: serial@12200 {
 		compatible = "marvell,armada-3700-uart-ext";
 		reg = <0x12200 0x30>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 1>;
 		interrupts =
 		<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 		<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v3 4/5] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it
  2021-07-17 12:38 ` [PATCH v3 0/5] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                     ` (2 preceding siblings ...)
  2021-07-17 12:38   ` [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
@ 2021-07-17 12:38   ` Pali Rohár
  2021-07-17 12:38   ` [PATCH v3 5/5] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
  4 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-07-17 12:38 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

This change defines DT node for UART clock "marvell,armada-3700-uart-clock"
and use this UART clock as a base clock for all UART devices.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 arch/arm64/boot/dts/marvell/armada-3720-db.dts    |  4 ++++
 .../boot/dts/marvell/armada-3720-espressobin.dtsi |  4 ++++
 .../boot/dts/marvell/armada-3720-turris-mox.dts   |  4 ++++
 arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts  |  4 ++++
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi      | 15 +++++++++++++--
 5 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 3e5789f37206..accf014a6a1e 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -191,6 +191,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /*
  * Exported on the micro USB connector CON30(V2.0)/CON32(V1.4) through
  * an FTDI (also on CON24(V2.0)/CON26(V1.4)).
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
index 5fc613d24151..d03c7cdfbfb3 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
@@ -117,6 +117,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /* Exported on the micro USB connector J5 through an FTDI */
 &uart0 {
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
index ce2bcddf396f..724b41cca3b6 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
@@ -137,6 +137,10 @@
 	status = "disabled";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
index 95d46e8d081c..c8217440b8dd 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
@@ -183,6 +183,10 @@
 	phy-names = "usb2-utmi-otg-phy";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 5db81a416cd6..d62bf4a798d9 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -132,10 +132,21 @@
 				reg = <0x11500 0x40>;
 			};
 
+			uartclk: uartclk@12000 {
+				compatible = "marvell,armada-3700-uart-clock";
+				reg = <0x12010 0x4>, <0x12210 0x4>;
+				clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
+					<&tbg 3>, <&xtalclk>;
+				clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S",
+					"TBG-B-S", "xtal";
+				#clock-cells = <1>;
+				status = "disabled";
+			};
+
 			uart0: serial@12000 {
 				compatible = "marvell,armada-3700-uart";
 				reg = <0x12000 0x18>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 0>;
 				interrupts =
 				<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -147,7 +158,7 @@
 			uart1: serial@12200 {
 				compatible = "marvell,armada-3700-uart-ext";
 				reg = <0x12200 0x30>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 1>;
 				interrupts =
 				<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 				<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v3 5/5] serial: mvebu-uart: implement support for baudrates higher than 230400
  2021-07-17 12:38 ` [PATCH v3 0/5] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                     ` (3 preceding siblings ...)
  2021-07-17 12:38   ` [PATCH v3 4/5] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
@ 2021-07-17 12:38   ` Pali Rohár
  4 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-07-17 12:38 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

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 <pali@kernel.org>
---
 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 f3fb1f3718f2..925b3e0c098c 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)) {
@@ -1394,14 +1439,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;
@@ -1416,7 +1461,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


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-07-17 12:38   ` [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
@ 2021-07-17 17:26     ` Andrew Lunn
  2021-07-17 18:05       ` Pali Rohár
  0 siblings, 1 reply; 67+ messages in thread
From: Andrew Lunn @ 2021-07-17 17:26 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, Geert Uytterhoeven, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

On Sat, Jul 17, 2021 at 02:38:26PM +0200, Pali Rohár wrote:
> @@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
>  static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
>  {
>  	unsigned int d_divisor, m_divisor;
> +	unsigned long flags;
>  	u32 brdv, osamp;
>  
>  	if (!port->uartclk)
> @@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
>  	m_divisor = OSAMP_DEFAULT_DIVISOR;
>  	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
>  
> +	spin_lock_irqsave(&mvebu_uart_lock, flags);

Hi Pali

You only need spin_lock_irqsave() if you plan on taking the spinlock
in an interrupt handler. It seems unlikely the baud rate will be
changed in interrupt context? Please check, and then swap to plain
spin_lock().

>  	brdv = readl(port->membase + UART_BRDV);
>  	brdv &= ~BRDV_BAUD_MASK;
>  	brdv |= d_divisor;
>  	writel(brdv, port->membase + UART_BRDV);
> +	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
>  
>  	osamp = readl(port->membase + UART_OSAMP);
>  	osamp &= ~OSAMP_DIVISORS_MASK;

> +	/* Recalculate UART1 divisor so UART1 baudrate does not change */
> +	if (prev_clock_rate) {
> +		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
> +						parent_clock_rate * prev_d1d2,
> +						prev_clock_rate * d1 * d2);
> +		if (divisor < 1)
> +			divisor = 1;
> +		else if (divisor > BRDV_BAUD_MAX)
> +			divisor = BRDV_BAUD_MAX;
> +		val = (val & ~BRDV_BAUD_MASK) | divisor;
> +	}

I don't see any range checks in the patch which verifies the requested
baud rate is actually possible. With code like this, it seems like the
baud rate change will be successful, but the actual baud rate will not
be what is requested.

> +	/* Recalculate UART2 divisor so UART2 baudrate does not change */
> +	if (prev_clock_rate) {
> +		val = readl(uart_clock_base->reg2);
> +		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
> +						parent_clock_rate * prev_d1d2,
> +						prev_clock_rate * d1 * d2);
> +		if (divisor < 1)
> +			divisor = 1;
> +		else if (divisor > BRDV_BAUD_MAX)
> +			divisor = BRDV_BAUD_MAX;
> +		val = (val & ~BRDV_BAUD_MASK) | divisor;
> +		writel(val, uart_clock_base->reg2);

Here it looks like UART1 could request a baud rate change, which ends
up setting the clocks so that UART2 is out of range? Could the change
for UART1 be successful, but you end up breaking UART2? I'm thinking
when you are at opposite ends of the scale. UART2 is running at
110baud and UART1 at 230400baud.

	Andrew

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell, armada-3700-uart-clock
  2021-07-17 12:38   ` [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
@ 2021-07-17 17:30     ` Andrew Lunn
  2021-08-02 14:45       ` Pali Rohár
  0 siblings, 1 reply; 67+ messages in thread
From: Andrew Lunn @ 2021-07-17 17:30 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, Geert Uytterhoeven, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

On Sat, Jul 17, 2021 at 02:38:27PM +0200, Pali Rohár wrote:
> This change adds DT bindings documentation for device nodes with compatible
> string "marvell,armada-3700-uart-clock".
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>
> ---
>  .../bindings/clock/armada3700-uart-clock.txt  | 24 +++++++++++++++++++
>  .../devicetree/bindings/serial/mvebu-uart.txt |  9 ++++---
>  2 files changed, 30 insertions(+), 3 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
> 
> diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
> new file mode 100644
> index 000000000000..144bc6d7eae8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt

Since this is a new binding, please use YAML.

      Andrew

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-07-17 17:26     ` Andrew Lunn
@ 2021-07-17 18:05       ` Pali Rohár
  2021-07-24  9:48         ` Pali Rohár
  0 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-07-17 18:05 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, Geert Uytterhoeven, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

On Saturday 17 July 2021 19:26:51 Andrew Lunn wrote:
> On Sat, Jul 17, 2021 at 02:38:26PM +0200, Pali Rohár wrote:
> > @@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
> >  static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
> >  {
> >  	unsigned int d_divisor, m_divisor;
> > +	unsigned long flags;
> >  	u32 brdv, osamp;
> >  
> >  	if (!port->uartclk)
> > @@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
> >  	m_divisor = OSAMP_DEFAULT_DIVISOR;
> >  	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
> >  
> > +	spin_lock_irqsave(&mvebu_uart_lock, flags);
> 
> Hi Pali
> 
> You only need spin_lock_irqsave() if you plan on taking the spinlock
> in an interrupt handler. It seems unlikely the baud rate will be
> changed in interrupt context? Please check, and then swap to plain
> spin_lock().

Hello! Ok, I will check it.

> >  	brdv = readl(port->membase + UART_BRDV);
> >  	brdv &= ~BRDV_BAUD_MASK;
> >  	brdv |= d_divisor;
> >  	writel(brdv, port->membase + UART_BRDV);
> > +	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
> >  
> >  	osamp = readl(port->membase + UART_OSAMP);
> >  	osamp &= ~OSAMP_DIVISORS_MASK;
> 
> > +	/* Recalculate UART1 divisor so UART1 baudrate does not change */
> > +	if (prev_clock_rate) {
> > +		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
> > +						parent_clock_rate * prev_d1d2,
> > +						prev_clock_rate * d1 * d2);
> > +		if (divisor < 1)
> > +			divisor = 1;
> > +		else if (divisor > BRDV_BAUD_MAX)
> > +			divisor = BRDV_BAUD_MAX;
> > +		val = (val & ~BRDV_BAUD_MASK) | divisor;
> > +	}
> 
> I don't see any range checks in the patch which verifies the requested
> baud rate is actually possible. With code like this, it seems like the
> baud rate change will be successful, but the actual baud rate will not
> be what is requested.

This code is in function which changes parent UART clock from one used
by bootloader to clock which will be used by kernel UART driver.

Yes, it is possible if you configure something unusual in bootloader
that that this code breaks it. But I think there is not so much what we
can done here.

In other patches is updated function mvebu_uart_set_termios() which
verifies that you can set particular baudrate.

> > +	/* Recalculate UART2 divisor so UART2 baudrate does not change */
> > +	if (prev_clock_rate) {
> > +		val = readl(uart_clock_base->reg2);
> > +		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
> > +						parent_clock_rate * prev_d1d2,
> > +						prev_clock_rate * d1 * d2);
> > +		if (divisor < 1)
> > +			divisor = 1;
> > +		else if (divisor > BRDV_BAUD_MAX)
> > +			divisor = BRDV_BAUD_MAX;
> > +		val = (val & ~BRDV_BAUD_MASK) | divisor;
> > +		writel(val, uart_clock_base->reg2);
> 
> Here it looks like UART1 could request a baud rate change, which ends
> up setting the clocks so that UART2 is out of range? Could the change
> for UART1 be successful, but you end up breaking UART2? I'm thinking
> when you are at opposite ends of the scale. UART2 is running at
> 110baud and UART1 at 230400baud.

This code is also in function which just do one time change of UART
parent clock. Once clk driver is probed this parent clock (and its d1
and d2 divisors) are not changed anymore. Parent clock and divisors are
chosen in way that kernel can always configure minimal baudrate 9600 on
both UARTs.

You are right that some combinations are not possible. But with these
patches it is fixed what is supported at clk driver probe time.

In v3 patch 5/5 is described how to calculate final baudrate from parent
clock and divisors d1, d2, d, m1, m2, m3, m4. Note that parent clock and
divisors d1 and d2 are shared for both UARTs. Other parameters (d, m1,
m2, m3, m4) can be set differently both UART1 and UART2. Changing shared
values is not possible during usage of UART.

If you have any idea how to improve current implementation, please let
me know.

Also note that all A3720 boards have disabled UART2 in DTS. And I'm not
sure if there is somebody who uses UART2 or who uses both UARTs.

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-06-25 15:38       ` Pali Rohár
  2021-06-25 15:50         ` Willy Tarreau
@ 2021-07-19 12:45         ` Andy Shevchenko
  1 sibling, 0 replies; 67+ messages in thread
From: Andy Shevchenko @ 2021-07-19 12:45 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Geert Uytterhoeven, Michael Turquette, Stephen Boyd, Rob Herring,
	Greg Kroah-Hartman, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Vladimir Vid, Marek Behún, linux-clk,
	open list:SERIAL DRIVERS, Linux Kernel Mailing List, Linux ARM

On Fri, Jun 25, 2021 at 6:39 PM Pali Rohár <pali@kernel.org> wrote:
> On Friday 25 June 2021 17:22:31 Geert Uytterhoeven wrote:
> > On Fri, Jun 25, 2021 at 4:37 PM Pali Rohár <pali@kernel.org> wrote:

...

> > > +/*
> > > + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer

> > > + * @dividend: unsigned 64bit dividend

(1)

> > > + * @divisor: unsigned 32bit divisor
> > > + *
> > > + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> > > + * and round to closest integer.
> > > + *
> > > + * Return: dividend / divisor rounded to nearest integer
> > > + */
> > > +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \
> > > +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
> >
> > Given "dividend" should already be an unsigned 64-bit value, I don't
> > think the cast to "u64" is needed. Similar macros in this file also
> > don't have the cast.
>
> It is just to ensure that plus operation between dividend and _tmp is
> evaluated in 64-bit context to prevent overflow. Just a case when user
> calls this macro with 32-bit dividend param.

This contradicts (1).

> As it is a macro (and not
> inline function) type is not automatically enforced.
>
> DIV_S64_ROUND_CLOSEST macro assigns its argument into temporary 64-bit
> variable which then ensures usage of 64-bit arithmetic operations. Same
> applies for DIV64_U64_ROUND_CLOSEST and DIV64_U64_ROUND_UP macros.
>
> So this is reason why I added explicit cast to u64.

I don't see the reason for casting in the current code. Probably you
need to rephrase documentation to explain why it's there.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v3 1/5] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-07-17 12:38   ` [PATCH v3 1/5] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
@ 2021-07-19 12:47     ` Andy Shevchenko
  2021-07-22 21:57       ` Pali Rohár
  0 siblings, 1 reply; 67+ messages in thread
From: Andy Shevchenko @ 2021-07-19 12:47 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel

On Sat, Jul 17, 2021 at 3:39 PM Pali Rohár <pali@kernel.org> wrote:
>
> Provide DIV_U64_ROUND_CLOSEST helper which uses div_u64 to perform
> division rounded to the closest integer using unsigned 64bit
> dividend and unsigned 32bit divisor.

...

> +/*
> + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer

> + * @dividend: unsigned 64bit dividend

Here you insist users to provide a u64 (or compatible) type.

> + * @divisor: unsigned 32bit divisor
> + *
> + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> + * and round to closest integer.
> + *
> + * Return: dividend / divisor rounded to nearest integer
> + */
> +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \

> +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })

Here is the casting to u64. Why? (Yes, I have read v1 discussion and I
just want to continue it here).

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v3 1/5] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-07-19 12:47     ` Andy Shevchenko
@ 2021-07-22 21:57       ` Pali Rohár
  2021-07-24 11:38         ` David Laight
  0 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-07-22 21:57 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel, Willy Tarreau

On Monday 19 July 2021 15:47:07 Andy Shevchenko wrote:
> On Sat, Jul 17, 2021 at 3:39 PM Pali Rohár <pali@kernel.org> wrote:
> >
> > Provide DIV_U64_ROUND_CLOSEST helper which uses div_u64 to perform
> > division rounded to the closest integer using unsigned 64bit
> > dividend and unsigned 32bit divisor.
> 
> ...
> 
> > +/*
> > + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
> 
> > + * @dividend: unsigned 64bit dividend
> 
> Here you insist users to provide a u64 (or compatible) type.
> 
> > + * @divisor: unsigned 32bit divisor
> > + *
> > + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> > + * and round to closest integer.
> > + *
> > + * Return: dividend / divisor rounded to nearest integer
> > + */
> > +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \
> 
> > +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
> 
> Here is the casting to u64. Why? (Yes, I have read v1 discussion and I
> just want to continue it here).

See also Willy's response: https://lore.kernel.org/lkml/20210625155008.GB16901@1wt.eu/

Macro does not enforce type as opposite to function.

There is no compile time check for correct type and neither compile time
warning if smaller typed value is passed.

And e.g. passing constant with explicit ULL suffix or casting external
constant to 64bit type is impractical.

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-07-17 18:05       ` Pali Rohár
@ 2021-07-24  9:48         ` Pali Rohár
  2021-07-24 16:33           ` Andrew Lunn
  0 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-07-24  9:48 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, Geert Uytterhoeven, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

On Saturday 17 July 2021 20:05:40 Pali Rohár wrote:
> On Saturday 17 July 2021 19:26:51 Andrew Lunn wrote:
> > On Sat, Jul 17, 2021 at 02:38:26PM +0200, Pali Rohár wrote:
> > > @@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
> > >  static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
> > >  {
> > >  	unsigned int d_divisor, m_divisor;
> > > +	unsigned long flags;
> > >  	u32 brdv, osamp;
> > >  
> > >  	if (!port->uartclk)
> > > @@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
> > >  	m_divisor = OSAMP_DEFAULT_DIVISOR;
> > >  	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
> > >  
> > > +	spin_lock_irqsave(&mvebu_uart_lock, flags);
> > 
> > Hi Pali
> > 
> > You only need spin_lock_irqsave() if you plan on taking the spinlock
> > in an interrupt handler. It seems unlikely the baud rate will be
> > changed in interrupt context? Please check, and then swap to plain
> > spin_lock().
> 
> Hello! Ok, I will check it.

Well, driver is already using spin_lock_irqsave() in all other
functions.

And in linux/clk-provider.h is documented that drivers can call
clk_enable() from an interrupt, so it means that spin_lock_irqsave() is
really needed for mvebu_uart_lock.

> > >  	brdv = readl(port->membase + UART_BRDV);
> > >  	brdv &= ~BRDV_BAUD_MASK;
> > >  	brdv |= d_divisor;
> > >  	writel(brdv, port->membase + UART_BRDV);
> > > +	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
> > >  
> > >  	osamp = readl(port->membase + UART_OSAMP);
> > >  	osamp &= ~OSAMP_DIVISORS_MASK;
> > 
> > > +	/* Recalculate UART1 divisor so UART1 baudrate does not change */
> > > +	if (prev_clock_rate) {
> > > +		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
> > > +						parent_clock_rate * prev_d1d2,
> > > +						prev_clock_rate * d1 * d2);
> > > +		if (divisor < 1)
> > > +			divisor = 1;
> > > +		else if (divisor > BRDV_BAUD_MAX)
> > > +			divisor = BRDV_BAUD_MAX;
> > > +		val = (val & ~BRDV_BAUD_MASK) | divisor;
> > > +	}
> > 
> > I don't see any range checks in the patch which verifies the requested
> > baud rate is actually possible. With code like this, it seems like the
> > baud rate change will be successful, but the actual baud rate will not
> > be what is requested.
> 
> This code is in function which changes parent UART clock from one used
> by bootloader to clock which will be used by kernel UART driver.
> 
> Yes, it is possible if you configure something unusual in bootloader
> that that this code breaks it. But I think there is not so much what we
> can done here.
> 
> In other patches is updated function mvebu_uart_set_termios() which
> verifies that you can set particular baudrate.
> 
> > > +	/* Recalculate UART2 divisor so UART2 baudrate does not change */
> > > +	if (prev_clock_rate) {
> > > +		val = readl(uart_clock_base->reg2);
> > > +		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
> > > +						parent_clock_rate * prev_d1d2,
> > > +						prev_clock_rate * d1 * d2);
> > > +		if (divisor < 1)
> > > +			divisor = 1;
> > > +		else if (divisor > BRDV_BAUD_MAX)
> > > +			divisor = BRDV_BAUD_MAX;
> > > +		val = (val & ~BRDV_BAUD_MASK) | divisor;
> > > +		writel(val, uart_clock_base->reg2);
> > 
> > Here it looks like UART1 could request a baud rate change, which ends
> > up setting the clocks so that UART2 is out of range? Could the change
> > for UART1 be successful, but you end up breaking UART2? I'm thinking
> > when you are at opposite ends of the scale. UART2 is running at
> > 110baud and UART1 at 230400baud.
> 
> This code is also in function which just do one time change of UART
> parent clock. Once clk driver is probed this parent clock (and its d1
> and d2 divisors) are not changed anymore. Parent clock and divisors are
> chosen in way that kernel can always configure minimal baudrate 9600 on
> both UARTs.
> 
> You are right that some combinations are not possible. But with these
> patches it is fixed what is supported at clk driver probe time.
> 
> In v3 patch 5/5 is described how to calculate final baudrate from parent
> clock and divisors d1, d2, d, m1, m2, m3, m4. Note that parent clock and
> divisors d1 and d2 are shared for both UARTs. Other parameters (d, m1,
> m2, m3, m4) can be set differently both UART1 and UART2. Changing shared
> values is not possible during usage of UART.
> 
> If you have any idea how to improve current implementation, please let
> me know.
> 
> Also note that all A3720 boards have disabled UART2 in DTS. And I'm not
> sure if there is somebody who uses UART2 or who uses both UARTs.

^ permalink raw reply	[flat|nested] 67+ messages in thread

* RE: [PATCH v3 1/5] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-07-22 21:57       ` Pali Rohár
@ 2021-07-24 11:38         ` David Laight
  0 siblings, 0 replies; 67+ messages in thread
From: David Laight @ 2021-07-24 11:38 UTC (permalink / raw)
  To: 'Pali Rohár', Andy Shevchenko
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, Geert Uytterhoeven, linux-clk,
	linux-serial, linux-kernel, linux-arm-kernel, Willy Tarreau

From: Pali Rohár
> Sent: 22 July 2021 22:58
> 
> On Monday 19 July 2021 15:47:07 Andy Shevchenko wrote:
> > On Sat, Jul 17, 2021 at 3:39 PM Pali Rohár <pali@kernel.org> wrote:
> > >
> > > Provide DIV_U64_ROUND_CLOSEST helper which uses div_u64 to perform
> > > division rounded to the closest integer using unsigned 64bit
> > > dividend and unsigned 32bit divisor.
> >
> > ...
> >
> > > +/*
> > > + * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
> >
> > > + * @dividend: unsigned 64bit dividend
> >
> > Here you insist users to provide a u64 (or compatible) type.
> >
> > > + * @divisor: unsigned 32bit divisor
> > > + *
> > > + * Divide unsigned 64bit dividend by unsigned 32bit divisor
> > > + * and round to closest integer.
> > > + *
> > > + * Return: dividend / divisor rounded to nearest integer
> > > + */
> > > +#define DIV_U64_ROUND_CLOSEST(dividend, divisor)       \
> >
> > > +       ({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
> >
> > Here is the casting to u64. Why? (Yes, I have read v1 discussion and I
> > just want to continue it here).
> 
> See also Willy's response: https://lore.kernel.org/lkml/20210625155008.GB16901@1wt.eu/
> 
> Macro does not enforce type as opposite to function.
> 
> There is no compile time check for correct type and neither compile time
> warning if smaller typed value is passed.
> 
> And e.g. passing constant with explicit ULL suffix or casting external
> constant to 64bit type is impractical.

What is wrong with:
	({ u32 _tmp = (divisor); div_u64((dividend) + (u64)0 + _tmp / 2, _tmp); })
Or:
	({ u32 _tmp = (divisor); div_u64((dividend) + (u64)(_tmp / 2), _tmp); })
Both will ensure a 32bit 'dividend' is promoted to 64 bits before the '+'.
Both will fail if 'dividend' isn't an integer type.
On 32bit systems the compiler will also know when the high bits van be ignored.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-07-24  9:48         ` Pali Rohár
@ 2021-07-24 16:33           ` Andrew Lunn
  2021-07-25 12:14             ` Pali Rohár
  0 siblings, 1 reply; 67+ messages in thread
From: Andrew Lunn @ 2021-07-24 16:33 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, Geert Uytterhoeven, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

On Sat, Jul 24, 2021 at 11:48:16AM +0200, Pali Rohár wrote:
> On Saturday 17 July 2021 20:05:40 Pali Rohár wrote:
> > On Saturday 17 July 2021 19:26:51 Andrew Lunn wrote:
> > > On Sat, Jul 17, 2021 at 02:38:26PM +0200, Pali Rohár wrote:
> > > > @@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
> > > >  static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
> > > >  {
> > > >  	unsigned int d_divisor, m_divisor;
> > > > +	unsigned long flags;
> > > >  	u32 brdv, osamp;
> > > >  
> > > >  	if (!port->uartclk)
> > > > @@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
> > > >  	m_divisor = OSAMP_DEFAULT_DIVISOR;
> > > >  	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
> > > >  
> > > > +	spin_lock_irqsave(&mvebu_uart_lock, flags);
> > > 
> > > Hi Pali
> > > 
> > > You only need spin_lock_irqsave() if you plan on taking the spinlock
> > > in an interrupt handler. It seems unlikely the baud rate will be
> > > changed in interrupt context? Please check, and then swap to plain
> > > spin_lock().
> > 
> > Hello! Ok, I will check it.
> 
> Well, driver is already using spin_lock_irqsave() in all other
> functions.

And some of those functions are called from interrupt context i
expect. For each lock you have, you need to decide if interrupt
context is an issue or not. spin_lock_irqsave() is more expansive,
since it has to disable interrupts, etc. It can upset real time
latency etc. So in the hot path, you want to try to avoid it, unless
you actually need it. But changing the baud rate is not the hot path,
it hardly every happens, so we can live with the unneeded overhead.

> And in linux/clk-provider.h is documented that drivers can call
> clk_enable() from an interrupt, so it means that spin_lock_irqsave() is
> really needed for mvebu_uart_lock.

Sure, drivers can. But in this case, does a driver actually do that?
Does it change the baud rate in interrupt context?

> > In other patches is updated function mvebu_uart_set_termios() which
> > verifies that you can set particular baudrate.

Great. It is not clear from the patches or the commit message that
this has been considered. It is something worth mentioning, just to
avoid questions.

> > Also note that all A3720 boards have disabled UART2 in DTS. And I'm not
> > sure if there is somebody who uses UART2 or who uses both UARTs.

That does not really matter. You should not regression a feature
because you think nobody is using it.

	Andrew

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-07-24 16:33           ` Andrew Lunn
@ 2021-07-25 12:14             ` Pali Rohár
  0 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-07-25 12:14 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, Geert Uytterhoeven, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

On Saturday 24 July 2021 18:33:33 Andrew Lunn wrote:
> On Sat, Jul 24, 2021 at 11:48:16AM +0200, Pali Rohár wrote:
> > On Saturday 17 July 2021 20:05:40 Pali Rohár wrote:
> > > On Saturday 17 July 2021 19:26:51 Andrew Lunn wrote:
> > > > On Sat, Jul 17, 2021 at 02:38:26PM +0200, Pali Rohár wrote:
> > > > > @@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
> > > > >  static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
> > > > >  {
> > > > >  	unsigned int d_divisor, m_divisor;
> > > > > +	unsigned long flags;
> > > > >  	u32 brdv, osamp;
> > > > >  
> > > > >  	if (!port->uartclk)
> > > > > @@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
> > > > >  	m_divisor = OSAMP_DEFAULT_DIVISOR;
> > > > >  	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
> > > > >  
> > > > > +	spin_lock_irqsave(&mvebu_uart_lock, flags);
> > > > 
> > > > Hi Pali
> > > > 
> > > > You only need spin_lock_irqsave() if you plan on taking the spinlock
> > > > in an interrupt handler. It seems unlikely the baud rate will be
> > > > changed in interrupt context? Please check, and then swap to plain
> > > > spin_lock().
> > > 
> > > Hello! Ok, I will check it.
> > 
> > Well, driver is already using spin_lock_irqsave() in all other
> > functions.
> 
> And some of those functions are called from interrupt context i
> expect. For each lock you have, you need to decide if interrupt
> context is an issue or not. spin_lock_irqsave() is more expansive,
> since it has to disable interrupts, etc. It can upset real time
> latency etc. So in the hot path, you want to try to avoid it, unless
> you actually need it. But changing the baud rate is not the hot path,
> it hardly every happens, so we can live with the unneeded overhead.

It happens either one time during "device" probing (e.g. when connected
bluetooth UART device want to use higher baudrate) or when user
explicitly ask to change baudrate (e.g. when want to transfer files over
UART via x/y/z-modem / kermit protocol). Or maybe if somebody wants to
establish and use PPP network over UART. So it should not be a problem.

> > And in linux/clk-provider.h is documented that drivers can call
> > clk_enable() from an interrupt, so it means that spin_lock_irqsave() is
> > really needed for mvebu_uart_lock.
> 
> Sure, drivers can. But in this case, does a driver actually do that?
> Does it change the baud rate in interrupt context?

Looks like that changing baudrate not. But other places where this lock
is used (e.g. in clk callbacks) can be called from interrupt context.

But for baudrate change, I think it is not so common action, so there
should not be issue with slightly higher overhead.

> > > In other patches is updated function mvebu_uart_set_termios() which
> > > verifies that you can set particular baudrate.
> 
> Great. It is not clear from the patches or the commit message that
> this has been considered. It is something worth mentioning, just to
> avoid questions.

This check was there also prior my patches. I only "extended" it to
match what is supported by this patch series.

> > > Also note that all A3720 boards have disabled UART2 in DTS. And I'm not
> > > sure if there is somebody who uses UART2 or who uses both UARTs.
> 
> That does not really matter. You should not regression a feature
> because you think nobody is using it.

I know. That is why I introduced code which recalculates divisors
registers to not change baudrate of UART2 during loading of UART1 and
also introduction of this clk subdriver with locks to prevent any
regressions.

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (11 preceding siblings ...)
  2021-07-17 12:38 ` [PATCH v3 0/5] serial: mvebu-uart: Support for higher baudrates Pali Rohár
@ 2021-08-02 14:45 ` Pali Rohár
  2021-08-02 14:45   ` [PATCH v4 1/6] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
                     ` (5 more replies)
  2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  13 siblings, 6 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-02 14:45 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This patch series add support for baudrates higher than 230400 on
Marvell Armada 37xx boards.

Please review these patches as they touch both Device Tree bindings and
mvebu-uart.c driver.

Changes in v4:
* converted armada3700-uart-clock documentation to YAML
* split documentation changes into two commits:
  - first which adds clock documentation
  - second which updates UART documentation

Changes in v3:
v3 is rebased on top of Linus master branch and all already applied patches
were dropped. There are no changes in patches itself since v2.

Pali Rohár (6):
  math64: New DIV_U64_ROUND_CLOSEST helper
  serial: mvebu-uart: implement UART clock driver for configuring UART
    base clock
  dt-bindings: mvebu-uart: document DT bindings for
    marvell,armada-3700-uart-clock
  dt-bindings: mvebu-uart: update information about UART clock
  arm64: dts: marvell: armada-37xx: add device node for UART clock and
    use it
  serial: mvebu-uart: implement support for baudrates higher than 230400

 .../bindings/clock/armada3700-uart-clock.yaml |  49 ++
 .../devicetree/bindings/serial/mvebu-uart.txt |   9 +-
 .../arm64/boot/dts/marvell/armada-3720-db.dts |   4 +
 .../dts/marvell/armada-3720-espressobin.dtsi  |   4 +
 .../dts/marvell/armada-3720-turris-mox.dts    |   4 +
 .../boot/dts/marvell/armada-3720-uDPU.dts     |   4 +
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi  |  15 +-
 drivers/tty/serial/Kconfig                    |   1 +
 drivers/tty/serial/mvebu-uart.c               | 592 +++++++++++++++++-
 include/linux/math64.h                        |  13 +
 10 files changed, 674 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml

-- 
2.20.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH v4 1/6] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-08-02 14:45 ` [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
@ 2021-08-02 14:45   ` Pali Rohár
  2021-08-02 14:45   ` [PATCH v4 2/6] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-02 14:45 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

Provide DIV_U64_ROUND_CLOSEST helper which uses div_u64 to perform
division rounded to the closest integer using unsigned 64bit
dividend and unsigned 32bit divisor.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 include/linux/math64.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/linux/math64.h b/include/linux/math64.h
index 66deb1fdc2ef..1cc61d748e1f 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -281,6 +281,19 @@ u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
 #define DIV64_U64_ROUND_CLOSEST(dividend, divisor)	\
 	({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); })
 
+/*
+ * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 32bit divisor
+ *
+ * Divide unsigned 64bit dividend by unsigned 32bit divisor
+ * and round to closest integer.
+ *
+ * Return: dividend / divisor rounded to nearest integer
+ */
+#define DIV_U64_ROUND_CLOSEST(dividend, divisor)	\
+	({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
+
 /*
  * DIV_S64_ROUND_CLOSEST - signed 64bit divide with 32bit divisor rounded to nearest integer
  * @dividend: signed 64bit dividend
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v4 2/6] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-08-02 14:45 ` [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  2021-08-02 14:45   ` [PATCH v4 1/6] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
@ 2021-08-02 14:45   ` Pali Rohár
  2021-08-02 14:45   ` [PATCH v4 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-02 14:45 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This patch implements a new device driver for controlling UART clocks on
Marvell Armada 3700 SoC. This device driver is loaded for devices which
match compatible string "marvell,armada-3700-uart-clock".

There are more pitfalls related to UART clocks. Both UARTs use same base
clock source. Also divisors for TBG base clock are shared between both
UARTs and are configured only from UART1 address space. Clocks can be
enabled / disabled separately for UART1 and UART2, but they are controlled
only from UART1 address space. Moreover Marvell Armada 3700 Functional
Specifications has swapped bits for enabling/disabling UART1 and UART2
clocks.

So driver for controlling UART2 needs to have access to UART1 address space
as UART1 address space contains some bits exclusively used by UART2 and
also bits which are shared for both UART1 and UART2.

For changing UART base clock (which controls both UARTs) during boot when
UART driver is not ready and only early console is active, is not simple
operation as it is required to also recalculate divisors to not change UART
baudrate used by early console. So for this operation UART1 clock driver
needs to access also into address space of UART2 where are registers for
UART2 divisors.

For these reasons, this new device driver for UART clocks does not use
ioremap_resource(), but only ioremap() to prevent resource conflicts
between UART clock driver and UART driver.

Shared between drivers are only two 4-bytes registers: UART Clock Control
and UART 2 Baud Rate Divisor. Access to these two registers are protected
by one spinlock to prevent any conflicts. Access is required only during
probe time, changing baudrate and during suspend/resume.

Hardware can be configured to use one of following clocks as UART base
clock: TBG-A-P, TBG-B-P, TBG-A-S, TBG-B-S, xtal. Not every clock is usable
for higher buadrates. In DT node can be specified any subset and kernel
choose the best one, which still supports required baudrate 9600. For
smooth boot log output it is needed to specify clock used by early console
otherwise garbage would be put on UART during probing for UART clock driver
and transitioning from early console to normal console.

This change is required to enable and configure TBG clock as a base clock
for UART. TBG clock is required to achieve higher baudrates than 230400.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 drivers/tty/serial/Kconfig      |   1 +
 drivers/tty/serial/mvebu-uart.c | 519 +++++++++++++++++++++++++++++++-
 2 files changed, 518 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 0c4cd4a348f4..b3726797a0f5 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1441,6 +1441,7 @@ config SERIAL_STM32_CONSOLE
 config SERIAL_MVEBU_UART
 	bool "Marvell EBU serial port support"
 	depends on ARCH_MVEBU || COMPILE_TEST
+	depends on COMMON_CLK
 	select SERIAL_CORE
 	help
 	  This driver is for Marvell EBU SoC's UART. If you have a machine
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index 414e92064ac6..a31235add99f 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -8,12 +8,14 @@
 */
 
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/math64.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
@@ -68,8 +70,31 @@
 #define  STAT_BRK_ERR		(STAT_BRK_DET | STAT_FRM_ERR \
 				 | STAT_PAR_ERR | STAT_OVR_ERR)
 
+/*
+ * Marvell Armada 3700 Functional Specifications describes that bit 21 of UART
+ * Clock Control register controls UART1 and bit 20 controls UART2. But in
+ * reality bit 21 controls UART2 and bit 20 controls UART1. This seems to be a
+ * bug in Marvell documentation. Hence following CLK_DIS macros are swapped.
+ */
+
 #define UART_BRDV		0x10
+/* These bits are located in UART1 address space and control UART2 */
+#define  UART2_CLK_DIS		BIT(21)
+/* These bits are located in UART1 address space and control UART1 */
+#define  UART1_CLK_DIS		BIT(20)
+/* These bits are located in UART1 address space and control both UARTs */
+#define  CLK_NO_XTAL		BIT(19)
+#define  CLK_TBG_DIV1_SHIFT	15
+#define  CLK_TBG_DIV1_MASK	0x7
+#define  CLK_TBG_DIV1_MAX	6
+#define  CLK_TBG_DIV2_SHIFT	12
+#define  CLK_TBG_DIV2_MASK	0x7
+#define  CLK_TBG_DIV2_MAX	6
+#define  CLK_TBG_SEL_SHIFT	10
+#define  CLK_TBG_SEL_MASK	0x3
+/* These bits are located in both UARTs address space */
 #define  BRDV_BAUD_MASK         0x3FF
+#define  BRDV_BAUD_MAX		BRDV_BAUD_MASK
 
 #define UART_OSAMP		0x14
 #define  OSAMP_DEFAULT_DIVISOR	16
@@ -153,6 +178,8 @@ static struct mvebu_uart *to_mvuart(struct uart_port *port)
 
 static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
 
+static DEFINE_SPINLOCK(mvebu_uart_lock);
+
 /* Core UART Driver Operations */
 static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
 {
@@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
 static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
 	unsigned int d_divisor, m_divisor;
+	unsigned long flags;
 	u32 brdv, osamp;
 
 	if (!port->uartclk)
@@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 	m_divisor = OSAMP_DEFAULT_DIVISOR;
 	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
 
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	brdv = readl(port->membase + UART_BRDV);
 	brdv &= ~BRDV_BAUD_MASK;
 	brdv |= d_divisor;
 	writel(brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 
 	osamp = readl(port->membase + UART_OSAMP);
 	osamp &= ~OSAMP_DIVISORS_MASK;
@@ -762,6 +792,7 @@ static int mvebu_uart_suspend(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	uart_suspend_port(&mvebu_uart_driver, port);
 
@@ -770,7 +801,9 @@ static int mvebu_uart_suspend(struct device *dev)
 	mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port));
 	mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port));
 	mvuart->pm_regs.stat = readl(port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP);
 
 	device_set_wakeup_enable(dev, true);
@@ -782,13 +815,16 @@ static int mvebu_uart_resume(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port));
 	writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port));
 	writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port));
 	writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port));
 	writel(mvuart->pm_regs.stat, port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP);
 
 	uart_resume_port(&mvebu_uart_driver, port);
@@ -975,6 +1011,476 @@ static struct platform_driver mvebu_uart_platform_driver = {
 	},
 };
 
+/* This code is based on clk-fixed-factor.c driver and modified. */
+
+struct mvebu_uart_clock {
+	struct clk_hw clk_hw;
+	int clock_idx;
+	u32 pm_context_reg1;
+	u32 pm_context_reg2;
+};
+
+struct mvebu_uart_clock_base {
+	struct mvebu_uart_clock clocks[2];
+	unsigned int parent_rates[5];
+	int parent_idx;
+	unsigned int div;
+	void __iomem *reg1;
+	void __iomem *reg2;
+	bool configured;
+};
+
+#define PARENT_CLOCK_XTAL 4
+
+#define to_uart_clock(hw) container_of(hw, struct mvebu_uart_clock, clk_hw)
+#define to_uart_clock_base(uart_clock) container_of(uart_clock, \
+	struct mvebu_uart_clock_base, clocks[uart_clock->clock_idx])
+
+static int mvebu_uart_clock_prepare(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned int prev_clock_idx, prev_clock_rate, prev_d1d2;
+	unsigned int parent_clock_idx, parent_clock_rate;
+	unsigned long flags;
+	unsigned int d1, d2;
+	u64 divisor;
+	u32 val;
+
+	/*
+	 * This function just reconfigures UART Clock Control register (located
+	 * in UART1 address space which controls both UART1 and UART2) to
+	 * selected UART base clock and recalculate current UART1/UART2 divisors
+	 * in their address spaces, so final baudrate will not be changed by
+	 * switching UART base clock. This is required otherwise kernel boot log
+	 * stops working. It is needed to ensure that UART baudrate does not
+	 * change during this setup. It is one time operation, so based on
+	 * "configured" member this function is skipped on second call. Because
+	 * this UART Clock Control register (UART_BRDV) is shared between UART1
+	 * baudrate function, UART1 clock selector and UART2 clock selector,
+	 * every access to UART_BRDV (reg1) needs to be protected by lock.
+	 */
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	if (uart_clock_base->configured) {
+		spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+		return 0;
+	}
+
+	parent_clock_idx = uart_clock_base->parent_idx;
+	parent_clock_rate = uart_clock_base->parent_rates[parent_clock_idx];
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock_base->div > CLK_TBG_DIV1_MAX) {
+		d1 = CLK_TBG_DIV1_MAX;
+		d2 = uart_clock_base->div / CLK_TBG_DIV1_MAX;
+	} else {
+		d1 = uart_clock_base->div;
+		d2 = 1;
+	}
+
+	if (val & CLK_NO_XTAL) {
+		prev_clock_idx = (val >> CLK_TBG_SEL_SHIFT) & CLK_TBG_SEL_MASK;
+		prev_d1d2 = ((val >> CLK_TBG_DIV1_SHIFT) & CLK_TBG_DIV1_MASK)
+			  * ((val >> CLK_TBG_DIV2_SHIFT) & CLK_TBG_DIV2_MASK);
+	} else {
+		prev_clock_idx = PARENT_CLOCK_XTAL;
+		prev_d1d2 = 1;
+	}
+
+	/* Note that uart_clock_base->parent_rates[i] may not be available */
+	prev_clock_rate = uart_clock_base->parent_rates[prev_clock_idx];
+
+	/* Recalculate UART1 divisor so UART1 baudrate does not change */
+	if (prev_clock_rate) {
+		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+						parent_clock_rate * prev_d1d2,
+						prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+	}
+
+	if (parent_clock_idx != PARENT_CLOCK_XTAL) {
+		/* Do not use XTAL, select TBG clock and TBG d1 * d2 divisors */
+		val |= CLK_NO_XTAL;
+		val &= ~(CLK_TBG_DIV1_MASK << CLK_TBG_DIV1_SHIFT);
+		val |= d1 << CLK_TBG_DIV1_SHIFT;
+		val &= ~(CLK_TBG_DIV2_MASK << CLK_TBG_DIV2_SHIFT);
+		val |= d2 << CLK_TBG_DIV2_SHIFT;
+		val &= ~(CLK_TBG_SEL_MASK << CLK_TBG_SEL_SHIFT);
+		val |= parent_clock_idx << CLK_TBG_SEL_SHIFT;
+	} else {
+		/* Use XTAL, TBG bits are then ignored */
+		val &= ~CLK_NO_XTAL;
+	}
+
+	writel(val, uart_clock_base->reg1);
+
+	/* Recalculate UART2 divisor so UART2 baudrate does not change */
+	if (prev_clock_rate) {
+		val = readl(uart_clock_base->reg2);
+		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+						parent_clock_rate * prev_d1d2,
+						prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+		writel(val, uart_clock_base->reg2);
+	}
+
+	uart_clock_base->configured = true;
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static int mvebu_uart_clock_enable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val &= ~UART1_CLK_DIS;
+	else
+		val &= ~UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_disable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val |= UART1_CLK_DIS;
+	else
+		val |= UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static int mvebu_uart_clock_is_enabled(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	u32 val;
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		return !(val & UART1_CLK_DIS);
+	else
+		return !(val & UART2_CLK_DIS);
+}
+
+static int mvebu_uart_clock_save_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	uart_clock->pm_context_reg1 = readl(uart_clock_base->reg1);
+	uart_clock->pm_context_reg2 = readl(uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_restore_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	writel(uart_clock->pm_context_reg1, uart_clock_base->reg1);
+	writel(uart_clock->pm_context_reg2, uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return parent_rate / uart_clock_base->div;
+}
+
+static long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long *parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return *parent_rate / uart_clock_base->div;
+}
+
+static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	/*
+	 * We must report success but we can do so unconditionally because
+	 * mvebu_uart_clock_round_rate returns values that ensure this call is a
+	 * nop.
+	 */
+
+	return 0;
+}
+
+static const struct clk_ops mvebu_uart_clock_ops = {
+	.prepare = mvebu_uart_clock_prepare,
+	.enable = mvebu_uart_clock_enable,
+	.disable = mvebu_uart_clock_disable,
+	.is_enabled = mvebu_uart_clock_is_enabled,
+	.save_context = mvebu_uart_clock_save_context,
+	.restore_context = mvebu_uart_clock_restore_context,
+	.round_rate = mvebu_uart_clock_round_rate,
+	.set_rate = mvebu_uart_clock_set_rate,
+	.recalc_rate = mvebu_uart_clock_recalc_rate,
+};
+
+static int mvebu_uart_clock_register(struct device *dev,
+				     struct mvebu_uart_clock *uart_clock,
+				     const char *name,
+				     const char *parent_name)
+{
+	struct clk_init_data init = { };
+
+	uart_clock->clk_hw.init = &init;
+
+	init.name = name;
+	init.ops = &mvebu_uart_clock_ops;
+	init.flags = 0;
+	init.num_parents = 1;
+	init.parent_names = &parent_name;
+
+	return devm_clk_hw_register(dev, &uart_clock->clk_hw);
+}
+
+static int mvebu_uart_clock_probe(struct platform_device *pdev)
+{
+	static const char *const uart_clk_names[] = { "uart_1", "uart_2" };
+	static const char *const parent_clk_names[] = { "TBG-A-P", "TBG-B-P",
+							"TBG-A-S", "TBG-B-S",
+							"xtal" };
+	struct clk *parent_clks[ARRAY_SIZE(parent_clk_names)];
+	struct mvebu_uart_clock_base *uart_clock_base;
+	struct clk_hw_onecell_data *hw_clk_data;
+	struct device *dev = &pdev->dev;
+	int i, parent_clk_idx, ret;
+	unsigned long div, rate;
+	struct resource *res;
+	unsigned int d1, d2;
+
+	BUILD_BUG_ON(ARRAY_SIZE(uart_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->clocks));
+	BUILD_BUG_ON(ARRAY_SIZE(parent_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->parent_rates));
+
+	uart_clock_base = devm_kzalloc(dev,
+				       sizeof(*uart_clock_base),
+				       GFP_KERNEL);
+	if (!uart_clock_base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "Couldn't get first register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART Clock Control register (reg1 / UART_BRDV) is in address range
+	 * of UART1 (standard UART variant), controls clock source and dividers
+	 * for both UART1 and UART2 and is supplied via DT as first resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART1 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg1 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg1))
+		return PTR_ERR(uart_clock_base->reg1);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "Couldn't get second register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART 2 Baud Rate Divisor register (reg2 / UART_BRDV) is in address
+	 * range of UART2 (extended UART variant), controls only one UART2
+	 * specific divider and is supplied via DT as second resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART2 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg2 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg2))
+		return PTR_ERR(uart_clock_base->reg2);
+
+	hw_clk_data = devm_kzalloc(dev,
+				   struct_size(hw_clk_data, hws,
+					       ARRAY_SIZE(uart_clk_names)),
+				   GFP_KERNEL);
+	if (!hw_clk_data)
+		return -ENOMEM;
+
+	hw_clk_data->num = ARRAY_SIZE(uart_clk_names);
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		hw_clk_data->hws[i] = &uart_clock_base->clocks[i].clk_hw;
+		uart_clock_base->clocks[i].clock_idx = i;
+	}
+
+	parent_clk_idx = -1;
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		parent_clks[i] = devm_clk_get(dev, parent_clk_names[i]);
+		if (IS_ERR(parent_clks[i])) {
+			if (PTR_ERR(parent_clks[i]) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			dev_warn(dev, "Couldn't get the parent clock %s: %ld\n",
+				parent_clk_names[i], PTR_ERR(parent_clks[i]));
+			continue;
+		}
+
+		ret = clk_prepare_enable(parent_clks[i]);
+		if (ret) {
+			dev_warn(dev, "Couldn't enable parent clock %s: %d\n",
+				parent_clk_names[i], ret);
+			continue;
+		}
+		rate = clk_get_rate(parent_clks[i]);
+		uart_clock_base->parent_rates[i] = rate;
+
+		if (i != PARENT_CLOCK_XTAL) {
+			/*
+			 * Calculate the smallest TBG d1 and d2 divisors that
+			 * still can provide 9600 baudrate.
+			 */
+			d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_DEFAULT_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 *
+						BRDV_BAUD_MAX * d1);
+			if (d2 < 1)
+				d2 = 1;
+			else if (d2 > CLK_TBG_DIV2_MAX)
+				d2 = CLK_TBG_DIV2_MAX;
+		} else {
+			/*
+			 * When UART clock uses XTAL clock as a source then it
+			 * is not possible to use d1 and d2 divisors.
+			 */
+			d1 = d2 = 1;
+		}
+
+		/* Skip clock source which cannot provide 9600 baudrate */
+		if (rate > 9600 * OSAMP_DEFAULT_DIVISOR * BRDV_BAUD_MAX * d1 * d2)
+			continue;
+
+		/*
+		 * Choose TBG clock source with the smallest divisors. Use XTAL
+		 * clock source only in case TBG is not available as XTAL cannot
+		 * be used for baudrates higher than 230400.
+		 */
+		if (parent_clk_idx == -1 ||
+		    (i != PARENT_CLOCK_XTAL && div > d1 * d2)) {
+			parent_clk_idx = i;
+			div = d1 * d2;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		if (i == parent_clk_idx || IS_ERR(parent_clks[i]))
+			continue;
+		clk_disable_unprepare(parent_clks[i]);
+		devm_clk_put(dev, parent_clks[i]);
+	}
+
+	if (parent_clk_idx == -1) {
+		dev_err(dev, "No usable parent clock\n");
+		return -ENOENT;
+	}
+
+	uart_clock_base->parent_idx = parent_clk_idx;
+	uart_clock_base->div = div;
+
+	dev_notice(dev, "Using parent clock %s as base UART clock\n",
+		   __clk_get_name(parent_clks[parent_clk_idx]));
+
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		ret = mvebu_uart_clock_register(dev,
+				&uart_clock_base->clocks[i],
+				uart_clk_names[i],
+				__clk_get_name(parent_clks[parent_clk_idx]));
+		if (ret) {
+			dev_err(dev, "Can't register UART clock %d: %d\n",
+				i, ret);
+			return ret;
+		}
+	}
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+					   hw_clk_data);
+}
+
+static const struct of_device_id mvebu_uart_clock_of_match[] = {
+	{ .compatible = "marvell,armada-3700-uart-clock", },
+	{ }
+};
+
+static struct platform_driver mvebu_uart_clock_platform_driver = {
+	.probe = mvebu_uart_clock_probe,
+	.driver		= {
+		.name	= "mvebu-uart-clock",
+		.of_match_table = mvebu_uart_clock_of_match,
+	},
+};
+
 static int __init mvebu_uart_init(void)
 {
 	int ret;
@@ -983,10 +1489,19 @@ static int __init mvebu_uart_init(void)
 	if (ret)
 		return ret;
 
+	ret = platform_driver_register(&mvebu_uart_clock_platform_driver);
+	if (ret) {
+		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
+
 	ret = platform_driver_register(&mvebu_uart_platform_driver);
-	if (ret)
+	if (ret) {
+		platform_driver_unregister(&mvebu_uart_clock_platform_driver);
 		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
 
-	return ret;
+	return 0;
 }
 arch_initcall(mvebu_uart_init);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v4 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock
  2021-08-02 14:45 ` [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  2021-08-02 14:45   ` [PATCH v4 1/6] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
  2021-08-02 14:45   ` [PATCH v4 2/6] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
@ 2021-08-02 14:45   ` Pali Rohár
  2021-08-06  0:30     ` Stephen Boyd
  2021-08-02 14:45   ` [PATCH v4 4/6] dt-bindings: mvebu-uart: update information about UART clock Pali Rohár
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-08-02 14:45 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This change adds DT bindings documentation for device nodes with compatible
string "marvell,armada-3700-uart-clock".

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 .../bindings/clock/armada3700-uart-clock.yaml | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml

diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
new file mode 100644
index 000000000000..5ef04f3affda
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/marvell,armada-3700-uart-clock#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Marvell Armada 3720 UART clocks
+properties:
+  compatible:
+    const: marvell,armada-3700-uart-clock
+  reg:
+    items:
+      - description: UART Clock Control Register
+      - description: UART 2 Baud Rate Divisor Register
+  clocks:
+    description: |
+      List of parent clocks suitable for UART from following set:
+        "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
+      UART clock can use one from this set and when more are provided
+      then kernel would choose and configure the most suitable one.
+      It is suggest to specify at least one TBG clock to achieve
+      baudrates above 230400 and also to specify clock which bootloader
+      used for UART (most probably xtal) for smooth boot log on UART.
+  clock-names:
+    items:
+      - const: TBG-A-P
+      - const: TBG-B-P
+      - const: TBG-A-S
+      - const: TBG-B-S
+      - const: xtal
+    minItems: 1
+    maxItems: 5
+  '#clock-cells':
+    const: 1
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#clock-cells'
+additionalProperties: false
+examples:
+  - |
+    uartclk: uartclk@12000 {
+      compatible = "marvell,armada-3700-uart-clock";
+      reg = <0x12010 0x4>, <0x12210 0x4>;
+      clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, <&tbg 3>, <&xtalclk>;
+      clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal";
+      #clock-cells = <1>;
+    };
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v4 4/6] dt-bindings: mvebu-uart: update information about UART clock
  2021-08-02 14:45 ` [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                     ` (2 preceding siblings ...)
  2021-08-02 14:45   ` [PATCH v4 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
@ 2021-08-02 14:45   ` Pali Rohár
  2021-08-02 14:45   ` [PATCH v4 5/6] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
  2021-08-02 14:45   ` [PATCH v4 6/6] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
  5 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-02 14:45 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

Device "marvell,armada-3700-uart" should use
"marvell,armada-3700-uart-clock" compatible clock.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 Documentation/devicetree/bindings/serial/mvebu-uart.txt | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
index 2d0dbdf32d1d..a062bbca532c 100644
--- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
@@ -14,7 +14,10 @@ Required properties:
       is provided (possible only with the "marvell,armada-3700-uart"
       compatible string for backward compatibility), it will only work
       if the baudrate was initialized by the bootloader and no baudrate
-      change will then be possible.
+      change will then be possible. When provided it should be UART1-clk
+      for standard variant of UART and UART2-clk for extended variant
+      of UART. TBG clock (with UART TBG divisors d1=d2=1) or xtal clock
+      should not be used and are supported only for backward compatibility.
 - interrupts:
     - Must contain three elements for the standard variant of the IP
       (marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx",
@@ -34,7 +37,7 @@ Example:
 	uart0: serial@12000 {
 		compatible = "marvell,armada-3700-uart";
 		reg = <0x12000 0x18>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 0>;
 		interrupts =
 		<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 		<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -45,7 +48,7 @@ Example:
 	uart1: serial@12200 {
 		compatible = "marvell,armada-3700-uart-ext";
 		reg = <0x12200 0x30>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 1>;
 		interrupts =
 		<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 		<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v4 5/6] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it
  2021-08-02 14:45 ` [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                     ` (3 preceding siblings ...)
  2021-08-02 14:45   ` [PATCH v4 4/6] dt-bindings: mvebu-uart: update information about UART clock Pali Rohár
@ 2021-08-02 14:45   ` Pali Rohár
  2021-08-02 14:45   ` [PATCH v4 6/6] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
  5 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-02 14:45 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This change defines DT node for UART clock "marvell,armada-3700-uart-clock"
and use this UART clock as a base clock for all UART devices.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 arch/arm64/boot/dts/marvell/armada-3720-db.dts    |  4 ++++
 .../boot/dts/marvell/armada-3720-espressobin.dtsi |  4 ++++
 .../boot/dts/marvell/armada-3720-turris-mox.dts   |  4 ++++
 arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts  |  4 ++++
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi      | 15 +++++++++++++--
 5 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 3e5789f37206..accf014a6a1e 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -191,6 +191,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /*
  * Exported on the micro USB connector CON30(V2.0)/CON32(V1.4) through
  * an FTDI (also on CON24(V2.0)/CON26(V1.4)).
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
index 5fc613d24151..d03c7cdfbfb3 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
@@ -117,6 +117,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /* Exported on the micro USB connector J5 through an FTDI */
 &uart0 {
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
index cacf2a05fb22..972c6d400f8b 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
@@ -167,6 +167,10 @@
 	status = "disabled";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
index 95d46e8d081c..c8217440b8dd 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
@@ -183,6 +183,10 @@
 	phy-names = "usb2-utmi-otg-phy";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 20dd9d9e9d58..d9bdd374cf45 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -132,10 +132,21 @@
 				reg = <0x11500 0x40>;
 			};
 
+			uartclk: uartclk@12000 {
+				compatible = "marvell,armada-3700-uart-clock";
+				reg = <0x12010 0x4>, <0x12210 0x4>;
+				clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
+					<&tbg 3>, <&xtalclk>;
+				clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S",
+					"TBG-B-S", "xtal";
+				#clock-cells = <1>;
+				status = "disabled";
+			};
+
 			uart0: serial@12000 {
 				compatible = "marvell,armada-3700-uart";
 				reg = <0x12000 0x18>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 0>;
 				interrupts =
 				<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -147,7 +158,7 @@
 			uart1: serial@12200 {
 				compatible = "marvell,armada-3700-uart-ext";
 				reg = <0x12200 0x30>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 1>;
 				interrupts =
 				<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 				<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v4 6/6] serial: mvebu-uart: implement support for baudrates higher than 230400
  2021-08-02 14:45 ` [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                     ` (4 preceding siblings ...)
  2021-08-02 14:45   ` [PATCH v4 5/6] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
@ 2021-08-02 14:45   ` Pali Rohár
  5 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-02 14:45 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

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 <pali@kernel.org>
---
 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


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell, armada-3700-uart-clock
  2021-07-17 17:30     ` [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell, armada-3700-uart-clock Andrew Lunn
@ 2021-08-02 14:45       ` Pali Rohár
  0 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-02 14:45 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, Geert Uytterhoeven, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

On Saturday 17 July 2021 19:30:19 Andrew Lunn wrote:
> On Sat, Jul 17, 2021 at 02:38:27PM +0200, Pali Rohár wrote:
> > This change adds DT bindings documentation for device nodes with compatible
> > string "marvell,armada-3700-uart-clock".
> > 
> > Signed-off-by: Pali Rohár <pali@kernel.org>
> > ---
> >  .../bindings/clock/armada3700-uart-clock.txt  | 24 +++++++++++++++++++
> >  .../devicetree/bindings/serial/mvebu-uart.txt |  9 ++++---
> >  2 files changed, 30 insertions(+), 3 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
> > new file mode 100644
> > index 000000000000..144bc6d7eae8
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.txt
> 
> Since this is a new binding, please use YAML.

Changed in v4.

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v4 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock
  2021-08-02 14:45   ` [PATCH v4 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
@ 2021-08-06  0:30     ` Stephen Boyd
  2021-08-06  8:28       ` Pali Rohár
  0 siblings, 1 reply; 67+ messages in thread
From: Stephen Boyd @ 2021-08-06  0:30 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Michael Turquette, pali, Rob Herring
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, kabel, linux-clk, linux-serial, linux-kernel,
	linux-arm-kernel

> diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> new file mode 100644
> index 000000000000..5ef04f3affda
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> @@ -0,0 +1,49 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/marvell,armada-3700-uart-clock#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +title: Marvell Armada 3720 UART clocks

Please add a newline here

> +properties:
> +  compatible:
> +    const: marvell,armada-3700-uart-clock

Please add a newline here

> +  reg:
> +    items:
> +      - description: UART Clock Control Register
> +      - description: UART 2 Baud Rate Divisor Register

Please add a newline here

> +  clocks:
> +    description: |
> +      List of parent clocks suitable for UART from following set:
> +        "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
> +      UART clock can use one from this set and when more are provided
> +      then kernel would choose and configure the most suitable one.
> +      It is suggest to specify at least one TBG clock to achieve
> +      baudrates above 230400 and also to specify clock which bootloader
> +      used for UART (most probably xtal) for smooth boot log on UART.

Please use items and const like clock-names for the clocks property. The
description makes me feel like the DT is configuring the choices
available. Ideally, the clocks and clock-names properties are fixed in
length and never change unless the compatible changes.

Please add a newline here

> +  clock-names:
> +    items:
> +      - const: TBG-A-P
> +      - const: TBG-B-P
> +      - const: TBG-A-S
> +      - const: TBG-B-S
> +      - const: xtal
> +    minItems: 1
> +    maxItems: 5

Please add a newline here

> +  '#clock-cells':
> +    const: 1

Please add a newline here

> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +  - '#clock-cells'

Please add a newline here

> +additionalProperties: false

Please add a newline here

> +examples:
> +  - |
> +    uartclk: uartclk@12000 {
> +      compatible = "marvell,armada-3700-uart-clock";
> +      reg = <0x12010 0x4>, <0x12210 0x4>;
> +      clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, <&tbg 3>, <&xtalclk>;
> +      clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal";
> +      #clock-cells = <1>;
> +    };

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v4 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock
  2021-08-06  0:30     ` Stephen Boyd
@ 2021-08-06  8:28       ` Pali Rohár
  2021-08-12 19:33         ` Stephen Boyd
  0 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-08-06  8:28 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Greg Kroah-Hartman, Michael Turquette, Rob Herring, Andrew Lunn,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid, kabel,
	linux-clk, linux-serial, linux-kernel, linux-arm-kernel

On Thursday 05 August 2021 17:30:19 Stephen Boyd wrote:
> > diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> > new file mode 100644
> > index 000000000000..5ef04f3affda
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> > @@ -0,0 +1,49 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/clock/marvell,armada-3700-uart-clock#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +title: Marvell Armada 3720 UART clocks
> 
> Please add a newline here
> 
> > +properties:
> > +  compatible:
> > +    const: marvell,armada-3700-uart-clock
> 
> Please add a newline here
> 
> > +  reg:
> > +    items:
> > +      - description: UART Clock Control Register
> > +      - description: UART 2 Baud Rate Divisor Register
> 
> Please add a newline here
> 
> > +  clocks:
> > +    description: |
> > +      List of parent clocks suitable for UART from following set:
> > +        "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
> > +      UART clock can use one from this set and when more are provided
> > +      then kernel would choose and configure the most suitable one.
> > +      It is suggest to specify at least one TBG clock to achieve
> > +      baudrates above 230400 and also to specify clock which bootloader
> > +      used for UART (most probably xtal) for smooth boot log on UART.
> 
> Please use items and const like clock-names for the clocks property.

It is already there, see below.

> The description makes me feel like the DT is configuring the choices
> available.

See description. It is kernel (driver) who is choosing one clock from
the set and then configure it a UART clock.

> Ideally, the clocks and clock-names properties are fixed in
> length and never change unless the compatible changes.
> 
> Please add a newline here
> 
> > +  clock-names:
> > +    items:
> > +      - const: TBG-A-P
> > +      - const: TBG-B-P
> > +      - const: TBG-A-S
> > +      - const: TBG-B-S
> > +      - const: xtal
> > +    minItems: 1
> > +    maxItems: 5
> 
> Please add a newline here
> 
> > +  '#clock-cells':
> > +    const: 1
> 
> Please add a newline here
> 
> > +required:
> > +  - compatible
> > +  - reg
> > +  - clocks
> > +  - clock-names
> > +  - '#clock-cells'
> 
> Please add a newline here
> 
> > +additionalProperties: false
> 
> Please add a newline here
> 
> > +examples:
> > +  - |
> > +    uartclk: uartclk@12000 {
> > +      compatible = "marvell,armada-3700-uart-clock";
> > +      reg = <0x12010 0x4>, <0x12210 0x4>;
> > +      clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, <&tbg 3>, <&xtalclk>;
> > +      clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal";
> > +      #clock-cells = <1>;
> > +    };

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates
  2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
                   ` (12 preceding siblings ...)
  2021-08-02 14:45 ` [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
@ 2021-08-09 14:53 ` Pali Rohár
  2021-08-09 14:53   ` [PATCH v5 1/6] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
                     ` (6 more replies)
  13 siblings, 7 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-09 14:53 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This patch series add support for baudrates higher than 230400 on
Marvell Armada 37xx boards.

Please review these patches as they touch both Device Tree bindings and
mvebu-uart.c driver.

Changes in v5:
* fixed yaml binding file

Changes in v4:
* converted armada3700-uart-clock documentation to YAML
* split documentation changes into two commits:
  - first which adds clock documentation
  - second which updates UART documentation

Changes in v3:
v3 is rebased on top of Linus master branch and all already applied patches
were dropped. There are no changes in patches itself since v2.

Pali Rohár (6):
  math64: New DIV_U64_ROUND_CLOSEST helper
  serial: mvebu-uart: implement UART clock driver for configuring UART
    base clock
  dt-bindings: mvebu-uart: document DT bindings for
    marvell,armada-3700-uart-clock
  dt-bindings: mvebu-uart: update information about UART clock
  arm64: dts: marvell: armada-37xx: add device node for UART clock and
    use it
  serial: mvebu-uart: implement support for baudrates higher than 230400

 .../bindings/clock/armada3700-uart-clock.yaml |  57 ++
 .../devicetree/bindings/serial/mvebu-uart.txt |   9 +-
 .../arm64/boot/dts/marvell/armada-3720-db.dts |   4 +
 .../dts/marvell/armada-3720-espressobin.dtsi  |   4 +
 .../dts/marvell/armada-3720-turris-mox.dts    |   4 +
 .../boot/dts/marvell/armada-3720-uDPU.dts     |   4 +
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi  |  15 +-
 drivers/tty/serial/Kconfig                    |   1 +
 drivers/tty/serial/mvebu-uart.c               | 592 +++++++++++++++++-
 include/linux/math64.h                        |  13 +
 10 files changed, 682 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml

-- 
2.20.1


^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH v5 1/6] math64: New DIV_U64_ROUND_CLOSEST helper
  2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
@ 2021-08-09 14:53   ` Pali Rohár
  2021-08-09 14:53   ` [PATCH v5 2/6] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-09 14:53 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

Provide DIV_U64_ROUND_CLOSEST helper which uses div_u64 to perform
division rounded to the closest integer using unsigned 64bit
dividend and unsigned 32bit divisor.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 include/linux/math64.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/linux/math64.h b/include/linux/math64.h
index 66deb1fdc2ef..1cc61d748e1f 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -281,6 +281,19 @@ u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
 #define DIV64_U64_ROUND_CLOSEST(dividend, divisor)	\
 	({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); })
 
+/*
+ * DIV_U64_ROUND_CLOSEST - unsigned 64bit divide with 32bit divisor rounded to nearest integer
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 32bit divisor
+ *
+ * Divide unsigned 64bit dividend by unsigned 32bit divisor
+ * and round to closest integer.
+ *
+ * Return: dividend / divisor rounded to nearest integer
+ */
+#define DIV_U64_ROUND_CLOSEST(dividend, divisor)	\
+	({ u32 _tmp = (divisor); div_u64((u64)(dividend) + _tmp / 2, _tmp); })
+
 /*
  * DIV_S64_ROUND_CLOSEST - signed 64bit divide with 32bit divisor rounded to nearest integer
  * @dividend: signed 64bit dividend
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v5 2/6] serial: mvebu-uart: implement UART clock driver for configuring UART base clock
  2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  2021-08-09 14:53   ` [PATCH v5 1/6] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
@ 2021-08-09 14:53   ` Pali Rohár
  2021-08-09 14:53   ` [PATCH v5 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-09 14:53 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This patch implements a new device driver for controlling UART clocks on
Marvell Armada 3700 SoC. This device driver is loaded for devices which
match compatible string "marvell,armada-3700-uart-clock".

There are more pitfalls related to UART clocks. Both UARTs use same base
clock source. Also divisors for TBG base clock are shared between both
UARTs and are configured only from UART1 address space. Clocks can be
enabled / disabled separately for UART1 and UART2, but they are controlled
only from UART1 address space. Moreover Marvell Armada 3700 Functional
Specifications has swapped bits for enabling/disabling UART1 and UART2
clocks.

So driver for controlling UART2 needs to have access to UART1 address space
as UART1 address space contains some bits exclusively used by UART2 and
also bits which are shared for both UART1 and UART2.

For changing UART base clock (which controls both UARTs) during boot when
UART driver is not ready and only early console is active, is not simple
operation as it is required to also recalculate divisors to not change UART
baudrate used by early console. So for this operation UART1 clock driver
needs to access also into address space of UART2 where are registers for
UART2 divisors.

For these reasons, this new device driver for UART clocks does not use
ioremap_resource(), but only ioremap() to prevent resource conflicts
between UART clock driver and UART driver.

Shared between drivers are only two 4-bytes registers: UART Clock Control
and UART 2 Baud Rate Divisor. Access to these two registers are protected
by one spinlock to prevent any conflicts. Access is required only during
probe time, changing baudrate and during suspend/resume.

Hardware can be configured to use one of following clocks as UART base
clock: TBG-A-P, TBG-B-P, TBG-A-S, TBG-B-S, xtal. Not every clock is usable
for higher buadrates. In DT node can be specified any subset and kernel
choose the best one, which still supports required baudrate 9600. For
smooth boot log output it is needed to specify clock used by early console
otherwise garbage would be put on UART during probing for UART clock driver
and transitioning from early console to normal console.

This change is required to enable and configure TBG clock as a base clock
for UART. TBG clock is required to achieve higher baudrates than 230400.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 drivers/tty/serial/Kconfig      |   1 +
 drivers/tty/serial/mvebu-uart.c | 519 +++++++++++++++++++++++++++++++-
 2 files changed, 518 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 0c4cd4a348f4..b3726797a0f5 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1441,6 +1441,7 @@ config SERIAL_STM32_CONSOLE
 config SERIAL_MVEBU_UART
 	bool "Marvell EBU serial port support"
 	depends on ARCH_MVEBU || COMPILE_TEST
+	depends on COMMON_CLK
 	select SERIAL_CORE
 	help
 	  This driver is for Marvell EBU SoC's UART. If you have a machine
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index 414e92064ac6..a31235add99f 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -8,12 +8,14 @@
 */
 
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/math64.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
@@ -68,8 +70,31 @@
 #define  STAT_BRK_ERR		(STAT_BRK_DET | STAT_FRM_ERR \
 				 | STAT_PAR_ERR | STAT_OVR_ERR)
 
+/*
+ * Marvell Armada 3700 Functional Specifications describes that bit 21 of UART
+ * Clock Control register controls UART1 and bit 20 controls UART2. But in
+ * reality bit 21 controls UART2 and bit 20 controls UART1. This seems to be a
+ * bug in Marvell documentation. Hence following CLK_DIS macros are swapped.
+ */
+
 #define UART_BRDV		0x10
+/* These bits are located in UART1 address space and control UART2 */
+#define  UART2_CLK_DIS		BIT(21)
+/* These bits are located in UART1 address space and control UART1 */
+#define  UART1_CLK_DIS		BIT(20)
+/* These bits are located in UART1 address space and control both UARTs */
+#define  CLK_NO_XTAL		BIT(19)
+#define  CLK_TBG_DIV1_SHIFT	15
+#define  CLK_TBG_DIV1_MASK	0x7
+#define  CLK_TBG_DIV1_MAX	6
+#define  CLK_TBG_DIV2_SHIFT	12
+#define  CLK_TBG_DIV2_MASK	0x7
+#define  CLK_TBG_DIV2_MAX	6
+#define  CLK_TBG_SEL_SHIFT	10
+#define  CLK_TBG_SEL_MASK	0x3
+/* These bits are located in both UARTs address space */
 #define  BRDV_BAUD_MASK         0x3FF
+#define  BRDV_BAUD_MAX		BRDV_BAUD_MASK
 
 #define UART_OSAMP		0x14
 #define  OSAMP_DEFAULT_DIVISOR	16
@@ -153,6 +178,8 @@ static struct mvebu_uart *to_mvuart(struct uart_port *port)
 
 static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
 
+static DEFINE_SPINLOCK(mvebu_uart_lock);
+
 /* Core UART Driver Operations */
 static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
 {
@@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port)
 static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
 	unsigned int d_divisor, m_divisor;
+	unsigned long flags;
 	u32 brdv, osamp;
 
 	if (!port->uartclk)
@@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 	m_divisor = OSAMP_DEFAULT_DIVISOR;
 	d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
 
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	brdv = readl(port->membase + UART_BRDV);
 	brdv &= ~BRDV_BAUD_MASK;
 	brdv |= d_divisor;
 	writel(brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 
 	osamp = readl(port->membase + UART_OSAMP);
 	osamp &= ~OSAMP_DIVISORS_MASK;
@@ -762,6 +792,7 @@ static int mvebu_uart_suspend(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	uart_suspend_port(&mvebu_uart_driver, port);
 
@@ -770,7 +801,9 @@ static int mvebu_uart_suspend(struct device *dev)
 	mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port));
 	mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port));
 	mvuart->pm_regs.stat = readl(port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP);
 
 	device_set_wakeup_enable(dev, true);
@@ -782,13 +815,16 @@ static int mvebu_uart_resume(struct device *dev)
 {
 	struct mvebu_uart *mvuart = dev_get_drvdata(dev);
 	struct uart_port *port = mvuart->port;
+	unsigned long flags;
 
 	writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port));
 	writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port));
 	writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port));
 	writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port));
 	writel(mvuart->pm_regs.stat, port->membase + UART_STAT);
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
 	writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP);
 
 	uart_resume_port(&mvebu_uart_driver, port);
@@ -975,6 +1011,476 @@ static struct platform_driver mvebu_uart_platform_driver = {
 	},
 };
 
+/* This code is based on clk-fixed-factor.c driver and modified. */
+
+struct mvebu_uart_clock {
+	struct clk_hw clk_hw;
+	int clock_idx;
+	u32 pm_context_reg1;
+	u32 pm_context_reg2;
+};
+
+struct mvebu_uart_clock_base {
+	struct mvebu_uart_clock clocks[2];
+	unsigned int parent_rates[5];
+	int parent_idx;
+	unsigned int div;
+	void __iomem *reg1;
+	void __iomem *reg2;
+	bool configured;
+};
+
+#define PARENT_CLOCK_XTAL 4
+
+#define to_uart_clock(hw) container_of(hw, struct mvebu_uart_clock, clk_hw)
+#define to_uart_clock_base(uart_clock) container_of(uart_clock, \
+	struct mvebu_uart_clock_base, clocks[uart_clock->clock_idx])
+
+static int mvebu_uart_clock_prepare(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned int prev_clock_idx, prev_clock_rate, prev_d1d2;
+	unsigned int parent_clock_idx, parent_clock_rate;
+	unsigned long flags;
+	unsigned int d1, d2;
+	u64 divisor;
+	u32 val;
+
+	/*
+	 * This function just reconfigures UART Clock Control register (located
+	 * in UART1 address space which controls both UART1 and UART2) to
+	 * selected UART base clock and recalculate current UART1/UART2 divisors
+	 * in their address spaces, so final baudrate will not be changed by
+	 * switching UART base clock. This is required otherwise kernel boot log
+	 * stops working. It is needed to ensure that UART baudrate does not
+	 * change during this setup. It is one time operation, so based on
+	 * "configured" member this function is skipped on second call. Because
+	 * this UART Clock Control register (UART_BRDV) is shared between UART1
+	 * baudrate function, UART1 clock selector and UART2 clock selector,
+	 * every access to UART_BRDV (reg1) needs to be protected by lock.
+	 */
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	if (uart_clock_base->configured) {
+		spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+		return 0;
+	}
+
+	parent_clock_idx = uart_clock_base->parent_idx;
+	parent_clock_rate = uart_clock_base->parent_rates[parent_clock_idx];
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock_base->div > CLK_TBG_DIV1_MAX) {
+		d1 = CLK_TBG_DIV1_MAX;
+		d2 = uart_clock_base->div / CLK_TBG_DIV1_MAX;
+	} else {
+		d1 = uart_clock_base->div;
+		d2 = 1;
+	}
+
+	if (val & CLK_NO_XTAL) {
+		prev_clock_idx = (val >> CLK_TBG_SEL_SHIFT) & CLK_TBG_SEL_MASK;
+		prev_d1d2 = ((val >> CLK_TBG_DIV1_SHIFT) & CLK_TBG_DIV1_MASK)
+			  * ((val >> CLK_TBG_DIV2_SHIFT) & CLK_TBG_DIV2_MASK);
+	} else {
+		prev_clock_idx = PARENT_CLOCK_XTAL;
+		prev_d1d2 = 1;
+	}
+
+	/* Note that uart_clock_base->parent_rates[i] may not be available */
+	prev_clock_rate = uart_clock_base->parent_rates[prev_clock_idx];
+
+	/* Recalculate UART1 divisor so UART1 baudrate does not change */
+	if (prev_clock_rate) {
+		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+						parent_clock_rate * prev_d1d2,
+						prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+	}
+
+	if (parent_clock_idx != PARENT_CLOCK_XTAL) {
+		/* Do not use XTAL, select TBG clock and TBG d1 * d2 divisors */
+		val |= CLK_NO_XTAL;
+		val &= ~(CLK_TBG_DIV1_MASK << CLK_TBG_DIV1_SHIFT);
+		val |= d1 << CLK_TBG_DIV1_SHIFT;
+		val &= ~(CLK_TBG_DIV2_MASK << CLK_TBG_DIV2_SHIFT);
+		val |= d2 << CLK_TBG_DIV2_SHIFT;
+		val &= ~(CLK_TBG_SEL_MASK << CLK_TBG_SEL_SHIFT);
+		val |= parent_clock_idx << CLK_TBG_SEL_SHIFT;
+	} else {
+		/* Use XTAL, TBG bits are then ignored */
+		val &= ~CLK_NO_XTAL;
+	}
+
+	writel(val, uart_clock_base->reg1);
+
+	/* Recalculate UART2 divisor so UART2 baudrate does not change */
+	if (prev_clock_rate) {
+		val = readl(uart_clock_base->reg2);
+		divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
+						parent_clock_rate * prev_d1d2,
+						prev_clock_rate * d1 * d2);
+		if (divisor < 1)
+			divisor = 1;
+		else if (divisor > BRDV_BAUD_MAX)
+			divisor = BRDV_BAUD_MAX;
+		val = (val & ~BRDV_BAUD_MASK) | divisor;
+		writel(val, uart_clock_base->reg2);
+	}
+
+	uart_clock_base->configured = true;
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static int mvebu_uart_clock_enable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val &= ~UART1_CLK_DIS;
+	else
+		val &= ~UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_disable(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		val |= UART1_CLK_DIS;
+	else
+		val |= UART2_CLK_DIS;
+
+	writel(val, uart_clock_base->reg1);
+
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static int mvebu_uart_clock_is_enabled(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	u32 val;
+
+	val = readl(uart_clock_base->reg1);
+
+	if (uart_clock->clock_idx == 0)
+		return !(val & UART1_CLK_DIS);
+	else
+		return !(val & UART2_CLK_DIS);
+}
+
+static int mvebu_uart_clock_save_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	uart_clock->pm_context_reg1 = readl(uart_clock_base->reg1);
+	uart_clock->pm_context_reg2 = readl(uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+
+	return 0;
+}
+
+static void mvebu_uart_clock_restore_context(struct clk_hw *hw)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mvebu_uart_lock, flags);
+	writel(uart_clock->pm_context_reg1, uart_clock_base->reg1);
+	writel(uart_clock->pm_context_reg2, uart_clock_base->reg2);
+	spin_unlock_irqrestore(&mvebu_uart_lock, flags);
+}
+
+static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return parent_rate / uart_clock_base->div;
+}
+
+static long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long *parent_rate)
+{
+	struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
+	struct mvebu_uart_clock_base *uart_clock_base =
+						to_uart_clock_base(uart_clock);
+
+	return *parent_rate / uart_clock_base->div;
+}
+
+static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	/*
+	 * We must report success but we can do so unconditionally because
+	 * mvebu_uart_clock_round_rate returns values that ensure this call is a
+	 * nop.
+	 */
+
+	return 0;
+}
+
+static const struct clk_ops mvebu_uart_clock_ops = {
+	.prepare = mvebu_uart_clock_prepare,
+	.enable = mvebu_uart_clock_enable,
+	.disable = mvebu_uart_clock_disable,
+	.is_enabled = mvebu_uart_clock_is_enabled,
+	.save_context = mvebu_uart_clock_save_context,
+	.restore_context = mvebu_uart_clock_restore_context,
+	.round_rate = mvebu_uart_clock_round_rate,
+	.set_rate = mvebu_uart_clock_set_rate,
+	.recalc_rate = mvebu_uart_clock_recalc_rate,
+};
+
+static int mvebu_uart_clock_register(struct device *dev,
+				     struct mvebu_uart_clock *uart_clock,
+				     const char *name,
+				     const char *parent_name)
+{
+	struct clk_init_data init = { };
+
+	uart_clock->clk_hw.init = &init;
+
+	init.name = name;
+	init.ops = &mvebu_uart_clock_ops;
+	init.flags = 0;
+	init.num_parents = 1;
+	init.parent_names = &parent_name;
+
+	return devm_clk_hw_register(dev, &uart_clock->clk_hw);
+}
+
+static int mvebu_uart_clock_probe(struct platform_device *pdev)
+{
+	static const char *const uart_clk_names[] = { "uart_1", "uart_2" };
+	static const char *const parent_clk_names[] = { "TBG-A-P", "TBG-B-P",
+							"TBG-A-S", "TBG-B-S",
+							"xtal" };
+	struct clk *parent_clks[ARRAY_SIZE(parent_clk_names)];
+	struct mvebu_uart_clock_base *uart_clock_base;
+	struct clk_hw_onecell_data *hw_clk_data;
+	struct device *dev = &pdev->dev;
+	int i, parent_clk_idx, ret;
+	unsigned long div, rate;
+	struct resource *res;
+	unsigned int d1, d2;
+
+	BUILD_BUG_ON(ARRAY_SIZE(uart_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->clocks));
+	BUILD_BUG_ON(ARRAY_SIZE(parent_clk_names) !=
+		     ARRAY_SIZE(uart_clock_base->parent_rates));
+
+	uart_clock_base = devm_kzalloc(dev,
+				       sizeof(*uart_clock_base),
+				       GFP_KERNEL);
+	if (!uart_clock_base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "Couldn't get first register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART Clock Control register (reg1 / UART_BRDV) is in address range
+	 * of UART1 (standard UART variant), controls clock source and dividers
+	 * for both UART1 and UART2 and is supplied via DT as first resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART1 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg1 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg1))
+		return PTR_ERR(uart_clock_base->reg1);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "Couldn't get second register\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * UART 2 Baud Rate Divisor register (reg2 / UART_BRDV) is in address
+	 * range of UART2 (extended UART variant), controls only one UART2
+	 * specific divider and is supplied via DT as second resource.
+	 * Therefore use ioremap() function rather than ioremap_resource() to
+	 * avoid conflicts with UART2 driver. Access to UART_BRDV is protected
+	 * by lock shared between clock and UART driver.
+	 */
+	uart_clock_base->reg2 = devm_ioremap(dev, res->start,
+					     resource_size(res));
+	if (IS_ERR(uart_clock_base->reg2))
+		return PTR_ERR(uart_clock_base->reg2);
+
+	hw_clk_data = devm_kzalloc(dev,
+				   struct_size(hw_clk_data, hws,
+					       ARRAY_SIZE(uart_clk_names)),
+				   GFP_KERNEL);
+	if (!hw_clk_data)
+		return -ENOMEM;
+
+	hw_clk_data->num = ARRAY_SIZE(uart_clk_names);
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		hw_clk_data->hws[i] = &uart_clock_base->clocks[i].clk_hw;
+		uart_clock_base->clocks[i].clock_idx = i;
+	}
+
+	parent_clk_idx = -1;
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		parent_clks[i] = devm_clk_get(dev, parent_clk_names[i]);
+		if (IS_ERR(parent_clks[i])) {
+			if (PTR_ERR(parent_clks[i]) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			dev_warn(dev, "Couldn't get the parent clock %s: %ld\n",
+				parent_clk_names[i], PTR_ERR(parent_clks[i]));
+			continue;
+		}
+
+		ret = clk_prepare_enable(parent_clks[i]);
+		if (ret) {
+			dev_warn(dev, "Couldn't enable parent clock %s: %d\n",
+				parent_clk_names[i], ret);
+			continue;
+		}
+		rate = clk_get_rate(parent_clks[i]);
+		uart_clock_base->parent_rates[i] = rate;
+
+		if (i != PARENT_CLOCK_XTAL) {
+			/*
+			 * Calculate the smallest TBG d1 and d2 divisors that
+			 * still can provide 9600 baudrate.
+			 */
+			d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_DEFAULT_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 *
+						BRDV_BAUD_MAX * d1);
+			if (d2 < 1)
+				d2 = 1;
+			else if (d2 > CLK_TBG_DIV2_MAX)
+				d2 = CLK_TBG_DIV2_MAX;
+		} else {
+			/*
+			 * When UART clock uses XTAL clock as a source then it
+			 * is not possible to use d1 and d2 divisors.
+			 */
+			d1 = d2 = 1;
+		}
+
+		/* Skip clock source which cannot provide 9600 baudrate */
+		if (rate > 9600 * OSAMP_DEFAULT_DIVISOR * BRDV_BAUD_MAX * d1 * d2)
+			continue;
+
+		/*
+		 * Choose TBG clock source with the smallest divisors. Use XTAL
+		 * clock source only in case TBG is not available as XTAL cannot
+		 * be used for baudrates higher than 230400.
+		 */
+		if (parent_clk_idx == -1 ||
+		    (i != PARENT_CLOCK_XTAL && div > d1 * d2)) {
+			parent_clk_idx = i;
+			div = d1 * d2;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
+		if (i == parent_clk_idx || IS_ERR(parent_clks[i]))
+			continue;
+		clk_disable_unprepare(parent_clks[i]);
+		devm_clk_put(dev, parent_clks[i]);
+	}
+
+	if (parent_clk_idx == -1) {
+		dev_err(dev, "No usable parent clock\n");
+		return -ENOENT;
+	}
+
+	uart_clock_base->parent_idx = parent_clk_idx;
+	uart_clock_base->div = div;
+
+	dev_notice(dev, "Using parent clock %s as base UART clock\n",
+		   __clk_get_name(parent_clks[parent_clk_idx]));
+
+	for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
+		ret = mvebu_uart_clock_register(dev,
+				&uart_clock_base->clocks[i],
+				uart_clk_names[i],
+				__clk_get_name(parent_clks[parent_clk_idx]));
+		if (ret) {
+			dev_err(dev, "Can't register UART clock %d: %d\n",
+				i, ret);
+			return ret;
+		}
+	}
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+					   hw_clk_data);
+}
+
+static const struct of_device_id mvebu_uart_clock_of_match[] = {
+	{ .compatible = "marvell,armada-3700-uart-clock", },
+	{ }
+};
+
+static struct platform_driver mvebu_uart_clock_platform_driver = {
+	.probe = mvebu_uart_clock_probe,
+	.driver		= {
+		.name	= "mvebu-uart-clock",
+		.of_match_table = mvebu_uart_clock_of_match,
+	},
+};
+
 static int __init mvebu_uart_init(void)
 {
 	int ret;
@@ -983,10 +1489,19 @@ static int __init mvebu_uart_init(void)
 	if (ret)
 		return ret;
 
+	ret = platform_driver_register(&mvebu_uart_clock_platform_driver);
+	if (ret) {
+		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
+
 	ret = platform_driver_register(&mvebu_uart_platform_driver);
-	if (ret)
+	if (ret) {
+		platform_driver_unregister(&mvebu_uart_clock_platform_driver);
 		uart_unregister_driver(&mvebu_uart_driver);
+		return ret;
+	}
 
-	return ret;
+	return 0;
 }
 arch_initcall(mvebu_uart_init);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v5 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock
  2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  2021-08-09 14:53   ` [PATCH v5 1/6] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
  2021-08-09 14:53   ` [PATCH v5 2/6] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
@ 2021-08-09 14:53   ` Pali Rohár
  2021-08-09 14:53   ` [PATCH v5 4/6] dt-bindings: mvebu-uart: update information about UART clock Pali Rohár
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-09 14:53 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This change adds DT bindings documentation for device nodes with compatible
string "marvell,armada-3700-uart-clock".

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 .../bindings/clock/armada3700-uart-clock.yaml | 57 +++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml

diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
new file mode 100644
index 000000000000..5bdb23e0ba3e
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/marvell,armada-3700-uart-clock#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Marvell Armada 3720 UART clocks
+
+properties:
+  compatible:
+    const: marvell,armada-3700-uart-clock
+
+  reg:
+    items:
+      - description: UART Clock Control Register
+      - description: UART 2 Baud Rate Divisor Register
+
+  clocks:
+    description: |
+      List of parent clocks suitable for UART from following set:
+        "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
+      UART clock can use one from this set and when more are provided
+      then kernel would choose and configure the most suitable one.
+      It is suggest to specify at least one TBG clock to achieve
+      baudrates above 230400 and also to specify clock which bootloader
+      used for UART (most probably xtal) for smooth boot log on UART.
+
+  clock-names:
+    items:
+      - const: TBG-A-P
+      - const: TBG-B-P
+      - const: TBG-A-S
+      - const: TBG-B-S
+      - const: xtal
+    minItems: 1
+    maxItems: 5
+
+  '#clock-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    uartclk: uartclk@12000 {
+      compatible = "marvell,armada-3700-uart-clock";
+      reg = <0x12010 0x4>, <0x12210 0x4>;
+      clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, <&tbg 3>, <&xtalclk>;
+      clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal";
+      #clock-cells = <1>;
+    };
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v5 4/6] dt-bindings: mvebu-uart: update information about UART clock
  2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                     ` (2 preceding siblings ...)
  2021-08-09 14:53   ` [PATCH v5 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
@ 2021-08-09 14:53   ` Pali Rohár
  2021-08-09 14:53   ` [PATCH v5 5/6] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-09 14:53 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

Device "marvell,armada-3700-uart" should use
"marvell,armada-3700-uart-clock" compatible clock.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 Documentation/devicetree/bindings/serial/mvebu-uart.txt | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
index 2d0dbdf32d1d..a062bbca532c 100644
--- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt
@@ -14,7 +14,10 @@ Required properties:
       is provided (possible only with the "marvell,armada-3700-uart"
       compatible string for backward compatibility), it will only work
       if the baudrate was initialized by the bootloader and no baudrate
-      change will then be possible.
+      change will then be possible. When provided it should be UART1-clk
+      for standard variant of UART and UART2-clk for extended variant
+      of UART. TBG clock (with UART TBG divisors d1=d2=1) or xtal clock
+      should not be used and are supported only for backward compatibility.
 - interrupts:
     - Must contain three elements for the standard variant of the IP
       (marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx",
@@ -34,7 +37,7 @@ Example:
 	uart0: serial@12000 {
 		compatible = "marvell,armada-3700-uart";
 		reg = <0x12000 0x18>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 0>;
 		interrupts =
 		<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 		<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -45,7 +48,7 @@ Example:
 	uart1: serial@12200 {
 		compatible = "marvell,armada-3700-uart-ext";
 		reg = <0x12200 0x30>;
-		clocks = <&xtalclk>;
+		clocks = <&uartclk 1>;
 		interrupts =
 		<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 		<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v5 5/6] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it
  2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                     ` (3 preceding siblings ...)
  2021-08-09 14:53   ` [PATCH v5 4/6] dt-bindings: mvebu-uart: update information about UART clock Pali Rohár
@ 2021-08-09 14:53   ` Pali Rohár
  2021-08-09 14:53   ` [PATCH v5 6/6] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
  2021-08-20 17:22   ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  6 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-09 14:53 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

This change defines DT node for UART clock "marvell,armada-3700-uart-clock"
and use this UART clock as a base clock for all UART devices.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 arch/arm64/boot/dts/marvell/armada-3720-db.dts    |  4 ++++
 .../boot/dts/marvell/armada-3720-espressobin.dtsi |  4 ++++
 .../boot/dts/marvell/armada-3720-turris-mox.dts   |  4 ++++
 arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts  |  4 ++++
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi      | 15 +++++++++++++--
 5 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 3e5789f37206..accf014a6a1e 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -191,6 +191,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /*
  * Exported on the micro USB connector CON30(V2.0)/CON32(V1.4) through
  * an FTDI (also on CON24(V2.0)/CON26(V1.4)).
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
index 5fc613d24151..d03c7cdfbfb3 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi
@@ -117,6 +117,10 @@
 	};
 };
 
+&uartclk {
+	status = "okay";
+};
+
 /* Exported on the micro USB connector J5 through an FTDI */
 &uart0 {
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
index cacf2a05fb22..972c6d400f8b 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
@@ -167,6 +167,10 @@
 	status = "disabled";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
index 95d46e8d081c..c8217440b8dd 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
@@ -183,6 +183,10 @@
 	phy-names = "usb2-utmi-otg-phy";
 };
 
+&uartclk {
+	status = "okay";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 20dd9d9e9d58..d9bdd374cf45 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -132,10 +132,21 @@
 				reg = <0x11500 0x40>;
 			};
 
+			uartclk: uartclk@12000 {
+				compatible = "marvell,armada-3700-uart-clock";
+				reg = <0x12010 0x4>, <0x12210 0x4>;
+				clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
+					<&tbg 3>, <&xtalclk>;
+				clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S",
+					"TBG-B-S", "xtal";
+				#clock-cells = <1>;
+				status = "disabled";
+			};
+
 			uart0: serial@12000 {
 				compatible = "marvell,armada-3700-uart";
 				reg = <0x12000 0x18>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 0>;
 				interrupts =
 				<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
@@ -147,7 +158,7 @@
 			uart1: serial@12200 {
 				compatible = "marvell,armada-3700-uart-ext";
 				reg = <0x12200 0x30>;
-				clocks = <&xtalclk>;
+				clocks = <&uartclk 1>;
 				interrupts =
 				<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
 				<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v5 6/6] serial: mvebu-uart: implement support for baudrates higher than 230400
  2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                     ` (4 preceding siblings ...)
  2021-08-09 14:53   ` [PATCH v5 5/6] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
@ 2021-08-09 14:53   ` Pali Rohár
  2021-08-20 17:22   ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
  6 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-09 14:53 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Greg Kroah-Hartman
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
	Vladimir Vid, Marek Behún, linux-clk, linux-serial,
	linux-kernel, linux-arm-kernel

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 <pali@kernel.org>
---
 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


^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH v4 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock
  2021-08-06  8:28       ` Pali Rohár
@ 2021-08-12 19:33         ` Stephen Boyd
  2021-08-12 20:08           ` Pali Rohár
  0 siblings, 1 reply; 67+ messages in thread
From: Stephen Boyd @ 2021-08-12 19:33 UTC (permalink / raw)
  To: pali
  Cc: Greg Kroah-Hartman, Michael Turquette, Rob Herring, Andrew Lunn,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid, kabel,
	linux-clk, linux-serial, linux-kernel, linux-arm-kernel

Quoting Pali (2021-08-06 01:28:18)
> On Thursday 05 August 2021 17:30:19 Stephen Boyd wrote:
> > > diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> > > new file mode 100644
> > > index 000000000000..5ef04f3affda
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> > > @@ -0,0 +1,49 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/clock/marvell,armada-3700-uart-clock#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +title: Marvell Armada 3720 UART clocks
> > 
> > Please add a newline here
> > 
> > > +properties:
> > > +  compatible:
> > > +    const: marvell,armada-3700-uart-clock
> > 
> > Please add a newline here
> > 
> > > +  reg:
> > > +    items:
> > > +      - description: UART Clock Control Register
> > > +      - description: UART 2 Baud Rate Divisor Register
> > 
> > Please add a newline here
> > 
> > > +  clocks:
> > > +    description: |
> > > +      List of parent clocks suitable for UART from following set:
> > > +        "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
> > > +      UART clock can use one from this set and when more are provided
> > > +      then kernel would choose and configure the most suitable one.
> > > +      It is suggest to specify at least one TBG clock to achieve
> > > +      baudrates above 230400 and also to specify clock which bootloader
> > > +      used for UART (most probably xtal) for smooth boot log on UART.
> > 
> > Please use items and const like clock-names for the clocks property.
> 
> It is already there, see below.
> 
> > The description makes me feel like the DT is configuring the choices
> > available.
> 
> See description. It is kernel (driver) who is choosing one clock from
> the set and then configure it a UART clock.

Can that be done with assigned-clock-parents?

> 
> > Ideally, the clocks and clock-names properties are fixed in
> > length and never change unless the compatible changes.
> > 
> > Please add a newline here
> > 
> > > +  clock-names:
> > > +    items:
> > > +      - const: TBG-A-P
> > > +      - const: TBG-B-P
> > > +      - const: TBG-A-S
> > > +      - const: TBG-B-S
> > > +      - const: xtal
> > > +    minItems: 1
> > > +    maxItems: 5
> > 
> > Please add a newline here
> > 
> > > +  '#clock-cells':
> > > +    const: 1
> > 
> > Please add a newline here
> > 
> > > +required:
> > > +  - compatible
> > > +  - reg
> > > +  - clocks
> > > +  - clock-names
> > > +  - '#clock-cells'
> > 
> > Please add a newline here
> > 
> > > +additionalProperties: false
> > 
> > Please add a newline here
> > 
> > > +examples:
> > > +  - |
> > > +    uartclk: uartclk@12000 {
> > > +      compatible = "marvell,armada-3700-uart-clock";
> > > +      reg = <0x12010 0x4>, <0x12210 0x4>;

The reg property looks like this is poking a mux that is part of a
larger device. What device is this actually part of? The uart hardware?

> > > +      clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, <&tbg 3>, <&xtalclk>;
> > > +      clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal";

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v4 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock
  2021-08-12 19:33         ` Stephen Boyd
@ 2021-08-12 20:08           ` Pali Rohár
  0 siblings, 0 replies; 67+ messages in thread
From: Pali Rohár @ 2021-08-12 20:08 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Greg Kroah-Hartman, Michael Turquette, Rob Herring, Andrew Lunn,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid, kabel,
	linux-clk, linux-serial, linux-kernel, linux-arm-kernel

On Thursday 12 August 2021 12:33:19 Stephen Boyd wrote:
> Quoting Pali (2021-08-06 01:28:18)
> > On Thursday 05 August 2021 17:30:19 Stephen Boyd wrote:
> > > > diff --git a/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> > > > new file mode 100644
> > > > index 000000000000..5ef04f3affda
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> > > > @@ -0,0 +1,49 @@
> > > > +# SPDX-License-Identifier: GPL-2.0
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/clock/marvell,armada-3700-uart-clock#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +title: Marvell Armada 3720 UART clocks
> > > 
> > > Please add a newline here
> > > 
> > > > +properties:
> > > > +  compatible:
> > > > +    const: marvell,armada-3700-uart-clock
> > > 
> > > Please add a newline here
> > > 
> > > > +  reg:
> > > > +    items:
> > > > +      - description: UART Clock Control Register
> > > > +      - description: UART 2 Baud Rate Divisor Register
> > > 
> > > Please add a newline here
> > > 
> > > > +  clocks:
> > > > +    description: |
> > > > +      List of parent clocks suitable for UART from following set:
> > > > +        "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
> > > > +      UART clock can use one from this set and when more are provided
> > > > +      then kernel would choose and configure the most suitable one.
> > > > +      It is suggest to specify at least one TBG clock to achieve
> > > > +      baudrates above 230400 and also to specify clock which bootloader
> > > > +      used for UART (most probably xtal) for smooth boot log on UART.
> > > 
> > > Please use items and const like clock-names for the clocks property.
> > 
> > It is already there, see below.
> > 
> > > The description makes me feel like the DT is configuring the choices
> > > available.
> > 
> > See description. It is kernel (driver) who is choosing one clock from
> > the set and then configure it a UART clock.
> 
> Can that be done with assigned-clock-parents?

I'm not sure if it is possible. Frequencies of "TBG-A-P", "TBG-B-P",
"TBG-A-S" and "TBG-B-S" clocks are set by firmware and frequency of
"xtal" by strapping pin. So they are not static constants. And also
kernel cannot change frequency of these clocks.

Driver reads frequencies of these clocks and choose the one which is the
most suitable for UART at runtime.

> > > Ideally, the clocks and clock-names properties are fixed in
> > > length and never change unless the compatible changes.
> > > 
> > > Please add a newline here
> > > 
> > > > +  clock-names:
> > > > +    items:
> > > > +      - const: TBG-A-P
> > > > +      - const: TBG-B-P
> > > > +      - const: TBG-A-S
> > > > +      - const: TBG-B-S
> > > > +      - const: xtal
> > > > +    minItems: 1
> > > > +    maxItems: 5
> > > 
> > > Please add a newline here
> > > 
> > > > +  '#clock-cells':
> > > > +    const: 1
> > > 
> > > Please add a newline here
> > > 
> > > > +required:
> > > > +  - compatible
> > > > +  - reg
> > > > +  - clocks
> > > > +  - clock-names
> > > > +  - '#clock-cells'
> > > 
> > > Please add a newline here
> > > 
> > > > +additionalProperties: false
> > > 
> > > Please add a newline here
> > > 
> > > > +examples:
> > > > +  - |
> > > > +    uartclk: uartclk@12000 {
> > > > +      compatible = "marvell,armada-3700-uart-clock";
> > > > +      reg = <0x12010 0x4>, <0x12210 0x4>;
> 
> The reg property looks like this is poking a mux that is part of a
> larger device. What device is this actually part of? The uart hardware?

Yes, UART hardware.

> > > > +      clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, <&tbg 3>, <&xtalclk>;
> > > > +      clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal";

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates
  2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
                     ` (5 preceding siblings ...)
  2021-08-09 14:53   ` [PATCH v5 6/6] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
@ 2021-08-20 17:22   ` Pali Rohár
  2021-08-31  8:35     ` Pali Rohár
  6 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-08-20 17:22 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Michael Turquette, Rob Herring, Greg Kroah-Hartman, Andrew Lunn,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, linux-clk, linux-serial, linux-kernel,
	linux-arm-kernel

On Monday 09 August 2021 16:53:23 Pali Rohár wrote:
> This patch series add support for baudrates higher than 230400 on
> Marvell Armada 37xx boards.
> 
> Please review these patches as they touch both Device Tree bindings and
> mvebu-uart.c driver.

Stephen, is this patch series OK now? Or is there any other issue?

> Changes in v5:
> * fixed yaml binding file
> 
> Changes in v4:
> * converted armada3700-uart-clock documentation to YAML
> * split documentation changes into two commits:
>   - first which adds clock documentation
>   - second which updates UART documentation
> 
> Changes in v3:
> v3 is rebased on top of Linus master branch and all already applied patches
> were dropped. There are no changes in patches itself since v2.
> 
> Pali Rohár (6):
>   math64: New DIV_U64_ROUND_CLOSEST helper
>   serial: mvebu-uart: implement UART clock driver for configuring UART
>     base clock
>   dt-bindings: mvebu-uart: document DT bindings for
>     marvell,armada-3700-uart-clock
>   dt-bindings: mvebu-uart: update information about UART clock
>   arm64: dts: marvell: armada-37xx: add device node for UART clock and
>     use it
>   serial: mvebu-uart: implement support for baudrates higher than 230400
> 
>  .../bindings/clock/armada3700-uart-clock.yaml |  57 ++
>  .../devicetree/bindings/serial/mvebu-uart.txt |   9 +-
>  .../arm64/boot/dts/marvell/armada-3720-db.dts |   4 +
>  .../dts/marvell/armada-3720-espressobin.dtsi  |   4 +
>  .../dts/marvell/armada-3720-turris-mox.dts    |   4 +
>  .../boot/dts/marvell/armada-3720-uDPU.dts     |   4 +
>  arch/arm64/boot/dts/marvell/armada-37xx.dtsi  |  15 +-
>  drivers/tty/serial/Kconfig                    |   1 +
>  drivers/tty/serial/mvebu-uart.c               | 592 +++++++++++++++++-
>  include/linux/math64.h                        |  13 +
>  10 files changed, 682 insertions(+), 21 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> 
> -- 
> 2.20.1
> 

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates
  2021-08-20 17:22   ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
@ 2021-08-31  8:35     ` Pali Rohár
  2021-09-21  7:41       ` Greg Kroah-Hartman
  0 siblings, 1 reply; 67+ messages in thread
From: Pali Rohár @ 2021-08-31  8:35 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Michael Turquette, Rob Herring, Greg Kroah-Hartman, Andrew Lunn,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, linux-clk, linux-serial, linux-kernel,
	linux-arm-kernel

On Friday 20 August 2021 19:22:38 Pali Rohár wrote:
> On Monday 09 August 2021 16:53:23 Pali Rohár wrote:
> > This patch series add support for baudrates higher than 230400 on
> > Marvell Armada 37xx boards.
> > 
> > Please review these patches as they touch both Device Tree bindings and
> > mvebu-uart.c driver.
> 
> Stephen, is this patch series OK now? Or is there any other issue?

PING?

> > Changes in v5:
> > * fixed yaml binding file
> > 
> > Changes in v4:
> > * converted armada3700-uart-clock documentation to YAML
> > * split documentation changes into two commits:
> >   - first which adds clock documentation
> >   - second which updates UART documentation
> > 
> > Changes in v3:
> > v3 is rebased on top of Linus master branch and all already applied patches
> > were dropped. There are no changes in patches itself since v2.
> > 
> > Pali Rohár (6):
> >   math64: New DIV_U64_ROUND_CLOSEST helper
> >   serial: mvebu-uart: implement UART clock driver for configuring UART
> >     base clock
> >   dt-bindings: mvebu-uart: document DT bindings for
> >     marvell,armada-3700-uart-clock
> >   dt-bindings: mvebu-uart: update information about UART clock
> >   arm64: dts: marvell: armada-37xx: add device node for UART clock and
> >     use it
> >   serial: mvebu-uart: implement support for baudrates higher than 230400
> > 
> >  .../bindings/clock/armada3700-uart-clock.yaml |  57 ++
> >  .../devicetree/bindings/serial/mvebu-uart.txt |   9 +-
> >  .../arm64/boot/dts/marvell/armada-3720-db.dts |   4 +
> >  .../dts/marvell/armada-3720-espressobin.dtsi  |   4 +
> >  .../dts/marvell/armada-3720-turris-mox.dts    |   4 +
> >  .../boot/dts/marvell/armada-3720-uDPU.dts     |   4 +
> >  arch/arm64/boot/dts/marvell/armada-37xx.dtsi  |  15 +-
> >  drivers/tty/serial/Kconfig                    |   1 +
> >  drivers/tty/serial/mvebu-uart.c               | 592 +++++++++++++++++-
> >  include/linux/math64.h                        |  13 +
> >  10 files changed, 682 insertions(+), 21 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/clock/armada3700-uart-clock.yaml
> > 
> > -- 
> > 2.20.1
> > 

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates
  2021-08-31  8:35     ` Pali Rohár
@ 2021-09-21  7:41       ` Greg Kroah-Hartman
  0 siblings, 0 replies; 67+ messages in thread
From: Greg Kroah-Hartman @ 2021-09-21  7:41 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Stephen Boyd, Michael Turquette, Rob Herring, Andrew Lunn,
	Gregory Clement, Sebastian Hesselbarth, Vladimir Vid,
	Marek Behún, linux-clk, linux-serial, linux-kernel,
	linux-arm-kernel

On Tue, Aug 31, 2021 at 10:35:10AM +0200, Pali Rohár wrote:
> On Friday 20 August 2021 19:22:38 Pali Rohár wrote:
> > On Monday 09 August 2021 16:53:23 Pali Rohár wrote:
> > > This patch series add support for baudrates higher than 230400 on
> > > Marvell Armada 37xx boards.
> > > 
> > > Please review these patches as they touch both Device Tree bindings and
> > > mvebu-uart.c driver.
> > 
> > Stephen, is this patch series OK now? Or is there any other issue?
> 
> PING?

I'm going to drop this series from my queue.  Please resend it as it
seems people who need to review this have ignored it :(

greg k-h

^ permalink raw reply	[flat|nested] 67+ messages in thread

end of thread, other threads:[~2021-09-21  7:41 UTC | newest]

Thread overview: 67+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-24 22:48 [PATCH 00/10] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
2021-06-24 22:49 ` [PATCH 01/10] serial: mvebu-uart: fix calculation of clock divisor Pali Rohár
2021-06-24 22:49 ` [PATCH 02/10] serial: mvebu-uart: do not allow changing baudrate when uartclk is not available Pali Rohár
2021-06-24 22:49 ` [PATCH 03/10] serial: mvebu-uart: correctly calculate minimal possible baudrate Pali Rohár
2021-06-24 22:49 ` [PATCH 04/10] dt-bindings: mvebu-uart: fix documentation Pali Rohár
2021-06-24 22:49 ` [PATCH 05/10] arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART Pali Rohár
2021-06-24 22:49 ` [PATCH 06/10] serial: mvebu-uart: remove unused member nb from struct mvebu_uart Pali Rohár
2021-06-24 22:49 ` [PATCH 07/10] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
2021-06-24 22:49 ` [PATCH 08/10] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
2021-06-24 22:49 ` [PATCH 09/10] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
2021-06-24 22:49 ` [PATCH 10/10] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
2021-06-25 14:36 ` [PATCH v2 00/11] serial: mvebu-uart: Fixes and new support for higher baudrates Pali Rohár
2021-06-25 14:36   ` [PATCH v2 01/11] serial: mvebu-uart: fix calculation of clock divisor Pali Rohár
2021-06-25 14:36   ` [PATCH v2 02/11] serial: mvebu-uart: do not allow changing baudrate when uartclk is not available Pali Rohár
2021-06-25 14:36   ` [PATCH v2 03/11] serial: mvebu-uart: correctly calculate minimal possible baudrate Pali Rohár
2021-06-25 14:36   ` [PATCH v2 04/11] dt-bindings: mvebu-uart: fix documentation Pali Rohár
2021-06-25 14:36   ` [PATCH v2 05/11] arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART Pali Rohár
2021-06-25 14:36   ` [PATCH v2 06/11] serial: mvebu-uart: remove unused member nb from struct mvebu_uart Pali Rohár
2021-06-25 14:36   ` [PATCH v2 07/11] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
2021-06-25 15:22     ` Geert Uytterhoeven
2021-06-25 15:38       ` Pali Rohár
2021-06-25 15:50         ` Willy Tarreau
2021-06-25 17:39           ` Geert Uytterhoeven
2021-06-25 17:44             ` Pali Rohár
2021-06-25 18:11               ` Geert Uytterhoeven
2021-07-19 12:45         ` Andy Shevchenko
2021-06-25 14:36   ` [PATCH v2 08/11] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
2021-06-25 14:36   ` [PATCH v2 09/11] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
2021-06-25 14:36   ` [PATCH v2 10/11] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
2021-06-25 14:36   ` [PATCH v2 11/11] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
2021-07-17 12:38 ` [PATCH v3 0/5] serial: mvebu-uart: Support for higher baudrates Pali Rohár
2021-07-17 12:38   ` [PATCH v3 1/5] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
2021-07-19 12:47     ` Andy Shevchenko
2021-07-22 21:57       ` Pali Rohár
2021-07-24 11:38         ` David Laight
2021-07-17 12:38   ` [PATCH v3 2/5] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
2021-07-17 17:26     ` Andrew Lunn
2021-07-17 18:05       ` Pali Rohár
2021-07-24  9:48         ` Pali Rohár
2021-07-24 16:33           ` Andrew Lunn
2021-07-25 12:14             ` Pali Rohár
2021-07-17 12:38   ` [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
2021-07-17 17:30     ` [PATCH v3 3/5] dt-bindings: mvebu-uart: document DT bindings for marvell, armada-3700-uart-clock Andrew Lunn
2021-08-02 14:45       ` Pali Rohár
2021-07-17 12:38   ` [PATCH v3 4/5] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
2021-07-17 12:38   ` [PATCH v3 5/5] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
2021-08-02 14:45 ` [PATCH v4 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
2021-08-02 14:45   ` [PATCH v4 1/6] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
2021-08-02 14:45   ` [PATCH v4 2/6] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
2021-08-02 14:45   ` [PATCH v4 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
2021-08-06  0:30     ` Stephen Boyd
2021-08-06  8:28       ` Pali Rohár
2021-08-12 19:33         ` Stephen Boyd
2021-08-12 20:08           ` Pali Rohár
2021-08-02 14:45   ` [PATCH v4 4/6] dt-bindings: mvebu-uart: update information about UART clock Pali Rohár
2021-08-02 14:45   ` [PATCH v4 5/6] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
2021-08-02 14:45   ` [PATCH v4 6/6] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
2021-08-09 14:53 ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
2021-08-09 14:53   ` [PATCH v5 1/6] math64: New DIV_U64_ROUND_CLOSEST helper Pali Rohár
2021-08-09 14:53   ` [PATCH v5 2/6] serial: mvebu-uart: implement UART clock driver for configuring UART base clock Pali Rohár
2021-08-09 14:53   ` [PATCH v5 3/6] dt-bindings: mvebu-uart: document DT bindings for marvell,armada-3700-uart-clock Pali Rohár
2021-08-09 14:53   ` [PATCH v5 4/6] dt-bindings: mvebu-uart: update information about UART clock Pali Rohár
2021-08-09 14:53   ` [PATCH v5 5/6] arm64: dts: marvell: armada-37xx: add device node for UART clock and use it Pali Rohár
2021-08-09 14:53   ` [PATCH v5 6/6] serial: mvebu-uart: implement support for baudrates higher than 230400 Pali Rohár
2021-08-20 17:22   ` [PATCH v5 0/6] serial: mvebu-uart: Support for higher baudrates Pali Rohár
2021-08-31  8:35     ` Pali Rohár
2021-09-21  7:41       ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).