serial: dm: Add support for puts
authorSean Anderson <sean.anderson@seco.com>
Tue, 22 Mar 2022 20:59:34 +0000 (16:59 -0400)
committerTom Rini <trini@konsulko.com>
Fri, 1 Apr 2022 20:56:54 +0000 (16:56 -0400)
Some serial drivers can be vastly more efficient when printing multiple
characters at once. Non-DM serial has had a puts option for these sorts
of drivers; implement it for DM serial as well.

Because we have to add carriage returns, we can't just pass the whole
string directly to the serial driver. Instead, we print up to the
newline, then print a carriage return, and then continue on. This is
less efficient, but it is better than printing each character
individually. It also avoids having to allocate memory just to add a few
characters.

Drivers may perform short writes (such as filling a FIFO) and return the
number of characters written in len. We loop over them in the same way
that _serial_putc loops over putc.

This results in around sizeof(void *) growth for all boards with
DM_SERIAL. The full implementation takes around 140 bytes.

Signed-off-by: Sean Anderson <sean.anderson@seco.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/serial/Kconfig
drivers/serial/serial-uclass.c
include/serial.h

index a07fab225fd457f44b216d024807818e72b0f268..76171e7146a7cf7baf1ae8d593da3d46aaae2429 100644 (file)
@@ -133,6 +133,19 @@ config SERIAL_RX_BUFFER_SIZE
        help
          The size of the RX buffer (needs to be power of 2)
 
+config SERIAL_PUTS
+       bool "Enable printing strings all at once"
+       depends on DM_SERIAL
+       help
+         Some serial drivers are much more efficient when printing multiple
+         characters at once rather than printing characters individually. This
+         can be because they can load a fifo, or because individual print
+         calls have a constant overhead. With this option set, the serial
+         subsystem will try to provide serial drivers with as many characters
+         at once as possible, instead of printing characters one by one. Most
+         serial drivers do not need this config to print efficiently. If
+         unsure, say N.
+
 config SERIAL_SEARCH_ALL
        bool "Search for serial devices after default one failed"
        depends on DM_SERIAL
index f30f352bd7a6ad9a8c3aee34e1c5c0ec7bfae5a9..10d6b800e2f8261564889c81919f062539ce713c 100644 (file)
@@ -200,8 +200,30 @@ static void _serial_putc(struct udevice *dev, char ch)
 
 static void _serial_puts(struct udevice *dev, const char *str)
 {
-       while (*str)
-               _serial_putc(dev, *str++);
+       struct dm_serial_ops *ops = serial_get_ops(dev);
+
+       if (!CONFIG_IS_ENABLED(SERIAL_PUTS) || !ops->puts) {
+               while (*str)
+                       _serial_putc(dev, *str++);
+               return;
+       }
+
+       do {
+               const char *newline = strchrnul(str, '\n');
+               size_t len = newline - str + !!*newline;
+
+               do {
+                       ssize_t written = ops->puts(dev, str, len);
+
+                       if (written < 0)
+                               return;
+                       str += written;
+                       len -= written;
+               } while (len);
+
+               if (*newline)
+                       _serial_putc(dev, '\r');
+       } while (*str);
 }
 
 static int __serial_getc(struct udevice *dev)
index 2681d26c829daafec59a0118ad7f310eba7d8ad7..8c2e7adbc3215a0b87103c413a1c852c7305d462 100644 (file)
@@ -195,6 +195,24 @@ struct dm_serial_ops {
         * @return 0 if OK, -ve on error
         */
        int (*putc)(struct udevice *dev, const char ch);
+       /**
+        * puts() - Write a string
+        *
+        * This writes a string. This function should be implemented only if
+        * writing multiple characters at once is more performant than just
+        * calling putc() in a loop.
+        *
+        * If the whole string cannot be written at once, then this function
+        * should return the number of characters written. Returning a negative
+        * error code implies that no characters were written. If this function
+        * returns 0, then it will be called again with the same arguments.
+        *
+        * @dev: Device pointer
+        * @s: The string to write
+        * @len: The length of the string to write.
+        * @return The number of characters written on success, or -ve on error
+        */
+       ssize_t (*puts)(struct udevice *dev, const char *s, size_t len);
        /**
         * pending() - Check if input/output characters are waiting
         *