]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
drivers: serial: serial_omap: Fix TI OMAP UART U-Boot driver to support higher baudrates
authorGokul Praveen <g-praveen@ti.com>
Tue, 26 Nov 2024 10:51:31 +0000 (16:21 +0530)
committerTom Rini <trini@konsulko.com>
Sat, 14 Dec 2024 15:32:59 +0000 (09:32 -0600)
Move to OMAP specific implementation of certain ops functions as the UART
prints on the serial console fail for baudrates greater than 460800.

The MDR1 register is responsible for determining the speed mode at which
the UART should operate for OMAP specific devices. The baud divisor is used
to set the UART_DLL register which is used for generation of the baud
clock in the baud rate generator. The implementation logic is similar to
how it is implemented in omap_8250_get_divisor function of 8250_omap UART
linux driver.

Signed-off-by: Gokul Praveen <g-praveen@ti.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/serial/serial_omap.c

index 94672655c288e364065df03401abc9828ef1e568..224d9cbf29d7a7bcb190cbc6762f827a4cc0845c 100644 (file)
 #include <clk.h>
 #include <linux/err.h>
 
+/*
+ * These are the definitions for the MDR1 register
+ */
+#define UART_OMAP_MDR1_16X_MODE                0x00    /* UART 16x mode */
+#define UART_OMAP_MDR1_13X_MODE                0x03    /* UART 13x mode */
+
 #ifndef CFG_SYS_NS16550_CLK
 #define CFG_SYS_NS16550_CLK  0
 #endif
@@ -151,6 +157,54 @@ static const struct udevice_id omap_serial_ids[] = {
 };
 #endif /* OF_REAL */
 
+static int omap_serial_calc_divisor(struct ns16550 *com_port, int clock, int baudrate)
+{
+       unsigned int div_13, div_16;
+       unsigned int abs_d13, abs_d16;
+       /*
+        * The below logic sets the MDR1 register based on clock and baudrate.
+        */
+       div_13 = DIV_ROUND_CLOSEST(clock, 13 * baudrate);
+       div_16 = DIV_ROUND_CLOSEST(clock, 16 * baudrate);
+
+       if (!div_13)
+               div_13 = 1;
+       if (!div_16)
+               div_16 = 1;
+
+       abs_d13 = abs(baudrate - clock / 13 / div_13);
+       abs_d16 = abs(baudrate - clock / 16 / div_16);
+
+       if (abs_d13 >= abs_d16)
+               serial_out(UART_OMAP_MDR1_16X_MODE, &com_port->mdr1);
+       else
+               serial_out(UART_OMAP_MDR1_13X_MODE, &com_port->mdr1);
+
+       return abs_d13 >= abs_d16 ? div_16 : div_13;
+}
+
+static int omap_serial_setbrg(struct udevice *dev, int baudrate)
+{
+       struct ns16550 *const com_port = dev_get_priv(dev);
+       struct ns16550_plat *plat = com_port->plat;
+       int clock_divisor;
+
+       clock_divisor = omap_serial_calc_divisor(com_port, plat->clock, baudrate);
+
+       ns16550_setbrg(com_port, clock_divisor);
+
+       return 0;
+}
+
+const struct dm_serial_ops omap_serial_ops = {
+       .putc = ns16550_serial_putc,
+       .pending = ns16550_serial_pending,
+       .getc = ns16550_serial_getc,
+       .setbrg = omap_serial_setbrg,
+       .setconfig = ns16550_serial_setconfig,
+       .getinfo = ns16550_serial_getinfo,
+};
+
 #if CONFIG_IS_ENABLED(SERIAL_PRESENT)
 U_BOOT_DRIVER(omap_serial) = {
        .name   = "omap_serial",
@@ -162,7 +216,7 @@ U_BOOT_DRIVER(omap_serial) = {
 #endif
        .priv_auto      = sizeof(struct ns16550),
        .probe = ns16550_serial_probe,
-       .ops    = &ns16550_serial_ops,
+       .ops    = &omap_serial_ops,
 #if !CONFIG_IS_ENABLED(OF_CONTROL)
        .flags  = DM_FLAG_PRE_RELOC,
 #endif