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

📄 nand_base.c

📁 this is for nand controller
💻 C
📖 第 1 页 / 共 5 页
字号:
            
            case NAND_TIMED_OUT:
            {
 printk("EDU_read60\n");
                //Read has timed out 
                printk(KERN_ERR "nand_select_cache_is_valid has timed out.\n");
                ret = -ETIMEDOUT;
                done = 1;
            }
            break;

            default:
            {
 printk("EDU_read70\n");
                BUG_ON(1);
                /* Should never get here */
                ret = -EINVAL;
                done = 1;
            }
            break; 
        }//End of switch()
    }//End of while()

out:

    return ret;
}

#else // NO EDU PRESENT OR EDU DISABLED

/**
 * 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.
 *
 * 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)
{
	struct nand_chip* chip = mtd->priv;
	L_OFF_T sliceOffset = __ll_and32(offset, ~ (mtd->eccsize - 1));
	int i, ret;
	int retries = 2, done = 0;
	uint32_t* p32 = (uint32_t*) oobarea;

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 %08x is not cache aligned, sliceOffset=%08lx, CacheSize=%d\n", 
				__FUNCTION__, (unsigned int) offset, (unsigned long) sliceOffset, mtd->eccsize);
			return -EINVAL;
		}


		chip->ctrl_writeAddr(chip, sliceOffset, 0);
		PLATFORM_IOFLUSH_WAR();
		chip->ctrl_write(BCHP_NAND_CMD_START, OP_PAGE_READ);

		// Wait until cache is filled up
		ret = nand_select_cache_is_valid(mtd, FL_READING, offset);
		switch (ret) {
		case NAND_CORRECTABLE_ECC_ERROR: /* Success, no errors */
		case NAND_SUCCESS:
			if (buffer) {
				nand_from_flash_memcpy32(chip, buffer, offset, mtd->eccsize);
			}

			if (oobarea) {
				PLATFORM_IOFLUSH_WAR();
				for (i = 0; i < 4; i++) {
					p32[i] = /* THT 11-30-06 */ be32_to_cpu (chip->ctrl_read(BCHP_NAND_SPARE_AREA_READ_OFS_0 + i*4));
				}
if (gdebug) {printk("%s: offset=%08x, oob=\n", __FUNCTION__, __ll_low(sliceOffset)); print_oobbuf(oobarea, 16);}
			}

			// ret = NAND_CORRECTABLE_ECC_ERROR; // Success
			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 erased, allFF;
				int i;

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

				for (i = 0; i < 4; i++) {
					p32[i] = /* THT 11-30-06 */ be32_to_cpu (chip->ctrl_read(BCHP_NAND_SPARE_AREA_READ_OFS_0 + i*4));
				}
				if (chip->ecclevel == NAND_ECC_HAMMING) {
				erased = (oobarea[6] == 0xff && oobarea[7] == 0xff && oobarea[8] == 0xff);
				allFF = (oobarea[6] == 0x00 && oobarea[7] == 0x00 && oobarea[8] == 0x00);
if (gdebug > 3 ) {printk("%s: erased=%d, allFF=%d\n", __FUNCTION__, erased, allFF);}
				}
				else if (chip->ecclevel >= NAND_ECC_BCH_1 && chip->ecclevel <= NAND_ECC_BCH_12) {
					erased = allFF = 1;
					// For BCH-n, the ECC bytes are at the end of the OOB area
					for (i=chip->eccOobSize-chip->eccbytes; i<chip->eccOobSize; i++) {
						erased = erased && (oobarea[i] == 0xff);
						allFF = allFF && (oobarea[i] == 0x00);
					}
//if (gdebug > 3 ) 
{printk("%s: eccOobSize=%d, eccbytes=%d, erased=%d, allFF=%d\n", __FUNCTION__, 
chip->eccOobSize, chip->eccbytes, erased, allFF);}
				}
				else {
					printk("BUG: Unsupported ECC level %d\n", chip->ecclevel);
					BUG();
				}
						
				if ( erased || 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 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 < chip->eccsize/4; i++) {
						p32[i] = 0xFFFFFFFF;
					}
					ret = 0; // Success

				}
				else {
					/* Real error: Disturb read returns uncorrectable errors */
					ret = -EBADMSG; 
if (gdebug > 3 ) {printk("<-- %s: ret -EBADMSG\n", __FUNCTION__);}
				}
				done = 1;
				
				break;
			}
		case NAND_FLASH_STATUS_ERROR:
			printk(KERN_ERR "nand_cache_is_valid returns 0\n");
			ret = -EBADMSG;
			done = 1;
			break;			
			
		case NAND_TIMED_OUT:
			//Read has timed out 
			printk(KERN_ERR "nand_cache_is_valid returns 0\n");
			ret = -ETIMEDOUT;
			done = 1;
			break;

		default:
			BUG_ON(1);
			/* Should never gets here */
			ret = -EFAULT;
			done = 1;
			break; 
		}
	}

if (gdebug > 3 ) {
printk("<-- %s: offset=%s\n", __FUNCTION__, __ll_sprintf(NandMsg, offset));
print_databuf(buffer, 32);
}
	return ret;
}

#endif // CONFIG_MTD_NAND_EDU

/**
 * nand_posted_read_oob - [NAND Interface] Read the spare area
 * @param mtd		MTD data structure
 * @param oobarea	Spare area, pass NULL if not interested
 * @param offset	offset to read from or write to
 *
 * This is a little bit faster than nand_posted_read, making this command useful for improving
 * the performance of BBT management.
 * The 512B flash cache is invalidated.
 *
 * Read the cache area into buffer.  The size of the cache is mtd->writesize and is always 512B,
 * for this version of the NAND controller.
 */
static int nand_posted_read_oob(struct mtd_info* mtd, 
		unsigned char* oobarea, L_OFF_T offset, int raw)
{
	struct nand_chip* chip = mtd->priv;
	L_OFF_T sliceOffset = __ll_and32(offset, ~(mtd->eccsize - 1));
	int i, ret, done = 0;
	int retries = 5;
	
//char msg[20];

PRINTK("->%s: offset=%s\n", __FUNCTION__, __ll_sprintf(NandMsg, offset));
PRINTK("->%s: sliceOffset=%s\n", __FUNCTION__, __ll_sprintf(NandMsg, sliceOffset));
PRINTK("eccsize = %d\n", mtd->eccsize);

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

		chip->ctrl_writeAddr(chip, sliceOffset, 0);
		chip->ctrl_write(BCHP_NAND_CMD_START, OP_SPARE_AREA_READ);

		// Wait until spare area is filled up
		switch (nand_spare_is_valid(mtd, FL_READING, raw)) {
		case 1:
			if (oobarea) {
				uint32_t* p32 = (uint32_t*) oobarea;
				
				for (i = 0; i < 4; i++) {
					p32[i] = /* THT 11-30-06 */ be32_to_cpu /**/(chip->ctrl_read(BCHP_NAND_SPARE_AREA_READ_OFS_0 + (i<<2)));
				}
if (gdebug > 3) {printk("%s: offset=%08x, oob=\n", __FUNCTION__, __ll_low(sliceOffset)); print_oobbuf(oobarea, 16);}

			}
			
			ret = 0;
			done = 1;
			break;

		case -1:
			ret = -EBADMSG;
if (gdebug > 3 ) {printk("%s: ret = -EBADMSG\n", __FUNCTION__);}
			/* nand_spare_is_valid also clears the error bit, so just retry it */
			retries--;
			break;
			
		case 0:
			//Read has timed out or read found bad block. TBD: Find out which is which
			ret = -ETIMEDOUT;
			done = 1;
			break;
			
		default:
			BUG_ON(1);
			/* NOTREACHED */
			ret = -EINVAL;
			done = 1;
			break; /* Should never gets here */
		}

	}	

if (gdebug > 3 ) {
printk("<--%s: offset=%08x\n", __FUNCTION__, (uint32_t) offset); 
print_oobbuf(oobarea, 16);}
	return ret;
}

#ifdef CONFIG_MTD_NAND_EDU
/**
 * nand_posted_write - [NAND Interface] Write a buffer to the flash cache
 * Assuming nand_get_device() has been called to obtain exclusive lock
 *
 * @param mtd        MTD data structure
 * @param buffer    the databuffer to put/get data
 * @param oobarea    Spare area, pass NULL if not interested
 * @param offset    offset to write to, and must be 512B aligned
 *
 * Write to the cache area TBD 4/26/06
 */
