/****************************************************************************** * $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");