www.pudn.com > BIOS-S3C2410.rar > NandFlash.c


//#include "../inc/def.h" 
//#include "../inc/config.h" 
//#include "../inc/utils.h" 
//#include "../inc/board.h" 
#include "def.h" 
#include "2410addr.h" 
#include "2410lib.h" 
 
#ifdef	NAND_FLASH_SUPPORT 
 
struct NFChipInfo { 
	U32 id; 
	U32 size; 
} 
 
static NandFlashChip[] = { 
	{0xec73, SIZE_16M}, 
	{0xec75, SIZE_32M}, 
	{0xec76, SIZE_64M}, 
	{0xec79, SIZE_128M}, 
	{0, 0}, 
}; 
 
#define	BLK_IDXL	8 
#define	BLK_IDXH	9 
#define	FMT_TAG		15 
 
char format_tags[] = "Formatted For NAND FLASH Driver";	//must be less than 32 
/***********************************************************/ 
//nand ecc utils 
typedef	unsigned char u_char; 
static u_char eccpos[6] = {0, 1, 2, 3, 6, 7}; 
 
/* 
 * Pre-calculated 256-way 1 byte column parity 
 */ 
static const u_char nand_ecc_precalc_table[] = { 
	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, 
	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 
	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 
	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 
	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 
	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 
	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 
	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 
	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 
	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 
	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 
	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 
	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 
	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 
	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 
	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 
}; 
 
 
/** 
 * nand_trans_result - [GENERIC] create non-inverted ECC 
 * @reg2:	line parity reg 2 
 * @reg3:	line parity reg 3 
 * @ecc_code:	ecc  
 * 
 * Creates non-inverted ECC code from line parity 
 */ 
static void nand_trans_result(u_char reg2, u_char reg3, 
	u_char *ecc_code) 
{ 
	u_char a, b, i, tmp1, tmp2; 
	 
	/* Initialize variables */ 
	a = b = 0x80; 
	tmp1 = tmp2 = 0; 
	 
	/* Calculate first ECC byte */ 
	for (i = 0; i < 4; i++) { 
		if (reg3 & a)		/* LP15,13,11,9 --> ecc_code[0] */ 
			tmp1 |= b; 
		b >>= 1; 
		if (reg2 & a)		/* LP14,12,10,8 --> ecc_code[0] */ 
			tmp1 |= b; 
		b >>= 1; 
		a >>= 1; 
	} 
	 
	/* Calculate second ECC byte */ 
	b = 0x80; 
	for (i = 0; i < 4; i++) { 
		if (reg3 & a)		/* LP7,5,3,1 --> ecc_code[1] */ 
			tmp2 |= b; 
		b >>= 1; 
		if (reg2 & a)		/* LP6,4,2,0 --> ecc_code[1] */ 
			tmp2 |= b; 
		b >>= 1; 
		a >>= 1; 
	} 
	 
	/* Store two of the ECC bytes */ 
	ecc_code[0] = tmp1; 
	ecc_code[1] = tmp2; 
} 
 
/** 
 * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block 
 * @dat:	raw data 
 * @ecc_code:	buffer for ECC 
 */ 
int nand_calculate_ecc(const u_char *dat, u_char *ecc_code) 
{ 
	u_char idx, reg1, reg2, reg3; 
	int j; 
	 
	/* Initialize variables */ 
	reg1 = reg2 = reg3 = 0; 
	ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; 
	 
	/* Build up column parity */  
	for(j = 0; j < 256; j++) { 
		 
		/* Get CP0 - CP5 from table */ 
		idx = nand_ecc_precalc_table[dat[j]]; 
		reg1 ^= (idx & 0x3f); 
		 
		/* All bit XOR = 1 ? */ 
		if (idx & 0x40) { 
			reg3 ^= (u_char) j; 
			reg2 ^= ~((u_char) j); 
		} 
	} 
	 
	/* Create non-inverted ECC code from line parity */ 
	nand_trans_result(reg2, reg3, ecc_code); 
	 
	/* Calculate final ECC code */ 
	ecc_code[0] = ~ecc_code[0]; 
	ecc_code[1] = ~ecc_code[1]; 
	ecc_code[2] = ((~reg1) << 2) | 0x03; 
	return 0; 
} 
 
/** 
 * nand_correct_data - [NAND Interface] Detect and correct bit error(s) 
 * @dat:	raw data read from the chip 
 * @read_ecc:	ECC from the chip 
 * @calc_ecc:	the ECC calculated from raw data 
 * 
 * Detect and correct a 1 bit error for 256 byte block 
 */ 
int nand_correct_data(u_char *dat, u_char *read_ecc, u_char *calc_ecc) 
{ 
	u_char a, b, c, d1, d2, d3, add, bit, i; 
	 
	/* Do error detection */  
	d1 = calc_ecc[0] ^ read_ecc[0]; 
	d2 = calc_ecc[1] ^ read_ecc[1]; 
	d3 = calc_ecc[2] ^ read_ecc[2]; 
	 
	if ((d1 | d2 | d3) == 0) { 
		/* No errors */ 
		return 0; 
	} 
	else { 
		a = (d1 ^ (d1 >> 1)) & 0x55; 
		b = (d2 ^ (d2 >> 1)) & 0x55; 
		c = (d3 ^ (d3 >> 1)) & 0x54; 
		 
		/* Found and will correct single bit error in the data */ 
		if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { 
			c = 0x80; 
			add = 0; 
			a = 0x80; 
			for (i=0; i<4; i++) { 
				if (d1 & c) 
					add |= a; 
				c >>= 2; 
				a >>= 1; 
			} 
			c = 0x80; 
			for (i=0; i<4; i++) { 
				if (d2 & c) 
					add |= a; 
				c >>= 2; 
				a >>= 1; 
			} 
			bit = 0; 
			b = 0x04; 
			c = 0x80; 
			for (i=0; i<3; i++) { 
				if (d3 & c) 
					bit |= b; 
				c >>= 2; 
				b >>= 1; 
			} 
			b = 0x01; 
			a = dat[add]; 
			a ^= (b << bit); 
			dat[add] = a; 
			return 1; 
		} 
		else { 
			i = 0; 
			while (d1) { 
				if (d1 & 0x01) 
					++i; 
				d1 >>= 1; 
			} 
			while (d2) { 
				if (d2 & 0x01) 
					++i; 
				d2 >>= 1; 
			} 
			while (d3) { 
				if (d3 & 0x01) 
					++i; 
				d3 >>= 1; 
			} 
			if (i == 1) { 
				/* ECC Code Error Correction */ 
				read_ecc[0] = calc_ecc[0]; 
				read_ecc[1] = calc_ecc[1]; 
				read_ecc[2] = calc_ecc[2]; 
				return 2; 
			} 
			else { 
				/* Uncorrectable Error */ 
				return -1; 
			} 
		} 
	} 
	 
	/* Should never happen */ 
	return -1; 
} 
 
/**********************************************************/ 
 
/* 
struct Partition oNandPartition[] = { 
	{0x00000000, 0x00030000, "boot"}, 
	{0x00030000, 0x001d0000, "kernel"}, 
	{0x00200000, 0x00600000, "rootfs"}, 
	{0x00800000, 0x00800000, "ext-fs1"}, 
	{0x01000000, 0x01000000, "ext-fs2"}, 
	{0x00000000, 0x00000000, 0} 
};*/ 
 
extern struct Partition *pNandPart; 
 
U32 NandFlashSize; 
 
static U16 NandAddr; 
static U16 support; 
 
#define	NAND_DAT	0x02000000 
#define	NAND_ALE	0x02000004 
#define	NAND_CLE	0x02000002 
 
#define	READCMD0	0 
#define	READCMD1	1 
#define	READCMD2	0x50 
#define	ERASECMD0	0x60 
#define	ERASECMD1	0xd0 
#define	PROGCMD0	0x80 
#define	PROGCMD1	0x10 
#define	QUERYCMD	0x70 
#define	READIDCMD	0x90 
 
void NFChipSel(U32); 
int  NFIsReady(void); 
void NFWrCmd(int); 
void NFWrAddr(int); 
void NFWrDat(int); 
U8   NFRdDat(void); 
 
#define	NFChipEn()	NFChipSel(1) 
#define	NFChipDs()	NFChipSel(0) 
#define	NFIsBusy()	(!NFIsReady()) 
 
//#define	NFWrCmd(cmd)	*(volatile U8 *)NAND_CLE = (cmd) 
//#define	NFWrAddr(addr)	*(volatile U8 *)NAND_ALE = (addr) 
//#define	NFWrDat(dat)	*(volatile U8 *)NAND_DAT = (dat) 
//#define	NFRdDat()		*(volatile U8 *)NAND_DAT 
 
//#define	WIAT_BUSY_HARD 
//#define	ER_BAD_BLK_TEST 
//#define	WR_BAD_BLK_TEST 
 
#ifdef	WIAT_BUSY_HARD 
#define	NFWaitBusy()	while(NFIsBusy()) 
#else 
static U32 NFWaitBusy(void) 
{ 
	U8 stat; 
	 
	NFWrCmd(QUERYCMD); 
	do { 
		stat = NFRdDat(); 
		//printf("%x\n", stat); 
	}while(!(stat&0x40)); 
	NFWrCmd(READCMD0); 
	return stat&1; 
} 
#endif 
 
static U32 NFReadID(void) 
{ 
	U32 id, loop = 0; 
 
	NFChipEn(); 
	NFWrCmd(READIDCMD); 
	NFWrAddr(0); 
	while(NFIsBusy()&&(loop<10000)) loop++; 
	if(loop>=10000) 
		return 0; 
	id  = NFRdDat()<<8; 
	id |= NFRdDat(); 
	NFChipDs(); 
	 
	return id; 
} 
 
static U16 NFReadStat(void) 
{ 
	U16 stat; 
	 
	NFChipEn();	 
	NFWrCmd(QUERYCMD); 
	stat = NFRdDat();	 
	NFChipDs(); 
	 
	return stat; 
} 
 
static U32 NFEraseBlock(U32 addr) 
{ 
	U8 stat; 
 
	addr &= ~0x1f; 
		 
	NFChipEn();	 
	NFWrCmd(ERASECMD0);		 
	NFWrAddr(addr); 
	NFWrAddr(addr>>8); 
	if(NandAddr) 
		NFWrAddr(addr>>16); 
	NFWrCmd(ERASECMD1);		 
	stat = NFWaitBusy(); 
	NFChipDs(); 
	 
#ifdef	ER_BAD_BLK_TEST 
	if(!((addr+0xe0)&0xff)) stat = 1;	//just for test bad block 
#endif 
	 
//	printf("Erase block 0x%08x %s\n", addr, stat?"fail":"ok"); 
	putch('.'); 
	 
	return stat; 
} 
 
//addr = page address 
static void NFReadPage(U32 addr, U8 *buf) 
{ 
	U16 i; 
	 
	NFChipEn(); 
	NFWrCmd(READCMD0); 
	NFWrAddr(0); 
	NFWrAddr(addr); 
	NFWrAddr(addr>>8); 
	if(NandAddr) 
		NFWrAddr(addr>>16); 
//	InitEcc(); 
	NFWaitBusy();		 
	for(i=0; i<512; i++) 
		buf[i] = NFRdDat();		 
	NFChipDs(); 
} 
 
//addr = page address 
static U32 NFWritePage(U32 addr, U8 *buf, U16 blk_idx) 
{ 
	U16 i, stat; 
//	U8 tmp[3]; 
	U8 ecc_code[3]; 
	U8 oob_info[16]; 
		 
	for(i=0; i>8; 
	oob_info[FMT_TAG]   = format_tags[addr&0x1f]; 
	 
	NFChipEn(); 
	NFWrCmd(PROGCMD0); 
	NFWrAddr(0); 
	NFWrAddr(addr); 
	NFWrAddr(addr>>8); 
	if(NandAddr) 
		NFWrAddr(addr>>16); 
//	InitEcc();	 
	for(i=0; i<512; i++) 
		NFWrDat(buf[i]); 
		 
	if(!addr) { 
		NFWrDat('b'); 
		NFWrDat('o'); 
		NFWrDat('o'); 
		NFWrDat('t');		 
	} else {		 
		for(i=0; i>8); 
	if(NandAddr) 
		NFWrAddr(addr>>16); 
	for(i=0; i<16; i++) 
		NFWrDat(0);		//mark with 0	 
	NFWrCmd(PROGCMD1); 
	NFWaitBusy();		//needn't check return status 
	 
	NFWrCmd(READCMD0);	//point to area a 
		 
	NFChipDs(); 
} 
 
static int NFChkBadBlk(U32 addr) 
{ 
	U8 dat; 
	 
	addr &= ~0x1f; 
	 
	NFChipEn(); 
	 
	NFWrCmd(READCMD2);	//point to area c 
	NFWrAddr(5);		//mark offset 5 
	NFWrAddr(addr); 
	NFWrAddr(addr>>8); 
	if(NandAddr) 
		NFWrAddr(addr>>16); 
	NFWaitBusy(); 
	dat = NFRdDat(); 
	 
	NFWrCmd(READCMD0);	//point to area a 
	 
	NFChipDs(); 
 
	return (dat!=0xff); 
} 
 
 
 
static struct Partition *NFSelPart(char *info) 
{ 
	int i, max_sel; 
 
	printf("Please select Nand flash region to %s, Esc to abort\n", info); 
	 
	for(i=0; pNandPart[i].size; i++) 
		printf("%d : start 0x%08x, size 0x%08x\t[Part%d]\n", i, pNandPart[i].offset, pNandPart[i].size, i/*pNandPart[i].name*/ ); 
 
	max_sel = i;	 
	 
	while(1) { 
		char c = getch(); 
		 
		if(c==0x1b) 
			return 0; 
		if((c>='0')&&(c<(max_sel+'0'))) 
			return &(pNandPart[c-'0']); 
	}	 
} 
 
static void NFReadPart(struct Partition *part, U8 *buf) 
{ 
	U32 i, start_page; 
	U8 *ram_addr; 
	int size; 
	 
	start_page = part->offset>>9; 
	size = part->size; 
	ram_addr = buf; 
	 
	for(i=0; size>0; ) { 
		if(!(i&0x1f)) { 
			if(NFChkBadBlk(i+start_page)) { 
				printf("Skipped bad block at 0x%08x\n", i+start_page); 
				i += 32; 
				size -= 32<<9; 
				continue; 
			} 
		} 
		NFReadPage((i+start_page), ram_addr); 
//			printf("Read page %d\n", i); 
		i++; 
		size -= 512; 
		ram_addr += 512; 
	} 
} 
 
/******************************************************/ 
int WrFileToNF(U32 src_addr, U32 w_size) 
{ 
	struct Partition *part; 
	U32 start_page, i, skip_blks; 
	U8 *ram_addr; 
	int size;	//must be int 
	U32 start_addr; 
	 
	if(!support) 
		return -1; 
		 
	part = NFSelPart("write"); 
	if(!part) 
		return -1; 
	 
	if(w_size>part->size) { 
		puts("File size is too long!\n"); 
		return -1; 
	} 
 
	start_page = part->offset>>9; 
	 
	printf("Are you sure to write nand flash from 0x%x with ram address 0x%x, size %d ?\n", part->offset, src_addr, w_size); 
	if(!getyorn()) 
		return -1; 
		 
	skip_blks = 0; 
	ram_addr = (U8 *)src_addr; 
	start_addr = (U32)src_addr; 
	size = w_size; 
	printf("start address 0x%x\n", start_page); 
	for(i=0; size>0; )	{ 
		if(!(i&0x1f)) { 
			if(NFEraseBlock(i+start_page)) { 
/*				part->size -= 32<<9;	//fail, partition available size - 1 block size 
				if(FileSize>part->size) { 
					puts("Program nand flash fail\n"); 
					return; 
				} 
				NFMarkBadBlk(i+start_page); 
				skip_blks++; 
				i += 32;			 
				continue;*/ 
				goto WrFileToNFErr; 
			} 
		} 
		if(NFWritePage(i+start_page, ram_addr, ((U32)ram_addr-start_addr)>>14)) { 
			ram_addr -= (i&0x1f)<<9; 
			size += (i&0x1f)<<9; 
			i &= ~0x1f; 
WrFileToNFErr:			 
			part->size -= 32<<9;	//partition available size - 1 block size 
			if(w_size>part->size) { 
				puts("Program nand flash fail\n"); 
				return -1; 
			}			 
			NFMarkBadBlk(i+start_page); 
			skip_blks++;			 
			i += 32;		 
			continue; 
		} 
		ram_addr += 512; 
		size -= 512; 
		i++; 
	} 
	printf("\nend address 0x%x\n", start_page+i); 
 
	puts("Program nand flash partition success\n"); 
	if(skip_blks) 
		printf("Skiped %d bad block(s)\n", skip_blks); 
		 
	return 0;	 
} 
 
int RdFileFrNF(U32 dst_addr, U32 load_part) 
{ 
	U32 i; 
	struct Partition *part; 
	 
	if(!support) 
		return -1; 
 
	for(i=0; pNandPart[i].size; i++); 
	if(i>load_part) 
		part = pNandPart+load_part; 
	else { 
		part = NFSelPart("read"); 
		if(!part) 
			return -1; 
	} 
	 
	puts("Loading...\n"); 
	 
	NFReadPart(part, (U8 *)dst_addr); 
	 
	puts("end\n"); 
	 
	return 0; 
} 
 
int EraseNandPart(void) 
{ 
	struct Partition *part; 
	U32 start_page, blk_cnt; 
	int i, err = 0;	 
 
	if(!support) 
		return -1; 
		 
	part = NFSelPart("erase"); 
	if(!part) 
		return -1; 
 
	start_page = part->offset>>9; 
	blk_cnt  = part->size>>14; 
 
	printf("Are you sure to erase nand flash from page 0x%x, block count 0x%x ?", start_page, blk_cnt); 
	if(!getyorn()) 
		return -1; 
	 
	printf("start address 0x%x\n", start_page); 
	for(i=0; blk_cnt; blk_cnt--, i+=32) { 
		if(NFEraseBlock(i+start_page)) { 
			err ++; 
			puts("Press any key to continue...\n"); 
			getch(); 
		} 
	} 
	printf("\nend address 0x%x\n", start_page+i-32); 
	 
	puts("Erase Nand partition completed "); 
	if(err) 
		printf("with %d bad block(s)\n", err); 
	else 
		puts("success\n"); 
	 
	return 0; 
} 
 
#ifdef	SAVE_ENV_IN_NAND 
U32 NFSaveParams(char *pEnv) 
{ 
	char dat[512]; 
	U32 addr; 
	 
	if(support) { 
		memcpy(dat, pEnv, sizeof(EnvParams)); 
		for(addr=SIZE_64K>>9; addr<(0x30000>>9); addr++) { 
			NFEraseBlock(addr); 
			if(!NFWritePage(addr, (U8 *)dat, 0)) 
				return 0; 
		} 
	} 
	return -1; 
} 
 
U32 NFSearchParams(char *pEnv) 
{ 
	char dat[512]; 
	U32 addr; 
	 
	if(support) { 
		for(addr=SIZE_64K>>9; addr<(0x30000>>9); addr++) { 
			NFReadPage(addr, (U8 *)dat);		 
			if(!strncmp(dat, "params", 7)) { 
				memcpy(pEnv, dat, sizeof(EnvParams));			 
				return 0; 
			} 
		} 
	} 
	return -1;	 
} 
#endif 
 
static U32 nand_id; 
 
void NandFlashInit(void) 
{ 
	int i;	 
	 
	support = 0; 
	nand_id = NFReadID(); 
	 
	for(i=0; NandFlashChip[i].id!=0; i++) 
		if(NandFlashChip[i].id==nand_id) {			 
			nand_id = i; 
			NandFlashSize = NandFlashChip[i].size; 
			support  = 1; 
			NandAddr = NandFlashSize>SIZE_32M; 
			if(!pNandPart[0].size) { 
				pNandPart[0].offset = 0; 
				pNandPart[0].size   = NandFlashSize; 
				pNandPart[1].size   = 0;				 
			}			 
			return; 
		} 
	 
} 
 
void NandFlashStatusRep(void) 
{ 
	if(support) { 
		printf("Nand Flash ID is 0x%x, Size = %dM, Status = 0x%x\n", NandFlashChip[nand_id].id, NandFlashChip[nand_id].size>>20, NFReadStat()); 
	} else { 
		printf("No supported Nand Flash Found!\n"); 
	} 
} 
 
//void (*pNandFlashInit)(void) = NandFlashInit; 
 
#endif	/* NAND_SUPPORT */ 
 
#ifdef	NAND_FLASH_SUPPORT 
 
int NandProg(int argc, char *argv[]) 
{ 
	unsigned int size = ~0; 
	unsigned int data_begin = ~0; 
 
	data_begin = download_addr; 
	size       = download_len; 
	 
	if(argc>1) 
		data_begin = strtoul((char *)argv[1]); 
	if(argc>2)	 
		size       = strtoul((char *)argv[2]);	 
	if((size==-1)||(data_begin==-1)) { 
		printf("Arguments error\n"); 
		goto err_exit; 
	} 
	 
	if(size==0) { 
		printf("Write 0 Bytes!\n"); 
		return -1; 
	} 
	else 
		return WrFileToNF(data_begin, size); 
	 
err_exit: 
	printf("Usage:	nfprog addr size\naddr = data pointer to ram\nsize = program size(Bytes)\n"); 
	return -1; 
} 
 
int NandLoad(int argc, char *argv[]) 
{ 
	U32 load_part = -1; 
	download_addr = DFT_DOWNLOAD_ADDR; 
	 
	if(argc>1) { 
		download_addr = strtoul((char *)argv[1]); 
		if(download_addr==-1) 
			download_addr = DFT_DOWNLOAD_ADDR; 
		if(argc>2) 
			load_part = strtoul(argv[2]); 
	} 
	 
	printf("Load data form nand flash to 0x%x\n", download_addr); 
	return RdFileFrNF(download_addr, load_part); 
} 
 
int NandErase(int argc, char *argv[]) 
{ 
	return EraseNandPart(); 
} 
 
int NandPart(int argc, char*argv[]) 
{ 
	unsigned long i, addr[8]; 
	 
	if(!NandFlashSize) 
		return -1; 
	if((argc<=1)||(argc>9)) 
		goto err_exit; 
 
	addr[0] = 0; 
	for(i=1; iNandFlashSize)) 
			goto err_exit; 
	} 
	 
	printf("Set %d partition(s) :\n", argc-1); 
	for(i=0; i>9; addr<(0x30000>>9); addr++) { 
			//NFEraseBlock(addr); 
			 EraseBlock(addr); 
			//if(!NFWritePage(addr, (U8 *)dat, 0)) 
			 if(!WritePage(addr, (U8 *)dat)) 
			 { 
				//printf("wite succes\n"); 
				return 0; 
			 } 
		} 
	} 
	return -1; 
	 
} 
 
 
U32 NFSearchParams(char *pEnv) 
{ 
	char dat[512]; 
	U32 addr; 
	InitNandFlash(); 
	if(1) { 
		for(addr=SIZE_128K>>9; addr<(0x30000>>9); addr++) { 
			ReadPage(addr, (U8 *)dat);		 
			//if(!strncmp(dat, "params", 7)) { 
			memcpy(pEnv, dat, sizeof(EnvParams));			 
			return 0;	 
		} 
	} 
	return -1;	 
} 
 
#endif