lpcload, added support for writing data to flash (untested!)
[my-code/arm.git] / betty / lpcload.c
1 /*
2  * lpcload.c - load firmware into ram of lpc2220 via uart0
3  *
4  * author: hackbard@hackdaworld.org, rolf.anders@physik.uni-augsburg.de
5  *
6  * build: make
7  * usage: sudo ./lpcload -d /dev/ttyS0 -f firmware.hex -D0 fw0.bin [-v]
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <termios.h>
18
19 #define VERBOSE                 (1<<0)
20 #define FIRMWARE                (1<<1)
21 #define BANK0                   (1<<2)
22 #define BANK2                   (1<<3)
23 #define BL                      (1<<4)
24 #define FLASHFW                 (1<<5)
25
26 #define BANK0_ADDR              0x80000000
27 #define BANK2_ADDR              0x82000000
28 #define BANK_SIZE               0x00100000
29 #define BL_ADDR                 0x7fffe000
30 #define BL_SIZE                 0x00002000
31
32 #define CMD_READ                'R'             // stay compatible to fwflash!
33 #define CMD_WRITE               'W'
34 #define CMD_CHIP_ERASE          'E'
35
36 #define TXRX_TYPE_SYNC          0x00
37 #define TXRX_TYPE_CKSM          0x00
38 #define TXRX_TYPE_BAUD          0x01
39 #define TXRX_TYPE_CMD           0x02
40 #define TXRX_TYPE_DATA          0x03
41 #define TXRX_TYPE_GO            0x04
42
43 #define CMD_SUCCESS             "0\r\n"
44 #define INVALID_COMMAND         "1\r\n"
45 #define SRC_ADDR_ERROR          "2\r\n"
46 #define DST_ADDR_ERROR          "3\r\n"
47 #define SRC_ADDR_NOT_MAPPED     "4\r\n"
48 #define DST_ADDR_NOT_MAPPED     "5\r\n"
49 #define COUNT_ERROR             "6\r\n"
50 #define COMPARE_ERROR           "10\r\n"
51 #define BUSY                    "11\r\n"
52 #define PARAM_ERROR             "12\r\n"
53 #define ADDR_ERROR              "13\r\n"
54 #define ADDR_NOT_MAPPED         "14\r\n"
55 #define CMD_LOCKED              "15\r\n"
56 #define INVALID_CODE            "16\r\n"
57 #define INVALID_BAUD_RATE       "17\r\n"
58 #define INVALID_STOP_BIT        "18\r\n"
59
60 #define RAM                     0x01
61 #define FLASH                   0x02
62
63 #define CRYSTFREQ               "10000"
64 #define RAMOFFSET               0x40000200
65
66 #define BUFSIZE                 128
67
68 typedef unsigned char u8;
69 typedef unsigned short u16;
70 typedef unsigned int u32;
71
72 typedef struct s_lpc {
73         int sfd;                /* serial fd */
74         char sdev[128];         /* seriel device */
75         int fwfd;               /* fimrware fd */
76         char fwfile[128];       /* firmware file */
77         u32 info;               /* info/mode */
78         char freq[8];           /* frequency */
79         char bank0[127];        /* flash dump bank0 */
80         int b0fd;               /* dumpfile fd bank0 */
81         char bank2[127];        /* flash dump bank2 */
82         int b2fd;               /* dumpfile fd bank0 */
83         char bl[127];           /* flash dump bootloader */
84         int blfd;               /* dumpfile fd bootloader */
85         char ffwfile[127];      /* file with firmware to be flashed */
86         int ffwfd;              /* fd of the above */
87         u32 roff;               /* ram offset of uc */
88         u32 jaddr;              /* addr for the jump */
89 } t_lpc;
90
91 void usage(void) {
92
93         printf("possible argv:\n");
94         printf("  -d  <serial device>\n");
95         printf("  -f  <firmware>\n");
96         printf("  -c  <crystal freq>\n");
97         printf("  -Dx <filename>\n");
98         printf("      x=0: bank0, x=2: bank2, x=b: bootloader\n");
99         printf("  -w <firmware which goes to flash>\n");
100         printf("  -v\n");
101
102 }
103
104 int open_serial_device(t_lpc *lpc) {
105
106         struct termios term;
107
108         //memset(&term,0,sizeof(struct termios));
109
110         /* open serial device */
111
112         lpc->sfd=open(lpc->sdev,O_RDWR);
113         if(lpc->sfd<0) {
114                 perror("tts open");
115                 return lpc->sfd;
116         }
117
118         /* configure the serial device */
119
120         tcgetattr(lpc->sfd,&term);
121
122         // input/output baudrate
123
124         cfsetispeed(&term,B38400);
125         cfsetospeed(&term,B38400);
126
127         // control options -> 8n1
128
129         term.c_cflag&=~PARENB;  // no parity
130         term.c_cflag&=~CSTOPB;  // only 1 stop bit
131         term.c_cflag&=~CSIZE;   // no bit mask for data bits
132         term.c_cflag|=CS8;      // 8 data bits
133
134         // line options -> raw input
135         
136         term.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
137
138         // input options -> enable flow control
139         
140         term.c_iflag&=~(INLCR|ICRNL|IXANY);
141         term.c_iflag|=(IXON|IXOFF);
142         
143         // output options
144
145         term.c_oflag=0;
146
147         // more control options -> timeout / flow control
148         
149         term.c_cc[VMIN]=0;
150         term.c_cc[VTIME]=20;    // 2 seconds timeout
151         //term.c_cc[VSTART]=0x11;
152         //term.c_cc[VSTOP]=0x13;
153
154         tcsetattr(lpc->sfd,TCSANOW,&term);
155
156         return lpc->sfd;
157 }
158
159 int reconfig_serial_device(t_lpc *lpc) {
160
161         struct termios term;
162         int ret;
163
164         /* reconfigure the serial device for our lousy loader tool */
165
166         tcgetattr(lpc->sfd,&term);
167
168         // disable flow control
169         
170         term.c_iflag&=~(IXON|IXOFF|IXANY|INLCR|ICRNL);
171
172         // change baudrate
173
174         cfsetispeed(&term,B115200);
175         cfsetospeed(&term,B115200);
176
177         ret=tcsetattr(lpc->sfd,TCSANOW,&term);
178
179         return ret;
180 }
181
182 int open_firmware(t_lpc *lpc) {
183
184         /* open firmware file */
185
186         lpc->fwfd=open(lpc->fwfile,O_RDONLY);
187
188         if(lpc->fwfd<0) {
189                 perror("fw open");
190                 return lpc->fwfd;
191         }
192
193         if(lpc->info&FLASHFW) {
194                 lpc->ffwfd=open(lpc->ffwfile,O_RDONLY);
195                 if(lpc->ffwfd<0) {
196                         perror("ffw open");
197                         return lpc->ffwfd;
198                 }
199         }
200
201         return lpc->fwfd;
202 }
203
204 int open_dumpfiles(t_lpc *lpc) {
205
206         /* open dumpfiles */
207
208         if(lpc->info&BANK0) {
209                 lpc->b0fd=open(lpc->bank0,O_WRONLY|O_CREAT);
210                 if(lpc->b0fd<0) {
211                         perror("bank0 dump file open");
212                         return lpc->b0fd;
213                 }
214         }
215
216         if(lpc->info&BANK2) {
217                 lpc->b2fd=open(lpc->bank2,O_WRONLY|O_CREAT);
218                 if(lpc->b2fd<0) {
219                         perror("bank2 dump file open");
220                         return lpc->b2fd;
221                 }
222         }
223
224         if(lpc->info&BL) {
225                 lpc->blfd=open(lpc->bl,O_WRONLY|O_CREAT);
226                 if(lpc->blfd<0) {
227                         perror("bootloader dump file open");
228                         return lpc->blfd;
229                 }
230         }
231
232         return 0;
233
234 }
235 int txrx(t_lpc *lpc,char *buf,int len,u8 type) {
236
237         int ret,cnt;
238         int i;
239
240         /* write */
241
242         if(lpc->info&VERBOSE)
243                 printf("  >> ");
244         cnt=0;
245         while(len) {
246                 ret=write(lpc->sfd,buf+cnt,len);
247                 if(ret<0) {
248                         perror("txrx write");
249                         return ret;
250                 }
251                 if(lpc->info&VERBOSE)
252                         for(i=0;i<ret;i++)
253                                 printf("%c",
254                                        ((buf[cnt+i]>0x19)&(buf[cnt+i]<0x7f))?
255                                        buf[cnt+i]:'.');
256                 len-=ret;
257                 cnt+=ret;
258         }
259         if(lpc->info&VERBOSE) {
260                 printf(" | ");
261                 for(i=0;i<cnt;i++)
262                         printf("%02x ",buf[i]);
263                 printf("| (%d)\n",cnt);
264         }
265
266
267
268         /* cut the echo if not of type auto baud */
269
270         if(type!=TXRX_TYPE_BAUD) {
271                 while(cnt) {
272                         ret=read(lpc->sfd,buf,cnt);
273                         if(ret<0) {
274                                 perror("txrx echo cut");
275                                 return ret;
276                         }
277                         cnt-=ret;
278                 }
279         }
280
281         /* return if type is go */
282
283         if(type==TXRX_TYPE_GO)
284                 return cnt;
285
286         /* return here if type is data */
287
288         if(type==TXRX_TYPE_DATA)
289                 return cnt;
290
291         /* read */
292
293         ret=read(lpc->sfd,buf,1);
294         if(ret<0) {
295                 perror("txrx read (first byte)");
296                 return ret;
297         }
298                 
299         switch(buf[0]) {
300                 case 'S':
301                         cnt=13;
302                         break;
303                 case 'O':
304                         cnt=3;
305                         break;
306                 case 'R':
307                         cnt=7;
308                         break;
309                 case '0':
310                         cnt=2;
311                         break;
312                 default:
313                         printf("txrx read: bad return byte '%02x'\n",buf[0]);
314                         break;
315         }
316
317         ret=1;
318         i=cnt;
319         while(i) {
320                 ret=read(lpc->sfd,buf+1+cnt-i,i);
321                 if(ret<0) {
322                         perror("txrx read (next bytes)");
323                         return ret;
324                 }
325                 i-=ret;
326         }
327         if(lpc->info&VERBOSE) {
328                 printf("  << ");
329                 for(i=0;i<cnt+1;i++)
330                         printf("%c",((buf[i]>0x19)&(buf[i]<0x7f))?
331                                     buf[i]:'.');
332                 printf(" | ");
333                 for(i=0;i<cnt+1;i++)
334                         printf("%02x ",buf[i]);
335                 printf("| (%d)\n",cnt+1);
336         }
337         buf[cnt+1]='\0';
338
339         /* check/strip return code if type is cmd */
340
341         if(type==TXRX_TYPE_CMD) {
342                 ret=strlen(CMD_SUCCESS);
343                 if(!strncmp(buf,CMD_SUCCESS,ret)) {
344                         for(i=ret;i<cnt;i++)
345                                 buf[i-ret]=buf[i];
346                         buf[cnt]='\0';
347                 }
348                 else {
349                         printf("txrx bad return code!\n");
350                         return -1;
351                 }
352         }
353
354         return cnt;
355 }
356
357 int bl_init(t_lpc *lpc) {
358
359         char buf[BUFSIZE];
360         int len;
361
362         /* auto baud sequence */
363         buf[0]='?';
364         txrx(lpc,buf,1,TXRX_TYPE_BAUD);
365         if(strncmp(buf,"Synchronized\r\n",14)) {
366                 printf("auto baud detection failed\n");
367                 return -1;
368         }
369
370         /* tell bl that we are synchronized (it's allready in buf) */
371         txrx(lpc,buf,14,TXRX_TYPE_SYNC);
372         if(strncmp(buf,"OK\r\n",4)) {
373                 printf("sync failed\n");
374                 return -1;
375         }
376
377         /* tell bl the crystal frequency */
378         len=strlen(lpc->freq)+2;
379         strncpy(buf,lpc->freq,BUFSIZE);
380         buf[len-2]='\r';
381         buf[len-1]='\n';
382         txrx(lpc,buf,len,TXRX_TYPE_SYNC);
383         if(strncmp(buf,"OK\r\n",4)) {
384                 printf("freq set failed\n");
385                 return -1;
386         }
387
388         return 0;
389 }
390
391 int unlock_go(t_lpc *lpc) {
392
393         char buf[BUFSIZE];
394         int ret;
395
396         memcpy(buf,"U 23130\r\n",9);
397         ret=txrx(lpc,buf,9,TXRX_TYPE_CMD);
398
399         return ret;
400 }
401
402 int go(t_lpc *lpc) {
403
404         char buf[BUFSIZE];
405         int ret,len;
406
407         snprintf(buf,BUFSIZE,"G %d A\r\n",lpc->jaddr);
408         len=strlen(buf);
409         ret=txrx(lpc,buf,len,TXRX_TYPE_GO);
410
411         return ret;
412 }
413
414 int uuencode(u8 *in,u8 *out,int len) {
415
416         out[0]=0x20+len;
417         out[1]=0x20+((in[0]>>2)&0x3f);
418         out[2]=0x20+(((in[0]<<4)|(in[1]>>4))&0x3f);
419         out[3]=0x20+(((in[1]<<2)|(in[2]>>6))&0x3f);
420         out[4]=0x20+(in[2]&0x3f);
421
422         return 0;
423 }
424
425 int write_to_ram(t_lpc *lpc,char *buf,u32 addr,int len) {
426
427         int lcount;
428         u32 checksum;
429         char txrxbuf[BUFSIZE];
430         int count,bcnt;
431         int nlen,slen;
432         int i;
433
434         /* check length */
435         if(len%4) {
436                 printf("ram write: not a multiple of 4\n");
437                 return -1;
438         }
439
440         /* make it a multiple of 3 (reason: uuencode) */
441         nlen=(!(len%3))?len:((len/3+1)*3);
442         if(nlen>BUFSIZE) {
443                 printf("ram write: too much data\n");
444                 return -1;
445         }
446         for(i=len;i<nlen;i++) buf[i]=0;
447
448         /* prepare addr */
449         addr+=lpc->roff;
450
451         /* prepare write command */
452         if(lpc->info&VERBOSE)
453                 printf("writing 0x%02x bytes to 0x%08x\n",len,addr);
454         snprintf(txrxbuf,BUFSIZE,"W %d %d\r\n",addr,len);
455         slen=strlen(txrxbuf);
456
457         /* send command and check return code */
458         txrx(lpc,txrxbuf,slen,TXRX_TYPE_CMD);
459
460         /* send data */
461         lcount=0;
462         bcnt=0;
463         count=0;
464         checksum=0;
465         while(bcnt<nlen) {
466
467                 /* uuencode / prepare data bytes */
468                 uuencode((u8 *)(buf+bcnt),(u8 *)(txrxbuf),
469                          (bcnt==nlen-3)?(len%3?len%3:3):3);
470                 txrxbuf[5]='\r';
471                 txrxbuf[6]='\n';
472
473                 /* checksum */
474                 checksum+=((u8)buf[bcnt]+(u8)buf[bcnt+1]+(u8)buf[bcnt+2]);
475
476                 /* send a data line */
477                 txrx(lpc,txrxbuf,7,TXRX_TYPE_DATA);
478
479                 /* increase counters */
480                 lcount+=1;
481                 bcnt+=3;
482                 count+=3;
483
484                 /* checksum */
485                 if((!(lcount%20))|(bcnt==nlen)) {
486                         /* send backtick */
487                         memcpy(txrxbuf,"`\r\n",3);
488                         //txrx(lpc,txrxbuf,3,TXRX_TYPE_DATA);
489                         /* send checksum */
490                         snprintf(txrxbuf,BUFSIZE,"%d\r\n",checksum);
491                         slen=strlen(txrxbuf);
492                         txrx(lpc,txrxbuf,slen,TXRX_TYPE_CKSM);
493                         if(!strncmp(txrxbuf,"RESE",4)) {
494                                 read(lpc->sfd,txrxbuf+4,4);
495                                 printf("ram write: resending ...\n");
496                                 bcnt-=count;
497                         }
498                         if(strncmp(txrxbuf,"OK\r\n",4)) {
499                                 printf("ram write: bad response\n");
500                                 return -1;
501                         }
502                         /* reset checksum & counter */
503                         checksum=0;
504                         count=0;
505                 }
506
507         }
508
509         return 0;
510 }
511
512 int send_cmd(int sfd,u32 addr,u32 len,u8 cmd) {
513
514         int ret,i,cnt,size;
515         int as,ls;
516         u8 send[9];
517
518         switch(cmd) {
519                 case CMD_READ:
520                 case CMD_WRITE:
521                         as=4;
522                         ls=4;
523                         break;
524                 case CMD_CHIP_ERASE:
525                         as=0;
526                         ls=1;
527                         break;
528                 default:
529                         printf("send cmd: cmd '%02x' not supported\n",cmd);
530                         return -1;
531         }
532
533         size=1+as+ls;
534         send[0]=cmd;
535
536         for(i=0;i<as;i++)
537                 send[1+i]=(addr>>((as-1-i)*8))&0xff;
538         for(i=0;i<ls;i++)
539                 send[1+i+as]=(len>>((ls-1-i)*8))&0xff;
540
541         cnt=0;
542         printf("  sending cmd: ");
543         while(size) {
544                 ret=write(sfd,send+cnt,size);
545                 if(ret<0) {
546                         perror("dump file: send cmd ");
547                         return ret;
548                 }
549                 for(i=cnt;i<cnt+ret;i++)
550                         printf("%02x ",send[i]);
551                 size-=ret;
552                 cnt+=ret;
553         }
554         printf("\n");
555
556         return 0;
557 }
558
559 int write_to_flash(t_lpc *lpc,char *buf,u32 addr,int len) {
560
561         int cnt,size,ret;
562
563         /* send cmd */
564         send_cmd(lpc->sfd,addr,len,CMD_WRITE);
565
566         /* transfer data */
567         while(len) {
568                 size=2;
569                 while(size) {
570                         ret=write(lpc->sfd,buf+cnt,2);
571                         if(ret<0) {
572                                 perror("transmit flash content");
573                                 return ret;
574                         }
575                         size-=ret;
576                 }
577                 cnt+=2;
578         }
579
580         return 0;
581 }
582
583 int firmware_to_mem(t_lpc *lpc,u8 memtype) {
584
585         char buf[BUFSIZE];
586         u32 addr,len,type;
587         int ret,temp;
588         int fd;
589
590         /* prepare for memory type */
591         if(memtype==RAM)
592                 fd=lpc->fwfd;
593         else if(memtype==FLASH)
594                 fd=lpc->ffwfd;
595         else
596                 return -1;
597
598         /* read a line */
599         ret=1;
600         while(ret) {
601                 /* sync line */
602                 ret=read(fd,buf,1);
603                 switch(buf[0]) {
604                         case '\r':
605                                 continue;
606                         case '\n':
607                                 continue;
608                         case ':':
609                                 /* start code */
610                                 break;
611                         default:
612                                 printf("fw to mem: no ihex format\n");
613                                 return -1;
614                 }
615                 /* read len */
616                 ret=read(fd,buf,2);
617                 sscanf(buf,"%02x",&len);
618                 /* read addr */
619                 ret=read(fd,buf,4);
620                 sscanf(buf,"%04x",&addr);
621                 /* read type */
622                 ret=read(fd,buf,2);
623                 sscanf(buf,"%02x",&type);
624                 /* successfull return if type is end of file */
625                 if(type==0x01)
626                         return 0;
627                 /* read data (and cksum) */
628                 ret=read(fd,buf,2*(len+1));
629                 if(ret!=(2*(len+1))) {
630                         printf("fw to mem: data missing\n");
631                                 return -1;
632                 }
633                 for(ret=0;ret<len;ret++) {
634                         sscanf(buf+2*ret,"%02x",&temp);
635                         buf[ret]=temp;
636                 }
637                 /* act according to type */
638                 switch(type) {
639                         //case 0x03:
640                         //      /* get cs and ip */
641                         //      break;
642                         case 0x00:
643                                 if(len%4) {
644                                         printf("fw to mem: invalid len\n");
645                                         return -1;
646                                 }
647                                 if(memtype==RAM)
648                                         write_to_ram(lpc,buf,addr,len);
649                                 else
650                                         write_to_flash(lpc,buf,addr,len);
651                                 break;
652                         case 0x04:
653                                 lpc->roff=((buf[0]<<24)|(buf[1]<<16));
654                                 break;
655                         case 0x05:
656                                 lpc->jaddr=((buf[0]<<24)|(buf[1]<<16));
657                                 lpc->jaddr|=((buf[2]<<8)|buf[3]);
658                                 break;
659                         default:
660                                 printf("fw to mem: unknown type %02x\n",type);
661                                 return -1;
662                 }
663         }
664
665         return 0;
666 }
667
668 int lpc_txbuf_flush(t_lpc *lpc) {
669
670         int i,ret;
671         u8 buf[16];
672
673         ret=1;
674         printf("flushing lpc tx buffer: ");
675         while(ret) {
676                 ret=read(lpc->sfd,buf,16);
677                 for(i=0;i<ret;i++)
678                         printf("%02x ",buf[i]);
679         }
680         printf("\n");
681
682         return 0;
683 }
684
685 int dump_files(int sfd,int dfd,u32 addr,u32 len) {
686
687         int ret;
688         int size;
689         int cnt;
690         u8 buf[16];
691
692         printf("dumping content (addr=0x%08x, len=0x%08x) ...\n",addr,len);
693
694         /* send the cmd */
695         send_cmd(sfd,addr,len,CMD_READ);
696
697         /* receive data and dump it to file */
698         ret=1;
699         cnt=0;
700         printf("  receiving data ...\n");
701         while(ret) {
702                 ret=read(sfd,buf,16);
703                 if(ret<0) {
704                         perror("dump file: read data");
705                         return ret;
706                 }
707                 size=ret;
708                 cnt=0;
709                 while(size) {
710                         ret=write(dfd,buf+cnt,size-cnt);
711                         if(ret<0) {
712                                 perror("dump file: write data");
713                                 return ret;
714                         }
715                         cnt+=ret;
716                         size-=ret;
717                 }
718         }
719
720         return 0;
721 }
722
723 int main(int argc,char **argv) {
724
725         t_lpc lpc;
726         int i;
727         int ret;
728
729         /*
730          * initial ... 
731          */
732
733         memset(&lpc,0,sizeof(t_lpc));
734         strncpy(lpc.freq,CRYSTFREQ,7);
735         lpc.roff=RAMOFFSET;
736         lpc.jaddr=RAMOFFSET;
737
738         /* parse argv */
739
740         for(i=1;i<argc;i++) {
741
742                 if(argv[i][0]!='-') {
743                         usage();
744                         return -1;
745                 }
746
747                 switch(argv[i][1]) {
748                         case 'd':
749                                 strncpy(lpc.sdev,argv[++i],127);
750                                 break;
751                         case 'f':
752                                 strncpy(lpc.fwfile,argv[++i],127);
753                                 lpc.info|=FIRMWARE;
754                                 break;
755                         case 'v':
756                                 lpc.info|=VERBOSE;
757                                 break;
758                         case 'c':
759                                 strncpy(lpc.freq,argv[++i],7);
760                                 break;
761                         case 'D':
762                                 if(argv[i][2]=='0') {
763                                         lpc.info|=BANK0;
764                                         strncpy(lpc.bank0,argv[++i],127);
765                                         break;
766                                 }
767                                 else if(argv[i][2]=='2') {
768                                         lpc.info|=BANK2;
769                                         strncpy(lpc.bank2,argv[++i],127);
770                                         break;
771                                 }
772                                 else if(argv[i][2]=='b') {
773                                         lpc.info|=BL;
774                                         strncpy(lpc.bl,argv[++i],127);
775                                         break;
776                                 }
777                                 else {
778                                         usage();
779                                         return -1;
780                                 }
781                         case 'w':
782                                 strncpy(lpc.ffwfile,argv[++i],127);
783                                 lpc.info|=FLASHFW;
784                                 break;
785                         default:
786                                 usage();
787                                 return -1;
788                 }
789
790         }
791
792         /* open serial port */
793         if(open_serial_device(&lpc)<0)
794                 goto end;
795
796         /* boot loader init */
797         printf("boot loader init ...\n");
798         if(bl_init(&lpc)<0)
799                 return -1;
800
801         /* quit if there is no hex file to process */
802         if(!(lpc.info&FIRMWARE)) {
803                 printf("no firmware -> aborting\n");
804                 goto end;
805         }
806
807         /* open firmware file */
808         if(open_firmware(&lpc)<0)
809                 goto end;
810
811         /* open dump files */
812         if(open_dumpfiles(&lpc)<0)
813                 goto end;
814
815         /* parse intel hex file and write to ram */
816         printf("write firmware to ram ...\n");
817         firmware_to_mem(&lpc,RAM);
818
819         /* unlock go cmd */
820         printf("unlock go command ...\n");
821         unlock_go(&lpc);
822
823         /* go! */
824         printf("go ...\n");
825         ret=go(&lpc);
826
827         /* flush the lpc2220 tx buf */
828         lpc_txbuf_flush(&lpc);
829
830         /* reconfigure the serial port */
831         if(reconfig_serial_device(&lpc)<0)
832                 goto end;
833
834         /* download flash/bootloader content */
835         if(lpc.info&BANK0)
836                 dump_files(lpc.sfd,lpc.b0fd,BANK0_ADDR,BANK_SIZE);
837         if(lpc.info&BANK2)
838                 dump_files(lpc.sfd,lpc.b2fd,BANK2_ADDR,BANK_SIZE);
839         if(lpc.info&BL)
840                 dump_files(lpc.sfd,lpc.blfd,BL_ADDR,BL_SIZE);
841
842         /* write a firmware to the lpc flash */
843         if(lpc.info&FLASHFW) {
844                 send_cmd(lpc.sfd,0,0,CMD_CHIP_ERASE);
845                 lpc.roff=BANK0_ADDR;
846                 firmware_to_mem(&lpc,FLASH);
847         }
848
849 end:
850         if(lpc.sfd)
851                 close(lpc.sfd);
852         if(lpc.fwfd)
853                 close(lpc.fwfd);
854         if(lpc.b0fd)
855                 close(lpc.b0fd);
856         if(lpc.b2fd)
857                 close(lpc.b2fd);
858         if(lpc.blfd)
859                 close(lpc.blfd);
860         if(lpc.ffwfd)
861                 close(lpc.ffwfd);
862
863         return 0;
864 }
865