www.pudn.com > LJD2440-II_MON_OK.rar > nand.c


/* 
 create by hzh, support 512/page NAND Flash only 
*/ 
#include  
 
#include "def.h" 
#include "2440addr.h" 
#include "2440lib.h" 
#include "2440slib.h" 
#include "Nand.h" 
 
//suppport boot params 
#define	GLOBAL_PARAMS 
#include "bootpara.h" 
 
#define	puts	Uart_Printf 
#define	printf	Uart_Printf 
#define	getch	Uart_Getch 
#define	putch	Uart_SendByte 
 
#define	EnNandFlash()	(rNFCONT |= 1) 
#define	DsNandFlash()	(rNFCONT &= ~1) 
#define	NFChipEn()		(rNFCONT &= ~(1<<1)) 
#define	NFChipDs()		(rNFCONT |= (1<<1)) 
#define	InitEcc()		(rNFCONT |= (1<<4)) 
#define	MEccUnlock()	(rNFCONT &= ~(1<<5)) 
#define	MEccLock()		(rNFCONT |= (1<<5)) 
#define	SEccUnlock()	(rNFCONT &= ~(1<<6)) 
#define	SEccLock()		(rNFCONT |= (1<<6)) 
 
#define	WrNFDat8(dat)	(rNFDATA8 = (dat)) 
#define	WrNFDat32(dat)	(rNFDATA = (dat)) 
#define	RdNFDat8()		(rNFDATA8)	//byte access 
#define	RdNFDat32()		(rNFDATA)	//word access 
 
#define	WrNFCmd(cmd)	(rNFCMD = (cmd)) 
#define	WrNFAddr(addr)	(rNFADDR = (addr)) 
#define	WrNFDat(dat)	WrNFDat8(dat) 
#define	RdNFDat()		RdNFDat8()	//for 8 bit nand flash, use byte access 
 
#define	RdNFMEcc()		(rNFMECC0)	//for 8 bit nand flash, only use NFMECC0 
#define	RdNFSEcc()		(rNFSECC)	//for 8 bit nand flash, only use low 16 bits 
 
#define	RdNFStat()		(rNFSTAT) 
#define	NFIsBusy()		(!(rNFSTAT&1)) 
#define	NFIsReady()		(rNFSTAT&1) 
 
//#define	WIAT_BUSY_HARD	1 
//#define	ER_BAD_BLK_TEST 
//#define	WR_BAD_BLK_TEST 
 
#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	RdIDCMD		0x90 
 
static U16 NandAddr; 
 
// HCLK=100Mhz 
#define TACLS		1//7	// 1-clk(0ns)  
#define TWRPH0		4//7	// 3-clk(25ns) 
#define TWRPH1		1//7	// 1-clk(10ns)  //TACLS+TWRPH0+TWRPH1>=50ns 
 
static void InitNandCfg(void) 
{ 
	// for S3C2440 
 
	rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);	 
	// TACLS		[14:12]	CLE&ALE duration = HCLK*TACLS. 
	// TWRPH0		[10:8]	TWRPH0 duration = HCLK*(TWRPH0+1) 
	// TWRPH1		[6:4]	TWRPH1 duration = HCLK*(TWRPH1+1) 
	// AdvFlash(R)	[3]		Advanced NAND, 0:256/512, 1:1024/2048 
	// PageSize(R)	[2]		NAND memory page size 
	//						when [3]==0, 0:256, 1:512 bytes/page. 
	//						when [3]==1, 0:1024, 1:2048 bytes/page. 
	// AddrCycle(R)	[1]		NAND flash addr size 
	//						when [3]==0, 0:3-addr, 1:4-addr. 
	//						when [3]==1, 0:4-addr, 1:5-addr. 
	// BusWidth(R/W) [0]	NAND bus width. 0:8-bit, 1:16-bit. 
	 
	rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0); 
	// Lock-tight	[13]	0:Disable lock, 1:Enable lock. 
	// Soft Lock	[12]	0:Disable lock, 1:Enable lock. 
	// EnablillegalAcINT[10]	Illegal access interupt control. 0:Disable, 1:Enable 
	// EnbRnBINT	[9]		RnB interrupt. 0:Disable, 1:Enable 
	// RnB_TrandMode[8]		RnB transition detection config. 0:Low to High, 1:High to Low 
	// SpareECCLock	[6]		0:Unlock, 1:Lock 
	// MainECCLock	[5]		0:Unlock, 1:Lock 
	// InitECC(W)	[4]		1:Init ECC decoder/encoder. 
	// Reg_nCE		[1]		0:nFCE=0, 1:nFCE=1. 
	// NANDC Enable	[0]		operating mode. 0:Disable, 1:Enable. 
 
