Blame view

cmd/load.c 24.8 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
8bde7f776   wdenk   * Code cleanup:
2
  /*
232c150a2   wdenk   Add support for S...
3
   * (C) Copyright 2000-2004
8bde7f776   wdenk   * Code cleanup:
4
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
8bde7f776   wdenk   * Code cleanup:
5
6
7
8
9
10
11
   */
  
  /*
   * Serial up- and download support
   */
  #include <common.h>
  #include <command.h>
24b852a7a   Simon Glass   Move console defi...
12
  #include <console.h>
1eb69ae49   Simon Glass   common: Move ARM ...
13
  #include <cpu_func.h>
c7694dd48   Simon Glass   env: Move env_set...
14
  #include <env.h>
0ee48252b   Simon Glass   common: Move flas...
15
  #include <flash.h>
8e8ccfe1a   Simon Glass   common: Move the ...
16
  #include <image.h>
8bde7f776   wdenk   * Code cleanup:
17
18
  #include <s_record.h>
  #include <net.h>
27b207fd0   wdenk   * Implement new m...
19
  #include <exports.h>
b03e0510d   Simon Glass   common: Move seri...
20
  #include <serial.h>
f2841d377   Markus Klotzbuecher   Add support for y...
21
  #include <xyzModem.h>
8bde7f776   wdenk   * Code cleanup:
22

d87080b72   Wolfgang Denk   GCC-4.x fixes: cl...
23
  DECLARE_GLOBAL_DATA_PTR;
8bde7f776   wdenk   * Code cleanup:
24

c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
25
  #if defined(CONFIG_CMD_LOADB)
6e66bd559   Angus Ainslie   Enable xmodem sup...
26
  static ulong load_serial_ymodem(ulong offset, int mode);
8546e2390   Wolfgang Denk   Declare load_seri...
27
  #endif
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
28
  #if defined(CONFIG_CMD_LOADS)
088f1b199   Kim Phillips   common/cmd_*.c: s...
29
30
  static ulong load_serial(long offset);
  static int read_record(char *buf, ulong len);
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
31
  # if defined(CONFIG_CMD_SAVES)
088f1b199   Kim Phillips   common/cmd_*.c: s...
32
33
  static int save_serial(ulong offset, ulong size);
  static int write_record(char *buf);
902531788   Jon Loeliger   common/: Remove l...
34
  #endif
8bde7f776   wdenk   * Code cleanup:
35
36
  
  static int do_echo = 1;
902531788   Jon Loeliger   common/: Remove l...
37
  #endif
8bde7f776   wdenk   * Code cleanup:
38
39
  
  /* -------------------------------------------------------------------- */
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
40
  #if defined(CONFIG_CMD_LOADS)
088f1b199   Kim Phillips   common/cmd_*.c: s...
41
42
  static int do_load_serial(cmd_tbl_t *cmdtp, int flag, int argc,
  			  char * const argv[])
