⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand_base.c

📁 this is for nand controller
💻 C
📖 第 1 页 / 共 5 页
字号:
{
	struct nand_chip * chip = mtd->priv;
	unsigned long timeout;
	uint32_t ready;

	
	/* The 20 msec is enough */
	timeout = jiffies + msecs_to_jiffies(3000); // 3 sec timeout for now
	while (time_before(jiffies, timeout)) {
		PLATFORM_IOFLUSH_WAR();
		ready = chip->ctrl_read(BCHP_NAND_INTFC_STATUS);

		if (ready & (BCHP_NAND_INTFC_STATUS_CTLR_READY_MASK | 0x1)) {
			int ecc;
			
			if (ready & 0x1) {
				printk(KERN_ERR "%s: Flash chip report error %08x\n", __FUNCTION__, ready);
				return NAND_FLASH_STATUS_ERROR;
			}

			//if (!raw) {
			ecc = nand_verify_ecc(chip, state);
// Let caller handle it
//printk("%s: Possible Uncorrectable ECC error at offset %08x\n", __FUNCTION__, (unsigned long) offset);
				return ecc;
			//}
			//return NAND_SUCCESS;
		}
		if (state != FL_READING)
			cond_resched();

	}

	return NAND_TIMED_OUT; // TimeOut
}

#ifdef CONFIG_MTD_NAND_EDU

/* 
 * Returns      1: Success, no errors
 *              0: Timeout
 *            -1: Errors
 */
static int nand_EDU_cache_is_valid(struct mtd_info* mtd,  int state, L_OFF_T offset) 
{
        uint32 rd_data = 0;
        int error = 0;

        rd_data = EDU_poll(EDU_BASE_ADDRESS  + BCHP_HIF_INTR2_CPU_STATUS, HIF_INTR2_EDU_DONE, HIF_INTR2_EDU_DONE);  

        if(rd_data != 0)
        {
            error = nand_cache_is_valid(mtd, state, offset);
        }
        
        EDU_volatileWrite(EDU_BASE_ADDRESS  + EDU_DONE, 0x00000000);
        EDU_volatileWrite(EDU_BASE_ADDRESS  + EDU_ERR_STATUS, 0x00000000);
        EDU_volatileWrite(EDU_BASE_ADDRESS  + BCHP_HIF_INTR2_CPU_CLEAR, HIF_INTR2_EDU_CLEAR);    
       
        return error;
}

#endif  // CONFIG_MTD_NAND_EDU


static int nand_select_cache_is_valid(struct mtd_info* mtd,  int state, L_OFF_T offset) 
{
    int ret = 0;
#ifdef CONFIG_MTD_NAND_EDU
    ret =   nand_EDU_cache_is_valid(mtd,state,offset);  
#else
    ret =   nand_cache_is_valid(mtd,state,offset);  
#endif
    return ret;
}
/* 
 * Returns 	 1: Success, no errors
 * 			 0: Timeout
 *			-1: Errors
 */
static int nand_spare_is_valid(struct mtd_info* mtd,  int state, int raw) 
{
	struct nand_chip * chip = mtd->priv;
	unsigned long timeout;
	uint32_t ready;

	/* The 20 msec is enough */
	timeout = jiffies + msecs_to_jiffies(3000);  // 3 sec timeout for now
	while (time_before(jiffies, timeout)) {
		PLATFORM_IOFLUSH_WAR();
		ready = chip->ctrl_read(BCHP_NAND_INTFC_STATUS);

		if (ready & BCHP_NAND_INTFC_STATUS_CTLR_READY_MASK) {
			int ecc;

			if (!raw) {
				ecc = nand_verify_ecc(chip, state);
				if (ecc < 0) {
//printk("%s: Uncorrectable ECC error at offset %08x\n", __FUNCTION__, (unsigned long) offset);
					return -1;
				}
			}
			return 1;
		}
		if (state != FL_READING)
			cond_resched();
	}

	return 0; // Timed out
}

#ifdef CONFIG_MTD_NAND_EDU

