[PATCH 0/2] UART support for higher baudrate

The OMAP specific UART driver is changed from a generic implementation of certain ops functions to an OMAP specific implementation of it to add support for higher baudrates for OMAP devices.
Hence to support the above change, static functionality of ops functions in generic ns16550 UART U-Boot driver is removed and also migrated certain macros to its header file for usage in device-specific drivers.
Boot logs link :
https://gist.github.com/GOKU-THUG/8b90117c963e5da5c1b6caeee427c82c
Gokul Praveen (2): serial: ns16550: Increase scope of ops functions drivers: serial: serial_omap: Fix TI OMAP UART U-Boot driver to support higher baudrates
drivers/serial/ns16550.c | 25 ++++++---------- drivers/serial/serial_omap.c | 56 +++++++++++++++++++++++++++++++++++- include/ns16550.h | 18 ++++++++++++ 3 files changed, 81 insertions(+), 18 deletions(-)

Increase scope of ops functions and do some clean up for usage in device -specific UART drivers.
Remove the static functionality of ops functions and migrate certain macros to header file for usage in device-specific drivers.
Signed-off-by: Gokul Praveen g-praveen@ti.com --- drivers/serial/ns16550.c | 25 ++++++++----------------- include/ns16550.h | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 17 deletions(-)
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 3f6860f391..c3b884b6d0 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -12,7 +12,6 @@ #include <log.h> #include <ns16550.h> #include <reset.h> -#include <serial.h> #include <spl.h> #include <watchdog.h> #include <asm/global_data.h> @@ -158,7 +157,7 @@ static inline int serial_in_dynamic(struct ns16550_plat *plat, u8 *addr)
#endif /* CONFIG_NS16550_DYNAMIC */
-static void ns16550_writeb(struct ns16550 *port, int offset, int value) +void ns16550_writeb(struct ns16550 *port, int offset, int value) { struct ns16550_plat *plat = port->plat; unsigned char *addr; @@ -193,13 +192,6 @@ static u32 ns16550_getfcr(struct ns16550 *port) return plat->fcr; }
-/* We can clean these up once everything is moved to driver model */ -#define serial_out(value, addr) \ - ns16550_writeb(com_port, \ - (unsigned char *)addr - (unsigned char *)com_port, value) -#define serial_in(addr) \ - ns16550_readb(com_port, \ - (unsigned char *)addr - (unsigned char *)com_port) #else static u32 ns16550_getfcr(struct ns16550 *port) { @@ -214,7 +206,7 @@ int ns16550_calc_divisor(struct ns16550 *port, int clock, int baudrate) return DIV_ROUND_CLOSEST(clock, mode_x_div * baudrate); }
-static void ns16550_setbrg(struct ns16550 *com_port, int baud_divisor) +void ns16550_setbrg(struct ns16550 *com_port, int baud_divisor) { /* to keep serial format, read lcr before writing BKSE */ int lcr_val = serial_in(&com_port->lcr) & ~UART_LCR_BKSE; @@ -380,7 +372,7 @@ DEBUG_UART_FUNCS #endif
#if CONFIG_IS_ENABLED(DM_SERIAL) -static int ns16550_serial_putc(struct udevice *dev, const char ch) +int ns16550_serial_putc(struct udevice *dev, const char ch) { struct ns16550 *const com_port = dev_get_priv(dev);
@@ -400,7 +392,7 @@ static int ns16550_serial_putc(struct udevice *dev, const char ch) return 0; }
-static int ns16550_serial_pending(struct udevice *dev, bool input) +int ns16550_serial_pending(struct udevice *dev, bool input) { struct ns16550 *const com_port = dev_get_priv(dev);
@@ -410,7 +402,7 @@ static int ns16550_serial_pending(struct udevice *dev, bool input) return (serial_in(&com_port->lsr) & UART_LSR_THRE) ? 0 : 1; }
-static int ns16550_serial_getc(struct udevice *dev) +int ns16550_serial_getc(struct udevice *dev) { struct ns16550 *const com_port = dev_get_priv(dev);
@@ -420,7 +412,7 @@ static int ns16550_serial_getc(struct udevice *dev) return serial_in(&com_port->rbr); }
-static int ns16550_serial_setbrg(struct udevice *dev, int baudrate) +int ns16550_serial_setbrg(struct udevice *dev, int baudrate) { struct ns16550 *const com_port = dev_get_priv(dev); struct ns16550_plat *plat = com_port->plat; @@ -433,7 +425,7 @@ static int ns16550_serial_setbrg(struct udevice *dev, int baudrate) return 0; }
-static int ns16550_serial_setconfig(struct udevice *dev, uint serial_config) +int ns16550_serial_setconfig(struct udevice *dev, uint serial_config) { struct ns16550 *const com_port = dev_get_priv(dev); int lcr_val = UART_LCR_WLS_8; @@ -466,8 +458,7 @@ static int ns16550_serial_setconfig(struct udevice *dev, uint serial_config) return 0; }
-static int ns16550_serial_getinfo(struct udevice *dev, - struct serial_device_info *info) +int ns16550_serial_getinfo(struct udevice *dev, struct serial_device_info *info) { struct ns16550 *const com_port = dev_get_priv(dev); struct ns16550_plat *plat = com_port->plat; diff --git a/include/ns16550.h b/include/ns16550.h index 7f48130008..5d9ff10541 100644 --- a/include/ns16550.h +++ b/include/ns16550.h @@ -25,6 +25,7 @@ #define __ns16550_h
#include <linux/types.h> +#include <serial.h>
#if CONFIG_IS_ENABLED(DM_SERIAL) || defined(CONFIG_NS16550_DYNAMIC) || \ defined(CONFIG_DEBUG_UART) @@ -116,6 +117,15 @@ struct ns16550 { #endif };
+#if CONFIG_IS_ENABLED(DM_SERIAL) +#define serial_out(value, addr) \ + ns16550_writeb(com_port, \ + (unsigned char *)(addr) - (unsigned char *)com_port, value) +#define serial_in(addr) \ + ns16550_readb(com_port, \ + (unsigned char *)(addr) - (unsigned char *)com_port) +#endif + #define thr rbr #define iir fcr #define dll rbr @@ -225,6 +235,14 @@ void ns16550_putc(struct ns16550 *com_port, char c); char ns16550_getc(struct ns16550 *com_port); int ns16550_tstc(struct ns16550 *com_port); void ns16550_reinit(struct ns16550 *com_port, int baud_divisor); +int ns16550_serial_putc(struct udevice *dev, const char ch); +int ns16550_serial_pending(struct udevice *dev, bool input); +int ns16550_serial_getc(struct udevice *dev); +int ns16550_serial_setbrg(struct udevice *dev, int baudrate); +int ns16550_serial_setconfig(struct udevice *dev, uint serial_config); +int ns16550_serial_getinfo(struct udevice *dev, struct serial_device_info *info); +void ns16550_writeb(struct ns16550 *port, int offset, int value); +void ns16550_setbrg(struct ns16550 *com_port, int baud_divisor);
/** * ns16550_calc_divisor() - calculate the divisor given clock and baud rate

On Tue, 26 Nov 2024 at 03:51, Gokul Praveen g-praveen@ti.com wrote:
Increase scope of ops functions and do some clean up for usage in device -specific UART drivers.
Remove the static functionality of ops functions and migrate certain macros to header file for usage in device-specific drivers.
Signed-off-by: Gokul Praveen g-praveen@ti.com
drivers/serial/ns16550.c | 25 ++++++++----------------- include/ns16550.h | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 17 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

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 --- drivers/serial/serial_omap.c | 56 +++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c index 94672655c2..224d9cbf29 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

On Tue, 26 Nov 2024 at 03:51, Gokul Praveen g-praveen@ti.com wrote:
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
drivers/serial/serial_omap.c | 56 +++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

On Tue, 26 Nov 2024 16:21:29 +0530, Gokul Praveen wrote:
The OMAP specific UART driver is changed from a generic implementation of certain ops functions to an OMAP specific implementation of it to add support for higher baudrates for OMAP devices.
Hence to support the above change, static functionality of ops functions in generic ns16550 UART U-Boot driver is removed and also migrated certain macros to its header file for usage in device-specific drivers.
[...]
Applied to u-boot/next, thanks!
participants (3)
-
Gokul Praveen
-
Simon Glass
-
Tom Rini