2 * (C) Copyright 2000-2004
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * See file CREDITS for list of people who contributed to this
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * Serial up- and download support
34 DECLARE_GLOBAL_DATA_PTR;
36 #if defined(CONFIG_CMD_LOADB)
37 static ulong load_serial_ymodem(ulong offset);
40 #if defined(CONFIG_CMD_LOADS)
41 static ulong load_serial(ulong offset);
42 static int read_record(char *buf, ulong len);
44 #if defined(CONFIG_CMD_SAVES)
45 static int save_serial(ulong offset, ulong size);
46 static int write_record(char *buf);
47 #endif /* CONFIG_CMD_SAVES */
49 static int do_echo = 1;
50 #endif /* CONFIG_CMD_LOADS */
52 #if defined(CONFIG_CMD_LOADB) ||\
53 defined(CONFIG_CMD_LOADS) ||\
54 defined(CONFIG_CMD_SAVES)
55 static const unsigned long baudrate_table[] = CFG_BAUDRATE_TABLE;
56 #define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
58 static void switch_baudrate(int baudrate, int back)
60 printf("Switch%s baudrate to %d bps and press ENTER...\n", back > 0 ? " back" : "", baudrate);
63 gd->baudrate = baudrate;
76 /* -------------------------------------------------------------------- */
78 #if defined(CONFIG_CMD_LOADS)
79 int do_load_serial(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
86 int load_baudrate, current_baudrate;
88 load_baudrate = current_baudrate = gd->baudrate;
90 if (((env_echo = getenv("loads_echo")) != NULL) && (*env_echo == '1')) {
96 offset = simple_strtoul(argv[1], NULL, 16);
99 load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
101 /* default to current baudrate */
102 if (load_baudrate == 0)
103 load_baudrate = current_baudrate;
106 if (load_baudrate != current_baudrate) {
107 for (i = 0; i < N_BAUDRATES; ++i) {
108 if (load_baudrate == baudrate_table[i])
112 if (i == N_BAUDRATES) {
113 printf_err("baudrate %d bps is not supported, will use current: %d bps\n",
114 load_baudrate, current_baudrate);
116 load_baudrate = current_baudrate;
118 switch_baudrate(load_baudrate, 0);
121 printf("Ready for S-Record download...\n");
123 addr = load_serial(offset);
126 * Gather any trailing characters (for instance, the ^D which
127 * is sent by 'cu' after sending a file), and give the
128 * box some time (100 * 1 ms)
130 for (i=0; i<100; ++i) {
138 printf_err("S-Record download aborted!\n");
142 if (load_baudrate != current_baudrate)
143 switch_baudrate(current_baudrate, 1);
148 static ulong load_serial(ulong offset)
150 char record[SREC_MAXRECLEN + 1]; /* buffer for one S-Record */
151 char binbuf[SREC_MAXBINLEN]; /* buffer for binary data */
152 int binlen; /* no. of data bytes in S-Rec. */
153 int type; /* return code for record type */
154 ulong addr; /* load address from S-Record */
155 ulong size; /* number of bytes transferred */
158 ulong start_addr = ~0;
162 while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {
163 type = srec_decode(record, &binlen, &addr, binbuf);
166 return ~0; /* Invalid S-Record */
172 store_addr = addr + offset;
175 if (addr2info(store_addr)) {
176 int rc = flash_write((char *)binbuf, store_addr, binlen);
185 memcpy((char *)(store_addr), binbuf, binlen);
188 if ((store_addr) < start_addr)
189 start_addr = store_addr;
191 if ((store_addr + binlen - 1) > end_addr)
192 end_addr = store_addr + binlen - 1;
199 size = end_addr - start_addr + 1;
201 printf("\nS-Record download complete!\n");
202 printf(" First load address: 0x%08lX\n", start_addr);
203 printf(" Last load address: 0x%08lX\n", end_addr);
204 printf("Total downloaded size: 0x%08lX (%d bytes)\n", size, size);
205 printf(" Data start address: 0x%08lX\n\n", addr);
207 flush_cache(start_addr, size);
209 sprintf(buf, "0x%lX", size);
210 setenv("filesize", buf);
212 sprintf(buf, "0x%lX", addr);
213 setenv("fileaddr", buf);
222 /* print a '.' every 100 lines */
224 if ((++line_count % 100) == 0)
229 /* Download aborted */
233 static int read_record(char *buf, ulong len)
238 /* always leave room for terminating '\0' byte */
241 for (p=buf; p < buf+len; ++p) {
245 /* ... and echo it */
262 /* Check for the console hangup (if any different from serial) */
263 if (gd->jt[XF_getc] != getc) {
269 /* line too long - truncate */
275 #if defined(CONFIG_CMD_SAVES)
276 int do_save_serial(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
280 int save_baudrate, current_baudrate, i;
282 save_baudrate = current_baudrate = gd->baudrate;
285 offset = simple_strtoul(argv[1], NULL, 16);
288 size = simple_strtoul(argv[2], NULL, 16);
291 save_baudrate = (int)simple_strtoul(argv[3], NULL, 10);
293 /* default to current baudrate */
294 if (save_baudrate == 0)
295 save_baudrate = current_baudrate;
298 if (save_baudrate != current_baudrate) {
299 for (i = 0; i < N_BAUDRATES; ++i) {
300 if (save_baudrate == baudrate_table[i])
304 if (i == N_BAUDRATES) {
305 printf_err("baudrate %d bps is not supported, will use current: %d bps\n",
306 save_baudrate, current_baudrate);
308 save_baudrate = current_baudrate;
310 switch_baudrate(save_baudrate, 0);
313 printf("Ready for S-Record upload, press ENTER to proceed...\n");
320 if (save_serial(offset, size))
321 printf_err("S-Record upload aborted!\n");
323 printf("\nS-Record upload complete!\n");
325 if (save_baudrate != current_baudrate)
326 switch_baudrate(current_baudrate, 1);
331 #define SREC3_START "S0030000FC\n"
332 #define SREC3_FORMAT "S3%02X%08lX%s%02X\n"
333 #define SREC3_END "S70500000000FA\n"
334 #define SREC_BYTES_PER_RECORD 16
336 static int save_serial(ulong address, ulong count)
338 int i, c, reclen, checksum, length;
339 char *hex = "0123456789ABCDEF";
340 char record[2*SREC_BYTES_PER_RECORD+16]; /* buffer for one S-Record */
341 char data[2*SREC_BYTES_PER_RECORD+1]; /* buffer for hex data */
346 /* write the header */
347 if (write_record(SREC3_START))
351 /* collect hex data in the buffer */
354 c = *(volatile uchar*)(address + reclen);
356 /* accumulate checksum */
359 data[2*reclen] = hex[(c>>4)&0x0f];
360 data[2*reclen+1] = hex[c & 0x0f];
361 data[2*reclen+2] = '\0';
366 if (reclen == SREC_BYTES_PER_RECORD || count == 0) {
367 /* enough data collected for one record: dump it */
368 /* build & write a data record: */
370 /* address + data + checksum */
371 length = 4 + reclen + 1;
373 /* accumulate length bytes into checksum */
374 for (i = 0; i < 2; i++)
375 checksum += (length >> (8*i)) & 0xff;
377 /* accumulate address bytes into checksum */
378 for (i = 0; i < 4; i++)
379 checksum += (address >> (8*i)) & 0xff;
381 /* make proper checksum byte: */
382 checksum = ~checksum & 0xff;
384 /* output one record: */
385 sprintf(record, SREC3_FORMAT, length, address, data, checksum);
387 if (write_record(record))
391 /* increment address */
398 /* write the final record */
399 if (write_record(SREC3_END))
405 static int write_record(char *buf)
412 /* Check for the console hangup (if any different from serial) */
418 #endif /* CONFIG_CMD_SAVES */
419 #endif /* CONFIG_CMD_LOADS */
421 /* loadb command (load binary) included */
422 #if defined(CONFIG_CMD_LOADB)
426 #define START_CHAR 0x01
427 #define ETX_CHAR 0x03
428 #define END_CHAR 0x0D
430 #define K_ESCAPE 0x23
431 #define SEND_TYPE 'S'
432 #define DATA_TYPE 'D'
434 #define NACK_TYPE 'N'
435 #define BREAK_TYPE 'B'
436 #define tochar(x) ((char) (((x) + SPACE) & 0xff))
437 #define untochar(x) ((int) (((x) - SPACE) & 0xff))
439 extern int os_data_count;
440 extern int os_data_header[8];
442 static void set_kerm_bin_mode(unsigned long *);
443 static int k_recv(void);
444 static int load_serial_bin(ulong offset);
446 char his_eol; /* character he needs at end of packet */
447 int his_pad_count; /* number of pad chars he needs */
448 char his_pad_char; /* pad chars he needs */
449 char his_quote; /* quote chars he'll use */
451 int do_load_serial_bin(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
454 int rcode = 0, size_dl = 0;
457 int load_baudrate, current_baudrate;
459 load_baudrate = current_baudrate = gd->baudrate;
461 /* pre-set address from $loadaddr */
462 if ((s = getenv("loadaddr")) != NULL)
463 address = simple_strtoul(s, NULL, 16);
466 address = simple_strtoul(argv[1], NULL, 16);
469 printf_err("destination address can't be 0x0!\n");
473 /* don't allow to write directly to FLASH (that will need erase before!) */
474 if (addr2info(address) != NULL) {
475 printf_err("destination address in FLASH is not allowed!\n");
480 load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
482 /* default to current baudrate */
483 if (load_baudrate == 0)
484 load_baudrate = current_baudrate;
487 if (load_baudrate != current_baudrate) {
488 for (i = 0; i < N_BAUDRATES; ++i) {
489 if (load_baudrate == baudrate_table[i])
493 if (i == N_BAUDRATES) {
494 printf_err("baudrate %d bps is not supported, will use current: %d bps\n",
495 load_baudrate, current_baudrate);
497 load_baudrate = current_baudrate;
499 switch_baudrate(load_baudrate, 0);
502 printf("Ready for binary (%s) download to 0x%08lX at %d bps...\n",
503 strcmp(argv[0],"loady") == 0 ? "Ymodem" : "Kermit",
504 address, load_baudrate);
506 if (strcmp(argv[0],"loady") == 0)
507 size_dl = load_serial_ymodem(address);
509 size_dl = load_serial_bin(address);
512 printf("\n%s download complete!\n",
513 strcmp(argv[0],"loady") == 0 ? "Ymodem" : "Kermit");
515 printf("Total downloaded size: 0x%08lX (%d bytes)\n",
518 printf(" Data start address: 0x%08lX\n\n", address);
520 flush_cache(address, size_dl);
522 sprintf(buf, "0x%X", size_dl);
523 setenv("filesize", buf);
525 sprintf(buf, "0x%lX", address);
526 setenv("fileaddr", buf);
529 printf_err("downloaded data size is zero!\n");
533 if (load_baudrate != current_baudrate)
534 switch_baudrate(current_baudrate, 1);
539 static int load_serial_bin(ulong address)
543 set_kerm_bin_mode((ulong *)address);
547 * Gather any trailing characters (for instance, the ^D which
548 * is sent by 'cu' after sending a file), and give the
549 * box some time (100 * 1 ms)
551 for (i = 0; i < 100; ++i) {
563 int count = his_pad_count;
569 /* converts escaped kermit char to binary char */
572 if ((in & 0x60) == 0x40)
573 return (char)(in & ~0x40);
574 else if ((in & 0x7f) == 0x3f)
575 return (char)(in | 0x40);
580 int chk1(char *buffer)
587 return (int)((total + ((total >> 6) & 0x03)) & 0x3f);
590 void s1_sendpacket(char *packet)
606 a_b[4] = tochar(chk1(&a_b[1]));
613 void send_nack(int n)
620 a_b[4] = tochar(chk1(&a_b[1]));
628 /* os_data_* takes an OS Open image and puts it into memory, and
629 puts the boot header in an array named os_data_header
630 if image is binary, no header is stored in os_data_header.
632 void (*os_data_init)(void);
633 void (*os_data_char)(char new_char);
634 static int os_data_state, os_data_state_saved;
636 static int os_data_count_saved;
637 static char *os_data_addr, *os_data_addr_saved;
638 static char *bin_start_address;
639 int os_data_header[8];
641 static void bin_data_init(void)
645 os_data_addr = bin_start_address;
648 static void os_data_save(void)
650 os_data_state_saved = os_data_state;
651 os_data_count_saved = os_data_count;
652 os_data_addr_saved = os_data_addr;
655 static void os_data_restore(void)
657 os_data_state = os_data_state_saved;
658 os_data_count = os_data_count_saved;
659 os_data_addr = os_data_addr_saved;
662 static void bin_data_char(char new_char)
664 switch (os_data_state) {
667 *os_data_addr++ = new_char;
673 static void set_kerm_bin_mode(unsigned long *addr)
675 bin_start_address = (char *)addr;
676 os_data_init = bin_data_init;
677 os_data_char = bin_data_char;
680 /* k_data_* simply handles the kermit escape translations */
681 static int k_data_escape, k_data_escape_saved;
682 void k_data_init(void)
688 void k_data_save(void)
690 k_data_escape_saved = k_data_escape;
694 void k_data_restore(void)
696 k_data_escape = k_data_escape_saved;
700 void k_data_char(char new_char)
703 /* last char was escape - translate this character */
704 os_data_char(ktrans(new_char));
707 if (new_char == his_quote)
708 k_data_escape = 1; /* this char is escape - remember */
710 os_data_char(new_char); /* otherwise send this char as-is */
714 #define SEND_DATA_SIZE 20
715 char send_parms[SEND_DATA_SIZE];
718 /* handle_send_packet interprits the protocol info and builds and
719 sends an appropriate ack for what we can do */
720 void handle_send_packet(int n)
725 /* initialize some protocol parameters */
726 his_eol = END_CHAR; /* default end of line character */
729 his_quote = K_ESCAPE;
731 /* ignore last character if it filled the buffer */
732 if (send_ptr == &send_parms[SEND_DATA_SIZE - 1])
735 /* how many bytes we'll process */
736 bytes = send_ptr - send_parms;
742 /* handle MAXL - max length */
743 /* ignore what he says - most I'll take (here) is 94 */
744 a_b[++length] = tochar(94);
749 /* handle TIME - time you should wait for my packets */
750 /* ignore what he says - don't wait for my ack longer than 1 second */
751 a_b[++length] = tochar(1);
756 /* handle NPAD - number of pad chars I need */
757 /* remember what he says - I need none */
758 his_pad_count = untochar(send_parms[2]);
759 a_b[++length] = tochar(0);
764 /* handle PADC - pad chars I need */
765 /* remember what he says - I need none */
766 his_pad_char = ktrans(send_parms[3]);
767 a_b[++length] = 0x40; /* He should ignore this */
772 /* handle EOL - end of line he needs */
773 /* remember what he says - I need CR */
774 his_eol = untochar(send_parms[4]);
775 a_b[++length] = tochar(END_CHAR);
780 /* handle QCTL - quote control char he'll use */
781 /* remember what he says - I'll use '#' */
782 his_quote = send_parms[5];
788 /* handle QBIN - 8-th bit prefixing */
789 /* ignore what he says - I refuse */
795 /* handle CHKT - the clock check type */
796 /* ignore what he says - I do type 1 (for now) */
802 /* handle REPT - the repeat prefix */
803 /* ignore what he says - I refuse (for now) */
809 /* handle CAPAS - the capabilities mask */
810 /* ignore what he says - I only do long packets - I don't do windows */
811 a_b[++length] = tochar(2); /* only long packets */
812 a_b[++length] = tochar(0); /* no windows */
813 a_b[++length] = tochar(94); /* large packet msb */
814 a_b[++length] = tochar(94); /* large packet lsb */
818 a_b[1] = tochar(length);
821 a_b[++length] = '\0';
822 a_b[length] = tochar(chk1(&a_b[1]));
823 a_b[++length] = his_eol;
824 a_b[++length] = '\0';
829 /* k_recv receives a OS Open image file over kermit line */
830 static int k_recv(void)
833 char k_state, k_state_saved;
841 /* initialize some protocol parameters */
842 his_eol = END_CHAR; /* default end of line character */
845 his_quote = K_ESCAPE;
847 /* initialize the k_recv and k_data state machine */
852 k_state_saved = k_state;
856 /* just to get rid of a warning */
860 /* expect this "type" sequence (but don't check):
865 B: break transmission
868 /* enter main loop */
870 /* set the send packet pointer to begining of send packet parms */
871 send_ptr = send_parms;
873 /* With each packet, start summing the bytes starting with the length.
874 Save the current sequence number.
875 Note the type of the packet.
876 If a character less than SPACE (0x20) is received - error.
880 /* wait for the starting character or ^C */
886 /* ^C waiting for packet */
895 /* get length of packet */
898 if ((new_char & 0xE0) == 0)
901 sum += new_char & 0xff;
902 length = untochar(new_char);
904 /* get sequence number */
906 if ((new_char & 0xE0) == 0)
909 sum += new_char & 0xff;
910 n = untochar(new_char);
913 /* NEW CODE - check sequence numbers for retried packets */
914 /* Note - this new code assumes that the sequence number is correctly
915 * received. Handling an invalid sequence number adds another layer
916 * of complexity that may not be needed - yet! At this time, I'm hoping
917 * that I don't need to buffer the incoming data packets and can write
918 * the data into memory in real time.
921 /* same sequence number, restore the previous state */
922 k_state = k_state_saved;
925 /* new sequence number, checkpoint the download */
927 k_state_saved = k_state;
932 /* get packet type */
934 if ((new_char & 0xE0) == 0)
937 sum += new_char & 0xff;
941 /* check for extended length */
943 /* (length byte was 0, decremented twice) */
944 /* get the two length bytes */
946 if ((new_char & 0xE0) == 0)
949 sum += new_char & 0xff;
950 len_hi = untochar(new_char);
952 if ((new_char & 0xE0) == 0)
955 sum += new_char & 0xff;
956 len_lo = untochar(new_char);
957 length = len_hi * 95 + len_lo;
958 /* check header checksum */
960 if ((new_char & 0xE0) == 0)
963 if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
966 sum += new_char & 0xff;
967 /* --length; */ /* new length includes only data and block check to come */
970 /* bring in rest of packet */
973 if ((new_char & 0xE0) == 0)
976 sum += new_char & 0xff;
979 if (k_state == DATA_TYPE) {
980 /* pass on the data if this is a data packet */
981 k_data_char(new_char);
982 } else if (k_state == SEND_TYPE) {
983 /* save send pack in buffer as is */
984 *send_ptr++ = new_char;
986 /* if too much data, back off the pointer */
987 if (send_ptr >= &send_parms[SEND_DATA_SIZE])
992 /* get and validate checksum character */
994 if ((new_char & 0xE0) == 0)
997 if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
1002 if (new_char != END_CHAR) {
1004 /* restore state machines */
1005 k_state = k_state_saved;
1008 /* send a negative acknowledge packet in */
1010 } else if (k_state == SEND_TYPE) {
1011 /* crack the protocol parms, build an appropriate ack packet */
1012 handle_send_packet(n);
1014 /* send simple acknowledge packet in */
1016 /* quit if end of transmission */
1017 if (k_state == BREAK_TYPE)
1024 return ((ulong)os_data_addr - (ulong)bin_start_address);
1027 static int getcxmodem(void)
1035 static ulong load_serial_ymodem(ulong address)
1040 connection_info_t info;
1041 char ymodemBuf[1024];
1042 ulong store_addr = ~0;
1046 info.mode = xyzModem_ymodem;
1048 res = xyzModem_stream_open(&info, &err);
1051 while ((res = xyzModem_stream_read(ymodemBuf, 1024, &err)) > 0) {
1052 store_addr = addr + address;
1056 memcpy((char *)(store_addr), ymodemBuf, res);
1060 printf_err("%s\n", xyzModem_error(err));
1063 xyzModem_stream_close(&err);
1064 xyzModem_stream_terminate(0, &getcxmodem);
1069 #endif /* CONFIG_CMD_LOADB */
1071 /* -------------------------------------------------------------------- */
1073 #if defined(CONFIG_CMD_LOADS)
1074 U_BOOT_CMD(loads, 3, 0, do_load_serial,
1075 "load S-Record file over serial\n",
1077 "\t- load S-Record file over serial with offset 'off' and baudrate 'baud'\n"
1081 * SAVES always requires LOADS support, but not vice versa
1083 #if defined(CONFIG_CMD_SAVES)
1084 U_BOOT_CMD(saves, 4, 0, do_save_serial,
1085 "save S-Record file over serial\n",
1086 "[addr] [size] [baud]\n"
1087 "\t- upload S-Record file over serial from address 'addr', size 'size' with baudrate 'baud'\n"
1089 #endif /* CONFIG_CMD_SAVES */
1090 #endif /* CONFIG_CMD_LOADS */
1092 #if defined(CONFIG_CMD_LOADB)
1093 U_BOOT_CMD(loadb, 3, 0, do_load_serial_bin,
1094 "load binary file over serial (Kermit mode)\n",
1096 "\t- load binary file over serial at address 'addr', with baudrate 'baud'\n"
1099 U_BOOT_CMD(loady, 3, 0, do_load_serial_bin,
1100 "load binary file over serial (Ymodem mode)\n",
1102 "\t- load binary file over serial at address 'addr', with baudrate 'baud'\n"
1104 #endif /* CONFIG_CMD_LOADB */