powerpc: Migrate SYS_L3_SIZE to Kconfig
[platform/kernel/u-boot.git] / common / console.c
index 5b113da..0c9bf66 100644 (file)
@@ -7,6 +7,7 @@
 #include <common.h>
 #include <console.h>
 #include <debug_uart.h>
+#include <display_options.h>
 #include <dm.h>
 #include <env.h>
 #include <stdarg.h>
@@ -19,6 +20,7 @@
 #include <exports.h>
 #include <env_internal.h>
 #include <watchdog.h>
+#include <asm/global_data.h>
 #include <linux/delay.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -94,16 +96,22 @@ static void console_record_putc(const char c)
 {
        if (!(gd->flags & GD_FLG_RECORD))
                return;
-       if  (gd->console_out.start)
-               membuff_putbyte((struct membuff *)&gd->console_out, c);
+       if  (gd->console_out.start &&
+            !membuff_putbyte((struct membuff *)&gd->console_out, c))
+               gd->flags |= GD_FLG_RECORD_OVF;
 }
 
 static void console_record_puts(const char *s)
 {
        if (!(gd->flags & GD_FLG_RECORD))
                return;
-       if  (gd->console_out.start)
-               membuff_put((struct membuff *)&gd->console_out, s, strlen(s));
+       if  (gd->console_out.start) {
+               int len = strlen(s);
+
+               if (membuff_put((struct membuff *)&gd->console_out, s, len) !=
+                   len)
+                       gd->flags |= GD_FLG_RECORD_OVF;
+       }
 }
 
 static int console_record_getc(void)
@@ -191,6 +199,7 @@ static int console_setfile(int file, struct stdio_dev * dev)
                case stdout:
                        gd->jt->putc  = putc;
                        gd->jt->puts  = puts;
+                       STDIO_DEV_ASSIGN_FLUSH(gd->jt, flush);
                        gd->jt->printf = printf;
                        break;
                }
@@ -206,7 +215,7 @@ static int console_setfile(int file, struct stdio_dev * dev)
  * console_dev_is_serial() - Check if a stdio device is a serial device
  *
  * @sdev: Device to check
