update yaffs2 nand according to raho project
authorhxy <hxy@rock-chips.com>
Wed, 29 Dec 2010 08:13:09 +0000 (16:13 +0800)
committerhxy <hxy@rock-chips.com>
Wed, 29 Dec 2010 08:22:08 +0000 (16:22 +0800)
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/rk29_nand.c
fs/yaffs2/yaffs_mtdif2.c
include/linux/mtd/nand.h

index b1221872dd3f90a9dff3f2c2f376c64f72f91a91..0d3e8b779715122500b9dd08860aad0241f772cd 100644 (file)
@@ -1191,8 +1191,15 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                        else
                                ret = chip->ecc.read_page(mtd, chip, bufpoi,
                                                          page);
+#ifdef CONFIG_MTD_NAND_RK29
+            extern int rk29_nand_refresh(struct mtd_info *mtd, int srcAddr);
+                   if(ret == -1)
+                       ret=rk29_nand_refresh(mtd, page<<chip->page_shift);
+#endif              
                        if (ret < 0)
+                       {
                                break;
+                       }
 
                        /* Transfer not aligned data */
                        if (!aligned) {
index bd977a5a904ca571e26adbf8cbb300690c0c95a8..421563cacc59d06ee0155375b1f6067fc1fbd56e 100644 (file)
@@ -1004,6 +1004,10 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
        if (md)
                mark_bbt_region(mtd, md);
 
+#ifdef CONFIG_MTD_NAND_RK29
+    extern void mark_reserve_region(struct mtd_info *mtd,struct nand_bbt_descr *td,struct nand_bbt_descr *md);
+    mark_reserve_region(mtd, td, md);
+#endif    
        vfree(buf);
        return res;
 }
index 222d2d8ef8cb32e057f69c5e95e0f00dc5ba82d1..6ed17fcf1cc136034baeda0902f04b8b0630a551 100644 (file)
 
 /* Define delays in microsec for NAND device operations */
 #define TROP_US_DELAY   2000
+#define NAND_FLAG_WRITE 1
 
+#if 1
+#define FLASH_DEBUG(x...) do{printk(x);}while(0)
+#else
+#define FLASH_DEBUG(s,x...)
+#endif
 
 #ifdef CONFIG_DM9000_USE_NAND_CONTROL
 static DEFINE_MUTEX(rknand_mutex);
@@ -69,6 +75,8 @@ struct rk29_nand_mtd {
 #endif
 
 };
+static int read_in_refresh = 0;
+static int gbRefresh = 0;
 
 /* OOB placement block for use with software ecc generation */
 static struct nand_ecclayout nand_sw_eccoob_8 = {
@@ -169,7 +177,397 @@ static int rk29_nand_dev_ready(struct mtd_info *mtd)
        else
           return 0;
 }
