/*************nand flash***********
 *	
 **************************/
 #include "2410lib.h"
 #include "2410addr.h"




#define U32 unsigned int
#define U16 unsigned short
#define U8 unsigned char
static U16 NandAddr;
static U16 support;
extern U32 downloadFileSize;
extern U32 downloadAddress;


#define	EnNandFlash()	(rNFCONF |= 0x8000)
#define	DsNandFlash()	(rNFCONF &= ~0x8000)
#define	InitEcc()		(rNFCONF |= 0x1000)
#define	NoEcc()			(rNFCONF &= ~0x1000)
#define	NFChipEn()		(rNFCONF &= ~0x800)
#define	NFChipDs()		(rNFCONF |= 0x800)

#define	WrNFCmd(cmd)	(rNFCMD = (cmd))
#define	WrNFAddr(addr)	(rNFADDR = (addr))
#define	WrNFDat(dat)	(rNFDATA = (dat))
#define	RdNFDat()		(rNFDATA)
#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;
static U32 StartPage, BlockCnt;



#define	BLK_IDXL	8
#define	BLK_IDXH	9
#define	FMT_TAG		15


#define u_char	U8







 static U32 ReadChipId(void)
{
	U32 id;
	
	NFChipEn();	
	WrNFCmd(RdIDCMD);
	WrNFAddr(0);
	while(NFIsBusy());	
	id  = RdNFDat()<<8;
	id |= RdNFDat();		
	NFChipDs();		
	
	return id;
}

  
static void InitNandCfg(void)
{
	//enable nand flash control, initilize ecc, chip disable,
	rNFCONF = (1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7);	
}

 		 

   

void InitNandFlash(void)
{	
	U32 i;
	
 InitNandCfg();
		i = ReadChipId();
//	uart_printf("Read chip id = %x\n", i);	
	if((i==0x9873)||(i==0xec75))	
		NandAddr = 0;
	else if(i==0xec76)
	{	
		support=1;	
		NandAddr = 1;
	}
	else {	
	//	puts("Chip id error!!!\n");
	uart_printf("Chip id error!!!\n");
		return;
	}
//*/	printf("Nand flash status = %x\n", ReadStatus()); 	 */
} 	   




#ifdef	WIAT_BUSY_HARD
#define	WaitNFBusy()	while(NFIsBusy())
#else
static U32 WaitNFBusy(void)	
{
	U8 stat;
	
	WrNFCmd(QUERYCMD);
	do {
		stat = RdNFDat();
		//uart_printf("%x\n", stat);
	}while(!(stat&0x40));
	WrNFCmd(READCMD0);
	return stat&1;
}
#endif


 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
	
	//printf("Erase block 0x%x %s\n", addr, stat?"fail":"ok");
//	uart_printf	(".");
	return stat;
}


/**
 * 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
 */




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();
	WrNFCmd(READCMD0);//add 

	for(i=0; i<512; i++)
		buf[i] = RdNFDat();
	NFChipDs();
}




U32 WritePage(U32 addr, U8 *buf)
{
	U16 i;
	U8 stat;

	
	NFChipEn();
    WrNFCmd(READCMD0);//add 


	WrNFCmd(PROGCMD0);
	WrNFAddr(0);
	WrNFAddr(addr);
	WrNFAddr(addr>>8);
	if(NandAddr)
		WrNFAddr(addr>>16);

	for(i=0; i<512; i++)
		WrNFDat(buf[i]);
	
	WrNFCmd(PROGCMD1);
	stat = WaitNFBusy();
	WrNFCmd(READCMD0);//add
	NFChipDs();
		
	if(stat)
		uart_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]) {
				uart_printf("Check data at page 0x%x, offset 0x%x fail\n", addr, i);
				stat = 1;
				break;
			}
	}
		
	return stat;	
}




