//	rNFSTAT = 0; 
     
//    Nand_Reset(); 
} 
 
#ifdef	WIAT_BUSY_HARD 
#define	WaitNFBusy()	while(NFIsBusy()) 
#else 
static U32 WaitNFBusy(void)	// R/B 未接好? 
{ 
	U8 stat; 
	 
	WrNFCmd(QUERYCMD); 
	do { 
		stat = RdNFDat(); 
		//printf("%x\n", stat); 
	}while(!(stat&0x40)); 
	WrNFCmd(READCMD0); 
	return stat&1; 
} 
#endif 
 
static U32 ReadChipId(void) 
{ 
	U32 id; 
	 
	NFChipEn();	 
	WrNFCmd(RdIDCMD); 
	WrNFAddr(0); 
	while(NFIsBusy());	 
	id  = RdNFDat()<<8; 
	id |= RdNFDat();		 
	NFChipDs();		 
	 
	return id; 
} 
 
static U16 ReadStatus(void) 
{ 
	U16 stat; 
	 
	NFChipEn();	 
	WrNFCmd(QUERYCMD);		 
	stat = RdNFDat();	 
	NFChipDs(); 
	 
	return stat; 
} 
 
static U32 EraseBlock(U32 addr) 
{ 
	U8 stat; 
 
	addr &= ~0x1f; 
		 
	NFChipEn();	 
	WrNFCmd(ERASECMD0);		 
	WrNFAddr(addr); 
	WrNFAddr(addr>>8); 
	if(NandAddr) 
		WrNFAddr(addr>>16); 
	WrNFCmd(ERASECMD1);		 
	stat = WaitNFBusy(); 
	NFChipDs(); 
	 
#ifdef	ER_BAD_BLK_TEST 
	if(!((addr+0xe0)&0xff)) stat = 1;	//just for test bad block 
#endif 
	 
	putch('.'); 
	//printf("Erase block 0x%x %s\n", addr, stat?"fail":"ok"); 
		 
	return stat; 
} 
 
//addr = page address 
static void ReadPage(U32 addr, U8 *buf) 
{ 
	U16 i; 
	 
	NFChipEn(); 
	WrNFCmd(READCMD0); 
	WrNFAddr(0); 
	WrNFAddr(addr); 
	WrNFAddr(addr>>8); 
	if(NandAddr) 
		WrNFAddr(addr>>16); 
	InitEcc(); 
	WaitNFBusy(); 
	for(i=0; i<512; i++) 
		buf[i] = RdNFDat(); 
	NFChipDs(); 
} 
 
static U32 WritePage(U32 addr, U8 *buf) 
{ 
	U32 i, mecc; 
	U8 stat, tmp[7]; 
	 
	 
	NFChipEn(); 
	WrNFCmd(PROGCMD0); 
	WrNFAddr(0); 
	WrNFAddr(addr); 
	WrNFAddr(addr>>8); 
	if(NandAddr) 
		WrNFAddr(addr>>16); 
	InitEcc();	//reset mecc and secc 
	MEccUnlock(); 
	for(i=0; i<512; i++) 
		WrNFDat(buf[i]); 
	MEccLock(); 
	 
	mecc = RdNFMEcc(); 
		 
	tmp[0] = mecc&0xff; 
    tmp[1] = (mecc>>8)&0xff; 
    tmp[2] = (mecc>>16)&0xff; 
    tmp[3] = (mecc>>24)&0xff; 
    tmp[5] = 0xff;	//mark good block 
     
    SEccUnlock(); 
	WrNFDat(tmp[0]); 
	WrNFDat(tmp[1]); 
	WrNFDat(tmp[2]); 
	WrNFDat(tmp[3]); 
	SEccLock(); 
	WrNFDat(tmp[4]); 
	WrNFDat(tmp[5]); 
    	 
	WrNFCmd(PROGCMD1); 
	stat = WaitNFBusy(); 
	NFChipDs(); 
	 
#ifdef	WR_BAD_BLK_TEST 
	if((addr&0xff)==0x17) stat = 1;	//just for test bad block 
#endif 
		 
	if(stat) 
		printf("Write nand flash 0x%x fail\n", addr); 
	else {	 
		U8 RdDat[512]; 
		 
		ReadPage(addr, RdDat);		 
		for(i=0; i<512; i++) 
			if(RdDat[i]!=buf[i]) { 
				printf("Check data at page 0x%x, offset 0x%x fail\n", addr, i); 
				stat = 1; 
				break; 
			} 
	} 
		 
	return stat;	 
} 
 
