From: Lucas Tanure <tanure@linux.com>
To: u-boot@lists.u-boot-project.org
Cc: neil.armstrong@linaro.org, trini@konsulko.com,
ilias.apalodimas@linaro.org, funderscore@postmasteros.org,
u-boot-amlogic@groups.io, Lucas Tanure <tanure@linux.com>
Subject: [PATCH 1/4] serial: meson: add Amlogic S4 UART support
Date: Thu, 6 Aug 2026 11:18:06 +0100 [thread overview]
Message-ID: <20260806101809.72526-2-tanure@linux.com> (raw)
In-Reply-To: <20260806101809.72526-1-tanure@linux.com>
The S4-generation UART (S4, T7, ...) derives its baud rate from the
24 MHz crystal divided by 2, selected via the XTAL_DIV2 bit in the
baud rate register, while older SoCs divide the crystal by 3. Add the
"amlogic,meson-s4-uart" compatible with driver data selecting the
div-by-2 scheme, matching the Linux driver (meson_s4_uart_data) and
the configuration the vendor BL2 programs on T7 hardware.
Older SoCs keep the existing div-by-3 behaviour: Linux also uses
div-by-2 on G12A, but both modes work there and switching would risk
regressing boards that have shipped with div-by-3 for years.
Also drain the transmitter before changing the baud rate so in-flight
characters are not garbled, as the Linux driver does.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Lucas Tanure <tanure@linux.com>
---
drivers/serial/serial_meson.c | 51 ++++++++++++++++++++++++++---------
1 file changed, 38 insertions(+), 13 deletions(-)
diff --git a/drivers/serial/serial_meson.c b/drivers/serial/serial_meson.c
index cc71381f87e..d909fedcfc4 100644
--- a/drivers/serial/serial_meson.c
+++ b/drivers/serial/serial_meson.c
@@ -62,26 +62,49 @@ struct meson_serial_plat {
#define AML_UART_REG5_USE_NEW_BAUD BIT(23) /* default 1 (use new baud rate register) */
#define AML_UART_REG5_BAUD_MASK 0x7fffff
+/* Driver data flags */
+#define MESON_UART_XTAL_DIV2 BIT(0)
+
#if CONFIG_IS_ENABLED(DM_SERIAL)
-static u32 meson_calc_baud_divisor(ulong src_rate, u32 baud)
+static u32 meson_uart_xtal_div(struct udevice *dev)
+{
+ /*
+ * S4-generation UARTs (S4, T7, ...) derive the baud rate from the
+ * crystal divided by 2, older ones divide by 3.
+ */
+ return (dev_get_driver_data(dev) & MESON_UART_XTAL_DIV2) ? 2 : 3;
+}
+
+static u32 meson_calc_baud_divisor(struct udevice *dev, 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.
+ * device. Since 8 Mb/s is the maximum supported baud rate, use a
+ * divided crystal to derive the baud rate. This choice is used also in
+ * meson_serial_setbrg.
*/
- return DIV_ROUND_CLOSEST(src_rate / 3, baud) - 1;
+ return DIV_ROUND_CLOSEST(src_rate / meson_uart_xtal_div(dev), baud) - 1;
}
-static void meson_serial_set_baud(struct meson_uart *uart, ulong src_rate, u32 baud)
+static void meson_serial_set_baud(struct udevice *dev, struct meson_uart *uart,
+ ulong src_rate, u32 baud)
{
/*
- * Set crystal divided by 3 (regardless of device tree clock property)
+ * Set the divided crystal (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 divisor = meson_calc_baud_divisor(dev, src_rate, baud);
u32 val = AML_UART_REG5_USE_XTAL_CLK | AML_UART_REG5_USE_NEW_BAUD |
(divisor & AML_UART_REG5_BAUD_MASK);
+
+ if (meson_uart_xtal_div(dev) == 2)
+ val |= AML_UART_REG5_XTAL_DIV2;
+
+ /* Drain the transmitter before changing the baud rate */
+ while ((readl(&uart->status) & (AML_UART_TX_EMPTY | AML_UART_XMIT_BUSY))
+ != AML_UART_TX_EMPTY)
+ ;
+
writel(val, &uart->reg5);
}
@@ -109,7 +132,7 @@ static int meson_serial_probe(struct udevice *dev)
return ret;
ulong rate = clk_get_rate(&per_clk);
- meson_serial_set_baud(uart, rate, CONFIG_BAUDRATE);
+ meson_serial_set_baud(dev, uart, rate, CONFIG_BAUDRATE);
meson_serial_init(uart);
return 0;
@@ -165,8 +188,9 @@ 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).
+ * counter with an 8 MHz, or 12 MHz for XTAL_DIV2 devices, clock input)
+ * and the actual baud rate is within 2% of the requested value (2% is
+ * arbitrary).
*/
if (baud < 1 || baud > 8000000)
return -EINVAL;
@@ -179,14 +203,14 @@ static int meson_serial_setbrg(struct udevice *dev, const int baud)
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 divisor = meson_calc_baud_divisor(dev, rate, baud);
+ u32 calc_baud = (rate / meson_uart_xtal_div(dev)) / (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);
+ meson_serial_set_baud(dev, uart, rate, baud);
return 0;
}
@@ -244,6 +268,7 @@ static const struct udevice_id meson_serial_ids[] = {
{ .compatible = "amlogic,meson-uart" },
{ .compatible = "amlogic,meson-gx-uart" },
{ .compatible = "amlogic,meson-a1-uart" },
+ { .compatible = "amlogic,meson-s4-uart", .data = MESON_UART_XTAL_DIV2 },
{ }
};
--
2.55.0
next prev parent reply other threads:[~2026-08-06 11:00 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-06 10:18 [PATCH 0/4] Add Amlogic T7 (A311D2) and Khadas VIM4 support Lucas Tanure
2026-08-06 10:18 ` Lucas Tanure [this message]
2026-08-10 14:01 ` [PATCH 1/4] serial: meson: add Amlogic S4 UART support Ferass El Hafidi
2026-08-06 10:18 ` [PATCH 2/4] arm: meson: add Amlogic T7 SoC family support Lucas Tanure
2026-08-10 14:15 ` Ferass El Hafidi
2026-08-06 10:18 ` [PATCH 3/4] board: amlogic: add Khadas VIM4 support Lucas Tanure
2026-08-10 14:30 ` Ferass El Hafidi
2026-08-06 10:18 ` [PATCH 4/4] doc: board: amlogic: add Khadas VIM4 documentation Lucas Tanure
2026-08-10 8:13 ` [PATCH 0/4] Add Amlogic T7 (A311D2) and Khadas VIM4 support neil.armstrong
2026-08-10 14:12 ` Ferass El Hafidi
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=20260806101809.72526-2-tanure@linux.com \
--to=tanure@linux.com \
--cc=funderscore@postmasteros.org \
--cc=ilias.apalodimas@linaro.org \
--cc=neil.armstrong@linaro.org \
--cc=trini@konsulko.com \
--cc=u-boot-amlogic@groups.io \
--cc=u-boot@lists.u-boot-project.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox