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