1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * (C) Copyright 2000-2004 3*2e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4*2e192b24SSimon Glass * 5*2e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6*2e192b24SSimon Glass */ 7*2e192b24SSimon Glass 8*2e192b24SSimon Glass /* 9*2e192b24SSimon Glass * Serial up- and download support 10*2e192b24SSimon Glass */ 11*2e192b24SSimon Glass #include <common.h> 12*2e192b24SSimon Glass #include <command.h> 13*2e192b24SSimon Glass #include <console.h> 14*2e192b24SSimon Glass #include <s_record.h> 15*2e192b24SSimon Glass #include <net.h> 16*2e192b24SSimon Glass #include <exports.h> 17*2e192b24SSimon Glass #include <xyzModem.h> 18*2e192b24SSimon Glass 19*2e192b24SSimon Glass DECLARE_GLOBAL_DATA_PTR; 20*2e192b24SSimon Glass 21*2e192b24SSimon Glass #if defined(CONFIG_CMD_LOADB) 22*2e192b24SSimon Glass static ulong load_serial_ymodem(ulong offset, int mode); 23*2e192b24SSimon Glass #endif 24*2e192b24SSimon Glass 25*2e192b24SSimon Glass #if defined(CONFIG_CMD_LOADS) 26*2e192b24SSimon Glass static ulong load_serial(long offset); 27*2e192b24SSimon Glass static int read_record(char *buf, ulong len); 28*2e192b24SSimon Glass # if defined(CONFIG_CMD_SAVES) 29*2e192b24SSimon Glass static int save_serial(ulong offset, ulong size); 30*2e192b24SSimon Glass static int write_record(char *buf); 31*2e192b24SSimon Glass #endif 32*2e192b24SSimon Glass 33*2e192b24SSimon Glass static int do_echo = 1; 34*2e192b24SSimon Glass #endif 35*2e192b24SSimon Glass 36*2e192b24SSimon Glass /* -------------------------------------------------------------------- */ 37*2e192b24SSimon Glass 38*2e192b24SSimon Glass #if defined(CONFIG_CMD_LOADS) 39*2e192b24SSimon Glass static int do_load_serial(cmd_tbl_t *cmdtp, int flag, int argc, 40*2e192b24SSimon Glass char * const argv[]) 41*2e192b24SSimon Glass { 42*2e192b24SSimon Glass long offset = 0; 43*2e192b24SSimon Glass ulong addr; 44*2e192b24SSimon Glass int i; 45*2e192b24SSimon Glass char *env_echo; 46*2e192b24SSimon Glass int rcode = 0; 47*2e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE 48*2e192b24SSimon Glass int load_baudrate, current_baudrate; 49*2e192b24SSimon Glass 50*2e192b24SSimon Glass load_baudrate = current_baudrate = gd->baudrate; 51*2e192b24SSimon Glass #endif 52*2e192b24SSimon Glass 53*2e192b24SSimon Glass if (((env_echo = getenv("loads_echo")) != NULL) && (*env_echo == '1')) { 54*2e192b24SSimon Glass do_echo = 1; 55*2e192b24SSimon Glass } else { 56*2e192b24SSimon Glass do_echo = 0; 57*2e192b24SSimon Glass } 58*2e192b24SSimon Glass 59*2e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE 60*2e192b24SSimon Glass if (argc >= 2) { 61*2e192b24SSimon Glass offset = simple_strtol(argv[1], NULL, 16); 62*2e192b24SSimon Glass } 63*2e192b24SSimon Glass if (argc == 3) { 64*2e192b24SSimon Glass load_baudrate = (int)simple_strtoul(argv[2], NULL, 10); 65*2e192b24SSimon Glass 66*2e192b24SSimon Glass /* default to current baudrate */ 67*2e192b24SSimon Glass if (load_baudrate == 0) 68*2e192b24SSimon Glass load_baudrate = current_baudrate; 69*2e192b24SSimon Glass } 70*2e192b24SSimon Glass if (load_baudrate != current_baudrate) { 71*2e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ENTER ...\n", 72*2e192b24SSimon Glass load_baudrate); 73*2e192b24SSimon Glass udelay(50000); 74*2e192b24SSimon Glass gd->baudrate = load_baudrate; 75*2e192b24SSimon Glass serial_setbrg(); 76*2e192b24SSimon Glass udelay(50000); 77*2e192b24SSimon Glass for (;;) { 78*2e192b24SSimon Glass if (getc() == '\r') 79*2e192b24SSimon Glass break; 80*2e192b24SSimon Glass } 81*2e192b24SSimon Glass } 82*2e192b24SSimon Glass #else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */ 83*2e192b24SSimon Glass if (argc == 2) { 84*2e192b24SSimon Glass offset = simple_strtol(argv[1], NULL, 16); 85*2e192b24SSimon Glass } 86*2e192b24SSimon Glass #endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */ 87*2e192b24SSimon Glass 88*2e192b24SSimon Glass printf("## Ready for S-Record download ...\n"); 89*2e192b24SSimon Glass 90*2e192b24SSimon Glass addr = load_serial(offset); 91*2e192b24SSimon Glass 92*2e192b24SSimon Glass /* 93*2e192b24SSimon Glass * Gather any trailing characters (for instance, the ^D which 94*2e192b24SSimon Glass * is sent by 'cu' after sending a file), and give the 95*2e192b24SSimon Glass * box some time (100 * 1 ms) 96*2e192b24SSimon Glass */ 97*2e192b24SSimon Glass for (i=0; i<100; ++i) { 98*2e192b24SSimon Glass if (tstc()) { 99*2e192b24SSimon Glass (void) getc(); 100*2e192b24SSimon Glass } 101*2e192b24SSimon Glass udelay(1000); 102*2e192b24SSimon Glass } 103*2e192b24SSimon Glass 104*2e192b24SSimon Glass if (addr == ~0) { 105*2e192b24SSimon Glass printf("## S-Record download aborted\n"); 106*2e192b24SSimon Glass rcode = 1; 107*2e192b24SSimon Glass } else { 108*2e192b24SSimon Glass printf("## Start Addr = 0x%08lX\n", addr); 109*2e192b24SSimon Glass load_addr = addr; 110*2e192b24SSimon Glass } 111*2e192b24SSimon Glass 112*2e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE 113*2e192b24SSimon Glass if (load_baudrate != current_baudrate) { 114*2e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ESC ...\n", 115*2e192b24SSimon Glass current_baudrate); 116*2e192b24SSimon Glass udelay(50000); 117*2e192b24SSimon Glass gd->baudrate = current_baudrate; 118*2e192b24SSimon Glass serial_setbrg(); 119*2e192b24SSimon Glass udelay(50000); 120*2e192b24SSimon Glass for (;;) { 121*2e192b24SSimon Glass if (getc() == 0x1B) /* ESC */ 122*2e192b24SSimon Glass break; 123*2e192b24SSimon Glass } 124*2e192b24SSimon Glass } 125*2e192b24SSimon Glass #endif 126*2e192b24SSimon Glass return rcode; 127*2e192b24SSimon Glass } 128*2e192b24SSimon Glass 129*2e192b24SSimon Glass static ulong load_serial(long offset) 130*2e192b24SSimon Glass { 131*2e192b24SSimon Glass char record[SREC_MAXRECLEN + 1]; /* buffer for one S-Record */ 132*2e192b24SSimon Glass char binbuf[SREC_MAXBINLEN]; /* buffer for binary data */ 133*2e192b24SSimon Glass int binlen; /* no. of data bytes in S-Rec. */ 134*2e192b24SSimon Glass int type; /* return code for record type */ 135*2e192b24SSimon Glass ulong addr; /* load address from S-Record */ 136*2e192b24SSimon Glass ulong size; /* number of bytes transferred */ 137*2e192b24SSimon Glass ulong store_addr; 138*2e192b24SSimon Glass ulong start_addr = ~0; 139*2e192b24SSimon Glass ulong end_addr = 0; 140*2e192b24SSimon Glass int line_count = 0; 141*2e192b24SSimon Glass 142*2e192b24SSimon Glass while (read_record(record, SREC_MAXRECLEN + 1) >= 0) { 143*2e192b24SSimon Glass type = srec_decode(record, &binlen, &addr, binbuf); 144*2e192b24SSimon Glass 145*2e192b24SSimon Glass if (type < 0) { 146*2e192b24SSimon Glass return (~0); /* Invalid S-Record */ 147*2e192b24SSimon Glass } 148*2e192b24SSimon Glass 149*2e192b24SSimon Glass switch (type) { 150*2e192b24SSimon Glass case SREC_DATA2: 151*2e192b24SSimon Glass case SREC_DATA3: 152*2e192b24SSimon Glass case SREC_DATA4: 153*2e192b24SSimon Glass store_addr = addr + offset; 154*2e192b24SSimon Glass #ifndef CONFIG_SYS_NO_FLASH 155*2e192b24SSimon Glass if (addr2info(store_addr)) { 156*2e192b24SSimon Glass int rc; 157*2e192b24SSimon Glass 158*2e192b24SSimon Glass rc = flash_write((char *)binbuf,store_addr,binlen); 159*2e192b24SSimon Glass if (rc != 0) { 160*2e192b24SSimon Glass flash_perror(rc); 161*2e192b24SSimon Glass return (~0); 162*2e192b24SSimon Glass } 163*2e192b24SSimon Glass } else 164*2e192b24SSimon Glass #endif 165*2e192b24SSimon Glass { 166*2e192b24SSimon Glass memcpy((char *)(store_addr), binbuf, binlen); 167*2e192b24SSimon Glass } 168*2e192b24SSimon Glass if ((store_addr) < start_addr) 169*2e192b24SSimon Glass start_addr = store_addr; 170*2e192b24SSimon Glass if ((store_addr + binlen - 1) > end_addr) 171*2e192b24SSimon Glass end_addr = store_addr + binlen - 1; 172*2e192b24SSimon Glass break; 173*2e192b24SSimon Glass case SREC_END2: 174*2e192b24SSimon Glass case SREC_END3: 175*2e192b24SSimon Glass case SREC_END4: 176*2e192b24SSimon Glass udelay(10000); 177*2e192b24SSimon Glass size = end_addr - start_addr + 1; 178*2e192b24SSimon Glass printf("\n" 179*2e192b24SSimon Glass "## First Load Addr = 0x%08lX\n" 180*2e192b24SSimon Glass "## Last Load Addr = 0x%08lX\n" 181*2e192b24SSimon Glass "## Total Size = 0x%08lX = %ld Bytes\n", 182*2e192b24SSimon Glass start_addr, end_addr, size, size 183*2e192b24SSimon Glass ); 184*2e192b24SSimon Glass flush_cache(start_addr, size); 185*2e192b24SSimon Glass setenv_hex("filesize", size); 186*2e192b24SSimon Glass return (addr); 187*2e192b24SSimon Glass case SREC_START: 188*2e192b24SSimon Glass break; 189*2e192b24SSimon Glass default: 190*2e192b24SSimon Glass break; 191*2e192b24SSimon Glass } 192*2e192b24SSimon Glass if (!do_echo) { /* print a '.' every 100 lines */ 193*2e192b24SSimon Glass if ((++line_count % 100) == 0) 194*2e192b24SSimon Glass putc('.'); 195*2e192b24SSimon Glass } 196*2e192b24SSimon Glass } 197*2e192b24SSimon Glass 198*2e192b24SSimon Glass return (~0); /* Download aborted */ 199*2e192b24SSimon Glass } 200*2e192b24SSimon Glass 201*2e192b24SSimon Glass static int read_record(char *buf, ulong len) 202*2e192b24SSimon Glass { 203*2e192b24SSimon Glass char *p; 204*2e192b24SSimon Glass char c; 205*2e192b24SSimon Glass 206*2e192b24SSimon Glass --len; /* always leave room for terminating '\0' byte */ 207*2e192b24SSimon Glass 208*2e192b24SSimon Glass for (p=buf; p < buf+len; ++p) { 209*2e192b24SSimon Glass c = getc(); /* read character */ 210*2e192b24SSimon Glass if (do_echo) 211*2e192b24SSimon Glass putc(c); /* ... and echo it */ 212*2e192b24SSimon Glass 213*2e192b24SSimon Glass switch (c) { 214*2e192b24SSimon Glass case '\r': 215*2e192b24SSimon Glass case '\n': 216*2e192b24SSimon Glass *p = '\0'; 217*2e192b24SSimon Glass return (p - buf); 218*2e192b24SSimon Glass case '\0': 219*2e192b24SSimon Glass case 0x03: /* ^C - Control C */ 220*2e192b24SSimon Glass return (-1); 221*2e192b24SSimon Glass default: 222*2e192b24SSimon Glass *p = c; 223*2e192b24SSimon Glass } 224*2e192b24SSimon Glass 225*2e192b24SSimon Glass /* Check for the console hangup (if any different from serial) */ 226*2e192b24SSimon Glass if (gd->jt->getc != getc) { 227*2e192b24SSimon Glass if (ctrlc()) { 228*2e192b24SSimon Glass return (-1); 229*2e192b24SSimon Glass } 230*2e192b24SSimon Glass } 231*2e192b24SSimon Glass } 232*2e192b24SSimon Glass 233*2e192b24SSimon Glass /* line too long - truncate */ 234*2e192b24SSimon Glass *p = '\0'; 235*2e192b24SSimon Glass return (p - buf); 236*2e192b24SSimon Glass } 237*2e192b24SSimon Glass 238*2e192b24SSimon Glass #if defined(CONFIG_CMD_SAVES) 239*2e192b24SSimon Glass 240*2e192b24SSimon Glass int do_save_serial (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 241*2e192b24SSimon Glass { 242*2e192b24SSimon Glass ulong offset = 0; 243*2e192b24SSimon Glass ulong size = 0; 244*2e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE 245*2e192b24SSimon Glass int save_baudrate, current_baudrate; 246*2e192b24SSimon Glass 247*2e192b24SSimon Glass save_baudrate = current_baudrate = gd->baudrate; 248*2e192b24SSimon Glass #endif 249*2e192b24SSimon Glass 250*2e192b24SSimon Glass if (argc >= 2) { 251*2e192b24SSimon Glass offset = simple_strtoul(argv[1], NULL, 16); 252*2e192b24SSimon Glass } 253*2e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE 254*2e192b24SSimon Glass if (argc >= 3) { 255*2e192b24SSimon Glass size = simple_strtoul(argv[2], NULL, 16); 256*2e192b24SSimon Glass } 257*2e192b24SSimon Glass if (argc == 4) { 258*2e192b24SSimon Glass save_baudrate = (int)simple_strtoul(argv[3], NULL, 10); 259*2e192b24SSimon Glass 260*2e192b24SSimon Glass /* default to current baudrate */ 261*2e192b24SSimon Glass if (save_baudrate == 0) 262*2e192b24SSimon Glass save_baudrate = current_baudrate; 263*2e192b24SSimon Glass } 264*2e192b24SSimon Glass if (save_baudrate != current_baudrate) { 265*2e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ENTER ...\n", 266*2e192b24SSimon Glass save_baudrate); 267*2e192b24SSimon Glass udelay(50000); 268*2e192b24SSimon Glass gd->baudrate = save_baudrate; 269*2e192b24SSimon Glass serial_setbrg(); 270*2e192b24SSimon Glass udelay(50000); 271*2e192b24SSimon Glass for (;;) { 272*2e192b24SSimon Glass if (getc() == '\r') 273*2e192b24SSimon Glass break; 274*2e192b24SSimon Glass } 275*2e192b24SSimon Glass } 276*2e192b24SSimon Glass #else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */ 277*2e192b24SSimon Glass if (argc == 3) { 278*2e192b24SSimon Glass size = simple_strtoul(argv[2], NULL, 16); 279*2e192b24SSimon Glass } 280*2e192b24SSimon Glass #endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */ 281*2e192b24SSimon Glass 282*2e192b24SSimon Glass printf("## Ready for S-Record upload, press ENTER to proceed ...\n"); 283*2e192b24SSimon Glass for (;;) { 284*2e192b24SSimon Glass if (getc() == '\r') 285*2e192b24SSimon Glass break; 286*2e192b24SSimon Glass } 287*2e192b24SSimon Glass if (save_serial(offset, size)) { 288*2e192b24SSimon Glass printf("## S-Record upload aborted\n"); 289*2e192b24SSimon Glass } else { 290*2e192b24SSimon Glass printf("## S-Record upload complete\n"); 291*2e192b24SSimon Glass } 292*2e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE 293*2e192b24SSimon Glass if (save_baudrate != current_baudrate) { 294*2e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ESC ...\n", 295*2e192b24SSimon Glass (int)current_baudrate); 296*2e192b24SSimon Glass udelay(50000); 297*2e192b24SSimon Glass gd->baudrate = current_baudrate; 298*2e192b24SSimon Glass serial_setbrg(); 299*2e192b24SSimon Glass udelay(50000); 300*2e192b24SSimon Glass for (;;) { 301*2e192b24SSimon Glass if (getc() == 0x1B) /* ESC */ 302*2e192b24SSimon Glass break; 303*2e192b24SSimon Glass } 304*2e192b24SSimon Glass } 305*2e192b24SSimon Glass #endif 306*2e192b24SSimon Glass return 0; 307*2e192b24SSimon Glass } 308*2e192b24SSimon Glass 309*2e192b24SSimon Glass #define SREC3_START "S0030000FC\n" 310*2e192b24SSimon Glass #define SREC3_FORMAT "S3%02X%08lX%s%02X\n" 311*2e192b24SSimon Glass #define SREC3_END "S70500000000FA\n" 312*2e192b24SSimon Glass #define SREC_BYTES_PER_RECORD 16 313*2e192b24SSimon Glass 314*2e192b24SSimon Glass static int save_serial(ulong address, ulong count) 315*2e192b24SSimon Glass { 316*2e192b24SSimon Glass int i, c, reclen, checksum, length; 317*2e192b24SSimon Glass char *hex = "0123456789ABCDEF"; 318*2e192b24SSimon Glass char record[2*SREC_BYTES_PER_RECORD+16]; /* buffer for one S-Record */ 319*2e192b24SSimon Glass char data[2*SREC_BYTES_PER_RECORD+1]; /* buffer for hex data */ 320*2e192b24SSimon Glass 321*2e192b24SSimon Glass reclen = 0; 322*2e192b24SSimon Glass checksum = 0; 323*2e192b24SSimon Glass 324*2e192b24SSimon Glass if(write_record(SREC3_START)) /* write the header */ 325*2e192b24SSimon Glass return (-1); 326*2e192b24SSimon Glass do { 327*2e192b24SSimon Glass if(count) { /* collect hex data in the buffer */ 328*2e192b24SSimon Glass c = *(volatile uchar*)(address + reclen); /* get one byte */ 329*2e192b24SSimon Glass checksum += c; /* accumulate checksum */ 330*2e192b24SSimon Glass data[2*reclen] = hex[(c>>4)&0x0f]; 331*2e192b24SSimon Glass data[2*reclen+1] = hex[c & 0x0f]; 332*2e192b24SSimon Glass data[2*reclen+2] = '\0'; 333*2e192b24SSimon Glass ++reclen; 334*2e192b24SSimon Glass --count; 335*2e192b24SSimon Glass } 336*2e192b24SSimon Glass if(reclen == SREC_BYTES_PER_RECORD || count == 0) { 337*2e192b24SSimon Glass /* enough data collected for one record: dump it */ 338*2e192b24SSimon Glass if(reclen) { /* build & write a data record: */ 339*2e192b24SSimon Glass /* address + data + checksum */ 340*2e192b24SSimon Glass length = 4 + reclen + 1; 341*2e192b24SSimon Glass 342*2e192b24SSimon Glass /* accumulate length bytes into checksum */ 343*2e192b24SSimon Glass for(i = 0; i < 2; i++) 344*2e192b24SSimon Glass checksum += (length >> (8*i)) & 0xff; 345*2e192b24SSimon Glass 346*2e192b24SSimon Glass /* accumulate address bytes into checksum: */ 347*2e192b24SSimon Glass for(i = 0; i < 4; i++) 348*2e192b24SSimon Glass checksum += (address >> (8*i)) & 0xff; 349*2e192b24SSimon Glass 350*2e192b24SSimon Glass /* make proper checksum byte: */ 351*2e192b24SSimon Glass checksum = ~checksum & 0xff; 352*2e192b24SSimon Glass 353*2e192b24SSimon Glass /* output one record: */ 354*2e192b24SSimon Glass sprintf(record, SREC3_FORMAT, length, address, data, checksum); 355*2e192b24SSimon Glass if(write_record(record)) 356*2e192b24SSimon Glass return (-1); 357*2e192b24SSimon Glass } 358*2e192b24SSimon Glass address += reclen; /* increment address */ 359*2e192b24SSimon Glass checksum = 0; 360*2e192b24SSimon Glass reclen = 0; 361*2e192b24SSimon Glass } 362*2e192b24SSimon Glass } 363*2e192b24SSimon Glass while(count); 364*2e192b24SSimon Glass if(write_record(SREC3_END)) /* write the final record */ 365*2e192b24SSimon Glass return (-1); 366*2e192b24SSimon Glass return(0); 367*2e192b24SSimon Glass } 368*2e192b24SSimon Glass 369*2e192b24SSimon Glass static int write_record(char *buf) 370*2e192b24SSimon Glass { 371*2e192b24SSimon Glass char c; 372*2e192b24SSimon Glass 373*2e192b24SSimon Glass while((c = *buf++)) 374*2e192b24SSimon Glass putc(c); 375*2e192b24SSimon Glass 376*2e192b24SSimon Glass /* Check for the console hangup (if any different from serial) */ 377*2e192b24SSimon Glass 378*2e192b24SSimon Glass if (ctrlc()) { 379*2e192b24SSimon Glass return (-1); 380*2e192b24SSimon Glass } 381*2e192b24SSimon Glass return (0); 382*2e192b24SSimon Glass } 383*2e192b24SSimon Glass # endif 384*2e192b24SSimon Glass 385*2e192b24SSimon Glass #endif 386*2e192b24SSimon Glass 387*2e192b24SSimon Glass 388*2e192b24SSimon Glass #if defined(CONFIG_CMD_LOADB) 389*2e192b24SSimon Glass /* 390*2e192b24SSimon Glass * loadb command (load binary) included 391*2e192b24SSimon Glass */ 392*2e192b24SSimon Glass #define XON_CHAR 17 393*2e192b24SSimon Glass #define XOFF_CHAR 19 394*2e192b24SSimon Glass #define START_CHAR 0x01 395*2e192b24SSimon Glass #define ETX_CHAR 0x03 396*2e192b24SSimon Glass #define END_CHAR 0x0D 397*2e192b24SSimon Glass #define SPACE 0x20 398*2e192b24SSimon Glass #define K_ESCAPE 0x23 399*2e192b24SSimon Glass #define SEND_TYPE 'S' 400*2e192b24SSimon Glass #define DATA_TYPE 'D' 401*2e192b24SSimon Glass #define ACK_TYPE 'Y' 402*2e192b24SSimon Glass #define NACK_TYPE 'N' 403*2e192b24SSimon Glass #define BREAK_TYPE 'B' 404*2e192b24SSimon Glass #define tochar(x) ((char) (((x) + SPACE) & 0xff)) 405*2e192b24SSimon Glass #define untochar(x) ((int) (((x) - SPACE) & 0xff)) 406*2e192b24SSimon Glass 407*2e192b24SSimon Glass static void set_kerm_bin_mode(unsigned long *); 408*2e192b24SSimon Glass static int k_recv(void); 409*2e192b24SSimon Glass static ulong load_serial_bin(ulong offset); 410*2e192b24SSimon Glass 411*2e192b24SSimon Glass 412*2e192b24SSimon Glass static char his_eol; /* character he needs at end of packet */ 413*2e192b24SSimon Glass static int his_pad_count; /* number of pad chars he needs */ 414*2e192b24SSimon Glass static char his_pad_char; /* pad chars he needs */ 415*2e192b24SSimon Glass static char his_quote; /* quote chars he'll use */ 416*2e192b24SSimon Glass 417*2e192b24SSimon Glass static int do_load_serial_bin(cmd_tbl_t *cmdtp, int flag, int argc, 418*2e192b24SSimon Glass char * const argv[]) 419*2e192b24SSimon Glass { 420*2e192b24SSimon Glass ulong offset = 0; 421*2e192b24SSimon Glass ulong addr; 422*2e192b24SSimon Glass int load_baudrate, current_baudrate; 423*2e192b24SSimon Glass int rcode = 0; 424*2e192b24SSimon Glass char *s; 425*2e192b24SSimon Glass 426*2e192b24SSimon Glass /* pre-set offset from CONFIG_SYS_LOAD_ADDR */ 427*2e192b24SSimon Glass offset = CONFIG_SYS_LOAD_ADDR; 428*2e192b24SSimon Glass 429*2e192b24SSimon Glass /* pre-set offset from $loadaddr */ 430*2e192b24SSimon Glass if ((s = getenv("loadaddr")) != NULL) { 431*2e192b24SSimon Glass offset = simple_strtoul(s, NULL, 16); 432*2e192b24SSimon Glass } 433*2e192b24SSimon Glass 434*2e192b24SSimon Glass load_baudrate = current_baudrate = gd->baudrate; 435*2e192b24SSimon Glass 436*2e192b24SSimon Glass if (argc >= 2) { 437*2e192b24SSimon Glass offset = simple_strtoul(argv[1], NULL, 16); 438*2e192b24SSimon Glass } 439*2e192b24SSimon Glass if (argc == 3) { 440*2e192b24SSimon Glass load_baudrate = (int)simple_strtoul(argv[2], NULL, 10); 441*2e192b24SSimon Glass 442*2e192b24SSimon Glass /* default to current baudrate */ 443*2e192b24SSimon Glass if (load_baudrate == 0) 444*2e192b24SSimon Glass load_baudrate = current_baudrate; 445*2e192b24SSimon Glass } 446*2e192b24SSimon Glass 447*2e192b24SSimon Glass if (load_baudrate != current_baudrate) { 448*2e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ENTER ...\n", 449*2e192b24SSimon Glass load_baudrate); 450*2e192b24SSimon Glass udelay(50000); 451*2e192b24SSimon Glass gd->baudrate = load_baudrate; 452*2e192b24SSimon Glass serial_setbrg(); 453*2e192b24SSimon Glass udelay(50000); 454*2e192b24SSimon Glass for (;;) { 455*2e192b24SSimon Glass if (getc() == '\r') 456*2e192b24SSimon Glass break; 457*2e192b24SSimon Glass } 458*2e192b24SSimon Glass } 459*2e192b24SSimon Glass 460*2e192b24SSimon Glass if (strcmp(argv[0],"loady")==0) { 461*2e192b24SSimon Glass printf("## Ready for binary (ymodem) download " 462*2e192b24SSimon Glass "to 0x%08lX at %d bps...\n", 463*2e192b24SSimon Glass offset, 464*2e192b24SSimon Glass load_baudrate); 465*2e192b24SSimon Glass 466*2e192b24SSimon Glass addr = load_serial_ymodem(offset, xyzModem_ymodem); 467*2e192b24SSimon Glass 468*2e192b24SSimon Glass } else if (strcmp(argv[0],"loadx")==0) { 469*2e192b24SSimon Glass printf("## Ready for binary (xmodem) download " 470*2e192b24SSimon Glass "to 0x%08lX at %d bps...\n", 471*2e192b24SSimon Glass offset, 472*2e192b24SSimon Glass load_baudrate); 473*2e192b24SSimon Glass 474*2e192b24SSimon Glass addr = load_serial_ymodem(offset, xyzModem_xmodem); 475*2e192b24SSimon Glass 476*2e192b24SSimon Glass } else { 477*2e192b24SSimon Glass 478*2e192b24SSimon Glass printf("## Ready for binary (kermit) download " 479*2e192b24SSimon Glass "to 0x%08lX at %d bps...\n", 480*2e192b24SSimon Glass offset, 481*2e192b24SSimon Glass load_baudrate); 482*2e192b24SSimon Glass addr = load_serial_bin(offset); 483*2e192b24SSimon Glass 484*2e192b24SSimon Glass if (addr == ~0) { 485*2e192b24SSimon Glass load_addr = 0; 486*2e192b24SSimon Glass printf("## Binary (kermit) download aborted\n"); 487*2e192b24SSimon Glass rcode = 1; 488*2e192b24SSimon Glass } else { 489*2e192b24SSimon Glass printf("## Start Addr = 0x%08lX\n", addr); 490*2e192b24SSimon Glass load_addr = addr; 491*2e192b24SSimon Glass } 492*2e192b24SSimon Glass } 493*2e192b24SSimon Glass if (load_baudrate != current_baudrate) { 494*2e192b24SSimon Glass printf("## Switch baudrate to %d bps and press ESC ...\n", 495*2e192b24SSimon Glass current_baudrate); 496*2e192b24SSimon Glass udelay(50000); 497*2e192b24SSimon Glass gd->baudrate = current_baudrate; 498*2e192b24SSimon Glass serial_setbrg(); 499*2e192b24SSimon Glass udelay(50000); 500*2e192b24SSimon Glass for (;;) { 501*2e192b24SSimon Glass if (getc() == 0x1B) /* ESC */ 502*2e192b24SSimon Glass break; 503*2e192b24SSimon Glass } 504*2e192b24SSimon Glass } 505*2e192b24SSimon Glass 506*2e192b24SSimon Glass return rcode; 507*2e192b24SSimon Glass } 508*2e192b24SSimon Glass 509*2e192b24SSimon Glass 510*2e192b24SSimon Glass static ulong load_serial_bin(ulong offset) 511*2e192b24SSimon Glass { 512*2e192b24SSimon Glass int size, i; 513*2e192b24SSimon Glass 514*2e192b24SSimon Glass set_kerm_bin_mode((ulong *) offset); 515*2e192b24SSimon Glass size = k_recv(); 516*2e192b24SSimon Glass 517*2e192b24SSimon Glass /* 518*2e192b24SSimon Glass * Gather any trailing characters (for instance, the ^D which 519*2e192b24SSimon Glass * is sent by 'cu' after sending a file), and give the 520*2e192b24SSimon Glass * box some time (100 * 1 ms) 521*2e192b24SSimon Glass */ 522*2e192b24SSimon Glass for (i=0; i<100; ++i) { 523*2e192b24SSimon Glass if (tstc()) { 524*2e192b24SSimon Glass (void) getc(); 525*2e192b24SSimon Glass } 526*2e192b24SSimon Glass udelay(1000); 527*2e192b24SSimon Glass } 528*2e192b24SSimon Glass 529*2e192b24SSimon Glass flush_cache(offset, size); 530*2e192b24SSimon Glass 531*2e192b24SSimon Glass printf("## Total Size = 0x%08x = %d Bytes\n", size, size); 532*2e192b24SSimon Glass setenv_hex("filesize", size); 533*2e192b24SSimon Glass 534*2e192b24SSimon Glass return offset; 535*2e192b24SSimon Glass } 536*2e192b24SSimon Glass 537*2e192b24SSimon Glass static void send_pad(void) 538*2e192b24SSimon Glass { 539*2e192b24SSimon Glass int count = his_pad_count; 540*2e192b24SSimon Glass 541*2e192b24SSimon Glass while (count-- > 0) 542*2e192b24SSimon Glass putc(his_pad_char); 543*2e192b24SSimon Glass } 544*2e192b24SSimon Glass 545*2e192b24SSimon Glass /* converts escaped kermit char to binary char */ 546*2e192b24SSimon Glass static char ktrans(char in) 547*2e192b24SSimon Glass { 548*2e192b24SSimon Glass if ((in & 0x60) == 0x40) { 549*2e192b24SSimon Glass return (char) (in & ~0x40); 550*2e192b24SSimon Glass } else if ((in & 0x7f) == 0x3f) { 551*2e192b24SSimon Glass return (char) (in | 0x40); 552*2e192b24SSimon Glass } else 553*2e192b24SSimon Glass return in; 554*2e192b24SSimon Glass } 555*2e192b24SSimon Glass 556*2e192b24SSimon Glass static int chk1(char *buffer) 557*2e192b24SSimon Glass { 558*2e192b24SSimon Glass int total = 0; 559*2e192b24SSimon Glass 560*2e192b24SSimon Glass while (*buffer) { 561*2e192b24SSimon Glass total += *buffer++; 562*2e192b24SSimon Glass } 563*2e192b24SSimon Glass return (int) ((total + ((total >> 6) & 0x03)) & 0x3f); 564*2e192b24SSimon Glass } 565*2e192b24SSimon Glass 566*2e192b24SSimon Glass static void s1_sendpacket(char *packet) 567*2e192b24SSimon Glass { 568*2e192b24SSimon Glass send_pad(); 569*2e192b24SSimon Glass while (*packet) { 570*2e192b24SSimon Glass putc(*packet++); 571*2e192b24SSimon Glass } 572*2e192b24SSimon Glass } 573*2e192b24SSimon Glass 574*2e192b24SSimon Glass static char a_b[24]; 575*2e192b24SSimon Glass static void send_ack(int n) 576*2e192b24SSimon Glass { 577*2e192b24SSimon Glass a_b[0] = START_CHAR; 578*2e192b24SSimon Glass a_b[1] = tochar(3); 579*2e192b24SSimon Glass a_b[2] = tochar(n); 580*2e192b24SSimon Glass a_b[3] = ACK_TYPE; 581*2e192b24SSimon Glass a_b[4] = '\0'; 582*2e192b24SSimon Glass a_b[4] = tochar(chk1(&a_b[1])); 583*2e192b24SSimon Glass a_b[5] = his_eol; 584*2e192b24SSimon Glass a_b[6] = '\0'; 585*2e192b24SSimon Glass s1_sendpacket(a_b); 586*2e192b24SSimon Glass } 587*2e192b24SSimon Glass 588*2e192b24SSimon Glass static void send_nack(int n) 589*2e192b24SSimon Glass { 590*2e192b24SSimon Glass a_b[0] = START_CHAR; 591*2e192b24SSimon Glass a_b[1] = tochar(3); 592*2e192b24SSimon Glass a_b[2] = tochar(n); 593*2e192b24SSimon Glass a_b[3] = NACK_TYPE; 594*2e192b24SSimon Glass a_b[4] = '\0'; 595*2e192b24SSimon Glass a_b[4] = tochar(chk1(&a_b[1])); 596*2e192b24SSimon Glass a_b[5] = his_eol; 597*2e192b24SSimon Glass a_b[6] = '\0'; 598*2e192b24SSimon Glass s1_sendpacket(a_b); 599*2e192b24SSimon Glass } 600*2e192b24SSimon Glass 601*2e192b24SSimon Glass 602*2e192b24SSimon Glass static void (*os_data_init)(void); 603*2e192b24SSimon Glass static void (*os_data_char)(char new_char); 604*2e192b24SSimon Glass static int os_data_state, os_data_state_saved; 605*2e192b24SSimon Glass static char *os_data_addr, *os_data_addr_saved; 606*2e192b24SSimon Glass static char *bin_start_address; 607*2e192b24SSimon Glass 608*2e192b24SSimon Glass static void bin_data_init(void) 609*2e192b24SSimon Glass { 610*2e192b24SSimon Glass os_data_state = 0; 611*2e192b24SSimon Glass os_data_addr = bin_start_address; 612*2e192b24SSimon Glass } 613*2e192b24SSimon Glass 614*2e192b24SSimon Glass static void os_data_save(void) 615*2e192b24SSimon Glass { 616*2e192b24SSimon Glass os_data_state_saved = os_data_state; 617*2e192b24SSimon Glass os_data_addr_saved = os_data_addr; 618*2e192b24SSimon Glass } 619*2e192b24SSimon Glass 620*2e192b24SSimon Glass static void os_data_restore(void) 621*2e192b24SSimon Glass { 622*2e192b24SSimon Glass os_data_state = os_data_state_saved; 623*2e192b24SSimon Glass os_data_addr = os_data_addr_saved; 624*2e192b24SSimon Glass } 625*2e192b24SSimon Glass 626*2e192b24SSimon Glass static void bin_data_char(char new_char) 627*2e192b24SSimon Glass { 628*2e192b24SSimon Glass switch (os_data_state) { 629*2e192b24SSimon Glass case 0: /* data */ 630*2e192b24SSimon Glass *os_data_addr++ = new_char; 631*2e192b24SSimon Glass break; 632*2e192b24SSimon Glass } 633*2e192b24SSimon Glass } 634*2e192b24SSimon Glass 635*2e192b24SSimon Glass static void set_kerm_bin_mode(unsigned long *addr) 636*2e192b24SSimon Glass { 637*2e192b24SSimon Glass bin_start_address = (char *) addr; 638*2e192b24SSimon Glass os_data_init = bin_data_init; 639*2e192b24SSimon Glass os_data_char = bin_data_char; 640*2e192b24SSimon Glass } 641*2e192b24SSimon Glass 642*2e192b24SSimon Glass 643*2e192b24SSimon Glass /* k_data_* simply handles the kermit escape translations */ 644*2e192b24SSimon Glass static int k_data_escape, k_data_escape_saved; 645*2e192b24SSimon Glass static void k_data_init(void) 646*2e192b24SSimon Glass { 647*2e192b24SSimon Glass k_data_escape = 0; 648*2e192b24SSimon Glass os_data_init(); 649*2e192b24SSimon Glass } 650*2e192b24SSimon Glass 651*2e192b24SSimon Glass static void k_data_save(void) 652*2e192b24SSimon Glass { 653*2e192b24SSimon Glass k_data_escape_saved = k_data_escape; 654*2e192b24SSimon Glass os_data_save(); 655*2e192b24SSimon Glass } 656*2e192b24SSimon Glass 657*2e192b24SSimon Glass static void k_data_restore(void) 658*2e192b24SSimon Glass { 659*2e192b24SSimon Glass k_data_escape = k_data_escape_saved; 660*2e192b24SSimon Glass os_data_restore(); 661*2e192b24SSimon Glass } 662*2e192b24SSimon Glass 663*2e192b24SSimon Glass static void k_data_char(char new_char) 664*2e192b24SSimon Glass { 665*2e192b24SSimon Glass if (k_data_escape) { 666*2e192b24SSimon Glass /* last char was escape - translate this character */ 667*2e192b24SSimon Glass os_data_char(ktrans(new_char)); 668*2e192b24SSimon Glass k_data_escape = 0; 669*2e192b24SSimon Glass } else { 670*2e192b24SSimon Glass if (new_char == his_quote) { 671*2e192b24SSimon Glass /* this char is escape - remember */ 672*2e192b24SSimon Glass k_data_escape = 1; 673*2e192b24SSimon Glass } else { 674*2e192b24SSimon Glass /* otherwise send this char as-is */ 675*2e192b24SSimon Glass os_data_char(new_char); 676*2e192b24SSimon Glass } 677*2e192b24SSimon Glass } 678*2e192b24SSimon Glass } 679*2e192b24SSimon Glass 680*2e192b24SSimon Glass #define SEND_DATA_SIZE 20 681*2e192b24SSimon Glass static char send_parms[SEND_DATA_SIZE]; 682*2e192b24SSimon Glass static char *send_ptr; 683*2e192b24SSimon Glass 684*2e192b24SSimon Glass /* handle_send_packet interprits the protocol info and builds and 685*2e192b24SSimon Glass sends an appropriate ack for what we can do */ 686*2e192b24SSimon Glass static void handle_send_packet(int n) 687*2e192b24SSimon Glass { 688*2e192b24SSimon Glass int length = 3; 689*2e192b24SSimon Glass int bytes; 690*2e192b24SSimon Glass 691*2e192b24SSimon Glass /* initialize some protocol parameters */ 692*2e192b24SSimon Glass his_eol = END_CHAR; /* default end of line character */ 693*2e192b24SSimon Glass his_pad_count = 0; 694*2e192b24SSimon Glass his_pad_char = '\0'; 695*2e192b24SSimon Glass his_quote = K_ESCAPE; 696*2e192b24SSimon Glass 697*2e192b24SSimon Glass /* ignore last character if it filled the buffer */ 698*2e192b24SSimon Glass if (send_ptr == &send_parms[SEND_DATA_SIZE - 1]) 699*2e192b24SSimon Glass --send_ptr; 700*2e192b24SSimon Glass bytes = send_ptr - send_parms; /* how many bytes we'll process */ 701*2e192b24SSimon Glass do { 702*2e192b24SSimon Glass if (bytes-- <= 0) 703*2e192b24SSimon Glass break; 704*2e192b24SSimon Glass /* handle MAXL - max length */ 705*2e192b24SSimon Glass /* ignore what he says - most I'll take (here) is 94 */ 706*2e192b24SSimon Glass a_b[++length] = tochar(94); 707*2e192b24SSimon Glass if (bytes-- <= 0) 708*2e192b24SSimon Glass break; 709*2e192b24SSimon Glass /* handle TIME - time you should wait for my packets */ 710*2e192b24SSimon Glass /* ignore what he says - don't wait for my ack longer than 1 second */ 711*2e192b24SSimon Glass a_b[++length] = tochar(1); 712*2e192b24SSimon Glass if (bytes-- <= 0) 713*2e192b24SSimon Glass break; 714*2e192b24SSimon Glass /* handle NPAD - number of pad chars I need */ 715*2e192b24SSimon Glass /* remember what he says - I need none */ 716*2e192b24SSimon Glass his_pad_count = untochar(send_parms[2]); 717*2e192b24SSimon Glass a_b[++length] = tochar(0); 718*2e192b24SSimon Glass if (bytes-- <= 0) 719*2e192b24SSimon Glass break; 720*2e192b24SSimon Glass /* handle PADC - pad chars I need */ 721*2e192b24SSimon Glass /* remember what he says - I need none */ 722*2e192b24SSimon Glass his_pad_char = ktrans(send_parms[3]); 723*2e192b24SSimon Glass a_b[++length] = 0x40; /* He should ignore this */ 724*2e192b24SSimon Glass if (bytes-- <= 0) 725*2e192b24SSimon Glass break; 726*2e192b24SSimon Glass /* handle EOL - end of line he needs */ 727*2e192b24SSimon Glass /* remember what he says - I need CR */ 728*2e192b24SSimon Glass his_eol = untochar(send_parms[4]); 729*2e192b24SSimon Glass a_b[++length] = tochar(END_CHAR); 730*2e192b24SSimon Glass if (bytes-- <= 0) 731*2e192b24SSimon Glass break; 732*2e192b24SSimon Glass /* handle QCTL - quote control char he'll use */ 733*2e192b24SSimon Glass /* remember what he says - I'll use '#' */ 734*2e192b24SSimon Glass his_quote = send_parms[5]; 735*2e192b24SSimon Glass a_b[++length] = '#'; 736*2e192b24SSimon Glass if (bytes-- <= 0) 737*2e192b24SSimon Glass break; 738*2e192b24SSimon Glass /* handle QBIN - 8-th bit prefixing */ 739*2e192b24SSimon Glass /* ignore what he says - I refuse */ 740*2e192b24SSimon Glass a_b[++length] = 'N'; 741*2e192b24SSimon Glass if (bytes-- <= 0) 742*2e192b24SSimon Glass break; 743*2e192b24SSimon Glass /* handle CHKT - the clock check type */ 744*2e192b24SSimon Glass /* ignore what he says - I do type 1 (for now) */ 745*2e192b24SSimon Glass a_b[++length] = '1'; 746*2e192b24SSimon Glass if (bytes-- <= 0) 747*2e192b24SSimon Glass break; 748*2e192b24SSimon Glass /* handle REPT - the repeat prefix */ 749*2e192b24SSimon Glass /* ignore what he says - I refuse (for now) */ 750*2e192b24SSimon Glass a_b[++length] = 'N'; 751*2e192b24SSimon Glass if (bytes-- <= 0) 752*2e192b24SSimon Glass break; 753*2e192b24SSimon Glass /* handle CAPAS - the capabilities mask */ 754*2e192b24SSimon Glass /* ignore what he says - I only do long packets - I don't do windows */ 755*2e192b24SSimon Glass a_b[++length] = tochar(2); /* only long packets */ 756*2e192b24SSimon Glass a_b[++length] = tochar(0); /* no windows */ 757*2e192b24SSimon Glass a_b[++length] = tochar(94); /* large packet msb */ 758*2e192b24SSimon Glass a_b[++length] = tochar(94); /* large packet lsb */ 759*2e192b24SSimon Glass } while (0); 760*2e192b24SSimon Glass 761*2e192b24SSimon Glass a_b[0] = START_CHAR; 762*2e192b24SSimon Glass a_b[1] = tochar(length); 763*2e192b24SSimon Glass a_b[2] = tochar(n); 764*2e192b24SSimon Glass a_b[3] = ACK_TYPE; 765*2e192b24SSimon Glass a_b[++length] = '\0'; 766*2e192b24SSimon Glass a_b[length] = tochar(chk1(&a_b[1])); 767*2e192b24SSimon Glass a_b[++length] = his_eol; 768*2e192b24SSimon Glass a_b[++length] = '\0'; 769*2e192b24SSimon Glass s1_sendpacket(a_b); 770*2e192b24SSimon Glass } 771*2e192b24SSimon Glass 772*2e192b24SSimon Glass /* k_recv receives a OS Open image file over kermit line */ 773*2e192b24SSimon Glass static int k_recv(void) 774*2e192b24SSimon Glass { 775*2e192b24SSimon Glass char new_char; 776*2e192b24SSimon Glass char k_state, k_state_saved; 777*2e192b24SSimon Glass int sum; 778*2e192b24SSimon Glass int done; 779*2e192b24SSimon Glass int length; 780*2e192b24SSimon Glass int n, last_n; 781*2e192b24SSimon Glass int len_lo, len_hi; 782*2e192b24SSimon Glass 783*2e192b24SSimon Glass /* initialize some protocol parameters */ 784*2e192b24SSimon Glass his_eol = END_CHAR; /* default end of line character */ 785*2e192b24SSimon Glass his_pad_count = 0; 786*2e192b24SSimon Glass his_pad_char = '\0'; 787*2e192b24SSimon Glass his_quote = K_ESCAPE; 788*2e192b24SSimon Glass 789*2e192b24SSimon Glass /* initialize the k_recv and k_data state machine */ 790*2e192b24SSimon Glass done = 0; 791*2e192b24SSimon Glass k_state = 0; 792*2e192b24SSimon Glass k_data_init(); 793*2e192b24SSimon Glass k_state_saved = k_state; 794*2e192b24SSimon Glass k_data_save(); 795*2e192b24SSimon Glass n = 0; /* just to get rid of a warning */ 796*2e192b24SSimon Glass last_n = -1; 797*2e192b24SSimon Glass 798*2e192b24SSimon Glass /* expect this "type" sequence (but don't check): 799*2e192b24SSimon Glass S: send initiate 800*2e192b24SSimon Glass F: file header 801*2e192b24SSimon Glass D: data (multiple) 802*2e192b24SSimon Glass Z: end of file 803*2e192b24SSimon Glass B: break transmission 804*2e192b24SSimon Glass */ 805*2e192b24SSimon Glass 806*2e192b24SSimon Glass /* enter main loop */ 807*2e192b24SSimon Glass while (!done) { 808*2e192b24SSimon Glass /* set the send packet pointer to begining of send packet parms */ 809*2e192b24SSimon Glass send_ptr = send_parms; 810*2e192b24SSimon Glass 811*2e192b24SSimon Glass /* With each packet, start summing the bytes starting with the length. 812*2e192b24SSimon Glass Save the current sequence number. 813*2e192b24SSimon Glass Note the type of the packet. 814*2e192b24SSimon Glass If a character less than SPACE (0x20) is received - error. 815*2e192b24SSimon Glass */ 816*2e192b24SSimon Glass 817*2e192b24SSimon Glass #if 0 818*2e192b24SSimon Glass /* OLD CODE, Prior to checking sequence numbers */ 819*2e192b24SSimon Glass /* first have all state machines save current states */ 820*2e192b24SSimon Glass k_state_saved = k_state; 821*2e192b24SSimon Glass k_data_save (); 822*2e192b24SSimon Glass #endif 823*2e192b24SSimon Glass 824*2e192b24SSimon Glass /* get a packet */ 825*2e192b24SSimon Glass /* wait for the starting character or ^C */ 826*2e192b24SSimon Glass for (;;) { 827*2e192b24SSimon Glass switch (getc ()) { 828*2e192b24SSimon Glass case START_CHAR: /* start packet */ 829*2e192b24SSimon Glass goto START; 830*2e192b24SSimon Glass case ETX_CHAR: /* ^C waiting for packet */ 831*2e192b24SSimon Glass return (0); 832*2e192b24SSimon Glass default: 833*2e192b24SSimon Glass ; 834*2e192b24SSimon Glass } 835*2e192b24SSimon Glass } 836*2e192b24SSimon Glass START: 837*2e192b24SSimon Glass /* get length of packet */ 838*2e192b24SSimon Glass sum = 0; 839*2e192b24SSimon Glass new_char = getc(); 840*2e192b24SSimon Glass if ((new_char & 0xE0) == 0) 841*2e192b24SSimon Glass goto packet_error; 842*2e192b24SSimon Glass sum += new_char & 0xff; 843*2e192b24SSimon Glass length = untochar(new_char); 844*2e192b24SSimon Glass /* get sequence number */ 845*2e192b24SSimon Glass new_char = getc(); 846*2e192b24SSimon Glass if ((new_char & 0xE0) == 0) 847*2e192b24SSimon Glass goto packet_error; 848*2e192b24SSimon Glass sum += new_char & 0xff; 849*2e192b24SSimon Glass n = untochar(new_char); 850*2e192b24SSimon Glass --length; 851*2e192b24SSimon Glass 852*2e192b24SSimon Glass /* NEW CODE - check sequence numbers for retried packets */ 853*2e192b24SSimon Glass /* Note - this new code assumes that the sequence number is correctly 854*2e192b24SSimon Glass * received. Handling an invalid sequence number adds another layer 855*2e192b24SSimon Glass * of complexity that may not be needed - yet! At this time, I'm hoping 856*2e192b24SSimon Glass * that I don't need to buffer the incoming data packets and can write 857*2e192b24SSimon Glass * the data into memory in real time. 858*2e192b24SSimon Glass */ 859*2e192b24SSimon Glass if (n == last_n) { 860*2e192b24SSimon Glass /* same sequence number, restore the previous state */ 861*2e192b24SSimon Glass k_state = k_state_saved; 862*2e192b24SSimon Glass k_data_restore(); 863*2e192b24SSimon Glass } else { 864*2e192b24SSimon Glass /* new sequence number, checkpoint the download */ 865*2e192b24SSimon Glass last_n = n; 866*2e192b24SSimon Glass k_state_saved = k_state; 867*2e192b24SSimon Glass k_data_save(); 868*2e192b24SSimon Glass } 869*2e192b24SSimon Glass /* END NEW CODE */ 870*2e192b24SSimon Glass 871*2e192b24SSimon Glass /* get packet type */ 872*2e192b24SSimon Glass new_char = getc(); 873*2e192b24SSimon Glass if ((new_char & 0xE0) == 0) 874*2e192b24SSimon Glass goto packet_error; 875*2e192b24SSimon Glass sum += new_char & 0xff; 876*2e192b24SSimon Glass k_state = new_char; 877*2e192b24SSimon Glass --length; 878*2e192b24SSimon Glass /* check for extended length */ 879*2e192b24SSimon Glass if (length == -2) { 880*2e192b24SSimon Glass /* (length byte was 0, decremented twice) */ 881*2e192b24SSimon Glass /* get the two length bytes */ 882*2e192b24SSimon Glass new_char = getc(); 883*2e192b24SSimon Glass if ((new_char & 0xE0) == 0) 884*2e192b24SSimon Glass goto packet_error; 885*2e192b24SSimon Glass sum += new_char & 0xff; 886*2e192b24SSimon Glass len_hi = untochar(new_char); 887*2e192b24SSimon Glass new_char = getc(); 888*2e192b24SSimon Glass if ((new_char & 0xE0) == 0) 889*2e192b24SSimon Glass goto packet_error; 890*2e192b24SSimon Glass sum += new_char & 0xff; 891*2e192b24SSimon Glass len_lo = untochar(new_char); 892*2e192b24SSimon Glass length = len_hi * 95 + len_lo; 893*2e192b24SSimon Glass /* check header checksum */ 894*2e192b24SSimon Glass new_char = getc(); 895*2e192b24SSimon Glass if ((new_char & 0xE0) == 0) 896*2e192b24SSimon Glass goto packet_error; 897*2e192b24SSimon Glass if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f)) 898*2e192b24SSimon Glass goto packet_error; 899*2e192b24SSimon Glass sum += new_char & 0xff; 900*2e192b24SSimon Glass /* --length; */ /* new length includes only data and block check to come */ 901*2e192b24SSimon Glass } 902*2e192b24SSimon Glass /* bring in rest of packet */ 903*2e192b24SSimon Glass while (length > 1) { 904*2e192b24SSimon Glass new_char = getc(); 905*2e192b24SSimon Glass if ((new_char & 0xE0) == 0) 906*2e192b24SSimon Glass goto packet_error; 907*2e192b24SSimon Glass sum += new_char & 0xff; 908*2e192b24SSimon Glass --length; 909*2e192b24SSimon Glass if (k_state == DATA_TYPE) { 910*2e192b24SSimon Glass /* pass on the data if this is a data packet */ 911*2e192b24SSimon Glass k_data_char (new_char); 912*2e192b24SSimon Glass } else if (k_state == SEND_TYPE) { 913*2e192b24SSimon Glass /* save send pack in buffer as is */ 914*2e192b24SSimon Glass *send_ptr++ = new_char; 915*2e192b24SSimon Glass /* if too much data, back off the pointer */ 916*2e192b24SSimon Glass if (send_ptr >= &send_parms[SEND_DATA_SIZE]) 917*2e192b24SSimon Glass --send_ptr; 918*2e192b24SSimon Glass } 919*2e192b24SSimon Glass } 920*2e192b24SSimon Glass /* get and validate checksum character */ 921*2e192b24SSimon Glass new_char = getc(); 922*2e192b24SSimon Glass if ((new_char & 0xE0) == 0) 923*2e192b24SSimon Glass goto packet_error; 924*2e192b24SSimon Glass if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f)) 925*2e192b24SSimon Glass goto packet_error; 926*2e192b24SSimon Glass /* get END_CHAR */ 927*2e192b24SSimon Glass new_char = getc(); 928*2e192b24SSimon Glass if (new_char != END_CHAR) { 929*2e192b24SSimon Glass packet_error: 930*2e192b24SSimon Glass /* restore state machines */ 931*2e192b24SSimon Glass k_state = k_state_saved; 932*2e192b24SSimon Glass k_data_restore(); 933*2e192b24SSimon Glass /* send a negative acknowledge packet in */ 934*2e192b24SSimon Glass send_nack(n); 935*2e192b24SSimon Glass } else if (k_state == SEND_TYPE) { 936*2e192b24SSimon Glass /* crack the protocol parms, build an appropriate ack packet */ 937*2e192b24SSimon Glass handle_send_packet(n); 938*2e192b24SSimon Glass } else { 939*2e192b24SSimon Glass /* send simple acknowledge packet in */ 940*2e192b24SSimon Glass send_ack(n); 941*2e192b24SSimon Glass /* quit if end of transmission */ 942*2e192b24SSimon Glass if (k_state == BREAK_TYPE) 943*2e192b24SSimon Glass done = 1; 944*2e192b24SSimon Glass } 945*2e192b24SSimon Glass } 946*2e192b24SSimon Glass return ((ulong) os_data_addr - (ulong) bin_start_address); 947*2e192b24SSimon Glass } 948*2e192b24SSimon Glass 949*2e192b24SSimon Glass static int getcxmodem(void) { 950*2e192b24SSimon Glass if (tstc()) 951*2e192b24SSimon Glass return (getc()); 952*2e192b24SSimon Glass return -1; 953*2e192b24SSimon Glass } 954*2e192b24SSimon Glass static ulong load_serial_ymodem(ulong offset, int mode) 955*2e192b24SSimon Glass { 956*2e192b24SSimon Glass int size; 957*2e192b24SSimon Glass int err; 958*2e192b24SSimon Glass int res; 959*2e192b24SSimon Glass connection_info_t info; 960*2e192b24SSimon Glass char ymodemBuf[1024]; 961*2e192b24SSimon Glass ulong store_addr = ~0; 962*2e192b24SSimon Glass ulong addr = 0; 963*2e192b24SSimon Glass 964*2e192b24SSimon Glass size = 0; 965*2e192b24SSimon Glass info.mode = mode; 966*2e192b24SSimon Glass res = xyzModem_stream_open(&info, &err); 967*2e192b24SSimon Glass if (!res) { 968*2e192b24SSimon Glass 969*2e192b24SSimon Glass while ((res = 970*2e192b24SSimon Glass xyzModem_stream_read(ymodemBuf, 1024, &err)) > 0) { 971*2e192b24SSimon Glass store_addr = addr + offset; 972*2e192b24SSimon Glass size += res; 973*2e192b24SSimon Glass addr += res; 974*2e192b24SSimon Glass #ifndef CONFIG_SYS_NO_FLASH 975*2e192b24SSimon Glass if (addr2info(store_addr)) { 976*2e192b24SSimon Glass int rc; 977*2e192b24SSimon Glass 978*2e192b24SSimon Glass rc = flash_write((char *) ymodemBuf, 979*2e192b24SSimon Glass store_addr, res); 980*2e192b24SSimon Glass if (rc != 0) { 981*2e192b24SSimon Glass flash_perror (rc); 982*2e192b24SSimon Glass return (~0); 983*2e192b24SSimon Glass } 984*2e192b24SSimon Glass } else 985*2e192b24SSimon Glass #endif 986*2e192b24SSimon Glass { 987*2e192b24SSimon Glass memcpy((char *)(store_addr), ymodemBuf, 988*2e192b24SSimon Glass res); 989*2e192b24SSimon Glass } 990*2e192b24SSimon Glass 991*2e192b24SSimon Glass } 992*2e192b24SSimon Glass } else { 993*2e192b24SSimon Glass printf("%s\n", xyzModem_error(err)); 994*2e192b24SSimon Glass } 995*2e192b24SSimon Glass 996*2e192b24SSimon Glass xyzModem_stream_close(&err); 997*2e192b24SSimon Glass xyzModem_stream_terminate(false, &getcxmodem); 998*2e192b24SSimon Glass 999*2e192b24SSimon Glass 1000*2e192b24SSimon Glass flush_cache(offset, size); 1001*2e192b24SSimon Glass 1002*2e192b24SSimon Glass printf("## Total Size = 0x%08x = %d Bytes\n", size, size); 1003*2e192b24SSimon Glass setenv_hex("filesize", size); 1004*2e192b24SSimon Glass 1005*2e192b24SSimon Glass return offset; 1006*2e192b24SSimon Glass } 1007*2e192b24SSimon Glass 1008*2e192b24SSimon Glass #endif 1009*2e192b24SSimon Glass 1010*2e192b24SSimon Glass /* -------------------------------------------------------------------- */ 1011*2e192b24SSimon Glass 1012*2e192b24SSimon Glass #if defined(CONFIG_CMD_LOADS) 1013*2e192b24SSimon Glass 1014*2e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE 1015*2e192b24SSimon Glass U_BOOT_CMD( 1016*2e192b24SSimon Glass loads, 3, 0, do_load_serial, 1017*2e192b24SSimon Glass "load S-Record file over serial line", 1018*2e192b24SSimon Glass "[ off ] [ baud ]\n" 1019*2e192b24SSimon Glass " - load S-Record file over serial line" 1020*2e192b24SSimon Glass " with offset 'off' and baudrate 'baud'" 1021*2e192b24SSimon Glass ); 1022*2e192b24SSimon Glass 1023*2e192b24SSimon Glass #else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */ 1024*2e192b24SSimon Glass U_BOOT_CMD( 1025*2e192b24SSimon Glass loads, 2, 0, do_load_serial, 1026*2e192b24SSimon Glass "load S-Record file over serial line", 1027*2e192b24SSimon Glass "[ off ]\n" 1028*2e192b24SSimon Glass " - load S-Record file over serial line with offset 'off'" 1029*2e192b24SSimon Glass ); 1030*2e192b24SSimon Glass #endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */ 1031*2e192b24SSimon Glass 1032*2e192b24SSimon Glass /* 1033*2e192b24SSimon Glass * SAVES always requires LOADS support, but not vice versa 1034*2e192b24SSimon Glass */ 1035*2e192b24SSimon Glass 1036*2e192b24SSimon Glass 1037*2e192b24SSimon Glass #if defined(CONFIG_CMD_SAVES) 1038*2e192b24SSimon Glass #ifdef CONFIG_SYS_LOADS_BAUD_CHANGE 1039*2e192b24SSimon Glass U_BOOT_CMD( 1040*2e192b24SSimon Glass saves, 4, 0, do_save_serial, 1041*2e192b24SSimon Glass "save S-Record file over serial line", 1042*2e192b24SSimon Glass "[ off ] [size] [ baud ]\n" 1043*2e192b24SSimon Glass " - save S-Record file over serial line" 1044*2e192b24SSimon Glass " with offset 'off', size 'size' and baudrate 'baud'" 1045*2e192b24SSimon Glass ); 1046*2e192b24SSimon Glass #else /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */ 1047*2e192b24SSimon Glass U_BOOT_CMD( 1048*2e192b24SSimon Glass saves, 3, 0, do_save_serial, 1049*2e192b24SSimon Glass "save S-Record file over serial line", 1050*2e192b24SSimon Glass "[ off ] [size]\n" 1051*2e192b24SSimon Glass " - save S-Record file over serial line with offset 'off' and size 'size'" 1052*2e192b24SSimon Glass ); 1053*2e192b24SSimon Glass #endif /* CONFIG_SYS_LOADS_BAUD_CHANGE */ 1054*2e192b24SSimon Glass #endif /* CONFIG_CMD_SAVES */ 1055*2e192b24SSimon Glass #endif /* CONFIG_CMD_LOADS */ 1056*2e192b24SSimon Glass 1057*2e192b24SSimon Glass 1058*2e192b24SSimon Glass #if defined(CONFIG_CMD_LOADB) 1059*2e192b24SSimon Glass U_BOOT_CMD( 1060*2e192b24SSimon Glass loadb, 3, 0, do_load_serial_bin, 1061*2e192b24SSimon Glass "load binary file over serial line (kermit mode)", 1062*2e192b24SSimon Glass "[ off ] [ baud ]\n" 1063*2e192b24SSimon Glass " - load binary file over serial line" 1064*2e192b24SSimon Glass " with offset 'off' and baudrate 'baud'" 1065*2e192b24SSimon Glass ); 1066*2e192b24SSimon Glass 1067*2e192b24SSimon Glass U_BOOT_CMD( 1068*2e192b24SSimon Glass loadx, 3, 0, do_load_serial_bin, 1069*2e192b24SSimon Glass "load binary file over serial line (xmodem mode)", 1070*2e192b24SSimon Glass "[ off ] [ baud ]\n" 1071*2e192b24SSimon Glass " - load binary file over serial line" 1072*2e192b24SSimon Glass " with offset 'off' and baudrate 'baud'" 1073*2e192b24SSimon Glass ); 1074*2e192b24SSimon Glass 1075*2e192b24SSimon Glass U_BOOT_CMD( 1076*2e192b24SSimon Glass loady, 3, 0, do_load_serial_bin, 1077*2e192b24SSimon Glass "load binary file over serial line (ymodem mode)", 1078*2e192b24SSimon Glass "[ off ] [ baud ]\n" 1079*2e192b24SSimon Glass " - load binary file over serial line" 1080*2e192b24SSimon Glass " with offset 'off' and baudrate 'baud'" 1081*2e192b24SSimon Glass ); 1082*2e192b24SSimon Glass 1083*2e192b24SSimon Glass #endif /* CONFIG_CMD_LOADB */ 1084*2e192b24SSimon Glass 1085*2e192b24SSimon Glass /* -------------------------------------------------------------------- */ 1086*2e192b24SSimon Glass 1087*2e192b24SSimon Glass #if defined(CONFIG_CMD_HWFLOW) 1088*2e192b24SSimon Glass int do_hwflow(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 1089*2e192b24SSimon Glass { 1090*2e192b24SSimon Glass extern int hwflow_onoff(int); 1091*2e192b24SSimon Glass 1092*2e192b24SSimon Glass if (argc == 2) { 1093*2e192b24SSimon Glass if (strcmp(argv[1], "off") == 0) 1094*2e192b24SSimon Glass hwflow_onoff(-1); 1095*2e192b24SSimon Glass else 1096*2e192b24SSimon Glass if (strcmp(argv[1], "on") == 0) 1097*2e192b24SSimon Glass hwflow_onoff(1); 1098*2e192b24SSimon Glass else 1099*2e192b24SSimon Glass return CMD_RET_USAGE; 1100*2e192b24SSimon Glass } 1101*2e192b24SSimon Glass printf("RTS/CTS hardware flow control: %s\n", hwflow_onoff(0) ? "on" : "off"); 1102*2e192b24SSimon Glass return 0; 1103*2e192b24SSimon Glass } 1104*2e192b24SSimon Glass 1105*2e192b24SSimon Glass /* -------------------------------------------------------------------- */ 1106*2e192b24SSimon Glass 1107*2e192b24SSimon Glass U_BOOT_CMD( 1108*2e192b24SSimon Glass hwflow, 2, 0, do_hwflow, 1109*2e192b24SSimon Glass "turn RTS/CTS hardware flow control in serial line on/off", 1110*2e192b24SSimon Glass "[on|off]" 1111*2e192b24SSimon Glass ); 1112*2e192b24SSimon Glass 1113*2e192b24SSimon Glass #endif /* CONFIG_CMD_HWFLOW */ 1114