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