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