/******************************************************************************
 * $Id: rtk_nand.c,v 1.0 2015/09/11 Scott Wu Exp $
 * drivers/mtd/nand/rtk_nand.c
 * Overview: Realtek MTD NAND Driver 
 * Copyright (c) 2015 Realtek Semiconductor Corp. All Rights Reserved.
 * Modification History:
 *    #000 2015-09-11 Scott Wu create file
 *
 *******************************************************************************/
/**
********************************** include file*********************************
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/string.h>
#include <linux/mtd/partitions.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/jiffies.h>
#include <linux/vmalloc.h>
#include <mtd/mtd-abi.h>
#include <asm/io.h>
#include <asm/page.h>
#include "bspchip.h"

/**
******************************** macro definition*******************************
*/
#define RTK_MTDSIZE	(sizeof (struct mtd_info) + sizeof (struct nand_chip) + sizeof (struct rtk_priv))
#define RTK_STEP_DATA_SIZE 512
#define NOTALIGNED_PAGE(mtd, x) ((x & (mtd->writesize-1)) != 0)
#define NOTALIGNED_BLOCK(mtd, x) ((x & (mtd->erasesize-1)) != 0)
#define ALL_ONE (1<<8)
/** 
 * define mars read/write NAND HW registers
 * use them because standard readb/writeb have warning msgs in our gcc 2.96
 * ex: passing arg 2 of `writeb' makes pointer from integer without a cast
 */
#define rtk_readb(offset)         (*(volatile unsigned char *)(offset))
#define rtk_readw(offset)         (*(volatile unsigned short *)(offset))
#define rtk_readl(offset)         (*(volatile unsigned long *)(offset))

#define rtk_writeb(val, offset)    (*(volatile unsigned char *)(offset) = val)
#define rtk_writew(val, offset)    (*(volatile unsigned short *)(offset) = val)
#define rtk_writel(val, offset)    (*(volatile unsigned long *)(offset) = val)

/*
 * This is defined in Linux-3.10 but delete in Linux-3.18 where use to decide dma buffer size
 */
#define NAND_MAX_OOBSIZE        640
#define NAND_MAX_PAGESIZE       8192

/** 
 * If the page size is 2K, the bbi is in data area where we need to switch with 
 * oob for maintaining the bbi architecture.
 */
#define RTK_BBI_DMABUF_POS_2K  2048
#define RTK_BBI_SWITCHTO_POS_2K  (2096 + 6 -1)
#define RTK_OOB_BBI_POS_2K  ((16*4) - 10 -1)

#define NAND_ADDR_MASK	(3<<28)
#if defined(CONFIG_RTL8685) || defined(CONFIG_RTL8685S)
#define NAND_ADDR_CYCLE	(((*(volatile unsigned int *)((NACFR)) & NAND_ADDR_MASK) == 0) ? 1:0)
#else
#include <bspchip_8672_8676.h>
#define NAND_ADDR_CYCLE (((*(volatile unsigned int *)((BSP_MISC_PINOCR)) & BSP_NAND_ADDR_MASK) == 0) ? 1:0)
#endif

/**
 * It define a tolerating percent of bad block numbers in the system.
 */
#define BBT_PERCENT 5
/*define the last BBT block's position default : 128MB*/
//#define NORMAL_BBT_POSITION           0x8000000 
/*init value of BBT element*/
#define	BB_INIT	0xFFFE
#define BB_DIE_INIT	0xEEEE
/*bbi value of BBT pgae*/
#define	BBT_TAG	0xBB
/*the number of BBT backups*/
#define BACKUP_BBT 3
/**
******************************* extern function*******************************
*/

extern int add_mtd_device(struct mtd_info *mtd);
extern int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
extern int del_mtd_partitions(struct mtd_info *);
extern int parse_mtd_partitions(struct mtd_info *master, const char * const *types, struct mtd_partition **pparts, struct mtd_part_parser_data *data);
/**
******************************* struct definition*******************************
*/

/**
 * rtk private data struct where store in nand_chip->priv
 * @data_pos:	where to read/rite from dma buffer  
 * @command_record:		records the last cmd where is used to determine using dma or PIO
 * @dmabuf:		the dma bufferfor flash controller
 * @max_ecc_counter:	the records of max ecc number for all steps
 * @write_page:	used to records NAND_CMD_SEQIN cmd page information
 * @select_chip_record:		since NACMR cannot read we need to use select_chip_record to record the chip we select
 * @bbt_num:	the numbers of elements in BBT.
 */
struct rtk_priv {
	//dma variables
	unsigned int data_pos;
	unsigned int command_record;
	uint8_t *dmabuf;
	//ecc variables
	int max_ecc_counter;
	//write page record
	int write_page;
	//NACMR record
	unsigned int select_chip_record;
	//number of BBT elements
	unsigned int bbt_num;
};

/**
 * BBT element struct
 * @bad_block:	this bad block's index
 * @block_info:	this bad block's value
 * @BB_die: doesn't use any more. We cannot delete it since compatible with bootcode's framework.
 * @RB_die: doesn't use any more. We cannot delete it since compatible with bootcode's framework.
 */
typedef struct  __attribute__ ((__packed__)){
    u16 BB_die;
    u16 bad_block;
    u16 RB_die;
    u16 block_info;
}BBT_normal;

/**
******************************* global variable*********************************
*/

/**
 *mtd subsystem's main struct where the priv member stores nand_chip struct and the priv member of nand_chip
 *stores rtk_priv struct.
 */
struct mtd_info *rtk_mtd;

/*skip BBT scan or not*/
static int skipbbt = 0;

const char *ptypes[] = {"cmdlinepart", NULL};

/**
 * since our system use syndrome architecture, the ecc will spread in 4 places for 2048B (a page).
 * the layout will be : data(512B) + tag(prepad for 6B) + ecc(10B which cannot acess from software) 
 * + data + ... + tag + ecc. 
 * Byte 1~5:	available to user
 * Byte 6~15:	hardware ecc
 * Byte 16~21:	available to user
 * Byte 22~31:	hardware ecc
 * Byte 32~37:	available to user
 * Byte 38~47:	hardware ecc
 * Byte 48~52:	available to user
 * Byte 53:		badblock marker with sync with bootcode (see RTK_OOB_BBI_POS_2K)
 * Byte 54~63:	hardware ecc
 */
static struct nand_ecclayout rtk_oobinfo_2048 = {
	.eccbytes = 40,
	.eccpos = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 
				22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
				38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
				54, 55, 56, 57, 58, 59, 60, 61, 62, 63},
	.oobavail = 23,
	.oobfree = {{0, 6}, {16, 6}, {32, 6}, {48, 5}}
};

/**
 * since our system use syndrome architecture the layout will be : 
 * data(512B) + tag(prepad for 6B) + ecc(10B which cannot acess from software) 
 * Byte 0~4:	available to user
 * Byte 5:	badblock marker
 * Byte 6~15:	hardware ecc
 */
static struct nand_ecclayout rtk_oobinfo_512 = {
	.eccbytes = 10,
	.eccpos = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
	.oobavail = 5,
	.oobfree = {{0, 5}}
};

/**
******************************* BBT function****************************************
*/

/**
 * Read a page from BBT block to buf
 * @mtd: MTD device structure
 * @buf: temporary buffer
 * @offs: offset at which to read
 * 
 * Note : if the return value is EBADMSG or EUCLEAN it means cannot fix all ecc errors.
 */
static int read_bbt_page(struct mtd_info *mtd, uint8_t *buf, loff_t offs)
{
	struct mtd_oob_ops ops;
	int ret = 0;
	
	ops.mode = MTD_OPS_PLACE_OOB;
	ops.ooboffs = 0;
	ops.ooblen = mtd->oobsize;

	ops.datbuf = buf;
	ops.len = mtd->writesize;
	ops.oobbuf = buf + ops.len;

	ret = mtd_read_oob(mtd, offs, &ops);
	
	return ret;
}

/**
 * Write a page including oob area (bbi should set to BBT_TAG) from buf to BBT block
 * @mtd: MTD device structure
 * @buf: temporary buffer
 * @offs: offset at which to write
 * 
 * Note : if the return value is EBADMSG or EUCLEAN it means cannot fix all ecc errors.
 */
static int write_bbt_page(struct mtd_info *mtd, uint8_t *buf, loff_t offs)
{
	struct mtd_oob_ops ops;
	int ret = 0;
	
	ops.len = mtd->writesize;
	ops.mode = MTD_OPS_PLACE_OOB;
	ops.ooboffs = 0;
	ops.ooblen = mtd->oobsize;
	ops.datbuf = buf;
	ops.oobbuf = buf + ops.len;
	
	ret = mtd_write_oob(mtd, offs, &ops);

	return ret;
}

/**
 * Dump BBT of memory (nand_chip->bbt)
 * @mtd:	MTD device structure
 */
static void dump_BBT(struct mtd_info *mtd)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	BBT_normal *bbt_ptr = (BBT_normal *)nand_ptr->bbt;
	int i;
	
	if(nand_ptr->bbt != NULL){
		printk("%s: Nand normal BBT Content\n", __FUNCTION__);
		
		for ( i=0; i<rtk_priv_ptr->bbt_num; i++){
			if ( i==0 && (bbt_ptr[i].BB_die == BB_DIE_INIT) && (bbt_ptr[i].bad_block == BB_INIT) ){
				printk("%s: No bad block in this nand flash\n", __FUNCTION__);
				break;
			}
			if ( bbt_ptr[i].bad_block != BB_INIT ){
				printk("%s: badblock(%x) BBI(%x)\n", __FUNCTION__, bbt_ptr[i].bad_block, bbt_ptr[i].block_info);
			}
		}
	}
	else{
		printk("%s: Error, BBT not exist in memory\n", __FUNCTION__);
	}
}

/**
 * The function will read the block marker
 * @mtd: MTD device structure
 * @ofs: offset from device start
 * return: 0: good block(bbi = 0xff) or BBT block(bbi = BBT_TAG) ; 1: bad block
 * 
 * note: This func differs from nand_block_bad where it will identify BBT block as bad block.
 * The function should be called before the BBT has been ready.
 * The datbuf is NULL which means that it will call nand_do_read_oob where it will ignore ecc 
 * check.
 */
static int rtk_block_isbad(struct mtd_info *mtd, loff_t ofs){
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	struct mtd_oob_ops ops;
	int ret = 0, i = 0;
	uint8_t bad;
	
	//printk("%s: Debug, offset(%llx)\n",__FUNCTION__, ofs);
	
	//If the bbi is stored in the last page, set the offset to the last page.
	if (nand_ptr->bbt_options & NAND_BBT_SCANLASTPAGE){
		ofs += mtd->erasesize - mtd->writesize;
		//printk("%s: Debug, read last page bbt_options(%x) offset(%llx)\n",__FUNCTION__, nand_ptr->bbt_options, ofs);
	}
	
	//set ops struct
	ops.mode = MTD_OPS_PLACE_OOB;
	ops.ooboffs = nand_ptr->badblockpos;
	ops.len = ops.ooblen = 1;
	ops.datbuf = NULL;
	ops.oobbuf = &bad;
	
	do {
		ret = mtd_read_oob(mtd, ofs, &ops);
		if(ret){
			printk("%s: Error, mtd_read_oob error(%d) offset(%llx)\n",__FUNCTION__, ret, ofs);
			ret = 1;
			break;
		}
		
		if((bad != 0xff) && (bad != BBT_TAG)){
			printk("%s: Error, bad block bbi(%x) in offset(%llx)\n",__FUNCTION__, bad, ofs);
			ret = 1;
			break;
		}
		//printk("%s: Debug bad(%x) i(%x) ret(%d)\n",__FUNCTION__, bad, i, ret);
		
		ofs += mtd->writesize;
		i++;
	} while (!ret && i < 2 && (nand_ptr->bbt_options & NAND_BBT_SCAN2NDPAGE));

	return ret;
}

/**
******************** re implement BBT function of nand_bbt.c************************
*/

/**
 * This is a dummy function where defined in nand_bbt.c. Since we don't use Linux
 * BBT framework we cannot include nand_bbt.c (delete nand_bbt.o in Makefile). But
 * the nand_base.c will use this function defined in nand_bbt.c. So we implement 
 * the function with no functionality.
 * @mtd: MTD device structure
 *
 * Note : if we want to use Linux framework we should delete this function.
 */
int nand_default_bbt(struct mtd_info *mtd)
{
	printk("%s: Error, we don't use this function\n",__FUNCTION__);

	return -1;
}
EXPORT_SYMBOL(nand_default_bbt);

/**
 * It will Check if a block is reserved (BBT block)
 * This is a re write function where defined in nand_bbt.c. Since we don't use Linux
 * BBT framework we cannot include nand_bbt.c (delete nand_bbt.o in Makefile). But
 * the nand_base.c will use this function defined in nand_bbt.c. So we implement 
 * the function with RTK's functionality.
 * @mtd: MTD device structure
 * @offs: offset in the device
 */
int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	int block;
	
	block = (int)(offs >> nand_ptr->phys_erase_shift);
	if(block >= (div_u64(mtd->size,mtd->erasesize)-BACKUP_BBT)){
		//bbt block
		return 1;
	}
	else{
		//non bbt block
		return 0;
	}
}

/**
 * It will search the BBT for checking the given offs is good or bad block.
 * This is a re write function where defined in nand_bbt.c. Since we don't use Linux
 * BBT framework we cannot include nand_bbt.c (delete nand_bbt.o in Makefile). But
 * the nand_base.c will use this function defined in nand_bbt.c. So we implement 
 * the function with RTK's functionality.
 * @mtd: MTD device structure
 * @offs: offset in the device
 * @allowbbt: allow access to bad block table region. not use in rtk framework
 * return: 0 if not bad block in BBT; otherwise is bad block in BBT.
 *
 * Note: Since different BBT framework compared to Linux we don't use allowbbt 
 * means that we can always use bbt table region. it may cause problem in Linux 
 * 3.10 where nand_block_checkbad may not permit to use bbt region. 
 */
int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	BBT_normal *bbt_ptr = (BBT_normal *)nand_ptr->bbt;
	unsigned int block,i;
	int ret = 0;
	
	block = (unsigned int)(offs >> nand_ptr->phys_erase_shift);
	//printk("%s: Debug, block is %x offset is %llx nand_ptr->phys_erase_shift(%x)\n",__FUNCTION__,block,offs,nand_ptr->phys_erase_shift);
	for(i = 0;i < rtk_priv_ptr->bbt_num;i++){
		if ( bbt_ptr[i].bad_block != BB_INIT ){
			if ( block == bbt_ptr[i].bad_block ){
				printk("%s: Error, block:%x is bad\n",__FUNCTION__,block);
				ret = 1;
				break;
			}
		}
	}
	
	return ret;
}

/**
 * It will update BBT from memory to flash in RTK's BBT framework.
 * Linux-3.10 : 
 * This is a re write function where defined in nand_bbt.c. Since we don't use Linux
 * BBT framework we cannot include nand_bbt.c (delete nand_bbt.o in Makefile). But
 * the nand_base.c will use this function defined in nand_bbt.c. So we implement 
 * the function with RTK's functionality. (in Linux-3.10)
 * Linux-3.18 : 
 * The new kernel Linux-3.18 uses nand_markbad_bbt not nand_update_bbt in nand_base.c
 * in nand_block_markbad(mtd->_block_markbad) where nand_markbad_bbt needs to update 
 * bbt in flash and memory. So change its name to nand_markbad_bbt and add update bbt
 * in memory functionality.
 * @mtd: MTD device structure
 * @offs: the offset of the newly marked block. not use in rtk framework
 *
 * The function updates the bad block table(s).
 */
int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	BBT_normal *bbt_ptr = (BBT_normal *)nand_ptr->bbt;
	struct erase_info einfo;
	unsigned int block_error_count = 0;
	unsigned int ppb = mtd->erasesize/mtd->writesize;
	unsigned int bbt_page = (div_u64(mtd->size,mtd->erasesize)-BACKUP_BBT)*ppb;
	unsigned int bbt_page_num, bbt_page_index;
	int ret = 0, len, res, offset, page, i, block;
	int copy_len; 
	uint8_t *buf = NULL;
	bbt_page_num = ((sizeof(BBT_normal)*rtk_priv_ptr->bbt_num) + mtd->writesize - 1 ) / mtd->writesize;
	
	/* Get block number */
	block = (int)(offs >> nand_ptr->bbt_erase_shift);
	
	/* Mark block bad in memory-based BBT */
	if (nand_ptr->bbt){
		printk("%s: Debug, before : \n",__FUNCTION__);
		dump_BBT(mtd);
		for(i = 0;i < rtk_priv_ptr->bbt_num;i++){
			if ( bbt_ptr[i].bad_block == BB_INIT){
				bbt_ptr[i].bad_block = block;
				bbt_ptr[i].block_info = 0xba;
				bbt_ptr[i].BB_die = 0;
				bbt_ptr[i].RB_die = 0;
				printk("%s: Debug, bad block(%x): \n",__FUNCTION__, block);
				break;
			}
		}
		printk("%s: Debug, after : \n",__FUNCTION__);
		dump_BBT(mtd);
	}
	i = 0;

	
	/* Allocate a temporary buffer for bbt_page_num * (oobsize + pagesize) where we cannot allocate 
		one eraseblock incl. oob since memory not enough*/
	len = bbt_page_num * (mtd->writesize + mtd->oobsize);
	printk("%s: Debug, temp buf len (%x) bbt_erase_shift(%x)\n", __FUNCTION__, len, nand_ptr->bbt_erase_shift);
	buf = kmalloc( len, GFP_KERNEL );
	if (!buf) {
		printk("%s: Error, no enough memory for buf\n",__FUNCTION__);
		ret = -ENOMEM;
		goto UPDATE_BBT_EXIT;
	}
	memset(buf, 0xff, len);
	
	/*copy BBT to buf where we will use the BBT size in the buf. We need to reset it*/
	len = mtd->writesize + mtd->oobsize;
	copy_len = (sizeof(BBT_normal) * rtk_priv_ptr->bbt_num);
	printk("%s: Debug, copy_len(%x) bbt_page_num(%x)\n",__FUNCTION__, copy_len, bbt_page_num);
	
	for(bbt_page_index = 0;bbt_page_index < bbt_page_num;bbt_page_index++){
		if(copy_len<0){
			printk("%s: Error, BBT size not fit(%x, %d)\n", __FUNCTION__, bbt_page_num, copy_len);
			ret = -1;
			goto UPDATE_BBT_EXIT;
		}
						
		if(copy_len < mtd->writesize){
			memcpy((buf + (bbt_page_index * len)), (nand_ptr->bbt + (bbt_page_index * mtd->writesize)), copy_len);
		}
		else{
			memcpy((buf + (bbt_page_index * len)), (nand_ptr->bbt + (bbt_page_index * mtd->writesize)), mtd->writesize);
		}
		
		if((!NAND_ADDR_CYCLE) && (mtd->writesize == 2048))
			*(buf + (bbt_page_index * len) + mtd->writesize + RTK_OOB_BBI_POS_2K) = BBT_TAG;
		else
			*(buf + (bbt_page_index * len) + mtd->writesize + 5) = BBT_TAG;
			
		copy_len -= mtd->writesize;
	}

    //setup BBT in each BACKUP_BBT block
	for(i=0;i<BACKUP_BBT;i++){
		page = (bbt_page+(i*ppb));
		offset = page * mtd->writesize;
		len = mtd->writesize + mtd->oobsize;
		//We assume bbt already create
		res = mtd_block_isbad(mtd, offset );
		printk("%s: Debug, mtd_block_isbad res %d offset(%x)\n",__FUNCTION__, res, offset);
		if(!res){
			printk("%s: Debug, start to write bbt table:%d page:%d\n\r",__FUNCTION__, i, page);
			
			/* Attempt erase before marking OOB */
			memset(&einfo, 0, sizeof(einfo));
			einfo.mtd = mtd;
			einfo.addr = offset;
			einfo.len = 1 << nand_ptr->phys_erase_shift;
			res = nand_erase_nand(mtd, &einfo, 0);
			if (!res){
				//write the block's page to flash
				for(bbt_page_index = 0;bbt_page_index < bbt_page_num;bbt_page_index++){
					res = write_bbt_page(mtd, (buf + (bbt_page_index * len)), (offset + (bbt_page_index * mtd->writesize)));
					if(res){
						//write BBT error. If it is EBADMSG or EUCLEAN we need to mark this block as bad block
						if (res < 0) {
							if (mtd_is_eccerr(res) || mtd_is_bitflip(res)) {
								printk("%s: Error, write normal bbt table:%d page:%x fail! mark it as bad block\n",__FUNCTION__,i, page);
								//set this block as bad block
								res = mtd_block_markbad(mtd, offset);
								if(!res){
									printk("%s: Error, mtd_block_markbad failed res(%d) offset(%x)\n",__FUNCTION__, res, offset);
								}
							} else {
								printk("%s: Error, write normal bbt table:%d page:%x fail! unknown error : %d\n",__FUNCTION__,i, page, res);
							}
							
							block_error_count++;
							//Since this block is bad block we don't need to write further.
							break;
						}
					}
				}
			}
			else{
				printk("%s Error, erase block %x failure !!\n", __FUNCTION__, offset);
				
				//Since erase failure, mark it as bad block.
				res = mtd_block_markbad(mtd, offset);
				if(!res){
					printk("%s: Error, mtd_block_markbad failed res(%d) offset(%x)\n",__FUNCTION__, res, offset);
				}
				block_error_count++;
			}
		}else{
			printk("%s: Error, unable to write bbt table:%d block:%x page:%x is bad\n",__FUNCTION__, i,(bbt_page/ppb)+i,page);
			block_error_count++;
		}
	}

UPDATE_BBT_EXIT:
	if(block_error_count >= BACKUP_BBT){
		printk("%s: Error, %d normal bbt table are all bad\n", __FUNCTION__, BACKUP_BBT);
		ret = -1;
	}
	
	if(buf){
		kfree(buf);	
	}
	
	return ret;
}

/**
 * create the nand_chip->bbt's memory
 * @mtd:	MTD device structure
 */
