changeset 37:437f9365249c

loadagent: baud rate switching implemented
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Mon, 13 May 2013 06:56:54 +0000
parents 65111e6eee9e
children 5b3d7398d2d9
files target-utils/libcommon/Makefile target-utils/libcommon/cmd_baud_switch.c target-utils/loadagent/cmdtab.c
diffstat 3 files changed, 116 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/target-utils/libcommon/Makefile	Mon May 06 02:04:56 2013 +0000
+++ b/target-utils/libcommon/Makefile	Mon May 13 06:56:54 2013 +0000
@@ -5,7 +5,8 @@
 RANLIB=	arm-elf-ranlib
 
 OBJS=	cmdentry.o dispatch.o hexarg.o parseargs.o serio.o serflush.o uartsel.o\
-	cmd_jump.o cmd_r8.o cmd_r16.o cmd_r32.o cmd_w8.o cmd_w16.o cmd_w32.o
+	cmd_baud_switch.o cmd_jump.o cmd_r8.o cmd_r16.o cmd_r32.o cmd_w8.o \
+	cmd_w16.o cmd_w32.o
 
 all:	libcommon.a
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target-utils/libcommon/cmd_baud_switch.c	Mon May 13 06:56:54 2013 +0000
@@ -0,0 +1,112 @@
+/*
+ * Baud rate switching command
+ */
+
+#include <stdlib.h>
+#include "types.h"
+#include "ns16550.h"
+
+extern struct ns16550_regs *uart_base;
+extern int serial_in_poll();
+
+static const struct tab {
+	int baud;
+	int divisor;
+} rate_table[] = {
+	/*
+	 * First support the rates and divisors implemented by the
+	 * Calypso boot ROM.  Dividing 13 MHz by 7 gives an approximation
+	 * of 115200 (x16); the divisors used by the boot ROM code for
+	 * the slower baud rates are all 7x the usual PC value.
+	 */
+	{115200, 7},
+	{57600, 7 * 2},
+	{38400, 7 * 3},
+	{28800, 7 * 4},
+	{19200, 7 * 6},
+	/*
+	 * Going faster than ~115200 baud means using a divisor
+	 * less than 7, resulting in a non-standard baud rate.
+	 * The /1, /2 and /4 seem like reasonable choices.
+	 */
+	{812500, 1},
+	{406250, 2},
+	{203125, 4},
+	/* that's all we really need to support */
+	{0, 0}
+};
+
+/*
+ * The following helper function actually switches the UART
+ * baud rate divisor.  Call serial_flush() first.  It returns the
+ * old divisor value.
+ *
+ * Note the u8 type for both the new and old divisor values.
+ * All supported divisors are well below 255, so we don't bother
+ * with the upper byte.
+ */
+static u8
+actually_switch_baud(newdiv)
+	u8 newdiv;
+{
+	volatile struct ns16550_regs *regs;
+	u8 save_lcr, save_old_baud;
+
+	regs = uart_base;
+	save_lcr = regs->lcr;
+	regs->lcr = save_lcr | NS16550_LCR_DLAB;
+	save_old_baud = regs->datareg;
+	regs->datareg = newdiv;
+	regs->lcr = save_lcr;
+	return(save_old_baud);
+}
+
+void
+cmd_baud_switch(argbulk)
+	char *argbulk;
+{
+	char *argv[2];
+	int baudarg;
+	struct tab *tp;
+	u8 save_old_baud;
+	int c;
+
+	if (parse_args(argbulk, 1, 1, argv, 0) < 0)
+		return;
+	baudarg = atoi(argv[0]);
+	for (tp = rate_table; tp->baud; tp++)
+		if (tp->baud == baudarg)
+			break;
+	if (!tp->baud) {
+		printf("ERROR: invalid/unimplemented baud rate argument\n");
+		return;
+	}
+
+	/* do it */
+	serial_flush();
+	save_old_baud = actually_switch_baud(tp->divisor);
+
+	/*
+	 * After getting the echo of this command at the old baud rate
+	 * (see the serial flush call just before switching the divisor),
+	 * the line will go silent from the user's perspective.
+	 * The user should wait just a little bit, then send us a 0x55 ('U')
+	 * at the new baud rate - we should be in the below loop waiting
+	 * for this character by then.  Receiving that character
+	 * correctly (0x55 was chosen for the bit pattern - unlikely to
+	 * be received if the sender is sending at a wrong baud rate)
+	 * will cause us to conclude this command and return a new '='
+	 * prompt at the new baud rate.
+	 *
+	 * If we get something else, we assume that someone messed up,
+	 * switch back to the old baud rate, scribble an error message
+	 * and return.
+	 */
+	do
+		c = serial_in_poll();
+	while (c < 0);
+	if (c != 0x55) {
+	  actually_switch_baud(save_old_baud);
+	  printf("ERROR: no \'U\' received, switched back to old baud rate\n");
+	}
+}
--- a/target-utils/loadagent/cmdtab.c	Mon May 06 02:04:56 2013 +0000
+++ b/target-utils/loadagent/cmdtab.c	Mon May 13 06:56:54 2013 +0000
@@ -9,11 +9,13 @@
 extern void cmd_w16();
 extern void cmd_w32();
 
+extern void cmd_baud_switch();
 extern void cmd_memdump_human();
 extern void cmd_memdump_machine();
 
 const struct cmdtab cmdtab[] = {
 	{"DUMP", cmd_memdump_machine},
+	{"baud", cmd_baud_switch},
 	{"crc32", cmd_crc32},
 	{"dump", cmd_memdump_human},
 	{"jump", cmd_jump},