added fwdump, basic data write implemented
[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
5  *
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <termios.h>
16
17 #define VERBOSE                 (1<<0)
18 #define FIRMWARE                (1<<1)
19
20 #define TXRX_TYPE_BAUD          0x01
21 #define TXRX_TYPE_SYNC          0x02
22 #define TXRX_TYPE_CMD           0x03
23 #define TXRX_TYPE_DATA          0x04
24
25 #define CMD_SUCCESS             "0\r\n"
26 #define INVALID_COMMAND         "1\r\n"
27 #define SRC_ADDR_ERROR          "2\r\n"
28 #define DST_ADDR_ERROR          "3\r\n"
29 #define SRC_ADDR_NOT_MAPPED     "4\r\n"
30 #define DST_ADDR_NOT_MAPPED     "5\r\n"
31 #define COUNT_ERROR             "6\r\n"
32 #define COMPARE_ERROR           "10\r\n"
33 #define BUSY                    "11\r\n"
34 #define PARAM_ERROR             "12\r\n"
35 #define ADDR_ERROR              "13\r\n"
36 #define ADDR_NOT_MAPPED         "14\r\n"
37 #define CMD_LOCKED              "15\r\n"
38 #define INVALID_CODE            "16\r\n"
39 #define INVALID_BAUD_RATE       "17\r\n"
40 #define INVALID_STOP_BIT        "18\r\n"
41
42 #define CRYSTFREQ               "10000"
43
44 #define BUFSIZE                 64
45
46 typedef unsigned char u8;
47
48 typedef struct s_lpc {
49         int sfd;                /* serial fd */
50         char sdev[128];         /* seriel device */
51         int fwfd;               /* fimrware fd */
52         char fwfile[128];       /* firmware file */
53         u8 info;                /* info/mode */
54         char freq[8];           /* frequency */
55         int partid;             /* part id */
56         u8 bcv[2];              /* boot code version */
57 } t_lpc;
58
59 void usage(void) {
60
61         printf("possible argv:\n");
62         printf("  -d <serial device>\n");
63         printf("  -f <firmware>\n");
64         printf("  -c <crystal freq>\n");
65         printf("  -v\n");
66
67 }
68
69 int open_serial_device(t_lpc *lpc) {
70
71         struct termios term;
72
73         //memset(&term,0,sizeof(struct termios));
74
75         /* open serial device */
76
77         lpc->sfd=open(lpc->sdev,O_RDWR);
78         if(lpc->sfd<0) {
79                 perror("tts open");
80                 return lpc->sfd;
81         }
82
83         /* configure the serial device */
84
85         tcgetattr(lpc->sfd,&term);
86
87         // input/output baudrate
88
89         cfsetispeed(&term,B9600);
90         cfsetospeed(&term,B9600);
91
92         // control options -> 8n1
93
94         term.c_cflag&=~PARENB;  // no parity
95         term.c_cflag&=~CSTOPB;  // only 1 stop bit
96         term.c_cflag&=~CSIZE;   // no bit mask for data bits
97         term.c_cflag|=CS8;      // 8 data bits
98
99         // line options -> raw input
100         
101         term.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
102
103         // input options -> disable flow control
104         
105         term.c_iflag&=~(IXON|IXOFF|IXANY);
106
107         // more control options -> timeout
108         
109         term.c_cc[VMIN]=0;
110         term.c_cc[VTIME]=10;    // 1 second timeout
111
112         tcsetattr(lpc->sfd,TCSANOW,&term);
113
114         return lpc->sfd;
115 }
116
117 int open_firmware(t_lpc *lpc) {
118
119         /* open firmware file */
120
121         lpc->fwfd=open(lpc->fwfile,O_RDONLY);
122
123         if(lpc->fwfd<0)
124                 perror("fw open");
125
126         return lpc->fwfd;
127 }
128
129 int txrx(t_lpc *lpc,u8 *buf,int len,u8 type) {
130
131         int ret,cnt;
132         int i;
133
134         /* write */
135
136         if(lpc->info&VERBOSE)
137                 printf("  >> ");
138         cnt=0;
139         while(len) {
140                 ret=write(lpc->sfd,buf+cnt,len);
141                 if(ret<0) {
142                         perror("txrx write");
143                         return ret;
144                 }
145                 if(lpc->info&VERBOSE)
146                         for(i=0;i<ret;i++)
147                                 printf("%c",
148                                        ((buf[cnt+i]>0x19)&(buf[cnt+i]<0x7f))?
149                                        buf[cnt+i]:'.');
150                 len-=ret;
151                 cnt+=ret;
152         }
153         if(lpc->info&VERBOSE)
154                 printf(" (%d)\n",cnt);
155
156         /* cut the echo if not of type auto baud */
157
158         if(type!=TXRX_TYPE_BAUD) {
159                 while(cnt) {
160                         ret=read(lpc->sfd,buf,cnt);
161                         if(ret<0) {
162                                 perror("txrx echo cut");
163                                 return ret;
164                         }
165                         cnt-=ret;
166                 }
167         }
168
169         /* return here if type is data */
170
171         if(type==TXRX_TYPE_DATA)
172                 return cnt;
173
174         /* read */
175
176         if(lpc->info&VERBOSE)
177                 printf("  << ");
178         ret=1;
179         cnt=0;
180         while(ret>0) {
181                 ret=read(lpc->sfd,buf+cnt,BUFSIZE-cnt);
182                 if(ret<0) {
183                         perror("txrx read");
184                         return ret;
185                 }
186                 if(ret+cnt>BUFSIZE) {
187                         printf("txrx read: too small buf size (%d)!\n",BUFSIZE);
188                         return -1;
189                 }
190                 if(lpc->info&VERBOSE)
191                         for(i=0;i<ret;i++)
192                                 printf("%c",
193                                        ((buf[cnt+i]>0x19)&(buf[cnt+i]<0x7f))?
194                                        buf[cnt+i]:'.');
195                 cnt+=ret;
196         }
197         if(lpc->info&VERBOSE)
198                 printf(" (%d)\n",cnt);
199         buf[cnt]='\0';
200
201         /* check/strip return code if type is data */
202
203         if(type==TXRX_TYPE_CMD) {
204                 ret=strlen(CMD_SUCCESS);
205                 if(!strncmp(buf,CMD_SUCCESS,ret)) {
206                         for(i=ret;i<cnt;i++)
207                                 buf[i-ret]=buf[i];
208                         buf[cnt]='\0';
209                 }
210                 else {
211                         printf("txrx bad return code!\n");
212                         return -1;
213                 }
214         }
215
216         return cnt;
217 }
218
219 int bl_init(t_lpc *lpc) {
220
221         u8 buf[BUFSIZE];
222         int len;
223
224         /* auto baud sequence */
225         buf[0]='?';
226         txrx(lpc,buf,1,TXRX_TYPE_BAUD);
227         if(strncmp(buf,"Synchronized\r\n",14)) {
228                 printf("auto baud detection failed\n");
229                 return -1;
230         }
231
232         /* tell bl that we are synchronized (it's allready in buf) */
233         txrx(lpc,buf,14,TXRX_TYPE_SYNC);
234         if(strncmp(buf,"OK\r\n",4)) {
235                 printf("sync failed\n");
236                 return -1;
237         }
238
239         /* tell bl the crystal frequency */
240         len=strlen(lpc->freq)+2;
241         strncpy(buf,lpc->freq,BUFSIZE);
242         buf[len-2]='\r';
243         buf[len-1]='\n';
244         txrx(lpc,buf,len,TXRX_TYPE_SYNC);
245         if(strncmp(buf,"OK\r\n",4)) {
246                 printf("freq set failed\n");
247                 return -1;
248         }
249
250         return 0;
251 }
252
253 int read_part_id(t_lpc *lpc) {
254
255         u8 buf[BUFSIZE];
256
257         memcpy(buf,"J\r\n",3);
258         txrx(lpc,buf,3,TXRX_TYPE_CMD);
259         lpc->partid=atoi(buf);
260
261         return lpc->partid;
262 }
263
264 int read_bcv(t_lpc *lpc) {
265
266         u8 buf[BUFSIZE];
267         char *ptr;
268
269         memcpy(buf,"K\r\n",3);
270         txrx(lpc,buf,3,TXRX_TYPE_CMD);
271         ptr=strtok(buf,"\r\n");
272         lpc->bcv[0]=strtol(ptr,NULL,16);
273         ptr=strtok(NULL,"\r\n");
274         lpc->bcv[1]=strtol(ptr,NULL,16);
275
276         return 0;
277 }
278
279 int uuencode(u8 *in,u8 *out) {
280
281         out[0]=0x20+((in[0]>>2)&0x3f);
282         out[1]=0x20+(((in[0]<<4)|(in[1]>>4))&0x3f);
283         out[2]=0x20+(((in[1]<<2)|(in[2]>>6))&0x3f);
284         out[3]=0x20+(in[2]&0x3f);
285
286         return 0;
287 }
288
289 int write_to_ram(t_lpc *lpc,u8 *buf,int addr,int len) {
290
291         int lcount;
292         u8 checksum;
293         u8 txrxbuf[BUFSIZE];
294         int count,bcnt;
295         int nlen,slen;
296         int i;
297
298         /* check length */
299         if(len%4) {
300                 printf("ram write: not a multiple of 4\n");
301                 return -1;
302         }
303
304         /* make it a multiple of 3 (reason: uuencode) */
305         nlen=(len/3+1)*3;
306         if(nlen>BUFSIZE) {
307                 printf("ram write: too much data\n");
308                 return -1;
309         }
310         for(i=len;i<nlen;i++) buf[i]=0;
311
312         /* prepare write command */
313         snprintf(txrxbuf,BUFSIZE,"W %d %d",addr,len);
314         slen=strlen(txrxbuf);
315         txrxbuf[slen]='\r';
316         txrxbuf[slen+1]='\0';
317         slen+=2;
318
319         /* send command and check return code */
320         txrx(lpc,txrxbuf,slen,TXRX_TYPE_CMD);
321         if(strncmp(txrxbuf,"OK\r\n",4)) {
322                 printf("ram write: write command failed\n");
323                 return -1;
324         }
325
326         /* send data */
327         lcount=0;
328         bcnt=0;
329         count=0;
330         checksum=0;
331         while(bcnt<nlen) {
332
333                 /* uuencode / prepare data bytes */
334                 uuencode(buf+bcnt,txrxbuf);
335                 txrxbuf[4]='\0';
336                 txrxbuf[5]='\0';
337
338                 /* checksum */
339                 checksum+=(buf[0]+buf[1]+buf[2]);
340
341                 /* send a data line */
342                 txrx(lpc,txrxbuf,6,TXRX_TYPE_DATA);
343
344                 /* increase counters */
345                 lcount+=1;
346                 bcnt+=3;
347                 count+=3;
348
349                 /* checksum */
350                 if(!(lcount%20)) {
351                         /* send checksum */
352                         txrxbuf[0]=checksum;
353                         txrx(lpc,txrxbuf,1,TXRX_TYPE_CMD);
354                         if(!strncmp(txrxbuf,"RESEND\r\n",8)) {
355                                 printf("ram write: resending ...\n");
356                                 bcnt-=count;
357                         }
358                         if(strncmp(txrxbuf,"OK\r\n",4)) {
359                                 printf("ram write: bad response\n");
360                                 return -1;
361                         }
362                         /* reset checksum & counter */
363                         checksum=0;
364                         count=0;
365                 }
366
367         }
368
369         return 0;
370 }
371
372 int firmware_to_ram(t_lpc *lpc) {
373
374
375
376         return 0;
377 }
378
379 int main(int argc,char **argv) {
380
381         t_lpc lpc;
382         int i;
383
384         /*
385          * initial ... 
386          */
387
388         memset(&lpc,0,sizeof(t_lpc));
389         strncpy(lpc.freq,CRYSTFREQ,7);
390
391         /* parse argv */
392
393         for(i=1;i<argc;i++) {
394
395                 if(argv[i][0]!='-') {
396                         usage();
397                         return -1;
398                 }
399
400                 switch(argv[i][1]) {
401                         case 'd':
402                                 strncpy(lpc.sdev,argv[++i],127);
403                                 break;
404                         case 'f':
405                                 strncpy(lpc.fwfile,argv[++i],127);
406                                 lpc.info|=FIRMWARE;
407                                 break;
408                         case 'v':
409                                 lpc.info|=VERBOSE;
410                                 break;
411                         case 'c':
412                                 strncpy(lpc.freq,argv[++i],7);
413                                 break;
414                         default:
415                                 usage();
416                                 return -1;
417                 }
418
419         }
420
421         /* open serial port */
422         if(open_serial_device(&lpc)<0)
423                 goto end;
424
425         /* boot loader init */
426         printf("boot loader init ...\n");
427         bl_init(&lpc);
428
429         /* read part id */
430         read_part_id(&lpc);
431         printf("part id: %d\n",lpc.partid);
432
433         /* read boot code version */
434         read_bcv(&lpc);
435         printf("boot code version: %02x %02x\n",lpc.bcv[0],lpc.bcv[1]);
436
437         // to be continued ... (parsing fw file and poking it to ram)
438         if(open_firmware(&lpc)<0)
439                 goto end;
440         firmware_to_ram(&lpc);
441
442 end:
443         close(lpc.sfd);
444         close(lpc.fwfd);
445
446         return 0;
447 }
448