static int create_bbt_mem(struct mtd_info *mtd){
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	int len, ret = 0;
	
	len = sizeof(BBT_normal) * rtk_priv_ptr->bbt_num;
	printk("%s: Debug, bbt bytes (%x)\n", __FUNCTION__, len);
	nand_ptr->bbt = kmalloc( len, GFP_KERNEL );
	if ( !nand_ptr->bbt ){
		printk("%s: Error, no enough memory for BBT Normal\n",__FUNCTION__);
		return -ENOMEM;
	}
	memset(nand_ptr->bbt, 0,  len);
	dma_cache_wback((unsigned long) nand_ptr->bbt, len);
	
	return ret;
}

/**
 * It will scan each block quickly which only scans the bbi byte. Then build 
 * BBT in memory. (nand_chip->bbt)
 * @mtd:	MTD device structure
 */
static int scan_normal_BB(struct mtd_info *mtd)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	int table_index=0, i, len, ret = 0;
	int block_size = 1 << nand_ptr->phys_erase_shift;
	BBT_normal *bbt_ptr = NULL;
	uint8_t *tempbuf = NULL;
	u32 addr;
	
	//allocate temporarily bbt buf (see Note A)
	len = sizeof(BBT_normal) * rtk_priv_ptr->bbt_num;
	printk("%s: Debug, bbt bytes (%x)\n", __FUNCTION__, len);
	tempbuf = kmalloc( len, GFP_KERNEL );
	if ( !tempbuf ){
		printk("%s: Error, no enough memory for temp BBT buf\n",__FUNCTION__);
		ret = -ENOMEM;
		goto SCAN_BB_OUT;
	}
	memset(tempbuf, 0,  len);
	dma_cache_wback((unsigned long) tempbuf, len);
	bbt_ptr = (BBT_normal *)tempbuf;
	
	printk("%s: Debug, block_size(%x) nand_ptr->phys_erase_shift(%x) mtd->size(%llx)\n",__FUNCTION__, block_size, nand_ptr->phys_erase_shift, mtd->size);
	for( addr = 0; addr < mtd->size; addr += block_size ){
		//We assume bbt not create yet
		if ( rtk_block_isbad(mtd, addr) ){
			printk("%s: Debug, block %x is bad\n",__FUNCTION__, (addr >> nand_ptr->phys_erase_shift));
			bbt_ptr[table_index].bad_block = addr >> nand_ptr->phys_erase_shift;
			bbt_ptr[table_index].block_info = 0xba;
			bbt_ptr[table_index].BB_die = 0;
			bbt_ptr[table_index].RB_die = 0;
			table_index++;
		}
		else{
			//printk("%s: Debug, block %x is good\n",__FUNCTION__, (addr >> nand_ptr->phys_erase_shift));
		}
		
		if(table_index >= rtk_priv_ptr->bbt_num){
			printk("%s: Error, bad block number %d exceed bbt_num %x\n",__FUNCTION__,table_index,rtk_priv_ptr->bbt_num);
			ret = -1;
			goto SCAN_BB_OUT;
		}		
	}
	for( i = table_index;table_index < rtk_priv_ptr->bbt_num;table_index++){
		bbt_ptr[table_index].bad_block = BB_INIT;
		bbt_ptr[table_index].block_info = 0xff;
		bbt_ptr[table_index].BB_die = BB_DIE_INIT;
		bbt_ptr[table_index].RB_die = BB_DIE_INIT;
	}
	
	
	//Allocate bbt memory (We must allocate it before use it. see Note A)
	ret = create_bbt_mem(mtd);
	if(ret != 0){
		printk("%s: Error, create_bbt_mem\n",__FUNCTION__);
		ret = -1;
		goto SCAN_BB_OUT;
	}
	
	//copy temporarily bbt buf to nand_chip->bbt
	memcpy(nand_ptr->bbt, tempbuf, len);

SCAN_BB_OUT:
	if(tempbuf){
		bbt_ptr = NULL;
		kfree(tempbuf);
	}
	
	return ret;
}

/**
 * It will create BBT in memory(nand_chip->bbt) and flash.
 * @mtd:	MTD device structure
 * @buf:	temporary buf.
 * We will try operations in following order:
 * (1) create BBT in the memory (nand_chip->bbt)
 * (2) write BBT from memory to flash
 */
static int rtk_create_normal_bbt(struct mtd_info *mtd, uint8_t *buf)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	struct erase_info einfo;
	unsigned int block_error_count = 0;
	unsigned int ppb = mtd->erasesize/mtd->writesize;
	unsigned int bbt_page = (div_u64(mtd->size,mtd->erasesize)-BACKUP_BBT)*ppb;
	unsigned int bbt_page_num, bbt_page_index;
	int ret = 0, i, res;
	int offset, page, len;
	int copy_len; 
	
	/*(1) create BBT in the memory (nand_chip->bbt)*/
	if ( scan_normal_BB(mtd) ){
		printk("%s: Error, create BBT in memory error\n", __FUNCTION__);
		return -1;
	}
	
	dump_BBT(mtd);
	
	//copy the BBT from memory to temporary buf.
	bbt_page_num = ((sizeof(BBT_normal)*rtk_priv_ptr->bbt_num) + mtd->writesize - 1 ) / mtd->writesize;
	len = mtd->writesize + mtd->oobsize;
	
	/*We will use the BBT size in the buf. We need to reset it*/
	memset(buf, 0xff, (bbt_page_num * len));
	copy_len = (sizeof(BBT_normal) * rtk_priv_ptr->bbt_num);
	printk("%s: Debug, copy_len(%x) bbt_page_num(%x)\n",__FUNCTION__, copy_len, bbt_page_num);
	
	for(bbt_page_index = 0;bbt_page_index < bbt_page_num;bbt_page_index++){
		if(copy_len<0){
			printk("%s: Error, BBT size not fit(%x, %d)\n", __FUNCTION__, bbt_page_num, copy_len);
			return -1;
		}
		
		if(copy_len < mtd->writesize){
			memcpy((buf + (bbt_page_index * len)), (nand_ptr->bbt + (bbt_page_index * mtd->writesize)), copy_len);
		}
		else{
			memcpy((buf + (bbt_page_index * len)), (nand_ptr->bbt + (bbt_page_index * mtd->writesize)), mtd->writesize);
		}
		
		if((!NAND_ADDR_CYCLE) && (mtd->writesize == 2048))
			*(buf + (bbt_page_index * len) + mtd->writesize + RTK_OOB_BBI_POS_2K) = BBT_TAG;
		else
			*(buf + (bbt_page_index * len) + mtd->writesize + 5) = BBT_TAG;
			
		copy_len -= mtd->writesize;
	}
	
	/* (2) write BBT from memory to flash*/
	
	//setup BBT in each BACKUP_BBT block
	for(i=0;i<BACKUP_BBT;i++){
		page = (bbt_page+(i*ppb));
		offset = page * mtd->writesize;
		len = mtd->writesize + mtd->oobsize;
		//We assume bbt already create
		res = mtd_block_isbad(mtd, offset );
		printk("%s: Debug, mtd_block_isbad res %d offset(%x)\n",__FUNCTION__, res, offset);
		if(!res){
			printk("%s: Debug, start to write bbt table:%d page:%d\n\r",__FUNCTION__, i, page);
			
			/* Attempt erase before marking OOB */
			memset(&einfo, 0, sizeof(einfo));
			einfo.mtd = mtd;
			einfo.addr = offset;
			einfo.len = 1 << nand_ptr->phys_erase_shift;
			res = nand_erase_nand(mtd, &einfo, 0);
			if (!res){
				//write the block's page to flash
				for(bbt_page_index = 0;bbt_page_index < bbt_page_num;bbt_page_index++){
					res = write_bbt_page(mtd, (buf + (bbt_page_index * len)), (offset + (bbt_page_index * mtd->writesize)));
					if(res){
						//write BBT error. If it is EBADMSG or EUCLEAN we need to mark this block as bad block
						if (res < 0) {
							if (mtd_is_eccerr(res) || mtd_is_bitflip(res)) {
								printk("%s: Error, write normal bbt table:%d page:%x fail! mark it as bad block\n",__FUNCTION__,i, page);
								//set this block as bad block
								res = mtd_block_markbad(mtd, offset);
								if(!res){
									printk("%s: Error, mtd_block_markbad failed res(%d) offset(%x)\n",__FUNCTION__, res, offset);
								}
							} else {
								printk("%s: Error, write normal bbt table:%d page:%x fail! unknown error : %d\n",__FUNCTION__,i, page, res);
							}
							
							block_error_count++;
							//Since this block is bad block we don't need to write further.
							break;
						}
					}
				}
			}
			else{
				printk("%s Error, erase block %x failure !!\n", __FUNCTION__, offset);
				
				//Since erase failure, mark it as bad block.
				res = mtd_block_markbad(mtd, offset);
				if(!res){
					printk("%s: Error, mtd_block_markbad failed res(%d) offset(%x)\n",__FUNCTION__, res, offset);
				}
				block_error_count++;
			}
		}else{
			printk("%s: Error, unable to write bbt table:%d block:%x page:%x is bad\n",__FUNCTION__, i,(bbt_page/ppb)+i,page);
			block_error_count++;
		}
	}

	if(block_error_count >= BACKUP_BBT){
		printk("%s: Error, %d normal bbt table are all bad\n", __FUNCTION__, BACKUP_BBT);
		ret = -1;
	}
	
	return ret;		
}

/**
 * check if BBT already in the flash
 * return: 0: BBT not in the flash ; 1: BBT already in the flash
 * @mtd:	MTD device structure
 * @buf:	temporary buf
 *
 * The function will check BACKUP_BBT blocks at NORMAL_BBT_POSITION.
 * If one of the block's first page's bbi is BBT_TAG it means that  
 * BBT already exists in the flash.
 */
static int is_BBT_in_flash(struct mtd_info *mtd, uint8_t *buf){
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	unsigned int ppb = mtd->erasesize/mtd->writesize;
	unsigned int bbt_page = (div_u64(mtd->size,mtd->erasesize)-BACKUP_BBT)*ppb;
	unsigned int block_error_count = 0;
	int ret = 0, res, i, len, offset, page;
	__u8 isbbt;
	
	/*We will use a page in the buf. We need to reset it*/
	len = mtd->writesize + mtd->oobsize;
	memset(buf, 0xff, len);
	
	for(i=0;i<BACKUP_BBT;i++){
		//check if the block is bad block
		page = (bbt_page+(i*ppb));
		offset = page * mtd->writesize;
		len = mtd->writesize + mtd->oobsize;
		//We assume bbt not create yet
		res = rtk_block_isbad(mtd, offset );
		printk("%s: Debug, rtk_block_isbad res %d offset(%x)\n",__FUNCTION__, res, offset);
		if(!res){
			printk("%s: Debug, load normal bbt table:%d page:%x\n",__FUNCTION__, i, page);
			
			//read the block's first page from flash to memory.
			res = read_bbt_page(mtd, buf, offset);
			if(!res){
				//get bbi byte.
				if((!NAND_ADDR_CYCLE) && (mtd->writesize == 2048)){
					isbbt = *(buf + mtd->writesize + RTK_OOB_BBI_POS_2K);
				}
				else{
					isbbt = *(buf + mtd->writesize + 5);
				}
				
				if(isbbt == BBT_TAG){
					//the page stores part of BBT.
					printk("%s: Debug, find bbt table:%d on block(%x) page(%x)\n", __FUNCTION__,i,(page/ppb),page);
					ret = 1;
					goto EXIT;
				}else{
					//This BBT format is wrong.
					printk("%s: Error, bbt table:%d format is wrong\n\r",__FUNCTION__, i);						
					block_error_count++;
				}
			}else{
				//read BBT error. If it is EBADMSG or EUCLEAN we need to mark this block as bad block
				if (res < 0) {
					if (mtd_is_eccerr(res) || mtd_is_bitflip(res)) {
						printk("%s: Error, read normal bbt table:%d page:%x fail! mark it as bad block\n",__FUNCTION__,i, page);
						//set this block as bad block
						res = mtd_block_markbad(mtd, offset);
						if(!res){
							printk("%s: Error, mtd_block_markbad failed res(%d) offset(%x)\n",__FUNCTION__, res, offset);
						}
					} else {
						printk("%s: Error, read normal bbt table:%d page:%d fail! unknown error : %d\n",__FUNCTION__,i, page, res);
					}
					
					block_error_count++;
				}
			}
			
		}else{
			printk("%s: Error,normal bbt table:%d block:%x page:%x is bad\n",__FUNCTION__, i,(bbt_page/ppb)+i,bbt_page+(i*ppb));
			block_error_count++;
		}
	}

EXIT:	
	if(block_error_count >= BACKUP_BBT){
		printk("%s: Error, %d normal bbt table are all bad\n", __FUNCTION__, BACKUP_BBT);
		ret = 0;
	}

	return ret;
}