static int nand_posted_write_cache(struct mtd_info *mtd,
        const void* buffer, const unsigned char* oobarea, L_OFF_T offset)
{
    uint32_t* p32;
    int i; 
    int ret;

    struct nand_chip* this = mtd->priv;    
    int needBBT=0;
    L_OFF_T sliceOffset = __ll_and32(offset, ~ (mtd->eccsize - 1));


#ifdef WR_BADBLOCK_SIMULATION
    unsigned long tmp = (unsigned long) offset;
    DIunion wrFailLocationOffset;
#endif

// printk("%s\n", __FUNCTION__);
// printk("EDU10\n");
    if (unlikely(__ll_isub(sliceOffset, offset))) {
        printk(KERN_ERR "%s: offset %s is not cache aligned\n", 
            __FUNCTION__, __ll_sprintf(NandMsg, offset));

        ret =  -EINVAL;
        goto out;
    }

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

// printk("EDU20\n");

    if (oobarea) {
        p32 = (uint32_t*) oobarea;
if (gdebug) {printk("%s: oob=\n", __FUNCTION__); print_oobbuf(oobarea, 16);}
    }
    else {
        // Fill with 0xFF if don't want to change OOB
        p32 = (uint32_t*) &ffchars[0];
    }

// printk("EDU40\n");
    for (i = 0; i < 4; i++) {
        this->ctrl_write(BCHP_NAND_SPARE_AREA_WRITE_OFS_0 + i*4, /* THT 11-30-06 */ cpu_to_be32 /* */(p32[i]));
    }

    PLATFORM_IOFLUSH_WAR(); // Check if this line may be taken-out

#if 0
// printk("EDUWrite\n");
// printk("EDU_write: %08x\n", (uint32) EDU_ldw);
        if(this->options & NAND_COMPLEX_OOB_WRITE)
        {
                EDU_write((uint32)ffchars, (uint32) EDU_ldw);
                // printk("EDU45: NAND_COMPLEX_OOB_WRITE... must investigate!\n"); 
        }
        else
#endif
	{
		ret = EDU_write(buffer, EDU_ldw);
		if (ret) 
			goto out;
	}
// printk("EDU50\n");

    // Wait until flash is ready
    ret = nand_select_write_is_complete(mtd, &needBBT);

#ifdef WR_BADBLOCK_SIMULATION
    if((tmp == wrBadBlockFailLocation) && (bScanBypass_badBlock == 0))
    {
        wrFailLocationOffset.s.high = 0;
        wrFailLocationOffset.s.low = wrBadBlockFailLocation;
        printk("Creating new bad block @ %s\n", __ll_sprintf(NandMsg, wrFailLocationOffset.ll, this->xor_invert_val));
        needBBT = 1;
        ret = 1;
    }
#endif 

    if (ret) 
    {
        if (!needBBT) 
        {
            ret = 0;
            goto out;
        }
        else
        { // Need BBT
#if defined (ECC_CORRECTABLE_SIMULATION) || defined(ECC_UNCORRECTABLE_SIMULATION) || defined(WR_BADBLOCK_SIMULATION)
            printk("%s: Marking bad block @%s\n", __FUNCTION__, __ll_sprintf(NandMsg, offset, this->xor_invert_val));
#endif            
            ret = this->block_markbad(mtd, offset);
            ret = -EINVAL;
            //ret = -EINVAL;
            goto out;
        }
    }

    //Write has timed out or read found bad block. TBD: Find out which is which
    printk(KERN_INFO "%s: Timeout\n", __FUNCTION__);
    ret = -ETIMEDOUT;

out:
// printk("EDU99\n");

    return ret;
}

#else // NO EDU PRESENT OR EDU DISABLED

/**
 * nand_posted_write - [NAND Interface] Write a buffer to the flash cache
 * Assuming nand_get_device() has been called to obtain exclusive lock
 *
 * @param mtd		MTD data structure
 * @param buffer	the databuffer to put/get data
 * @param oobarea	Spare area, pass NULL if not interested
 * @param offset	offset to write to, and must be 512B aligned
 *
 * Write to the cache area TBD 4/26/06
 */
static int nand_posted_write_cache(struct mtd_info *mtd,
		const void* buffer, const unsigned char* oobarea, L_OFF_T offset)
{
	struct nand_chip* chip = mtd->priv;
	L_OFF_T sliceOffset = __ll_and32(offset, ~ (mtd->eccsize - 1));
	uint32_t* p32;
	int i, needBBT=0;
	int ret;

	//char msg[20];


if (gdebug > 3 ) {
printk("--> %s: offset=%sx\n", __FUNCTION__, __ll_sprintf(NandMsg, offset));
print_databuf(buffer, 32);}

	if (unlikely(__ll_isub(sliceOffset, offset))) {
		printk(KERN_ERR "%s: offset %s is not cache aligned\n", 
			__FUNCTION__, __ll_sprintf(NandMsg, offset));

		ret =  -EINVAL;
		goto out;
	}
	chip->ctrl_writeAddr(chip, sliceOffset, 0);


	if (buffer) {
if (gdebug > 3 ) {print_databuf(buffer, 32);}
		nand_to_flash_memcpy32(chip, offset, buffer, mtd->eccsize);
	}
#if 0 
	/* Must write data when NAND_COMPLEX_OOB_WRITE */
	else if (chip->options & NAND_COMPLEX_OOB_WRITE) {
		nand_to_flash_memcpy32(chip, offset, ffchars, mtd->eccsize);
	}
#endif


//printk("30\n");
	if (oobarea) {
		p32 = (uint32_t*) oobarea;
if (gdebug > 3) {printk("%s: oob=\n", __FUNCTION__); print_oobbuf(oobarea, 16);}
	}
	else {
		// Fill with 0xFF if don't want to change OOB
		p32 = (uint32_t*) &ffchars[0];
	}

//printk("40\n");
	for (i = 0; i < 4; i++) {
		chip->ctrl_write(BCHP_NAND_SPARE_AREA_WRITE_OFS_0 + i*4, /* THT 11-30-06 */ cpu_to_be32 /* */(p32[i]));

⌨️ 快捷键说明

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