- * @return true if this device is in the serial uclass (or for pre-driver-model,
+ * Return: true if this device is in the serial uclass (or for pre-driver-model,
  * whether it is called "serial".
  */
 static bool console_dev_is_serial(struct stdio_dev *sdev)
@@ -232,9 +241,35 @@ static struct stdio_dev *tstcdev;
 struct stdio_dev **console_devices[MAX_FILES];
 int cd_count[MAX_FILES];
 
-static void __maybe_unused console_devices_set(int file, struct stdio_dev *dev)
+static void console_devices_set(int file, struct stdio_dev *dev)
 {
        console_devices[file][0] = dev;
+       cd_count[file] = 1;
+}
+
+/**
+ * console_needs_start_stop() - check if we need to start or stop the STDIO device
+ * @file: STDIO file
+ * @sdev: STDIO device in question
+ *
+ * This function checks if we need to start or stop the stdio device used for
+ * a console. For IOMUX case it simply enforces one time start and one time
+ * stop of the device independently of how many STDIO files are using it. In
+ * other words, we start console once before first STDIO device wants it and
+ * stop after the last is gone.
+ */
+static bool console_needs_start_stop(int file, struct stdio_dev *sdev)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(cd_count); i++) {
+               if (i == file)
+                       continue;
+
+               if (iomux_match_device(console_devices[i], cd_count[i], sdev) >= 0)
+                       return false;
+       }
+       return true;
 }
 
 /*
@@ -266,8 +301,7 @@ static int console_tstc(int file)
        int prev;
 
        prev = disable_ctrlc(1);
-       for (i = 0; i < cd_count[file]; i++) {
-               dev = console_devices[file][i];
+       for_each_console_dev(i, file, dev) {
                if (dev->tstc != NULL) {
                        ret = dev->tstc(dev);
                        if (ret > 0) {
@@ -287,8 +321,7 @@ static void console_putc(int file, const char c)
        int i;
        struct stdio_dev *dev;
 
-       for (i = 0; i < cd_count[file]; i++) {
-               dev = console_devices[file][i];
+       for_each_console_dev(i, file, dev) {
                if (dev->putc != NULL)
                        dev->putc(dev, c);
        }
@@ -307,11 +340,9 @@ static void console_puts_select(int file, bool serial_only, const char *s)
        int i;
        struct stdio_dev *dev;
 
-       for (i = 0; i < cd_count[file]; i++) {
-               bool is_serial;
+       for_each_console_dev(i, file, dev) {
+               bool is_serial = console_dev_is_serial(dev);
 
-               dev = console_devices[file][i];
-               is_serial = console_dev_is_serial(dev);
                if (dev->puts && serial_only == is_serial)
                        dev->puts(dev, s);
        }
@@ -319,7 +350,8 @@ static void console_puts_select(int file, bool serial_only, const char *s)
 
 void console_puts_select_stderr(bool serial_only, const char *s)
 {
-       console_puts_select(stderr, serial_only, s);
+       if (gd->flags & GD_FLG_DEVINIT)
+               console_puts_select(stderr, serial_only, s);
 }
 
 static void console_puts(int file, const char *s)
@@ -327,13 +359,25 @@ static void console_puts(int file, const char *s)
        int i;
        struct stdio_dev *dev;
 
-       for (i = 0; i < cd_count[file]; i++) {
-               dev = console_devices[file][i];
+       for_each_console_dev(i, file, dev) {
                if (dev->puts != NULL)
                        dev->puts(dev, s);
        }
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+static void console_flush(int file)
+{
+       int i;
+       struct stdio_dev *dev;
+
+       for_each_console_dev(i, file, dev) {
+               if (dev->flush != NULL)
+                       dev->flush(dev);
+       }
+}
+#endif
+
 #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
 static inline void console_doenv(int file, struct stdio_dev *dev)
 {
@@ -342,8 +386,13 @@ static inline void console_doenv(int file, struct stdio_dev *dev)
 #endif
 #else
 
-static void __maybe_unused console_devices_set(int file, struct stdio_dev *dev)
+static void console_devices_set(int file, struct stdio_dev *dev)
+{
+}
+
+static inline bool console_needs_start_stop(int file, struct stdio_dev *sdev)
 {
+       return true;
 }
 
 static inline int console_getc(int file)
@@ -368,7 +417,8 @@ static inline void console_putc(int file, const char c)
 
 void console_puts_select(int file, bool serial_only, const char *s)
 {
-       if (serial_only == console_dev_is_serial(stdio_devices[file]))
+       if ((gd->flags & GD_FLG_DEVINIT) &&
+           serial_only == console_dev_is_serial(stdio_devices[file]))
                stdio_devices[file]->puts(stdio_devices[file], s);
 }
 
@@ -377,6 +427,14 @@ static inline void console_puts(int file, const char *s)
        stdio_devices[file]->puts(stdio_devices[file], s);
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+static inline void console_flush(int file)
+{
+       if (stdio_devices[file]->flush)
+               stdio_devices[file]->flush(stdio_devices[file]);
+}
+#endif
+
 #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
 static inline void console_doenv(int file, struct stdio_dev *dev)
 {
@@ -385,10 +443,19 @@ static inline void console_doenv(int file, struct stdio_dev *dev)
 #endif
 #endif /* CONIFIG_IS_ENABLED(CONSOLE_MUX) */
 