/**
 * The function tries to create BBT in memory which is nand_chip->bbt. It will also
 * create BBT in the flash if there is no BBT in flash. The position in flash is at
 * NORMAL_BBT_POSITION block and backup forward BACKUP_BBT blocks.
 * @mtd:	MTD device structure
 * 
 * We try operations in following order : 
 * (1) check if the BBT already be stored in flash. If BBT already exists in flash
 *		read BBT from flash to memory (nand_chip->bbt), then end the flow. Else go
 *		to step (2)
 * (2) create BBT in the memory (nand_chip->bbt)
 * (3) write BBT from memory to flash
 *
 * Note: if we receive EBADMSG or EUCLEAN we need to identify this block as bad block.
 */
static int rtk_scan_bbt(struct mtd_info *mtd)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	unsigned int ppb = mtd->erasesize/mtd->writesize;
	unsigned int bbt_page = (div_u64(mtd->size,mtd->erasesize)-BACKUP_BBT)*ppb;
	unsigned int block_error_count = 0;
	unsigned int bbt_page_num, bbt_page_index, bbt_page_count;
	int bbt_in_flash = 0;
	int ret = 0, res, i;
	int offset, page, len;
	uint8_t *buf;
	__u8 isbbt;
	
	printk("%s: Debug, ppb(%x) mtd(%s) mtd->erasesize(%x) mtd->writesize(%x) size(%llx) BACKUP_BBT(%x) bbt_page(%x)\n",__FUNCTION__, 
		ppb, mtd->name, mtd->erasesize, mtd->writesize, mtd->size, BACKUP_BBT, bbt_page);
	
	//initialize variables
	rtk_priv_ptr->bbt_num = ((u32)mtd->size >> nand_ptr->phys_erase_shift) * BBT_PERCENT/100;
	printk("%s: Debug, bbt_num=%x, BBT_PERCENT = %d\n", __FUNCTION__, 
		rtk_priv_ptr->bbt_num, BBT_PERCENT);
	printk("%s: Debug, mtd->size(%llx) nand_ptr->phys_erase_shift(%x)\n", __FUNCTION__, 
		mtd->size, nand_ptr->phys_erase_shift);
	bbt_page_num = ((sizeof(BBT_normal)*rtk_priv_ptr->bbt_num) + mtd->writesize - 1 ) / mtd->writesize;
	
	/*Note A: initialize bbt struct. nand_ptr->bbt should be NULL until start copy the BBT data to it.Since mtd_block_isbad 
	will use it to decide checking from bbt or flash. If we create bbt before mtd_block_isbad without setting it 
	correctly mtd_block_isbad will read data from bbt which is wrong data.*/
	nand_ptr->bbt = NULL;
	
	/*Allocate a temporary buffer for bbt_page_num * (mtd->writesize + mtd->oobsize) which 
	used to store BBT block where we cannot allocate one eraseblock incl. oob since memory
	not enough*/
	len = bbt_page_num * (mtd->writesize + mtd->oobsize);
	printk("%s: Debug, temp buf len (%x)\n", __FUNCTION__, len);
	buf = vmalloc(len);
	if (!buf) {
		printk("%s: Error, no enough memory for buf\n",__FUNCTION__);
		ret = -ENOMEM;
		goto EXIT;
	}
	memset(buf, 0xff, len);
	
	/**
	 * (1) check if the BBT already be stored in flash. If BBT already exists in flash
	 *		read BBT from flash to memory (nand_chip->bbt), then end the flow. Else go
	 *		to step (2)
	 */
	bbt_in_flash = is_BBT_in_flash(mtd, buf);
	printk("%s: Debug, bbt_in_flash %d \n",__FUNCTION__, bbt_in_flash);
	
	if(bbt_in_flash){
		/**
		 * read BBT from flash to memory (nand_chip->bbt)
		 */
		
		/*We will use the buf. We need to reset it*/
		len = bbt_page_num * (mtd->writesize + mtd->oobsize);
		memset(buf, 0xff, len);
		
		for(i=0;i<BACKUP_BBT;i++){
			//check if the block is bad block
			page = (bbt_page+(i*ppb));
			offset = page * mtd->writesize;
			len = mtd->writesize + mtd->oobsize;
			//We assume bbt not create yet
			res = rtk_block_isbad(mtd, offset );
			printk("%s: Debug, rtk_block_isbad res %d offset(%x)\n",__FUNCTION__, res, offset);
			if(!res){
				printk("%s: Debug, load normal bbt table:%d page:%x\n",__FUNCTION__, i, page);
				
				//read the block's data from flash to memory.
				bbt_page_count = 0;
				for(bbt_page_index = 0;bbt_page_index < bbt_page_num;bbt_page_index++){
					res = read_bbt_page(mtd, (buf + (bbt_page_index * len)), (offset + (bbt_page_index * mtd->writesize)));
					if(!res){
						//get bbi byte.
						if((!NAND_ADDR_CYCLE) && (mtd->writesize == 2048))
							isbbt = *(buf + (bbt_page_index * len) + mtd->writesize + RTK_OOB_BBI_POS_2K);
						else
							isbbt = *(buf + (bbt_page_index * len) + mtd->writesize + 5);
						
						if(isbbt == BBT_TAG){
							//the page stores part of BBT.
							printk("%s: Debug, find bbt table:%d on block(%x) page(%x)\n", __FUNCTION__,i,(page/ppb),(page+bbt_page_index));
							bbt_page_count++;
						}else{
							//This BBT format is wrong.
							printk("%s: Error, bbt table:%d format is wrong\n",__FUNCTION__, i);						
							block_error_count++;
							//Since this BBT format is wrong we don't need to read further.
							break;
						}
					}else{
						//read BBT error. If it is EBADMSG or EUCLEAN we need to mark this block as bad block
						if (res < 0) {
							if (mtd_is_eccerr(res) || mtd_is_bitflip(res)) {
								printk("%s: Error, read normal bbt table:%d page:%x fail! mark it as bad block\n",__FUNCTION__,i, page);
								//set this block as bad block
								res = mtd_block_markbad(mtd, offset);
								if(!res){
									printk("%s: Error, mtd_block_markbad failed res(%d) offset(%x)\n",__FUNCTION__, res, offset);
								}
							} else {
								printk("%s: Error, read normal bbt table:%d page:%x fail! unknown error : %d\n",__FUNCTION__,i, page, res);
							}
							
							block_error_count++;
							//Since this block is bad block we don't need to read further.
							break;
						}
					}
				}
				
				if(bbt_page_count == bbt_page_num){
					//Allocate bbt memory (We must allocate it before use it. see Note A)
					res = create_bbt_mem(mtd);
					if(res != 0){
						printk("%s: Error, create_bbt_mem\n",__FUNCTION__);
						ret = res;
						goto EXIT;
					}
					
					//copy the BBT from temporary buf to nand_chip->bbt where we shuold skip oob area.
					int copy_len = (sizeof(BBT_normal) * rtk_priv_ptr->bbt_num); 
					printk("%s: Debug, check normal bbt table:%d OK\n",__FUNCTION__, i);
					for(bbt_page_index = 0;bbt_page_index < bbt_page_num;bbt_page_index++){
						if(copy_len<0){
							printk("%s: Error, BBT size not fit(%x, %d)\n", __FUNCTION__, bbt_page_num, copy_len);
							ret = -1;
							goto EXIT;
						}
					
						if(copy_len < mtd->writesize){
							memcpy( nand_ptr->bbt, (buf + (bbt_page_index * len)), copy_len);
						}
						else{
							memcpy( nand_ptr->bbt, (buf + (bbt_page_index * len)), mtd->writesize);
						}
						copy_len -= mtd->writesize;
					}
					
					ret = 0;
					goto EXIT;
				}
				else{
					printk("%s: Debug, some error occurs. bbt pages should be %x but is %x\n",__FUNCTION__, bbt_page_num, bbt_page_count);
				}
				
			}else{
				printk("%s: Error,normal bbt table:%d block:%x page:%x is bad\n",__FUNCTION__, i,(bbt_page/ppb)+i,bbt_page+(i*ppb));
				block_error_count++;
			}
		}
		
		if(block_error_count >= BACKUP_BBT){
			printk("%s: Error, %d normal bbt table are all bad\n", __FUNCTION__, BACKUP_BBT);
			ret = -1;
			goto EXIT;
		}
	}
	else{
		/**
		 * (2) create BBT in the memory (nand_chip->bbt)
		 * (3) write BBT from memory to flash
		 */
		res = rtk_create_normal_bbt(mtd, buf);
		if(res < 0){
			ret = -1;
			goto EXIT;
		}
		else{
			ret = 0;
			goto EXIT;
		}
	
	}	
	
EXIT:	
	//dmup BBT 
	dump_BBT(mtd);

	if(buf){
		vfree(buf);
	}
	
	if(ret < 0){
		printk("%s: Error, BBT built failed\n",__FUNCTION__);
		if (!nand_ptr->bbt){
			kfree(nand_ptr->bbt);
			nand_ptr->bbt = NULL;
		}
	}
	
	return ret;
}

/**
******************************* mtd & nand_chip function****************************************
*/

/**
 * display nand flash driver's version
 */
static void display_version (void)
{
	printk(" Rev:1.0 2015.09.11\n");
}

/**
 * Used for controlling ALE/CLE/nCE. Also used to write command and address.
 *
 * we don't use this function to read/write operations, since we use dma to acess flash
 * the NAND_CMD_STATUS/ NAND_CMD_READID/ NAND_CMD_RESET/ NAND_CMD_ERASE1/NAND_CMD_ERASE2 
 * cmds will send cmd in rtk_nand_cmdfunc.
 */
static void rtk_cmd_ctrl(struct mtd_info *mtd, int cmd,
				   unsigned int ctrl)
{
	printk("%s: Error, We don't support this function.\n",__FUNCTION__);
}
/**
 * check nand controller ready/busy
 */