+void mark_reserve_region(struct mtd_info *mtd,struct nand_bbt_descr *td,struct nand_bbt_descr *md)
+{
+    int i, block, nrblocks, tdblock, update = 0;
+    struct nand_chip *this = mtd->priv;
+    uint8_t oldval, newval;
+
+    tdblock = (td->maxblocks >= md->maxblocks)?td->maxblocks:md->maxblocks;
+    nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
+    block = nrblocks - tdblock - RK29_RESERVE_BLOCK_NUM;
+    block <<= 1;
+
+    for(i=0; i<RK29_RESERVE_BLOCK_NUM; i++) {
+            oldval = this->bbt[(block>>3)];
+            newval = oldval|(0x2 << (block & 0x06));
+            this->bbt[(block>>3)] = newval;
+            if (oldval != newval)
+                update = 1;
+            block += 2;
+        }
+  
+    if(update&&td->reserved_block_code)
+    {
+        printk("mark_reserve_region need update!\n");
+        nand_update_bbt(mtd, (loff_t)(block - 2) <<
+                (this->bbt_erase_shift - 1));
+    }
+}
+
+EXPORT_SYMBOL_GPL(mark_reserve_region);
+
+static int rk29_nand_erase(struct mtd_info *mtd, int srcAddr)
+{
+    struct nand_chip *this = mtd->priv;
+    int status;
+
+    //printk(">>>>>>> erase page [%d]\n", srcAddr>>this->page_shift);
+    this->select_chip(mtd, 0);
+    this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, srcAddr>>this->page_shift);
+       this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+    status = this->waitfunc(mtd, this);
+    if(status&NAND_STATUS_FAIL){
+        FLASH_DEBUG("%s: %s erase failed!\n", __FILE__,__FUNCTION__);
+        return -1;
+        }
+    return 0;
+}
+
+static int rk29_get_swap_block_erased(struct mtd_info *mtd, int bdown)
+{
+    struct nand_chip *this = mtd->priv;
+    struct nand_bbt_descr *td = this->bbt_td;
+    struct nand_bbt_descr *md = this->bbt_md;
+    int nrblocks, block, tdblock, startblock, i, fward;
+
+    tdblock = (td->maxblocks > md->maxblocks)?td->maxblocks:md->maxblocks;
+    nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
+    if(bdown){
+        startblock = nrblocks-tdblock-1;
+        fward = -1;
+        }
+    else{
+        startblock = nrblocks-tdblock-RK29_RESERVE_BLOCK_NUM;
+        fward = 1;
+        }
+    
+    for(i=0; i<RK29_RESERVE_BLOCK_NUM; i++){
+        block = startblock + fward*i;
+        if(((this->bbt[block>>2]>>(2*(block & 0x03)))&0x03)==0x02){
+            if(rk29_nand_erase(mtd, block<<this->phys_erase_shift)){
+                mtd->block_markbad(mtd, block<<this->phys_erase_shift);
+                FLASH_DEBUG("%s: %s erase failed!\n", __FILE__,__FUNCTION__);
+                }
+            else{
+                return block<<this->phys_erase_shift;
+                }
+        }
+    }
+    return 0;
+}
+
+static int rk29_block_copy(struct mtd_info *mtd, int srcAddr, int dstAddr, int bSetFlag)
+{
+    struct nand_chip *this = mtd->priv;
+    uint8_t *buf=(uint8_t*)kmalloc(mtd->writesize+32, GFP_KERNEL);
+    int    i,status,pagePblock,src_page,dst_page,src_block;
+    u_char oob[4], oob_bak[4];
+
+    if(!buf){
+        printk("%s:kmalloc failed!\n", __FUNCTION__);
+        return -1;
+        }
+    
+    pagePblock = mtd->erasesize/mtd->writesize;
+    src_page = srcAddr>>this->page_shift;
+    src_block = srcAddr>>this->phys_erase_shift;
+    dst_page = dstAddr>>this->page_shift;
+    
+    memcpy(oob_bak, (u_char *)(this->oob_poi + this->ops.ooboffs),4);
+    if(bSetFlag){
+        uint8_t block_1_8, block_2_8;
+        
+        if(src_block >= 65535){
+            printk("block num err\n");
+            kfree(buf);
+            return -1;
+            }
+
+        block_1_8 = src_block&0xFF;
+        block_2_8 = (src_block>>8)&0xFF;
+        
+        oob[0]='S';
+        oob[1]='W';
+        oob[2]=block_1_8;
+        oob[3]=block_2_8;
+        }
+    else{
+        oob[0]=0xFF;
+        oob[1]=0xFF;
+        oob[2]=0xFF;
+        oob[3]=0xFF;
+        }
+    memcpy((u_char *)(this->oob_poi + this->ops.ooboffs),(u_char *)oob,4);  
+
+    this->select_chip(mtd, 0);
+    for(i=0;i<pagePblock;i++){    
+        this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, src_page);
+        status = this->ecc.read_page(mtd, this, buf, src_page);
+        if(status==-2){
+            FLASH_DEBUG("%s: %s read_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
+            kfree(buf);
+            return -1;
+        }
+
+        this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, dst_page);
+        this->ecc.write_page_raw(mtd, this, buf);
+        this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+        status = this->waitfunc(mtd, this);
+        if(status&NAND_STATUS_FAIL){
+            FLASH_DEBUG("%s: %s write_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
+            kfree(buf);
+            return -1;
+            }
+            
+        src_page++;
+        dst_page++;
+    }
+
+    kfree(buf);
+    memcpy((u_char *)(this->oob_poi + this->ops.ooboffs), oob_bak, 4);
+    
+    return 0;
+}
+
+#if NAND_FLAG_WRITE
+static int rk29_flag_check(struct mtd_info *mtd, uint8_t *buf)
+{
+    int i;
+    
+    if(buf[0] == 'R' && buf[1] == 'K' 
+        && buf[2] == '2' && buf[3] == '9' 
+        && buf[4] == '1' && buf[5] == '8')
+        {
+        return 0;
+        }
+     else{
+        for(i=0;i<mtd->writesize;i++){
+            if(buf[i]!=0xFF)
+                return 1;
+            }
+        return 2;
+        }
+}
+
+static int rk29_get_flag_page(struct mtd_info *mtd, int bdown)
+{
+    struct nand_chip *this = mtd->priv;
+    struct nand_bbt_descr *td = this->bbt_td;
+    struct nand_bbt_descr *md = this->bbt_md;
+    int nrblocks, block, tdblock, startblock, i, status, fward, j, src_page, pageState;
+    uint8_t *buf=(uint8_t*)kmalloc(mtd->writesize+32, GFP_KERNEL);
+
+    if(!buf){
+        printk("%s:kmalloc failed!\n", __FUNCTION__);
+        return 0;
+        }
+        
+    tdblock = (td->maxblocks > md->maxblocks)?td->maxblocks:md->maxblocks;
+    nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
+    if(bdown){
+        startblock = nrblocks-tdblock-1;
+        fward = -1;
+        }
+    else{
+        startblock = nrblocks-tdblock-RK29_RESERVE_BLOCK_NUM;
+        fward = 1;
+        }
+    this->select_chip(mtd, 0);
+    for(i=0; i<RK29_RESERVE_BLOCK_NUM - 3; i++){
+        block = startblock + fward*i;
+        if(((this->bbt[block>>2]>>(2*(block & 0x03)))&0x03)==0x02){
+            for(j=0; j<(1<<(this->phys_erase_shift-this->page_shift)); j++){
+                src_page = (block<<(this->phys_erase_shift-this->page_shift))+j;
+                this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, src_page);
+                status = this->ecc.read_page_raw(mtd, this, buf, src_page);
+                if(status==-2){
+                    FLASH_DEBUG("%s: %s read_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
+                    kfree(buf);
+                    return 0;
+                }
+                if(j==0){
+                    u_char oob[4];
+                    memcpy(oob, (u_char *)(this->oob_poi + this->ops.ooboffs),4);
+                    if((oob[0]!='R')||(oob[1]!='K')||(oob[2]!='F')||(oob[3]!='G')){
+                        if(rk29_nand_erase(mtd, block<<this->phys_erase_shift)){
+                            mtd->block_markbad(mtd, block<<this->phys_erase_shift);
+                            break;
+                            }
+                        //printk("get a free block [%d]!\n", block);
+                        }
+                    this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, src_page);
+                    status = this->ecc.read_page_raw(mtd, this, buf, src_page);
+                    if(status==-2){
+                        FLASH_DEBUG("%s: %s read_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
+                        kfree(buf);
+                        return 0;
+                        }
+                    }
+                pageState = rk29_flag_check(mtd, buf);
+                //printk("src_page = [%d] pageState = [%d]\n", src_page, pageState);
+                if(pageState == 0){
+                    continue;
+                    }
+                else if(pageState == 1){
+                    if(rk29_nand_erase(mtd, block<<this->phys_erase_shift)){
+                        mtd->block_markbad(mtd, block<<this->phys_erase_shift);
+                        break;
+                        }
+                    kfree(buf);
+                    //printk("rk29_get_flag_page: block<<(this->phys_erase_shift-this->page_shift = [%d]\n", block<<(this->phys_erase_shift-this->page_shift));
+                    return block<<(this->phys_erase_shift-this->page_shift);
+                    }
+                else{
+                    kfree(buf);
+                    //printk("rk29_get_flag_page: src_page = [%d]\n", src_page);
+                    return src_page;
+                    }
+            }
+        }
+    }
+    kfree(buf);
+    return 0;
+}
+
+static int rk29_nand_refresh_flag(struct mtd_info *mtd, int srcAddr, int swapAddr)
+{
+    int flagAddr, status;
+    struct nand_chip *this = mtd->priv;
+    uint8_t *buf=(uint8_t*)kmalloc(mtd->writesize+32, GFP_KERNEL);
+    u_char oob[4];
+    
+    if(!buf){
+        printk("%s:kmalloc failed!\n", __FUNCTION__);
+        return 0;
+        }
+    
+    
+    flagAddr = rk29_get_flag_page(mtd, 1);
+    if(flagAddr){
+        buf[0] = 'R';
+        buf[1] = 'K';
+        buf[2] = '2';
+        buf[3] = '9';
+        buf[4] = '1';
+        buf[5] = '8';
+        buf[6] = (uint8_t)(srcAddr&0xFF);
+        buf[7] = (uint8_t)((srcAddr>>8)&0xFF);
+        buf[8] = (uint8_t)((srcAddr>>16)&0xFF);
+        buf[9] = (uint8_t)((srcAddr>>24)&0xFF);
+        memset(&buf[10], 0x88, mtd->writesize-10);
+
+        oob[0]='R';
+        oob[1]='K';
+        oob[2]='F';
+        oob[3]='G';
+        memcpy((u_char *)(this->oob_poi + this->ops.ooboffs),oob,4);
+        
+        this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, flagAddr);
+        this->ecc.write_page_raw(mtd, this, buf);
+        this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+        status = this->waitfunc(mtd, this);
+        if(status&NAND_STATUS_FAIL){
+            FLASH_DEBUG("%s: %s write_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
+            kfree(buf);
+            return -1;
+            }
+        //printk("rk29_nand_refresh_flag: page = [%d]\n", flagAddr);
+        }
+    kfree(buf);
+    return 0;
+}
+#endif
+
+int rk29_nand_refresh(struct mtd_info *mtd, int srcAddr)
+{
+    struct nand_chip *this = mtd->priv;
+    int swapAddr;
+    int ret = 0;
+
+    if(!gbRefresh){
+        printk("bbt is not ready!\n");
+        return 0;
+        }
+
+    srcAddr = (srcAddr>>this->phys_erase_shift)<<this->phys_erase_shift;
+    
+    swapAddr = rk29_get_swap_block_erased(mtd, 0);
+    printk("%s swapAddr[%d] srcAddr[%d]\n", __FUNCTION__, swapAddr, srcAddr);
+
+#if NAND_FLAG_WRITE    
+    rk29_nand_refresh_flag(mtd, srcAddr, swapAddr);
+#endif
+    
+    read_in_refresh = 1;
+    if(!swapAddr){
+        printk("no swap block fined!!!\n");
+        ret = -1;
+        goto nand_refresh_error;
+        }
+
+    if(rk29_nand_erase(mtd, swapAddr)){
+        printk("rk29_nand_erase[0x%x] failed!\n", srcAddr);
+        ret = -1;
+        goto nand_refresh_error;
+        }
+        
+    if(rk29_block_copy(mtd, srcAddr, swapAddr, 1)){
+        printk("rk29_block_copy[0x%x ---> 0x%x] failed!\n", srcAddr, swapAddr);
+        ret = -1;
+        goto nand_refresh_error;
+        }
+
+    if(rk29_nand_erase(mtd, srcAddr)){
+        printk("rk29_nand_erase[0x%x] failed!\n", srcAddr);
+        ret = -1;
+        goto nand_refresh_error;
+        }
+        
+    if(rk29_block_copy(mtd, swapAddr, srcAddr, 0)){
+        printk("rk29_block_copy[0x%x ---> 0x%x] failed!\n", swapAddr, srcAddr);
+        ret = -1;
+        goto nand_refresh_error;
+        }
+    if(rk29_nand_erase(mtd, swapAddr)){
+        printk("rk29_nand_erase[0x%x] failed!\n", srcAddr);
+        ret = -1;
+        goto nand_refresh_error;
+        }
+nand_refresh_error:
+    read_in_refresh = 0;
+    return ret;
+}
+
+EXPORT_SYMBOL_GPL(rk29_nand_refresh);
+
+
+static int rk29_nand_check_hwecc(struct mtd_info *mtd, int page)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+
+       if((pRK29NC->BCHST[0]&0x1) && (pRK29NC->BCHST[0]&0x4))
+        {
+        FLASH_DEBUG("%s: %s BCH FAIL!!!page=[%d]\n", __FILE__,__FUNCTION__, page);
+        dump_stack();
+        return 2;
+        }
+    
+    if((((pRK29NC->BCHST[0])>>3)&0x1F) >= 12 /*|| refreshTestCnt++%10000 == 0*/)
+    {
+        return 1;
+    }
 
