Re: [PATCH 1/4] serial: meson: add Amlogic S4 UART support
Lucas Tanure <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <[email protected]> |
On 10/08/2026 15:01, Ferass El Hafidi wrote: > On Thu, 06 Aug 2026 10:18, "Lucas Tanure via groups.io" > <[email protected]> wrote: >> 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 > > As I understand it, LLM-assisted patches are not welcome in U-Boot right > now: https://lore.kernel.org/u-boot/20260515220758.GM1858239@bill-the-cat/ > > AFAIK there isn't an official AI policy yet, but it seems the concensus > on that matter is currently "please don't". Sorry. Ok, I will drop this line. > >> Signed-off-by: Lucas Tanure <[email protected]> >> --- >> 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 > > Best regards, > Ferass