added low level flash support
[my-code/arm.git] / betty / flash.c
diff --git a/betty/flash.c b/betty/flash.c
new file mode 100644 (file)
index 0000000..8d9c02a
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * flash.c - low level flash handling
+ *
+ * author: hackbard@hackdaworld.org
+ *
+ */
+
+#include "flash.h"
+
+/*
+ * sector addresses
+ */
+static unsigned long sector_address[19]={
+       0x00000,0x02000,0x03000,0x04000,0x08000,
+       0x10000,0x18000,
+       0x20000,0x28000,
+       0x30000,0x38000,
+       0x40000,0x48000,
+       0x50000,0x58000,
+       0x60000,0x68000,
+       0x70000,0x78000
+};
+
+/*
+ * functions
+ */
+
+void flash_init(void) {
+
+       /*
+        * idle clocks between rad & write: 0+1
+        * length of read access: 1+3
+        * bls lines high during write access
+        * length of write access: 0+1
+        * no write protect, no burst-rom
+        * 16 bit data width
+        */
+
+       BCFG0=0x10000420;       // flash 1
+       BCFG2=0x10000420;       // flash 2
+
+       /*
+        * p3.27: write enable
+        * p3.25: chip select 2
+        * p2.15 - p2.8: data bus
+        * a[1:15] -> address lines
+        */
+
+       PINSEL2=(PINSEL2&P2MASK)|(1<<8);
+       PINSEL2=(PINSEL2&P2MASK&~((1<<15)|(1<<14)))|(1<<14);
+       PINSEL2=(PINSEL2&P2MASK&~((1<<5)|(1<<4)))|(1<<4);
+       PINSEL2=(PINSEL2&P2MASK)|(1<<24);
+       PINSEL2=(PINSEL2&P2MASK&~((1<<27)|(1<<26)|(1<<25)))|(1<<27)|(1<<26);
+}
+
+void flash_reset(u8 bank) {
+
+       if((bank!='0')&(bank!='2'))
+               return;
+
+       if(bank=='0')
+               FLASH_B0F=0xf0;
+       else
+               FLASH_B2F=0xf0;
+}
+
+void flash_sector_erase(u8 bank,u8 sector) {
+
+       u32 a18_12;
+
+       if(sector>18)
+               return;
+       a18_12=sector_address[sector]<<1;
+
+       switch(bank) {
+               case '0':
+                       FLASH_B0F555=0xaa;
+                       FLASH_B0F2AA=0x55;
+                       FLASH_B0F555=0x80;
+                       FLASH_B0F555=0xaa;
+                       FLASH_B0F2AA=0x55;
+                       *((volatile u16 *)(FLASH_BANK0|a18_12))=0x30;
+                       break;
+               case '2': 
+                       FLASH_B2F555=0xaa;
+                       FLASH_B2F2AA=0x55;
+                       FLASH_B2F555=0x80;
+                       FLASH_B2F555=0xaa;
+                       FLASH_B2F2AA=0x55;
+                       *((volatile u16 *)(FLASH_BANK2|a18_12))=0x30;
+                       break;
+               default:
+                       return;
+       }
+
+       return;
+}
+
+void flash_chip_erase(u8 bank) {
+
+       u8 status;
+
+       if((bank!='0')&(bank!='2'))
+               return;
+
+       if(bank=='0') {
+               FLASH_B0F555=0xaa;
+               FLASH_B0F2AA=0x55;
+               FLASH_B0F555=0x80;
+               FLASH_B0F555=0xaa;
+               FLASH_B0F2AA=0x55;
+               FLASH_B0F555=0x10;
+       }
+       else {
+               FLASH_B2F555=0xaa;
+               FLASH_B2F2AA=0x55;
+               FLASH_B2F555=0x80;
+               FLASH_B2F555=0xaa;
+               FLASH_B2F2AA=0x55;
+               FLASH_B2F555=0x10;
+       }
+
+       while(1) {
+               if(bank=='0')
+                       status=FLASH_B0F;
+               else
+                       status=FLASH_B2F;
+               if(status&0x80)
+                       break;
+       }
+}
+
+void flash_unlock_bypass(u8 bank) {
+
+       if((bank!='0')&(bank!='2'))
+               return;
+
+       if(bank=='0') {
+               FLASH_B0F555=0xaa;
+               FLASH_B0F2AA=0x55;
+               FLASH_B0F555=0x20;
+       }
+       else {
+               FLASH_B2F555=0xaa;
+               FLASH_B2F2AA=0x55;
+               FLASH_B2F555=0x20;
+       }
+}
+
+void flash_unlock_bypass_reset(u8 bank) {
+
+       if((bank!='0')&(bank!='2'))
+               return;
+
+       if(bank=='0') {
+               FLASH_B0F=0x90;
+               FLASH_B0F=0x00;
+       }
+       else {
+               FLASH_B2F=0x90;
+               FLASH_B2F=0x00;
+       }
+}
+
+int flash_write_word(u32 addr,u16 data) {
+
+       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;
+
+       return 0;
+}
+
+#define flash_read_word(addr,data) *(data)=*((unsigned volatile short *)(addr))
+
+int flash_write_buf(u32 addr,u16 *buf,int len) {
+
+       int cnt,ret;
+       u8 bank;
+
+       /* len must be a multiple of 2 */
+       if(len&0x1)
+               return -1;
+
+       /* decide the bank */
+       if(addr<0x82000000)
+               bank='0';
+       else
+               bank='2';
+
+       /* unlock */
+       flash_unlock_bypass(bank);
+
+       /* write the data */
+       ret=0;
+       for(cnt=0;cnt<len/2;cnt++) {
+               if(flash_write_word(addr,*(buf+cnt))==0)
+                       ret+=2;
+               addr+=2;
+       }
+
+       /* relock */
+       flash_unlock_bypass_reset(bank);
+
+       return ret;
+}
+
+void flash_read_buf(u32 addr,u16 *buf,int len) {
+
+       int cnt;
+
+       /* len must be a multiple of 2 */
+       if(len&0x1)
+               return;
+
+       for(cnt=0;cnt<len/2;cnt++)
+               flash_read_word(addr,buf+cnt);
+}
+