+    if(pRK29NC->BCHST[0]&0x2){
+           return 0;
+           }
+       else{
+           FLASH_DEBUG("%s: %s Flash BCH no done!!!\n", __FILE__,__FUNCTION__);
+           return 2;
+           }
+}
 /*
 *  ÉèÖÃƬѡ
 */
@@ -316,9 +714,6 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column,
        struct nand_chip *nand_chip = mtd->priv;
        struct rk29_nand_mtd *master = nand_chip->priv;
        pNANDC pRK29NC=  (pNANDC)(master->regs);
-
-       char status,ret;
-
        
        switch (command) {
 
@@ -393,15 +788,6 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column,
                pRK29NC ->chip[master->cs].cmd = command;
                udelay(1);
                rk29_nand_wait_busy(mtd,PROGRAM_BUSY_COUNT);
-               
-               pRK29NC ->chip[master->cs].cmd  = NAND_CMD_STATUS;
-               status = pRK29NC ->chip[master->cs].data;
-               
-               if(status&0x1)
-                       ret = -1;
-               else
-                       ret =0;
-               
                break;
                
        case NAND_CMD_ERASE1:
@@ -420,14 +806,6 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column,
                pRK29NC ->FMCTL |= FMC_WP;  //½â³ýд±£»¤
                pRK29NC ->chip[master->cs].cmd  = command;             
                rk29_nand_wait_busy(mtd,ERASE_BUSY_COUNT);
-               pRK29NC ->chip[master->cs].cmd  = NAND_CMD_STATUS;
-               status = pRK29NC ->chip[master->cs].data;
-               
-               if(status&0x1)
-                       ret = -1;
-               else
-                       ret =0;
-               
                break;
                
        case NAND_CMD_SEQIN:
@@ -476,6 +854,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
  
      int eccdata[7],i;
         
+    FLASH_DEBUG("%s:%s, %d\n", __FILE__,__FUNCTION__, __LINE__);
        for(i=0;i<7;i++) 
         {
            eccdata[i] = pRK29NC->spare[i+1];
@@ -497,6 +876,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
        struct rk29_nand_mtd *master = nand_chip->priv;
        pNANDC pRK29NC=  (pNANDC)(master->regs);
 
+    FLASH_DEBUG("%s:%s, %d\n", __FILE__,__FUNCTION__, __LINE__);
        pRK29NC->BCHCTL = 1;  // reset bch and enable hw ecc
                
        return;
@@ -511,8 +891,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
        // hw correct data
        if( pRK29NC->BCHST[0] & (1<<2) )
         {
-               DEBUG(MTD_DEBUG_LEVEL0,
-                     "rk2818 nand :hw ecc uncorrectable error\n");
+        FLASH_DEBUG("%s: %s BCH FAILED!!!\n", __FILE__,__FUNCTION__);
                return -1;
        }
        
@@ -525,7 +904,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
        struct rk29_nand_mtd *master = nand_chip->priv;
        pNANDC pRK29NC=  (pNANDC)(master->regs);
          
-       int i,chipnr;
+       int i,chipnr, ecc = 0;
 
           
        RKNAND_LOCK();
@@ -533,9 +912,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
        chipnr = master->cs ;
        
        rk29_nand_select_chip(mtd,chipnr);
-       rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
+
           
        pRK29NC->FLCTL |= FL_BYPASS;  // dma mode
        
@@ -550,15 +927,27 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
               pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;         
                wait_op_done(mtd,TROP_US_DELAY,0);   
                rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;
-          
+        ecc |= rk29_nand_check_hwecc(mtd, page);
               memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400);  //  only use nandc sram0
        }
        
