www.pudn.com > cmd_nand.rar > cmd_nand.c


/*
 * (C) 2004 Samsung Electronics
 *        Young-jun Jang 
 *        - add/modify nandw,nandr, nande, nandv
 *        - bad block management (bbcheck, bbmark)
 *        - yaffs image r/w (nandyw, nandyr)
 * (C) 2004 Samsung Electronics
 *        SW.LEE 
 *        - add  nande, nandE
 *        - support 16Bit / 3 Addr cycle nand
 * (C) 2003 Samsung Electronics
 *        - getfree
 *
 * Driver for NAND support, Rick Bronson
 * borrowed heavily from:
 * (c) 1999 Machine Vision Holdings, Inc.
 * (c) 1999, 2000 David Woodhouse 
 */


#include 

#if defined(CONFIG_S3C24XX)

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#include 
#include 
#include 

#include 

#include 
#include 

#ifdef CONFIG_SHOW_BOOT_PROGRESS
#include 
#define SHOW_BOOT_PROGRESS(arg)	show_boot_progress(arg)
#else
#define SHOW_BOOT_PROGRESS(arg)
#endif

#define BAD_CHECK

//#undef	ECC_CHECK	/* XXX: we will do in the future */
#define ECC_CHECK



#ifdef	ECC_CHECK
#define		ECC_COUNT_BIT	256
#endif

#define ROUND_DOWN(value,boundary)      ((value) & (~((boundary)-1)))

static int NF_EraseBlock(u32 blockNum);
static int NF_WritePage(u32 block, u32 page, u8 * buffer);
static int NF_WriteOob(u32 block, u32 page, u8 * buffer, int yaffs_option);
static int NF_IsBadBlock(u32 block);
static int NF_MarkBadBlock(u32 block, int mark_flag);
static void NF_Reset(void);



static u8 seBuf[NAND_OOB_SIZE] = {
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};


/*
 * address format
 *              17 16         9 8            0
 * --------------------------------------------
 * | block(12bit) | page(5bit) | offset(9bit) |
 * --------------------------------------------
 */
static int nandll_read_page(uchar *buf, ulong addr)
{
        int i;
	int loop = 0;
	int j = 0;
#ifdef ECC_CHECK
	u8 oobbuf[NAND_OOB_SIZE] = {0};
#endif

#ifdef S3C24X0_16BIT_NAND
	ushort *ptr16 = (ushort *)buf;
#endif

        if (addr & NAND_PAGE_MASK) {
                return -1;      /* invalid alignment */
        }
	
//        NFCONT_REG &= ~(1<<1); //NFCONT_REG &= ~(1<<1); //NAND_ENABLE_CE();
        NFCONT_REG &= ~(1<<1);

#ifdef ECC_CHECK
	
	NF_RSTECC();		// Initialize ECC
	NF_MECC_UnLock();
	NF_CLRRnB();
#endif
        NFCMD_REG = NAND_CMD_READ0;		//0x0

        /* Write Address */
        NFADDR_REG = addr & 0xff;
        NFADDR_REG = (addr >> 7) & 0x0f;
        NFADDR_REG = (addr >> 11) & 0xff;
        NFADDR_REG = (addr >> 19) & 0xff;
	
	NFCMD_REG = 0x30;
        NF_TRANSRnB();
#ifndef	   ECC_CHECK	
	for(i=0; i < NAND_PAGE_SIZE; i++) {
                *buf = NFDATA8_REG;
		buf++;
        }
#else
	seBuf[0] = 0xff;
        seBuf[1] = 0xff;
        loop = 0;
	for(i = 0;i>8)&0xff); 
		seBuf[42+loop] = ((NFMECC0_REG >>16)&0xff);
		seBuf[42+loop] |= 0x03;
		loop += 3;
		NF_RSTECC();		// Initialize ECC
		NF_MECC_UnLock();
		NF_CLRRnB();		
	}

#endif
	NFCONT_REG |= (1<<1);

#if 0
#ifdef ECC_CHECK
	nandll_read_oob(oobbuf,addr);
	printf("\nRead ECC :");
	for(i = 0;i < 5; i++)
		printf("%x ",oobbuf[i]);
	printf("\nECC CODE :");
	for(i = 0;i < 5; i++)
		printf("%x ",seBuf[i]);
#endif
#endif
        return 0;
}

static int nandll_read_oob(char *buf, ulong addr)
{
        int i;
#ifdef S3C24X0_16BIT_NAND
	ushort *ptr16 = (ushort *)buf;
#else
	u8 *oobptr8 = (u8 *)buf;
#endif

        /* Chip Enable */
        NFCONT_REG &= ~(1<<1); //NFCONT_REG &= ~(1<<1); //NAND_ENABLE_CE();
	NF_CLRRnB();

        /* READOOB */
        NFCMD_REG = 0x0;//NAND_CMD_READOOB;

        /* Write Address */
        NFADDR_REG = 0x00;//addr & 0xff ;
        NFADDR_REG =  0x08;//(addr >> 0x07)&0x0f;
        NFADDR_REG = (addr >> 11) & 0xff;
        NFADDR_REG = (addr >> 19) & 0xff;

	NFCMD_REG = 0x30;
        NF_TRANSRnB();
	
	for(i=0; i < NAND_OOB_SIZE; i++) {
                *oobptr8 = NFDATA8_REG;
		oobptr8++;
        }
        NFCONT_REG |= (1<<1); //NAND_DISABLE_CE();
/*        printf("\nLast OOB :");
	for(i = 0;i < NAND_OOB_SIZE;i++)
		printf(" %2x ",buf[i]);
*/        return 0;
}

static int is_bad_block(unsigned long addr)
{
	char oob_buf[64];

	nandll_read_oob((char *)oob_buf, addr);   /* culprit */
#ifdef S3C24X0_16BIT_NAND
	if ( (oob_buf[0] != 0xFF) ||  (oob_buf[1] != 0xFF) )
		return 1;
#else
	if (oob_buf[0] != 0xFF)
		return 1;
#endif
	else
		return 0;
}

#ifdef OREIAS
#define adjust_bank(x)	\
	do { \
		if(x>=0x11e00000) \
			x=x+0x6200000;\
	} while(0)
#endif

#define check_blk_range(blk) \
	do { \
		if (blk<0 || blk>=4096) { \
			printf( "out of block range\n" ); \
			return 1; \
		} \
	} while(0)

#define check_page_range(page) \
	do { \
		if (page<0 || page>=32) { \
			printf( "out of page range\n" ); \
			return 1; \
		} \
	} while(0)

static int s3c24x0_nand_read(uint blockIndex, int size, uint destAddress, int flag)
{
	char *buf = (char *) destAddress;
	char page_buf[NAND_PAGE_SIZE];
	char oob_buf[NAND_OOB_SIZE];
	int i, j;
	u32 src_addr = blockIndex * NAND_BLOCK_SIZE;

	printf("block read : ");

	while (size > 0) {
		if (flag != NF_RW_YAFFS) {
			/* If this block is bad, go next block */
			if (is_bad_block(src_addr)) {
				src_addr += NAND_BLOCK_SIZE;
				continue;
			}
		}

		printf("%X ", (src_addr >> 17));

		/* Read block */
		for (i = 0; i < NAND_PAGES_IN_BLOCK; i++) {
			nandll_read_page((uchar *) page_buf, src_addr);
			for (j = 0; j < NAND_PAGE_SIZE; j++) {
				*buf++ = page_buf[j];
			}
			size -= NAND_PAGE_SIZE;
			if (size <= 0)
				break;

			if (flag == NF_RW_YAFFS) {
				/* read oob */
				nandll_read_oob((char *) oob_buf, src_addr);
				for (j = 0; j < NAND_OOB_SIZE; j++) {
					*buf++ = oob_buf[j];
				}
				size -= NAND_OOB_SIZE;
				if (size <= 0)
					break;
			}

			src_addr += NAND_PAGE_SIZE;
		}
	}
	printf("\n");

	return 0;
}

/*
 * s3c24x0_nand_write
 *
 * yaffs_option : only used when flag is yaffs mode.
 */