static int nand_EDU_write_is_complete(struct mtd_info *mtd, int* outp_needBBT)
{
    uint32 rd_data = 0;

// printk("%s\n", __FUNCTION__);

    *outp_needBBT = 1;
    
    rd_data = EDU_poll(EDU_BASE_ADDRESS  + BCHP_HIF_INTR2_CPU_STATUS, HIF_INTR2_EDU_DONE, HIF_INTR2_EDU_DONE);
        
    if ((rd_data & HIF_INTR2_EDU_DONE) == HIF_INTR2_EDU_DONE ) 
    {
        //Get status:
        *outp_needBBT = EDU_get_error_status_register();

        //Clear interrupt:
        EDU_volatileWrite(EDU_BASE_ADDRESS  + EDU_DONE, 0x00000000);
        EDU_volatileWrite(EDU_BASE_ADDRESS  + EDU_ERR_STATUS, 0x00000000);
        EDU_volatileWrite(EDU_BASE_ADDRESS  + BCHP_HIF_INTR2_CPU_CLEAR, HIF_INTR2_EDU_CLEAR);

        if (*outp_needBBT != 0)
        {
            printk("EDU_write_is_complete(): error 0x%08X\n", *outp_needBBT);
        }

        return 1;  //Poll success!
    }

    printk("EDU_write_is_complete(): error 2 rd_data: %08x\n", (unsigned int)rd_data);
    
    //Poll did not return HIF_INTR2_EDU_DONE:
    return 0;
}

#endif // CONFIG_MTD_NAND_EDU


static int nand_write_is_complete(struct mtd_info *mtd, int* outp_needBBT)
{
	int err;
	uint32_t status;
	uint32_t flashStatus = 0;

	*outp_needBBT = 1;
	err = nand_wait(mtd, FL_WRITING, &status);
	if (!err) {
		if (status & BCHP_NAND_INTFC_STATUS_CTLR_READY_MASK) {
			flashStatus = status & 0x01;
			*outp_needBBT = flashStatus; // 0 = write completes with no errors
			return 1;
		}
		else {
			return 0;
		}
	}
	return 0;
}

static int nand_select_write_is_complete(struct mtd_info *mtd, int* outp_needBBT)
{
    int ret = 0;
    
#ifdef CONFIG_MTD_NAND_EDU 
    //Check the state of the current lock of the device: 
    struct nand_chip *this = mtd->priv;
    
    if (this->state == FL_WRITING)
    {
        ret = nand_EDU_write_is_complete(mtd, outp_needBBT);
    }
    else
    {
        ret = nand_write_is_complete(mtd, outp_needBBT);
    }
#else
    ret = nand_write_is_complete(mtd, outp_needBBT);
#endif    

    return ret;
}



/**
 * nand_transfer_oob - [Internal] Transfer oob to client buffer
 * @chip:	nand chip structure
 * @oob:	oob destination address
 * @ops:	oob ops structure
 */
static uint8_t *
nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
				  struct mtd_oob_ops *ops)
{
	size_t len = ops->ooblen;

	switch(ops->mode) {

	case MTD_OOB_PLACE:
	case MTD_OOB_RAW:
		memcpy(oob, chip->oob_poi + ops->ooboffs, len);
		return oob + len;

	case MTD_OOB_AUTO: {
		struct nand_oobfree *free = chip->ecclayout->oobfree;
		uint32_t boffs = 0, roffs = ops->ooboffs;
		size_t bytes = 0;

		for(; free->length && len; free++, len -= bytes) {
			/* Read request not from offset 0 ? */
			if (unlikely(roffs)) {
				if (roffs >= free->length) {
					roffs -= free->length;
					continue;
				}
				boffs = free->offset + roffs;
				bytes = min_t(size_t, len,
					      (free->length - roffs));
				roffs = 0;
			} else {
				bytes = min_t(size_t, len, free->length);
				boffs = free->offset;
			}
			memcpy(oob, chip->oob_poi + boffs, bytes);
			oob += bytes;
		}
		return oob;
	}
	default:
		BUG();
	}
	return NULL;
}