static void MarkBadBlk(U32 addr) 
{ 
	addr &= ~0x1f; 
	 
	NFChipEn(); 
	 
	WrNFCmd(READCMD2);	//point to area c 
	 
	WrNFCmd(PROGCMD0); 
	WrNFAddr(4);		//mark offset 4,5,6,7 
	WrNFAddr(addr); 
	WrNFAddr(addr>>8); 
	if(NandAddr) 
		WrNFAddr(addr>>16); 
	WrNFDat(0);			//mark with 0 
	WrNFDat(0); 
	WrNFDat(0);			//mark with 0 
	WrNFDat(0); 
	WrNFCmd(PROGCMD1); 
	WaitNFBusy();		//needn't check return status 
	 
	WrNFCmd(READCMD0);	//point to area a 
		 
	NFChipDs(); 
} 
 
static int CheckBadBlk(U32 addr) 
{ 
	U8 dat; 
	 
	addr &= ~0x1f; 
	 
	NFChipEn(); 
	 
	WrNFCmd(READCMD2);	//point to area c 
	WrNFAddr(5);		//mark offset 4,5,6,7 
	WrNFAddr(addr); 
	WrNFAddr(addr>>8); 
	if(NandAddr) 
		WrNFAddr(addr>>16); 
	WaitNFBusy(); 
	dat = RdNFDat(); 
	 
	WrNFCmd(READCMD0);	//point to area a 
	 
	NFChipDs(); 
 
	return (dat!=0xff); 
} 
 
/************************************************************/ 
struct Partition{ 
	U32 offset; 
	U32 size; 
	char *name; 
}; 
/* 
static struct Partition NandPart[] = { 
	{0, 		 0x00030000, "boot"},		//256K 
	{0x00030000, 0x001d0000, "kernel"}, 
	{0x00200000, 0x01e00000, "rootfs"},		//30M 
	{0x02000000, 0x02000000, "ext-fs1"},	//32M 
	{0,			 0         , 0} 
}; 
*/ 
 
//modified by vontom 
//for AT2440EVB 
 
static struct Partition NandPart[] = { 
	{0, 		 0x00040000, "boot"},		//256K 
	{0x00040000, 0x001c0000, "kernel"}, 
	{0x00200000, 0x03500000, "rootfs"},		//30M 
	{0x03500000, 0x03500000, "ext-fs1"},	//32M 
	{0,			 0         , 0} 
}; 
/* 
static void TestFunc(void) 
{ 
	U32 i; 
	U8 buf[512]; 
	 
	if(EraseBlock(0x180)) 
		return; 
	 
	for(i=0; i<512; i++) 
		buf[i] = i; 
		 
	WritePage(0x180, buf);	 
	for(i=0; i<512; i++) 
		buf[i] = 0; 
	ReadPage(0x180, buf); 
	 
	for(i=0; i<512; i++) 
		printf("%4x", buf[i]); 
} 
*/ 
static U32 StartPage, BlockCnt; 
extern U32 downloadAddress;  
extern U32 downloadFileSize; 
 
 
static int NandSelPart(char *info) 
{ 
	U16 i, max_sel; 
	struct Partition *ptr = NandPart; 
	 
	printf("Please select which region to %s : Esc to abort\n", info); 
	 
	for(i=0; ptr->size!=0; i++, ptr++) 
		printf("%d : offset 0x%-8x, size 0x%-8x [%s]\n", i, ptr->offset, ptr->size, ptr->name); 
		 
	max_sel = i; 
	 
	while(1) { 
		i = getch(); 
		if(i==0x1b) 
			return -1; 
		if((i>='0')&&(i<(max_sel+'0'))) { 
			i -= '0'; 
			StartPage = NandPart[i].offset>>9; 
			BlockCnt  = NandPart[i].size>>14; 
			return i; 
		} 
	}	 
} 
 