static int s3c24x0_nand_write(
 uint targetBlock,
 uint targetSize,
 uint srcAddress,
 int flag,
 int yaffs_option
)
{
	int i;
	int programError = 0;
	u8 *srcPt, *saveSrcPt;
	u32 blockIndex;

	printf("\nNAND Flash Write\n");
	printf("Source base address        = 0x%x\n", srcAddress);
	printf("Target start block number  = 0x%x (%d)\n", targetBlock, targetBlock);
	printf("Target size    (0x4000*n)  = 0x%x\n", targetSize);
	printf("block written :\n");

	srcPt = (u8 *) srcAddress;
	blockIndex = targetBlock;
	while (1) {
		saveSrcPt = srcPt;
#if 1

#ifdef BAD_CHECK
		if (NF_IsBadBlock(blockIndex)) {
			blockIndex++;	// for next block
			continue;
		}
#endif
		if (!NF_EraseBlock(blockIndex)) {
			blockIndex++;	// for next block
			printf(" Error->  Erase Block %d  \n", (int) blockIndex);
			continue;
		}
#endif

		for (i = 0; i < NAND_PAGES_IN_BLOCK; i++) {
			if (!NF_WritePage(blockIndex, i, srcPt)) {
				programError = 1;
				break;
			}
/*
#ifdef ECC_CHECK
			if (flag != NF_RW_YAFFS) {
				if (!NF_ReadPage(blockIndex, i, srcPt)) {
					printf("ECC Error(block=%d,page=%d!!!\n", (int) blockIndex, i);
				}
			}
#endif
*/			srcPt += NAND_PAGE_SIZE;
/*
			if (flag == NF_RW_YAFFS) {
				if (!NF_WriteOob(blockIndex, i, srcPt, yaffs_option)) {
					programError = 1;
					break;
				}
				srcPt += NAND_OOB_SIZE;
			}

*/			//printf(".");
			if ((u32) srcPt >= (srcAddress + targetSize)) {	// Check end of buffer
				break;	// Exit for loop
			}
		}
		if (programError == 1) {
			blockIndex++;
			srcPt = saveSrcPt;
			programError = 0;
			continue;
		}

		printf("%3x ", blockIndex);
		if (!((blockIndex+1) % 16))
			printf("\n");

		if ((u32) srcPt >= (srcAddress + targetSize))
			break;	// Exit while loop
		blockIndex++;
	}

	printf("\n\n");
	return 0;
}