+static void __maybe_unused console_setfile_and_devices(int file, struct stdio_dev *dev)
+{
+       console_setfile(file, dev);
+       console_devices_set(file, dev);
+}
+
 int console_start(int file, struct stdio_dev *sdev)
 {
        int error;
 
+       if (!console_needs_start_stop(file, sdev))
+               return 0;
+
        /* Start new device */
        if (sdev->start) {
                error = sdev->start(sdev);
@@ -401,6 +468,9 @@ int console_start(int file, struct stdio_dev *sdev)
 
 void console_stop(int file, struct stdio_dev *sdev)
 {
+       if (!console_needs_start_stop(file, sdev))
+               return;
+
        if (sdev->stop)
                sdev->stop(sdev);
 }
@@ -432,7 +502,7 @@ int fgetc(int file)
                 * Effectively poll for input wherever it may be available.
                 */
                for (;;) {
-                       WATCHDOG_RESET();
+                       schedule();
                        if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
                                /*
                                 * Upper layer may have already called tstc() so
@@ -478,6 +548,14 @@ void fputs(int file, const char *s)
                console_puts(file, s);
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void fflush(int file)
+{
+       if (file < MAX_FILES)
+               console_flush(file);
+}
+#endif
+
 int fprintf(int file, const char *fmt, ...)
 {
        va_list args;
@@ -546,13 +624,16 @@ int tstc(void)
 #define PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL  1
 
 #if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
-#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_PRE_CON_BUF_SZ)
+#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_VAL(PRE_CON_BUF_SZ))
 
 static void pre_console_putc(const char c)
 {
        char *buffer;
 
-       buffer = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ);
+       if (gd->precon_buf_idx < 0)
+               return;
+
+       buffer = map_sysmem(CONFIG_VAL(PRE_CON_BUF_ADDR), CONFIG_VAL(PRE_CON_BUF_SZ));
 
        buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c;
 
@@ -561,22 +642,25 @@ static void pre_console_putc(const char c)
 
 static void pre_console_puts(const char *s)
 {
+       if (gd->precon_buf_idx < 0)
+               return;
+
        while (*s)
                pre_console_putc(*s++);
 }
 
 static void print_pre_console_buffer(int flushpoint)
 {
-       unsigned long in = 0, out = 0;
-       char buf_out[CONFIG_PRE_CON_BUF_SZ + 1];
+       long in = 0, out = 0;
+       char buf_out[CONFIG_VAL(PRE_CON_BUF_SZ) + 1];
        char *buf_in;
 
        if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
                return;
 
-       buf_in = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ);
-       if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ)
-               in = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ;
+       buf_in = map_sysmem(CONFIG_VAL(PRE_CON_BUF_ADDR), CONFIG_VAL(PRE_CON_BUF_SZ));
+       if (gd->precon_buf_idx > CONFIG_VAL(PRE_CON_BUF_SZ))
+               in = gd->precon_buf_idx - CONFIG_VAL(PRE_CON_BUF_SZ);
 
        while (in < gd->precon_buf_idx)
                buf_out[out++] = buf_in[CIRC_BUF_IDX(in++)];
@@ -584,6 +668,7 @@ static void print_pre_console_buffer(int flushpoint)
 
        buf_out[out] = 0;
 
+       gd->precon_buf_idx = -1;
        switch (flushpoint) {
        case PRE_CONSOLE_FLUSHPOINT1_SERIAL:
                puts(buf_out);
@@ -592,6 +677,7 @@ static void print_pre_console_buffer(int flushpoint)
                console_puts_select(stdout, false, buf_out);
                break;
        }
+       gd->precon_buf_idx = in;
 }
 #else
 static inline void pre_console_putc(const char c) {}
@@ -684,13 +770,49 @@ void puts(const char *s)
        }
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void flush(void)
+{
+       if (!gd)
+               return;
+
+       /* sandbox can send characters to stdout before it has a console */
+       if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
+               os_flush();
+               return;
+       }
+
+       if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY))
+               return;
+
+       if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
+               return;
+
+       if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
+               return;
+
+       if (!gd->have_console)
+               return;
+
+       if (gd->flags & GD_FLG_DEVINIT) {
+               /* Send to the standard output */
+               fflush(stdout);
+       } else {
+               /* Send directly to the handler */
+               serial_flush();
+       }
+}
+#endif
+
 #ifdef CONFIG_CONSOLE_RECORD
 int console_record_init(void)
 {
        int ret;
 
        ret = membuff_new((struct membuff *)&gd->console_out,
-                         CONFIG_CONSOLE_RECORD_OUT_SIZE);
+                         gd->flags & GD_FLG_RELOC ?
+                                 CONFIG_CONSOLE_RECORD_OUT_SIZE :
+                                 CONFIG_CONSOLE_RECORD_OUT_SIZE_F);
        if (ret)
                return ret;
        ret = membuff_new((struct membuff *)&gd->console_in,
@@ -703,6 +825,7 @@ void console_record_reset(void)
 {
        membuff_purge((struct membuff *)&gd->console_out);
        membuff_purge((struct membuff *)&gd->console_in);
+       gd->flags &= ~GD_FLG_RECORD_OVF;
 }
 
 int console_record_reset_enable(void)
@@ -715,6 +838,9 @@ int console_record_reset_enable(void)
 
 int console_record_readline(char *str, int maxlen)
 {
+       if (gd->flags & GD_FLG_RECORD_OVF)
+               return -ENOSPC;
+
        return membuff_readline((struct membuff *)&gd->console_out, str,
                                maxlen, ' ');
 }
@@ -724,6 +850,11 @@ int console_record_avail(void)
        return membuff_avail((struct membuff *)&gd->console_out);
 }
 
+int console_in_puts(const char *str)
+{
+       return membuff_put((struct membuff *)&gd->console_in, str, strlen(str));
+}
+
 #endif
 
 /* test if ctrl-c was pressed */
