]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
serial: implement common uart post test
authorMike Frysinger <vapier@gentoo.org>
Sat, 14 May 2011 06:56:15 +0000 (06:56 +0000)
committerWolfgang Denk <wd@denx.de>
Tue, 26 Jul 2011 14:39:03 +0000 (16:39 +0200)
The current arch/driver specific UART posts basically boil down to setting
the UART to loop back mode, then reading and writing data.  If we ignore
the loop back part, the rest can be built upon the existing common serial
API.  So let's do just that.

First add a call back for serial drivers to implement loop back control.
Then write a post test that walks all of the serial drivers, puts them
into loop back mode, and verifies that reading/writing at all the diff
baud rates is OK.

If a serial driver doesn't support loop back mode (either it can't or
it hasn't done so yet), then skip it.  This should allow for people to
easily migrate to the new post test with existing serial drivers.

I haven't touched the few already existing uart post tests as I don't
the hardware or knowledge of converting them over.  So I've marked the
new test as weak which will allow the existing tests to override the
default until they are converted.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
common/serial.c
include/serial.h

index bf7740950fd339ed20275f675e93f9acf3965d36..748e5d5b10b2f0b4ab1b29e6ad5c15efca52fa66 100644 (file)
@@ -24,6 +24,8 @@
 #include <common.h>
 #include <serial.h>
 #include <stdio_dev.h>
+#include <post.h>
+#include <linux/compiler.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -221,3 +223,91 @@ void serial_puts (const char *s)
 
        serial_current->puts (s);
 }
+
+#if CONFIG_POST & CONFIG_SYS_POST_UART
+static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE;
+
+/* Mark weak until post/cpu/.../uart.c migrate over */
+__weak
+int uart_post_test(int flags)
+{
+       unsigned char c;
+       int ret, saved_baud, b;
+       struct serial_device *saved_dev, *s;
+       bd_t *bd = gd->bd;
+
+       /* Save current serial state */
+       ret = 0;
+       saved_dev = serial_current;
+       saved_baud = bd->bi_baudrate;
+
+       for (s = serial_devices; s; s = s->next) {
+               /* If this driver doesn't support loop back, skip it */
+               if (!s->loop)
+                       continue;
+
+               /* Test the next device */
+               serial_current = s;
+
+               ret = serial_init();
+               if (ret)
+                       goto done;
+
+               /* Consume anything that happens to be queued */
+               while (serial_tstc())
+                       serial_getc();
+
+               /* Enable loop back */
+               s->loop(1);
+
+               /* Test every available baud rate */
+               for (b = 0; b < ARRAY_SIZE(bauds); ++b) {
+                       bd->bi_baudrate = bauds[b];
+                       serial_setbrg();
+
+                       /*
+                        * Stick to printable chars to avoid issues:
+                        *  - terminal corruption
+                        *  - serial program reacting to sequences and sending
+                        *    back random extra data
+                        *  - most serial drivers add in extra chars (like \r\n)
+                        */
+                       for (c = 0x20; c < 0x7f; ++c) {
+                               /* Send it out */
+                               serial_putc(c);
+
+                               /* Make sure it's the same one */
+                               ret = (c != serial_getc());
+                               if (ret) {
+                                       s->loop(0);
+                                       goto done;
+                               }
+
+                               /* Clean up the output in case it was sent */
+                               serial_putc('\b');
+                               ret = ('\b' != serial_getc());
+                               if (ret) {
+                                       s->loop(0);
+                                       goto done;
+                               }
+                       }
+               }
+
+               /* Disable loop back */
+               s->loop(0);
+
+               /* XXX: There is no serial_uninit() !? */
+               if (s->uninit)
+                       s->uninit();
+       }
+
+ done:
+       /* Restore previous serial state */
+       serial_current = saved_dev;
+       bd->bi_baudrate = saved_baud;
+       serial_reinit_all();
+       serial_setbrg();
+
+       return ret;
+}
+#endif
index e6d3859bd929dc734b5c9b51eb29fada40c680c9..08d106a7c05870516e640809a4d14cc340ebb433 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __SERIAL_H__
 #define __SERIAL_H__
 
+#include <post.h>
+
 #define NAMESIZE 16
 
 struct serial_device {
@@ -13,6 +15,9 @@ struct serial_device {
        int (*tstc) (void);
        void (*putc) (const char c);
        void (*puts) (const char *s);
+#if CONFIG_POST & CONFIG_SYS_POST_UART
+       void (*loop) (int);
+#endif
 
        struct serial_device *next;
 };