int do_nandE(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	int startblk, size, eraseblocks, i;

	if (argc != 3) {
		printf("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	startblk = simple_strtoul(argv[1], NULL, 16);
	size = simple_strtoul(argv[2], NULL, 16);
	printf("StartBlock %d (0x%x) : Size %d (0x%x) \n", startblk, startblk, size, size);
	eraseblocks = size / NAND_BLOCK_SIZE;
	printf("Total Erase Blocks %d (0x%x) \n", eraseblocks, eraseblocks);
	udelay(10000);

	NF_Reset();
	for (i = 0; i < eraseblocks; i++) {
		NF_EraseBlock(startblk);
		startblk++;
	}

	return 0;
}

int do_nandw(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	ulong startblk, size, memadr;

	if (argc != 4) {
		printf("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	startblk = simple_strtoul(argv[1], NULL, 16);
	size = simple_strtoul(argv[2], NULL, 16);
	memadr = simple_strtoul(argv[3], NULL, 16);

	NF_Reset();
	s3c24x0_nand_write(startblk, size, memadr, NF_RW_NORMAL, 0);

	{
		uint *magic = (uint*)(PHYS_SDRAM_1);
		magic[0] = 0x27051956;

	}
	return 0;
}


int do_nandr(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	ulong startblk, size, memadr;
	if (argc != 4) {
		printf("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	startblk = simple_strtoul(argv[1], NULL, 16);
	size = simple_strtoul(argv[2], NULL, 16);
	memadr = simple_strtoul(argv[3], NULL, 16);

	NF_Reset();
	s3c24x0_nand_read(startblk, size, memadr, NF_RW_NORMAL);
	return 0;
}

int do_nande(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	int i;
	ulong blk_start, blk_end;

	if (argc != 3) {
		printf("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	blk_start = simple_strtoul(argv[1], NULL, 16);
	blk_end = simple_strtoul(argv[2], NULL, 16);

	for (i = blk_start; i <= blk_end; i++) {
		if (!NF_EraseBlock(i)) {
			printf("nand flash erase error : at block %x\n", i);
		}
	}

	printf("nand flash erase complete\n");

	return 0;
}

int do_bbmark(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	ulong blk;

	if (argc != 3) {
		printf("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	blk = simple_strtoul(argv[1], NULL, 16);
	check_blk_range(blk);

	if (!NF_EraseBlock(blk)) {
		printf("erase error\n");
	}

	if (strcmp(argv[2], "on") == 0)
		NF_MarkBadBlock(blk, NF_BB_ON);
	else
		NF_MarkBadBlock(blk, NF_BB_OFF);

	return 0;
}

int do_bbcheck(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	int i, bb_cnt;

	printf("Bad block list : \n");
	for (bb_cnt = 0, i = 0; i < 4096; i++) {
		if (NF_IsBadBlock(i)) {
			bb_cnt++;
		}
	}

	if (bb_cnt > 0) {
		printf("\n Total bad block count : %d \n", bb_cnt);
	}
	else {
		printf("No bad block\n");
	}

	return 0;
}

/* show page data */
int do_nandv(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	int blk, page, i;
	u32 oob_buf[16 / 4];
	u32 page_buf[512 / 4];

	if (argc != 3) {
		printf("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	blk = simple_strtoul(argv[1], NULL, 16);
	page = simple_strtoul(argv[2], NULL, 10);
	check_blk_range(blk);
	check_page_range(page);

	nandll_read_page((u8 *) page_buf, (blk * NAND_BLOCK_SIZE) + (page * NAND_PAGE_SIZE));
	for (i = 0; i < 32; i++) {
		printf("%03x: %08x %08x %08x %08x\n",
		       i << 4,
		       page_buf[(i << 2) + 0], page_buf[(i << 2) + 1],
		       page_buf[(i << 2) + 2], page_buf[(i << 2) + 3]);
	}

	nandll_read_oob((char *) oob_buf, (blk * NAND_BLOCK_SIZE) + (page * NAND_PAGE_SIZE));
	printf("\nOOB: %08x %08x %08x %08x\n\n", oob_buf[0], oob_buf[1], oob_buf[2], oob_buf[3]);

	return 0;
}

int do_nandyw(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	ulong startblk, size, memadr;
	int ecc_option;

	if (argc != 5) {
		printf("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	startblk = simple_strtoul(argv[1], NULL, 16);
	check_blk_range(startblk);
	size = simple_strtoul(argv[2], NULL, 16);
	memadr = simple_strtoul(argv[3], NULL, 16);
	ecc_option = (argv[4][0] == 'y') ? NF_USE_ECC : NF_USE_MTD_ECC;

	// yaffs image don't use 1st block
	startblk++;

	NF_Reset();
	s3c24x0_nand_write(startblk, size, memadr, NF_RW_YAFFS, ecc_option);

	return 0;
}

int do_nandyr(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	ulong startblk, size, memadr;

	if (argc != 4) {
		printf("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	startblk = simple_strtoul(argv[1], NULL, 16);
	size = simple_strtoul(argv[2], NULL, 16);
	memadr = simple_strtoul(argv[3], NULL, 16);

	// yaffs image don't use 1st block
	startblk++;

	NF_Reset();
	s3c24x0_nand_read(startblk, size, memadr, NF_RW_YAFFS);
	return 0;
}

/* getfree added U_BOOT_CMD TABLE 2003.12.05 */

U_BOOT_CMD(nandr, 4, 0, do_nandr,
	   "nandr   - read data from NAND (specific)\n",
	   "blk# size memaddr\n"
	   "    - SMDK24XX NAND Flash Read Command\n"
	   "    - targetblock 0~0xfff(4095), targetsize memory addr\n");

U_BOOT_CMD(nandw, 4, 0, do_nandw,
	   "nandw   - write data to NAND (specific)\n",
	   "blk# size memaddr\n"
	   "    - SMDK24XX NAND Flash Write Command\n"
	   "    - targetblock 0~0xfff(4095), targetsize memory addr\n");

/* add command (nande, bbmark, bbcheck) by jyj. (2004.8.10) */
U_BOOT_CMD(nande, 3, 0, do_nande,
	   "nande   - erase NAND block (specific)\n",
	   "startblk# endblk#\n"
	   "    - SMDK24XX NAND Flash Erase Command\n"
	   "    - block range : 0 ~ 0xfff(4095) in hex value\n");

U_BOOT_CMD(bbmark, 3, 0, do_bbmark,
	   "bbmark  - mark NAND bad block (specific)\n",
	   "blk# on/off\n"
	   "    - SMDK24XX NAND Flash Mark Bad Block Command\n"
	   "    - block range : 0 ~ 0xfff(4095) as hex value\n"
	   "    - on/off : mark/unmark bad block\n");

U_BOOT_CMD(bbcheck, 3, 0, do_bbcheck,
	   "bbcheck - show NAND bad block (specific)\n",
	   "    - SMDK24XX NAND Flash Show Bad Block Command");

U_BOOT_CMD(nandv, 3, 0, do_nandv,
	   "nandv   - show NAND block data (specific)\n",
	   "blk page\n"
	   "    - SMDK24XX NAND Flash Show Block Data Command\n"
	   "    - block range : 0 ~ 0xfff(4095) in hexa\n"
	   "    - page  range : 0 ~ 31 in decimal\n");

U_BOOT_CMD(nandyw, 5, 0, do_nandyw,
	   "nandyw  - write YAFFS block in NAND (specific)\n",
	   "blk# size addr ecc_option\n"
	   "    - SMDK24XX NAND Flash Write Command for Yaffs\n"
	   "    - targetblock 0~0xfff(4095), targetsize memory addr\n"
	   "    -  ecc_option : [y] use yaffs ecc / [m] use mtd ecc\n");

U_BOOT_CMD(nandyr, 4, 0, do_nandyr,
	   "nandyr  - read YAFFS block in NAND (specific)\n",
	   "blk# size addr\n"
	   "    - SMDK24XX NAND Flash Read Command for Yaffs\n" "    - block 0~0xfff(4095)\n");

U_BOOT_CMD(nandE, 4, 0, do_nandE,
	   "nandE   - erase block and OOB (specific)\n",
	   "blk# size" "    - delete all blocks in given range regardless Bad Blcok\n");



/*
 * NF_MarkBadBlock :
 */

static int NF_MarkBadBlock(u32 block, int mark_flag)
{
	int i;
	u32 blockPage;
#ifdef S3C24X0_16BIT_NAND
	u16 *Buf = (unsigned short *) seBuf;
#endif

	blockPage = (block << 6);

	seBuf[0] = 0x44;
	seBuf[1] = 0xff;
	seBuf[40] = 0xff;
	seBuf[41] = 0xff;
	seBuf[42] = 0xff;
	
	seBuf[43] = 0xff;
	seBuf[44] = 0xff;
	seBuf[45] = 0xff;
	
	seBuf[46] = 0xff;
	seBuf[47] = 0xff;
	seBuf[48] = 0xff;
	
	seBuf[49] = 0xff;
	seBuf[50] = 0xff;
	seBuf[51] = 0xff;
	
	seBuf[52] = 0xff;
	seBuf[53] = 0xff;
	seBuf[54] = 0xff;
	
	seBuf[55] = 0xff;
	seBuf[56] = 0xff;
	seBuf[57] = 0xff;
	
	seBuf[58] = 0xff;
	seBuf[59] = 0xff;
	seBuf[60] = 0xff;
	
	seBuf[61] = 0xff;
	seBuf[62] = 0xff;
	seBuf[63] = 0xff;
	
//	seBuf[5] = 0x44;	// 0xff is good block, else is bad block
	if (mark_flag == NF_BB_OFF)
		seBuf[0] = 0xff;

	NF_nFCE_L();

//	NFCMD_REG = NAND_CMD_READOOB;
//	NFCMD_REG = NAND_CMD_SEQIN;	// Write 1st command

	NFCMD_REG = 0x80;
	
	NFADDR_REG = 0x00;	// The mark of bad block is
	NFADDR_REG = 0x00;
	
	NFADDR_REG = blockPage & 0xff;	// marked 5th spare array
	NFADDR_REG = (blockPage >>8) & 0xff;	// in the 1st page.
	
	for (i = 0; i < NAND_OOB_SIZE; i++) {
		NFDATA8_REG = seBuf[i];
	}

//	NFCMD_REG = NAND_CMD_PAGEPROG;
	NFCMD_REG = 0x10;
	
	for (i = 0; i < 10; i++);
	NF_TRANSRnB();
	NFCMD_REG = NAND_CMD_STATUS;
	for (i = 0; i < 3; i++);
	if (NFDATA8_REG & 0x1) {	// Spare arrray write error
		NF_nFCE_H();
		printf("[Program error is occurred but ignored]\n");
	}
	else {
		NF_nFCE_H();
	}

	if (mark_flag == NF_BB_ON) {
		printf("[block 0x%x is marked as a bad block]\n", block);
	}
	else {
		printf("[block 0x%x is marked as a good block]\n", block);
	}
	return 1;
}


static int NF_WritePage(u32 block, u32 page, u8 * buffer)
{
	int i;
	int j = 0;
	int loop = 0;
	u32 blockPage = (block * NAND_PAGES_IN_BLOCK) + page;
#ifdef S3C24X0_16BIT_NAND
	u16 *Buf = (unsigned short) seBuf;
	u16 *ptr16 = buffer;
#else
	u8 *ptr8 = buffer;
#endif
	int ret = 1;

#ifdef	ECC_CHECK	
	NF_RSTECC();		// Initialize ECC
	NF_MECC_UnLock();
	NF_CLRRnB();
#endif
	NAND_WP_OFF();
	NF_nFCE_L();
	
//	NFCMD_REG = NAND_CMD_READ0;
//	NFCMD_REG = NAND_CMD_SEQIN;

	NFCMD_REG = 0x80;
	
	NFADDR_REG = 0x00;
	NFADDR_REG = 0x00;
	
	NFADDR_REG = blockPage & 0xff;
	NFADDR_REG = ((blockPage >> 8) & 0xff);

#ifndef	ECC_CHECK	
	for(i = 0;i>8)&0xff); 
		seBuf[42+loop] = ((NFMECC0_REG >>16)&0xff);
		seBuf[42+loop] |= 0x03;
		loop += 3;
		NF_RSTECC();		// Initialize ECC
		NF_MECC_UnLock();
		NF_CLRRnB();		
	}
	
#endif
//	NFCMD_REG = NAND_CMD_PAGEPROG;
	NFCMD_REG = 0x10;
	for (i = 0; i < 10; i++);
	NF_TRANSRnB();

	NFCMD_REG = 0x70;//NAND_CMD_STATUS;
	for (i = 0; i < 10; i++);
	if (NFDATA8_REG & 0x1) {	/* Page Error */
		printf("[PROGRAM_ERROR:block#=%d]\n", block);
		NF_MarkBadBlock(block, NF_BB_ON);
		ret = 0;
	}	
	NF_nFCE_H();
	NAND_WP_ON();
	
#ifdef ECC_CHECK
	NF_WriteOob(block,page,seBuf,-1);
#endif
	
	return ret;
}


static int NF_WriteOob(u32 block, u32 page, u8 * buffer, int yaffs_option)
{
	int i;
	u32 blockPage = (block * NAND_PAGES_IN_BLOCK) + page;
#ifdef S3C24X0_16BIT_NAND
	u16 *ptr16 = buffer;
#else
	u8 *ptr8 = buffer;
	u8 oobBuf[NAND_OOB_SIZE];

	for (i = 0; i < NAND_OOB_SIZE; i++) {
		oobBuf[i] = (*ptr8++);
	}
	if (yaffs_option == NF_USE_MTD_ECC) {
		oobBuf[8] = 0xFF;
		oobBuf[9] = 0xFF;
		oobBuf[10] = 0xFF;
		oobBuf[13] = 0xFF;
		oobBuf[14] = 0xFF;
		oobBuf[15] = 0xFF;
	}
#endif
	
	NF_nFCE_L();
	
//	NFCMD_REG = NAND_CMD_READOOB;
//	NFCMD_REG = NAND_CMD_SEQIN;

	NFCMD_REG =0x80;
	
	NFADDR_REG = 0x00;
	NFADDR_REG = 0x08;
	
	NFADDR_REG = (blockPage & 0xff);
	NFADDR_REG = ((blockPage >> 8) & 0xff);

	for (i = 0; i < NAND_OOB_SIZE; i++) {
		NFDATA8_REG = oobBuf[i];
	}

//	NFCMD_REG = NAND_CMD_PAGEPROG;
	NFCMD_REG = 0x10;
	for (i = 0; i < 10; i++);
	NF_TRANSRnB();

	NFCMD_REG = NAND_CMD_STATUS;
	for (i = 0; i < 3; i++);
	if (NFDATA8_REG & 0x1) {	/* Page Error */
		printf("[Program error is occurred but ignored]\n");
	}

	NF_nFCE_H();
/*
	printf("\n ECC :" );
	for(i = 0;i<5;i++)
	{
		printf(" %x ",oobBuf[i]);		
	}
*/
	return 1;
}


static void NF_Reset(void)
{
	int i;

	NF_CLRRnB();
	NF_nFCE_L();

	NFCMD_REG = NAND_CMD_RESET;
	for (i = 0; i < 80; i++);
	NF_TRANSRnB();

	NF_nFCE_H();
}

/*
 * NF_EraseBlock
 */
#if 0
static int NF_EraseBlock (u32 block)
{
	u32 blockPage;
	int i, ret = 1;

	NAND_WP_OFF();
	blockPage = block * NAND_PAGES_IN_BLOCK;
	NF_CLRRnB();
	NF_nFCE_L();
	NFCMD_REG = 0x60//NAND_CMD_ERASE1;
	
	NFADDR_REG = blockPage & 0xff;
	NFADDR_REG = (blockPage >> 8) & 0xff;
	NFADDR_REG = (blockPage >> 16) & 0xff;


	NFCMD_REG = NAND_CMD_ERASE2;
	for (i = 0; i < 40; i++);
	NF_TRANSRnB();

	NFCMD_REG = NAND_CMD_STATUS;
	if (NFDATA8_REG & 0x1) { /* we got Erase error */
		printf("[ERASE_ERROR:block#=%d]\n", block);
		NF_MarkBadBlock(block, NF_BB_ON);
		ret = 0;
	}

	NF_nFCE_H();
	NAND_WP_ON();

	return ret;
}
#else

static int NF_EraseBlock (u32 block)
{
	u32 blockPage;
	int i, ret = 1;

	NAND_WP_OFF();
	blockPage = block * NAND_PAGES_IN_BLOCK;
	NF_CLRRnB();
	NF_nFCE_L();
	NFCMD_REG = 0x60;//NAND_CMD_ERASE1;
	
//	NFADDR_REG = blockPage & 0xff;
//	NFADDR_REG = (blockPage >> 8) & 0xff;
//	NFADDR_REG = (blockPage >> 16) & 0xff;

	NFADDR_REG = (blockPage & 0xff);
	NFADDR_REG = ((blockPage >> 8) & 0xff);

	NFCMD_REG = 0xD0;//NAND_CMD_ERASE2;
	
	for (i = 0; i < 40; i++);
	NF_TRANSRnB();

	NFCMD_REG = NAND_CMD_STATUS;
	if (NFDATA8_REG & 0x1) { /* we got Erase error */
		printf("[ERASE_ERROR:block#=%d]\n", block);
		NF_MarkBadBlock(block, NF_BB_ON);
		ret = 0;
	}

	NF_nFCE_H();
	NAND_WP_ON();

	return ret;
}
#endif

static int NF_IsBadBlock(u32 block)
{
	int i;
	int blockPage;
#ifdef S3C24X0_16BIT_NAND
	u16 data;
#else
	u8 data;
#endif
	blockPage = block * NAND_PAGES_IN_BLOCK;
	NF_CLRRnB();
	NF_nFCE_L();
//Joe
# if 0
	NFCMD_REG = NAND_CMD_READOOB;

#ifdef S3C24X0_16BIT_NAND
	NFADDR_REG = 512 & 0x7;	/* X16 A0~A2 are valid */
#else
	NFADDR_REG = 517 & 0xf;	// Read the mark of bad block in spare array(M addr=5)
#endif
	NFADDR_REG = blockPage & 0xff;	// The mark of bad block is in 0 page
	NFADDR_REG = (blockPage >> 8) & 0xff;	// For block number A[24:17]
#ifdef NAND_3_ADDR_CYCLE
#else
	NFADDR_REG = (blockPage >> 16) & 0xff;	// For block number A[25]
#endif

#endif

	NFCMD_REG = 0x0;
	
	NFADDR_REG = 0x00;
	NFADDR_REG  = 0x08;
	
	NFADDR_REG = (blockPage&0xff);
	NFADDR_REG =((blockPage>>8)&0xff);
	
	NFCMD_REG = 0x30;
	
//	data = NFDATA8_REG;
	for (i = 0; i < 10; i++);	/* dummy check me */

	NF_TRANSRnB();

	data = NFDATA8_REG;

	NF_nFCE_H();

	if (data != 0xff)
	{
		printf("[block 0x%x has been marked as a bad block(%x)]\n", block, data);
		return 1;
	}
	else {
		return 0;
	}
}

/*
void nand_init()
{
	printf("64MB\n");	
}
*/

#endif		/* (CONFIG_COMMANDS & CFG_CMD_NAND) */

#endif		/* CONFIG_S3C24XX */