no byte reply anymore (due to ack and tcflush) -> incredible speedup!
[my-code/arm.git] / betty / fwflash.c
index 4462654..85a64fa 100644 (file)
@@ -9,21 +9,35 @@
  * include files
  */
 
+#include <stdio.h>
+
 #include "lpc2xxx.h"
 
 /*
  * defines
  */
 
-/* band 0/2 addr */
+/* bank 0/2 and boootloader addr/size */
 #define BANK0                  0x80000000
 #define BANK2                  0x82000000
-#define B0HB                   0x00000000
-#define B2HB                   0x02000000
+#define BANK_SIZE              0x00100000
+#define BOOTLOADER             0x7fffe000
+#define BL_SIZE                        0x00002000
+
+/* flash cmd addresses - flash[0-18] <--> arm[1-19]*/
+#define B0F555 (*((volatile unsigned short *)(BANK0|0xaaa)))   // 0x555
+#define B0F2AA (*((volatile unsigned short *)(BANK0|0x554)))   // 0x2aa
+#define B0F    (*((volatile unsigned short *)(BANK0)))
+#define B2F555 (*((volatile unsigned short *)(BANK2|0xaaa)))   // 0x555
+#define B2F2AA (*((volatile unsigned short *)(BANK2|0x554)))   // 0x2aa
+#define B2F    (*((volatile unsigned short *)(BANK2)))
 
 /* commands */
 #define CMD_READ               'R'
+#define CMD_WRITE              'W'
 #define CMD_CHIP_ERASE         'E'
+#define CMD_SECTOR_ERASE       'S'
+#define CMD_CHIP_ID            'I'
 
 #define BUFSIZE                        16
 
@@ -36,186 +50,463 @@ typedef unsigned short u16;
 typedef unsigned int u32;
 
 /*
- * define macros
+ * sector addresses
  */
 
-#define TX_BYTE(x)             while(!(UART0_LSR&(1<<5))) continue; \
-                               UART0_THR=x;
-
-#define SEND_OK                        TX_BYTE('o'); TX_BYTE('k'); TX_BYTE('\n'); \
-                               TX_BYTE('\r');
+unsigned long sector_address[19]={
+       0x00000,0x02000,0x03000,0x04000,0x08000,
+       0x10000,0x18000,
+       0x20000,0x28000,
+       0x30000,0x38000,
+       0x40000,0x48000,
+       0x50000,0x58000,
+       0x60000,0x68000,
+       0x70000,0x78000
+};
 
 /*
- * function prototypes
+ * functions
  */
 
-void mmap_init(u8 memtype);
-void uart0_init(void);
-void uart0_send_string(char *txbuf);
-void uart0_send_char(char send);
+void uart0_send_byte(u8 send);
 