+    if(ecc & 0x2){
+        mtd->ecc_stats.failed++;
+               return -EBADMSG;
+        }
+    else if(ecc & 0x1){
+        if(!read_in_refresh){
+            //FLASH_DEBUG("Flash need fresh srcAddr = [%d]\n", ((page*mtd->writesize)/mtd->erasesize)*mtd->erasesize);
+            return -1;
+            }
+        }
                
        rk29_nand_select_chip(mtd,-1);
 
        RKNAND_UNLOCK();
-       
+       //t2 = ktime_get();
+       //delta = ktime_sub(t2, t1);
+       //FLASH_DEBUG("%s:%s [%lli nsec]\r\n",__FILE__,__FUNCTION__, (long long)ktime_to_ns(delta));
     return 0;
        
  }
@@ -613,7 +1002,11 @@ int rk29_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, i
        struct nand_chip *nand_chip = mtd->priv;
        struct rk29_nand_mtd *master = nand_chip->priv;
        pNANDC pRK29NC=  (pNANDC)(master->regs);
-       int i,chipnr;
+    int i,chipnr,ecc=0;
+       RKNAND_LOCK();
+       chipnr = master->cs ;
+       
+       rk29_nand_select_chip(mtd,chipnr);
 
          
        if (sndcmd) {
@@ -621,12 +1014,6 @@ int rk29_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, i
                sndcmd = 0;
        }
 