static void check_ready(struct mtd_info *mtd){
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	while(1) {
		if( (!!(rtk_readl(NACR) & 0x80000000)) ) 
			break;
	}
	return;
}

/**
 * reset ecc counter register including NECN, NRER, NWER, NDRS, NDWS
 */
static void rtk_reset_ecc(void){
	int status;
	
	status = rtk_readl(NASR);
	status &= 0x0f; //clear NECN, NRER, NWER, NDRS, NDWS
	rtk_writel(status, NASR);
}

/**
 * Check the ecc counter.
 * return: return 0: no ecc error; 1~4: ecc can fix it, return fix numbers;
 *		else return -1 (We don't return EBADMSG, since upper level will help
 *		us to return EBADMSG such as nand_do_read_ops function.)
 * 
 * Note that we should check ALL_ONE where the huge ecc errors occurs after
 * erasing the block.
 */
static int rtk_check_ecc(void)
{
	int error_count,result = 0;
	unsigned long status;
	
	status = rtk_readl(NASR);
	
	/*read status*/
	if( (status & NDRS)== NDRS){	
		/*ecc result = 1 , ecc read fail.*/
		if( status & NRER) {
			if(status & ALL_ONE){	//allone error : read after erase (double check where the all one error won't raise NRER in new controller.)
				printk("%s: Debug, ecc allone error ignore\n",__FUNCTION__);
				result = 0;
			}
			else{
				error_count = (status & 0xf0) >> 4;
				if(error_count <=4 && error_count > 0 ) {
					//printk("%s: Debug, ecc error status(%lx) counter(%x)\n", __FUNCTION__, status, error_count);
					result = error_count;
				}else{
					//counter == 0 (too many error to fixed) or > 4
					//printk("%s: Error, ecc cannot fix status(%lx) counter(%x)\n", __FUNCTION__, status, error_count);
					result = -1;		
				}
			}
		}
	}
	else if( (status & NDWS)== NDWS){	//write status
		/*ecc result = 1 , ecc write fail.*/
		if( status & NWER) {
			    //printk("%s: Error, ecc write failed status(%x) counter(%x)\n", __FUNCTION__, status, error_count);
			    result = -1;			
		}
	}
	else{
		printk("%s: Error, nand_check_eccStatus ERROR\n",__FUNCTION__);
	}

	return result;
}
/**
 * Send NAND_CMD_STATUS to controller and copy the result to dmabuf
 * @mtd:	MTD device structure
 */
void rtk_read_id (struct mtd_info *mtd)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	uint8_t *data_buf = rtk_priv_ptr->dmabuf;
	int i;
	unsigned long id_chain;

	check_ready(mtd);
	rtk_writel( (rtk_readl(NACR) |ECC_enable|RBO|WBO), NACR);

	rtk_writel( (rtk_priv_ptr->select_chip_record | NAND_CMD_READID), NACMR);          //read ID command
	check_ready(mtd);
	
	rtk_writel( (0x0 |AD2EN|AD1EN|AD0EN) , NAADR);  //dummy address cycle
	check_ready(mtd);
	
	id_chain = rtk_readl(NADR);
	for(i=0 ; i<4 ; i++){
		uint8_t temp = ((id_chain >> (i*8)) & 0xff);
		memcpy((data_buf + i), &temp , 1);
	}

	id_chain = rtk_readl(NADR);
	for(i=4 ; i<8 ; i++){
		uint8_t temp = ((id_chain >> (i*8)) & 0xff);
		memcpy((data_buf + i), &temp , 1);
	}

	rtk_writel( 0x0, NAADR);
}

/**
 * Send NAND_CMD_RESET to controller
 * @mtd:	MTD device structure
 */
int rtk_reset (struct mtd_info *mtd)	
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	
	check_ready(mtd);

	rtk_writel( (rtk_readl(NACR) |ECC_enable), NACR);
	rtk_writel((NWER|NRER|NDRS|NDWS), NASR);

	rtk_writel((rtk_priv_ptr->select_chip_record|NAND_CMD_RESET),NACMR);
	check_ready(mtd);
	
	return 0;
}

/**
 * Send NAND_CMD_STATUS to controller
 * @mtd:	MTD device structure
 *
 * Note MX30LF1G08AA says that The status read command 70h will keep the device 
 * at the status read mode unless next valid command is issued. it means that we
 * only need to send a cmd once but read it many times.
 */
unsigned long rtk_status (struct mtd_info *mtd)	
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	
	check_ready(mtd);

	rtk_writel( (rtk_readl(NACR) |ECC_enable), NACR);
	rtk_writel((NWER|NRER|NDRS|NDWS), NASR);

	rtk_writel((rtk_priv_ptr->select_chip_record|NAND_CMD_STATUS),NACMR);
	check_ready(mtd);
	
	return rtk_readl(NADR);
}

/**
 * Send NAND_CMD_ERASE1 and addr to flash controller.
 * @mtd:	MTD device structure
 * @page: the page address for this command
 */
int rtk_erase_block_top_half (struct mtd_info *mtd, int page)	
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	int addr_cycle[5], page_shift;
	
	/*simple check*/
	if(page < 0){
		printk("%s: Warn, the page para.(%d) is invalid\n",__FUNCTION__,page);
		return -1;
	}
	
	if ( NOTALIGNED_BLOCK(mtd, (page * mtd->writesize)) ){
		printk("%s: page %d is not block alignment mtd(%s) writesize(%x) !!\n", __FUNCTION__, page, mtd->name, mtd->writesize);
		return -1;
	}

	check_ready(mtd);

	rtk_writel( (rtk_readl(NACR) |ECC_enable), NACR);
	rtk_writel((NWER|NRER|NDRS|NDWS), NASR);

	rtk_writel((rtk_priv_ptr->select_chip_record|NAND_CMD_ERASE1),NACMR);
	check_ready(mtd);

	addr_cycle[0] = addr_cycle[1] =0;
	for(page_shift=0; page_shift<3; page_shift++){
		addr_cycle[page_shift+2] = (page>>(8*page_shift)) & 0xff;
	}

	rtk_writel( ((~enNextAD) & AD2EN|AD1EN|AD0EN|
			(addr_cycle[2]<<CE_ADDR0) |(addr_cycle[3]<<CE_ADDR1)|(addr_cycle[4]<<CE_ADDR2)),NAADR);
	check_ready(mtd);

	return 0;
}

/**
 * Send NAND_CMD_ERASE2 to flash controller.
 * @mtd:	MTD device structure
 */
int rtk_erase_block_bottom_half (struct mtd_info *mtd)	
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	
	rtk_writel((rtk_priv_ptr->select_chip_record|NAND_CMD_ERASE2),NACMR);
	check_ready(mtd);
	
	return 0;
}

/**
 * preparing for rtk_write_page_bottom_half.
 * @mtd:	MTD device structure
 * @page_addr: the page address for this command
 */
void rtk_write_page_top_half (struct mtd_info *mtd, int page)	
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	
	memset(rtk_priv_ptr->dmabuf, 0xff, (mtd->writesize + mtd->oobsize));
	rtk_priv_ptr->write_page = page;
}

/**
 * write a page from dma buffer(dmabuf) to flash page where the hardware will check ecc
 * automatically
 * @mtd:	MTD device structure
 *
 * Have to call rtk_write_page_top_half before calling rtk_write_page_bottom_half.
 */
int rtk_write_page_bottom_half (struct mtd_info *mtd)	
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	int page = rtk_priv_ptr->write_page;
	int page_num[3], page_shift=0;
	int dma_counter = mtd->writesize >> 9;	//Move unit=512Byte
	int buf_pos = 0;
	int page_unit = mtd->writesize/nand_ptr->ecc.steps;
	int oob_unit = mtd->oobsize/nand_ptr->ecc.steps;
	int ecc_counter = 0;
	uint8_t *oob = rtk_priv_ptr->dmabuf + page_unit;
	uint8_t *data_buf = rtk_priv_ptr->dmabuf;
	unsigned char switch_bbi=0;
	unsigned int ppb = mtd->erasesize/mtd->writesize;
	unsigned int write_bbi=0;
	unsigned int dram_sa, oob_sa;
	unsigned long flash_addr_t=0;
	
	//printk("%s: Debug, dma_counter(%x) mtd->writesize(%x) mtd->oobsize(%x) nand_ptr->ecc.steps(%x) page_unit(%x) oob_unit(%x)\n", __FUNCTION__, 
	//	dma_counter, mtd->writesize, mtd->oobsize, nand_ptr->ecc.steps, page_unit, oob_unit);
	
	/*simple check*/
	if(page < 0){
		printk("%s: Warn, the page para.(%d) is invalid\n",__FUNCTION__,page);
		return -1;
	}
	
	/*switch bbi and data byte*/
	if(nand_ptr->bbt_options & NAND_BBT_SCANLASTPAGE){
		/*bad block indicator is located in page (ppb-2) and page (ppb-1)*/
		write_bbi = page & (ppb-1);
		if((write_bbi == (ppb-2)) || (write_bbi ==(ppb-1))){
			switch_bbi = 1;
		}
	}else{
		/*bad block indicator is located in page 0 and page 1*/
		write_bbi = page & (ppb-1);
		if((write_bbi == 0) || (write_bbi ==1)){
			switch_bbi = 1;
		}
	}
	if((!NAND_ADDR_CYCLE) && (mtd->writesize == 2048)){
		unsigned char temp_val;
		if(switch_bbi && (page > ppb-1)){
			temp_val = rtk_priv_ptr->dmabuf[RTK_BBI_DMABUF_POS_2K];
			rtk_priv_ptr->dmabuf[RTK_BBI_DMABUF_POS_2K] = rtk_priv_ptr->dmabuf[RTK_BBI_SWITCHTO_POS_2K];
			rtk_priv_ptr->dmabuf[RTK_BBI_SWITCHTO_POS_2K] = temp_val;
		}
	}

	/*reset ecc counter before dma (make sure ecc value is not accumulated by last dma acess)*/
	rtk_reset_ecc();
	
	/*reset max_ecc_counter*/
	rtk_priv_ptr->max_ecc_counter = 0;
	
	dma_cache_wback_inv((unsigned long) rtk_priv_ptr->dmabuf ,(mtd->oobsize + mtd->writesize)); 
	
	//---------------------DMA write the 1st 528 bytes unit------------------// 
	oob_sa = ( (uint32_t)oob & (~M_mask));

	check_ready(mtd);
	wmb();
	rtk_writel( ( (rtk_readl(NACR)|ECC_enable) & (~RBO) & (~WBO)) , NACR);

	//set DMA RAM data start address
	dram_sa = ( (uint32_t)data_buf & (~M_mask));
	rtk_writel( dram_sa, NADRSAR);

	//set DMA RAM oob start address
	rtk_writel( oob_sa, NADTSAR);

	//set DMA flash start address
	for(page_shift=0;page_shift<3; page_shift++) {
		page_num[page_shift] = ((page>>(8*page_shift)) & 0xff);
		if(!NAND_ADDR_CYCLE){
			flash_addr_t |= (page_num[page_shift] << (12+8*page_shift));
		}else{
			flash_addr_t |= (page_num[page_shift] << (9+8*page_shift));
		}	
	}
	rtk_writel( flash_addr_t, NADFSAR);
	
	//DMA write
	wmb();
	rtk_writel( (DESC0|DMAWE|LBC_128 & (~TAG_DIS)),NADCRR);
	
	check_ready(mtd);
	//printk("%s: Debug, dram_sa = 0x%08X , oob_sa = 0x%08X \n", __FUNCTION__, dram_sa, oob_sa);
	
	/*check ecc counter for updating BBT*/
	
	/*update max_ecc_counter for correct function*/
	ecc_counter = rtk_check_ecc();
	if((ecc_counter < 0) || (rtk_priv_ptr->max_ecc_counter < 0)){
		rtk_priv_ptr->max_ecc_counter = -1;
	}
	else{
		rtk_priv_ptr->max_ecc_counter = max_t( int, ecc_counter, rtk_priv_ptr->max_ecc_counter);
	}
	
	/*reset ecc counter after first dma acess*/
	rtk_reset_ecc();
	dma_counter--;
	buf_pos++;
	
	//--------------------DMA the other 3*528 bytes-----------------//
	while(dma_counter>0){
		
		oob_sa =  ( (uint32_t)(oob + (buf_pos*(oob_unit + page_unit))) & (~M_mask));

		check_ready(mtd);
		wmb();
		rtk_writel( ( (rtk_readl(NACR)|ECC_enable) & (~RBO) & (~WBO)) , NACR);
		
		//set DMA RAM start address, add 512 bytes		
		dram_sa = ( (uint32_t)(data_buf + (buf_pos*(oob_unit + page_unit))) & (~M_mask));
		rtk_writel(dram_sa, NADRSAR);

		//set DMA RAM oob address
		rtk_writel( oob_sa, NADTSAR);

		//set DMA flash start address,add (512+6+10)bytes
		flash_addr_t += 528;
		rtk_writel( flash_addr_t, NADFSAR);
		
		//DMA write
		wmb();
		rtk_writel( (DESC0|DMAWE|LBC_128 & (~TAG_DIS)),NADCRR);

		check_ready(mtd);
		//printk("%s: Debug, dram_sa = 0x%08X oob_sa = 0x%08X\n", __FUNCTION__, dram_sa, oob_sa);
		
		/*check ecc counter for updating BBT*/
		
		/*update max_ecc_counter for correct function*/
		ecc_counter = rtk_check_ecc();
		if((ecc_counter < 0) || (rtk_priv_ptr->max_ecc_counter < 0)){
			rtk_priv_ptr->max_ecc_counter = -1;
		}
		else{
			rtk_priv_ptr->max_ecc_counter = max_t( int, ecc_counter, rtk_priv_ptr->max_ecc_counter);
		}
		
		/*reset ecc counter after dma acess*/
		rtk_reset_ecc();
		dma_counter--;
		buf_pos++;

	}
	
	return 0;
}

