still some bugs, though by setting pll mult -> br of 115200
[my-code/arm.git] / betty / lpcload.c
index 0d2f9c8..19d5a5b 100644 (file)
 
 #define VERBOSE                        (1<<0)
 #define FIRMWARE               (1<<1)
+#define BANK0                  (1<<2)
+#define BANK2                  (1<<3)
+#define BL                     (1<<4)
 
+#define BANK0_ADDR             0x80000000
+#define BANK2_ADDR             0x82000000
+#define BANK_SIZE              0x00100000
+#define BL_ADDR                        0x7fffe000
+#define BL_SIZE                        0x00002000
+
+#define CMD_READ               'R'             // stay compatible to fwflash!
+
+#define TXRX_TYPE_SYNC         0x00
+#define TXRX_TYPE_CKSM         0x00
 #define TXRX_TYPE_BAUD         0x01
-#define TXRX_TYPE_SYNC         0x02
-#define TXRX_TYPE_CMD          0x03
-#define TXRX_TYPE_DATA         0x04
-#define TXRX_TYPE_CKSM         0x05
+#define TXRX_TYPE_CMD          0x02
+#define TXRX_TYPE_DATA         0x03
+#define TXRX_TYPE_GO           0x04
 
 #define CMD_SUCCESS            "0\r\n"
 #define INVALID_COMMAND                "1\r\n"
@@ -58,17 +70,24 @@ typedef struct s_lpc {
        char fwfile[128];       /* firmware file */
        u8 info;                /* info/mode */
        char freq[8];           /* frequency */
-       u32 hoff;               /* start addr of ihex file */
+       char bank0[127];        /* flash dump bank0 */
+       int b0fd;               /* dumpfile fd bank0 */
+       char bank2[127];        /* flash dump bank2 */
+       int b2fd;               /* dumpfile fd bank0 */
+       char bl[127];           /* flash dump bootloader */
+       int blfd;               /* dumpfile fd bootloader */
        u32 roff;               /* ram offset of uc */
+       u32 jaddr;              /* addr for the jump */
 } t_lpc;
 
 void usage(void) {
 
        printf("possible argv:\n");
-       printf("  -d <serial device>\n");
-       printf("  -f <firmware>\n");
-       printf("  -c <crystal freq>\n");
-       printf("  -r <ram offset>\n");
+       printf("  -d  <serial device>\n");
+       printf("  -f  <firmware>\n");
+       printf("  -c  <crystal freq>\n");
+       printf("  -Dx <filename>\n");
+       printf("      x=0: bank0, x=2: bank2, x=b: bootloader\n");
        printf("  -v\n");
 
 }
