summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2014-10-29 13:09:03 -0600
committerSimon Glass <sjg@chromium.org>2014-11-21 08:10:16 +0100
commitad1b81c88080580b5db8b89c5a3b29d85a7488fc (patch)
treedb0219dad2135d3d256bb233103b64e52ebd97d1 /drivers
parente87e0e79edf8173fe3551eed53a3bc60aa927b0c (diff)
dm: serial: Support changing the baud rate
Implement this feature in the uclass so that the baudrate can be changed with 'setenv baudrate <rate>'. Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/serial/serial-uclass.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 71f1a5cb91..632933f5cc 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <dm.h>
+#include <environment.h>
#include <errno.h>
#include <fdtdec.h>
#include <os.h>
@@ -22,6 +23,11 @@ DECLARE_GLOBAL_DATA_PTR;
/* The currently-selected console serial device */
struct udevice *cur_dev __attribute__ ((section(".data")));
+/*
+ * Table with supported baudrates (defined in config_xyz.h)
+ */
+static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
+
#ifndef CONFIG_SYS_MALLOC_F_LEN
#error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work"
#endif
@@ -177,6 +183,67 @@ int serial_stub_tstc(struct stdio_dev *sdev)
return _serial_tstc(sdev->priv);
}
+/**
+ * on_baudrate() - Update the actual baudrate when the env var changes
+ *
+ * This will check for a valid baudrate and only apply it if valid.
+ */
+static int on_baudrate(const char *name, const char *value, enum env_op op,
+ int flags)
+{
+ int i;
+ int baudrate;
+
+ switch (op) {
+ case env_op_create:
+ case env_op_overwrite:
+ /*
+ * Switch to new baudrate if new baudrate is supported
+ */
+ baudrate = simple_strtoul(value, NULL, 10);
+
+ /* Not actually changing */
+ if (gd->baudrate == baudrate)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
+ if (baudrate == baudrate_table[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(baudrate_table)) {
+ if ((flags & H_FORCE) == 0)
+ printf("## Baudrate %d bps not supported\n",
+ baudrate);
+ return 1;
+ }
+ if ((flags & H_INTERACTIVE) != 0) {
+ printf("## Switch baudrate to %d bps and press ENTER ...\n",
+ baudrate);
+ udelay(50000);
+ }
+
+ gd->baudrate = baudrate;
+
+ serial_setbrg();
+
+ udelay(50000);
+
+ if ((flags & H_INTERACTIVE) != 0)
+ while (1) {
+ if (getc() == '\r')
+ break;
+ }
+
+ return 0;
+ case env_op_delete:
+ printf("## Baudrate may not be deleted\n");
+ return 1;
+ default:
+ return 0;
+ }
+}
+U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
+
static int serial_post_probe(struct udevice *dev)
{
struct stdio_dev sdev;