-       RKNAND_LOCK();
-
-       chipnr = master->cs ;
-
-       rk29_nand_select_chip(mtd,chipnr);
-
        rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
 
        
@@ -644,10 +1031,21 @@ int rk29_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, i
               pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;         
                wait_op_done(mtd,TROP_US_DELAY,0);   
                rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;
+        ecc |= rk29_nand_check_hwecc(mtd, page);
               if(i==0)
                  memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK29NC->spare),4); 
        }
 
+    if(ecc & 0x2){
+        mtd->ecc_stats.failed++;
+               return -EBADMSG;
+        }
+    else if(ecc & 0x1){
+        if(!read_in_refresh){
+            //FLASH_DEBUG("Flash need fresh srcAddr = [%d]\n", ((page*mtd->writesize)/mtd->erasesize)*mtd->erasesize);
+            return -1;
+            }
+        }
           
         rk29_nand_select_chip(mtd,-1);
 
@@ -663,7 +1061,7 @@ int        rk29_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_
        struct rk29_nand_mtd *master = nand_chip->priv;
        pNANDC pRK29NC=  (pNANDC)(master->regs);
 
-       int i,chipnr;
+    int i,chipnr,ecc=0;
 
        
     RKNAND_LOCK();
@@ -687,11 +1085,22 @@ int      rk29_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_
               pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;         
                wait_op_done(mtd,TROP_US_DELAY,0);   
                 rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;
