--- /dev/null
+/*
+ * 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);
+}
+