#ifdef CONFIG_MTD_NAND_EDU

/**
 * nand_posted_read_cache - [NAND Interface] Read the 512B cache area
 * Assuming nand_get_device() has been called to obtain exclusive lock
 * @param mtd        MTD data structure
 * @param oobarea    Spare area, pass NULL if not interested
 * @param buffer    the databuffer to put/get data, pass NULL if only spare area is wanted.
 * @param offset    offset to read from or write to, must be 512B aligned.
 * @param raw: Ignore BBT bytes when raw = 1
 *
 * Caller is responsible to pass a buffer that is
 * (1) large enough for 512B for data and optionally an oobarea large enough for 16B.
 * (2) 4-byte aligned.
 *
 * Read the cache area into buffer.  The size of the cache is mtd-->eccsize and is always 512B.
 */
static int nand_posted_read_cache(struct mtd_info* mtd, 
        void* buffer, u_char* oobarea, L_OFF_T offset)
{

    int ecc;
#if 0
    L_OFF_T blockOffset;
    static int refresh_recursive = 0;
#endif    
    struct nand_chip* this = mtd->priv;
    L_OFF_T sliceOffset = __ll_and32(offset, ~ (mtd->eccsize - 1));
    int i, ret = 0;
    int retries = 2, done = 0;
    uint32_t* p32 = (uint32_t*) oobarea;
    
    
#ifdef ECC_UNCORRECTABLE_SIMULATION
    uint8_t* my_buffer = NULL;
#endif    
    
if (gdebug > 3) {
printk("%s: offset=%s, oobarea=%p\n", __FUNCTION__, __ll_sprintf(NandMsg, offset), oobarea);}

    while (retries > 0 && !done) 
    {
        if (unlikely(__ll_isub(offset, sliceOffset))) {
            printk(KERN_ERR "%s: offset %s is not cache aligned, sliceOffset=%s, CacheSize=%d\n", 
                __FUNCTION__, __ll_sprintf(NandMsg, offset), __ll_sprintf(NandMsg, sliceOffset), mtd->eccsize);
            return -EINVAL;
        }

        this->ctrl_writeAddr(this, sliceOffset, 0);
        PLATFORM_IOFLUSH_WAR(); 

        ret = EDU_read(buffer, EDU_ldw);
	 if (ret)
	 	goto out;

        // Wait until cache is filled up
        ecc = nand_select_cache_is_valid(mtd, FL_READING, offset);

        if (oobarea) 
        {
            PLATFORM_IOFLUSH_WAR();
            for (i = 0; i < 4; i++) 
            {
                p32[i] = be32_to_cpu (this->ctrl_read(BCHP_NAND_SPARE_AREA_READ_OFS_0 + i*4));
            }
            if (gdebug) {printk("%s: offset=%s, oob=\n", __FUNCTION__, __ll_sprintf(NandMsg, sliceOffset)); 
                                print_oobbuf(oobarea, 16);}
        }
        
        switch (ecc) 
        {
            case NAND_SUCCESS: /* Success, no errors */
            {
                ret = 0;            // Success!
                done = 1;
            }
            break;

            case NAND_CORRECTABLE_ECC_ERROR:
            {
#if 0            
                if (refresh_recursive == 0)
                {
                    printk("%s: ECC correctable error at %s, refreshing block...\n",__FUNCTION__,__ll_sprintf(NandMsg, offset, this->xor_invert_val));

                    refresh_recursive = 1;

                    nand_deduce_blockOffset(mtd, offset, &blockOffset);

                    ret = nand_refresh_block(mtd, blockOffset);
                    
                    refresh_recursive = 0;
                    
                    if (ret == 0)
                    {
                        printk("%s: Block refreshed successfully\n",__FUNCTION__);
                        ret = -EECCCOR;  
                    }
                    else
                    {
                        printk("%s: Block refresh failure!\n",__FUNCTION__);
                    }
                }
#else
                ret = 0; // Success!  
#endif                
                done = 1;
            }
            break;
            
            case NAND_UNCORRECTABLE_ECC_ERROR:
            {
                /* Flash chip returns errors 

                || There is a bug in the controller, where if one reads from an erased block that has NOT been written to,
                || this error is raised.  
                || (Writing to OOB area does not have any effect on this bug)
                || The workaround is to also look into the OOB area, to see if they are all 0xFF
                
                */
                u_char oobbuf[16];
                int all00, allFF;

               // NAND CTRL BUG... EDU has stopped! Must copy buffer!!!
                memcpy(buffer, this->vbase, mtd->eccsize);

                if (!oobarea) 
                    oobarea = &oobbuf[0];
                p32 = (uint32_t*) oobarea;

                for (i = 0; i < 4; i++) {
                    p32[i] = /* THT 11-30-06 */ be32_to_cpu (this->ctrl_read(BCHP_NAND_SPARE_AREA_READ_OFS_0 + i*4));
                }

                all00 = (oobarea[6] == 0xff && oobarea[7] == 0xff && oobarea[8] == 0xff);
                allFF = (oobarea[6] == 0x00 && oobarea[7] == 0x00 && oobarea[8] == 0x00);
                if ( all00 || allFF) {
                    /* 
                     * For the first case, the slice is an erased block, and the ECC bytes are all 0xFF,
                     * for the 2nd, all bytes are 0xFF, so the Hamming Codes for it are all zeroes.
                     * The current version of the NAND controller treats these as un-correctable errors.
                     * For either case, fill data buffer with 0x00 or 0xff and return success.  The error has already
                     * been cleared inside nand_verify_ecc.
                     * Both case will be handled correctly by the Nand controller in later releases.
                     */
                    p32 = (uint32_t*) buffer;
                    for (i=0; i < mtd->eccsize/4; i++) {
                        p32[i] = 0xFFFFFFFF;
                    }
                    
              
                    ret = 0; // Success!

                }
                else 
                {
#ifdef ECC_UNCORRECTABLE_SIMULATION
                    if (bEccUncor)
                    {
                        printk("Inserting errors in buffer\n");
                        if (buffer != NULL)
                        {
                            my_buffer = (uint8_t*) buffer;
                            
                            //Invert data in buffer:
                            for (i = 0; i < mtd->eccsize; i++)
                            {
                                my_buffer[i] = ~my_buffer[i];
                            }
                        }
                    }
#endif 
                    /* Real error: Disturb read returns uncorrectable errors */

                    if (gdebug) printk("%s: ECC noncorrectable error at %s\n",__FUNCTION__, __ll_sprintf(NandMsg, offset));

#if 0 
//commented because yaffs2 and jffs2 are taking care of marking the bad blocks whenever we return -EECCUNCOR                    

                    printk("%s: Marking bad block @%s\n", __FUNCTION__, __ll_sprintf(NandMsg, offset, this->xor_invert_val));
                    ret = this->block_markbad(mtd, offset);
#endif                    
                    ret = -EBADMSG;

                    
                }
                done = 1;
            }
            break;
            
            case EDU_CORRECTABLE_ECC_ERROR:
            {
                memcpy(buffer, this->vbase, mtd->eccsize);  
                ret = 0;            // Success!
                done = 1;
                if (gdebug) printk("%s: EDU Correctable ECC error: ret -EBADMSG !!!\n",__FUNCTION__);
            }
            break; 

            case EDU_UNCORRECTABLE_ECC_ERROR:
            {
                 printk("EDU_read45\n");
                // NAND CTRL BUG... EDU has stopped! BUT NO ERROR!!! Must copy buffer!!!
                memcpy(buffer, this->vbase, mtd->eccsize);  
                ret = 0;            // Success!
                done = 1;
                if (gdebug) printk("%s: EDU ECC noncorrectable error at %s",__FUNCTION__, __ll_sprintf(NandMsg, offset));
            }            
            break;            

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -