aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGokul Praveen <g-praveen@ti.com>2024-11-26 16:21:31 +0530
committerTom Rini <trini@konsulko.com>2024-12-14 09:32:59 -0600
commit50cc0c16b7cc3a3a6d8bca646678e14aaa7cc794 (patch)
tree1bd216a5d7ecf31ef35f8b49988bb500c122ba03
parenta9c61ac04fdef8de7842456ff597db375f8b48d8 (diff)
downloadu-boot-50cc0c16b7cc3a3a6d8bca646678e14aaa7cc794.tar.gz
drivers: serial: serial_omap: Fix TI OMAP UART U-Boot driver to support higher baudrates
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>
-rw-r--r--drivers/serial/serial_omap.c56
1 files changed, 55 insertions, 1 deletions
diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c
index 94672655c28..224d9cbf29d 100644
--- a/drivers/serial/serial_omap.c
+++ b/drivers/serial/serial_omap.c
@@ -15,6 +15,12 @@
#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