static void WrFileToNF(void) 
{ 
	int nf_part, i ,size, skip_blks; 
	U32 ram_addr; 
	 
	nf_part = NandSelPart("write"); 
	if(nf_part<0) 
		return;	 
	 
	if(downloadFileSize>NandPart[nf_part].size) { 
		puts("Download file size is more large than selected partition size!!!\n"); 
//		return; 
	} 
	 
	printf("Now write nand flash page 0x%x from ram address 0x%x, filesize = %d\n", StartPage, downloadAddress, downloadFileSize); 
	puts("Are you sure? [y/n]\n"); 
	while(1) { 
		char c = getch(); 
		if((c=='y')||(c=='Y')) 
			break; 
		if((c=='n')||(c=='N'))			 
			return; 
	} 
	 
	skip_blks = 0; 
	ram_addr = downloadAddress; 
	size = downloadFileSize; 
	for(i=0; size>0; )	{	 
		if(!(i&0x1f)) { 
			if(EraseBlock(i+StartPage)) { 
				NandPart[nf_part].size -= 32<<9;	//partition available size - 1 block size 
				if(downloadFileSize>NandPart[nf_part].size) { 
					puts("Program nand flash fail\n"); 
					return; 
				} 
				MarkBadBlk(i+StartPage); 
				skip_blks++;				 
				i += 32;				 
				continue; 
			} 
		} 
		if(WritePage(i+StartPage, (U8 *)ram_addr)) { 
			ram_addr -= (i&0x1f)<<9; 
			size += (i&0x1f)<<9; 
			i &= ~0x1f; 
			NandPart[nf_part].size -= 32<<9;	//partition available size - 1 block size 
			if(downloadFileSize>NandPart[nf_part].size) { 
				puts("Program nand flash fail\n"); 
				return; 
			}			 
			MarkBadBlk(i+StartPage); 
			skip_blks++;			 
			i += 32;			 
			continue; 
		} 
		ram_addr += 512; 
		size -= 512; 
		i++; 
	} 
 
	puts("Program nand flash partition success\n"); 
	if(skip_blks) 
		printf("Skiped %d bad block(s)\n", skip_blks); 
} 
 
#define LINUX_PAGE_SHIFT	12 
#define LINUX_PAGE_SIZE		(1<>10, 
					devfs_sel, 
					boot_params.string); 
		 
		params->u1.s.page_size = LINUX_PAGE_SIZE; 
		params->u1.s.nr_pages = (boot_params.mem_cfg.val >> LINUX_PAGE_SHIFT); 
		memcpy(params->commandline, parameters, strlen(parameters)); 
	 
		printf("Set boot params = %s\n", params->commandline); 
	} 
 
	printf("Load Kernel...\n");	 
 
	if(boot_params.osstor.val)	//load program from NOR or NAND FLASH 
		memcpy((void *)buf, (void *)(0x04000000+0x00020000), 0x001e0000); 
	else { 
		StartPage = NandPart[1].offset>>9; 
		size = NandPart[1].size; 
		ram_addr = buf;	 
	 
		for(i=0; size>0; ) { 
			if(!(i&0x1f)) { 
				if(CheckBadBlk(i+StartPage)) { 
					printf("Skipped bad block at 0x%x\n", i+StartPage); 
					i += 32; 
					size -= 32<<9; 
					continue; 
				} 
			} 
			ReadPage((i+StartPage), (U8 *)ram_addr); 
			i++; 
			size -= 512; 
			ram_addr += 512; 
		} 
	} 
	 
	if(!boot_params.root_sel.val) { 
		int ramdisk_sz; 
		 
		printf("Load Ramdisk...\n"); 
		 
		StartPage = NandPart[2].offset>>9; 
		size = NandPart[1].size; 
		 
		ram_addr = boot_params.initrd_addr.val; 
		ramdisk_sz = boot_params.initrd_len.val; 
		 
		for(i=0; size>0&&ramdisk_sz>0; ) { 
			if(!(i&0x1f)) { 
				if(CheckBadBlk(i+StartPage)) { 
					printf("Skipped bad block at 0x%x\n", i+StartPage); 
					i += 32; 
					size -= 32<<9; 
					continue; 
				} 
			} 
			ReadPage((i+StartPage), (U8 *)ram_addr); 
			i++; 
			size -= 512; 
			ram_addr += 512; 
			ramdisk_sz -= 512; 
		} 
	} 
	 
	DsNandFlash(); 
 
		//ChangeClockDivider(13,12); 
		//ChangeMPllValue(67,1,1);	//300MHz,2440A! 
		//rCLKCON = 0x7fff0; 
	call_linux(0, boot_params.machine.val, buf); 
} 
 
/************************************************************/ 
static int have_nandflash; 
static void InitNandFlash(int info) 
{	 
	U32 i; 
	 
	InitNandCfg(); 
	i = ReadChipId(); 
	if(info) 
		printf("Read chip id = %x\n", i);	 
	if((i==0x9873)||(i==0xec75))	 
		NandAddr = 0; 
	else if(i==0xec76) 
		NandAddr = 1; 
	else { 
		if(info)	 
			puts("Chip id error!!!\n"); 
		have_nandflash = 0; 
		return; 
	} 
	have_nandflash = 1; 
	if(info) 
		printf("Nand flash status = %x\n", ReadStatus()); 
} 
 
void NandErase(void) 
{ 
	int i, err = 0; 
	 
	InitNandFlash(1); 
	if(!have_nandflash) 
		return; 
	 
	i = NandSelPart("erase"); 
	if(i<0) 
		return;	 
	 
	printf("Are you sure to erase nand flash from page 0x%x, block count 0x%x ? [y/n]\n", StartPage, BlockCnt); 
	while(1) { 
		char c; 
		 
		c = getch(); 
		if((c=='y')||(c=='Y')) 
			break; 
		if((c=='n')||(c=='N')) 
			return; 
	}	 
	 
	for(i=0; BlockCnt; BlockCnt--, i+=32) { 
		if(EraseBlock(i+StartPage)) { 
			err ++; 
			puts("Press any key to continue...\n"); 
			getch(); 
		} 
	}	 
 
	DsNandFlash();		//disable nand flash interface 
	puts("Erase Nand partition completed "); 
	if(err) 
		printf("with %d bad block(s)\n", err); 
	else 
		puts("success\n"); 
} 
 
void NandWrite(void) 
{ 
	InitNandFlash(1); 
	if(!have_nandflash) 
		return; 
	WrFileToNF(); 
	DsNandFlash();		//disable nand flash interface 
} 
 
extern MemoryTest(void); 
int RelocateNKBIN(U32 img_src, U32 *pStart, U32 *pLength, U32 *pLaunch); 
 
static void LoadRunWince(void) 
{ 
	U32 i, ram_addr, buf = boot_params.initrd_addr.val; 
	int size; 
	MemoryTest(); 
	printf("Load Kernel...\n");	 
 
	if(boot_params.osstor.val)	//load program from NOR or NAND FLASH 
		memcpy((void *)buf, (void *)(0x04000000+0x00020000), 0x00fe0000); 
	else { 
		StartPage = NandPart[boot_params.start.val].offset>>9;	//part 2,3... 
		size = NandPart[boot_params.root_sel.val].size - 0x200000;//load 30M data 
		ram_addr = buf; 
	 
		for(i=0; size>0; ) { 
			if(!(i&0x1f)) { 
				if(CheckBadBlk(i+StartPage)) { 
					printf("Skipped bad block at 0x%x\n", i+StartPage); 
					i += 32; 
					//size -= 32<<9; 
					continue; 
				} 
			} 
			ReadPage((i+StartPage), (U8 *)ram_addr); 
			i++; 
			size -= 512; 
			ram_addr += 512; 
		} 
	} 
	 
	printf("run 0x%08x...\n", boot_params.run_addr.val); 
	//RelocateNKBIN(buf, &buf, &i, &boot_params.run_addr.val); 
	call_linux(0, 0, boot_params.run_addr.val); 
} 
 
void NandLoadRun(void) 
{ 
	InitNandFlash(1); 
	//if(!have_nandflash) 
	//	return; 
	if(boot_params.start.val<2)	//linux 
		LoadRun(); 
	LoadRunWince(); 
} 
 
/* 
void TestNandFlash(void) 
{		 
	InitNandFlash();	 
	 
	while(1) 
	{ 
		U8 key = '2'; 
		 
		puts("\nNand flash operations, press ESC to exit\n"); 
		puts("1.Write nand flash with download file\n"); 
		puts("2.Load progam from nand flash and run\n"); 
		puts("3.Erase nand flash partition\n"); 
		puts("4.Test nand flash erase, write, read\n"); 
	 
		key = getch();		 
		 
		if(key==0x1b) 
			goto TestNandExit; 
		else if(key=='1') 
			WrFileToNF(); 
		else if(key=='2') 
			LoadRun(); 
		else if(key=='3') 
			NandErase(); 
		else if(key=='4')	 
			TestFunc(); 
	}			 
TestNandExit:	 
	DsNandFlash();		//disable nand flash interface 
}*/ 
 
#include "norflash.h" 
#define	NOR_PARAMS_OFFSET	0x1c000 
 
int search_params(void) 
{ 
	U32 page, page_cnt; 
	U8 dat[528]; 
	BootParams *pBP = (BootParams *)dat; 
	int ret=-1; 
	 
	InitNandFlash(0);	//don't show info in InitNandFlash! 
	if(have_nandflash) { 
		page     = NandPart[0].offset>>9; 
		page_cnt = NandPart[0].size>>9; 
	 
		//search from the last page 
		while(page_cnt--) { 
			ReadPage(page+page_cnt, dat); 
			if(!strncmp(boot_params.start.flags, pBP->start.flags, 10)) { 
				ret = 0; 
				break; 
			} 
		} 
	} else {	 
		memcpy(dat, (void *)(NOR_PARAMS_OFFSET), 512);	//now mmu is not set, so use original address 
		if(!strncmp(boot_params.start.flags, pBP->start.flags, 10)) 
			ret = 0; 
	} 
	 
	DsNandFlash(); 
	 
	if(!ret) { 
		ParamItem *pPIS = &pBP->start, *pPID = &boot_params.start; 
		 
		for(; pPID<=&boot_params.user_params; pPIS++, pPID++) 
			if(!strncmp(pPID->flags, pPIS->flags, sizeof(pPID->flags))) 
				pPID->val = pPIS->val; 
		strncpy(boot_params.string, pPIS->flags, boot_params.user_params.val+1); 
		if(boot_params.user_params.val!=strlen(pPID->flags)) { 
			memset(boot_params.string, 0, sizeof(boot_params.string)); 
			boot_params.user_params.val = 0; 
		} 
	} else { 
		//printf("Fail to find boot params! Use Default parameters.\n"); 
		//don't printf anything before serial initialized! 
	} 
	 
	return ret; 
} 
 
//保存在最后两个block,应确保程序(包括出现坏块时)不会覆盖到最后两块 
int save_params(void) 
{ 
	U32 page, page_cnt; 
	U8 dat[0x20000]; 
	int ret = 0; 
	 
	InitNandFlash(1); 
	have_nandflash=1; 
	if(have_nandflash) { 
		memset(dat, 0, sizeof(boot_params)); 
		memcpy(dat, &boot_params, sizeof(boot_params)); 
 
		page = (NandPart[1].offset>>9)-64; 
	 
		for(page_cnt=0; page_cnt<64; page_cnt++) { 
			if(!(page_cnt%32)) 
				EraseBlock(page); 
			if(!WritePage(page+page_cnt, dat)) 
				break; 
		} 
		if(page_cnt>=64) 
			ret = -1; 
		printf("Save boot params %s.\n", ret?"fail":"success"); 
	} else { 
		memcpy(dat, (void *)0x04000000, NOR_PARAMS_OFFSET); 
		memcpy(dat+NOR_PARAMS_OFFSET, &boot_params, sizeof(boot_params)); 
		ProgNorFlash(0, (U32)dat, sizeof(dat));	//28F128 
	} 
	 
	DsNandFlash(); 
	 
	return ret; 
} 
 
int set_params(void) 
{ 
	int i, key, chg=0; 
	ParamItem *pPID; 
	 
	printf("\nConfig parameters\n"); 
	 
	do { 
		pPID = &boot_params.start; 
		for(i=0; pPID<=&boot_params.user_params; pPID++, i++) 
			printf("[%d] : %s%-8s is 0x%08x (%d)\n", 
						i, (i>9)?"":" ", pPID->flags, pPID->val, pPID->val); 
		printf("[%d] : Exit\n", i); 
		if(boot_params.user_params.val) 
			printf("User parameters is : \"%s\"\n", boot_params.string); 
		 
		printf("\nplease select item:"); 
		key = Uart_GetIntNum(); 
		if(key>=0&&keyval = key; 
			} 
		} else 
			break; 
	} while(1); 
	 
	if(chg) { 
		printf("Do you want to save parameters? press y or Y for save.\n"); 
		key = getch(); 
		if(key=='y'||key=='Y') 
			save_params(); 
	} 
	 
	return 0; 
}