8bde7f776   wdenk   * Code cleanup:
43
  {
2b22d608f   Ricardo Ribalda Delgado   loads: allow nega...
44
  	long offset = 0;
8bde7f776   wdenk   * Code cleanup:
45
46
47
48
  	ulong addr;
  	int i;
  	char *env_echo;
  	int rcode = 0;
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
49
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
50
51
52
53
  	int load_baudrate, current_baudrate;
  
  	load_baudrate = current_baudrate = gd->baudrate;
  #endif
00caae6d4   Simon Glass   env: Rename geten...
54
55
  	env_echo = env_get("loads_echo");
  	if (env_echo && *env_echo == '1')
8bde7f776   wdenk   * Code cleanup:
56
  		do_echo = 1;
00caae6d4   Simon Glass   env: Rename geten...
57
  	else
8bde7f776   wdenk   * Code cleanup:
58
  		do_echo = 0;
8bde7f776   wdenk   * Code cleanup:
59

6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
60
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
61
  	if (argc >= 2) {
2b22d608f   Ricardo Ribalda Delgado   loads: allow nega...
62
  		offset = simple_strtol(argv[1], NULL, 16);
8bde7f776   wdenk   * Code cleanup:
63
64
65
66
67
68
69
70
71
  	}
  	if (argc == 3) {
  		load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
  
  		/* default to current baudrate */
  		if (load_baudrate == 0)
  			load_baudrate = current_baudrate;
  	}
  	if (load_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
72
73
  		printf("## Switch baudrate to %d bps and press ENTER ...
  ",
8bde7f776   wdenk   * Code cleanup:
74
75
76
  			load_baudrate);
  		udelay(50000);
  		gd->baudrate = load_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
77
  		serial_setbrg();
8bde7f776   wdenk   * Code cleanup:
78
79
80
81
82
83
  		udelay(50000);
  		for (;;) {
  			if (getc() == '\r')
  				break;
  		}
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
84
  #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
85
  	if (argc == 2) {
2b22d608f   Ricardo Ribalda Delgado   loads: allow nega...
86
  		offset = simple_strtol(argv[1], NULL, 16);
8bde7f776   wdenk   * Code cleanup:
87
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
88
  #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
89

088f1b199   Kim Phillips   common/cmd_*.c: s...
90
91
  	printf("## Ready for S-Record download ...
  ");
8bde7f776   wdenk   * Code cleanup:
92

088f1b199   Kim Phillips   common/cmd_*.c: s...
93
  	addr = load_serial(offset);
8bde7f776   wdenk   * Code cleanup:
94
95
96
97
98
99
100
  
  	/*
  	 * Gather any trailing characters (for instance, the ^D which
  	 * is sent by 'cu' after sending a file), and give the
  	 * box some time (100 * 1 ms)
  	 */
  	for (i=0; i<100; ++i) {
232c150a2   wdenk   Add support for S...
101
102
  		if (tstc()) {
  			(void) getc();
8bde7f776   wdenk   * Code cleanup:
103
104
105
106
107
  		}
  		udelay(1000);
  	}
  
  	if (addr == ~0) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
108
109
  		printf("## S-Record download aborted
  ");
8bde7f776   wdenk   * Code cleanup:
110
111
  		rcode = 1;
  	} else {
088f1b199   Kim Phillips   common/cmd_*.c: s...
112
113
  		printf("## Start Addr      = 0x%08lX
  ", addr);
bb872dd93   Simon Glass   image: Rename loa...
114
  		image_load_addr = addr;
8bde7f776   wdenk   * Code cleanup:
115
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
116
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
117
  	if (load_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
118
119
  		printf("## Switch baudrate to %d bps and press ESC ...
  ",
8bde7f776   wdenk   * Code cleanup:
120
  			current_baudrate);
088f1b199   Kim Phillips   common/cmd_*.c: s...
121
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
122
  		gd->baudrate = current_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
123
124
  		serial_setbrg();
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
125
126
127
128
129
130
131
132
  		for (;;) {
  			if (getc() == 0x1B) /* ESC */
  				break;
  		}
  	}
  #endif
  	return rcode;
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
133
  static ulong load_serial(long offset)
8bde7f776   wdenk   * Code cleanup:
134
135
136
137
138
139
140
  {
  	char	record[SREC_MAXRECLEN + 1];	/* buffer for one S-Record	*/
  	char	binbuf[SREC_MAXBINLEN];		/* buffer for binary data	*/
  	int	binlen;				/* no. of data bytes in S-Rec.	*/
  	int	type;				/* return code for record type	*/
  	ulong	addr;				/* load address from S-Record	*/
  	ulong	size;				/* number of bytes transferred	*/
8bde7f776   wdenk   * Code cleanup:
141
142
143
144
145
146
  	ulong	store_addr;
  	ulong	start_addr = ~0;
  	ulong	end_addr   =  0;
  	int	line_count =  0;
  
  	while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
147
  		type = srec_decode(record, &binlen, &addr, binbuf);
8bde7f776   wdenk   * Code cleanup:
148
149
150
151
152
153
154
155
156
157
  
  		if (type < 0) {
  			return (~0);		/* Invalid S-Record		*/
  		}
  
  		switch (type) {
  		case SREC_DATA2:
  		case SREC_DATA3:
  		case SREC_DATA4:
  		    store_addr = addr + offset;
e856bdcfb   Masahiro Yamada   flash: complete C...
158
  #ifdef CONFIG_MTD_NOR_FLASH
8bde7f776   wdenk   * Code cleanup:
159
160
  		    if (addr2info(store_addr)) {
  			int rc;
77ddac948   Wolfgang Denk   Cleanup for GCC-4.x
161
  			rc = flash_write((char *)binbuf,store_addr,binlen);
8bde7f776   wdenk   * Code cleanup:
162
  			if (rc != 0) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
163
  				flash_perror(rc);
8bde7f776   wdenk   * Code cleanup:
164
165
166
167
168
  				return (~0);
  			}
  		    } else
  #endif
  		    {
088f1b199   Kim Phillips   common/cmd_*.c: s...
169
  			memcpy((char *)(store_addr), binbuf, binlen);
8bde7f776   wdenk   * Code cleanup:
170
171
172
173
174
175
176
177
178
  		    }
  		    if ((store_addr) < start_addr)
  			start_addr = store_addr;
  		    if ((store_addr + binlen - 1) > end_addr)
  			end_addr = store_addr + binlen - 1;
  		    break;
  		case SREC_END2:
  		case SREC_END3:
  		case SREC_END4:
088f1b199   Kim Phillips   common/cmd_*.c: s...
179
  		    udelay(10000);
8bde7f776   wdenk   * Code cleanup:
180
  		    size = end_addr - start_addr + 1;
088f1b199   Kim Phillips   common/cmd_*.c: s...
181
182
  		    printf("
  "
8bde7f776   wdenk   * Code cleanup:
183
184
185
186
187
188
189
190
  			    "## First Load Addr = 0x%08lX
  "
  			    "## Last  Load Addr = 0x%08lX
  "
  			    "## Total Size      = 0x%08lX = %ld Bytes
  ",
  			    start_addr, end_addr, size, size
  		    );
088f1b199   Kim Phillips   common/cmd_*.c: s...
191
  		    flush_cache(start_addr, size);
018f53032   Simon Glass   env: Rename commo...
192
  		    env_set_hex("filesize", size);
8bde7f776   wdenk   * Code cleanup:
193
194
195
196
197
198
199
200
  		    return (addr);
  		case SREC_START:
  		    break;
  		default:
  		    break;
  		}
  		if (!do_echo) {	/* print a '.' every 100 lines */
  			if ((++line_count % 100) == 0)
088f1b199   Kim Phillips   common/cmd_*.c: s...
201
  				putc('.');
8bde7f776   wdenk   * Code cleanup:
202
203
204
205
206
  		}
  	}
  
  	return (~0);			/* Download aborted		*/
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
207
  static int read_record(char *buf, ulong len)
8bde7f776   wdenk   * Code cleanup:
208
209
210
211
212
213
214
  {
  	char *p;
  	char c;
  
  	--len;	/* always leave room for terminating '\0' byte */
  
  	for (p=buf; p < buf+len; ++p) {
232c150a2   wdenk   Add support for S...
215
  		c = getc();		/* read character		*/
8bde7f776   wdenk   * Code cleanup:
216
  		if (do_echo)
088f1b199   Kim Phillips   common/cmd_*.c: s...
217
  			putc(c);	/* ... and echo it		*/
8bde7f776   wdenk   * Code cleanup:
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  
  		switch (c) {
  		case '\r':
  		case '
  ':
  			*p = '\0';
  			return (p - buf);
  		case '\0':
  		case 0x03:			/* ^C - Control C		*/
  			return (-1);
  		default:
  			*p = c;
  		}
  
  	    /* Check for the console hangup (if any different from serial) */
49cad5478   Martin Dorwig   Export redesign
233
  	    if (gd->jt->getc != getc) {
8bde7f776   wdenk   * Code cleanup:
234
235
236
237
  		if (ctrlc()) {
  		    return (-1);
  		}
  	    }
8bde7f776   wdenk   * Code cleanup:
238
239
240
241
242
243
  	}
  
  	/* line too long - truncate */
  	*p = '\0';
  	return (p - buf);
  }
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
244
  #if defined(CONFIG_CMD_SAVES)
8bde7f776   wdenk   * Code cleanup:
245

54841ab50   Wolfgang Denk   Make sure that ar...
246
  int do_save_serial (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
8bde7f776   wdenk   * Code cleanup:
247
248
249
  {
  	ulong offset = 0;
  	ulong size   = 0;
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
250
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
251
252
253
254
255
256
257
258
  	int save_baudrate, current_baudrate;
  
  	save_baudrate = current_baudrate = gd->baudrate;
  #endif
  
  	if (argc >= 2) {
  		offset = simple_strtoul(argv[1], NULL, 16);
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
259
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
260
261
262
263
264
265
266
267
268
269
270
  	if (argc >= 3) {
  		size = simple_strtoul(argv[2], NULL, 16);
  	}
  	if (argc == 4) {
  		save_baudrate = (int)simple_strtoul(argv[3], NULL, 10);
  
  		/* default to current baudrate */
  		if (save_baudrate == 0)
  			save_baudrate = current_baudrate;
  	}
  	if (save_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
271
272
  		printf("## Switch baudrate to %d bps and press ENTER ...
  ",
8bde7f776   wdenk   * Code cleanup:
273
274
275
  			save_baudrate);
  		udelay(50000);
  		gd->baudrate = save_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
276
  		serial_setbrg();
8bde7f776   wdenk   * Code cleanup:
277
278
279
280
281
282
  		udelay(50000);
  		for (;;) {
  			if (getc() == '\r')
  				break;
  		}
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
283
  #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
284
285
286
  	if (argc == 3) {
  		size = simple_strtoul(argv[2], NULL, 16);
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
287
  #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
288

088f1b199   Kim Phillips   common/cmd_*.c: s...
289
290
  	printf("## Ready for S-Record upload, press ENTER to proceed ...
  ");
8bde7f776   wdenk   * Code cleanup:
291
292
293
294
  	for (;;) {
  		if (getc() == '\r')
  			break;
  	}
088f1b199   Kim Phillips   common/cmd_*.c: s...
295
296
297
  	if (save_serial(offset, size)) {
  		printf("## S-Record upload aborted
  ");
8bde7f776   wdenk   * Code cleanup:
298
  	} else {
088f1b199   Kim Phillips   common/cmd_*.c: s...
299
300
  		printf("## S-Record upload complete
  ");
8bde7f776   wdenk   * Code cleanup:
301
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
302
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
303
  	if (save_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
304
305
  		printf("## Switch baudrate to %d bps and press ESC ...
  ",
8bde7f776   wdenk   * Code cleanup:
306
  			(int)current_baudrate);
088f1b199   Kim Phillips   common/cmd_*.c: s...
307
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
308
  		gd->baudrate = current_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
309
310
  		serial_setbrg();
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  		for (;;) {
  			if (getc() == 0x1B) /* ESC */
  				break;
  		}
  	}
  #endif
  	return 0;
  }
  
  #define SREC3_START				"S0030000FC
  "
  #define SREC3_FORMAT			"S3%02X%08lX%s%02X
  "
  #define SREC3_END				"S70500000000FA
  "
  #define SREC_BYTES_PER_RECORD	16
088f1b199   Kim Phillips   common/cmd_*.c: s...
327
  static int save_serial(ulong address, ulong count)
8bde7f776   wdenk   * Code cleanup:
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  {
  	int i, c, reclen, checksum, length;
  	char *hex = "0123456789ABCDEF";
  	char	record[2*SREC_BYTES_PER_RECORD+16];	/* buffer for one S-Record	*/
  	char	data[2*SREC_BYTES_PER_RECORD+1];	/* buffer for hex data	*/
  
  	reclen = 0;
  	checksum  = 0;
  
  	if(write_record(SREC3_START))			/* write the header */
  		return (-1);
  	do {
  		if(count) {						/* collect hex data in the buffer  */
  			c = *(volatile uchar*)(address + reclen);	/* get one byte    */
  			checksum += c;							/* accumulate checksum */
  			data[2*reclen]   = hex[(c>>4)&0x0f];
  			data[2*reclen+1] = hex[c & 0x0f];
  			data[2*reclen+2] = '\0';
  			++reclen;
  			--count;
  		}
  		if(reclen == SREC_BYTES_PER_RECORD || count == 0) {
  			/* enough data collected for one record: dump it */
  			if(reclen) {	/* build & write a data record: */
  				/* address + data + checksum */
  				length = 4 + reclen + 1;
  
  				/* accumulate length bytes into checksum */
  				for(i = 0; i < 2; i++)
  					checksum += (length >> (8*i)) & 0xff;
  
  				/* accumulate address bytes into checksum: */
  				for(i = 0; i < 4; i++)
  					checksum += (address >> (8*i)) & 0xff;
  
  				/* make proper checksum byte: */
  				checksum = ~checksum & 0xff;
  
  				/* output one record: */
  				sprintf(record, SREC3_FORMAT, length, address, data, checksum);
  				if(write_record(record))
  					return (-1);
  			}
  			address  += reclen;  /* increment address */
  			checksum  = 0;
  			reclen    = 0;
  		}
  	}
  	while(count);
  	if(write_record(SREC3_END))	/* write the final record */
  		return (-1);
  	return(0);
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
381
  static int write_record(char *buf)
8bde7f776   wdenk   * Code cleanup:
382
383
384
385
  {
  	char c;
  
  	while((c = *buf++))
232c150a2   wdenk   Add support for S...
386
  		putc(c);
8bde7f776   wdenk   * Code cleanup:
387
388
389
390
391
392
393
394
  
  	/* Check for the console hangup (if any different from serial) */
  
  	if (ctrlc()) {
  	    return (-1);
  	}
  	return (0);
  }
902531788   Jon Loeliger   common/: Remove l...
395
  # endif
8bde7f776   wdenk   * Code cleanup:
396

902531788   Jon Loeliger   common/: Remove l...
397
  #endif
8bde7f776   wdenk   * Code cleanup:
398

c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
399
  #if defined(CONFIG_CMD_LOADB)
65c450b47   Jon Loeliger   common/cmd_[i-z]*...
400
401
402
  /*
   * loadb command (load binary) included
   */
8bde7f776   wdenk   * Code cleanup:
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  #define XON_CHAR        17
  #define XOFF_CHAR       19
  #define START_CHAR      0x01
  #define ETX_CHAR	0x03
  #define END_CHAR        0x0D
  #define SPACE           0x20
  #define K_ESCAPE        0x23
  #define SEND_TYPE       'S'
  #define DATA_TYPE       'D'
  #define ACK_TYPE        'Y'
  #define NACK_TYPE       'N'
  #define BREAK_TYPE      'B'
  #define tochar(x) ((char) (((x) + SPACE) & 0xff))
  #define untochar(x) ((int) (((x) - SPACE) & 0xff))
8bde7f776   wdenk   * Code cleanup:
417
418
  static void set_kerm_bin_mode(unsigned long *);
  static int k_recv(void);
088f1b199   Kim Phillips   common/cmd_*.c: s...
419
  static ulong load_serial_bin(ulong offset);
8bde7f776   wdenk   * Code cleanup:
420

088f1b199   Kim Phillips   common/cmd_*.c: s...
421
422
423
424
  static char his_eol;        /* character he needs at end of packet */
  static int  his_pad_count;  /* number of pad chars he needs */
  static char his_pad_char;   /* pad chars he needs */
  static char his_quote;      /* quote chars he'll use */
8bde7f776   wdenk   * Code cleanup:
425

088f1b199   Kim Phillips   common/cmd_*.c: s...
426
427
  static int do_load_serial_bin(cmd_tbl_t *cmdtp, int flag, int argc,
  			      char * const argv[])
8bde7f776   wdenk   * Code cleanup:
428
  {
8bde7f776   wdenk   * Code cleanup:
429
430
431
432
433
  	ulong offset = 0;
  	ulong addr;
  	int load_baudrate, current_baudrate;
  	int rcode = 0;
  	char *s;
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
434
435
  	/* pre-set offset from CONFIG_SYS_LOAD_ADDR */
  	offset = CONFIG_SYS_LOAD_ADDR;
8bde7f776   wdenk   * Code cleanup:
436
437
  
  	/* pre-set offset from $loadaddr */
00caae6d4   Simon Glass   env: Rename geten...
438
439
  	s = env_get("loadaddr");
  	if (s)
8bde7f776   wdenk   * Code cleanup:
440
  		offset = simple_strtoul(s, NULL, 16);
8bde7f776   wdenk   * Code cleanup:
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  
  	load_baudrate = current_baudrate = gd->baudrate;
  
  	if (argc >= 2) {
  		offset = simple_strtoul(argv[1], NULL, 16);
  	}
  	if (argc == 3) {
  		load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
  
  		/* default to current baudrate */
  		if (load_baudrate == 0)
  			load_baudrate = current_baudrate;
  	}
  
  	if (load_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
456
457
  		printf("## Switch baudrate to %d bps and press ENTER ...
  ",
8bde7f776   wdenk   * Code cleanup:
458
459
460
  			load_baudrate);
  		udelay(50000);
  		gd->baudrate = load_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
461
  		serial_setbrg();
8bde7f776   wdenk   * Code cleanup:
462
463
464
465
466
467
  		udelay(50000);
  		for (;;) {
  			if (getc() == '\r')
  				break;
  		}
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
468
  	if (strcmp(argv[0],"loady")==0) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
469
  		printf("## Ready for binary (ymodem) download "
f2841d377   Markus Klotzbuecher   Add support for y...
470
471
472
473
  			"to 0x%08lX at %d bps...
  ",
  			offset,
  			load_baudrate);
6e66bd559   Angus Ainslie   Enable xmodem sup...
474
475
476
477
478
479
480
481
482
483
  		addr = load_serial_ymodem(offset, xyzModem_ymodem);
  
  	} else if (strcmp(argv[0],"loadx")==0) {
  		printf("## Ready for binary (xmodem) download "
  			"to 0x%08lX at %d bps...
  ",
  			offset,
  			load_baudrate);
  
  		addr = load_serial_ymodem(offset, xyzModem_xmodem);
8bde7f776   wdenk   * Code cleanup:
484

8bde7f776   wdenk   * Code cleanup:
485
  	} else {
8bde7f776   wdenk   * Code cleanup:
486

088f1b199   Kim Phillips   common/cmd_*.c: s...
487
  		printf("## Ready for binary (kermit) download "
f2841d377   Markus Klotzbuecher   Add support for y...
488
489
490
491
  			"to 0x%08lX at %d bps...
  ",
  			offset,
  			load_baudrate);
088f1b199   Kim Phillips   common/cmd_*.c: s...
492
  		addr = load_serial_bin(offset);
f2841d377   Markus Klotzbuecher   Add support for y...
493
494
  
  		if (addr == ~0) {
bb872dd93   Simon Glass   image: Rename loa...
495
  			image_load_addr = 0;
088f1b199   Kim Phillips   common/cmd_*.c: s...
496
497
  			printf("## Binary (kermit) download aborted
  ");
f2841d377   Markus Klotzbuecher   Add support for y...
498
499
  			rcode = 1;
  		} else {
088f1b199   Kim Phillips   common/cmd_*.c: s...
500
501
  			printf("## Start Addr      = 0x%08lX
  ", addr);
bb872dd93   Simon Glass   image: Rename loa...
502
  			image_load_addr = addr;
f2841d377   Markus Klotzbuecher   Add support for y...
503
504
  		}
  	}
8bde7f776   wdenk   * Code cleanup:
505
  	if (load_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
506
507
  		printf("## Switch baudrate to %d bps and press ESC ...
  ",
8bde7f776   wdenk   * Code cleanup:
508
  			current_baudrate);
088f1b199   Kim Phillips   common/cmd_*.c: s...
509
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
510
  		gd->baudrate = current_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
511
512
  		serial_setbrg();
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
513
514
515
516
517
  		for (;;) {
  			if (getc() == 0x1B) /* ESC */
  				break;
  		}
  	}
8bde7f776   wdenk   * Code cleanup:
518
519
  	return rcode;
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
520
  static ulong load_serial_bin(ulong offset)
8bde7f776   wdenk   * Code cleanup:
521
522
  {
  	int size, i;
8bde7f776   wdenk   * Code cleanup:
523

088f1b199   Kim Phillips   common/cmd_*.c: s...
524
525
  	set_kerm_bin_mode((ulong *) offset);
  	size = k_recv();
8bde7f776   wdenk   * Code cleanup:
526
527
528
529
530
531
532
  
  	/*
  	 * Gather any trailing characters (for instance, the ^D which
  	 * is sent by 'cu' after sending a file), and give the
  	 * box some time (100 * 1 ms)
  	 */
  	for (i=0; i<100; ++i) {
232c150a2   wdenk   Add support for S...
533
534
  		if (tstc()) {
  			(void) getc();
8bde7f776   wdenk   * Code cleanup:
535
536
537
  		}
  		udelay(1000);
  	}
088f1b199   Kim Phillips   common/cmd_*.c: s...
538
  	flush_cache(offset, size);
8bde7f776   wdenk   * Code cleanup:
539
540
541
  
  	printf("## Total Size      = 0x%08x = %d Bytes
  ", size, size);
018f53032   Simon Glass   env: Rename commo...
542
  	env_set_hex("filesize", size);
8bde7f776   wdenk   * Code cleanup:
543
544
545
  
  	return offset;
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
546
  static void send_pad(void)
8bde7f776   wdenk   * Code cleanup:
547
548
549
550
  {
  	int count = his_pad_count;
  
  	while (count-- > 0)
088f1b199   Kim Phillips   common/cmd_*.c: s...
551
  		putc(his_pad_char);
8bde7f776   wdenk   * Code cleanup:
552
553
554
  }
  
  /* converts escaped kermit char to binary char */
088f1b199   Kim Phillips   common/cmd_*.c: s...
555
  static char ktrans(char in)
8bde7f776   wdenk   * Code cleanup:
556
557
558
559
560
561
562
563
  {
  	if ((in & 0x60) == 0x40) {
  		return (char) (in & ~0x40);
  	} else if ((in & 0x7f) == 0x3f) {
  		return (char) (in | 0x40);
  	} else
  		return in;
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
564
  static int chk1(char *buffer)
8bde7f776   wdenk   * Code cleanup:
565
566
567
568
569
570
571
572
  {
  	int total = 0;
  
  	while (*buffer) {
  		total += *buffer++;
  	}
  	return (int) ((total + ((total >> 6) & 0x03)) & 0x3f);
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
573
  static void s1_sendpacket(char *packet)
8bde7f776   wdenk   * Code cleanup:
574
  {
088f1b199   Kim Phillips   common/cmd_*.c: s...
575
  	send_pad();
8bde7f776   wdenk   * Code cleanup:
576
  	while (*packet) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
577
  		putc(*packet++);
8bde7f776   wdenk   * Code cleanup:
578
579
580
581
  	}
  }
  
  static char a_b[24];
088f1b199   Kim Phillips   common/cmd_*.c: s...
582
  static void send_ack(int n)
8bde7f776   wdenk   * Code cleanup:
583
584
  {
  	a_b[0] = START_CHAR;
088f1b199   Kim Phillips   common/cmd_*.c: s...
585
586
  	a_b[1] = tochar(3);
  	a_b[2] = tochar(n);
8bde7f776   wdenk   * Code cleanup:
587
588
  	a_b[3] = ACK_TYPE;
  	a_b[4] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
589
  	a_b[4] = tochar(chk1(&a_b[1]));
8bde7f776   wdenk   * Code cleanup:
590
591
  	a_b[5] = his_eol;
  	a_b[6] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
592
  	s1_sendpacket(a_b);
8bde7f776   wdenk   * Code cleanup:
593
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
594
  static void send_nack(int n)
8bde7f776   wdenk   * Code cleanup:
595
596
  {
  	a_b[0] = START_CHAR;
088f1b199   Kim Phillips   common/cmd_*.c: s...
597
598
  	a_b[1] = tochar(3);
  	a_b[2] = tochar(n);
8bde7f776   wdenk   * Code cleanup:
599
600
  	a_b[3] = NACK_TYPE;
  	a_b[4] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
601
  	a_b[4] = tochar(chk1(&a_b[1]));
8bde7f776   wdenk   * Code cleanup:
602
603
  	a_b[5] = his_eol;
  	a_b[6] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
604
  	s1_sendpacket(a_b);
8bde7f776   wdenk   * Code cleanup:
605
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
606
607
  static void (*os_data_init)(void);
  static void (*os_data_char)(char new_char);
8bde7f776   wdenk   * Code cleanup:
608
  static int os_data_state, os_data_state_saved;
8bde7f776   wdenk   * Code cleanup:
609
610
  static char *os_data_addr, *os_data_addr_saved;
  static char *bin_start_address;
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
611

088f1b199   Kim Phillips   common/cmd_*.c: s...
612
  static void bin_data_init(void)
8bde7f776   wdenk   * Code cleanup:
613
614
  {
  	os_data_state = 0;
8bde7f776   wdenk   * Code cleanup:
615
616
  	os_data_addr = bin_start_address;
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
617

088f1b199   Kim Phillips   common/cmd_*.c: s...
618
  static void os_data_save(void)
8bde7f776   wdenk   * Code cleanup:
619
620
  {
  	os_data_state_saved = os_data_state;
8bde7f776   wdenk   * Code cleanup:
621
622
  	os_data_addr_saved = os_data_addr;
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
623

088f1b199   Kim Phillips   common/cmd_*.c: s...
624
  static void os_data_restore(void)
8bde7f776   wdenk   * Code cleanup:
625
626
  {
  	os_data_state = os_data_state_saved;
8bde7f776   wdenk   * Code cleanup:
627
628
  	os_data_addr = os_data_addr_saved;
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
629

088f1b199   Kim Phillips   common/cmd_*.c: s...
630
  static void bin_data_char(char new_char)
8bde7f776   wdenk   * Code cleanup:
631
632
633
634
  {
  	switch (os_data_state) {
  	case 0:					/* data */
  		*os_data_addr++ = new_char;
8bde7f776   wdenk   * Code cleanup:
635
636
637
  		break;
  	}
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
638

088f1b199   Kim Phillips   common/cmd_*.c: s...
639
  static void set_kerm_bin_mode(unsigned long *addr)
8bde7f776   wdenk   * Code cleanup:
640
641
642
643
644
645
646
647
648
  {
  	bin_start_address = (char *) addr;
  	os_data_init = bin_data_init;
  	os_data_char = bin_data_char;
  }
  
  
  /* k_data_* simply handles the kermit escape translations */
  static int k_data_escape, k_data_escape_saved;
088f1b199   Kim Phillips   common/cmd_*.c: s...
649
  static void k_data_init(void)
8bde7f776   wdenk   * Code cleanup:
650
651
  {
  	k_data_escape = 0;
088f1b199   Kim Phillips   common/cmd_*.c: s...
652
  	os_data_init();
8bde7f776   wdenk   * Code cleanup:
653
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
654

088f1b199   Kim Phillips   common/cmd_*.c: s...
655
  static void k_data_save(void)
8bde7f776   wdenk   * Code cleanup:
656
657
  {
  	k_data_escape_saved = k_data_escape;
088f1b199   Kim Phillips   common/cmd_*.c: s...
658
  	os_data_save();
8bde7f776   wdenk   * Code cleanup:
659
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
660

088f1b199   Kim Phillips   common/cmd_*.c: s...
661
  static void k_data_restore(void)
8bde7f776   wdenk   * Code cleanup:
662
663
  {
  	k_data_escape = k_data_escape_saved;
088f1b199   Kim Phillips   common/cmd_*.c: s...
664
  	os_data_restore();
8bde7f776   wdenk   * Code cleanup:
665
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
666

088f1b199   Kim Phillips   common/cmd_*.c: s...
667
  static void k_data_char(char new_char)
8bde7f776   wdenk   * Code cleanup:
668
669
670
  {
  	if (k_data_escape) {
  		/* last char was escape - translate this character */
088f1b199   Kim Phillips   common/cmd_*.c: s...
671
  		os_data_char(ktrans(new_char));
8bde7f776   wdenk   * Code cleanup:
672
673
674
675
676
677
678
  		k_data_escape = 0;
  	} else {
  		if (new_char == his_quote) {
  			/* this char is escape - remember */
  			k_data_escape = 1;
  		} else {
  			/* otherwise send this char as-is */
088f1b199   Kim Phillips   common/cmd_*.c: s...
679
  			os_data_char(new_char);
8bde7f776   wdenk   * Code cleanup:
680
681
682
683
684
  		}
  	}
  }
  
  #define SEND_DATA_SIZE  20
088f1b199   Kim Phillips   common/cmd_*.c: s...
685
686
  static char send_parms[SEND_DATA_SIZE];
  static char *send_ptr;
8bde7f776   wdenk   * Code cleanup:
687
688
689
  
  /* handle_send_packet interprits the protocol info and builds and
     sends an appropriate ack for what we can do */
088f1b199   Kim Phillips   common/cmd_*.c: s...
690
  static void handle_send_packet(int n)
8bde7f776   wdenk   * Code cleanup:
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
  {
  	int length = 3;
  	int bytes;
  
  	/* initialize some protocol parameters */
  	his_eol = END_CHAR;		/* default end of line character */
  	his_pad_count = 0;
  	his_pad_char = '\0';
  	his_quote = K_ESCAPE;
  
  	/* ignore last character if it filled the buffer */
  	if (send_ptr == &send_parms[SEND_DATA_SIZE - 1])
  		--send_ptr;
  	bytes = send_ptr - send_parms;	/* how many bytes we'll process */
  	do {
  		if (bytes-- <= 0)
  			break;
  		/* handle MAXL - max length */
  		/* ignore what he says - most I'll take (here) is 94 */
088f1b199   Kim Phillips   common/cmd_*.c: s...
710
  		a_b[++length] = tochar(94);
8bde7f776   wdenk   * Code cleanup:
711
712
713
714
  		if (bytes-- <= 0)
  			break;
  		/* handle TIME - time you should wait for my packets */
  		/* ignore what he says - don't wait for my ack longer than 1 second */
088f1b199   Kim Phillips   common/cmd_*.c: s...
715
  		a_b[++length] = tochar(1);
8bde7f776   wdenk   * Code cleanup:
716
717
718
719
  		if (bytes-- <= 0)
  			break;
  		/* handle NPAD - number of pad chars I need */
  		/* remember what he says - I need none */
088f1b199   Kim Phillips   common/cmd_*.c: s...
720
721
  		his_pad_count = untochar(send_parms[2]);
  		a_b[++length] = tochar(0);
8bde7f776   wdenk   * Code cleanup:
722
723
724
725
  		if (bytes-- <= 0)
  			break;
  		/* handle PADC - pad chars I need */
  		/* remember what he says - I need none */
088f1b199   Kim Phillips   common/cmd_*.c: s...
726
  		his_pad_char = ktrans(send_parms[3]);
8bde7f776   wdenk   * Code cleanup:
727
728
729
730
731
  		a_b[++length] = 0x40;	/* He should ignore this */
  		if (bytes-- <= 0)
  			break;
  		/* handle EOL - end of line he needs */
  		/* remember what he says - I need CR */
088f1b199   Kim Phillips   common/cmd_*.c: s...
732
733
  		his_eol = untochar(send_parms[4]);
  		a_b[++length] = tochar(END_CHAR);
8bde7f776   wdenk   * Code cleanup:
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
  		if (bytes-- <= 0)
  			break;
  		/* handle QCTL - quote control char he'll use */
  		/* remember what he says - I'll use '#' */
  		his_quote = send_parms[5];
  		a_b[++length] = '#';
  		if (bytes-- <= 0)
  			break;
  		/* handle QBIN - 8-th bit prefixing */
  		/* ignore what he says - I refuse */
  		a_b[++length] = 'N';
  		if (bytes-- <= 0)
  			break;
  		/* handle CHKT - the clock check type */
  		/* ignore what he says - I do type 1 (for now) */
  		a_b[++length] = '1';
  		if (bytes-- <= 0)
  			break;
  		/* handle REPT - the repeat prefix */
  		/* ignore what he says - I refuse (for now) */
  		a_b[++length] = 'N';
  		if (bytes-- <= 0)
  			break;
  		/* handle CAPAS - the capabilities mask */
  		/* ignore what he says - I only do long packets - I don't do windows */
088f1b199   Kim Phillips   common/cmd_*.c: s...
759
760
761
762
  		a_b[++length] = tochar(2);	/* only long packets */
  		a_b[++length] = tochar(0);	/* no windows */
  		a_b[++length] = tochar(94);	/* large packet msb */
  		a_b[++length] = tochar(94);	/* large packet lsb */
8bde7f776   wdenk   * Code cleanup:
763
764
765
  	} while (0);
  
  	a_b[0] = START_CHAR;
088f1b199   Kim Phillips   common/cmd_*.c: s...
766
767
  	a_b[1] = tochar(length);
  	a_b[2] = tochar(n);
8bde7f776   wdenk   * Code cleanup:
768
769
  	a_b[3] = ACK_TYPE;
  	a_b[++length] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
770
  	a_b[length] = tochar(chk1(&a_b[1]));
8bde7f776   wdenk   * Code cleanup:
771
772
  	a_b[++length] = his_eol;
  	a_b[++length] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
773
  	s1_sendpacket(a_b);
8bde7f776   wdenk   * Code cleanup:
774
775
776
  }
  
  /* k_recv receives a OS Open image file over kermit line */
088f1b199   Kim Phillips   common/cmd_*.c: s...
777
  static int k_recv(void)
8bde7f776   wdenk   * Code cleanup:
778
779
780
781
782
783
784
  {
  	char new_char;
  	char k_state, k_state_saved;
  	int sum;
  	int done;
  	int length;
  	int n, last_n;
8bde7f776   wdenk   * Code cleanup:
785
786
787
788
789
790
791
792
793
794
795
  	int len_lo, len_hi;
  
  	/* initialize some protocol parameters */
  	his_eol = END_CHAR;		/* default end of line character */
  	his_pad_count = 0;
  	his_pad_char = '\0';
  	his_quote = K_ESCAPE;
  
  	/* initialize the k_recv and k_data state machine */
  	done = 0;
  	k_state = 0;
088f1b199   Kim Phillips   common/cmd_*.c: s...
796
  	k_data_init();
8bde7f776   wdenk   * Code cleanup:
797
  	k_state_saved = k_state;
088f1b199   Kim Phillips   common/cmd_*.c: s...
798
  	k_data_save();
8bde7f776   wdenk   * Code cleanup:
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
  	n = 0;				/* just to get rid of a warning */
  	last_n = -1;
  
  	/* expect this "type" sequence (but don't check):
  	   S: send initiate
  	   F: file header
  	   D: data (multiple)
  	   Z: end of file
  	   B: break transmission
  	 */
  
  	/* enter main loop */
  	while (!done) {
  		/* set the send packet pointer to begining of send packet parms */
  		send_ptr = send_parms;
  
  		/* With each packet, start summing the bytes starting with the length.
  		   Save the current sequence number.
  		   Note the type of the packet.
  		   If a character less than SPACE (0x20) is received - error.
  		 */
  
  #if 0
  		/* OLD CODE, Prior to checking sequence numbers */
  		/* first have all state machines save current states */
  		k_state_saved = k_state;
  		k_data_save ();
  #endif
  
  		/* get a packet */
  		/* wait for the starting character or ^C */
  		for (;;) {
232c150a2   wdenk   Add support for S...
831
  			switch (getc ()) {
8bde7f776   wdenk   * Code cleanup:
832
833
834
835
836
837
838
839
840
841
842
  			case START_CHAR:	/* start packet */
  				goto START;
  			case ETX_CHAR:		/* ^C waiting for packet */
  				return (0);
  			default:
  				;
  			}
  		}
  START:
  		/* get length of packet */
  		sum = 0;
088f1b199   Kim Phillips   common/cmd_*.c: s...
843
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
844
845
846
  		if ((new_char & 0xE0) == 0)
  			goto packet_error;
  		sum += new_char & 0xff;
088f1b199   Kim Phillips   common/cmd_*.c: s...
847
  		length = untochar(new_char);
8bde7f776   wdenk   * Code cleanup:
848
  		/* get sequence number */
088f1b199   Kim Phillips   common/cmd_*.c: s...
849
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
850
851
852
  		if ((new_char & 0xE0) == 0)
  			goto packet_error;
  		sum += new_char & 0xff;
088f1b199   Kim Phillips   common/cmd_*.c: s...
853
  		n = untochar(new_char);
8bde7f776   wdenk   * Code cleanup:
854
855
856
857
858
859
860
861
862
863
864
865
  		--length;
  
  		/* NEW CODE - check sequence numbers for retried packets */
  		/* Note - this new code assumes that the sequence number is correctly
  		 * received.  Handling an invalid sequence number adds another layer
  		 * of complexity that may not be needed - yet!  At this time, I'm hoping
  		 * that I don't need to buffer the incoming data packets and can write
  		 * the data into memory in real time.
  		 */
  		if (n == last_n) {
  			/* same sequence number, restore the previous state */
  			k_state = k_state_saved;
088f1b199   Kim Phillips   common/cmd_*.c: s...
866
  			k_data_restore();
8bde7f776   wdenk   * Code cleanup:
867
868
869
870
  		} else {
  			/* new sequence number, checkpoint the download */
  			last_n = n;
  			k_state_saved = k_state;
088f1b199   Kim Phillips   common/cmd_*.c: s...
871
  			k_data_save();
8bde7f776   wdenk   * Code cleanup:
872
873
874
875
  		}
  		/* END NEW CODE */
  
  		/* get packet type */
088f1b199   Kim Phillips   common/cmd_*.c: s...
876
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
877
878
879
880
881
882
883
884
885
  		if ((new_char & 0xE0) == 0)
  			goto packet_error;
  		sum += new_char & 0xff;
  		k_state = new_char;
  		--length;
  		/* check for extended length */
  		if (length == -2) {
  			/* (length byte was 0, decremented twice) */
  			/* get the two length bytes */
088f1b199   Kim Phillips   common/cmd_*.c: s...
886
  			new_char = getc();
8bde7f776   wdenk   * Code cleanup:
887
888
889
  			if ((new_char & 0xE0) == 0)
  				goto packet_error;
  			sum += new_char & 0xff;
088f1b199   Kim Phillips   common/cmd_*.c: s...
890
891
  			len_hi = untochar(new_char);
  			new_char = getc();
8bde7f776   wdenk   * Code cleanup:
892
893
894
  			if ((new_char & 0xE0) == 0)
  				goto packet_error;
  			sum += new_char & 0xff;
088f1b199   Kim Phillips   common/cmd_*.c: s...
895
  			len_lo = untochar(new_char);
8bde7f776   wdenk   * Code cleanup:
896
897
  			length = len_hi * 95 + len_lo;
  			/* check header checksum */
088f1b199   Kim Phillips   common/cmd_*.c: s...
898
  			new_char = getc();
8bde7f776   wdenk   * Code cleanup:
899
900
  			if ((new_char & 0xE0) == 0)
  				goto packet_error;
088f1b199   Kim Phillips   common/cmd_*.c: s...
901
  			if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
8bde7f776   wdenk   * Code cleanup:
902
903
904
905
906
907
  				goto packet_error;
  			sum += new_char & 0xff;
  /* --length; */ /* new length includes only data and block check to come */
  		}
  		/* bring in rest of packet */
  		while (length > 1) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
908
  			new_char = getc();
8bde7f776   wdenk   * Code cleanup:
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
  			if ((new_char & 0xE0) == 0)
  				goto packet_error;
  			sum += new_char & 0xff;
  			--length;
  			if (k_state == DATA_TYPE) {
  				/* pass on the data if this is a data packet */
  				k_data_char (new_char);
  			} else if (k_state == SEND_TYPE) {
  				/* save send pack in buffer as is */
  				*send_ptr++ = new_char;
  				/* if too much data, back off the pointer */
  				if (send_ptr >= &send_parms[SEND_DATA_SIZE])
  					--send_ptr;
  			}
  		}
  		/* get and validate checksum character */
088f1b199   Kim Phillips   common/cmd_*.c: s...
925
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
926
927
  		if ((new_char & 0xE0) == 0)
  			goto packet_error;
088f1b199   Kim Phillips   common/cmd_*.c: s...
928
  		if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
8bde7f776   wdenk   * Code cleanup:
929
930
  			goto packet_error;
  		/* get END_CHAR */
088f1b199   Kim Phillips   common/cmd_*.c: s...
931
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
932
933
934
935
  		if (new_char != END_CHAR) {
  		  packet_error:
  			/* restore state machines */
  			k_state = k_state_saved;
088f1b199   Kim Phillips   common/cmd_*.c: s...
936
  			k_data_restore();
8bde7f776   wdenk   * Code cleanup:
937
  			/* send a negative acknowledge packet in */
088f1b199   Kim Phillips   common/cmd_*.c: s...
938
  			send_nack(n);
8bde7f776   wdenk   * Code cleanup:
939
940
  		} else if (k_state == SEND_TYPE) {
  			/* crack the protocol parms, build an appropriate ack packet */
088f1b199   Kim Phillips   common/cmd_*.c: s...
941
  			handle_send_packet(n);
8bde7f776   wdenk   * Code cleanup:
942
943
  		} else {
  			/* send simple acknowledge packet in */
088f1b199   Kim Phillips   common/cmd_*.c: s...
944
  			send_ack(n);
8bde7f776   wdenk   * Code cleanup:
945
946
947
948
  			/* quit if end of transmission */
  			if (k_state == BREAK_TYPE)
  				done = 1;
  		}
8bde7f776   wdenk   * Code cleanup:
949
950
951
  	}
  	return ((ulong) os_data_addr - (ulong) bin_start_address);
  }
f2841d377   Markus Klotzbuecher   Add support for y...
952
953
  
  static int getcxmodem(void) {
cf48eb9ab   Wolfgang Denk   Some code cleanup
954
  	if (tstc())
f2841d377   Markus Klotzbuecher   Add support for y...
955
956
957
  		return (getc());
  	return -1;
  }
6e66bd559   Angus Ainslie   Enable xmodem sup...
958
  static ulong load_serial_ymodem(ulong offset, int mode)
f2841d377   Markus Klotzbuecher   Add support for y...
959
960
  {
  	int size;
f2841d377   Markus Klotzbuecher   Add support for y...
961
962
963
  	int err;
  	int res;
  	connection_info_t info;
cf48eb9ab   Wolfgang Denk   Some code cleanup
964
965
966
  	char ymodemBuf[1024];
  	ulong store_addr = ~0;
  	ulong addr = 0;
f2841d377   Markus Klotzbuecher   Add support for y...
967

cf48eb9ab   Wolfgang Denk   Some code cleanup
968
  	size = 0;
6e66bd559   Angus Ainslie   Enable xmodem sup...
969
  	info.mode = mode;
088f1b199   Kim Phillips   common/cmd_*.c: s...
970
  	res = xyzModem_stream_open(&info, &err);
f2841d377   Markus Klotzbuecher   Add support for y...
971
  	if (!res) {
f2841d377   Markus Klotzbuecher   Add support for y...
972

cf48eb9ab   Wolfgang Denk   Some code cleanup
973
  		while ((res =
088f1b199   Kim Phillips   common/cmd_*.c: s...
974
  			xyzModem_stream_read(ymodemBuf, 1024, &err)) > 0) {
cf48eb9ab   Wolfgang Denk   Some code cleanup
975
976
977
  			store_addr = addr + offset;
  			size += res;
  			addr += res;
e856bdcfb   Masahiro Yamada   flash: complete C...
978
  #ifdef CONFIG_MTD_NOR_FLASH
088f1b199   Kim Phillips   common/cmd_*.c: s...
979
  			if (addr2info(store_addr)) {
cf48eb9ab   Wolfgang Denk   Some code cleanup
980
  				int rc;
088f1b199   Kim Phillips   common/cmd_*.c: s...
981
  				rc = flash_write((char *) ymodemBuf,
cf48eb9ab   Wolfgang Denk   Some code cleanup
982
983
  						  store_addr, res);
  				if (rc != 0) {
0ee48252b   Simon Glass   common: Move flas...
984
  					flash_perror(rc);
cf48eb9ab   Wolfgang Denk   Some code cleanup
985
986
987
  					return (~0);
  				}
  			} else
f2841d377   Markus Klotzbuecher   Add support for y...
988
  #endif
cf48eb9ab   Wolfgang Denk   Some code cleanup
989
  			{
088f1b199   Kim Phillips   common/cmd_*.c: s...
990
  				memcpy((char *)(store_addr), ymodemBuf,
cf48eb9ab   Wolfgang Denk   Some code cleanup
991
992
993
994
995
  					res);
  			}
  
  		}
  	} else {
088f1b199   Kim Phillips   common/cmd_*.c: s...
996
997
  		printf("%s
  ", xyzModem_error(err));
f2841d377   Markus Klotzbuecher   Add support for y...
998
  	}
cf48eb9ab   Wolfgang Denk   Some code cleanup
999

088f1b199   Kim Phillips   common/cmd_*.c: s...
1000
1001
  	xyzModem_stream_close(&err);
  	xyzModem_stream_terminate(false, &getcxmodem);
f2841d377   Markus Klotzbuecher   Add support for y...
1002

0a6036da6   Chris Packham   cmd: load: align ...
1003
  	flush_cache(offset, ALIGN(size, ARCH_DMA_MINALIGN));
f2841d377   Markus Klotzbuecher   Add support for y...
1004

088f1b199   Kim Phillips   common/cmd_*.c: s...
1005
1006
  	printf("## Total Size      = 0x%08x = %d Bytes
  ", size, size);
018f53032   Simon Glass   env: Rename commo...
1007
  	env_set_hex("filesize", size);
f2841d377   Markus Klotzbuecher   Add support for y...
1008
1009
1010
  
  	return offset;
  }
902531788   Jon Loeliger   common/: Remove l...
1011
  #endif
8bde7f776   wdenk   * Code cleanup:
1012
1013
  
  /* -------------------------------------------------------------------- */
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
1014
  #if defined(CONFIG_CMD_LOADS)
8bde7f776   wdenk   * Code cleanup:
1015

6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1016
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
0d4983930   wdenk   Patch by Kenneth ...
1017
1018
  U_BOOT_CMD(
  	loads, 3, 0,	do_load_serial,
2fb2604d5   Peter Tyser   Command usage cle...
1019
  	"load S-Record file over serial line",
8bde7f776   wdenk   * Code cleanup:
1020
1021
1022
  	"[ off ] [ baud ]
  "
  	"    - load S-Record file over serial line"
a89c33db9   Wolfgang Denk   General help mess...
1023
  	" with offset 'off' and baudrate 'baud'"
8bde7f776   wdenk   * Code cleanup:
1024
  );
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1025
  #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
0d4983930   wdenk   Patch by Kenneth ...
1026
1027
  U_BOOT_CMD(
  	loads, 2, 0,	do_load_serial,
2fb2604d5   Peter Tyser   Command usage cle...
1028
  	"load S-Record file over serial line",
8bde7f776   wdenk   * Code cleanup:
1029
1030
  	"[ off ]
  "
a89c33db9   Wolfgang Denk   General help mess...
1031
  	"    - load S-Record file over serial line with offset 'off'"
8bde7f776   wdenk   * Code cleanup:
1032
  );
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1033
  #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
1034
1035
1036
1037
  
  /*
   * SAVES always requires LOADS support, but not vice versa
   */
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
1038
  #if defined(CONFIG_CMD_SAVES)
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1039
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
0d4983930   wdenk   Patch by Kenneth ...
1040
1041
  U_BOOT_CMD(
  	saves, 4, 0,	do_save_serial,
2fb2604d5   Peter Tyser   Command usage cle...
1042
  	"save S-Record file over serial line",
8bde7f776   wdenk   * Code cleanup:
1043
1044
1045
  	"[ off ] [size] [ baud ]
  "
  	"    - save S-Record file over serial line"
a89c33db9   Wolfgang Denk   General help mess...
1046
  	" with offset 'off', size 'size' and baudrate 'baud'"
8bde7f776   wdenk   * Code cleanup:
1047
  );
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1048
  #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
0d4983930   wdenk   Patch by Kenneth ...
1049
1050
  U_BOOT_CMD(
  	saves, 3, 0,	do_save_serial,
2fb2604d5   Peter Tyser   Command usage cle...
1051
  	"save S-Record file over serial line",
8bde7f776   wdenk   * Code cleanup:
1052
1053
  	"[ off ] [size]
  "
a89c33db9   Wolfgang Denk   General help mess...
1054
  	"    - save S-Record file over serial line with offset 'off' and size 'size'"
8bde7f776   wdenk   * Code cleanup:
1055
  );
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1056
  #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
70d7cb925   Robert P. J. Day   cmd_load.c: Add #...
1057
1058
  #endif	/* CONFIG_CMD_SAVES */
  #endif	/* CONFIG_CMD_LOADS */
8bde7f776   wdenk   * Code cleanup:
1059

c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
1060
  #if defined(CONFIG_CMD_LOADB)
0d4983930   wdenk   Patch by Kenneth ...
1061
1062
  U_BOOT_CMD(
  	loadb, 3, 0,	do_load_serial_bin,
2fb2604d5   Peter Tyser   Command usage cle...
1063
  	"load binary file over serial line (kermit mode)",
8bde7f776   wdenk   * Code cleanup:
1064
1065
1066
  	"[ off ] [ baud ]
  "
  	"    - load binary file over serial line"
6e66bd559   Angus Ainslie   Enable xmodem sup...
1067
1068
1069
1070
1071
1072
1073
1074
1075
  	" with offset 'off' and baudrate 'baud'"
  );
  
  U_BOOT_CMD(
  	loadx, 3, 0,	do_load_serial_bin,
  	"load binary file over serial line (xmodem mode)",
  	"[ off ] [ baud ]
  "
  	"    - load binary file over serial line"
a89c33db9   Wolfgang Denk   General help mess...
1076
  	" with offset 'off' and baudrate 'baud'"
8bde7f776   wdenk   * Code cleanup:
1077
  );
f2841d377   Markus Klotzbuecher   Add support for y...
1078
1079
  U_BOOT_CMD(
  	loady, 3, 0,	do_load_serial_bin,
2fb2604d5   Peter Tyser   Command usage cle...
1080
  	"load binary file over serial line (ymodem mode)",
f2841d377   Markus Klotzbuecher   Add support for y...
1081
1082
1083
  	"[ off ] [ baud ]
  "
  	"    - load binary file over serial line"
a89c33db9   Wolfgang Denk   General help mess...
1084
  	" with offset 'off' and baudrate 'baud'"
f2841d377   Markus Klotzbuecher   Add support for y...
1085
  );
70d7cb925   Robert P. J. Day   cmd_load.c: Add #...
1086
  #endif	/* CONFIG_CMD_LOADB */