12e192b24SSimon Glass /*
22e192b24SSimon Glass * (C) Copyright 2000-2004
32e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
42e192b24SSimon Glass *
52e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+
62e192b24SSimon Glass */
72e192b24SSimon Glass
82e192b24SSimon Glass /*
92e192b24SSimon Glass * Serial up- and download support
102e192b24SSimon Glass */
112e192b24SSimon Glass #include <common.h>
12*48650c55SJoseph Chen #include <boot_rkimg.h>
132e192b24SSimon Glass #include <command.h>
142e192b24SSimon Glass #include <console.h>
152e192b24SSimon Glass #include <s_record.h>
162e192b24SSimon Glass #include <net.h>
172e192b24SSimon Glass #include <exports.h>
182e192b24SSimon Glass #include <xyzModem.h>
192e192b24SSimon Glass
202e192b24SSimon Glass DECLARE_GLOBAL_DATA_PTR;
212e192b24SSimon Glass
222e192b24SSimon Glass #if defined(CONFIG_CMD_LOADB)
232e192b24SSimon Glass static ulong load_serial_ymodem(ulong offset, int mode);
24*48650c55SJoseph Chen static ulong load_serial_zmodem(ulong offset);
252e192b24SSimon Glass #endif
262e192b24SSimon Glass
272e192b24SSimon Glass #if defined(CONFIG_CMD_LOADS)
282e192b24SSimon Glass static ulong load_serial(long offset);
292e192b24SSimon Glass static int read_record(char *buf, ulong len);
302e192b24SSimon Glass # if defined(CONFIG_CMD_SAVES)
312e192b24SSimon Glass static int save_serial(ulong offset, ulong size);
322e192b24SSimon Glass static int write_record(char *buf);
332e192b24SSimon Glass #endif
342e192b24SSimon Glass
352e192b24SSimon Glass static int do_echo = 1;
362e192b24SSimon Glass #endif
372e192b24SSimon Glass
382e192b24SSimon Glass /* -------------------------------------------------------------------- */
392e192b24SSimon Glass
402e192b24SSimon Glass #if defined(CONFIG_CMD_LOADS)
do_load_serial(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])412e192b24SSimon Glass static int do_load_serial(cmd_tbl_t *cmdtp, int flag, int argc,
422e192b24SSimon Glass char * const argv[])
432e192b24SSimon Glass {
442e192b24SSimon Glass long offset = 0;
452e192b24SSimon Glass ulong addr;
462e192b24SSimon Glass int i;
472e192b24SSimon Glass char *env_echo;
482e192b24SSimon Glass int rcode = 0;
492e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
502e192b24SSimon Glass int load_baudrate, current_baudrate;
512e192b24SSimon Glass
522e192b24SSimon Glass load_baudrate = current_baudrate = gd->baudrate;
532e192b24SSimon Glass #endif
542e192b24SSimon Glass
5500caae6dSSimon Glass env_echo = env_get("loads_echo");
5600caae6dSSimon Glass if (env_echo && *env_echo == '1')
572e192b24SSimon Glass do_echo = 1;
5800caae6dSSimon Glass else
592e192b24SSimon Glass do_echo = 0;
602e192b24SSimon Glass
612e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
622e192b24SSimon Glass if (argc >= 2) {
632e192b24SSimon Glass offset = simple_strtol(argv[1], NULL, 16);
642e192b24SSimon Glass }
652e192b24SSimon Glass if (argc == 3) {
662e192b24SSimon Glass load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
672e192b24SSimon Glass
682e192b24SSimon Glass /* default to current baudrate */
692e192b24SSimon Glass if (load_baudrate == 0)
702e192b24SSimon Glass load_baudrate = current_baudrate;
712e192b24SSimon Glass }
722e192b24SSimon Glass if (load_baudrate != current_baudrate) {
732e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ENTER ...\n",
742e192b24SSimon Glass load_baudrate);
752e192b24SSimon Glass udelay(50000);
762e192b24SSimon Glass gd->baudrate = load_baudrate;
772e192b24SSimon Glass serial_setbrg();
782e192b24SSimon Glass udelay(50000);
792e192b24SSimon Glass for (;;) {
802e192b24SSimon Glass if (getc() == '\r')
812e192b24SSimon Glass break;
822e192b24SSimon Glass }
832e192b24SSimon Glass }
842e192b24SSimon Glass #else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
852e192b24SSimon Glass if (argc == 2) {
862e192b24SSimon Glass offset = simple_strtol(argv[1], NULL, 16);
872e192b24SSimon Glass }
882e192b24SSimon Glass #endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */
892e192b24SSimon Glass
902e192b24SSimon Glass printf("## Ready for S-Record download ...\n");
912e192b24SSimon Glass
922e192b24SSimon Glass addr = load_serial(offset);
932e192b24SSimon Glass
942e192b24SSimon Glass /*
952e192b24SSimon Glass * Gather any trailing characters (for instance, the ^D which
962e192b24SSimon Glass * is sent by 'cu' after sending a file), and give the
972e192b24SSimon Glass * box some time (100 * 1 ms)
982e192b24SSimon Glass */
992e192b24SSimon Glass for (i=0; i<100; ++i) {
1002e192b24SSimon Glass if (tstc()) {
1012e192b24SSimon Glass (void) getc();
1022e192b24SSimon Glass }
1032e192b24SSimon Glass udelay(1000);
1042e192b24SSimon Glass }
1052e192b24SSimon Glass
1062e192b24SSimon Glass if (addr == ~0) {
1072e192b24SSimon Glass printf("## S-Record download aborted\n");
1082e192b24SSimon Glass rcode = 1;
1092e192b24SSimon Glass } else {
1102e192b24SSimon Glass printf("## Start Addr = 0x%08lX\n", addr);
1112e192b24SSimon Glass load_addr = addr;
1122e192b24SSimon Glass }
1132e192b24SSimon Glass
1142e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
1152e192b24SSimon Glass if (load_baudrate != current_baudrate) {
1162e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ESC ...\n",
1172e192b24SSimon Glass current_baudrate);
1182e192b24SSimon Glass udelay(50000);
1192e192b24SSimon Glass gd->baudrate = current_baudrate;
1202e192b24SSimon Glass serial_setbrg();
1212e192b24SSimon Glass udelay(50000);
1222e192b24SSimon Glass for (;;) {
1232e192b24SSimon Glass if (getc() == 0x1B) /* ESC */
1242e192b24SSimon Glass break;
1252e192b24SSimon Glass }
1262e192b24SSimon Glass }
1272e192b24SSimon Glass #endif
1282e192b24SSimon Glass return rcode;
1292e192b24SSimon Glass }
1302e192b24SSimon Glass
load_serial(long offset)1312e192b24SSimon Glass static ulong load_serial(long offset)
1322e192b24SSimon Glass {
1332e192b24SSimon Glass char record[SREC_MAXRECLEN + 1]; /* buffer for one S-Record */
1342e192b24SSimon Glass char binbuf[SREC_MAXBINLEN]; /* buffer for binary data */
1352e192b24SSimon Glass int binlen; /* no. of data bytes in S-Rec. */
1362e192b24SSimon Glass int type; /* return code for record type */
1372e192b24SSimon Glass ulong addr; /* load address from S-Record */
1382e192b24SSimon Glass ulong size; /* number of bytes transferred */
1392e192b24SSimon Glass ulong store_addr;
1402e192b24SSimon Glass ulong start_addr = ~0;
1412e192b24SSimon Glass ulong end_addr = 0;
1422e192b24SSimon Glass int line_count = 0;
1432e192b24SSimon Glass
1442e192b24SSimon Glass while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {
1452e192b24SSimon Glass type = srec_decode(record, &binlen, &addr, binbuf);
1462e192b24SSimon Glass
1472e192b24SSimon Glass if (type < 0) {
1482e192b24SSimon Glass return (~0); /* Invalid S-Record */
1492e192b24SSimon Glass }
1502e192b24SSimon Glass
1512e192b24SSimon Glass switch (type) {
1522e192b24SSimon Glass case SREC_DATA2:
1532e192b24SSimon Glass case SREC_DATA3:
1542e192b24SSimon Glass case SREC_DATA4:
1552e192b24SSimon Glass store_addr = addr + offset;
156e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH
1572e192b24SSimon Glass if (addr2info(store_addr)) {
1582e192b24SSimon Glass int rc;
1592e192b24SSimon Glass
1602e192b24SSimon Glass rc = flash_write((char *)binbuf,store_addr,binlen);
1612e192b24SSimon Glass if (rc != 0) {
1622e192b24SSimon Glass flash_perror(rc);
1632e192b24SSimon Glass return (~0);
1642e192b24SSimon Glass }
1652e192b24SSimon Glass } else
1662e192b24SSimon Glass #endif
1672e192b24SSimon Glass {
1682e192b24SSimon Glass memcpy((char *)(store_addr), binbuf, binlen);
1692e192b24SSimon Glass }
1702e192b24SSimon Glass if ((store_addr) < start_addr)
1712e192b24SSimon Glass start_addr = store_addr;
1722e192b24SSimon Glass if ((store_addr + binlen - 1) > end_addr)
1732e192b24SSimon Glass end_addr = store_addr + binlen - 1;
1742e192b24SSimon Glass break;
1752e192b24SSimon Glass case SREC_END2:
1762e192b24SSimon Glass case SREC_END3:
1772e192b24SSimon Glass case SREC_END4:
1782e192b24SSimon Glass udelay(10000);
1792e192b24SSimon Glass size = end_addr - start_addr + 1;
1802e192b24SSimon Glass printf("\n"
1812e192b24SSimon Glass "## First Load Addr = 0x%08lX\n"
1822e192b24SSimon Glass "## Last Load Addr = 0x%08lX\n"
1832e192b24SSimon Glass "## Total Size = 0x%08lX = %ld Bytes\n",
1842e192b24SSimon Glass start_addr, end_addr, size, size
1852e192b24SSimon Glass );
1862e192b24SSimon Glass flush_cache(start_addr, size);
187018f5303SSimon Glass env_set_hex("filesize", size);
1882e192b24SSimon Glass return (addr);
1892e192b24SSimon Glass case SREC_START:
1902e192b24SSimon Glass break;
1912e192b24SSimon Glass default:
1922e192b24SSimon Glass break;
1932e192b24SSimon Glass }
1942e192b24SSimon Glass if (!do_echo) { /* print a '.' every 100 lines */
1952e192b24SSimon Glass if ((++line_count % 100) == 0)
1962e192b24SSimon Glass putc('.');
1972e192b24SSimon Glass }
1982e192b24SSimon Glass }
1992e192b24SSimon Glass
2002e192b24SSimon Glass return (~0); /* Download aborted */
2012e192b24SSimon Glass }
2022e192b24SSimon Glass
read_record(char * buf,ulong len)2032e192b24SSimon Glass static int read_record(char *buf, ulong len)
2042e192b24SSimon Glass {
2052e192b24SSimon Glass char *p;
2062e192b24SSimon Glass char c;
2072e192b24SSimon Glass
2082e192b24SSimon Glass --len; /* always leave room for terminating '\0' byte */
2092e192b24SSimon Glass
2102e192b24SSimon Glass for (p=buf; p < buf+len; ++p) {
2112e192b24SSimon Glass c = getc(); /* read character */
2122e192b24SSimon Glass if (do_echo)
2132e192b24SSimon Glass putc(c); /* ... and echo it */
2142e192b24SSimon Glass
2152e192b24SSimon Glass switch (c) {
2162e192b24SSimon Glass case '\r':
2172e192b24SSimon Glass case '\n':
2182e192b24SSimon Glass *p = '\0';
2192e192b24SSimon Glass return (p - buf);
2202e192b24SSimon Glass case '\0':
2212e192b24SSimon Glass case 0x03: /* ^C - Control C */
2222e192b24SSimon Glass return (-1);
2232e192b24SSimon Glass default:
2242e192b24SSimon Glass *p = c;
2252e192b24SSimon Glass }
2262e192b24SSimon Glass
2272e192b24SSimon Glass /* Check for the console hangup (if any different from serial) */
2282e192b24SSimon Glass if (gd->jt->getc != getc) {
2292e192b24SSimon Glass if (ctrlc()) {
2302e192b24SSimon Glass return (-1);
2312e192b24SSimon Glass }
2322e192b24SSimon Glass }
2332e192b24SSimon Glass }
2342e192b24SSimon Glass
2352e192b24SSimon Glass /* line too long - truncate */
2362e192b24SSimon Glass *p = '\0';
2372e192b24SSimon Glass return (p - buf);
2382e192b24SSimon Glass }
2392e192b24SSimon Glass
2402e192b24SSimon Glass #if defined(CONFIG_CMD_SAVES)
2412e192b24SSimon Glass
do_save_serial(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])2422e192b24SSimon Glass int do_save_serial (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
2432e192b24SSimon Glass {
2442e192b24SSimon Glass ulong offset = 0;
2452e192b24SSimon Glass ulong size = 0;
2462e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
2472e192b24SSimon Glass int save_baudrate, current_baudrate;
2482e192b24SSimon Glass
2492e192b24SSimon Glass save_baudrate = current_baudrate = gd->baudrate;
2502e192b24SSimon Glass #endif
2512e192b24SSimon Glass
2522e192b24SSimon Glass if (argc >= 2) {
2532e192b24SSimon Glass offset = simple_strtoul(argv[1], NULL, 16);
2542e192b24SSimon Glass }
2552e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
2562e192b24SSimon Glass if (argc >= 3) {
2572e192b24SSimon Glass size = simple_strtoul(argv[2], NULL, 16);
2582e192b24SSimon Glass }
2592e192b24SSimon Glass if (argc == 4) {
2602e192b24SSimon Glass save_baudrate = (int)simple_strtoul(argv[3], NULL, 10);
2612e192b24SSimon Glass
2622e192b24SSimon Glass /* default to current baudrate */
2632e192b24SSimon Glass if (save_baudrate == 0)
2642e192b24SSimon Glass save_baudrate = current_baudrate;
2652e192b24SSimon Glass }
2662e192b24SSimon Glass if (save_baudrate != current_baudrate) {
2672e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ENTER ...\n",
2682e192b24SSimon Glass save_baudrate);
2692e192b24SSimon Glass udelay(50000);
2702e192b24SSimon Glass gd->baudrate = save_baudrate;
2712e192b24SSimon Glass serial_setbrg();
2722e192b24SSimon Glass udelay(50000);
2732e192b24SSimon Glass for (;;) {
2742e192b24SSimon Glass if (getc() == '\r')
2752e192b24SSimon Glass break;
2762e192b24SSimon Glass }
2772e192b24SSimon Glass }
2782e192b24SSimon Glass #else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
2792e192b24SSimon Glass if (argc == 3) {
2802e192b24SSimon Glass size = simple_strtoul(argv[2], NULL, 16);
2812e192b24SSimon Glass }
2822e192b24SSimon Glass #endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */
2832e192b24SSimon Glass
2842e192b24SSimon Glass printf("## Ready for S-Record upload, press ENTER to proceed ...\n");
2852e192b24SSimon Glass for (;;) {
2862e192b24SSimon Glass if (getc() == '\r')
2872e192b24SSimon Glass break;
2882e192b24SSimon Glass }
2892e192b24SSimon Glass if (save_serial(offset, size)) {
2902e192b24SSimon Glass printf("## S-Record upload aborted\n");
2912e192b24SSimon Glass } else {
2922e192b24SSimon Glass printf("## S-Record upload complete\n");
2932e192b24SSimon Glass }
2942e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
2952e192b24SSimon Glass if (save_baudrate != current_baudrate) {
2962e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ESC ...\n",
2972e192b24SSimon Glass (int)current_baudrate);
2982e192b24SSimon Glass udelay(50000);
2992e192b24SSimon Glass gd->baudrate = current_baudrate;
3002e192b24SSimon Glass serial_setbrg();
3012e192b24SSimon Glass udelay(50000);
3022e192b24SSimon Glass for (;;) {
3032e192b24SSimon Glass if (getc() == 0x1B) /* ESC */
3042e192b24SSimon Glass break;
3052e192b24SSimon Glass }
3062e192b24SSimon Glass }
3072e192b24SSimon Glass #endif
3082e192b24SSimon Glass return 0;
3092e192b24SSimon Glass }
3102e192b24SSimon Glass
3112e192b24SSimon Glass #define SREC3_START "S0030000FC\n"
3122e192b24SSimon Glass #define SREC3_FORMAT "S3%02X%08lX%s%02X\n"
3132e192b24SSimon Glass #define SREC3_END "S70500000000FA\n"
3142e192b24SSimon Glass #define SREC_BYTES_PER_RECORD 16
3152e192b24SSimon Glass
save_serial(ulong address,ulong count)3162e192b24SSimon Glass static int save_serial(ulong address, ulong count)
3172e192b24SSimon Glass {
3182e192b24SSimon Glass int i, c, reclen, checksum, length;
3192e192b24SSimon Glass char *hex = "0123456789ABCDEF";
3202e192b24SSimon Glass char record[2*SREC_BYTES_PER_RECORD+16]; /* buffer for one S-Record */
3212e192b24SSimon Glass char data[2*SREC_BYTES_PER_RECORD+1]; /* buffer for hex data */
3222e192b24SSimon Glass
3232e192b24SSimon Glass reclen = 0;
3242e192b24SSimon Glass checksum = 0;
3252e192b24SSimon Glass
3262e192b24SSimon Glass if(write_record(SREC3_START)) /* write the header */
3272e192b24SSimon Glass return (-1);
3282e192b24SSimon Glass do {
3292e192b24SSimon Glass if(count) { /* collect hex data in the buffer */
3302e192b24SSimon Glass c = *(volatile uchar*)(address + reclen); /* get one byte */
3312e192b24SSimon Glass checksum += c; /* accumulate checksum */
3322e192b24SSimon Glass data[2*reclen] = hex[(c>>4)&0x0f];
3332e192b24SSimon Glass data[2*reclen+1] = hex[c & 0x0f];
3342e192b24SSimon Glass data[2*reclen+2] = '\0';
3352e192b24SSimon Glass ++reclen;
3362e192b24SSimon Glass --count;
3372e192b24SSimon Glass }
3382e192b24SSimon Glass if(reclen == SREC_BYTES_PER_RECORD || count == 0) {
3392e192b24SSimon Glass /* enough data collected for one record: dump it */
3402e192b24SSimon Glass if(reclen) { /* build & write a data record: */
3412e192b24SSimon Glass /* address + data + checksum */
3422e192b24SSimon Glass length = 4 + reclen + 1;
3432e192b24SSimon Glass
3442e192b24SSimon Glass /* accumulate length bytes into checksum */
3452e192b24SSimon Glass for(i = 0; i < 2; i++)
3462e192b24SSimon Glass checksum += (length >> (8*i)) & 0xff;
3472e192b24SSimon Glass
3482e192b24SSimon Glass /* accumulate address bytes into checksum: */
3492e192b24SSimon Glass for(i = 0; i < 4; i++)
3502e192b24SSimon Glass checksum += (address >> (8*i)) & 0xff;
3512e192b24SSimon Glass
3522e192b24SSimon Glass /* make proper checksum byte: */
3532e192b24SSimon Glass checksum = ~checksum & 0xff;
3542e192b24SSimon Glass
3552e192b24SSimon Glass /* output one record: */
3562e192b24SSimon Glass sprintf(record, SREC3_FORMAT, length, address, data, checksum);
3572e192b24SSimon Glass if(write_record(record))
3582e192b24SSimon Glass return (-1);
3592e192b24SSimon Glass }
3602e192b24SSimon Glass address += reclen; /* increment address */
3612e192b24SSimon Glass checksum = 0;
3622e192b24SSimon Glass reclen = 0;
3632e192b24SSimon Glass }
3642e192b24SSimon Glass }
3652e192b24SSimon Glass while(count);
3662e192b24SSimon Glass if(write_record(SREC3_END)) /* write the final record */
3672e192b24SSimon Glass return (-1);
3682e192b24SSimon Glass return(0);
3692e192b24SSimon Glass }
3702e192b24SSimon Glass
write_record(char * buf)3712e192b24SSimon Glass static int write_record(char *buf)
3722e192b24SSimon Glass {
3732e192b24SSimon Glass char c;
3742e192b24SSimon Glass
3752e192b24SSimon Glass while((c = *buf++))
3762e192b24SSimon Glass putc(c);
3772e192b24SSimon Glass
3782e192b24SSimon Glass /* Check for the console hangup (if any different from serial) */
3792e192b24SSimon Glass
3802e192b24SSimon Glass if (ctrlc()) {
3812e192b24SSimon Glass return (-1);
3822e192b24SSimon Glass }
3832e192b24SSimon Glass return (0);
3842e192b24SSimon Glass }
3852e192b24SSimon Glass # endif
3862e192b24SSimon Glass
3872e192b24SSimon Glass #endif
3882e192b24SSimon Glass
3892e192b24SSimon Glass
3902e192b24SSimon Glass #if defined(CONFIG_CMD_LOADB)
3912e192b24SSimon Glass /*
3922e192b24SSimon Glass * loadb command (load binary) included
3932e192b24SSimon Glass */
3942e192b24SSimon Glass #define XON_CHAR 17
3952e192b24SSimon Glass #define XOFF_CHAR 19
3962e192b24SSimon Glass #define START_CHAR 0x01
3972e192b24SSimon Glass #define ETX_CHAR 0x03
3982e192b24SSimon Glass #define END_CHAR 0x0D
3992e192b24SSimon Glass #define SPACE 0x20
4002e192b24SSimon Glass #define K_ESCAPE 0x23
4012e192b24SSimon Glass #define SEND_TYPE 'S'
4022e192b24SSimon Glass #define DATA_TYPE 'D'
4032e192b24SSimon Glass #define ACK_TYPE 'Y'
4042e192b24SSimon Glass #define NACK_TYPE 'N'
4052e192b24SSimon Glass #define BREAK_TYPE 'B'
4062e192b24SSimon Glass #define tochar(x) ((char) (((x) + SPACE) & 0xff))
4072e192b24SSimon Glass #define untochar(x) ((int) (((x) - SPACE) & 0xff))
4082e192b24SSimon Glass
4092e192b24SSimon Glass static void set_kerm_bin_mode(unsigned long *);
4102e192b24SSimon Glass static int k_recv(void);
4112e192b24SSimon Glass static ulong load_serial_bin(ulong offset);
4122e192b24SSimon Glass
4132e192b24SSimon Glass
4142e192b24SSimon Glass static char his_eol; /* character he needs at end of packet */
4152e192b24SSimon Glass static int his_pad_count; /* number of pad chars he needs */
4162e192b24SSimon Glass static char his_pad_char; /* pad chars he needs */
4172e192b24SSimon Glass static char his_quote; /* quote chars he'll use */
4182e192b24SSimon Glass
do_load_serial_bin(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])4192e192b24SSimon Glass static int do_load_serial_bin(cmd_tbl_t *cmdtp, int flag, int argc,
4202e192b24SSimon Glass char * const argv[])
4212e192b24SSimon Glass {
4222e192b24SSimon Glass ulong offset = 0;
4232e192b24SSimon Glass ulong addr;
4242e192b24SSimon Glass int load_baudrate, current_baudrate;
4252e192b24SSimon Glass int rcode = 0;
4262e192b24SSimon Glass char *s;
4272e192b24SSimon Glass
4282e192b24SSimon Glass /* pre-set offset from CONFIG_SYS_LOAD_ADDR */
4292e192b24SSimon Glass offset = CONFIG_SYS_LOAD_ADDR;
4302e192b24SSimon Glass
4312e192b24SSimon Glass /* pre-set offset from $loadaddr */
43200caae6dSSimon Glass s = env_get("loadaddr");
43300caae6dSSimon Glass if (s)
4342e192b24SSimon Glass offset = simple_strtoul(s, NULL, 16);
4352e192b24SSimon Glass
4362e192b24SSimon Glass load_baudrate = current_baudrate = gd->baudrate;
4372e192b24SSimon Glass
4382e192b24SSimon Glass if (argc >= 2) {
4392e192b24SSimon Glass offset = simple_strtoul(argv[1], NULL, 16);
4402e192b24SSimon Glass }
4412e192b24SSimon Glass if (argc == 3) {
4422e192b24SSimon Glass load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
4432e192b24SSimon Glass
4442e192b24SSimon Glass /* default to current baudrate */
4452e192b24SSimon Glass if (load_baudrate == 0)
4462e192b24SSimon Glass load_baudrate = current_baudrate;
4472e192b24SSimon Glass }
4482e192b24SSimon Glass
4492e192b24SSimon Glass if (load_baudrate != current_baudrate) {
4502e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ENTER ...\n",
4512e192b24SSimon Glass load_baudrate);
4522e192b24SSimon Glass udelay(50000);
4532e192b24SSimon Glass gd->baudrate = load_baudrate;
4542e192b24SSimon Glass serial_setbrg();
4552e192b24SSimon Glass udelay(50000);
4562e192b24SSimon Glass for (;;) {
4572e192b24SSimon Glass if (getc() == '\r')
4582e192b24SSimon Glass break;
4592e192b24SSimon Glass }
4602e192b24SSimon Glass }
4612e192b24SSimon Glass
4622e192b24SSimon Glass if (strcmp(argv[0],"loady")==0) {
4632e192b24SSimon Glass printf("## Ready for binary (ymodem) download "
4642e192b24SSimon Glass "to 0x%08lX at %d bps...\n",
4652e192b24SSimon Glass offset,
4662e192b24SSimon Glass load_baudrate);
4672e192b24SSimon Glass
4682e192b24SSimon Glass addr = load_serial_ymodem(offset, xyzModem_ymodem);
4692e192b24SSimon Glass
470*48650c55SJoseph Chen } else if (strcmp(argv[0],"loadz")==0) {
471*48650c55SJoseph Chen printf("## Ready for binary (zmodem) download"
472*48650c55SJoseph Chen "to 0x%08lX at %d bps...\n",
473*48650c55SJoseph Chen offset, load_baudrate);
474*48650c55SJoseph Chen addr = load_serial_zmodem(offset);
475*48650c55SJoseph Chen
4762e192b24SSimon Glass } else if (strcmp(argv[0],"loadx")==0) {
4772e192b24SSimon Glass printf("## Ready for binary (xmodem) download "
4782e192b24SSimon Glass "to 0x%08lX at %d bps...\n",
4792e192b24SSimon Glass offset,
4802e192b24SSimon Glass load_baudrate);
4812e192b24SSimon Glass
4822e192b24SSimon Glass addr = load_serial_ymodem(offset, xyzModem_xmodem);
4832e192b24SSimon Glass
4842e192b24SSimon Glass } else {
4852e192b24SSimon Glass
4862e192b24SSimon Glass printf("## Ready for binary (kermit) download "
4872e192b24SSimon Glass "to 0x%08lX at %d bps...\n",
4882e192b24SSimon Glass offset,
4892e192b24SSimon Glass load_baudrate);
4902e192b24SSimon Glass addr = load_serial_bin(offset);
4912e192b24SSimon Glass
4922e192b24SSimon Glass if (addr == ~0) {
4932e192b24SSimon Glass load_addr = 0;
4942e192b24SSimon Glass printf("## Binary (kermit) download aborted\n");
4952e192b24SSimon Glass rcode = 1;
4962e192b24SSimon Glass } else {
4972e192b24SSimon Glass printf("## Start Addr = 0x%08lX\n", addr);
4982e192b24SSimon Glass load_addr = addr;
4992e192b24SSimon Glass }
5002e192b24SSimon Glass }
5012e192b24SSimon Glass if (load_baudrate != current_baudrate) {
5022e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ESC ...\n",
5032e192b24SSimon Glass current_baudrate);
5042e192b24SSimon Glass udelay(50000);
5052e192b24SSimon Glass gd->baudrate = current_baudrate;
5062e192b24SSimon Glass serial_setbrg();
5072e192b24SSimon Glass udelay(50000);
5082e192b24SSimon Glass for (;;) {
5092e192b24SSimon Glass if (getc() == 0x1B) /* ESC */
5102e192b24SSimon Glass break;
5112e192b24SSimon Glass }
5122e192b24SSimon Glass }
5132e192b24SSimon Glass
5142e192b24SSimon Glass return rcode;
5152e192b24SSimon Glass }
5162e192b24SSimon Glass
5172e192b24SSimon Glass
load_serial_bin(ulong offset)5182e192b24SSimon Glass static ulong load_serial_bin(ulong offset)
5192e192b24SSimon Glass {
5202e192b24SSimon Glass int size, i;
5212e192b24SSimon Glass
5222e192b24SSimon Glass set_kerm_bin_mode((ulong *) offset);
5232e192b24SSimon Glass size = k_recv();
5242e192b24SSimon Glass
5252e192b24SSimon Glass /*
5262e192b24SSimon Glass * Gather any trailing characters (for instance, the ^D which
5272e192b24SSimon Glass * is sent by 'cu' after sending a file), and give the
5282e192b24SSimon Glass * box some time (100 * 1 ms)
5292e192b24SSimon Glass */
5302e192b24SSimon Glass for (i=0; i<100; ++i) {
5312e192b24SSimon Glass if (tstc()) {
5322e192b24SSimon Glass (void) getc();
5332e192b24SSimon Glass }
5342e192b24SSimon Glass udelay(1000);
5352e192b24SSimon Glass }
5362e192b24SSimon Glass
5372e192b24SSimon Glass flush_cache(offset, size);
5382e192b24SSimon Glass
5392e192b24SSimon Glass printf("## Total Size = 0x%08x = %d Bytes\n", size, size);
540018f5303SSimon Glass env_set_hex("filesize", size);
5412e192b24SSimon Glass
5422e192b24SSimon Glass return offset;
5432e192b24SSimon Glass }
5442e192b24SSimon Glass
send_pad(void)5452e192b24SSimon Glass static void send_pad(void)
5462e192b24SSimon Glass {
5472e192b24SSimon Glass int count = his_pad_count;
5482e192b24SSimon Glass
5492e192b24SSimon Glass while (count-- > 0)
5502e192b24SSimon Glass putc(his_pad_char);
5512e192b24SSimon Glass }
5522e192b24SSimon Glass
5532e192b24SSimon Glass /* converts escaped kermit char to binary char */
ktrans(char in)5542e192b24SSimon Glass static char ktrans(char in)
5552e192b24SSimon Glass {
5562e192b24SSimon Glass if ((in & 0x60) == 0x40) {
5572e192b24SSimon Glass return (char) (in & ~0x40);
5582e192b24SSimon Glass } else if ((in & 0x7f) == 0x3f) {
5592e192b24SSimon Glass return (char) (in | 0x40);
5602e192b24SSimon Glass } else
5612e192b24SSimon Glass return in;
5622e192b24SSimon Glass }
5632e192b24SSimon Glass
chk1(char * buffer)5642e192b24SSimon Glass static int chk1(char *buffer)
5652e192b24SSimon Glass {
5662e192b24SSimon Glass int total = 0;
5672e192b24SSimon Glass
5682e192b24SSimon Glass while (*buffer) {
5692e192b24SSimon Glass total += *buffer++;
5702e192b24SSimon Glass }
5712e192b24SSimon Glass return (int) ((total + ((total >> 6) & 0x03)) & 0x3f);
5722e192b24SSimon Glass }
5732e192b24SSimon Glass
s1_sendpacket(char * packet)5742e192b24SSimon Glass static void s1_sendpacket(char *packet)
5752e192b24SSimon Glass {
5762e192b24SSimon Glass send_pad();
5772e192b24SSimon Glass while (*packet) {
5782e192b24SSimon Glass putc(*packet++);
5792e192b24SSimon Glass }
5802e192b24SSimon Glass }
5812e192b24SSimon Glass
5822e192b24SSimon Glass static char a_b[24];
send_ack(int n)5832e192b24SSimon Glass static void send_ack(int n)
5842e192b24SSimon Glass {
5852e192b24SSimon Glass a_b[0] = START_CHAR;
5862e192b24SSimon Glass a_b[1] = tochar(3);
5872e192b24SSimon Glass a_b[2] = tochar(n);
5882e192b24SSimon Glass a_b[3] = ACK_TYPE;
5892e192b24SSimon Glass a_b[4] = '\0';
5902e192b24SSimon Glass a_b[4] = tochar(chk1(&a_b[1]));
5912e192b24SSimon Glass a_b[5] = his_eol;
5922e192b24SSimon Glass a_b[6] = '\0';
5932e192b24SSimon Glass s1_sendpacket(a_b);
5942e192b24SSimon Glass }
5952e192b24SSimon Glass
send_nack(int n)5962e192b24SSimon Glass static void send_nack(int n)
5972e192b24SSimon Glass {
5982e192b24SSimon Glass a_b[0] = START_CHAR;
5992e192b24SSimon Glass a_b[1] = tochar(3);
6002e192b24SSimon Glass a_b[2] = tochar(n);
6012e192b24SSimon Glass a_b[3] = NACK_TYPE;
6022e192b24SSimon Glass a_b[4] = '\0';
6032e192b24SSimon Glass a_b[4] = tochar(chk1(&a_b[1]));
6042e192b24SSimon Glass a_b[5] = his_eol;
6052e192b24SSimon Glass a_b[6] = '\0';
6062e192b24SSimon Glass s1_sendpacket(a_b);
6072e192b24SSimon Glass }
6082e192b24SSimon Glass
6092e192b24SSimon Glass
6102e192b24SSimon Glass static void (*os_data_init)(void);
6112e192b24SSimon Glass static void (*os_data_char)(char new_char);
6122e192b24SSimon Glass static int os_data_state, os_data_state_saved;
6132e192b24SSimon Glass static char *os_data_addr, *os_data_addr_saved;
6142e192b24SSimon Glass static char *bin_start_address;
6152e192b24SSimon Glass
bin_data_init(void)6162e192b24SSimon Glass static void bin_data_init(void)
6172e192b24SSimon Glass {
6182e192b24SSimon Glass os_data_state = 0;
6192e192b24SSimon Glass os_data_addr = bin_start_address;
6202e192b24SSimon Glass }
6212e192b24SSimon Glass
os_data_save(void)6222e192b24SSimon Glass static void os_data_save(void)
6232e192b24SSimon Glass {
6242e192b24SSimon Glass os_data_state_saved = os_data_state;
6252e192b24SSimon Glass os_data_addr_saved = os_data_addr;
6262e192b24SSimon Glass }
6272e192b24SSimon Glass
os_data_restore(void)6282e192b24SSimon Glass static void os_data_restore(void)
6292e192b24SSimon Glass {
6302e192b24SSimon Glass os_data_state = os_data_state_saved;
6312e192b24SSimon Glass os_data_addr = os_data_addr_saved;
6322e192b24SSimon Glass }
6332e192b24SSimon Glass
bin_data_char(char new_char)6342e192b24SSimon Glass static void bin_data_char(char new_char)
6352e192b24SSimon Glass {
6362e192b24SSimon Glass switch (os_data_state) {
6372e192b24SSimon Glass case 0: /* data */
6382e192b24SSimon Glass *os_data_addr++ = new_char;
6392e192b24SSimon Glass break;
6402e192b24SSimon Glass }
6412e192b24SSimon Glass }
6422e192b24SSimon Glass
set_kerm_bin_mode(unsigned long * addr)6432e192b24SSimon Glass static void set_kerm_bin_mode(unsigned long *addr)
6442e192b24SSimon Glass {
6452e192b24SSimon Glass bin_start_address = (char *) addr;
6462e192b24SSimon Glass os_data_init = bin_data_init;
6472e192b24SSimon Glass os_data_char = bin_data_char;
6482e192b24SSimon Glass }
6492e192b24SSimon Glass
6502e192b24SSimon Glass
6512e192b24SSimon Glass /* k_data_* simply handles the kermit escape translations */
6522e192b24SSimon Glass static int k_data_escape, k_data_escape_saved;
k_data_init(void)6532e192b24SSimon Glass static void k_data_init(void)
6542e192b24SSimon Glass {
6552e192b24SSimon Glass k_data_escape = 0;
6562e192b24SSimon Glass os_data_init();
6572e192b24SSimon Glass }
6582e192b24SSimon Glass
k_data_save(void)6592e192b24SSimon Glass static void k_data_save(void)
6602e192b24SSimon Glass {
6612e192b24SSimon Glass k_data_escape_saved = k_data_escape;
6622e192b24SSimon Glass os_data_save();
6632e192b24SSimon Glass }
6642e192b24SSimon Glass
k_data_restore(void)6652e192b24SSimon Glass static void k_data_restore(void)
6662e192b24SSimon Glass {
6672e192b24SSimon Glass k_data_escape = k_data_escape_saved;
6682e192b24SSimon Glass os_data_restore();
6692e192b24SSimon Glass }
6702e192b24SSimon Glass
k_data_char(char new_char)6712e192b24SSimon Glass static void k_data_char(char new_char)
6722e192b24SSimon Glass {
6732e192b24SSimon Glass if (k_data_escape) {
6742e192b24SSimon Glass /* last char was escape - translate this character */
6752e192b24SSimon Glass os_data_char(ktrans(new_char));
6762e192b24SSimon Glass k_data_escape = 0;
6772e192b24SSimon Glass } else {
6782e192b24SSimon Glass if (new_char == his_quote) {
6792e192b24SSimon Glass /* this char is escape - remember */
6802e192b24SSimon Glass k_data_escape = 1;
6812e192b24SSimon Glass } else {
6822e192b24SSimon Glass /* otherwise send this char as-is */
6832e192b24SSimon Glass os_data_char(new_char);
6842e192b24SSimon Glass }
6852e192b24SSimon Glass }
6862e192b24SSimon Glass }
6872e192b24SSimon Glass
6882e192b24SSimon Glass #define SEND_DATA_SIZE 20
6892e192b24SSimon Glass static char send_parms[SEND_DATA_SIZE];
6902e192b24SSimon Glass static char *send_ptr;
6912e192b24SSimon Glass
6922e192b24SSimon Glass /* handle_send_packet interprits the protocol info and builds and
6932e192b24SSimon Glass sends an appropriate ack for what we can do */
handle_send_packet(int n)6942e192b24SSimon Glass static void handle_send_packet(int n)
6952e192b24SSimon Glass {
6962e192b24SSimon Glass int length = 3;
6972e192b24SSimon Glass int bytes;
6982e192b24SSimon Glass
6992e192b24SSimon Glass /* initialize some protocol parameters */
7002e192b24SSimon Glass his_eol = END_CHAR; /* default end of line character */
7012e192b24SSimon Glass his_pad_count = 0;
7022e192b24SSimon Glass his_pad_char = '\0';
7032e192b24SSimon Glass his_quote = K_ESCAPE;
7042e192b24SSimon Glass
7052e192b24SSimon Glass /* ignore last character if it filled the buffer */
7062e192b24SSimon Glass if (send_ptr == &send_parms[SEND_DATA_SIZE - 1])
7072e192b24SSimon Glass --send_ptr;
7082e192b24SSimon Glass bytes = send_ptr - send_parms; /* how many bytes we'll process */
7092e192b24SSimon Glass do {
7102e192b24SSimon Glass if (bytes-- <= 0)
7112e192b24SSimon Glass break;
7122e192b24SSimon Glass /* handle MAXL - max length */
7132e192b24SSimon Glass /* ignore what he says - most I'll take (here) is 94 */
7142e192b24SSimon Glass a_b[++length] = tochar(94);
7152e192b24SSimon Glass if (bytes-- <= 0)
7162e192b24SSimon Glass break;
7172e192b24SSimon Glass /* handle TIME - time you should wait for my packets */
7182e192b24SSimon Glass /* ignore what he says - don't wait for my ack longer than 1 second */
7192e192b24SSimon Glass a_b[++length] = tochar(1);
7202e192b24SSimon Glass if (bytes-- <= 0)
7212e192b24SSimon Glass break;
7222e192b24SSimon Glass /* handle NPAD - number of pad chars I need */
7232e192b24SSimon Glass /* remember what he says - I need none */
7242e192b24SSimon Glass his_pad_count = untochar(send_parms[2]);
7252e192b24SSimon Glass a_b[++length] = tochar(0);
7262e192b24SSimon Glass if (bytes-- <= 0)
7272e192b24SSimon Glass break;
7282e192b24SSimon Glass /* handle PADC - pad chars I need */
7292e192b24SSimon Glass /* remember what he says - I need none */
7302e192b24SSimon Glass his_pad_char = ktrans(send_parms[3]);
7312e192b24SSimon Glass a_b[++length] = 0x40; /* He should ignore this */
7322e192b24SSimon Glass if (bytes-- <= 0)
7332e192b24SSimon Glass break;
7342e192b24SSimon Glass /* handle EOL - end of line he needs */
7352e192b24SSimon Glass /* remember what he says - I need CR */
7362e192b24SSimon Glass his_eol = untochar(send_parms[4]);
7372e192b24SSimon Glass a_b[++length] = tochar(END_CHAR);
7382e192b24SSimon Glass if (bytes-- <= 0)
7392e192b24SSimon Glass break;
7402e192b24SSimon Glass /* handle QCTL - quote control char he'll use */
7412e192b24SSimon Glass /* remember what he says - I'll use '#' */
7422e192b24SSimon Glass his_quote = send_parms[5];
7432e192b24SSimon Glass a_b[++length] = '#';
7442e192b24SSimon Glass if (bytes-- <= 0)
7452e192b24SSimon Glass break;
7462e192b24SSimon Glass /* handle QBIN - 8-th bit prefixing */
7472e192b24SSimon Glass /* ignore what he says - I refuse */
7482e192b24SSimon Glass a_b[++length] = 'N';
7492e192b24SSimon Glass if (bytes-- <= 0)
7502e192b24SSimon Glass break;
7512e192b24SSimon Glass /* handle CHKT - the clock check type */
7522e192b24SSimon Glass /* ignore what he says - I do type 1 (for now) */
7532e192b24SSimon Glass a_b[++length] = '1';
7542e192b24SSimon Glass if (bytes-- <= 0)
7552e192b24SSimon Glass break;
7562e192b24SSimon Glass /* handle REPT - the repeat prefix */
7572e192b24SSimon Glass /* ignore what he says - I refuse (for now) */
7582e192b24SSimon Glass a_b[++length] = 'N';
7592e192b24SSimon Glass if (bytes-- <= 0)
7602e192b24SSimon Glass break;
7612e192b24SSimon Glass /* handle CAPAS - the capabilities mask */
7622e192b24SSimon Glass /* ignore what he says - I only do long packets - I don't do windows */
7632e192b24SSimon Glass a_b[++length] = tochar(2); /* only long packets */
7642e192b24SSimon Glass a_b[++length] = tochar(0); /* no windows */
7652e192b24SSimon Glass a_b[++length] = tochar(94); /* large packet msb */
7662e192b24SSimon Glass a_b[++length] = tochar(94); /* large packet lsb */
7672e192b24SSimon Glass } while (0);
7682e192b24SSimon Glass
7692e192b24SSimon Glass a_b[0] = START_CHAR;
7702e192b24SSimon Glass a_b[1] = tochar(length);
7712e192b24SSimon Glass a_b[2] = tochar(n);
7722e192b24SSimon Glass a_b[3] = ACK_TYPE;
7732e192b24SSimon Glass a_b[++length] = '\0';
7742e192b24SSimon Glass a_b[length] = tochar(chk1(&a_b[1]));
7752e192b24SSimon Glass a_b[++length] = his_eol;
7762e192b24SSimon Glass a_b[++length] = '\0';
7772e192b24SSimon Glass s1_sendpacket(a_b);
7782e192b24SSimon Glass }
7792e192b24SSimon Glass
7802e192b24SSimon Glass /* k_recv receives a OS Open image file over kermit line */
k_recv(void)7812e192b24SSimon Glass static int k_recv(void)
7822e192b24SSimon Glass {
7832e192b24SSimon Glass char new_char;
7842e192b24SSimon Glass char k_state, k_state_saved;
7852e192b24SSimon Glass int sum;
7862e192b24SSimon Glass int done;
7872e192b24SSimon Glass int length;
7882e192b24SSimon Glass int n, last_n;
7892e192b24SSimon Glass int len_lo, len_hi;
7902e192b24SSimon Glass
7912e192b24SSimon Glass /* initialize some protocol parameters */
7922e192b24SSimon Glass his_eol = END_CHAR; /* default end of line character */
7932e192b24SSimon Glass his_pad_count = 0;
7942e192b24SSimon Glass his_pad_char = '\0';
7952e192b24SSimon Glass his_quote = K_ESCAPE;
7962e192b24SSimon Glass
7972e192b24SSimon Glass /* initialize the k_recv and k_data state machine */
7982e192b24SSimon Glass done = 0;
7992e192b24SSimon Glass k_state = 0;
8002e192b24SSimon Glass k_data_init();
8012e192b24SSimon Glass k_state_saved = k_state;
8022e192b24SSimon Glass k_data_save();
8032e192b24SSimon Glass n = 0; /* just to get rid of a warning */
8042e192b24SSimon Glass last_n = -1;
8052e192b24SSimon Glass
8062e192b24SSimon Glass /* expect this "type" sequence (but don't check):
8072e192b24SSimon Glass S: send initiate
8082e192b24SSimon Glass F: file header
8092e192b24SSimon Glass D: data (multiple)
8102e192b24SSimon Glass Z: end of file
8112e192b24SSimon Glass B: break transmission
8122e192b24SSimon Glass */
8132e192b24SSimon Glass
8142e192b24SSimon Glass /* enter main loop */
8152e192b24SSimon Glass while (!done) {
8162e192b24SSimon Glass /* set the send packet pointer to begining of send packet parms */
8172e192b24SSimon Glass send_ptr = send_parms;
8182e192b24SSimon Glass
8192e192b24SSimon Glass /* With each packet, start summing the bytes starting with the length.
8202e192b24SSimon Glass Save the current sequence number.
8212e192b24SSimon Glass Note the type of the packet.
8222e192b24SSimon Glass If a character less than SPACE (0x20) is received - error.
8232e192b24SSimon Glass */
8242e192b24SSimon Glass
8252e192b24SSimon Glass #if 0
8262e192b24SSimon Glass /* OLD CODE, Prior to checking sequence numbers */
8272e192b24SSimon Glass /* first have all state machines save current states */
8282e192b24SSimon Glass k_state_saved = k_state;
8292e192b24SSimon Glass k_data_save ();
8302e192b24SSimon Glass #endif
8312e192b24SSimon Glass
8322e192b24SSimon Glass /* get a packet */
8332e192b24SSimon Glass /* wait for the starting character or ^C */
8342e192b24SSimon Glass for (;;) {
8352e192b24SSimon Glass switch (getc ()) {
8362e192b24SSimon Glass case START_CHAR: /* start packet */
8372e192b24SSimon Glass goto START;
8382e192b24SSimon Glass case ETX_CHAR: /* ^C waiting for packet */
8392e192b24SSimon Glass return (0);
8402e192b24SSimon Glass default:
8412e192b24SSimon Glass ;
8422e192b24SSimon Glass }
8432e192b24SSimon Glass }
8442e192b24SSimon Glass START:
8452e192b24SSimon Glass /* get length of packet */
8462e192b24SSimon Glass sum = 0;
8472e192b24SSimon Glass new_char = getc();
8482e192b24SSimon Glass if ((new_char & 0xE0) == 0)
8492e192b24SSimon Glass goto packet_error;
8502e192b24SSimon Glass sum += new_char & 0xff;
8512e192b24SSimon Glass length = untochar(new_char);
8522e192b24SSimon Glass /* get sequence number */
8532e192b24SSimon Glass new_char = getc();
8542e192b24SSimon Glass if ((new_char & 0xE0) == 0)
8552e192b24SSimon Glass goto packet_error;
8562e192b24SSimon Glass sum += new_char & 0xff;
8572e192b24SSimon Glass n = untochar(new_char);
8582e192b24SSimon Glass --length;
8592e192b24SSimon Glass
8602e192b24SSimon Glass /* NEW CODE - check sequence numbers for retried packets */
8612e192b24SSimon Glass /* Note - this new code assumes that the sequence number is correctly
8622e192b24SSimon Glass * received. Handling an invalid sequence number adds another layer
8632e192b24SSimon Glass * of complexity that may not be needed - yet! At this time, I'm hoping
8642e192b24SSimon Glass * that I don't need to buffer the incoming data packets and can write
8652e192b24SSimon Glass * the data into memory in real time.
8662e192b24SSimon Glass */
8672e192b24SSimon Glass if (n == last_n) {
8682e192b24SSimon Glass /* same sequence number, restore the previous state */
8692e192b24SSimon Glass k_state = k_state_saved;
8702e192b24SSimon Glass k_data_restore();
8712e192b24SSimon Glass } else {
8722e192b24SSimon Glass /* new sequence number, checkpoint the download */
8732e192b24SSimon Glass last_n = n;
8742e192b24SSimon Glass k_state_saved = k_state;
8752e192b24SSimon Glass k_data_save();
8762e192b24SSimon Glass }
8772e192b24SSimon Glass /* END NEW CODE */
8782e192b24SSimon Glass
8792e192b24SSimon Glass /* get packet type */
8802e192b24SSimon Glass new_char = getc();
8812e192b24SSimon Glass if ((new_char & 0xE0) == 0)
8822e192b24SSimon Glass goto packet_error;
8832e192b24SSimon Glass sum += new_char & 0xff;
8842e192b24SSimon Glass k_state = new_char;
8852e192b24SSimon Glass --length;
8862e192b24SSimon Glass /* check for extended length */
8872e192b24SSimon Glass if (length == -2) {
8882e192b24SSimon Glass /* (length byte was 0, decremented twice) */
8892e192b24SSimon Glass /* get the two length bytes */
8902e192b24SSimon Glass new_char = getc();
8912e192b24SSimon Glass if ((new_char & 0xE0) == 0)
8922e192b24SSimon Glass goto packet_error;
8932e192b24SSimon Glass sum += new_char & 0xff;
8942e192b24SSimon Glass len_hi = untochar(new_char);
8952e192b24SSimon Glass new_char = getc();
8962e192b24SSimon Glass if ((new_char & 0xE0) == 0)
8972e192b24SSimon Glass goto packet_error;
8982e192b24SSimon Glass sum += new_char & 0xff;
8992e192b24SSimon Glass len_lo = untochar(new_char);
9002e192b24SSimon Glass length = len_hi * 95 + len_lo;
9012e192b24SSimon Glass /* check header checksum */
9022e192b24SSimon Glass new_char = getc();
9032e192b24SSimon Glass if ((new_char & 0xE0) == 0)
9042e192b24SSimon Glass goto packet_error;
9052e192b24SSimon Glass if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
9062e192b24SSimon Glass goto packet_error;
9072e192b24SSimon Glass sum += new_char & 0xff;
9082e192b24SSimon Glass /* --length; */ /* new length includes only data and block check to come */
9092e192b24SSimon Glass }
9102e192b24SSimon Glass /* bring in rest of packet */
9112e192b24SSimon Glass while (length > 1) {
9122e192b24SSimon Glass new_char = getc();
9132e192b24SSimon Glass if ((new_char & 0xE0) == 0)
9142e192b24SSimon Glass goto packet_error;
9152e192b24SSimon Glass sum += new_char & 0xff;
9162e192b24SSimon Glass --length;
9172e192b24SSimon Glass if (k_state == DATA_TYPE) {
9182e192b24SSimon Glass /* pass on the data if this is a data packet */
9192e192b24SSimon Glass k_data_char (new_char);
9202e192b24SSimon Glass } else if (k_state == SEND_TYPE) {
9212e192b24SSimon Glass /* save send pack in buffer as is */
9222e192b24SSimon Glass *send_ptr++ = new_char;
9232e192b24SSimon Glass /* if too much data, back off the pointer */
9242e192b24SSimon Glass if (send_ptr >= &send_parms[SEND_DATA_SIZE])
9252e192b24SSimon Glass --send_ptr;
9262e192b24SSimon Glass }
9272e192b24SSimon Glass }
9282e192b24SSimon Glass /* get and validate checksum character */
9292e192b24SSimon Glass new_char = getc();
9302e192b24SSimon Glass if ((new_char & 0xE0) == 0)
9312e192b24SSimon Glass goto packet_error;
9322e192b24SSimon Glass if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
9332e192b24SSimon Glass goto packet_error;
9342e192b24SSimon Glass /* get END_CHAR */
9352e192b24SSimon Glass new_char = getc();
9362e192b24SSimon Glass if (new_char != END_CHAR) {
9372e192b24SSimon Glass packet_error:
9382e192b24SSimon Glass /* restore state machines */
9392e192b24SSimon Glass k_state = k_state_saved;
9402e192b24SSimon Glass k_data_restore();
9412e192b24SSimon Glass /* send a negative acknowledge packet in */
9422e192b24SSimon Glass send_nack(n);
9432e192b24SSimon Glass } else if (k_state == SEND_TYPE) {
9442e192b24SSimon Glass /* crack the protocol parms, build an appropriate ack packet */
9452e192b24SSimon Glass handle_send_packet(n);
9462e192b24SSimon Glass } else {
9472e192b24SSimon Glass /* send simple acknowledge packet in */
9482e192b24SSimon Glass send_ack(n);
9492e192b24SSimon Glass /* quit if end of transmission */
9502e192b24SSimon Glass if (k_state == BREAK_TYPE)
9512e192b24SSimon Glass done = 1;
9522e192b24SSimon Glass }
9532e192b24SSimon Glass }
9542e192b24SSimon Glass return ((ulong) os_data_addr - (ulong) bin_start_address);
9552e192b24SSimon Glass }
9562e192b24SSimon Glass
getcxmodem(void)9572e192b24SSimon Glass static int getcxmodem(void) {
9582e192b24SSimon Glass if (tstc())
9592e192b24SSimon Glass return (getc());
9602e192b24SSimon Glass return -1;
9612e192b24SSimon Glass }
962*48650c55SJoseph Chen
963*48650c55SJoseph Chen extern int zmodem_rx(unsigned int addr, int *rxsize);
load_serial_zmodem(ulong offset)964*48650c55SJoseph Chen static ulong load_serial_zmodem(ulong offset)
965*48650c55SJoseph Chen {
966*48650c55SJoseph Chen int size = 0;
967*48650c55SJoseph Chen int res;
968*48650c55SJoseph Chen
969*48650c55SJoseph Chen printf("Start to run ZModem\n");
970*48650c55SJoseph Chen res = zmodem_rx(offset, &size);
971*48650c55SJoseph Chen if (res) {
972*48650c55SJoseph Chen printf("ZModem download error, ret=%d\n", res);
973*48650c55SJoseph Chen return offset;
974*48650c55SJoseph Chen }
975*48650c55SJoseph Chen
976*48650c55SJoseph Chen flush_cache(offset, ALIGN(size, ARCH_DMA_MINALIGN));
977*48650c55SJoseph Chen printf("## Total Size = 0x%08x = %d Bytes\n", size, size);
978*48650c55SJoseph Chen env_set_hex("filesize", size);
979*48650c55SJoseph Chen
980*48650c55SJoseph Chen return offset;
981*48650c55SJoseph Chen }
982*48650c55SJoseph Chen
load_serial_ymodem(ulong offset,int mode)9832e192b24SSimon Glass static ulong load_serial_ymodem(ulong offset, int mode)
9842e192b24SSimon Glass {
9852e192b24SSimon Glass int size;
9862e192b24SSimon Glass int err;
9872e192b24SSimon Glass int res;
9882e192b24SSimon Glass connection_info_t info;
9892e192b24SSimon Glass char ymodemBuf[1024];
9902e192b24SSimon Glass ulong store_addr = ~0;
9912e192b24SSimon Glass ulong addr = 0;
9922e192b24SSimon Glass
9932e192b24SSimon Glass size = 0;
9942e192b24SSimon Glass info.mode = mode;
9952e192b24SSimon Glass res = xyzModem_stream_open(&info, &err);
9962e192b24SSimon Glass if (!res) {
9972e192b24SSimon Glass
9982e192b24SSimon Glass while ((res =
9992e192b24SSimon Glass xyzModem_stream_read(ymodemBuf, 1024, &err)) > 0) {
10002e192b24SSimon Glass store_addr = addr + offset;
10012e192b24SSimon Glass size += res;
10022e192b24SSimon Glass addr += res;
1003e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH
10042e192b24SSimon Glass if (addr2info(store_addr)) {
10052e192b24SSimon Glass int rc;
10062e192b24SSimon Glass
10072e192b24SSimon Glass rc = flash_write((char *) ymodemBuf,
10082e192b24SSimon Glass store_addr, res);
10092e192b24SSimon Glass if (rc != 0) {
10102e192b24SSimon Glass flash_perror (rc);
10112e192b24SSimon Glass return (~0);
10122e192b24SSimon Glass }
10132e192b24SSimon Glass } else
10142e192b24SSimon Glass #endif
10152e192b24SSimon Glass {
10162e192b24SSimon Glass memcpy((char *)(store_addr), ymodemBuf,
10172e192b24SSimon Glass res);
10182e192b24SSimon Glass }
10192e192b24SSimon Glass
10202e192b24SSimon Glass }
10212e192b24SSimon Glass } else {
10222e192b24SSimon Glass printf("%s\n", xyzModem_error(err));
10232e192b24SSimon Glass }
10242e192b24SSimon Glass
10252e192b24SSimon Glass xyzModem_stream_close(&err);
10262e192b24SSimon Glass xyzModem_stream_terminate(false, &getcxmodem);
10272e192b24SSimon Glass
10282e192b24SSimon Glass
10290a6036daSChris Packham flush_cache(offset, ALIGN(size, ARCH_DMA_MINALIGN));
10302e192b24SSimon Glass
10312e192b24SSimon Glass printf("## Total Size = 0x%08x = %d Bytes\n", size, size);
1032018f5303SSimon Glass env_set_hex("filesize", size);
10332e192b24SSimon Glass
10342e192b24SSimon Glass return offset;
10352e192b24SSimon Glass }
10362e192b24SSimon Glass
do_loadz_flash(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])1037*48650c55SJoseph Chen static int do_loadz_flash(cmd_tbl_t *cmdtp, int flag, int argc,
1038*48650c55SJoseph Chen char * const argv[])
1039*48650c55SJoseph Chen {
1040*48650c55SJoseph Chen struct blk_desc *dev_desc;
1041*48650c55SJoseph Chen disk_partition_t part;
1042*48650c55SJoseph Chen const char *part_name;
1043*48650c55SJoseph Chen char cmd[64];
1044*48650c55SJoseph Chen ulong addr, size;
1045*48650c55SJoseph Chen int ret, blknum;
1046*48650c55SJoseph Chen int baudrate;
1047*48650c55SJoseph Chen
1048*48650c55SJoseph Chen if (argc != 4)
1049*48650c55SJoseph Chen return CMD_RET_USAGE;
1050*48650c55SJoseph Chen
1051*48650c55SJoseph Chen addr = simple_strtol(argv[1], NULL, 16);
1052*48650c55SJoseph Chen baudrate = (int)simple_strtoul(argv[2], NULL, 10);
1053*48650c55SJoseph Chen part_name = argv[3];
1054*48650c55SJoseph Chen
1055*48650c55SJoseph Chen /* search partition */
1056*48650c55SJoseph Chen dev_desc = rockchip_get_bootdev();
1057*48650c55SJoseph Chen if (!dev_desc) {
1058*48650c55SJoseph Chen printf("No boot device\n");
1059*48650c55SJoseph Chen return -ENODEV;
1060*48650c55SJoseph Chen }
1061*48650c55SJoseph Chen
1062*48650c55SJoseph Chen ret = part_get_info_by_name(dev_desc, part_name, &part);
1063*48650c55SJoseph Chen if (ret < 0) {
1064*48650c55SJoseph Chen printf("No partition '%s'\n", part_name);
1065*48650c55SJoseph Chen return -EINVAL;
1066*48650c55SJoseph Chen }
1067*48650c55SJoseph Chen
1068*48650c55SJoseph Chen snprintf(cmd, 64, "loadz 0x%08lx %d\n", addr, baudrate);
1069*48650c55SJoseph Chen ret = run_command(cmd, 0);
1070*48650c55SJoseph Chen if (ret) {
1071*48650c55SJoseph Chen printf("loadz failed, ret=%d\n", ret);
1072*48650c55SJoseph Chen return CMD_RET_FAILURE;
1073*48650c55SJoseph Chen }
1074*48650c55SJoseph Chen
1075*48650c55SJoseph Chen size = env_get_ulong("filesize", 16, 0);
1076*48650c55SJoseph Chen if (!size) {
1077*48650c55SJoseph Chen printf("loadz empty file\n");
1078*48650c55SJoseph Chen return CMD_RET_FAILURE;
1079*48650c55SJoseph Chen }
1080*48650c55SJoseph Chen
1081*48650c55SJoseph Chen /* flash */
1082*48650c55SJoseph Chen blknum = DIV_ROUND_UP(size, dev_desc->blksz);
1083*48650c55SJoseph Chen if (blknum > part.size) {
1084*48650c55SJoseph Chen printf("File size 0x%lx is too large to flash\n", size);
1085*48650c55SJoseph Chen return CMD_RET_FAILURE;
1086*48650c55SJoseph Chen }
1087*48650c55SJoseph Chen
1088*48650c55SJoseph Chen #ifdef CONFIG_CMD_CRYPTO_SUM
1089*48650c55SJoseph Chen snprintf(cmd, 64, "crypto_sum sha256 0x%lx 0x%lx", addr, size);
1090*48650c55SJoseph Chen run_command(cmd, 0);
1091*48650c55SJoseph Chen #elif defined(CONFIG_CMD_HASH)
1092*48650c55SJoseph Chen snprintf(cmd, 64, "hash sha256 0x%lx 0x%lx", addr, size);
1093*48650c55SJoseph Chen run_command(cmd, 0);
1094*48650c55SJoseph Chen #endif
1095*48650c55SJoseph Chen
1096*48650c55SJoseph Chen printf("## Flash data to partition %s@0x%lx sector with size 0x%lx ... ",
1097*48650c55SJoseph Chen part_name, (ulong)part.start, (ulong)size);
1098*48650c55SJoseph Chen if (dev_desc->if_type == IF_TYPE_MTD)
1099*48650c55SJoseph Chen dev_desc->op_flag |= BLK_MTD_CONT_WRITE;
1100*48650c55SJoseph Chen ret = blk_dwrite(dev_desc, part.start, blknum, (void *)addr);
1101*48650c55SJoseph Chen if (dev_desc->if_type == IF_TYPE_MTD)
1102*48650c55SJoseph Chen dev_desc->op_flag &= ~(BLK_MTD_CONT_WRITE);
1103*48650c55SJoseph Chen if (ret != blknum) {
1104*48650c55SJoseph Chen printf("Failed(%d)\n\n", ret);
1105*48650c55SJoseph Chen return CMD_RET_FAILURE;
1106*48650c55SJoseph Chen }
1107*48650c55SJoseph Chen printf("OK\n\n");
1108*48650c55SJoseph Chen
1109*48650c55SJoseph Chen return CMD_RET_SUCCESS;
1110*48650c55SJoseph Chen }
11112e192b24SSimon Glass #endif
11122e192b24SSimon Glass
11132e192b24SSimon Glass /* -------------------------------------------------------------------- */
11142e192b24SSimon Glass
11152e192b24SSimon Glass #if defined(CONFIG_CMD_LOADS)
11162e192b24SSimon Glass
11172e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
11182e192b24SSimon Glass U_BOOT_CMD(
11192e192b24SSimon Glass loads, 3, 0, do_load_serial,
11202e192b24SSimon Glass "load S-Record file over serial line",
11212e192b24SSimon Glass "[ off ] [ baud ]\n"
11222e192b24SSimon Glass " - load S-Record file over serial line"
11232e192b24SSimon Glass " with offset 'off' and baudrate 'baud'"
11242e192b24SSimon Glass );
11252e192b24SSimon Glass
11262e192b24SSimon Glass #else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
11272e192b24SSimon Glass U_BOOT_CMD(
11282e192b24SSimon Glass loads, 2, 0, do_load_serial,
11292e192b24SSimon Glass "load S-Record file over serial line",
11302e192b24SSimon Glass "[ off ]\n"
11312e192b24SSimon Glass " - load S-Record file over serial line with offset 'off'"
11322e192b24SSimon Glass );
11332e192b24SSimon Glass #endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */
11342e192b24SSimon Glass
11352e192b24SSimon Glass /*
11362e192b24SSimon Glass * SAVES always requires LOADS support, but not vice versa
11372e192b24SSimon Glass */
11382e192b24SSimon Glass
11392e192b24SSimon Glass
11402e192b24SSimon Glass #if defined(CONFIG_CMD_SAVES)
11412e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE
11422e192b24SSimon Glass U_BOOT_CMD(
11432e192b24SSimon Glass saves, 4, 0, do_save_serial,
11442e192b24SSimon Glass "save S-Record file over serial line",
11452e192b24SSimon Glass "[ off ] [size] [ baud ]\n"
11462e192b24SSimon Glass " - save S-Record file over serial line"
11472e192b24SSimon Glass " with offset 'off', size 'size' and baudrate 'baud'"
11482e192b24SSimon Glass );
11492e192b24SSimon Glass #else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
11502e192b24SSimon Glass U_BOOT_CMD(
11512e192b24SSimon Glass saves, 3, 0, do_save_serial,
11522e192b24SSimon Glass "save S-Record file over serial line",
11532e192b24SSimon Glass "[ off ] [size]\n"
11542e192b24SSimon Glass " - save S-Record file over serial line with offset 'off' and size 'size'"
11552e192b24SSimon Glass );
11562e192b24SSimon Glass #endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */
11572e192b24SSimon Glass #endif /* CONFIG_CMD_SAVES */
11582e192b24SSimon Glass #endif /* CONFIG_CMD_LOADS */
11592e192b24SSimon Glass
11602e192b24SSimon Glass
11612e192b24SSimon Glass #if defined(CONFIG_CMD_LOADB)
11622e192b24SSimon Glass U_BOOT_CMD(
11632e192b24SSimon Glass loadb, 3, 0, do_load_serial_bin,
11642e192b24SSimon Glass "load binary file over serial line (kermit mode)",
11652e192b24SSimon Glass "[ off ] [ baud ]\n"
11662e192b24SSimon Glass " - load binary file over serial line"
11672e192b24SSimon Glass " with offset 'off' and baudrate 'baud'"
11682e192b24SSimon Glass );
11692e192b24SSimon Glass
11702e192b24SSimon Glass U_BOOT_CMD(
11712e192b24SSimon Glass loadx, 3, 0, do_load_serial_bin,
11722e192b24SSimon Glass "load binary file over serial line (xmodem mode)",
11732e192b24SSimon Glass "[ off ] [ baud ]\n"
11742e192b24SSimon Glass " - load binary file over serial line"
11752e192b24SSimon Glass " with offset 'off' and baudrate 'baud'"
11762e192b24SSimon Glass );
11772e192b24SSimon Glass
11782e192b24SSimon Glass U_BOOT_CMD(
11792e192b24SSimon Glass loady, 3, 0, do_load_serial_bin,
11802e192b24SSimon Glass "load binary file over serial line (ymodem mode)",
11812e192b24SSimon Glass "[ off ] [ baud ]\n"
11822e192b24SSimon Glass " - load binary file over serial line"
11832e192b24SSimon Glass " with offset 'off' and baudrate 'baud'"
11842e192b24SSimon Glass );
11852e192b24SSimon Glass
1186*48650c55SJoseph Chen U_BOOT_CMD(
1187*48650c55SJoseph Chen loadz, 3, 0, do_load_serial_bin,
1188*48650c55SJoseph Chen "load binary file over serial line (zmodem mode)",
1189*48650c55SJoseph Chen "[ off ] [ baud ]\n"
1190*48650c55SJoseph Chen " - load binary file over serial line"
1191*48650c55SJoseph Chen " with offset 'off' and baudrate 'baud'"
1192*48650c55SJoseph Chen );
1193*48650c55SJoseph Chen
1194*48650c55SJoseph Chen U_BOOT_CMD(
1195*48650c55SJoseph Chen loadzflash, 4, 0, do_loadz_flash,
1196*48650c55SJoseph Chen "load binary file over serial line (zmodem mode) and flash to partition",
1197*48650c55SJoseph Chen "[ off ] [ baud ] [partition]\n"
1198*48650c55SJoseph Chen " - load binary file over serial line"
1199*48650c55SJoseph Chen " with offset 'off' and baudrate 'baud' and flash to 'partition'"
1200*48650c55SJoseph Chen );
12012e192b24SSimon Glass #endif /* CONFIG_CMD_LOADB */
1202