@@ -795,7 +926,7 @@ void clear_ctrlc(void)
 
 /** U-Boot INIT FUNCTIONS *************************************************/
 
-struct stdio_dev *search_device(int flags, const char *name)
+struct stdio_dev *console_search_dev(int flags, const char *name)
 {
        struct stdio_dev *dev;
 
@@ -817,21 +948,13 @@ int console_assign(int file, const char *devname)
        struct stdio_dev *dev;
 
        /* Check for valid file */
-       switch (file) {
-       case stdin:
-               flag = DEV_FLAGS_INPUT;
-               break;
-       case stdout:
-       case stderr:
-               flag = DEV_FLAGS_OUTPUT;
-               break;
-       default:
-               return -1;
-       }
+       flag = stdio_file_to_flags(file);
+       if (flag < 0)
+               return flag;
 
        /* Check for valid device name */
 
-       dev = search_device(flag, devname);
+       dev = console_search_dev(flag, devname);
 
        if (dev)
                return console_setfile(file, dev);
@@ -937,9 +1060,9 @@ int console_init_r(void)
        stderrname = env_get("stderr");
 
        if (OVERWRITE_CONSOLE == 0) {   /* if not overwritten by config switch */
-               inputdev  = search_device(DEV_FLAGS_INPUT,  stdinname);
-               outputdev = search_device(DEV_FLAGS_OUTPUT, stdoutname);
-               errdev    = search_device(DEV_FLAGS_OUTPUT, stderrname);
+               inputdev  = console_search_dev(DEV_FLAGS_INPUT,  stdinname);
+               outputdev = console_search_dev(DEV_FLAGS_OUTPUT, stdoutname);
+               errdev    = console_search_dev(DEV_FLAGS_OUTPUT, stderrname);
                if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
                        iomux_err = iomux_doenv(stdin, stdinname);
                        iomux_err += iomux_doenv(stdout, stdoutname);
@@ -951,13 +1074,13 @@ int console_init_r(void)
        }
        /* if the devices are overwritten or not found, use default device */
        if (inputdev == NULL) {
-               inputdev  = search_device(DEV_FLAGS_INPUT,  "serial");
+               inputdev  = console_search_dev(DEV_FLAGS_INPUT,  "serial");
        }
        if (outputdev == NULL) {
-               outputdev = search_device(DEV_FLAGS_OUTPUT, "serial");
+               outputdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
        }
        if (errdev == NULL) {
-               errdev    = search_device(DEV_FLAGS_OUTPUT, "serial");
+               errdev    = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
        }
        /* Initializes output console first */
        if (outputdev != NULL) {
@@ -992,11 +1115,6 @@ done:
 
        gd->flags |= GD_FLG_DEVINIT;    /* device initialization completed */
 
-#if 0
-       /* If nothing usable installed, use only the initial console */
-       if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
-               return 0;
-#endif
        print_pre_console_buffer(flushpoint);
        return 0;
 }
@@ -1027,7 +1145,7 @@ int console_init_r(void)
         */
        if (IS_ENABLED(CONFIG_SPLASH_SCREEN) && env_get("splashimage")) {
                if (!(gd->flags & GD_FLG_SILENT))
-                       outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
+                       outputdev = console_search_dev (DEV_FLAGS_OUTPUT, "serial");
        }
 
        /* Scan devices looking for input and output devices */
@@ -1046,17 +1164,13 @@ int console_init_r(void)
 
        /* Initializes output console first */
        if (outputdev != NULL) {
-               console_setfile(stdout, outputdev);
-               console_setfile(stderr, outputdev);
-               console_devices_set(stdout, outputdev);
-               console_devices_set(stderr, outputdev);
+               console_setfile_and_devices(stdout, outputdev);
+               console_setfile_and_devices(stderr, outputdev);
        }
 
        /* Initializes input console */
-       if (inputdev != NULL) {
-               console_setfile(stdin, inputdev);
-               console_devices_set(stdin, inputdev);
-       }
+       if (inputdev != NULL)
+               console_setfile_and_devices(stdin, inputdev);
 
        if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET))
                stdio_print_current_devices();
@@ -1068,11 +1182,6 @@ int console_init_r(void)
 
        gd->flags |= GD_FLG_DEVINIT;    /* device initialization completed */
 
-#if 0
-       /* If nothing usable installed, use only the initial console */
-       if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
-               return 0;
-#endif
        print_pre_console_buffer(flushpoint);
        return 0;
 }