summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Schinagl <oliver@schinagl.nl>2011-03-18 19:56:30 (GMT)
committerOliver Schinagl <oliver@schinagl.nl>2011-03-18 19:56:30 (GMT)
commitb10d9039a678f38ed48f4cf032c6b3bc82848594 (patch)
treefb0f35237b91b33d0694b8213d89cef0e84a80b8
parent569556c4a762771f01d767db95ad18966cedd2f7 (diff)
downloadopenipcam-b10d9039a678f38ed48f4cf032c6b3bc82848594.zip
openipcam-b10d9039a678f38ed48f4cf032c6b3bc82848594.tar.gz
openipcam-b10d9039a678f38ed48f4cf032c6b3bc82848594.tar.bz2
Winbond flash support.
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/Config.in5
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/Makefile3
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/blkmem.c18
-rwxr-xr-xuClinux-2.4.20-uc1/drivers/block/export.c38
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/wbflash/Config.in2
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/wbflash/Makefile7
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/wbflash/cfi.c279
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/wbflash/cfi.h39
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/wbflash/flash.c1056
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/wbflash/flash_u.c246
-rw-r--r--uClinux-2.4.20-uc1/drivers/block/wbflash/image.c178
-rw-r--r--uClinux-2.4.20-uc1/include/asm-armnommu/arch-W90N745/flash.h103
12 files changed, 1974 insertions, 0 deletions
diff --git a/uClinux-2.4.20-uc1/drivers/block/Config.in b/uClinux-2.4.20-uc1/drivers/block/Config.in
index e349779..52d0c96 100644
--- a/uClinux-2.4.20-uc1/drivers/block/Config.in
+++ b/uClinux-2.4.20-uc1/drivers/block/Config.in
@@ -33,6 +33,10 @@ dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARPORT
if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
source drivers/block/paride/Config.in
fi
+dep_tristate 'Winbond W90N745 flash support' CONFIG_WBFLASH
+if [ "$CONFIG_WBFLASH" = "y" -o "$CONFIG_WBFLASH" = "m" ]; then
+ source drivers/block/wbflash/Config.in
+fi
dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI
dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI
dep_mbool ' SCSI tape drive support for Smart Array 5xxx' CONFIG_CISS_SCSI_TAPE $CONFIG_BLK_CPQ_CISS_DA $CONFIG_SCSI
@@ -54,6 +58,7 @@ if [ "$CONFIG_BLK_DEV_BLKMEM" = "y" -o "$CONFIG_BLK_DEV_BLKMEM" = "m" ]; then
choice ' FLASH type' \
"NONE CONFIG_NOFLASH \
AMD CONFIG_AMDFLASH \
+ W90N745 CONFIG_WBFLASH \
INTEL CONFIG_INTELFLASH" NONE
if [ "$CONFIG_AMDFLASH" = "y" -o "$CONFIG_INTELFLASH" = "y" ]; then
choice ' FLASH size' \
diff --git a/uClinux-2.4.20-uc1/drivers/block/Makefile b/uClinux-2.4.20-uc1/drivers/block/Makefile
index 55106f0..e4186d2 100644
--- a/uClinux-2.4.20-uc1/drivers/block/Makefile
+++ b/uClinux-2.4.20-uc1/drivers/block/Makefile
@@ -32,8 +32,11 @@ obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o
obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o
obj-$(CONFIG_BLK_DEV_UMEM) += umem.o
obj-$(CONFIG_BLK_DEV_NBD) += nbd.o
+obj-$(CONFIG_WBFLASH) += wbflash/wbflash.o
+obj-y+= export.o
subdir-$(CONFIG_PARIDE) += paride
+subdir-$(CONFIG_WBFLASH) += wbflash
ifeq ($(CONFIG_ARCH_ACORN),y)
mod-subdirs += ../acorn/block
diff --git a/uClinux-2.4.20-uc1/drivers/block/blkmem.c b/uClinux-2.4.20-uc1/drivers/block/blkmem.c
index 27c506f..a71c55f 100644
--- a/uClinux-2.4.20-uc1/drivers/block/blkmem.c
+++ b/uClinux-2.4.20-uc1/drivers/block/blkmem.c
@@ -220,6 +220,14 @@ extern char __romfs_start[];
#define FIXED_ROMARRAY __romfs_start
#endif
+#ifdef CONFIG_ARCH_WINBOND
+#ifndef ROMFS_BASE
+#define FIXED_ROMARRAY (char *)0x700000
+#else
+#define FIXED_ROMARRAY (char *)ROMFS_BASE
+#endif
+#endif
+
/******* END OF BOARD-SPECIFIC CONFIGURATION ************/
/* Simple romfs, at internal, cat on the end of kernel, or seperate fixed adderess romfs. */
@@ -2799,6 +2807,16 @@ int __init blkmem_init( void )
#endif
for(i=0;i<arenas;i++) {
+#ifdef CONFIG_WBFLASH //lsshi 2005-8-31 04:47
+ if(i==0) {
+#ifndef ROMFS_BASE
+ arena[i].address = 0x700000; //GetImgAddr(0x700000);
+#else
+ arena[i].address = ROMFS_BASE;
+#endif
+ }
+#endif
+
if (arena[i].length == -1)
arena[i].length = ntohl(*(volatile unsigned long *)(arena[i].address+8));
blkmem_blocksizes[i] = 1024;
diff --git a/uClinux-2.4.20-uc1/drivers/block/export.c b/uClinux-2.4.20-uc1/drivers/block/export.c
new file mode 100755
index 0000000..97fa9fc
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/block/export.c
@@ -0,0 +1,38 @@
+#include <asm/arch/flash.h>
+#include <linux/slab.h>
+
+#ifndef CONFIG_WBFLASH//CONFIG_W90N745FLASH
+
+asmlinkage int sys_FindImage(UINT32 image_num, tfooter ** image_footer)
+{
+ return -ENOSYS;
+}
+asmlinkage int sys_DelImage(UINT32 image_num)
+{
+ return -ENOSYS;
+}
+asmlinkage int sys_CorruptCheck(tfooter * image_footer)
+{
+ return -ENOSYS;
+}
+asmlinkage int sys_ReadWinbondFlash(unsigned long pos, unsigned long length, char * buffer)
+{
+ return -ENOSYS;
+}
+asmlinkage int sys_WriteWinbondFlash(unsigned long pos, unsigned long length, char * buffer)
+{
+ return -ENOSYS;
+}
+asmlinkage int sys_WinbondFlashBlockSize(unsigned long pos)
+{
+ return -ENOSYS;
+}
+asmlinkage int sys_WinbondFlashTotalSize()
+{
+ return -ENOSYS;
+}
+asmlinkage int sys_WinbondFlashBase()
+{
+ return -ENOSYS;
+}
+#endif
diff --git a/uClinux-2.4.20-uc1/drivers/block/wbflash/Config.in b/uClinux-2.4.20-uc1/drivers/block/wbflash/Config.in
new file mode 100644
index 0000000..37cfeda
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/block/wbflash/Config.in
@@ -0,0 +1,2 @@
+comment 'Winbond low level flash drivers'
+dep_tristate ' Winbond low level flash driver support' CONFIG_WBFLASHDRV $CONFIG_WBFLASH
diff --git a/uClinux-2.4.20-uc1/drivers/block/wbflash/Makefile b/uClinux-2.4.20-uc1/drivers/block/wbflash/Makefile
new file mode 100644
index 0000000..426559f
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/block/wbflash/Makefile
@@ -0,0 +1,7 @@
+O_TARGET := wbflash.o
+
+obj-$(CONFIG_WBFLASHDRV) += cfi.o flash_u.o image.o
+
+#export-objs := wbflash.o
+
+include $(TOPDIR)/Rules.make
diff --git a/uClinux-2.4.20-uc1/drivers/block/wbflash/cfi.c b/uClinux-2.4.20-uc1/drivers/block/wbflash/cfi.c
new file mode 100644
index 0000000..ba4f0a3
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/block/wbflash/cfi.c
@@ -0,0 +1,279 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2007 Windond Electronics Corp.
+ * All rights reserved.
+ *
+ * $Workfile: cfi.c $
+ *
+ *
+ ******************************************************************************/
+
+//#include <stdio.h>
+//#include <string.h>
+//#include <stdlib.h>
+//#include "wblib.h"
+#include <asm/arch/flash.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include "cfi.h"
+//#include "platform.h"
+
+//#define FLASH_BASE 0xFF000000
+#define MAX_REGION_NUM 10
+
+static unsigned short cfiCmdSet = 0;
+static unsigned short cfiExtTab = 0;
+static unsigned int cfiDevSize = 0;
+static unsigned short cfiNumEraseBlkRegion = 0;
+
+static struct cfi_erase_block_region_info cfiEraseBlkRegionInfo[MAX_REGION_NUM];
+static int dummyErase(unsigned int address, unsigned int size);
+static int dummyWrite(unsigned int address, unsigned char *data, unsigned int size);
+
+struct cfi_command cfiCmd = {
+ write: dummyWrite,
+ erase: dummyErase,
+};
+
+
+/* Retrun 0: OK, otherwise: CFI not found */
+static int cfiCheckIdent(void)
+{
+ unsigned short i[3];
+
+ CFI_READ(FLASH_BASE, 0x10, i[0]);
+ CFI_READ(FLASH_BASE, 0x11, i[1]);
+ CFI_READ(FLASH_BASE, 0x12, i[2]);
+
+ if(i[0] == 'Q' && i[1] == 'R' && i[2] == 'Y')
+ return(0);
+ else
+ return(-1);
+
+}
+
+unsigned int cfiGetFlashSize(void)
+{
+ return(cfiDevSize);
+}
+
+unsigned int cfiGetBlockSize(unsigned int address)
+{
+ int i, offset = 0;
+
+ address = (address | 0x80000000) - (FLASH_BASE | 0x80000000);
+ //printk("addr %x %x\n", address, FLASH_BASE);
+
+ for(i = 0; i < cfiNumEraseBlkRegion; i++) {
+ if(address < (offset += (cfiEraseBlkRegionInfo[i].num * cfiEraseBlkRegionInfo[i].size)))
+ return(cfiEraseBlkRegionInfo[i].size);
+ }
+ //uprintf("get size error\n");
+
+ return(0);
+
+}
+
+static void flushDCache(void)
+{
+
+ if( *(unsigned int volatile *)(0xFFF02000) & 0x6 ) /* If write buffer or data cache is enabled */
+ {
+ *(unsigned int volatile *)(0xFFF02004) = 0x86;
+ while( *(unsigned int volatile *)(0xFFF02004));
+ }
+
+}
+
+
+static int polling16(unsigned int addr, unsigned short data)
+{
+ unsigned short rdata;
+ int timeout = 0x600000;
+
+ rdata = *(unsigned short volatile *)(addr);
+ while( rdata != data )
+ {
+ rdata = *(unsigned short volatile *)(addr);
+ if( !(timeout--) )
+ {
+ rdata = *(unsigned short volatile *)(addr);
+ if( rdata != data )
+ {
+ //printf("timeout\n");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int intelWrite(unsigned int address, unsigned char *data, unsigned int size)
+{
+ unsigned int i;
+ int status = 0;
+
+ address |= 0x80000000;
+ for(i = address; i < address + size; i += 2)
+ {
+ CFI_WRITE(i, 0, 0x40);
+ CFI_WRITE(i, 0, *(unsigned short *)data);
+ CFI_WRITE(address, 0, 0x70);
+ while(!( *(unsigned short *)(address) & 0x80));
+ if(*(unsigned short *)(address) & 0x19) {
+ status = -1;
+ goto exit;
+ }
+ data+=2;
+ }
+
+exit:
+ CFI_WRITE(address,0,0xFF);
+ flushDCache();
+ return(status);
+}
+
+static int dummyWrite(unsigned int address, unsigned char *data, unsigned int size)
+{
+ printk("Dummy Write\n");
+ return(-1);
+}
+static int amdWrite(unsigned int address, unsigned char *data, unsigned int size)
+{
+ int status;
+ unsigned int i;
+
+ address |= 0x80000000;
+ for(i = address; i < address+size; i += 2)
+ {
+ CFI_WRITE(FLASH_BASE, 0x555, 0xAA);
+ CFI_WRITE(FLASH_BASE, 0x2AA, 0x55);
+ CFI_WRITE(FLASH_BASE, 0x555, 0xA0);
+ CFI_WRITE(i, 0, *(unsigned short *)data);
+ status = polling16( i, *(unsigned short *)data);
+ if(status < 0) {
+ printk("write failed, time out!\n");
+ return(status); // time-out
+ }
+ data+=2;
+ }
+
+ flushDCache();
+ return(0);
+
+}
+
+static int intelErase(unsigned int address, unsigned int size)
+{
+ int status = 0;
+
+ address|=0x80000000;
+
+ CFI_WRITE(address, 0, 0x50); // Clear sttaus register
+ CFI_WRITE(address, 0, 0x20);
+ CFI_WRITE(address, 0, 0xD0);
+
+ CFI_WRITE(address, 0, 0x70);
+ while(!( *(unsigned short *)(address) & 0x80));
+ if(*(unsigned short *)(address) & 0x39)
+ status = -1;
+
+ CFI_WRITE(address, 0, 0xFF);
+ flushDCache();
+ return(status);
+}
+
+static int dummyErase(unsigned int address, unsigned int size)
+{
+ printk("Dummy Erase\n");
+ return(-1);
+}
+static int amdErase(unsigned int address, unsigned int size)
+{
+ int status;
+
+ //printk("erase addr: %x\n", address);
+
+ if((address & (size - 1)) != 0x0)
+ return -1;// not in the start of a block
+ address |= 0x80000000;
+ //printf("erase addr: %08x\n", address);
+ CFI_WRITE(FLASH_BASE, 0x555, 0xAA);
+ CFI_WRITE(FLASH_BASE, 0x2AA, 0x55);
+ CFI_WRITE(FLASH_BASE, 0x555, 0x80);
+ CFI_WRITE(FLASH_BASE, 0x555, 0xAA);
+ CFI_WRITE(FLASH_BASE, 0x2AA, 0x55);
+ CFI_WRITE(address, 0, 0x30);
+ status = polling16(address, 0xFFFF);
+ CFI_WRITE(FLASH_BASE, 0, 0xFF);
+ flushDCache();
+ if(status < 0)
+ printk("erase failed, time out!\n");
+ return(status);
+
+}
+
+int cfiGetFlashInfo(void)
+{
+
+ unsigned int i;
+
+ // goes into query mode
+ DESELECT_QUERY_MODE(FLASH_BASE);
+ SELECT_QUERY_MODE(FLASH_BASE);
+
+ if(cfiCheckIdent() != 0) {
+ printk("No CFI information found\n");
+ goto exit;
+ }
+
+ CFI_READ(FLASH_BASE, 0x13, cfiCmdSet);
+ CFI_READ(FLASH_BASE, 0x15, cfiExtTab);
+ CFI_READ(FLASH_BASE, 0x27, cfiDevSize);
+ cfiDevSize = 1 << cfiDevSize;
+
+ CFI_READ(FLASH_BASE, 0x2C, cfiNumEraseBlkRegion);
+ //cfiEraseBlkRegionInfo = (struct cfi_erase_block_region_info *)malloc(sizeof(struct cfi_erase_block_region_info) * cfiNumEraseBlkRegion);
+
+ if(cfiNumEraseBlkRegion > MAX_REGION_NUM) {
+ //sysprintf("Out of memory\n");
+ goto exit;
+ }
+
+ for(i = 0; i < cfiNumEraseBlkRegion * 4; i += 4) {
+ unsigned short s1, s2;
+ CFI_READ(FLASH_BASE, 0x2D + i, s1);
+ CFI_READ(FLASH_BASE, 0x2E + i, s2);
+
+ cfiEraseBlkRegionInfo[i/4].num = s1 + (s2 << 8) + 1;
+ //printk("num %d ", (cfiEraseBlkRegionInfo + i/4)->num);
+
+ CFI_READ(FLASH_BASE, 0x2F + i, s1);
+ CFI_READ(FLASH_BASE, 0x30 + i, s2);
+
+ cfiEraseBlkRegionInfo[i/4].size = (s1 + (s2 << 8)) * 256;
+ //printk("size %x \n", (cfiEraseBlkRegionInfo + i/4)->size);
+
+ }
+
+ DESELECT_QUERY_MODE(FLASH_BASE);
+ if(cfiCmdSet == AMD_CMD_SET) {
+ cfiCmd.write = amdWrite;
+ cfiCmd.erase = amdErase;
+
+ }else if(cfiCmdSet == INTEL_CMD_SET) {
+ cfiCmd.write = intelWrite;
+ cfiCmd.erase = intelErase;
+
+ } else {
+ printk("CFI command set %04x not support!\n", cfiCmdSet);
+ return(-1);
+ }
+ printk("CFI command set %04x will be used\n", cfiCmdSet);
+
+exit:
+ return(0);
+
+}
diff --git a/uClinux-2.4.20-uc1/drivers/block/wbflash/cfi.h b/uClinux-2.4.20-uc1/drivers/block/wbflash/cfi.h
new file mode 100644
index 0000000..19f2a65
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/block/wbflash/cfi.h
@@ -0,0 +1,39 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2007 Windond Electronics Corp.
+ * All rights reserved.
+ *
+ * $Workfile: cfi.h $
+ *
+ *
+ ******************************************************************************/
+#ifndef __CFI_H__
+#define __CFI_H__
+
+#define SELECT_QUERY_MODE(_base_) do{*(unsigned short volatile *)(((_base_) & 0xFFF00000) + (0x55 << 1)) = 0x98;}while(0)
+#define DESELECT_QUERY_MODE(_base_) do{*(unsigned short volatile *)((_base_) & 0xFFF00000) = 0xF0;\
+ *(unsigned short volatile *)((_base_) & 0xFFF00000) = 0xFF;}while(0)
+
+#define CFI_READ(_base_, _offset_, _var_) do{_var_ = *(unsigned short volatile *)(((_base_) & 0xFFF00000) + ((_offset_) << 1));}while(0)
+#define CFI_WRITE(_base_, _offset_, _var_) do{*(unsigned short volatile *)(((_base_) /*& 0xFFF00000*/) + ((_offset_) << 1)) = (_var_);}while(0)
+
+#define AMD_CMD_SET 0x0002
+#define INTEL_CMD_SET 0x0003
+
+struct cfi_erase_block_region_info {
+ unsigned int size;
+ unsigned int num;
+};
+
+
+struct cfi_command{
+ int (*write) (unsigned int address, unsigned char *data, unsigned int size);
+ int (*erase) (unsigned int address, unsigned int size);
+};
+
+extern unsigned int cfiGetBlockSize(unsigned int address);
+extern unsigned int cfiGetFlashSize(void);
+extern int cfiGetFlashInfo(void);
+extern struct cfi_command cfiCmd;
+
+#endif // #ifdef __CFI_H__
diff --git a/uClinux-2.4.20-uc1/drivers/block/wbflash/flash.c b/uClinux-2.4.20-uc1/drivers/block/wbflash/flash.c
new file mode 100644
index 0000000..d13d4a8
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/block/wbflash/flash.c
@@ -0,0 +1,1056 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2003 Windond Electronics Corp.
+ * All rights reserved.
+ *
+ * $Workfile: flash.c $
+ *
+ * $Author: andy $
+ ******************************************************************************/
+/*
+ * $History: flash.c $
+ *
+ * ***************** Version 10 *****************
+ * User: Wschang0 Date: 04/01/07 Time: 11:34a
+ * Updated in $/W90N740/FIRMWARE/WBLv1_1/Src
+ * Increase the timeout count in polling16 function to avoid early timeout
+ * in W29LV800BT
+ *
+ * ***************** Version 9 *****************
+ * User: Wschang0 Date: 03/12/25 Time: 4:06p
+ * Updated in $/W90N740/FIRMWARE/WBLv1_1/Src
+ * Add W29LV800BT, W29LV160DT, W29LV320DT
+ * Remove the FLASH_NUM
+ *
+ * ***************** Version 8 *****************
+ * User: Wschang0 Date: 03/12/03 Time: 5:16p
+ * Updated in $/W90N740/FIRMWARE/WBLv1_1/Src
+ * Add MX29LV160BT/TT
+ * Fixed MX28F160C3BT/TT.
+ * The MX28F160C3 sectors are default to be locked, thus it needs unlock
+ * it before write/erase it.
+ *
+ * ***************** Version 7 *****************
+ * User: Wschang0 Date: 03/11/05 Time: 11:03a
+ * Updated in $/W90N740/FIRMWARE/WBLv1_1/Src
+ * Add MX28F160C3T & MX28F160C3B
+ *
+ * ***************** Version 6 *****************
+ * User: Wschang0 Date: 03/09/26 Time: 2:30p
+ * Updated in $/W90N740/FIRMWARE/WBLv1_1/Src
+ * Correct the flash name of SST39VF160 in the flash[] table
+ *
+ * ***************** Version 5 *****************
+ * User: Wschang0 Date: 03/08/27 Time: 1:41p
+ * Updated in $/W90N740/FIRMWARE/WBLv1_1/Src
+ * Add FlushDCache to Write/Erase functions to avoid data cache
+ * incohereance after Write/Erase flash.
+ *
+ * ***************** Version 4 *****************
+ * User: Wschang0 Date: 03/08/27 Time: 11:28a
+ * Updated in $/W90N740/FIRMWARE/WBLv1_1/Src
+ * Add SST 39VF160 flash type
+ *
+ * ***************** Version 3 *****************
+ * User: Wschang0 Date: 03/08/20 Time: 1:39p
+ * Updated in $/W90N740/FIRMWARE/WBLv1_1/Src
+ *
+ * ***************** Version 2 *****************
+ * User: Wschang0 Date: 03/08/20 Time: 11:53a
+ * Updated in $/W90N740/FIRMWARE/WBLv1_1/Src
+ * Add VSS header
+ */
+#include <asm/arch/flash.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+// Update Note:
+// 8/19, 2003: Add Flash Tyep W28J800BT, W28J320TT, Fix the PID of W28J320BT
+// 8/07, 2003: W39L010 was protected when the erase address not in offset 0
+// 7/24, 2003: Remove the redundant code. Time-out check, for reliability
+
+UINT32 _flash_size = 0;
+
+#define DELAY_1US 20
+
+#define TIMEOUT 8000000UL
+static int normal_polling(unsigned int addr, unsigned short mask)
+{
+ unsigned short rdata;
+ unsigned int cnt;
+
+ rdata=inph(addr)&mask;
+ cnt=0;
+ while( rdata != mask )
+ {
+ rdata=inph(addr)&mask;
+ if( cnt++ > TIMEOUT ) return -1; // time-out
+ }
+
+ return 0;
+}
+
+static int polling16(unsigned int addr, unsigned short data)
+{
+ unsigned short rdata;
+ int timeout=0x600000;
+
+ rdata=inph(addr);
+ while( rdata != data )
+ {
+ rdata=inph(addr);
+ if( (rdata&0x20) || !(timeout--) )
+ {
+ rdata=inph(addr);
+ if( rdata != data )
+ {
+ //printf("polling time-out: %x\n",rdata);
+ return -1; //polling time-out
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static INT CheckDataWidth(INT w)
+{
+ INT extio_flag=0;
+ // check if the platform (the Flash ROM is not in 0x7F000000)
+ if( (ROMCON&0xFF000000)==0xFC000000 )extio_flag=1;
+
+ switch(w)
+ {
+ case 8:
+ if(extio_flag)
+ {
+ if( (EXT3CON&0x3)== 0x1 )return 1;
+ else return 0;
+ }
+ else
+ {
+ if( (ROMCON&0xC)== 0x0 )return 1;
+ else return 0;
+ }
+ case 16:
+ if(extio_flag)
+ {
+ if( (EXT3CON&0x3)== 0x2 )return 1;
+ else return 0;
+ }
+ else
+ {
+ if( (ROMCON&0xC)== 0x4 )return 1;
+ else return 0;
+ }
+ case 32:
+ if(extio_flag)
+ {
+ if( (EXT3CON&0x3)== 0x3 )return 1;
+ else return 0;
+ }
+ else
+ {
+ if( (ROMCON&0xC)== 0x8 )return 1;
+ else return 0;
+ }
+ default:
+ return 0;
+ }
+
+}
+
+
+void FlashDelay(UINT32 delay)
+{
+ volatile UINT32 i;
+ for(i=0;i<delay*DELAY_1US;i++);
+}
+
+static __inline void FlushDCache()
+{
+ /* Flush Entire DCache */
+ if( CAHCNF_R & 0x6 ) /* If write buffer or data cache is enabled */
+ {
+ CAHCON_R=0x86;
+ while( CAHCON_R );
+ }
+
+}
+
+
+
+INT BlockLock_W28J800TT(UINT32 address, UINT32 op)
+{
+ address|=0x80000000;
+
+ if( op==BLOCK_LOCK )
+ {
+ outph(address,0x70);
+ while( !(inph(address)&0x80) );
+ outph(address,0x60);
+ outph(address,0x01);
+ while( !(inph(address)&0x80) );
+ outph(address,0xFFFF);
+ }
+ else if( op==BLOCK_UNLOCK )
+ {
+ outph(address,0x70);
+ while( !(inph(address)&0x80) );
+ outph(address,0x60);
+ outph(address,0xD0);
+ while( !(inph(address)&0x80) );
+ outph(address,0xFFFF);
+ }
+ return 0;
+}
+
+INT BlockSize_W28J800TT(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address >= 0xF0000 )
+ {
+ if( address < _flash_size )
+ return 0x2000;
+ else
+ return 0;
+ }
+ else
+ return 0x10000;
+}
+
+INT BlockSize_W28J800BT(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < 0x10000 )
+ return 0x2000;
+ else
+ {
+ if( address < _flash_size )
+ return 0x10000;
+ else
+ return 0;
+ }
+}
+
+
+INT BlockErase_W28J800TT(UINT32 address,UINT32 size)
+{
+ int status;
+ if( (address&(size-1))!=0x0 )return -1;// not in the start of a block
+
+ BlockLock_W28J800TT(address,BLOCK_UNLOCK); // The intel flash sector is default to be locked
+
+ address|=0x80000000;
+ outph(address,0x70);
+ status=normal_polling( address, 0x80 );
+ if( status < 0 )return -1; // polling time-out
+ outph(address,0x20);
+ outph(address,0xD0);
+ status=normal_polling( address, 0x80 );
+ if( status < 0 )return -1; // polling time-out
+ outph(address,0xFFFF);
+ FlushDCache();
+
+ return 0;
+}
+
+INT BlockWrite_W28J800TT(UINT32 address, UCHAR * data, UINT32 size)
+{
+ UINT32 i;
+ int status;
+ address|=0x80000000;
+ BlockLock_W28J800TT(address,BLOCK_UNLOCK); // The MX28F160C3 sector is default to be locked
+ for(i=address;i<address+size;i+=2)
+ {
+ outph(i,0x40);
+ outph(i,*((UINT16 *)data));
+ //while( !(inph(i)&0x80) );
+ status=normal_polling( i, 0x80 );
+ if( status < 0 )return -1; // polling time-out
+ data+=2;
+ }
+ outph(address,0xFFFF);
+ FlushDCache();
+
+ return 0;
+}
+
+INT ReadPID_Winbond(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+ if( !CheckDataWidth(16) )return -1;
+
+ address|=0x80000000;
+ outph(address,0x70);
+ FlashDelay(50000); // delay 50ms
+ outph(address,0x90);
+ *pid0=inph(address);
+ *pid1=inph(address+1);
+ outph(address,0xFFFF);
+
+ return 0;
+}
+
+INT ReadPID_W28J800TT(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+ int status;
+ status=ReadPID_Winbond(address,pid0,pid1);
+ if( status < 0 )return -1; // not x16 flash
+ _flash_size=0x100000;
+ return 0;
+}
+
+INT ReadPID_W28J800BT(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+ int status;
+ status=ReadPID_Winbond(address,pid0,pid1);
+ if( status < 0 )return -1; // not x16 flash
+ _flash_size=0x100000;
+ return 0;
+}
+
+INT ReadPID_W28J160TT(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+ int status;
+ status=ReadPID_Winbond(address,pid0,pid1);
+ if( status < 0 )return -1; // not x16 flash
+ _flash_size=0x200000;
+ return 0;
+}
+
+INT ReadPID_W28J320TT(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+ int status;
+ status=ReadPID_Winbond(address,pid0,pid1);
+ if( status < 0 )return -1; // not x16 flash
+ _flash_size=0x400000;
+ return 0;
+}
+
+
+
+
+INT BlockSize_W28J320TT(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address >= 0x3F0000 )
+ {
+ if( address < _flash_size )
+ return 0x2000;
+ else
+ return 0;
+ }
+ else
+ return 0x10000;
+}
+
+
+INT BlockSize_W28J320BT(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < 0x10000 )
+ return 0x2000;
+ else
+ {
+ if( address < _flash_size )
+ return 0x10000;
+ else
+ return 0;
+ }
+}
+
+
+
+INT BlockSize_W28J160BT(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < 0x10000 )
+ return 0x2000;
+ else
+ {
+ if( address < _flash_size )
+ return 0x10000;
+ else
+ return 0;
+ }
+}
+
+INT BlockSize_W28J160TT(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address >= 0x1F0000 )
+ {
+ if( address < 0x200000 )
+ return 0x2000;
+ else
+ return 0;
+ }
+ else
+ return 0x10000;
+}
+
+
+INT BlockLock_W39L010(UINT32 address, UINT32 op)
+{
+ return -1;
+}
+
+INT BlockSize_W39L010(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < _flash_size )
+ return 0x20000;
+ else
+ return 0;
+}
+
+INT BlockErase_W39L010(UINT32 address,UINT32 size)
+{
+ UINT32 addr1,addr2;
+
+ if( (address&(0x20000-1))!=0x0 )return -1;// not in the start of flash
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555);
+ addr2=(address&0xFFF00000)+(0x2AAA);
+
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0x80);
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0x10);
+ while( (inpb(address)&0x80)!=0x80 );
+
+ FlushDCache();
+
+ return 0;
+}
+
+INT BlockWrite_W39L010(UINT32 address, UCHAR * data, UINT32 size)
+{
+ UINT32 i;
+ UINT32 addr1, addr2;
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555);
+ addr2=(address&0xFFF00000)+(0x2AAA);
+ for(i=address;i<address+size;i++)
+ {
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0xA0);
+ outpb(i,*data);
+ while( !((inpb(i)&0x80)==(*data&0x80)) );
+ data++;
+ }
+ FlushDCache();
+
+ return 0;
+}
+
+INT ReadPID_W39L010(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+ UINT32 addr1, addr2;
+
+ if( !CheckDataWidth(8) )return -1;
+
+
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555);
+ addr2=(address&0xFFF00000)+(0x2AAA);
+
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0x80);
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0x60);
+ *pid0=inpb(address);
+ *pid1=inpb(address+1);
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0xF0);
+ outpb(address,0xFF);
+
+ _flash_size=0x20000;
+
+ return 0;
+}
+
+
+
+INT BlockLock_W29EE011(UINT32 address, UINT32 op)
+{
+ return -1;
+}
+
+
+INT BlockSize_W29EE011(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < _flash_size )
+ return 0x80;
+ else
+ return 0;
+}
+
+INT BlockErase_W29EE011(UINT32 address,UINT32 size)
+{
+ UINT32 addr1,addr2;
+ static INT flag=0;
+
+ if( flag )return 0;
+
+ flag=1;
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555);
+ addr2=(address&0xFFF00000)+(0x2AAA);
+
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0x80);
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0x10);
+ FlashDelay(50000); // delay 50ms
+
+ FlushDCache();
+
+ return 0;
+}
+
+INT BlockWrite_W29EE011(UINT32 address, UCHAR * data, UINT32 size)
+{
+ UINT32 i;
+ UINT32 addr1, addr2;
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555);
+ addr2=(address&0xFFF00000)+(0x2AAA);
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0xA0);
+ for(i=0;i<size;i++)
+ outpb(address+i,*(data+i));
+ while( inpb(address+i-1)!=*(data+i-1) );
+ FlushDCache();
+
+ return 0;
+}
+
+INT ReadPID_W29EE011(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+ UINT32 addr1, addr2;
+
+ if( !CheckDataWidth(8) )return -1;
+
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555);
+ addr2=(address&0xFFF00000)+(0x2AAA);
+
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0x80);
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0x60);
+ FlashDelay(10);//delay 10 us
+ *pid0=inpb(address);
+ *pid1=inpb(address+1);
+ outpb(addr1,0xAA);
+ outpb(addr2,0x55);
+ outpb(addr1,0xF0);
+ FlashDelay(10);//delay 10 us
+ outpb(address,0xFF);
+
+ _flash_size=0x20000;
+
+ return 0;
+}
+
+
+
+INT BlockLock_AM29LV800BB(UINT32 address, UINT32 op)
+{
+ return -1;
+}
+
+
+INT BlockSize_AM29LV800BB(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < 0x4000 )
+ return 0x4000;
+ else if( address < 0x6000 )
+ return 0x2000;
+ else if( address < 0x8000 )
+ return 0x2000;
+ else if( address < 0x10000 )
+ return 0x8000;
+ else
+ {
+ if( address < _flash_size )
+ return 0x10000;
+ else
+ return 0;
+ }
+}
+
+INT BlockSize_AM29LV800BT(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < 0x0F0000 )
+ return 0x10000;
+ else if( address < 0xF8000 )
+ return 0x8000;
+ else if( address < 0xFA000 )
+ return 0x2000;
+ else if( address < 0xFC000 )
+ return 0x2000;
+ else
+ {
+ if( address < _flash_size )
+ return 0x4000;
+ else
+ return 0;
+ }
+}
+INT BlockErase_AM29LV800BB(UINT32 address,UINT32 size)
+{
+ UINT32 addr1,addr2;
+ INT status;
+
+ if( (address&(size-1))!=0x0 )return -1;// not in the start of a block
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555<<1);
+ addr2=(address&0xFFF00000)+(0x2AAA<<1);
+
+ outph(addr1,0xAA);
+ outph(addr2,0x55);
+ outph(addr1,0x80);
+ outph(addr1,0xAA);
+ outph(addr2,0x55);
+ outph(address,0x30);
+ //while( (inph(address))!=0xFFFF );
+ status=polling16(address, 0xFFFF);
+
+ FlushDCache();
+
+ return status;
+}
+
+INT BlockWrite_AM29LV800BB(UINT32 address, UCHAR * data, UINT32 size)
+{
+ UINT32 i;
+ UINT32 addr1, addr2;
+ INT status;
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555<<1);
+ addr2=(address&0xFFF00000)+(0x2AAA<<1);
+
+ for(i=address;i<address+size;i+=2)
+ {
+ outph(addr1,0xAA);
+ outph(addr2,0x55);
+ outph(addr1,0xA0);
+ outph(i,*((UINT16*)data));
+ status=polling16( i, (*(UINT16 *)data));
+ if( status < 0 )return status; // time-out
+ data+=2;
+ }
+
+ outph(address,0xFFFF);
+ FlushDCache();
+
+ return status;
+}
+
+
+INT ReadPID_AM29LV(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+ UINT32 addr1, addr2;
+
+ if( !CheckDataWidth(16) )return -1;
+
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555<<1);
+ addr2=(address&0xFFF00000)+(0x2AAA<<1);
+
+ outph(addr1,0xAA);
+ outph(addr2,0x55);
+ outph(addr1,0x90);
+ *pid0=(char)inph(address);
+ *pid1=(char)inph((address+2));
+ outph(address,0xFFFF);
+
+ return 0;
+}
+
+
+INT ReadPID_AM29LV800BB(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+
+ ReadPID_AM29LV(address, pid0, pid1);
+ _flash_size=0x100000;
+
+ return 0;
+}
+
+INT ReadPID_AM29LV160DB(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+
+ ReadPID_AM29LV(address, pid0, pid1);
+ _flash_size=0x200000;
+
+ return 0;
+}
+
+INT ReadPID_AM29LV320DB(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+
+ ReadPID_AM29LV(address, pid0, pid1);
+ _flash_size=0x400000;
+
+ return 0;
+}
+
+
+
+INT BlockSize_AM29LV160DB(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < 0x4000 )
+ return 0x4000;
+ else if( address < 0x6000 )
+ return 0x2000;
+ else if( address < 0x8000 )
+ return 0x2000;
+ else if( address < 0x10000 )
+ return 0x8000;
+ else
+ {
+ if( address < _flash_size )
+ return 0x10000;
+ else
+ return 0;
+ }
+}
+
+INT BlockSize_AM29LV160DT(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < 0x1F0000 )
+ return 0x10000;
+ else if( address < 0x1F8000 )
+ return 0x8000;
+ else if( address < 0x1FA000 )
+ return 0x2000;
+ else if( address < 0x1FC000 )
+ return 0x2000;
+ else
+ {
+ if( address < _flash_size )
+ return 0x4000;
+ else
+ return 0;
+ }
+}
+INT BlockSize_AM29LV320DB(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < 0x10000 )
+ return 0x2000;
+ else
+ {
+ if( address < _flash_size )
+ return 0x10000;
+ else
+ return 0;
+ }
+}
+
+INT BlockSize_AM29LV320DT(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < 0x3F0000 )
+ return 0x10000;
+ else
+ {
+ if( address < _flash_size )
+ return 0x2000;
+ else
+ return 0;
+ }
+}
+
+INT BlockLock_E28F640(UINT32 address, UINT32 op)
+{
+
+ address|=0x80000000;
+
+ if( op==BLOCK_LOCK )
+ {
+ outph(address,0x60);
+ outph(address,0x01);
+ while( !(inph(address)&0x80) );
+ outph(address,0xFFFF);
+ }
+ else if( op==BLOCK_UNLOCK )
+ {
+ outph(address,0x60);
+ outph(address,0xD0);
+ while( !(inph(address)&0x80) );
+ outph(address,0xFFFF);
+ }
+
+ return 0;
+}
+
+INT BlockSize_E28F640(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < _flash_size )
+ return 0x10000;
+ else
+ return 0;
+}
+
+INT BlockErase_E28F640(UINT32 address,UINT32 size)
+{
+ UINT32 i,j,tmp;
+ CHAR * buffer;
+
+ address|=0x80000000;
+ buffer = kmalloc(128*1024,GFP_KERNEL);
+ if(!buffer)
+ return 1;
+ // backup the data
+ j=0xFFFF;
+ if( (address & FLASH_BLOCK_SIZE) )
+ {
+
+ for(i=0;i<FLASH_BLOCK_SIZE/2;i++)
+ {
+ tmp=*((volatile unsigned short *)(address-FLASH_BLOCK_SIZE)+i);
+ *((volatile unsigned short *)buffer+i)=tmp;
+ j&=tmp;
+ }
+ }
+ else
+ {
+ for(i=0;i<FLASH_BLOCK_SIZE/2;i++)
+ {
+ tmp=*((volatile unsigned short *)(address+FLASH_BLOCK_SIZE)+i);
+ *((volatile unsigned short *)buffer+i)=tmp;
+ j&=tmp;
+ }
+ }
+
+
+ outph(address,0x20);
+ outph(address,0xD0);
+ while( !(inph(address)&0x80) );
+ outph(address,0xFFFF);
+
+
+ // write back the data
+ if( (j&0xFFFF)!=0xFFFF )
+ {
+ if( (address & FLASH_BLOCK_SIZE) )
+ BlockWrite_E28F640(address-FLASH_BLOCK_SIZE, (UCHAR *)buffer, FLASH_BLOCK_SIZE);
+ else
+ BlockWrite_E28F640(address+FLASH_BLOCK_SIZE, (UCHAR *)buffer, FLASH_BLOCK_SIZE);
+ }
+ FlushDCache();
+ kfree(buffer);
+ return 0;
+}
+
+INT BlockWrite_E28F640(UINT32 address, UCHAR * data, UINT32 size)
+{
+ UINT32 i;
+#if 0
+ UINT32 pdata,j;
+
+ address|=0x80000000;
+
+ do{
+ outph(address, 0xE8);
+ }while( !(inph(address)&0x80) );
+
+ i=size;
+ while(i)
+ {
+ if( i < 32 )
+ {
+ outph(address, i);
+ for(j=0;j<i/2;j++)
+ outph(address+j, *((unsigned short *)pdata+j));
+ pdata+=i;
+ i=0;
+ }
+ else
+ {
+ outph(address, 32);
+ for(j=0;j<16;j++)
+ outph(address+j, *((unsigned short *)pdata+j));
+ pdata+=32;
+ i-=32;
+ }
+ outph(address, 0xD0);
+ while( !(inph(address)&0x80) );
+ }
+
+#else
+ address|=0x80000000;
+
+ for(i=address;i<address+size;i+=2)
+ {
+ outph(i,0x40);
+ outph(i,*((UINT16 *)data));
+ while( !(inph(i)&0x80) );
+ data+=2;
+ }
+
+ outph(address,0xFFFF);
+#endif
+
+ FlushDCache();
+ return 0;
+}
+
+INT ReadPID_E28F640(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+ if( !CheckDataWidth(16) )return -1;
+
+ outph(address,0x90);
+ *pid0=inph(address);
+ *pid1=inph(address+1);
+ outph(address,0xFFFF);
+
+ _flash_size=0x800000;
+
+ return 0;
+}
+
+
+INT BlockSize_SST39VF160(UINT32 address)
+{
+ address-=FLASH_BASE;
+ address&=0x7FFFFFFF;
+ if( address < _flash_size )
+ return 0x10000;
+ else
+ return 0;
+
+}
+
+
+INT ReadPID_SST39VF160(UINT32 address, UCHAR *pid0, UCHAR *pid1)
+{
+
+ ReadPID_AM29LV(address, pid0, pid1);
+ outph(address, 0x00F0 ); /* Exit Software ID mode */
+ _flash_size=0x200000;
+
+ return 0;
+}
+
+INT BlockErase_SST39VF160(UINT32 address,UINT32 size)
+{
+ UINT32 addr1,addr2;
+ INT status;
+
+ if( (address&(size-1))!=0x0 )return -1;// not in the start of a block
+
+ address|=0x80000000;
+ addr1=(address&0xFFF00000)+(0x5555<<1);
+ addr2=(address&0xFFF00000)+(0x2AAA<<1);
+
+ outph(addr1,0xAA);
+ outph(addr2,0x55);
+ outph(addr1,0x80);
+ outph(addr1,0xAA);
+ outph(addr2,0x55);
+ outph(address,0x50);
+ status=polling16(address, 0xFFFF);
+
+ FlushDCache();
+
+ return status;
+}
+
+INT BlockErase_MX28F160C3B(UINT32 address,UINT32 size)
+{
+ int status;
+ if( (address&(size-1))!=0x0 )return -1;// not in the start of a block
+
+ BlockLock_W28J800TT(address,BLOCK_UNLOCK); // The MX28F160C3 sector is default to be locked
+
+ address|=0x80000000;
+ outph(address,0x70);
+ status=normal_polling( address, 0x80 );
+ if( status < 0 )return -1; // polling time-out
+ outph(address,0x20);
+ outph(address,0xD0);
+ status=normal_polling( address, 0x80 );
+ if( status < 0 )return -1; // polling time-out
+ outph(address,0xFFFF);
+ FlushDCache();
+
+ return 0;
+}
+
+INT BlockWrite_MX28F160C3B(UINT32 address, UCHAR * data, UINT32 size)
+{
+ UINT32 i;
+ int status;
+
+ BlockLock_W28J800TT(address,BLOCK_UNLOCK); // The MX28F160C3 sector is default to be locked
+
+ address|=0x80000000;
+ for(i=address;i<address+size;i+=2)
+ {
+ outph(i,0x40);
+ outph(i,*((UINT16 *)data));
+ //while( !(inph(i)&0x80) );
+ status=normal_polling( i, 0x80 );
+ if( status < 0 )return -1; // polling time-out
+ data+=2;
+ }
+ outph(address,0xFFFF);
+ FlushDCache();
+
+ return 0;
+}
+
+UINT32 FlashSize()
+{
+ return _flash_size;
+}
+
+
+
+
diff --git a/uClinux-2.4.20-uc1/drivers/block/wbflash/flash_u.c b/uClinux-2.4.20-uc1/drivers/block/wbflash/flash_u.c
new file mode 100644
index 0000000..55e6f52
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/block/wbflash/flash_u.c
@@ -0,0 +1,246 @@
+#include <asm/semaphore.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <asm/fcntl.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include <asm/arch/flash.h>
+#include <asm/arch/bib.h>
+
+#include <linux/init.h>
+#include "cfi.h"
+
+static int Init_WinbondFlash(void);
+
+#define BL_PHY 0
+#define BL_IC_PLUS 1
+#define BL_MARVELL6052 2
+
+tbl_info info;
+DECLARE_MUTEX(spare_lock);
+
+#define _DEBUG
+#undef _DEBUG
+
+#define MALLOC(x) kmalloc((x), GFP_KERNEL)
+#define FREE kfree
+#define MEMCPY memcpy //or use "copy_to_user"
+
+//yyang1 030605 ???
+int __init Init_WinbondFlash(void)
+{
+
+ if (cfiGetFlashInfo() == -1) {
+ printk("No supported flash detected!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+asmlinkage int sys_ReadWinbondFlash(unsigned long pos, unsigned long length, char * buffer)
+{
+ // if(!pCurFlash)
+ // return -EINVAL;
+ if(cfiGetFlashSize() <= 0)
+ return(-EINVAL);
+
+#ifdef _DEBUG
+ printk("\nWinbondFlash Read: pos = %x, length = %d, buffer = 0x%x.\n", pos, length, buffer);
+#endif
+ if(length%2)
+ length++;
+ down(&spare_lock);
+ if(copy_to_user(buffer, (void*)(FLASH_BASE | pos), length))
+ {
+ up(&spare_lock);
+ return -EFAULT;
+ }
+ up(&spare_lock);
+ return length;
+}
+
+static int _FlashWrite(char *pcBuf, int iBufLen, int iOffset);
+asmlinkage int sys_WriteWinbondFlash(unsigned long pos, unsigned long length, char * buffer)
+{
+ // if(!pCurFlash)
+ // return -EINVAL;;
+
+ if(cfiGetFlashSize() <= 0)
+ return(-EINVAL);
+
+#ifdef _DEBUG
+ printk("\nWinbondFlash Write: pos = %x, length = %d, buffer = 0x%x.\n", pos, length, buffer);
+#endif
+
+ return _FlashWrite(buffer, length, pos);
+}
+
+asmlinkage int sys_WinbondFlashBlockSize(unsigned long pos)
+{
+ if(cfiGetFlashSize() == 0)
+ return -EINVAL;;
+
+#ifdef _DEBUG
+ printk("\nWinbondFlash BlockSize: pos = %d.\n", pos);
+#endif
+
+ pos |= FLASH_BASE;
+ return cfiGetBlockSize(pos);
+}
+asmlinkage int sys_WinbondFlashTotalSize(void)
+{
+ printk("sys_WinbondFlashTotalSize\n");
+ return cfiGetFlashSize();
+}
+asmlinkage int sys_WinbondFlashBase(void)
+{
+ return FLASH_BASE;
+}
+
+static int _FlashWrite(char *pcBuf, int iBufLen, int iOffset)
+{
+ // unsigned long flags;
+ UINT32 blockSize,src,dest;
+ INT i;
+
+ if (cfiGetFlashSize() == 0) return -EINVAL;
+
+#ifdef _DEBUG
+ printk("\nWinbondFlash _FlashWrite: pos = %x, length = %d, buffer = 0x%x.\n", iOffset, iBufLen, pcBuf);
+#endif
+
+ //i = iBufLen;
+ i=(iBufLen%2)?(iBufLen+1):iBufLen;
+
+ src = (UINT32)pcBuf;
+ dest = (iOffset%2)?(iOffset+1):iOffset | FLASH_BASE;
+
+ //CSR_WRITE(WTCR, (CSR_READ(WTCR)&0xF7)|0x01);//clyu reset watch dog
+
+ while (i>0)
+ {
+ volatile UINT32 buf;
+ volatile UINT32 addr;
+ UINT32 count;
+ int len;
+ blockSize = cfiGetBlockSize(dest);
+ if(blockSize<=0)
+ return 0;
+
+#ifdef _DEBUG
+//#if 1
+ printk("\n_FlashWrite:dest:%x,cur blockSize:%x\n",dest,blockSize);
+#endif
+ addr=dest&~(blockSize-1);
+ for(len=0;len<i&&(len+dest-addr)<blockSize;len+=2)
+ if(inph((dest+len))!=0xFFFF)
+ {
+#ifdef _DEBUG
+ printk("01 inph(%x):%x\n",dest+len,inph(dest+len));
+#endif
+ if((dest&(blockSize-1))||(dest+i-addr)<=blockSize)
+ {
+ buf=(UINT32)MALLOC(blockSize);
+ if(buf != 0)
+ {
+#ifdef _DEBUG
+ printk("\n_FlashWrite:dest:%x,addr:%x,buf:%x\n",dest,addr,buf);
+#endif
+ //memset((UCHAR *)buf,0xFF,blockSize);
+ MEMCPY((UCHAR *)buf,(UCHAR *)addr,blockSize);
+
+ //MEMCPY((UCHAR *)buf,(UCHAR *)addr,dest-addr);
+ if(i<blockSize-(dest-addr))
+ count=i;
+ else
+ count=blockSize-(dest-addr);
+
+#ifdef _DEBUG
+ printk("\n_FlashWrite:i:%d,count:%d,dest:%x,addr:%x,len:%d\n",i,count,dest,addr,len);
+#endif
+
+ MEMCPY((void *)(buf+(dest-addr)),(void *)src,count);
+
+ down(&spare_lock);
+ //save_flags(flags); cli();//prevent closing watch dog interrupt
+#ifdef _DEBUG
+ printk("%s:%d BlockErase,%x\n",__FILE__,__LINE__,inph(dest+len));
+#endif
+ cfiCmd.erase(addr, blockSize);
+#ifdef _DEBUG
+ printk("02 inph(%x):%x\n",dest+len,inph(dest+len));
+ printk("%s:%d BlockWrite\n",__FILE__,__LINE__);
+#endif
+ cfiCmd.write(addr, (UCHAR *)buf, blockSize);
+#ifdef _DEBUG
+ printk("03 inph(%x):%x\n",dest+len,inph(dest+len));
+#endif
+ //restore_flags(flags);
+ up(&spare_lock);
+
+ FREE((void *)buf);
+ blockSize = count;
+ }
+ else
+ {
+ return (iBufLen - i);
+ }
+ }
+ else
+ {
+ down(&spare_lock);
+ //save_flags(flags); cli();
+#ifdef _DEBUG
+ printk("\nb_FlashWrite:i:%d,count:%d,dest:%x,addr:%x,%x\n",i,count,dest,addr,inph(dest+len));
+#endif
+ cfiCmd.erase(dest, blockSize);
+ cfiCmd.write(dest, (UCHAR *)src, blockSize);
+
+ //restore_flags(flags);
+ up(&spare_lock);
+ }
+ break;
+ }
+ if((len>=i)||((len+dest-addr)>=cfiGetBlockSize(dest)))
+ {
+ if((dest&(blockSize-1))||(dest+i-addr)<=blockSize)
+ {
+#ifdef _DEBUG
+printk("Write direct\n");
+#endif
+ if(i<blockSize-(dest-addr))
+ count=i;
+ else
+ count=blockSize-(dest-addr);
+ down(&spare_lock);
+ //save_flags(flags); cli();
+ cfiCmd.write(dest, (UCHAR *)src, count);
+ //restore_flags(flags);
+ up(&spare_lock);
+ blockSize=count;
+ }
+ else
+ {
+#ifdef _DEBUG
+printk("Write direct one block\n");
+#endif
+ down(&spare_lock);
+ //save_flags(flags); cli();
+ cfiCmd.write(dest, (UCHAR *)src, blockSize);
+ //restore_flags(flags);
+ up(&spare_lock);
+ }
+ }
+ src+=blockSize;
+ dest+=blockSize;
+ i-=blockSize;
+ }
+
+ return (iBufLen);
+}
+
+module_init(Init_WinbondFlash);
diff --git a/uClinux-2.4.20-uc1/drivers/block/wbflash/image.c b/uClinux-2.4.20-uc1/drivers/block/wbflash/image.c
new file mode 100644
index 0000000..ea79b7d
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/block/wbflash/image.c
@@ -0,0 +1,178 @@
+#include <asm/arch/flash.h>
+#include <asm/semaphore.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <asm/fcntl.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include "cfi.h"
+
+extern struct semaphore spare_lock;
+
+
+
+int FindFooter(tfooter *** image_footer)
+{
+ static tfooter * image_footers[MAX_FOOTER_NUM];
+ unsigned int footer_num=0;
+ //int flash_type;
+ unsigned int blocksize,addr,i;
+ tfooter * footer;
+ unsigned int * p;
+ unsigned long long sum;
+
+ *image_footer=image_footers;
+
+ if(cfiGetFlashSize() == 0 )
+ return -1;
+
+ addr=FLASH_BASE+BOOTER_BLOCK_LENGTH; // the 64kb of flash was preservied to boot loader
+ blocksize=cfiGetBlockSize(addr);
+ while( blocksize!= 0 )
+ {
+ addr+=blocksize;
+ footer=(tfooter *)(addr-sizeof(tfooter));
+ if(footer->signature==SIGNATURE_WORD)
+ {
+ p=(unsigned int *)footer;
+ sum=0;
+ for(i=0;i<sizeof(tfooter)/4-1;i++)// Not include the checksum
+ {
+ sum+=*(p+i);
+ }
+ sum = ~((sum&(-1LU))+(sum>>32));
+ if( (unsigned int)sum == footer->checksum )
+ image_footers[footer_num++]=footer;
+ }
+
+ blocksize=cfiGetBlockSize(addr);
+ }
+
+ return footer_num;
+}
+
+/*1 success 0 failure*/
+asmlinkage int sys_FindImage(unsigned int image_num, tfooter ** image_footer)
+{
+ int footer_num;
+ tfooter ** footer;
+ int i;
+
+
+ footer_num=FindFooter(&footer);
+ if(footer_num<=0)
+ {
+ return 0;
+ }
+
+ for(i=0;i<footer_num;i++)
+ {
+ if( footer[i]->num == image_num )
+ {
+ *image_footer=footer[i];
+ return 1;
+ }
+ }
+
+
+ return 0;
+}
+
+
+
+/*0 success*/
+asmlinkage int sys_DelImage(unsigned int image_num)
+{
+ unsigned int flash_type;
+ tfooter * footer;
+ unsigned int addr;
+ unsigned int blocksize;
+ unsigned int end;
+ unsigned long flags;
+
+ if( sys_FindImage( image_num, &footer) )
+ {
+ if(cfiGetFlashSize() == 0) {
+ printk("delete failed\n");
+ return -EINVAL;
+ }
+ addr=footer->base;
+ blocksize = cfiGetBlockSize(addr);
+ end=footer->base+footer->length;
+
+ end+=sizeof(tfooter);
+
+ //printk("end at:%x", end);
+
+ if((end & (blocksize-1)) == 0 )
+ end -= blocksize;
+ else
+ end = end&(~(blocksize-1));
+
+ //printk("end at:%x", end);
+
+
+ {
+ down(&spare_lock);
+ save_flags(flags); cli();
+
+ cfiGetBlockSize(end);
+ cfiCmd.erase(end,blocksize);
+ restore_flags(flags);
+ up(&spare_lock);
+ }
+
+ return 0;
+ }
+ printk("delete image failed\n");
+ return -EINVAL;
+}
+
+/*0 success 1 Corrupt*/
+asmlinkage int sys_CorruptCheck(tfooter * image_footer)
+{
+ int footer_num;
+ tfooter ** footer;
+ int i;
+ unsigned int a0,a1,b0,b1;
+
+ if( image_footer->base < (FLASH_BASE+BOOTER_BLOCK_LENGTH) )return 1;
+ if( image_footer->base+image_footer->length > (FLASH_BASE+cfiGetFlashSize()) )return 1;
+ footer_num=FindFooter(&footer);
+
+ if(footer_num<=0)
+ return 0;
+ for(i=0;i<footer_num;i++)
+ {
+ if( image_footer->num == footer[i]->num ) {
+ printk("iamge exists");
+ return 1;
+ }
+ }
+
+
+ b0=image_footer->base;
+ if( FLASH_BLOCK_SIZE-(image_footer->length%FLASH_BLOCK_SIZE) < sizeof(tfooter) )
+ b1=image_footer->base+image_footer->length+FLASH_BLOCK_SIZE;
+ else
+ b1=image_footer->base+image_footer->length;
+ for(i=0;i<footer_num;i++)
+ {
+ a0=footer[i]->base;
+ if( (FLASH_BLOCK_SIZE-(footer[i]->length%FLASH_BLOCK_SIZE) < sizeof(tfooter)) || !(footer[i]->length&(FLASH_BLOCK_SIZE-1)) )
+ a1=footer[i]->base+footer[i]->length+FLASH_BLOCK_SIZE;
+ else
+ a1=footer[i]->base+footer[i]->length;
+ if( (b0 >= a0) && (b0 < a1) )return 1;
+ if( (b1 >= a0) && (b1 < a1) )return 1;
+ if( (a0 > b0) && (a1 < b1) )return 1;
+ }
+
+ return 0;
+}
+
+
+
diff --git a/uClinux-2.4.20-uc1/include/asm-armnommu/arch-W90N745/flash.h b/uClinux-2.4.20-uc1/include/asm-armnommu/arch-W90N745/flash.h
new file mode 100644
index 0000000..49451df
--- /dev/null
+++ b/uClinux-2.4.20-uc1/include/asm-armnommu/arch-W90N745/flash.h
@@ -0,0 +1,103 @@
+#ifndef FLASH_H
+#define FLASH_H
+//---------------------------------------------------------------------------
+#include <asm/arch/cdefs.h>
+#include <asm/arch/bib.h>
+
+
+// if no platform.h
+#ifndef FLASH_BASE
+#define FLASH_BASE (0x7F000000)
+#define FLASH_BLOCK_SIZE (0x10000)
+#endif
+
+#ifndef ROMCON
+#define ROMCON (0xFFF01004)
+#endif
+
+#define EXT3CON (0xFFF01024)
+
+#define FLASH_NAME_SIZE 16
+
+#define VP_int(x) (*((volatile unsigned int*)(x)))
+#define VP_short(x) (*((volatile unsigned short*)(x)))
+#define VP_char(x) (*((volatile unsigned char*)(x)))
+#define CAHCNF_R VP_int(0xFFF02000)
+#define CAHCON_R VP_int(0xFFF02004)
+
+#if 0
+#define inph(x) VP_short(x)
+#define outph(x,y) VP_short(x)=(y)
+#define inpb(x) VP_char(x)
+#define outpb(x,y) VP_char(x)=(y)
+#endif
+
+
+#define inpw(port) *((volatile unsigned int *)port)
+#define outpw(port,x) *((volatile unsigned int *)port)=x
+#define inph(port) *((volatile unsigned short *)port)
+#define outph(port,x) *((volatile unsigned short *)port)=x
+#define inpb(port) *((volatile unsigned char *)port)
+#define outpb(port,x) *((volatile unsigned char *)port)=x
+
+
+#define BLOCK_LOCK 0
+#define BLOCK_UNLOCK 1
+
+
+typedef struct
+{
+ char PID0;
+ char PID1;
+ char name[FLASH_NAME_SIZE];
+ int (*BlockSize)(UINT32 address);
+ int (*BlockErase)(UINT32 address,UINT32 size);
+ int (*BlockWrite)(UINT32 address, UCHAR * data, UINT32 size);
+ int (*ReadPID)(UINT32 address, UCHAR *PID0, UCHAR *PID1 );
+ int (*BlockLock)(UINT32 address, UINT32 op);
+} flash_t;
+
+
+
+#define IMAGE_ACTIVE 0x1 // Only the active image will be processed by bootloader
+#define IMAGE_COPY2RAM 0x2 // copy this image to ram
+#define IMAGE_EXEC 0x4 // execute this image
+#define IMAGE_FILE 0x8 // file image
+#define IMAGE_COMPRESSED 0x10 // compressed image, bootloader will unzip it
+#define SIGNATURE_WORD 0xA0FFFF9F
+
+typedef struct t_footer
+{
+ UINT32 num;
+ UINT32 base;
+ UINT32 length;
+ UINT32 load_address;
+ UINT32 exec_address;
+ CHAR name[16];
+ UINT32 image_checksum;
+ UINT32 signature;
+ UINT32 type;
+ UINT32 checksum;
+} tfooter;
+
+
+#define MAX_FOOTER_NUM 8
+
+
+#define BOOTER_BLOCK_LENGTH FLASH_BLOCK_SIZE
+extern flash_t flash[];// The supported flash types
+extern int flash_type;
+extern UINT32 _flash_size;
+extern char * _flash_buffer;
+
+extern int FindFlash(void); // function to identify the flash type
+extern int FindFooter(tfooter *** image_footer); //function to find the image footers
+int sys_DelImage(UINT32 image_num);
+int sys_FindImage(UINT32 image_num, tfooter ** image_footer);
+extern int sys_CorruptCheck(tfooter * image_footer);//function to check if data corrupt
+extern tbl_info info;
+extern int GetImgAddr(unsigned int default_addr);
+extern int GetLoadImage();
+extern int get_flash_type_num(void);
+//---------------------------------------------------------------------------
+#endif