-/*
- * main function
- */
+void mmap_init(u8 memtype) {
 
-int main(void) {
+       MEMMAP=memtype;
+}
 
-       /* variables */
+void pll_init(void) {
 
-       u32 i,addrlen,datalen;
-       u8 buf[BUFSIZE];
-       u32 addr;
-       u16 *dptr;
-       u8 cmd;
-       u8 txrx;
+       /* configuration */
+       PLLCFG=0x42;    // multiplier = 3 (for cclk), dividor = 4 (for f_cco)
+       PLLCON=0x03;    // enable and set as clk source for the lpc
+       /* feed sequence */
+       PLLFEED=0xaa;
+       PLLFEED=0x55;
+       /* wait for lock */
+       while(!(PLLSTAT&(1<<10)))
+               continue;
+}
 
-       /* memory mapping of interrupt vectors to static ram */
+void ext_mem_bank_init(void) {
 
-       //mmap_init(MMAP_RAM);
+       BCFG0=0x10000420;       // flash 1
+       BCFG1=0x00000c42;       // lcd
+       BCFG2=0x10000420;       // flash 2
+}
 
-       /* uart initialization */
+void pin_select_init() {
+
+       /*
+        * a[19:2] -> address lines
+        */
+
+       PINSEL2=0x0d6041d4;
+}
 
-       //uart0_init();
+void uart0_init(void) {
 
        PINSEL0=0x05;                   // pin select -> tx, rx
        UART0_FCR=0x07;                 // enable fifo
        UART0_LCR=0x83;                 // set dlab + word length
-       UART0_DLL=0x10;                 // br: 9600 @ 10/4 mhz
+       UART0_DLL=0x04;                 // br: 38400 @ 10/4 mhz
        UART0_DLM=0x00;
        UART0_LCR=0x03;                 // unset dlab
+}
 
-       /* external memory init */
-
-       BCFG0=0x1000FBEF;               // no boot[1:0] influence? (thnx colibri)
-                                       // BCFG2 should be fine as is
+void uart0_send_string(char *txbuf) {
 
-       /* begin the main loop */
-       while(1) {
+       int i;
 
-       /* receive cmd */
-       while(1) {
+       i=0;
 
-               while(!(UART0_LSR&(1<<0)))
+       while(txbuf[i]) {
+               UART0_THR=txbuf[i++];
+               /* flush if tx buffer maximum reached */
+               if(!(i%16))
+                       while(!(UART0_LSR&(1<<6)))
+                               continue;
+       }
+       
+       /* flush if \n and \r do not fit in the tx buffer */
+       if(i>14)
+               while(!(UART0_LSR&(1<<6)))
                        continue;
-               cmd=UART0_RBR;
 
-               if(cmd==CMD_CHIP_ERASE) {
-SEND_OK
-                       addrlen=0;
-                       datalen=1;
+       UART0_THR='\n';
+       UART0_THR='\r';
+
+       /* flush uart0 anyways */
+       while(!(UART0_LSR&(1<<6)))
+               continue;
+}
+
+void uart0_send_buf16(u16 *buf,int len) {
+
+       int i;
+
+       i=0;
+
+       for(i=0;i<len/2;i++) {
+               if(!(i%8))
+                       while(!(UART0_LSR&(1<<6)))
+                               continue;
+               UART0_THR=buf[i]&0xff;
+               UART0_THR=(buf[i]>>8)&0xff;
+       }
+}
+
+void uart0_send_buf32(u32 *buf,int len) {
+
+       int i;
+
+       i=0;
+
+       for(i=0;i<len/4;i++) {
+               if(!(i%4))
+                       while(!(UART0_LSR&(1<<6)))
+                               continue;
+               UART0_THR=buf[i]&0xff;
+               UART0_THR=(buf[i]>>8)&0xff;
+               UART0_THR=(buf[i]>>16)&0xff;
+               UART0_THR=(buf[i]>>24)&0xff;
+       }
+}
+
+void uart0_send_byte(u8 send) {
+
+       while(!(UART0_LSR&(1<<5)))
+               continue;
+
+       UART0_THR=send;
+}
+
+u8 uart0_get_byte(void) {
+
+       u8 rx;
+
+       while(!(UART0_LSR&(1<<0)))
+               continue;
+
+       rx=UART0_RBR;
+
+       return rx;
+}
+
+void flash_reset(u8 bank) {
+
+       if((bank!='0')&(bank!='2'))
+               return;
+
+       if(bank=='0')
+               B0F=0xf0;
+       else
+               B2F=0xf0;
+}
+
+void flash_sector_erase(u8 flash,u8 sector) {
+
+       u32 a18_12;
+       u32 base;
+
+       if(sector>18)
+               return;
+       a18_12=sector_address[sector]<<1;
+
+       if((flash!='0')&(flash!='2'))
+               return;
+
+       switch(flash) {
+               case '0':
+                       base=0x80000000;
+                       B0F555=0xaa;
+                       B0F2AA=0x55;
+                       B0F555=0x80;
+                       B0F555=0xaa;
+                       B0F2AA=0x55;
+                       *((volatile u16 *)(base|a18_12))=0x30;
                        break;
-               }
+               case '2': 
+                       base=0x82000000;
+                       B2F555=0xaa;
+                       B2F2AA=0x55;
+                       B2F555=0x80;
+                       B2F555=0xaa;
+                       B2F2AA=0x55;
+                       *((volatile u16 *)(base|a18_12))=0x30;
+                       break;
+               default:
+                       return;
+       }
+
+       return;
+}
+
+void flash_chip_erase(u8 bank) {
+
+       u8 status;
+
+       if((bank!='0')&(bank!='2'))
+               return;
+
+       if(bank=='0') {
+               B0F555=0xaa;
+               B0F2AA=0x55;
+               B0F555=0x80;
+               B0F555=0xaa;
+               B0F2AA=0x55;
+               B0F555=0x10;
+       }
+       else {
+               B2F555=0xaa;
+               B2F2AA=0x55;
+               B2F555=0x80;
+               B2F555=0xaa;
+               B2F2AA=0x55;
+               B2F555=0x10;
+       }
 
-               if(cmd==CMD_READ) {
-                       addrlen=4;
-                       datalen=1;
+       while(1) {
+               if(bank=='0')
+                       status=B0F;
+               else
+                       status=B2F;
+
+               if(status&0x80) {
+                       /* send an ack */
+                       uart0_send_byte(status);
                        break;
                }
        }
+}
 
-       /* receive (only if there is) more data from uart0 */
+void unlock_bypass(u8 bank) {
 
-       addr=0;
-       for(i=0;i<addrlen;i++) {
-               while(!(UART0_LSR&(1<<0)))
-                       continue;
-               txrx=UART0_RBR;
-               addr|=(txrx<<(i*4));
+       if((bank!='0')&(bank!='2'))
+               return;
+
+       if(bank=='0') {
+               B0F555=0xaa;
+               B0F2AA=0x55;
+               B0F555=0x20;
+       }
+       else {
+               B2F555=0xaa;
+               B2F2AA=0x55;
+               B2F555=0x20;
        }
-SEND_OK
+}
 
-       for(i=0;i<datalen;i++) {
-               while(!(UART0_LSR&(1<<0)))
-                       continue;
-               buf[i++]=UART0_RBR;
+void unlock_bypass_reset(u8 bank) {
+
+       if((bank!='0')&(bank!='2'))
+               return;
+
+       if(bank=='0') {
+               B0F=0x90;
+               B0F=0x00;
+       }
+       else {
+               B2F=0x90;
+               B2F=0x00;
        }
-SEND_OK
+}
 
-       /* process the cmd */
+int flash_write(u32 addr,u16 data) {
 
-       switch(cmd) {
-               case CMD_READ:
-                       dptr=(u16 *)addr;
-                       for(i=0;i<buf[0];i++) {
-                               TX_BYTE(*dptr);
-                               dptr++;
-                       }
-                       break;  
-               case CMD_CHIP_ERASE:
-                       if(buf[0]=='0')
-                               addr=B0HB;
-                       else if(buf[0]=='2')
-                               addr=B2HB;
-                       else
-                               break;
-                       // cycle 1
-                       dptr=(u16 *)(addr|0x555);
-                       *dptr=0xaa;
-                       // cycle 2
-                       dptr=(u16 *)(addr|0x2aa);
-                       *dptr=0x55;
-                       // cycle 3+4
-                       dptr=(u16 *)(addr|0x555);
-                       *dptr=0x80;
-                       *dptr=0xaa;
-                       // cycle 5
-                       dptr=(u16 *)(addr|0x2aa);
-                       *dptr=0x55;
-                       // cycle 6
-                       dptr=(u16 *)(addr|0x555);
-                       *dptr=0x10;
-SEND_OK
-                       break;
-               default:
+       u16 check;
+
+       if(data==0xffff)
+               return 0;
+
+       *((unsigned volatile short *)addr)=0xa0;
+       *((unsigned volatile short *)addr)=data;
+       while(1) {
+               check=*((unsigned short *)addr);
+               if((data&0x80)==(check&0x80))
                        break;
        }
+       if(data!=check)
+               return -1;
 
-       /* send an ack, the cmd! */
-       TX_BYTE(cmd);
-               
+       return 0;
+}
+
+int receive_data_and_write_to_flash(u32 addr,u32 datalen) {
+
+       u8 bank;
+       u32 i,ret;
+       u16 data;
+       u8 cksm;
+       u8 byte;
+
+       /* which bank to program */
+       if(addr<0x82000000)
+               bank='0';
+       else
+               bank='2';
+
+       /* unlock bypass */
+       unlock_bypass(bank);
+
+       /* receive and write data */
+       cksm=0;
+       ret=0;
+       for(i=0;i<datalen/2;i++) {
+               byte=uart0_get_byte();
+               data=byte;
+               cksm+=byte;
+               byte=uart0_get_byte();
+               cksm+=byte;
+               data|=byte<<8;
+               if(flash_write(addr,data)<0)
+                       ret=-1;
+               addr+=2;
        }
 
-       return 0;
+       /* relock bypass */
+       unlock_bypass_reset(bank);
+
+       /* modify cksm on purpose, so the user knows ... */
+       if(ret==-1)
+               cksm+=1;
+
+       /* send the cksm */
+       uart0_send_byte(cksm);
+
+       return ret;
 }
 
 /*
- * functions
+ * main function
  */
 
-void mmap_init(u8 memtype) {
+int main(void) {
 
-       MEMMAP=memtype;
-}
+       /* variables */
 
-void uart0_init(void) {
+       u32 i,addrlen,datalen,addr;
+       u8 buf[BUFSIZE];
+       u16 data;
+       u8 cmd;
+       u8 txrx;
 
-       PINSEL0=0x05;                   // pin select -> tx, rx
-       UART0_FCR=0x07;                 // enable fifo
-       UART0_LCR=0x83;                 // set dlab + word length
-       UART0_DLL=0x10;                 // br: 9600 @ 10/4 mhz
-       UART0_DLM=0x00;
-       UART0_LCR=0x03;                 // unset dlab
-}
+       /* memory mapping of interrupt vectors to static ram */
 
-void uart0_send_string(char *txbuf) {
+       //mmap_init(MMAP_RAM);
+       
+       /* pll initialization */
+       pll_init();
 
-       int i;
+       /* uart initialization */
+       uart0_init();
 
-       i=0;
+       /* external memory init */
+       ext_mem_bank_init();
 
-       while(txbuf[i])
-               UART0_THR=txbuf[i++];
-       UART0_THR='\n';
-       UART0_THR='\r';
+       /* pin select init */
+       pin_select_init();
 
-       while(!(UART0_LSR&(1<<6))) {}
-}
+       /* begin the main loop */
+       while(1) {
+
+       /* receive cmd */
+       while(1) {
 
-void uart0_send_char(char send) {
+               cmd=uart0_get_byte();
+               txrx=1;
+               switch(cmd) {
+                       case CMD_CHIP_ERASE:
+                               addrlen=0;
+                               datalen=1;
+                               break;
+                       case CMD_SECTOR_ERASE:
+                               addrlen=0;
+                               datalen=2;
+                               break;
+                       case CMD_READ:
+                               addrlen=4;
+                               datalen=4;
+                       case CMD_WRITE:
+                               addrlen=4;
+                               datalen=4;
+                               break;
+                       case CMD_CHIP_ID:
+                               addrlen=0;
+                               datalen=1;
+                               break;
+                       default:
+                               txrx=0;
+                               break;
+               }
 
-       while(!(UART0_LSR&(1<<5)))
-               continue;
+               if(txrx)
+                       break;
+       }
 
-       UART0_THR=send;
+       /* receive (only if there is) more data from uart0 */
+       addr=0;
+       for(i=0;i<addrlen;i++) {
+               txrx=uart0_get_byte();
+               addr|=(txrx<<((addrlen-i-1)*8));
+       }
+
+       for(i=0;i<datalen;i++)
+               buf[i]=uart0_get_byte();
+
+       /* process the cmd */
+       switch(cmd) {
+               case CMD_SECTOR_ERASE:
+                       flash_sector_erase(buf[0],buf[1]);
+                       break;
+               case CMD_READ:
+                       /* data length to read */
+                       datalen=buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3];
+                       /* check addr and datalen */
+                       if((addr>=BANK0)&(addr+datalen<=BANK0+BANK_SIZE))
+                               uart0_send_buf16((u16 *)addr,datalen);
+                       if((addr>=BANK2)&(addr+datalen<=BANK2+BANK_SIZE))
+                               uart0_send_buf16((u16 *)addr,datalen);
+                       if((addr>=BOOTLOADER)&(addr+datalen<=BOOTLOADER+BL_SIZE))
+                               uart0_send_buf32((u32 *)addr,datalen);
+                       break;
+               case CMD_WRITE:
+                       /* data length */
+                       datalen=buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3];
+                       /* check addr and data len */
+                       if(((addr>=BANK0)&(addr+datalen<=BANK0+BANK_SIZE))|
+                          ((addr>=BANK2)&(addr+datalen<=BANK2+BANK_SIZE)))
+                               receive_data_and_write_to_flash(addr,datalen);
+                       break;
+               case CMD_CHIP_ERASE:
+                       flash_chip_erase(buf[0]);
+                       break;
+               case CMD_CHIP_ID:
+                       if(buf[0]=='0') {
+                               B0F555=0xaa;
+                               B0F2AA=0x55;
+                               B0F555=0x90;
+                               data=*((u16 *)BANK0);
+                               uart0_send_buf16(&data,2);
+                               data=*((u16 *)(BANK0|0x200));
+                               uart0_send_buf16(&data,2);
+                       }
+                       else if(buf[0]=='2') {
+                               B2F555=0xaa;
+                               B2F2AA=0x55;
+                               B2F555=0x90;
+                               data=*((u16 *)BANK2);
+                               uart0_send_buf16(&data,2);
+                               data=*((u16 *)(BANK2|0x200));
+                               uart0_send_buf16(&data,2);
+                       }
+                       break;
+               default:
+                       break;
+       }
+               
+       }
+
+       return 0;
 }