diff options
author | Simon Glass <sjg@chromium.org> | 2014-10-29 13:09:03 -0600 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2014-11-21 08:10:16 +0100 |
commit | ad1b81c88080580b5db8b89c5a3b29d85a7488fc (patch) | |
tree | db0219dad2135d3d256bb233103b64e52ebd97d1 /drivers | |
parent | e87e0e79edf8173fe3551eed53a3bc60aa927b0c (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.c | 67 |
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; |