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