@@ -93,8 +112,8 @@ int open_serial_device(t_lpc *lpc) {
 
        // input/output baudrate
 
-       cfsetispeed(&term,B9600);
-       cfsetospeed(&term,B9600);
+       cfsetispeed(&term,B38400);
+       cfsetospeed(&term,B38400);
 
        // control options -> 8n1
 
@@ -109,26 +128,49 @@ int open_serial_device(t_lpc *lpc) {
 
        // input options -> enable flow control
        
-       //term.c_iflag&=~(IXON|IXOFF|IXANY|INLCR|ICRNL);
        term.c_iflag&=~(INLCR|ICRNL|IXANY);
        term.c_iflag|=(IXON|IXOFF);
+       
+       // output options
+
+       term.c_oflag=0;
 
        // more control options -> timeout / flow control
        
        term.c_cc[VMIN]=0;
-       term.c_cc[VTIME]=10;    // 1 second timeout
-       term.c_cc[VSTART]=0x11;
-       term.c_cc[VSTOP]=0x13;
+       term.c_cc[VTIME]=20;    // 2 seconds timeout
+       //term.c_cc[VSTART]=0x11;
+       //term.c_cc[VSTOP]=0x13;
 
        tcsetattr(lpc->sfd,TCSANOW,&term);
 
        return lpc->sfd;
 }
 
-int open_firmware(t_lpc *lpc) {
+int reconfig_serial_device(t_lpc *lpc) {
 
+       struct termios term;
        int ret;
-       char buf[BUFSIZE];
+
+       /* reconfigure the serial device for our lousy loader tool */
+
+       tcgetattr(lpc->sfd,&term);
+
+       // disable flow control
+       
+       term.c_iflag&=~(IXON|IXOFF|IXANY|INLCR|ICRNL);
+
+       // change baudrate
+
+       cfsetispeed(&term,B115200);
+       cfsetospeed(&term,B115200);
+
+       ret=tcsetattr(lpc->sfd,TCSANOW,&term);
+
+       return ret;
+}
+
+int open_firmware(t_lpc *lpc) {
 
        /* open firmware file */
 
@@ -137,19 +179,40 @@ int open_firmware(t_lpc *lpc) {
        if(lpc->fwfd<0)
                perror("fw open");
 
-       /* read hex file offset */
+       return lpc->fwfd;
+}
 
-       ret=read(lpc->fwfd,buf,7);
-       if(buf[0]!=':') {
-               printf("fw open: not an intel hex file?\n");
-               return -1;
+int open_dumpfiles(t_lpc *lpc) {
+
+       /* open dumpfiles */
+
+       if(lpc->info&BANK0) {
+               lpc->b0fd=open(lpc->bank0,O_WRONLY|O_CREAT);
+               if(lpc->b0fd<0) {
+                       perror("bank0 dump file open");
+                       return lpc->b0fd;
+               }
        }
-       sscanf(buf+3,"%04x",&(lpc->hoff));
-       lseek(lpc->fwfd,0,SEEK_SET);
 
-       return lpc->fwfd;
-}
+       if(lpc->info&BANK2) {
+               lpc->b2fd=open(lpc->bank2,O_WRONLY|O_CREAT);
+               if(lpc->b2fd<0) {
+                       perror("bank2 dump file open");
+                       return lpc->b2fd;
+               }
+       }
 
+       if(lpc->info&BL) {
+               lpc->blfd=open(lpc->bl,O_WRONLY|O_CREAT);
+               if(lpc->blfd<0) {
+                       perror("bootloader dump file open");
+                       return lpc->blfd;
+               }
+       }
+
+       return 0;
+
+}
 int txrx(t_lpc *lpc,char *buf,int len,u8 type) {
 
        int ret,cnt;
@@ -181,6 +244,8 @@ int txrx(t_lpc *lpc,char *buf,int len,u8 type) {
                printf("| (%d)\n",cnt);
        }
 
+
+
        /* cut the echo if not of type auto baud */
 
        if(type!=TXRX_TYPE_BAUD) {
@@ -194,6 +259,11 @@ int txrx(t_lpc *lpc,char *buf,int len,u8 type) {
                }
        }
 
+       /* return if type is go */
+
+       if(type==TXRX_TYPE_GO)
+               return cnt;
+
        /* return here if type is data */
 
        if(type==TXRX_TYPE_DATA)
@@ -315,9 +385,9 @@ int go(t_lpc *lpc) {
        char buf[BUFSIZE];
        int ret,len;
 
-       snprintf(buf,BUFSIZE,"G %d A\r\n",lpc->roff);
+       snprintf(buf,BUFSIZE,"G %d A\r\n",lpc->jaddr);
        len=strlen(buf);
-       ret=txrx(lpc,buf,len,TXRX_TYPE_CMD);
+       ret=txrx(lpc,buf,len,TXRX_TYPE_GO);
 
        return ret;
 }
@@ -357,7 +427,7 @@ int write_to_ram(t_lpc *lpc,char *buf,u32 addr,int len) {
        for(i=len;i<nlen;i++) buf[i]=0;
 
        /* prepare addr */
-       addr+=(lpc->roff-lpc->hoff);
+       addr+=lpc->roff;
 
        /* prepare write command */
        if(lpc->info&VERBOSE)
@@ -446,10 +516,6 @@ int firmware_to_ram(t_lpc *lpc) {
                /* read len */
                ret=read(lpc->fwfd,buf,2);
                sscanf(buf,"%02x",&len);
-               if(len%4) {
-                       printf("fw to ram: len not a multiple of 4\n");
-                       return -1;
-               }
                /* read addr */
                ret=read(lpc->fwfd,buf,4);
                sscanf(buf,"%04x",&addr);
@@ -471,12 +537,23 @@ int firmware_to_ram(t_lpc *lpc) {
                }
                /* act according to type */
                switch(type) {
-                       case 0x03:
-                               /* get cs and ip */
-                               break;
+                       //case 0x03:
+                       //      /* get cs and ip */
+                       //      break;
                        case 0x00:
+                               if(len%4) {
+                                       printf("fw to ram: invalid len\n");
+                                       return -1;
+                               }
                                write_to_ram(lpc,buf,addr,len);
                                break;
+                       case 0x04:
+                               lpc->roff=((buf[0]<<24)|(buf[1]<<16));
+                               break;
+                       case 0x05:
+                               lpc->jaddr=((buf[0]<<24)|(buf[1]<<16));
+                               lpc->jaddr|=((buf[2]<<8)|buf[3]);
+                               break;
                        default:
                                printf("fw to ram: unknown type %02x\n",type);
                                return -1;
@@ -486,10 +563,90 @@ int firmware_to_ram(t_lpc *lpc) {
        return 0;
 }
 
+int lpc_txbuf_flush(t_lpc *lpc) {
+
+       int i,ret;
+       u8 buf[16];
+
+       ret=1;
+       printf("flushing lpc tx buffer: ");
+       while(ret) {
+               ret=read(lpc->sfd,buf,16);
+               for(i=0;i<ret;i++)
+                       printf("%02x ",buf[i]);
+       }
+       printf("\n");
+
+       return 0;
+}
+
+int dump_files(int sfd,int dfd,u32 addr,u32 len) {
+
+       int ret;
+       int size;
+       int cnt;
+       int i;
+       u8 buf[16];
+
+       printf("dumping content (addr=0x%08x, len=0x%08x) ...\n",addr,len);
+
+       /* send cmd */
+       size=1+4+4;
+       cnt=0;
+       buf[0]=CMD_READ;
+       buf[1]=(addr>>24)&0xff;
+       buf[2]=(addr>>16)&0xff;
+       buf[3]=(addr>>8)&0xff;
+       buf[4]=addr&0xff;
+       buf[5]=(len>>24)&0xff;
+       buf[6]=(len>>16)&0xff;
+       buf[7]=(len>>8)&0xff;
+       buf[8]=len&0xff;
+       printf("  sending cmd: ");
+       while(size) {
+               ret=write(sfd,buf+cnt,size);
+               for(i=cnt;i<cnt+ret;i++)
+                       printf("%02x ",buf[i]);
+               if(ret<0) {
+                       perror("dump file: send cmd ");
+                       return ret;
+               }
+               size-=ret;
+               cnt+=ret;
+       }
+       printf("\n");
+
+       /* receive data and dump it to file */
+       ret=1;
+       cnt=0;
+       printf("  receiving data ...\n");
+       while(ret) {
+               ret=read(sfd,buf,16);
+               if(ret<0) {
+                       perror("dump file: read data");
+                       return ret;
+               }
+               size=ret;
+               cnt=0;
+               while(size) {
+                       ret=write(dfd,buf+cnt,size-cnt);
+                       if(ret<0) {
+                               perror("dump file: write data");
+                               return ret;
+                       }
+                       cnt+=ret;
+                       size-=ret;
+               }
+       }
+
+       return 0;
+}
+
 int main(int argc,char **argv) {
 
        t_lpc lpc;
        int i;
+       int ret;
 
        /*
         * initial ... 
@@ -498,6 +655,7 @@ int main(int argc,char **argv) {
        memset(&lpc,0,sizeof(t_lpc));
        strncpy(lpc.freq,CRYSTFREQ,7);
        lpc.roff=RAMOFFSET;
+       lpc.jaddr=RAMOFFSET;
 
        /* parse argv */
 
@@ -522,6 +680,27 @@ int main(int argc,char **argv) {
                        case 'c':
                                strncpy(lpc.freq,argv[++i],7);
                                break;
+                       case 'D':
+                               if(argv[i][2]=='0') {
+                                       lpc.info|=BANK0;
+                                       strncpy(lpc.bank0,argv[++i],127);
+                                       break;
+                               }
+                               else if(argv[i][2]=='2') {
+                                       lpc.info|=BANK2;
+                                       strncpy(lpc.bank2,argv[++i],127);
+                                       break;
+                               }
+                               else if(argv[i][2]=='b') {
+                                       lpc.info|=BL;
+                                       strncpy(lpc.bl,argv[++i],127);
+                                       break;
+                               }
+                               else {
+                                       usage();
+                                       return -1;
+                               }
+                               
                        default:
                                usage();
                                return -1;
@@ -533,15 +712,25 @@ int main(int argc,char **argv) {
        if(open_serial_device(&lpc)<0)
                goto end;
 
-       /* open firmware file */
-       if(open_firmware(&lpc)<0)
-               goto end;
-
        /* boot loader init */
        printf("boot loader init ...\n");
        if(bl_init(&lpc)<0)
                return -1;
 
+       /* quit if there is no hex file to process */
+       if(!(lpc.info&FIRMWARE)) {
+               printf("no firmware -> aborting\n");
+               goto end;
+       }
+
+       /* open firmware file */
+       if(open_firmware(&lpc)<0)
+               goto end;
+
+       /* open dump files */
+       if(open_dumpfiles(&lpc)<0)
+               goto end;
+
        /* parse intel hex file and write to ram */
        printf("write firmware to ram ...\n");
        firmware_to_ram(&lpc);
@@ -552,12 +741,34 @@ int main(int argc,char **argv) {
 
        /* go! */
        printf("go ...\n");
-       go(&lpc);
-       printf("\n");
+       ret=go(&lpc);
+
+       /* flush the lpc2220 tx buf */
+       lpc_txbuf_flush(&lpc);
+
+       /* reconfigure the serial port */
+       if(reconfig_serial_device(&lpc)<0)
+               goto end;
+
+       /* download flash/bootloader content */
+       if(lpc.info&BANK0)
+               dump_files(lpc.sfd,lpc.b0fd,BANK0_ADDR,BANK_SIZE);
+       if(lpc.info&BANK2)
+               dump_files(lpc.sfd,lpc.b2fd,BANK2_ADDR,BANK_SIZE);
+       if(lpc.info&BL)
+               dump_files(lpc.sfd,lpc.blfd,BL_ADDR,BL_SIZE);
 
 end:
-       close(lpc.sfd);
-       close(lpc.fwfd);
+       if(lpc.sfd)
+               close(lpc.sfd);
+       if(lpc.fwfd)
+               close(lpc.fwfd);
+       if(lpc.b0fd)
+               close(lpc.b0fd);
+       if(lpc.b2fd)
+               close(lpc.b2fd);
+       if(lpc.blfd)
+               close(lpc.blfd);
 
        return 0;
 }