All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART
@ 2021-05-25 17:42 Marek Behún
  2021-05-25 17:42 ` [PATCH u-boot-marvell 1/5] serial: a37xx: Fix parent clock rate value and divider calculation Marek Behún
                   ` (5 more replies)
  0 siblings, 6 replies; 14+ messages in thread
From: Marek Behún @ 2021-05-25 17:42 UTC (permalink / raw)
  To: Stefan Roese, u-boot; +Cc: Pali Rohár, Marek Behún

This series adds support for more baudrates on Armada 3720 UART
(up to 6 MBaud).

Marek Behún (1):
  clk: armada-37xx: Set DM_FLAG_PRE_RELOC

Pali Rohár (4):
  serial: a37xx: Fix parent clock rate value and divider calculation
  serial: a37xx: Use TBG as parent clock
  serial: a37xx: Switch to XTAL clock when booting Linux kernel
  arm: mvebu: a37xx: Enable more baudrates

 drivers/clk/mvebu/armada-37xx-periph.c |   1 +
 drivers/clk/mvebu/armada-37xx-tbg.c    |   1 +
 drivers/serial/serial_mvebu_a3700.c    | 179 ++++++++++++++++++++++++-
 include/configs/mvebu_armada-37xx.h    |   9 +-
 include/configs/turris_mox.h           |   9 +-
 5 files changed, 190 insertions(+), 9 deletions(-)

-- 
2.26.3


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