+        ecc |= rk29_nand_check_hwecc(mtd, page);
               memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400);  //  only use nandc sram0
               if(i==0)
                  memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK29NC->spare),4); 
        }
 
+    if(ecc & 0x2){
+        mtd->ecc_stats.failed++;
+               return -EBADMSG;
+        }
+    else if(ecc & 0x1){
+        if(!read_in_refresh){
+            //FLASH_DEBUG("Flash need fresh srcAddr = [%d]\n", ((page*mtd->writesize)/mtd->erasesize)*mtd->erasesize);
+            return -1;
+            }
+        }
         
         rk29_nand_select_chip(mtd,-1);
         RKNAND_UNLOCK();
@@ -699,6 +1108,45 @@ int       rk29_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_
         
     return 0;
 }
+int    rk29_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,const uint8_t *buf)
+{
+    struct nand_chip *nand_chip = mtd->priv;
+    struct rk29_nand_mtd *master = nand_chip->priv;
+    pNANDC pRK29NC=  (pNANDC)(master->regs);
+    int i,chipnr;
+
+    //FLASH_DEBUG("%s: %s, %d\n", __FILE__ ,__FUNCTION__, __LINE__);
+    
+    RKNAND_LOCK();
+
+       chipnr = master->cs ;
+       
+       rk29_nand_select_chip(mtd,chipnr);
+
+    rk29_nand_wait_busy(mtd, PROGRAM_BUSY_COUNT);
+          
+       pRK29NC->FLCTL |= FL_BYPASS;  // dma mode
+
+       if(chip->options&NAND_BUSWIDTH_16)
+       {
+               pRK29NC ->FMCTL |= FMC_WIDTH_16;  // ÉèÖÃΪ16λ
+       }        
+
+    for(i=0;i<mtd->writesize/0x400;i++)
+    {
+        pRK29NC->BCHCTL = BCH_WR|BCH_RST;              
+        memcpy((u_char *)(pRK29NC->buf),(buf+i*0x400),0x400);
+        if(i==0)
+            memcpy((u_char *)(pRK29NC->spare),(u_char *)(chip->oob_poi + chip->ops.ooboffs),4);  
+        pRK29NC->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_RDN|FL_BYPASS|FL_START;  
+        wait_op_done(mtd,TROP_US_DELAY,0);     
+    }
+        rk29_nand_select_chip(mtd,-1);
+
+    RKNAND_UNLOCK();        
+    return 0;
+}
+
 
 static int rk29_nand_setrate(struct rk29_nand_mtd *info)
 {
@@ -795,7 +1243,6 @@ static int rk29_nand_probe(struct platform_device *pdev)
        int err = 0;
        pNANDC pRK29NC;
        u_char  maf_id,dev_id,ext_id3,ext_id4;
-    struct nand_chip *chip;
     
 #ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *partitions = NULL;
@@ -896,39 +1343,16 @@ static int rk29_nand_probe(struct platform_device *pdev)
    
        /* Scan to find existence of the device */
 #if 0
-          if (nand_scan(mtd, 8)) {     // rk2818 nandc support max 8 cs
+          if (nand_scan(mtd, 8)) {     // rk29 nandc support max 8 cs
 #else
           if (nand_scan(mtd, 1)) {      // test for fpga board nand
 #endif
                DEBUG(MTD_DEBUG_LEVEL0,
-                     "RK2818 NAND: Unable to find any NAND device.\n");
+                     "RK29 NAND: Unable to find any NAND device.\n");
                err = -ENXIO;
                goto outscan;
        }
 
-       //¸ù¾ÝƬѡÇé¿ö»Ö¸´IO MUXԭʼֵ
-#if 0
-    chip = mtd->priv;
-    switch(chip->numchips)
-    {
-        case 1:
-            rk2818_mux_api_mode_resume(GPIOA5_FLASHCS1_SEL_NAME);
-        case 2:
-            rk2818_mux_api_mode_resume(GPIOA6_FLASHCS2_SEL_NAME);
-        case 3:
-            rk2818_mux_api_mode_resume(GPIOA7_FLASHCS3_SEL_NAME);
-        case 4:
-            rk2818_mux_api_mode_resume(GPIOE_SPI1_FLASH_SEL1_NAME);
-        case 5:
-        case 6:
-            rk2818_mux_api_mode_resume(GPIOE_SPI1_FLASH_SEL_NAME);
-        case 7:
-        case 8:
-            break;
-        default:
-            DEBUG(MTD_DEBUG_LEVEL0, "RK2818 NAND: numchips error!!!\n");
-    }
-#endif    
 
 #ifdef CONFIG_MTD_PARTITIONS
         num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
@@ -959,6 +1383,7 @@ static int rk29_nand_probe(struct platform_device *pdev)
        
 outres:
 outscan:
+    printk("rk29_nand_probe error!!!\n");
        iounmap(master->regs);
        kfree(master);
 
@@ -998,6 +1423,7 @@ static int rk29_nand_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int rk29_nand_suspend(struct platform_device *pdev, pm_message_t state)
 {
+#if 0
        struct mtd_info *info = platform_get_drvdata(pdev);
        int ret = 0;
 
@@ -1005,10 +1431,14 @@ static int rk29_nand_suspend(struct platform_device *pdev, pm_message_t state)
        if (info)
                ret = info->suspend(info);
        return ret;
+#else
+    return 0;
+#endif
 }
 
 static int rk29_nand_resume(struct platform_device *pdev)
 {
+#if 0
        struct mtd_info *info = platform_get_drvdata(pdev);
        int ret = 0;
 
@@ -1019,6 +1449,9 @@ static int rk29_nand_resume(struct platform_device *pdev)
                info->resume(info);
 
        return ret;
+#else
+    return 0;
+#endif
 }
 #else
 #define rk29_nand_suspend   NULL
index 282a093d854d43b8a7914d049b1d8654349b7dcb..afe076f6775ecf0a63bdc11bc5a0a888f3dfa2b2 100644 (file)
@@ -173,7 +173,12 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
        if (localData)
                yaffs_ReleaseTempBuffer(dev, data, __LINE__);
 
+#ifdef CONFIG_MTD_NAND_RK29
+    //dxj 20101221@ if return -EBADMSG then i think the page is badchunk so just set the eccResult=YAFFS_ECC_RESULT_NO_ERROR
+    if (tags && retval == -EBADMSG /*&& tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR*/) {
+#else    
        if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
+#endif 
                tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
                dev->eccUnfixed++;
        }
index 7a232a9bdd6230e0db32e93b582af621c88a02ba..4186923e0d2532c11a42f6bcaa53934f6f9d057f 100644 (file)
@@ -36,6 +36,9 @@ extern void nand_release (struct mtd_info *mtd);
 /* Internal helper for board drivers which need to override command function */
 extern void nand_wait_ready(struct mtd_info *mtd);
 
+#ifdef CONFIG_MTD_NAND_RK29
+#define RK29_RESERVE_BLOCK_NUM    5
+#endif
 /* The maximum number of NAND chips in an array */
 #define NAND_MAX_CHIPS         8