All of lore.kernel.org
 help / color / mirror / Atom feed
From: Edoardo Tomelleri <e.tomell@gmail.com>
To: u-boot-amlogic <u-boot-amlogic@groups.io>
Cc: Edoardo Tomelleri <e.tomell@gmail.com>,
	Neil Armstrong <narmstrong@baylibre.com>,
	Tom Rini <trini@konsulko.com>,
	u-boot@lists.denx.de
Subject: [PATCH] arm: amlogic: add setbrg op to serial device
Date: Sun, 18 Sep 2022 18:17:01 +0200	[thread overview]
Message-ID: <20220918161701.572814-1-e.tomell@gmail.com> (raw)

Implement setbrg in amlogic/meson serial device with driver model
similar to how the meson_uart.c driver does it in Linux. Also
configure (probe) the serial device with the new reg5 register.

Signed-off-by: Edoardo Tomelleri <e.tomell@gmail.com>
---

 drivers/serial/serial_meson.c | 70 +++++++++++++++++++++++++++++++++++
 include/configs/meson64.h     |  7 ++++
 2 files changed, 77 insertions(+)

diff --git a/drivers/serial/serial_meson.c b/drivers/serial/serial_meson.c
index d69ec221..90c370cf 100644
--- a/drivers/serial/serial_meson.c
+++ b/drivers/serial/serial_meson.c
@@ -7,9 +7,11 @@
 #include <dm.h>
 #include <errno.h>
 #include <fdtdec.h>
+#include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/compiler.h>
 #include <serial.h>
+#include <clk.h>
 
 struct meson_uart {
 	u32 wfifo;
@@ -17,6 +19,7 @@ struct meson_uart {
 	u32 control;
 	u32 status;
 	u32 misc;
+	u32 reg5; /* New baud control register */
 };
 
 struct meson_serial_plat {
@@ -42,6 +45,35 @@ struct meson_serial_plat {
 #define AML_UART_RX_RST			BIT(23)
 #define AML_UART_CLR_ERR		BIT(24)
 
+/* AML_UART_REG5 bits */
+#define AML_UART_REG5_XTAL_DIV2		BIT(27)
+#define AML_UART_REG5_XTAL_CLK_SEL	BIT(26) /* default 0 (div by 3), 1 for no div */
+#define AML_UART_REG5_USE_XTAL_CLK	BIT(24) /* default 1 (use crystal as clock source) */
+#define AML_UART_REG5_USE_NEW_BAUD	BIT(23) /* default 1 (use new baud rate register) */
+#define AML_UART_REG5_BAUD_MASK		0x7fffff
+
+static u32 meson_calc_baud_divisor(ulong src_rate, u32 baud)
+{
+	/*
+	 * Usually src_rate is 24 MHz (from crystal) as clock source for serial
+	 * device. Since 8 Mb/s is the maximum supported baud rate, use div by 3
+	 * to derive baud rate. This choice is used also in meson_serial_setbrg.
+	 */
+	return DIV_ROUND_CLOSEST(src_rate / 3, baud) - 1;
+}
+
+static void meson_serial_set_baud(struct meson_uart *uart, ulong src_rate, u32 baud)
+{
+	/*
+	 * Set crystal divided by 3 (regardless of device tree clock property)
+	 * as clock source and the corresponding divisor to approximate baud
+	 */
+	u32 divisor = meson_calc_baud_divisor(src_rate, baud);
+	u32 val = AML_UART_REG5_USE_XTAL_CLK | AML_UART_REG5_USE_NEW_BAUD |
+		(divisor & AML_UART_REG5_BAUD_MASK);
+	writel(val, &uart->reg5);
+}
+
 static void meson_serial_init(struct meson_uart *uart)
 {
 	u32 val;
@@ -59,7 +91,14 @@ static int meson_serial_probe(struct udevice *dev)
 {
 	struct meson_serial_plat *plat = dev_get_plat(dev);
 	struct meson_uart *const uart = plat->reg;
+	struct clk per_clk;
+	int ret = clk_get_by_name(dev, "baud", &per_clk);
+
+	if (ret)
+		return ret;
+	ulong rate = clk_get_rate(&per_clk);
 
+	meson_serial_set_baud(uart, rate, CONFIG_BAUDRATE);
 	meson_serial_init(uart);
 
 	return 0;
@@ -111,6 +150,36 @@ static int meson_serial_putc(struct udevice *dev, const char ch)
 	return 0;
 }
 
+static int meson_serial_setbrg(struct udevice *dev, const int baud)
+{
+	/*
+	 * Change device baud rate if baud is reasonable (considering a 23 bit
+	 * counter with an 8 MHz clock input) and the actual baud
+	 * rate is within 2% of the requested value (2% is arbitrary).
+	 */
+	if (baud < 1 || baud > 8000000)
+		return -EINVAL;
+
+	struct meson_serial_plat *const plat = dev_get_plat(dev);
+	struct meson_uart *const uart = plat->reg;
+	struct clk per_clk;
+	int ret = clk_get_by_name(dev, "baud", &per_clk);
+
+	if (ret)
+		return ret;
+	ulong rate = clk_get_rate(&per_clk);
+	u32 divisor = meson_calc_baud_divisor(rate, baud);
+	u32 calc_baud = (rate / 3) / (divisor + 1);
+	u32 calc_err = baud > calc_baud ? baud - calc_baud : calc_baud - baud;
+
+	if (((calc_err * 100) / baud) > 2)
+		return -EINVAL;
+
+	meson_serial_set_baud(uart, rate, baud);
+
+	return 0;
+}
+
 static int meson_serial_pending(struct udevice *dev, bool input)
 {
 	struct meson_serial_plat *plat = dev_get_plat(dev);
@@ -154,6 +223,7 @@ static const struct dm_serial_ops meson_serial_ops = {
 	.putc = meson_serial_putc,
 	.pending = meson_serial_pending,
 	.getc = meson_serial_getc,
+	.setbrg = meson_serial_setbrg,
 };
 
 static const struct udevice_id meson_serial_ids[] = {
diff --git a/include/configs/meson64.h b/include/configs/meson64.h
index 196e58ed..01413a02 100644
--- a/include/configs/meson64.h
+++ b/include/configs/meson64.h
@@ -16,6 +16,13 @@
 #define GICC_BASE			0xc4302000
 #endif
 
+/* Serial drivers */
+/* The following table includes the supported baudrates */
+#define CONFIG_SYS_BAUDRATE_TABLE  \
+	{300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, \
+		230400, 250000, 460800, 500000, 1000000, 2000000, 4000000, \
+		8000000 }
+
 /* For splashscreen */
 #ifdef CONFIG_DM_VIDEO
 #define STDOUT_CFG "vidconsole,serial"
-- 
2.37.3


             reply	other threads:[~2022-09-18 16:17 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-18 16:17 Edoardo Tomelleri [this message]
2022-09-22 16:51 ` [PATCH] arm: amlogic: add setbrg op to serial device Neil Armstrong
2022-09-22 18:51   ` Edoardo Tomelleri
2022-09-23  8:23     ` neil.armstrong
2022-09-23  8:23       ` Neil Armstrong
     [not found]     ` <17176FB5AE83328E.16904@groups.io>
2022-09-23  8:24       ` Neil Armstrong
2022-09-23  8:24         ` Neil Armstrong
2022-09-23  8:26 ` Neil Armstrong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220918161701.572814-1-e.tomell@gmail.com \
    --to=e.tomell@gmail.com \
    --cc=narmstrong@baylibre.com \
    --cc=trini@konsulko.com \
    --cc=u-boot-amlogic@groups.io \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.