* [PATCH u-boot-marvell 1/5] serial: a37xx: Fix parent clock rate value and divider calculation
  2021-05-25 17:42 [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Marek Behún
@ 2021-05-25 17:42 ` Marek Behún
  2021-05-27  6:13   ` Stefan Roese
  2021-05-25 17:42 ` [PATCH u-boot-marvell 2/5] clk: armada-37xx: Set DM_FLAG_PRE_RELOC Marek Behún
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 14+ messages in thread
From: Marek Behún @ 2021-05-25 17:42 UTC (permalink / raw)
  To: Stefan Roese, u-boot; +Cc: Pali Rohár, Marek Behún

From: Pali Rohár <pali@kernel.org>

UART parent clock is by default the platform's xtal clock, which is
25 MHz.

The value defined in the driver, though, is 25.8048 MHz. This is a hack
for the suboptimal divisor calculation
  Divisor = UART clock / (16 * baudrate)
which does not use rounding division, resulting in a suboptimal value
for divisor if the correct parent clock rate was used.

Change the code for divisor calculation to round to closest value, i.e.
  Divisor = Round(UART clock / (16 * baudrate))
and change the parent clock rate value to that returned by
get_ref_clk().

This makes A3720 UART stable at standard UART baudrates between 1800 and
230400.

Signed-off-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Marek Behún <marek.behun@nic.cz>
---
 drivers/serial/serial_mvebu_a3700.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
index 8f404879a5..9e7e479f80 100644
--- a/drivers/serial/serial_mvebu_a3700.c
+++ b/drivers/serial/serial_mvebu_a3700.c
@@ -7,6 +7,7 @@
 #include <dm.h>
 #include <serial.h>
 #include <asm/io.h>
+#include <asm/arch/cpu.h>
 
 struct mvebu_plat {
 	void __iomem *base;
@@ -29,8 +30,6 @@ struct mvebu_plat {
 #define UART_CTRL_RXFIFO_RESET	0x4000
 #define UART_CTRL_TXFIFO_RESET	0x8000
 
-#define CONFIG_UART_BASE_CLOCK	25804800
-
 static int mvebu_serial_putc(struct udevice *dev, const char ch)
 {
 	struct mvebu_plat *plat = dev_get_plat(dev);
@@ -75,12 +74,15 @@ static int mvebu_serial_setbrg(struct udevice *dev, int baudrate)
 {
 	struct mvebu_plat *plat = dev_get_plat(dev);
 	void __iomem *base = plat->base;
+	u32 parent_rate, divider;
 
 	/*
 	 * Calculate divider
 	 * baudrate = clock / 16 / divider
 	 */
-	writel(CONFIG_UART_BASE_CLOCK / baudrate / 16, base + UART_BAUD_REG);
+	parent_rate = get_ref_clk() * 1000000;
+	divider = DIV_ROUND_CLOSEST(parent_rate, baudrate * 16);
+	writel(divider, base + UART_BAUD_REG);
 
 	/*
 	 * Set Programmable Oversampling Stack to 0,
@@ -144,6 +146,7 @@ U_BOOT_DRIVER(serial_mvebu) = {
 static inline void _debug_uart_init(void)
 {
 	void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
+	u32 baudrate, parent_rate, divider;
 
 	/* reset FIFOs */
 	writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
@@ -156,7 +159,10 @@ static inline void _debug_uart_init(void)
 	 * Calculate divider
 	 * baudrate = clock / 16 / divider
 	 */
-	writel(CONFIG_UART_BASE_CLOCK / 115200 / 16, base + UART_BAUD_REG);
+	baudrate = 115200;
+	parent_rate = get_ref_clk() * 1000000;
+	divider = DIV_ROUND_CLOSEST(parent_rate, baudrate * 16);
+	writel(divider, base + UART_BAUD_REG);
 
 	/*
 	 * Set Programmable Oversampling Stack to 0,
-- 
2.26.3


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

* [PATCH u-boot-marvell 2/5] clk: armada-37xx: Set DM_FLAG_PRE_RELOC
  2021-05-25 17:42 [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Marek Behún
  2021-05-25 17:42 ` [PATCH u-boot-marvell 1/5] serial: a37xx: Fix parent clock rate value and divider calculation Marek Behún
@ 2021-05-25 17:42 ` Marek Behún
  2021-05-27  6:14   ` Stefan Roese
  2021-05-25 17:42 ` [PATCH u-boot-marvell 3/5] serial: a37xx: Use TBG as parent clock Marek Behún
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 14+ messages in thread
From: Marek Behún @ 2021-05-25 17:42 UTC (permalink / raw)
  To: Stefan Roese, u-boot; +Cc: Pali Rohár, Marek Behún

Setting DM_FLAG_PRE_RELOC for Armada 3720 clock drivers (TBG and
peripheral clocks) makes it possible for serial driver to retrieve clock
rates via clk API.

Signed-off-by: Marek Behún <marek.behun@nic.cz>
---
 drivers/clk/mvebu/armada-37xx-periph.c | 1 +
 drivers/clk/mvebu/armada-37xx-tbg.c    | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index b0f47c33b3..3b767d7060 100644
--- a/drivers/clk/mvebu/armada-37xx-periph.c
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
@@ -626,4 +626,5 @@ U_BOOT_DRIVER(armada_37xx_periph_clk) = {
 	.ops		= &armada_37xx_periph_clk_ops,
 	.priv_auto	= sizeof(struct a37xx_periphclk),
 	.probe		= armada_37xx_periph_clk_probe,
+	.flags		= DM_FLAG_PRE_RELOC,
 };
diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c
index b1c0852e89..054aff5e6a 100644
--- a/drivers/clk/mvebu/armada-37xx-tbg.c
+++ b/drivers/clk/mvebu/armada-37xx-tbg.c
@@ -152,4 +152,5 @@ U_BOOT_DRIVER(armada_37xx_tbg_clk) = {
 	.ops		= &armada_37xx_tbg_clk_ops,
 	.priv_auto	= sizeof(struct a37xx_tbgclk),
 	.probe		= armada_37xx_tbg_clk_probe,
+	.flags		= DM_FLAG_PRE_RELOC,
 };
-- 
2.26.3


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

* [PATCH u-boot-marvell 3/5] serial: a37xx: Use TBG as parent clock
  2021-05-25 17:42 [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Marek Behún
  2021-05-25 17:42 ` [PATCH u-boot-marvell 1/5] serial: a37xx: Fix parent clock rate value and divider calculation Marek Behún
  2021-05-25 17:42 ` [PATCH u-boot-marvell 2/5] clk: armada-37xx: Set DM_FLAG_PRE_RELOC Marek Behún
@ 2021-05-25 17:42 ` Marek Behún
  2021-05-27  6:15   ` Stefan Roese
  2021-05-25 17:42 ` [PATCH u-boot-marvell 4/5] serial: a37xx: Switch to XTAL clock when booting Linux kernel Marek Behún
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 14+ messages in thread
From: Marek Behún @ 2021-05-25 17:42 UTC (permalink / raw)
  To: Stefan Roese, u-boot; +Cc: Pali Rohár, Marek Behún

From: Pali Rohár <pali@kernel.org>

Using TBG clock as parent clock for UART allows us using higher
baudrates than 230400.

Turris MOX with external FT232RL USB-UART works fine up to 3 MBaud
(which is maximum for this USB-UART controller), while EspressoBIN with
integrated pl2303 USB-UART also works fine up to 6 MBaud.

Slower baudrates with TBG as a parent clock can be achieved by
increasing TBG dividers and oversampling divider. When using the slowest
TBG clock, minimal working baudrate is 300.

Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Marek Behún <marek.behun@nic.cz>
---
 drivers/serial/serial_mvebu_a3700.c | 106 ++++++++++++++++++++++++++--
 1 file changed, 101 insertions(+), 5 deletions(-)

diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
index 9e7e479f80..ba2ac5917f 100644
--- a/drivers/serial/serial_mvebu_a3700.c
+++ b/drivers/serial/serial_mvebu_a3700.c
@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <clk.h>
 #include <dm.h>
 #include <serial.h>
 #include <asm/io.h>
@@ -11,6 +12,8 @@
 
 struct mvebu_plat {
 	void __iomem *base;
+	ulong tbg_rate;
+	u8 tbg_idx;
 };
 
 /*
@@ -74,21 +77,70 @@ static int mvebu_serial_setbrg(struct udevice *dev, int baudrate)
 {
 	struct mvebu_plat *plat = dev_get_plat(dev);
 	void __iomem *base = plat->base;
-	u32 parent_rate, divider;
+	u32 divider, d1, d2;
+	u32 oversampling;
 
 	/*
 	 * Calculate divider
 	 * baudrate = clock / 16 / divider
 	 */
-	parent_rate = get_ref_clk() * 1000000;
-	divider = DIV_ROUND_CLOSEST(parent_rate, baudrate * 16);
-	writel(divider, base + UART_BAUD_REG);
+	d1 = d2 = 1;
+	divider = DIV_ROUND_CLOSEST(plat->tbg_rate, baudrate * 16 * d1 * d2);
 
 	/*
 	 * Set Programmable Oversampling Stack to 0,
 	 * UART defaults to 16x scheme
 	 */
-	writel(0, base + UART_POSSR_REG);
+	oversampling = 0;
+
+	if (divider < 1)
+		divider = 1;
+	else if (divider > 1023) {
+		/*
+		 * If divider is too high for selected baudrate then set
+		 * divider d1 to the maximal value 6.
+		 */
+		d1 = 6;
+		divider = DIV_ROUND_CLOSEST(plat->tbg_rate,
+					    baudrate * 16 * d1 * d2);
+		if (divider < 1)
+			divider = 1;
+		else if (divider > 1023) {
+			/*
+			 * If divider is still too high then set also divider
+			 * d2 to the maximal value 6.
+			 */
+			d2 = 6;
+			divider = DIV_ROUND_CLOSEST(plat->tbg_rate,
+						    baudrate * 16 * d1 * d2);
+			if (divider < 1)
+				divider = 1;
+			else if (divider > 1023) {
+				/*
+				 * And if divider is still to high then
+				 * use oversampling with maximal factor 63.
+				 */
+				oversampling = (63 << 0) | (63 << 8) |
+					      (63 << 16) | (63 << 24);
+				divider = DIV_ROUND_CLOSEST(plat->tbg_rate,
+						baudrate * 63 * d1 * d2);
+				if (divider < 1)
+					divider = 1;
+				else if (divider > 1023)
+					divider = 1023;
+			}
+		}
+	}
+
+	divider |= BIT(19); /* Do not use XTAL as a base clock */
+	divider |= d1 << 15; /* Set d1 divider */
+	divider |= d2 << 12; /* Set d2 divider */
+	divider |= plat->tbg_idx << 10; /* Use selected TBG as a base clock */
+
+	while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY))
+		;
+	writel(divider, base + UART_BAUD_REG);
+	writel(oversampling, base + UART_POSSR_REG);
 
 	return 0;
 }
@@ -97,6 +149,50 @@ static int mvebu_serial_probe(struct udevice *dev)
 {
 	struct mvebu_plat *plat = dev_get_plat(dev);
 	void __iomem *base = plat->base;
+	struct udevice *nb_clk;
+	ofnode nb_clk_node;
+	int i, res;
+
+	nb_clk_node = ofnode_by_compatible(ofnode_null(),
+					   "marvell,armada-3700-periph-clock-nb");
+	if (!ofnode_valid(nb_clk_node)) {
+		printf("%s: NB periph clock node not available\n", __func__);
+		return -ENODEV;
+	}
+
+	res = device_get_global_by_ofnode(nb_clk_node, &nb_clk);
+	if (res) {
+		printf("%s: Cannot get NB periph clock\n", __func__);
+		return res;
+	}
+
+	/*
+	 * Choose the TBG clock with lowest frequency which allows to configure
+	 * UART also at lower baudrates.
+	 */
+	for (i = 0; i < 4; i++) {
+		struct clk clk;
+		ulong rate;
+
+		res = clk_get_by_index_nodev(nb_clk_node, i, &clk);
+		if (res) {
+			printf("%s: Cannot get TBG clock %i: %i\n", __func__,
+			       i, res);
+			return -ENODEV;
+		}
+
+		rate = clk_get_rate(&clk);
+		if (!rate || IS_ERR_VALUE(rate)) {
+			printf("%s: Cannot get rate for TBG clock %i\n",
+			       __func__, i);
+			return -EINVAL;
+		}
+
+		if (!i || plat->tbg_rate > rate) {
+			plat->tbg_rate = rate;
+			plat->tbg_idx = i;
+		}
+	}
 
 	/* reset FIFOs */
 	writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
-- 
2.26.3


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

* [PATCH u-boot-marvell 4/5] serial: a37xx: Switch to XTAL clock when booting Linux kernel
  2021-05-25 17:42 [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Marek Behún
                   ` (2 preceding siblings ...)
  2021-05-25 17:42 ` [PATCH u-boot-marvell 3/5] serial: a37xx: Use TBG as parent clock Marek Behún
@ 2021-05-25 17:42 ` Marek Behún
  2021-05-27  6:17   ` Stefan Roese
  2021-05-25 17:42 ` [PATCH u-boot-marvell 5/5] arm: mvebu: a37xx: Enable more baudrates Marek Behún
  2021-07-09  5:18 ` [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Stefan Roese
  5 siblings, 1 reply; 14+ messages in thread
From: Marek Behún @ 2021-05-25 17:42 UTC (permalink / raw)
  To: Stefan Roese, u-boot; +Cc: Pali Rohár, Marek Behún

From: Pali Rohár <pali@kernel.org>

Unfortunately the UART driver in current Linux for Armada 3700 expects
UART's parent clock to be XTAL and calculats baudrate divisor according
to XTAL clock. Therefore we must switch back to XTAL clock before
booting kernel.

Implement .remove method for this driver with DM_FLAG_OS_PREPARE flag
set.

If current baudrate is unsuitable for XTAL clock then we do not change
anything. This can only happen if the user either configured unsupported
settings or knows what they are doing and has kernel patches which allow
usage of non-XTAL parent clock.

Signed-off-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Marek Behún <marek.behun@nic.cz>
---
 drivers/serial/serial_mvebu_a3700.c | 67 +++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
index ba2ac5917f..c7e66fef87 100644
--- a/drivers/serial/serial_mvebu_a3700.c
+++ b/drivers/serial/serial_mvebu_a3700.c
@@ -204,6 +204,71 @@ static int mvebu_serial_probe(struct udevice *dev)
 	return 0;
 }
 
+static int mvebu_serial_remove(struct udevice *dev)
+{
+	struct mvebu_plat *plat = dev_get_plat(dev);
+	void __iomem *base = plat->base;
+	ulong new_parent_rate, parent_rate;
+	u32 new_divider, divider;
+	u32 new_oversampling;
+	u32 oversampling;
+	u32 d1, d2;
+
+	/*
+	 * Switch UART base clock back to XTAL because older Linux kernel
+	 * expects it. Otherwise it does not calculate UART divisor correctly
+	 * and therefore UART does not work in kernel.
+	 */
+	divider = readl(base + UART_BAUD_REG);
+	if (!(divider & BIT(19))) /* UART already uses XTAL */
+		return 0;
+
+	/* Read current divisors settings */
+	d1 = (divider >> 15) & 7;
+	d2 = (divider >> 12) & 7;
+	parent_rate = plat->tbg_rate;
+	divider &= 1023;
+	oversampling = readl(base + UART_POSSR_REG) & 63;
+	if (!oversampling)
+		oversampling = 16;
+
+	/* Calculate new divisor against XTAL clock without changing baudrate */
+	new_oversampling = 0;
+	new_parent_rate = get_ref_clk() * 1000000;
+	new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 * d2 *
+					oversampling, parent_rate * 16);
+
+	/*
+	 * UART does not work reliably when XTAL divisor is smaller than 4.
+	 * In this case we do not switch UART parent to XTAL. User either
+	 * configured unsupported settings or has newer kernel with patches
+	 * which allow usage of non-XTAL clock as a parent clock.
+	 */
+	if (new_divider < 4)
+		return 0;
+
+	/*
+	 * If new divisor is larger than maximal supported, try to switch
+	 * from default x16 scheme to oversampling with maximal factor 63.
+	 */
+	if (new_divider > 1023) {
+		new_oversampling = 63;
+		new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 *
+						d2 * oversampling,
+						parent_rate * new_oversampling);
+		if (new_divider < 4 || new_divider > 1023)
+			return 0;
+	}
+
+	while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY))
+		;
+
+	writel(new_divider, base + UART_BAUD_REG);
+	writel(new_oversampling, base + UART_POSSR_REG);
+
+	return 0;
+}
+
 static int mvebu_serial_of_to_plat(struct udevice *dev)
 {
 	struct mvebu_plat *plat = dev_get_plat(dev);
@@ -232,6 +297,8 @@ U_BOOT_DRIVER(serial_mvebu) = {
 	.of_to_plat = mvebu_serial_of_to_plat,
 	.plat_auto	= sizeof(struct mvebu_plat),
 	.probe	= mvebu_serial_probe,
+	.remove	= mvebu_serial_remove,
+	.flags	= DM_FLAG_OS_PREPARE,
 	.ops	= &mvebu_serial_ops,
 };
 
-- 
2.26.3


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

* [PATCH u-boot-marvell 5/5] arm: mvebu: a37xx: Enable more baudrates
  2021-05-25 17:42 [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Marek Behún
                   ` (3 preceding siblings ...)
  2021-05-25 17:42 ` [PATCH u-boot-marvell 4/5] serial: a37xx: Switch to XTAL clock when booting Linux kernel Marek Behún
@ 2021-05-25 17:42 ` Marek Behún
  2021-05-27  6:18   ` Stefan Roese
  2021-07-09  5:18 ` [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Stefan Roese
  5 siblings, 1 reply; 14+ messages in thread
From: Marek Behún @ 2021-05-25 17:42 UTC (permalink / raw)
  To: Stefan Roese, u-boot; +Cc: Pali Rohár, Marek Behún

From: Pali Rohár <pali@kernel.org>

Extend CONFIG_SYS_BAUDRATE_TABLE and include all standard baudrates and
also nonstandard up to the 6 MBaud. U-Boot's A3720 UART driver can use
baudrates from 300 Baud to 6 MBaud.

This changes all A3720 boards, since all of them include either
mvebu_armada-37xx.h or turris_mox.h config file.

Signed-off-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Marek Behún <marek.behun@nic.cz>
---
 include/configs/mvebu_armada-37xx.h | 9 +++++++--
 include/configs/turris_mox.h        | 9 +++++++--
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/include/configs/mvebu_armada-37xx.h b/include/configs/mvebu_armada-37xx.h
index 2ad4325eaf..a2bea2947d 100644
--- a/include/configs/mvebu_armada-37xx.h
+++ b/include/configs/mvebu_armada-37xx.h
@@ -17,8 +17,13 @@
 
 #define CONFIG_SYS_BOOTM_LEN	SZ_64M /* Increase max gunzip size */
 
-#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, \
-					  115200, 230400, 460800, 921600 }
+#define CONFIG_SYS_BAUDRATE_TABLE	{ 300, 600, 1200, 1800, 2400, 4800, \
+					  9600, 19200, 38400, 57600, 115200, \
+					  230400, 460800, 500000, 576000, \
+					  921600, 1000000, 1152000, 1500000, \
+					  2000000, 2500000, 3000000, 3500000, \
+					  4000000, 4500000, 5000000, 5500000, \
+					  6000000 }
 
 /*
  * For booting Linux, the board info and command line data
diff --git a/include/configs/turris_mox.h b/include/configs/turris_mox.h
index 51445ec60a..df312f2019 100644
--- a/include/configs/turris_mox.h
+++ b/include/configs/turris_mox.h
@@ -22,8 +22,13 @@
 
 /* auto boot */
 
-#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, \
-					  115200, 230400, 460800, 921600 }
+#define CONFIG_SYS_BAUDRATE_TABLE	{ 300, 600, 1200, 1800, 2400, 4800, \
+					  9600, 19200, 38400, 57600, 115200, \
+					  230400, 460800, 500000, 576000, \
+					  921600, 1000000, 1152000, 1500000, \
+					  2000000, 2500000, 3000000, 3500000, \
+					  4000000, 4500000, 5000000, 5500000, \
+					  6000000 }
 
 /*
  * For booting Linux, the board info and command line data
-- 
2.26.3


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

* Re: [PATCH u-boot-marvell 1/5] serial: a37xx: Fix parent clock rate value and divider calculation
  2021-05-25 17:42 ` [PATCH u-boot-marvell 1/5] serial: a37xx: Fix parent clock rate value and divider calculation Marek Behún
@ 2021-05-27  6:13   ` Stefan Roese
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Roese @ 2021-05-27  6:13 UTC (permalink / raw)
  To: Marek Behún, u-boot; +Cc: Pali Rohár

On 25.05.21 19:42, Marek Behún wrote:
> From: Pali Rohár <pali@kernel.org>
> 
> UART parent clock is by default the platform's xtal clock, which is
> 25 MHz.
> 
> The value defined in the driver, though, is 25.8048 MHz. This is a hack
> for the suboptimal divisor calculation
>    Divisor = UART clock / (16 * baudrate)
> which does not use rounding division, resulting in a suboptimal value
> for divisor if the correct parent clock rate was used.
> 
> Change the code for divisor calculation to round to closest value, i.e.
>    Divisor = Round(UART clock / (16 * baudrate))
> and change the parent clock rate value to that returned by
> get_ref_clk().
> 
> This makes A3720 UART stable at standard UART baudrates between 1800 and
> 230400.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>
> Reviewed-by: Marek Behún <marek.behun@nic.cz>

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan

> ---
>   drivers/serial/serial_mvebu_a3700.c | 14 ++++++++++----
>   1 file changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
> index 8f404879a5..9e7e479f80 100644
> --- a/drivers/serial/serial_mvebu_a3700.c
> +++ b/drivers/serial/serial_mvebu_a3700.c
> @@ -7,6 +7,7 @@
>   #include <dm.h>
>   #include <serial.h>
>   #include <asm/io.h>
> +#include <asm/arch/cpu.h>
>   
>   struct mvebu_plat {
>   	void __iomem *base;
> @@ -29,8 +30,6 @@ struct mvebu_plat {
>   #define UART_CTRL_RXFIFO_RESET	0x4000
>   #define UART_CTRL_TXFIFO_RESET	0x8000
>   
> -#define CONFIG_UART_BASE_CLOCK	25804800
> -
>   static int mvebu_serial_putc(struct udevice *dev, const char ch)
>   {
>   	struct mvebu_plat *plat = dev_get_plat(dev);
> @@ -75,12 +74,15 @@ static int mvebu_serial_setbrg(struct udevice *dev, int baudrate)
>   {
>   	struct mvebu_plat *plat = dev_get_plat(dev);
>   	void __iomem *base = plat->base;
> +	u32 parent_rate, divider;
>   
>   	/*
>   	 * Calculate divider
>   	 * baudrate = clock / 16 / divider
>   	 */
> -	writel(CONFIG_UART_BASE_CLOCK / baudrate / 16, base + UART_BAUD_REG);
> +	parent_rate = get_ref_clk() * 1000000;
> +	divider = DIV_ROUND_CLOSEST(parent_rate, baudrate * 16);
> +	writel(divider, base + UART_BAUD_REG);
>   
>   	/*
>   	 * Set Programmable Oversampling Stack to 0,
> @@ -144,6 +146,7 @@ U_BOOT_DRIVER(serial_mvebu) = {
>   static inline void _debug_uart_init(void)
>   {
>   	void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
> +	u32 baudrate, parent_rate, divider;
>   
>   	/* reset FIFOs */
>   	writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
> @@ -156,7 +159,10 @@ static inline void _debug_uart_init(void)
>   	 * Calculate divider
>   	 * baudrate = clock / 16 / divider
>   	 */
> -	writel(CONFIG_UART_BASE_CLOCK / 115200 / 16, base + UART_BAUD_REG);
> +	baudrate = 115200;
> +	parent_rate = get_ref_clk() * 1000000;
> +	divider = DIV_ROUND_CLOSEST(parent_rate, baudrate * 16);
> +	writel(divider, base + UART_BAUD_REG);
>   
>   	/*
>   	 * Set Programmable Oversampling Stack to 0,
> 


Viele Grüße,
Stefan

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

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

* Re: [PATCH u-boot-marvell 2/5] clk: armada-37xx: Set DM_FLAG_PRE_RELOC
  2021-05-25 17:42 ` [PATCH u-boot-marvell 2/5] clk: armada-37xx: Set DM_FLAG_PRE_RELOC Marek Behún
@ 2021-05-27  6:14   ` Stefan Roese
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Roese @ 2021-05-27  6:14 UTC (permalink / raw)
  To: Marek Behún, u-boot; +Cc: Pali Rohár

On 25.05.21 19:42, Marek Behún wrote:
> Setting DM_FLAG_PRE_RELOC for Armada 3720 clock drivers (TBG and
> peripheral clocks) makes it possible for serial driver to retrieve clock
> rates via clk API.
> 
> Signed-off-by: Marek Behún <marek.behun@nic.cz>

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan

> ---
>   drivers/clk/mvebu/armada-37xx-periph.c | 1 +
>   drivers/clk/mvebu/armada-37xx-tbg.c    | 1 +
>   2 files changed, 2 insertions(+)
> 
> diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
> index b0f47c33b3..3b767d7060 100644
> --- a/drivers/clk/mvebu/armada-37xx-periph.c
> +++ b/drivers/clk/mvebu/armada-37xx-periph.c
> @@ -626,4 +626,5 @@ U_BOOT_DRIVER(armada_37xx_periph_clk) = {
>   	.ops		= &armada_37xx_periph_clk_ops,
>   	.priv_auto	= sizeof(struct a37xx_periphclk),
>   	.probe		= armada_37xx_periph_clk_probe,
> +	.flags		= DM_FLAG_PRE_RELOC,
>   };
> diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c
> index b1c0852e89..054aff5e6a 100644
> --- a/drivers/clk/mvebu/armada-37xx-tbg.c
> +++ b/drivers/clk/mvebu/armada-37xx-tbg.c
> @@ -152,4 +152,5 @@ U_BOOT_DRIVER(armada_37xx_tbg_clk) = {
>   	.ops		= &armada_37xx_tbg_clk_ops,
>   	.priv_auto	= sizeof(struct a37xx_tbgclk),
>   	.probe		= armada_37xx_tbg_clk_probe,
> +	.flags		= DM_FLAG_PRE_RELOC,
>   };
> 


Viele Grüße,
Stefan

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

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

* Re: [PATCH u-boot-marvell 3/5] serial: a37xx: Use TBG as parent clock
  2021-05-25 17:42 ` [PATCH u-boot-marvell 3/5] serial: a37xx: Use TBG as parent clock Marek Behún
@ 2021-05-27  6:15   ` Stefan Roese
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Roese @ 2021-05-27  6:15 UTC (permalink / raw)
  To: Marek Behún, u-boot; +Cc: Pali Rohár

On 25.05.21 19:42, Marek Behún wrote:
> From: Pali Rohár <pali@kernel.org>
> 
> Using TBG clock as parent clock for UART allows us using higher
> baudrates than 230400.
> 
> Turris MOX with external FT232RL USB-UART works fine up to 3 MBaud
> (which is maximum for this USB-UART controller), while EspressoBIN with
> integrated pl2303 USB-UART also works fine up to 6 MBaud.
> 
> Slower baudrates with TBG as a parent clock can be achieved by
> increasing TBG dividers and oversampling divider. When using the slowest
> TBG clock, minimal working baudrate is 300.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>
> Signed-off-by: Marek Behún <marek.behun@nic.cz>

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan

> ---
>   drivers/serial/serial_mvebu_a3700.c | 106 ++++++++++++++++++++++++++--
>   1 file changed, 101 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
> index 9e7e479f80..ba2ac5917f 100644
> --- a/drivers/serial/serial_mvebu_a3700.c
> +++ b/drivers/serial/serial_mvebu_a3700.c
> @@ -4,6 +4,7 @@
>    */
>   
>   #include <common.h>
> +#include <clk.h>
>   #include <dm.h>
>   #include <serial.h>
>   #include <asm/io.h>
> @@ -11,6 +12,8 @@
>   
>   struct mvebu_plat {
>   	void __iomem *base;
> +	ulong tbg_rate;
> +	u8 tbg_idx;
>   };
>   
>   /*
> @@ -74,21 +77,70 @@ static int mvebu_serial_setbrg(struct udevice *dev, int baudrate)
>   {
>   	struct mvebu_plat *plat = dev_get_plat(dev);
>   	void __iomem *base = plat->base;
> -	u32 parent_rate, divider;
> +	u32 divider, d1, d2;
> +	u32 oversampling;
>   
>   	/*
>   	 * Calculate divider
>   	 * baudrate = clock / 16 / divider
>   	 */
> -	parent_rate = get_ref_clk() * 1000000;
> -	divider = DIV_ROUND_CLOSEST(parent_rate, baudrate * 16);
> -	writel(divider, base + UART_BAUD_REG);
> +	d1 = d2 = 1;
> +	divider = DIV_ROUND_CLOSEST(plat->tbg_rate, baudrate * 16 * d1 * d2);
>   
>   	/*
>   	 * Set Programmable Oversampling Stack to 0,
>   	 * UART defaults to 16x scheme
>   	 */
> -	writel(0, base + UART_POSSR_REG);
> +	oversampling = 0;
> +
> +	if (divider < 1)
> +		divider = 1;
> +	else if (divider > 1023) {
> +		/*
> +		 * If divider is too high for selected baudrate then set
> +		 * divider d1 to the maximal value 6.
> +		 */
> +		d1 = 6;
> +		divider = DIV_ROUND_CLOSEST(plat->tbg_rate,
> +					    baudrate * 16 * d1 * d2);
> +		if (divider < 1)
> +			divider = 1;
> +		else if (divider > 1023) {
> +			/*
> +			 * If divider is still too high then set also divider
> +			 * d2 to the maximal value 6.
> +			 */
> +			d2 = 6;
> +			divider = DIV_ROUND_CLOSEST(plat->tbg_rate,
> +						    baudrate * 16 * d1 * d2);
> +			if (divider < 1)
> +				divider = 1;
> +			else if (divider > 1023) {
> +				/*
> +				 * And if divider is still to high then
> +				 * use oversampling with maximal factor 63.
> +				 */
> +				oversampling = (63 << 0) | (63 << 8) |
> +					      (63 << 16) | (63 << 24);
> +				divider = DIV_ROUND_CLOSEST(plat->tbg_rate,
> +						baudrate * 63 * d1 * d2);
> +				if (divider < 1)
> +					divider = 1;
> +				else if (divider > 1023)
> +					divider = 1023;
> +			}
> +		}
> +	}
> +
> +	divider |= BIT(19); /* Do not use XTAL as a base clock */
> +	divider |= d1 << 15; /* Set d1 divider */
> +	divider |= d2 << 12; /* Set d2 divider */
> +	divider |= plat->tbg_idx << 10; /* Use selected TBG as a base clock */
> +
> +	while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY))
> +		;
> +	writel(divider, base + UART_BAUD_REG);
> +	writel(oversampling, base + UART_POSSR_REG);
>   
>   	return 0;
>   }
> @@ -97,6 +149,50 @@ static int mvebu_serial_probe(struct udevice *dev)
>   {
>   	struct mvebu_plat *plat = dev_get_plat(dev);
>   	void __iomem *base = plat->base;
> +	struct udevice *nb_clk;
> +	ofnode nb_clk_node;
> +	int i, res;
> +
> +	nb_clk_node = ofnode_by_compatible(ofnode_null(),
> +					   "marvell,armada-3700-periph-clock-nb");
> +	if (!ofnode_valid(nb_clk_node)) {
> +		printf("%s: NB periph clock node not available\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	res = device_get_global_by_ofnode(nb_clk_node, &nb_clk);
> +	if (res) {
> +		printf("%s: Cannot get NB periph clock\n", __func__);
> +		return res;
> +	}
> +
> +	/*
> +	 * Choose the TBG clock with lowest frequency which allows to configure
> +	 * UART also at lower baudrates.
> +	 */
> +	for (i = 0; i < 4; i++) {
> +		struct clk clk;
> +		ulong rate;
> +
> +		res = clk_get_by_index_nodev(nb_clk_node, i, &clk);
> +		if (res) {
> +			printf("%s: Cannot get TBG clock %i: %i\n", __func__,
> +			       i, res);
> +			return -ENODEV;
> +		}
> +
> +		rate = clk_get_rate(&clk);
> +		if (!rate || IS_ERR_VALUE(rate)) {
> +			printf("%s: Cannot get rate for TBG clock %i\n",
> +			       __func__, i);
> +			return -EINVAL;
> +		}
> +
> +		if (!i || plat->tbg_rate > rate) {
> +			plat->tbg_rate = rate;
> +			plat->tbg_idx = i;
> +		}
> +	}
>   
>   	/* reset FIFOs */
>   	writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
> 


Viele Grüße,
Stefan

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

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

* Re: [PATCH u-boot-marvell 4/5] serial: a37xx: Switch to XTAL clock when booting Linux kernel
  2021-05-25 17:42 ` [PATCH u-boot-marvell 4/5] serial: a37xx: Switch to XTAL clock when booting Linux kernel Marek Behún
@ 2021-05-27  6:17   ` Stefan Roese
  2021-05-27  8:17     ` Pali Rohár
  0 siblings, 1 reply; 14+ messages in thread
From: Stefan Roese @ 2021-05-27  6:17 UTC (permalink / raw)
  To: Marek Behún, u-boot; +Cc: Pali Rohár

On 25.05.21 19:42, Marek Behún wrote:
> From: Pali Rohár <pali@kernel.org>
> 
> Unfortunately the UART driver in current Linux for Armada 3700 expects
> UART's parent clock to be XTAL and calculats baudrate divisor according
> to XTAL clock. Therefore we must switch back to XTAL clock before
> booting kernel.

Do you plan to enhance the Linux driver as well to support TBG as
clock in input at some time?

> Implement .remove method for this driver with DM_FLAG_OS_PREPARE flag
> set.
> 
> If current baudrate is unsuitable for XTAL clock then we do not change
> anything. This can only happen if the user either configured unsupported
> settings or knows what they are doing and has kernel patches which allow
> usage of non-XTAL parent clock.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>
> Reviewed-by: Marek Behún <marek.behun@nic.cz>

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan

> ---
>   drivers/serial/serial_mvebu_a3700.c | 67 +++++++++++++++++++++++++++++
>   1 file changed, 67 insertions(+)
> 
> diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
> index ba2ac5917f..c7e66fef87 100644
> --- a/drivers/serial/serial_mvebu_a3700.c
> +++ b/drivers/serial/serial_mvebu_a3700.c
> @@ -204,6 +204,71 @@ static int mvebu_serial_probe(struct udevice *dev)
>   	return 0;
>   }
>   
> +static int mvebu_serial_remove(struct udevice *dev)
> +{
> +	struct mvebu_plat *plat = dev_get_plat(dev);
> +	void __iomem *base = plat->base;
> +	ulong new_parent_rate, parent_rate;
> +	u32 new_divider, divider;
> +	u32 new_oversampling;
> +	u32 oversampling;
> +	u32 d1, d2;
> +
> +	/*
> +	 * Switch UART base clock back to XTAL because older Linux kernel
> +	 * expects it. Otherwise it does not calculate UART divisor correctly
> +	 * and therefore UART does not work in kernel.
> +	 */
> +	divider = readl(base + UART_BAUD_REG);
> +	if (!(divider & BIT(19))) /* UART already uses XTAL */
> +		return 0;
> +
> +	/* Read current divisors settings */
> +	d1 = (divider >> 15) & 7;
> +	d2 = (divider >> 12) & 7;
> +	parent_rate = plat->tbg_rate;
> +	divider &= 1023;
> +	oversampling = readl(base + UART_POSSR_REG) & 63;
> +	if (!oversampling)
> +		oversampling = 16;
> +
> +	/* Calculate new divisor against XTAL clock without changing baudrate */
> +	new_oversampling = 0;
> +	new_parent_rate = get_ref_clk() * 1000000;
> +	new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 * d2 *
> +					oversampling, parent_rate * 16);
> +
> +	/*
> +	 * UART does not work reliably when XTAL divisor is smaller than 4.
> +	 * In this case we do not switch UART parent to XTAL. User either
> +	 * configured unsupported settings or has newer kernel with patches
> +	 * which allow usage of non-XTAL clock as a parent clock.
> +	 */
> +	if (new_divider < 4)
> +		return 0;
> +
> +	/*
> +	 * If new divisor is larger than maximal supported, try to switch
> +	 * from default x16 scheme to oversampling with maximal factor 63.
> +	 */
> +	if (new_divider > 1023) {
> +		new_oversampling = 63;
> +		new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 *
> +						d2 * oversampling,
> +						parent_rate * new_oversampling);
> +		if (new_divider < 4 || new_divider > 1023)
> +			return 0;
> +	}
> +
> +	while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY))
> +		;
> +
> +	writel(new_divider, base + UART_BAUD_REG);
> +	writel(new_oversampling, base + UART_POSSR_REG);
> +
> +	return 0;
> +}
> +
>   static int mvebu_serial_of_to_plat(struct udevice *dev)
>   {
>   	struct mvebu_plat *plat = dev_get_plat(dev);
> @@ -232,6 +297,8 @@ U_BOOT_DRIVER(serial_mvebu) = {
>   	.of_to_plat = mvebu_serial_of_to_plat,
>   	.plat_auto	= sizeof(struct mvebu_plat),
>   	.probe	= mvebu_serial_probe,
> +	.remove	= mvebu_serial_remove,
> +	.flags	= DM_FLAG_OS_PREPARE,
>   	.ops	= &mvebu_serial_ops,
>   };
>   
> 


Viele Grüße,
Stefan

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

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

* Re: [PATCH u-boot-marvell 5/5] arm: mvebu: a37xx: Enable more baudrates
  2021-05-25 17:42 ` [PATCH u-boot-marvell 5/5] arm: mvebu: a37xx: Enable more baudrates Marek Behún
@ 2021-05-27  6:18   ` Stefan Roese
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Roese @ 2021-05-27  6:18 UTC (permalink / raw)
  To: Marek Behún, u-boot; +Cc: Pali Rohár

On 25.05.21 19:42, Marek Behún wrote:
> From: Pali Rohár <pali@kernel.org>
> 
> Extend CONFIG_SYS_BAUDRATE_TABLE and include all standard baudrates and
> also nonstandard up to the 6 MBaud. U-Boot's A3720 UART driver can use
> baudrates from 300 Baud to 6 MBaud.
> 
> This changes all A3720 boards, since all of them include either
> mvebu_armada-37xx.h or turris_mox.h config file.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>
> Reviewed-by: Marek Behún <marek.behun@nic.cz>

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan

> ---
>   include/configs/mvebu_armada-37xx.h | 9 +++++++--
>   include/configs/turris_mox.h        | 9 +++++++--
>   2 files changed, 14 insertions(+), 4 deletions(-)
> 
> diff --git a/include/configs/mvebu_armada-37xx.h b/include/configs/mvebu_armada-37xx.h
> index 2ad4325eaf..a2bea2947d 100644
> --- a/include/configs/mvebu_armada-37xx.h
> +++ b/include/configs/mvebu_armada-37xx.h
> @@ -17,8 +17,13 @@
>   
>   #define CONFIG_SYS_BOOTM_LEN	SZ_64M /* Increase max gunzip size */
>   
> -#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, \
> -					  115200, 230400, 460800, 921600 }
> +#define CONFIG_SYS_BAUDRATE_TABLE	{ 300, 600, 1200, 1800, 2400, 4800, \
> +					  9600, 19200, 38400, 57600, 115200, \
> +					  230400, 460800, 500000, 576000, \
> +					  921600, 1000000, 1152000, 1500000, \
> +					  2000000, 2500000, 3000000, 3500000, \
> +					  4000000, 4500000, 5000000, 5500000, \
> +					  6000000 }
>   
>   /*
>    * For booting Linux, the board info and command line data
> diff --git a/include/configs/turris_mox.h b/include/configs/turris_mox.h
> index 51445ec60a..df312f2019 100644
> --- a/include/configs/turris_mox.h
> +++ b/include/configs/turris_mox.h
> @@ -22,8 +22,13 @@
>   
>   /* auto boot */
>   
> -#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, \
> -					  115200, 230400, 460800, 921600 }
> +#define CONFIG_SYS_BAUDRATE_TABLE	{ 300, 600, 1200, 1800, 2400, 4800, \
> +					  9600, 19200, 38400, 57600, 115200, \
> +					  230400, 460800, 500000, 576000, \
> +					  921600, 1000000, 1152000, 1500000, \
> +					  2000000, 2500000, 3000000, 3500000, \
> +					  4000000, 4500000, 5000000, 5500000, \
> +					  6000000 }
>   
>   /*
>    * For booting Linux, the board info and command line data
> 


Viele Grüße,
Stefan

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

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

* Re: [PATCH u-boot-marvell 4/5] serial: a37xx: Switch to XTAL clock when booting Linux kernel
  2021-05-27  6:17   ` Stefan Roese
@ 2021-05-27  8:17     ` Pali Rohár
  2021-06-25 12:04       ` Pali Rohár
  0 siblings, 1 reply; 14+ messages in thread
From: Pali Rohár @ 2021-05-27  8:17 UTC (permalink / raw)
  To: Stefan Roese; +Cc: Marek Behún, u-boot

On Thursday 27 May 2021 08:17:41 Stefan Roese wrote:
> On 25.05.21 19:42, Marek Behún wrote:
> > From: Pali Rohár <pali@kernel.org>
> > 
> > Unfortunately the UART driver in current Linux for Armada 3700 expects
> > UART's parent clock to be XTAL and calculats baudrate divisor according
> > to XTAL clock. Therefore we must switch back to XTAL clock before
> > booting kernel.
> 
> Do you plan to enhance the Linux driver as well to support TBG as
> clock in input at some time?

Yes! I have already written patches but they need cleanup and more tests.

> > Implement .remove method for this driver with DM_FLAG_OS_PREPARE flag
> > set.
> > 
> > If current baudrate is unsuitable for XTAL clock then we do not change
> > anything. This can only happen if the user either configured unsupported
> > settings or knows what they are doing and has kernel patches which allow
> > usage of non-XTAL parent clock.
> > 
> > Signed-off-by: Pali Rohár <pali@kernel.org>
> > Reviewed-by: Marek Behún <marek.behun@nic.cz>
> 
> Reviewed-by: Stefan Roese <sr@denx.de>
> 
> Thanks,
> Stefan
> 
> > ---
> >   drivers/serial/serial_mvebu_a3700.c | 67 +++++++++++++++++++++++++++++
> >   1 file changed, 67 insertions(+)
> > 
> > diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
> > index ba2ac5917f..c7e66fef87 100644
> > --- a/drivers/serial/serial_mvebu_a3700.c
> > +++ b/drivers/serial/serial_mvebu_a3700.c
> > @@ -204,6 +204,71 @@ static int mvebu_serial_probe(struct udevice *dev)
> >   	return 0;
> >   }
> > +static int mvebu_serial_remove(struct udevice *dev)
> > +{
> > +	struct mvebu_plat *plat = dev_get_plat(dev);
> > +	void __iomem *base = plat->base;
> > +	ulong new_parent_rate, parent_rate;
> > +	u32 new_divider, divider;
> > +	u32 new_oversampling;
> > +	u32 oversampling;
> > +	u32 d1, d2;
> > +
> > +	/*
> > +	 * Switch UART base clock back to XTAL because older Linux kernel
> > +	 * expects it. Otherwise it does not calculate UART divisor correctly
> > +	 * and therefore UART does not work in kernel.
> > +	 */
> > +	divider = readl(base + UART_BAUD_REG);
> > +	if (!(divider & BIT(19))) /* UART already uses XTAL */
> > +		return 0;
> > +
> > +	/* Read current divisors settings */
> > +	d1 = (divider >> 15) & 7;
> > +	d2 = (divider >> 12) & 7;
> > +	parent_rate = plat->tbg_rate;
> > +	divider &= 1023;
> > +	oversampling = readl(base + UART_POSSR_REG) & 63;
> > +	if (!oversampling)
> > +		oversampling = 16;
> > +
> > +	/* Calculate new divisor against XTAL clock without changing baudrate */
> > +	new_oversampling = 0;
> > +	new_parent_rate = get_ref_clk() * 1000000;
> > +	new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 * d2 *
> > +					oversampling, parent_rate * 16);
> > +
> > +	/*
> > +	 * UART does not work reliably when XTAL divisor is smaller than 4.
> > +	 * In this case we do not switch UART parent to XTAL. User either
> > +	 * configured unsupported settings or has newer kernel with patches
> > +	 * which allow usage of non-XTAL clock as a parent clock.
> > +	 */
> > +	if (new_divider < 4)
> > +		return 0;
> > +
> > +	/*
> > +	 * If new divisor is larger than maximal supported, try to switch
> > +	 * from default x16 scheme to oversampling with maximal factor 63.
> > +	 */
> > +	if (new_divider > 1023) {
> > +		new_oversampling = 63;
> > +		new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 *
> > +						d2 * oversampling,
> > +						parent_rate * new_oversampling);
> > +		if (new_divider < 4 || new_divider > 1023)
> > +			return 0;
> > +	}
> > +
> > +	while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY))
> > +		;
> > +
> > +	writel(new_divider, base + UART_BAUD_REG);
> > +	writel(new_oversampling, base + UART_POSSR_REG);
> > +
> > +	return 0;
> > +}
> > +
> >   static int mvebu_serial_of_to_plat(struct udevice *dev)
> >   {
> >   	struct mvebu_plat *plat = dev_get_plat(dev);
> > @@ -232,6 +297,8 @@ U_BOOT_DRIVER(serial_mvebu) = {
> >   	.of_to_plat = mvebu_serial_of_to_plat,
> >   	.plat_auto	= sizeof(struct mvebu_plat),
> >   	.probe	= mvebu_serial_probe,
> > +	.remove	= mvebu_serial_remove,
> > +	.flags	= DM_FLAG_OS_PREPARE,
> >   	.ops	= &mvebu_serial_ops,
> >   };
> > 
> 
> 
> Viele Grüße,
> Stefan
> 
> -- 
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

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

* Re: [PATCH u-boot-marvell 4/5] serial: a37xx: Switch to XTAL clock when booting Linux kernel
  2021-05-27  8:17     ` Pali Rohár
@ 2021-06-25 12:04       ` Pali Rohár
  0 siblings, 0 replies; 14+ messages in thread
From: Pali Rohár @ 2021-06-25 12:04 UTC (permalink / raw)
  To: Stefan Roese; +Cc: Marek Behún, u-boot

On Thursday 27 May 2021 10:17:33 Pali Rohár wrote:
> On Thursday 27 May 2021 08:17:41 Stefan Roese wrote:
> > On 25.05.21 19:42, Marek Behún wrote:
> > > From: Pali Rohár <pali@kernel.org>
> > > 
> > > Unfortunately the UART driver in current Linux for Armada 3700 expects
> > > UART's parent clock to be XTAL and calculats baudrate divisor according
> > > to XTAL clock. Therefore we must switch back to XTAL clock before
> > > booting kernel.
> > 
> > Do you plan to enhance the Linux driver as well to support TBG as
> > clock in input at some time?
> 
> Yes! I have already written patches but they need cleanup and more tests.

Patches for Linux kernel are here:
https://lore.kernel.org/linux-serial/20210624224909.6350-1-pali@kernel.org/

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

* Re: [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART
  2021-05-25 17:42 [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Marek Behún
                   ` (4 preceding siblings ...)
  2021-05-25 17:42 ` [PATCH u-boot-marvell 5/5] arm: mvebu: a37xx: Enable more baudrates Marek Behún
@ 2021-07-09  5:18 ` Stefan Roese
  5 siblings, 0 replies; 14+ messages in thread
From: Stefan Roese @ 2021-07-09  5:18 UTC (permalink / raw)
  To: Marek Behún, u-boot; +Cc: Pali Rohár

On 25.05.21 19:42, Marek Behún wrote:
> This series adds support for more baudrates on Armada 3720 UART
> (up to 6 MBaud).
> 
> Marek Behún (1):
>    clk: armada-37xx: Set DM_FLAG_PRE_RELOC
> 
> Pali Rohár (4):
>    serial: a37xx: Fix parent clock rate value and divider calculation
>    serial: a37xx: Use TBG as parent clock
>    serial: a37xx: Switch to XTAL clock when booting Linux kernel
>    arm: mvebu: a37xx: Enable more baudrates
> 
>   drivers/clk/mvebu/armada-37xx-periph.c |   1 +
>   drivers/clk/mvebu/armada-37xx-tbg.c    |   1 +
>   drivers/serial/serial_mvebu_a3700.c    | 179 ++++++++++++++++++++++++-
>   include/configs/mvebu_armada-37xx.h    |   9 +-
>   include/configs/turris_mox.h           |   9 +-
>   5 files changed, 190 insertions(+), 9 deletions(-)
> 

Applied to u-boot-marvell/master

Thanks,
Stefan

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

end of thread, other threads:[~2021-07-09  5:18 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-25 17:42 [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Marek Behún
2021-05-25 17:42 ` [PATCH u-boot-marvell 1/5] serial: a37xx: Fix parent clock rate value and divider calculation Marek Behún
2021-05-27  6:13   ` Stefan Roese
2021-05-25 17:42 ` [PATCH u-boot-marvell 2/5] clk: armada-37xx: Set DM_FLAG_PRE_RELOC Marek Behún
2021-05-27  6:14   ` Stefan Roese
2021-05-25 17:42 ` [PATCH u-boot-marvell 3/5] serial: a37xx: Use TBG as parent clock Marek Behún
2021-05-27  6:15   ` Stefan Roese
2021-05-25 17:42 ` [PATCH u-boot-marvell 4/5] serial: a37xx: Switch to XTAL clock when booting Linux kernel Marek Behún
2021-05-27  6:17   ` Stefan Roese
2021-05-27  8:17     ` Pali Rohár
2021-06-25 12:04       ` Pali Rohár
2021-05-25 17:42 ` [PATCH u-boot-marvell 5/5] arm: mvebu: a37xx: Enable more baudrates Marek Behún
2021-05-27  6:18   ` Stefan Roese
2021-07-09  5:18 ` [PATCH u-boot-marvell 0/5] Support higher baudrates on Armada 3720 UART Stefan Roese

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.