/**
 * Read a page from page position to dma buffer(dmabuf) where the hardware will check ecc
 * automatically
 * @mtd:	MTD device structure
 * @page:	the page address for this command
 */
static int rtk_read_page_lowlevel (struct mtd_info *mtd, int page)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	int dram_sa, oob_sa;
	int dma_counter = mtd->writesize >> 9;	//Move unit=512Byte
	int buf_pos = 0;
	int page_num[3], page_shift=0;
	int page_unit = mtd->writesize/nand_ptr->ecc.steps;
	int oob_unit = mtd->oobsize/nand_ptr->ecc.steps;
	int ecc_counter = 0;
	uint8_t *oob = rtk_priv_ptr->dmabuf + page_unit;
	uint8_t *data_buf = rtk_priv_ptr->dmabuf;
	unsigned long flash_addr_t=0;
	unsigned char switch_bbi=0;
	unsigned int ppb = mtd->erasesize/mtd->writesize;
	unsigned int read_bbi=0;
	
	//printk("%s: Debug, dma_counter(%x) mtd->writesize(%x) mtd->oobsize(%x) nand_ptr->ecc.steps(%x) page_unit(%x) oob_unit(%x)\n", __FUNCTION__, 
	//	dma_counter, mtd->writesize, mtd->oobsize, nand_ptr->ecc.steps, page_unit, oob_unit);
	
	/*simple check*/
	if(page < 0){
		printk("%s: Warn, the page para.(%d) is invalid\n",__FUNCTION__,page);
		return -1;
	}
	
	/*reset ecc counter before dma (make sure ecc value is not accumulated by last dma acess)*/
	rtk_reset_ecc();
	
	/*reset max_ecc_counter*/
	rtk_priv_ptr->max_ecc_counter = 0;
	
	memset(rtk_priv_ptr->dmabuf, 0xff, (mtd->oobsize + mtd->writesize));
	dma_cache_wback_inv((unsigned long) rtk_priv_ptr->dmabuf ,(mtd->oobsize + mtd->writesize));   
	oob_sa = ((uint32_t)oob) & (~M_mask);
	

	//---------------------DMA the 1st page ----------------------// 
	check_ready(mtd);
	wmb();
	
	rtk_writel( ( (rtk_readl(NACR) |ECC_enable) & (~RBO) & (~WBO)), NACR);
	
	//set DMA RAM data start address
	dram_sa = ((uint32_t)data_buf) & (~M_mask);
	rtk_writel( dram_sa, NADRSAR);
	
	//set DMA RAM oob start address
	rtk_writel( oob_sa, NADTSAR);

	//set DMA flash start address
	for(page_shift=0;page_shift<3; page_shift++) {
		page_num[page_shift] = ((page>>(8*page_shift)) & 0xff);

		if(!NAND_ADDR_CYCLE){
			flash_addr_t |= (page_num[page_shift] << (12+8*page_shift));
		}else{
			flash_addr_t |= (page_num[page_shift] << (9+8*page_shift));
		}
	}
	//printk("%s: Debug, flash_addr_t = 0x%08X, page = %d\n",__FUNCTION__, flash_addr_t, page);
	rtk_writel( flash_addr_t, NADFSAR);
	
	//DMA read
	wmb();
	rtk_writel( ((~TAG_DIS)&(DESC0|DMARE|LBC_128)),NADCRR);	
	
	check_ready(mtd);
	//printk("%s: Debug, dram_sa = 0x%08X  oob_sa = 0x%08X\n", __FUNCTION__, dram_sa, oob_sa);
	
	/*check ecc counter for updating BBT*/
	
	/*update max_ecc_counter for correct function*/
	ecc_counter = rtk_check_ecc();
	if((ecc_counter < 0) || (rtk_priv_ptr->max_ecc_counter < 0)){
		rtk_priv_ptr->max_ecc_counter = -1;
	}
	else{
		rtk_priv_ptr->max_ecc_counter = max_t( int, ecc_counter, rtk_priv_ptr->max_ecc_counter);
	}
	
	/*reset ecc counter after first dma acess*/
	rtk_reset_ecc();
	dma_counter--;
	buf_pos++;
	
	/*========================Move 512Bytes once==========================*/
	while(dma_counter>0){

		oob_sa = ((uint32_t)oob + (buf_pos*(oob_unit + page_unit))) & (~M_mask);
		
		check_ready(mtd);
		wmb();
		
		rtk_writel( ( (rtk_readl(NACR) |ECC_enable) & (~RBO) & (~WBO)), NACR);
		
		//set DMA RAM start address, add 512 bytes	
		dram_sa = ( (uint32_t)(data_buf + (buf_pos*(oob_unit + page_unit))) & (~M_mask));
		rtk_writel(dram_sa, NADRSAR);

		//set DMA RAM oob start address
		rtk_writel( oob_sa, NADTSAR);
		
		//set DMA flash start address,add (512+6+10)bytes
		flash_addr_t += 528;
		rtk_writel( flash_addr_t, NADFSAR);
		
		//DMA read
		wmb();
		rtk_writel( ((~TAG_DIS)&(DESC0|DMARE|LBC_128)),NADCRR);
		
		check_ready(mtd);
		//printk("%s: Debug, dram_sa = 0x%08X oob_sa = 0x%08X\n", __FUNCTION__, dram_sa, oob_sa);
		
		/*check ecc counter for updating BBT*/
		
		/*update max_ecc_counter for correct function*/
		ecc_counter = rtk_check_ecc();
		if((ecc_counter < 0) || (rtk_priv_ptr->max_ecc_counter < 0)){
			rtk_priv_ptr->max_ecc_counter = -1;
		}
		else{
			rtk_priv_ptr->max_ecc_counter = max_t( int, ecc_counter, rtk_priv_ptr->max_ecc_counter);
		}
		
		/*reset ecc counter after dma acess*/
		rtk_reset_ecc();
		dma_counter--;
		buf_pos++;		
	}

	//printk("%s: Debug, bbt_options(%x)\n",__FUNCTION__, nand_ptr->bbt_options);
	
	/*switch bbi and data byte*/
	if(nand_ptr->bbt_options & NAND_BBT_SCANLASTPAGE){
		read_bbi = page & (ppb-1);
		if((read_bbi == (ppb-2)) || (read_bbi == (ppb-1))){
			switch_bbi = 1;
		}
	}else{
		read_bbi = page & (ppb-1);
		if((read_bbi == 0) || (read_bbi ==1)){
			switch_bbi = 1;
		}
	}	
	if((!NAND_ADDR_CYCLE) && (mtd->writesize == 2048)){
		/*switch bad block info*/
		unsigned char temp_val=0;
		if(switch_bbi && (page > ppb-1)){
			temp_val = rtk_priv_ptr->dmabuf[RTK_BBI_DMABUF_POS_2K];
			rtk_priv_ptr->dmabuf[RTK_BBI_DMABUF_POS_2K] = rtk_priv_ptr->dmabuf[RTK_BBI_SWITCHTO_POS_2K];
			rtk_priv_ptr->dmabuf[RTK_BBI_SWITCHTO_POS_2K] = temp_val;
		}
	}
	dma_cache_wback_inv((unsigned long) rtk_priv_ptr->dmabuf ,(mtd->oobsize + mtd->writesize));
	
	return 0;
}

/**
 * rtk_nand_cmdfunc - Send command to NAND large page device
 * @mtd: MTD device structure
 * @command: the command to be sent
 * @column: the column address for this command, -1 if none
 * @page_addr: the page address for this command, -1 if none
 *
 */
