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