static void rtk_nand_cmdfunc(struct mtd_info *mtd, unsigned int command,
			    int column, int page_addr)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	
	//printk("%s: Debug, flash cmd: %x\n",__FUNCTION__, command);
	//dump_stack();
	
	/*reset reader/writer's pointer to 0 of dmabuf*/
	rtk_priv_ptr->data_pos = 0;
	
	/*record the flash cmd.*/
	rtk_priv_ptr->command_record = command;
	
	if (command == NAND_CMD_READ0) {
		/* read a page from dma to buffer*/
		
		if(column != -1){
			rtk_priv_ptr->data_pos += column;
		}
		
		/*read a page from flash to dmabuf*/
		rtk_read_page_lowlevel(mtd, page_addr);
	}
	else if (command == NAND_CMD_READOOB) {
		int part_oob_size = 0, part_index;
	
		/*read a page to dma buffer. then move reader's pointer to specific 
		 DMA buffer's position*/
		command = NAND_CMD_READ0;
		
		/*read a page from flash to dmabuf*/
		rtk_read_page_lowlevel(mtd, page_addr);
		
		/*calculate column's absolute position*/
		part_oob_size = nand_ptr->ecc.bytes + nand_ptr->ecc.prepad + nand_ptr->ecc.postpad;
		//column only 0~63 in 2k page where the part_index could be 0~3.
		part_index = column/part_oob_size;
		
		/*adjust pointer to colume*/
		rtk_priv_ptr->data_pos = (nand_ptr->ecc.size * (part_index + 1)) + column;
	}
	else if (command == NAND_CMD_READ1) {
		/* doesn't support*/
		printk("%s: Error, We don't support NAND_CMD_READ1 cmd.\n",__FUNCTION__);
	}
	else if (command == NAND_CMD_RNDOUT) {
		/*DMA will transfer one page where we don't need this cmd.
		 we just need to move reader's pointer to specific DMA buffer's position*/
		if (page_addr != -1){
			printk("%s: Error, NAND_CMD_RNDOUT cmd. para error page_addr (%x)\n",__FUNCTION__, page_addr);
			return;
		}
		rtk_priv_ptr->data_pos += column;
		
	}
	else if (command == NAND_CMD_PAGEPROG) {
		/* start dma writing (bottom half)*/
		
		if((column != -1) || (page_addr != -1)){
			printk("%s: Error, NAND_CMD_PAGEPROG cmd. para error page_addr(%x) column(%x)\n",__FUNCTION__, page_addr, column);
			return;
		}
		
		rtk_write_page_bottom_half(mtd);
	}
	else if (command == NAND_CMD_ERASE1) {
		/* send erase1 cmd to flash (top half erase)*/
		
		/*erase address alignment check*/
		if ( NOTALIGNED_BLOCK(mtd, (page_addr * mtd->writesize)) || (column != -1) ){
			printk("%s: Error, NAND_CMD_ERASE1 is a block unit cmd. page_addr(%x) column(%x) mtd(%s) writesize(%x) \n",__FUNCTION__, page_addr, column, mtd->name, mtd->writesize);
			return;
		}
		
		rtk_erase_block_top_half(mtd, page_addr);
	}
	else if (command == NAND_CMD_STATUS) {
		/* send read status cmd to flash*/
		
		if ( (page_addr != -1) || (column != -1) ){
			printk("%s: Error, NAND_CMD_STATUS invalid para. page_addr(%x) column(%x)\n",__FUNCTION__, page_addr, column);
			return;
		}
		
		rtk_status(mtd);
	}
	else if (command == NAND_CMD_SEQIN) {
		/*dma write top half*/
		
		rtk_write_page_top_half(mtd, page_addr);
		
		if(column != -1){
			rtk_priv_ptr->data_pos += column;
		}
	}
	else if (command == NAND_CMD_RNDIN) {
		/*DMA will transfer one page where we don't need this cmd.
		 we just need to move writer's pointer to specific DMA buffer's position*/
		if (page_addr != -1){
			printk("%s: Error, NAND_CMD_RNDIN cmd. para error page_addr (%x)\n",__FUNCTION__, page_addr);
			return;
		}
		rtk_priv_ptr->data_pos += column;
	}
	else if (command == NAND_CMD_ERASE2) {
		/* send erase2 cmd to flash*/
		
		if ( (page_addr != -1) || (column != -1) ){
			printk("%s: Error, NAND_CMD_ERASE2 invalid para. page_addr(%x) column(%x)\n",__FUNCTION__, page_addr, column);
			return;
		}
		
		rtk_erase_block_bottom_half(mtd);
	}
	else if (command == NAND_CMD_READID) {
		/* send NAND_CMD_READID cmd to flash and copy id to dmabuf */
		
		rtk_read_id(mtd);
	}
	else if (command == NAND_CMD_RESET) {
		/* send reset cmd to flash*/
		
		//printk("%s: Warn, NAND_CMD_RESET not support yet\n",__FUNCTION__);
		//rtk_reset(mtd);
	}
	else{
		printk("%s: Error, cmd not support (%x)\n",__FUNCTION__, command);
		return;
	}

	/*
	 * Program and erase have their own busy handlers status, sequential
	 * in, and deplete1 need no delay.
	 */
	switch (command) {

	case NAND_CMD_CACHEDPROG:
	case NAND_CMD_PAGEPROG:
	case NAND_CMD_ERASE1:
	case NAND_CMD_ERASE2:
	case NAND_CMD_SEQIN:
	case NAND_CMD_RNDIN:
	case NAND_CMD_STATUS:
		return;

	case NAND_CMD_RESET:
		if (nand_ptr->dev_ready)
			break;
		udelay(nand_ptr->chip_delay);
		nand_ptr->cmd_ctrl(mtd, NAND_CMD_STATUS,
			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
		nand_ptr->cmd_ctrl(mtd, NAND_CMD_NONE,
			       NAND_NCE | NAND_CTRL_CHANGE);
		while (!(nand_ptr->read_byte(mtd) & NAND_STATUS_READY))
				;
		return;

	case NAND_CMD_RNDOUT:
		/* we don't need to send NAND_CMD_RNDOUTSTART cmd, since we won't
		 send NAND_CMD_RNDOUT to flash eventually. (just move writer's pointer)*/
		return;

	case NAND_CMD_READ0:
		/* we don't need to send NAND_CMD_READSTART cmd, since our system is dma system
		 where the hardware will send read cmd. automatically*/

		/* This applies to read commands */
	default:
		/*
		 * If we don't have access to the busy pin, we apply the given
		 * command delay.
		 */
		if (!nand_ptr->dev_ready) {
			udelay(nand_ptr->chip_delay);
			return;
		}
	}

	/*
	 * Apply this short delay always to ensure that we do wait tWB in
	 * any case on any machine.
	 */
	ndelay(100);

	nand_wait_ready(mtd);
}

/**
 * control CE line
 * @mtd: MTD device structure
 * @chipnr: chipnumber to select, -1 for deselect
 *
 */
 static void rtk_select_chip(struct mtd_info *mtd, int chipnr)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	
	rtk_priv_ptr->select_chip_record = 0;
	
	switch(chipnr) {
		case -1:
			rtk_writel(0x0, NACMR);
			break;			
		case 0:
			rtk_writel(CECS0, NACMR);
			rtk_priv_ptr->select_chip_record |= CECS0;
			break;
		case 1:
			rtk_writel(CECS1, NACMR);
			rtk_priv_ptr->select_chip_record |= CECS1;
			break;
		default:
			rtk_writel(0x0, NACMR);  //SD5 only support chip1 & chip0
	}
}

/**
 * determine using dma or PIO
 * return : 0: PIO ; 1: DMA
 */
static int is_dma_command(struct mtd_info *mtd)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;

	switch (rtk_priv_ptr->command_record) {

	case NAND_CMD_READ0:
	case NAND_CMD_READ1:
	case NAND_CMD_RNDOUT:
	case NAND_CMD_PAGEPROG:
	case NAND_CMD_READOOB:
	case NAND_CMD_SEQIN:
	case NAND_CMD_RNDIN:
	case NAND_CMD_READID:
		return 1;

	case NAND_CMD_RESET:
	case NAND_CMD_ERASE1:
	case NAND_CMD_ERASE2:
	case NAND_CMD_STATUS:
		return 0;
		
	default:
		printk("%s: Error, cmd not support (%x)\n",__FUNCTION__, rtk_priv_ptr->command_record);
		return 0;
	}
	
}

/**
 * not support in our system
 * @mtd: MTD device structure
 */
static u16 rtk_read_word(struct mtd_info *mtd){
	printk("%s: Error, func not support.\n",__FUNCTION__);
	return -1;
}

/**
 * read a byte from dma buffer indicated by data_pos
 * @mtd: MTD device structure
 */
static uint8_t rtk_read_byte(struct mtd_info *mtd)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	uint8_t d;

	if(is_dma_command(mtd)){
		memcpy(&d, rtk_priv_ptr->dmabuf + rtk_priv_ptr->data_pos, 1);
		rtk_priv_ptr->data_pos += 1;
	}
	else{
		d = rtk_readl(NADR) & 0xff;
	}
	
	return d;
}

/**
 * read data from dma buffer (indicated by data_pos) to buf
 * @mtd: MTD device structure
 * @buf: data buffer
 * @len: number of data bytes to write/read
 */
static void rtk_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	unsigned long NADR_result;

	if(is_dma_command(mtd)){
		memcpy(buf, rtk_priv_ptr->dmabuf + rtk_priv_ptr->data_pos, len);
		rtk_priv_ptr->data_pos += len;
	}
	else{
		if(len > 4){
			printk("%s: Error, len (%x), exceed reg len.\n",__FUNCTION__, len);
			return;
		}
		NADR_result = rtk_readl(NADR);
		memcpy(buf, &NADR_result, len);
	}
}

/**
 * write data from buf to dma buffer (indicated by data_pos)
 * @mtd: MTD device structure
 * @buf: data buffer
 * @len: number of data bytes to write/read
 */
static void rtk_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	unsigned long NADR_result;
	
	if(is_dma_command(mtd)){
		memcpy(rtk_priv_ptr->dmabuf + rtk_priv_ptr->data_pos, buf, len);
		rtk_priv_ptr->data_pos += len;
	}
	else{
		if(len > 4){
			printk("%s: Error, len (%x), exceed reg len.\n",__FUNCTION__, len);
			return;
		}
		NADR_result = rtk_readl(NADR);
		memcpy(&NADR_result, buf, len);
	}
}

/**
 * use to check flash controller is Ready/Busy
 * @mtd: MTD device structure
 */
static int rtk_device_ready(struct mtd_info *mtd)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	int result = 0;
	uint8_t res = 0;
	
	res = (rtk_status(mtd) & 0xff);
	if((!!(rtk_readl(NACR) & 0x80000000)) && (res & NAND_STATUS_READY)){
		result = 1;
	}
	
	return result;
}

/**
 * rtk hardware init.
 */
static void rtk_nand_controller_init (void)
{
	rtk_writel(0xC00FFFFF, NACR);     //Enable ECC	
	rtk_writel(0x0000000F, NASR);     //clear NAND flash status register
}

/**
 * Similar to nand_default_block_markbad where it will mark a block bad.
 * @mtd: MTD device structure
 * @ofs: offset from device start
 *
 * Linux-3.10 : 
 * We try operations in the following order:
 *  (1) erase the affected block, to allow OOB marker to be written cleanly
 *  (2) update in-memory BBT
 *  (3) write bad block marker to OOB area of affected block
 *  (4) update flash-based BBT
 * Note that we retain the first error encountered in (3) or (4), finish the
 * procedures, and dump the error in the end.
 *
 * Since our BBT table's format is different from Linux where the rtk_block_markbad 
 * function will use Linux BBT's information, we have to re-write this function. The
 * most important thing is we have to follow Linux flow in rtk_block_markbad.
 * Linux-3.18 : 
 * nand_chip->block_markbad only need to write block's bbi bit. The full functionality
 * move to nand_block_markbad_lowlevel called by mtd->_block_markbad.
 */
static int rtk_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	uint8_t buf[2] = { 0, 0 };
	int res, ret = 0, i;
	struct mtd_oob_ops ops;
	loff_t wr_ofs = ofs;
	printk("%s: Debug, start flow...\n",__FUNCTION__);

	/* Write bad block marker to OOB */
	ops.mode = MTD_OPS_PLACE_OOB;
	ops.ooboffs = nand_ptr->badblockpos;
	if (nand_ptr->options & NAND_BUSWIDTH_16) {
		ops.ooboffs &= ~0x01;
		ops.len = ops.ooblen = 2;
	} else {
		ops.len = ops.ooblen = 1;
	}
	ops.datbuf = NULL;
	ops.oobbuf = buf;

	if (nand_ptr->bbt_options & NAND_BBT_SCANLASTPAGE)
		wr_ofs += mtd->erasesize - mtd->writesize;
	do {
		res = mtd_write_oob(mtd, wr_ofs, &ops);
		printk("%s: Debug, mtd_write_oob res(%d) ofs(%llx) len(%x) ooblen(%x)\n",__FUNCTION__, res, wr_ofs, ops.len, ops.ooblen);
		if (!ret)
			ret = res;

		i++;
		wr_ofs += mtd->writesize;
	} while ((nand_ptr->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);

	return ret;
}

/**
 * Use with NAND_SKIP_BBTSCAN (skips the bbt scan during initialization) flag. Since
 * there is no BBT in system, we cannot check badblock in BBT.
 */
static int rtk_block_bad_null(struct mtd_info *mtd, loff_t ofs, int getchip)
{
	return 0;
}

/**
 * Function to control hardware ECC generator. We don't need to control ecc hardware
 * in our system.
 */
void rtk_hwctl(struct mtd_info *mtd, int mode){
	return;
}

/**
 * Function for ECC calculation or readback from ECC hardware. Software cannot acess ecc in
 * our system where hardware will count it automatically.
 */
int rtk_calculate(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code){
	return 0;
}

/**
 * Function for ECC correction, matching to ECC generator. Software cannot acess ecc in
 * our system. We just need to return the number of ecc bits.
 * return: return 0: no ecc error; 1~4: ecc can fix it, return fix numbers;
 *		else return -EBADMSG
 *
 * Since rtk_read_page_lowlevel will read one page at once, we cannot correct each step. 
 * This function will always return the max ecc number in all steps
 */			
int rtk_correct(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc){
	struct nand_chip *nand_ptr = (struct nand_chip *) mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	int result = 0;
	
	if(rtk_priv_ptr->max_ecc_counter > 0){
		result = rtk_priv_ptr->max_ecc_counter;
		//printk("%s: Debug, ecc error (%d)\n",__FUNCTION__, result);
	}
	else if(rtk_priv_ptr->max_ecc_counter < 0){
		result = -EBADMSG;
		//printk("%s: Debug, ecc error too many (%d)\n",__FUNCTION__, result);
	}
	
	return result;
}

/**
******************************** module init*************************************
*/


static int __init rtk_nand_init (void)
{
	struct nand_chip *nand_ptr = NULL;
	struct rtk_priv *rtk_priv_ptr = NULL;
	struct mtd_partition *mtd_parts = NULL;
	struct nand_buffers *nbuf;
	char *ptype;
	int ret = 0;
	int pnum = 0;
	
	/*driver version display*/
	display_version();
	
	/*alloc mtd, nand_chip, rtk_priv struct mem.*/
	rtk_mtd = kmalloc (RTK_MTDSIZE, GFP_KERNEL);
	if ( !rtk_mtd ){
		printk("%s: Error, no enough memory for rtk_mtd\n",__FUNCTION__);
		ret = -ENOMEM;
		goto EXIT;
	}	
	memset ( (char *)rtk_mtd, 0, RTK_MTDSIZE);
	nand_ptr = (struct nand_chip *)(rtk_mtd+1);
	rtk_priv_ptr = (struct rtk_priv *)(nand_ptr+1);
	rtk_mtd->priv = nand_ptr;
	nand_ptr->priv = rtk_priv_ptr;
	rtk_mtd->owner = THIS_MODULE;
	
	/*alloc dma mem and nand_chip buffers(if use dma, we need to set buffers to dma mem.).*/
	rtk_priv_ptr->dmabuf = kmalloc( (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE + sizeof(struct nand_buffers) + NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE), GFP_KERNEL );
	if (!rtk_priv_ptr->dmabuf) {
		printk("%s: Error, no enough memory for dmabuf\n",__FUNCTION__);
		ret = -ENOMEM;
		goto EXIT;
	}
	nand_ptr->buffers = nbuf = rtk_priv_ptr->dmabuf + (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE);
	
	/* this driver does not need the @ecccalc and @ecccode */
	nbuf->ecccalc = NULL;
	nbuf->ecccode = NULL;
	nbuf->databuf = (uint8_t *)(nbuf + 2);	//skip two pointers
	
	/*nand controller init*/
	rtk_nand_controller_init();
	
	/*setup function and variables*/
	rtk_mtd->name = "rtk_nand";
	nand_ptr->cmdfunc = rtk_nand_cmdfunc;
	nand_ptr->dev_ready = rtk_device_ready;
	nand_ptr->read_byte = rtk_read_byte;
	nand_ptr->read_word = rtk_read_word;
	nand_ptr->read_buf = rtk_read_buf;
	nand_ptr->write_buf = rtk_write_buf;
	nand_ptr->select_chip = rtk_select_chip;
	nand_ptr->cmd_ctrl = rtk_cmd_ctrl;
	nand_ptr->block_markbad = rtk_block_markbad;
	nand_ptr->scan_bbt = rtk_scan_bbt;
	nand_ptr->options = NAND_OWN_BUFFERS;
	
	if (skipbbt) {
		nand_ptr->options |= NAND_SKIP_BBTSCAN;
		nand_ptr->block_bad = rtk_block_bad_null;
	}
	
	/*scan flash type and setup flash's info. such as mtd->name, mtd->writesize, mtd->erasesize*/
	if (nand_scan_ident(rtk_mtd, 2, NULL)) {
		printk("%s: Error, flash cannot identify\n",__FUNCTION__);
		ret = -ENXIO;
		goto EXIT;
	}
	
	/**
	 * The nand_decode_bbm_options called in nand_get_flash_type will set bbt_options and bbi position 
	 * according to nand flash manufacture. Our architecture will re-write bbi data where we need to 
	 * switch it to avoid this accident. The switch is between RTK_DATA_BBI_POS_2K in data area and
	 * RTK_OOB_BBI_POS_2K in oob area. We need to reset chip->badblockpos to RTK_OOB_BBI_POS_2K to make
	 * sure block_bad(nand_block_bad) can work well.
	 */
	nand_ptr->badblockpos = RTK_OOB_BBI_POS_2K;
	printk("%s: Debug, badblockpos(%x) bbt_options(%x)\n",__FUNCTION__, nand_ptr->badblockpos, nand_ptr->bbt_options);
	printk("%s: Debug, mtd->writesize(%x) mtd->oobsize(%x) mtd->erasesize(%x) name(%s)\n", __FUNCTION__, 
		rtk_mtd->writesize, rtk_mtd->oobsize, rtk_mtd->erasesize, rtk_mtd->name);
	
	/*a page must be multiple of 512B*/
	if ( (rtk_mtd->writesize&(0x200-1)) ){
		printk("%s: Error, pagesize is not 512B Multiple",__FUNCTION__);
		ret = -1;
		goto EXIT;
	}

	/* Set up ECC struct according to the type of chip we found */
	if (rtk_mtd->writesize == 2048) {
		nand_ptr->ecc.layout = &rtk_oobinfo_2048;
	} else if (rtk_mtd->writesize == 512) {
		nand_ptr->ecc.layout = &rtk_oobinfo_512;
	} else {
		printk("%s: Error, Unexpected NAND flash writesize %d. for ecclayout Aborting\n",__FUNCTION__,rtk_mtd->writesize);
		goto EXIT;
	}
	nand_ptr->ecc.mode = NAND_ECC_HW_SYNDROME;
	nand_ptr->ecc.size = RTK_STEP_DATA_SIZE;
	nand_ptr->ecc.bytes = 10;
	nand_ptr->ecc.strength = 4;
	nand_ptr->ecc.prepad = 6;
	nand_ptr->ecc.postpad = 0;
	
	nand_ptr->options |= NAND_NO_SUBPAGE_WRITE;
	
	nand_ptr->ecc.hwctl  = rtk_hwctl;
	nand_ptr->ecc.calculate = rtk_calculate;
	nand_ptr->ecc.correct  = rtk_correct;
	
	/*we use our BBT subsystem not Linux BBT subsystem*/
	nand_ptr->bbt_td = NULL;
	nand_ptr->bbt_md = NULL;
	////////////////////////////////////////////////////////////////////////////////////////////
	
	/*setup the rest callback func. and call scan_bbt func.*/
	ret = nand_scan_tail(rtk_mtd);
	if (ret)
		goto EXIT;
	
	/*registers mtd and partitions*/
#ifdef CONFIG_MTD_CMDLINE_PARTS
	ptype = (char *)ptypes[0];
	pnum = parse_mtd_partitions (rtk_mtd, ptypes, &mtd_parts, 0);
#endif
	if (pnum <= 0) {	
		printk(KERN_NOTICE "RTK: using the whole nand as a partitoin\n");
		//if(mtd_device_parse_register(rtk_mtd, NULL, NULL, mtd_parts, pnum)) {
		if(add_mtd_device(rtk_mtd)) {
			printk(KERN_WARNING "RTK: Failed to register new nand device\n");
			ret = -EAGAIN;
			goto EXIT;
		}
	}else{
		printk(KERN_NOTICE "RTK: using dynamic nand partition\n");
		//if (mtd_device_parse_register(rtk_mtd, NULL, NULL, mtd_parts, pnum)) {	
		if (add_mtd_partitions (rtk_mtd, mtd_parts, pnum)) {
			printk("%s: Error, cannot add %s device\n", __FUNCTION__, rtk_mtd->name);
			rtk_mtd->size = 0;
			ret = -EAGAIN;
			goto EXIT;
		}	
	}
////////////////////////////////////////////////////////////////////////////////////////////

EXIT:
	if ( ret<0 ){
		if (rtk_mtd){
			del_mtd_partitions (rtk_mtd);
			if(nand_ptr){
				kfree(nand_ptr);
			}
			if(rtk_priv_ptr){
				if(rtk_priv_ptr->dmabuf)
					kfree(rtk_priv_ptr->dmabuf);
				kfree(rtk_priv_ptr);
			}
			kfree(rtk_mtd);
		}
	}else
		printk(KERN_INFO "Realtek Nand Flash Driver is successfully installing.\n");
	
	return ret;
}
void __exit rtk_nand_exit (void)
{
	struct nand_chip *nand_ptr = (struct nand_chip *) rtk_mtd->priv;
	struct rtk_priv *rtk_priv_ptr = (struct rtk_priv *) nand_ptr->priv;
	if (rtk_mtd){
		del_mtd_partitions (rtk_mtd);
		if(nand_ptr){
			kfree(nand_ptr);
		}
		if(rtk_priv_ptr){
			if(rtk_priv_ptr->dmabuf)
					kfree(rtk_priv_ptr->dmabuf);
			kfree(rtk_priv_ptr);
		}
		kfree(rtk_mtd);
	}
	
}

module_init(rtk_nand_init);
module_exit(rtk_nand_exit);
MODULE_AUTHOR("Scott Wu<a27585206@realtek.com>");
MODULE_DESCRIPTION("Realtek NAND Flash Controller Driver");