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

📄 nand_base.c

📁 this is for nand controller
💻 C
📖 第 1 页 / 共 5 页
字号:
	}

	PLATFORM_IOFLUSH_WAR();
	chip->ctrl_write(BCHP_NAND_CMD_START, OP_PROGRAM_PAGE);
//printk("50\n");

	// Wait until flash is ready
	if (nand_write_is_complete(mtd, &needBBT)) {
		if (!needBBT) {
			ret = 0;
			goto out;
		}
	
		else { // Need BBT
			printk(KERN_WARNING "%s: Marking bad block @%s\n", __FUNCTION__, __ll_sprintf(NandMsg, offset));
//printk("80 block mark bad\n");
			ret = chip->block_markbad(mtd, offset);
			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("99\n");

	return ret;
}

#endif // CONFIG_EDU SUPPORT

/**
 * nand_posted_write_oob - [NAND Interface] Write the spare area
 * @param mtd		MTD data structure
 * @param oobarea	Spare area, pass NULL if not interested.  Must be able to 
 *					hold mtd->oobsize (16) bytes.
 * @param offset	offset to write to, and must be 512B aligned
 *
 */
static int nand_posted_write_oob(struct mtd_info *mtd,
		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;


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

	if (unlikely(__ll_isub(sliceOffset, offset))) {
		printk(KERN_ERR "%s: offset %08x is not cache aligned\n", 
			__FUNCTION__, (unsigned int) offset);
	}
	
	chip->ctrl_writeAddr(chip, sliceOffset, 0);

#if 0
	/* Must write data when NAND_COMPLEX_OOB_WRITE option is set */
	if (chip->options & NAND_COMPLEX_OOB_WRITE) {
		nand_to_flash_memcpy32(chip, offset, ffchars, mtd->eccsize);
	}
#endif

	// assert oobarea here
	BUG_ON(!oobarea);	
	p32 = (uint32_t*) oobarea;
		
	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]));
	}

	PLATFORM_IOFLUSH_WAR();
#if 0
	if (chip->options & NAND_COMPLEX_OOB_WRITE) {
printk("****** Workaround, using OP_PROGRAM_PAGE instead of OP_PROGRAM_SPARE_AREA\n");
		chip->ctrl_write(BCHP_NAND_CMD_START, OP_PROGRAM_PAGE);
	}
	else 
#endif
	{
		chip->ctrl_write(BCHP_NAND_CMD_START, OP_PROGRAM_SPARE_AREA);
	}

	// Wait until flash is ready
	if (nand_write_is_complete(mtd, &needBBT)) {
		return 0;
	}
	if (needBBT){
		int ret;
		
		printk(KERN_WARNING "%s: Marking bad block @%08x\n", __FUNCTION__, (unsigned int) offset);
		ret = chip->block_markbad(mtd, offset);
		return -EINVAL;
	}

	return -ETIMEDOUT;
	
}



/**
 * nand_get_device - [GENERIC] Get chip for selected access
 * @param mtd		MTD device structure
 * @param new_state	the state which is requested
 *
 * Get the device and lock it for exclusive access
 */
static int nand_get_device(struct mtd_info *mtd, int new_state)
{
	struct nand_chip * chip = mtd->priv;

	if (chip) {
		DECLARE_WAITQUEUE(wait, current);

		/*
		 * Grab the lock and see if the device is available
		 */
		while (1) {
			spin_lock(&chip->chip_lock);

			if (chip->state == FL_READY) {
				chip->state = new_state;
				spin_unlock(&chip->chip_lock);
				break;
			}
			if (new_state == FL_PM_SUSPENDED) {
				spin_unlock(&chip->chip_lock);
				return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
			}
			set_current_state(TASK_UNINTERRUPTIBLE);
			add_wait_queue(&chip->wq, &wait);
			spin_unlock(&chip->chip_lock);
			schedule();
			remove_wait_queue(&chip->wq, &wait);
		}

		return 0;
	}
	else
		return -EINVAL;
}

static struct nand_chip* 
nand_get_device_exclusive(void)
{
	struct nand_chip * chip = (struct nand_chip*) get_nand_handle();
	struct mtd_info *mtd; 
	int ret;

	mtd = (struct mtd_info*) chip->priv;

	if (mtd) {
		ret = nand_get_device(mtd, NAND_FL_XIP);
	}
	else 
		ret = -1;
	if (0 == ret)
		return chip;
	else
		return ((struct nand_chip *) 0);
}




/**
 * nand_release_device - [GENERIC] release chip
 * @param mtd		MTD device structure
 *
 * Deselect, release chip lock and wake up anyone waiting on the device
 */
static void nand_release_device(struct mtd_info *mtd)
{
	struct nand_chip * chip = mtd->priv;

	/* Release the chip */
	spin_lock(&chip->chip_lock);
	chip->state = FL_READY;
	wake_up(&chip->wq);
	spin_unlock(&chip->chip_lock);
}






/**
 * nand_read_page - {REPLACABLE] hardware ecc based page read function
 * @mtd:	mtd info structure
 * @chip:	nand chip info structure.  The OOB buf is stored here on return
 * @buf:	buffer to store read data
 *
 * Not for syndrome calculating ecc controllers which need a special oob layout
 */
static int 
nand_read_page(struct mtd_info *mtd,
				uint8_t *outp_buf, uint8_t* outp_oob, uint32_t page)
{
	struct nand_chip *chip = (struct nand_chip*) mtd->priv;
	int winslice;
	int dataRead = 0;
	int oobRead = 0;
	int ret = 0;
	L_OFF_T offset = __ll_LeftShift32(page, chip->page_shift);

//if (1/* (int) offset <= 0x2000 /*gdebug > 3 */) {
//printk("-->%s, offset=%08x\n", __FUNCTION__, (uint32_t) offset);}

	chip->pagebuf = page;

	for (winslice = 0; winslice < chip->eccsteps && ret == 0; winslice++) {
		ret = nand_posted_read_cache(mtd, &outp_buf[dataRead], 
					outp_oob ? &outp_oob[oobRead] : NULL, 
					__ll_add32(offset, dataRead));
		
		if (ret == NAND_CORRECTABLE_ECC_ERROR) {
			(mtd->ecc_stats.corrected)++;
			ret = 0;
		} 
		else if (ret < 0) {
			printk(KERN_ERR "%s: posted read cache failed at offset=%08lx, ret=%d\n", 
				__FUNCTION__, (unsigned long) __ll_add32(offset, dataRead), ret);
			return ret;
		}
		dataRead += chip->eccsize;
		oobRead += chip->eccOobSize;
	}
	return ret;
}


/**
 * nand_read_page_oob - {REPLACABLE] hardware ecc based page read function
 * @mtd:	mtd info structure
 * @chip:	nand chip info structure.  The OOB buf is stored in the oob_poi ptr on return
 *
 * Not for syndrome calculating ecc controllers which need a special oob layout
 */
static int 
nand_read_page_oob(struct mtd_info *mtd, 
				uint8_t* outp_oob, uint32_t  page)
{
	struct nand_chip *chip = (struct nand_chip*) mtd->priv;
	int winslice;
	int dataRead = 0;
	int oobRead = 0;
	int corrected = 0; // Only update stats once per page
	int ret = 0;
	L_OFF_T offset = __ll_LeftShift32(page, chip->page_shift);


if (gdebug > 3 ) {
printk("-->%s, offset=%08x\n", __FUNCTION__, (uint32_t) offset);}

	chip->pagebuf = page;

	for (winslice = 0; winslice < chip->eccsteps && ret == 0; winslice++) {
//gdebug=4;
		ret = nand_posted_read_oob(mtd, &outp_oob[oobRead], 
					__ll_add32(offset, dataRead), 1);
//gdebug=0;
		
		if (ret == NAND_CORRECTABLE_ECC_ERROR && !corrected) {
			(mtd->ecc_stats.corrected)++;
			corrected = 1;
			ret = 0;
		} 
		else if (ret < 0) {
			printk(KERN_ERR "%s: posted read oob failed at offset=%08lx, ret=%d\n", 
				__FUNCTION__, (unsigned long) __ll_add32(offset, dataRead), ret);
			return ret;
		}
		dataRead += chip->eccsize;
		oobRead += chip->eccOobSize;
	}

if (gdebug > 3 ) {
printk("<--%s offset=%08x\n", __FUNCTION__, __ll_low(offset));
print_oobbuf(outp_oob, mtd->oobsize); }
	return ret;
}

#ifdef CONFIG_MTD_NAND_CORRECTABLE_ERR_HANDLING
static int nand_refresh_blk(struct mtd_info *mtd, loff_t from)
{
	struct nand_chip *this = mtd->priv;
	int i, j, k, numpages, ret, count = 0, nonecccount = 0;
	uint8_t *blk_buf;	/* Store one block of data (including OOB) */
	unsigned int realpage, pg_idx, oob_idx;
	struct erase_info *instr;
	//int gdebug = 1; 
	struct nand_ecclayout *oobinfo;
	uint8_t *oobptr;
	uint32_t *oobptr32, blkbegin;
	unsigned int block_size;


#if CONFIG_MTD_NAND_VERSION >= CONFIG_MTD_NAND_VERS_1_0
	this->ctrl_write(BCHP_NAND_ECC_CORR_EXT_ADDR, 0);
#endif
	this->ctrl_write(BCHP_NAND_ECC_CORR_ADDR, 0);

	DEBUG(MTD_DEBUG_LEVEL3, "Inside %s:\n", __FUNCTION__, __ll_low(from));
	printk(KERN_INFO "%s: Performing block refresh to single bit ECC error\n", __FUNCTION__);
	pg_idx = 0;
	oob_idx = mtd->writesize;
	numpages = mtd->erasesize/mtd->writesize;
	block_size = (1 << this->erase_shift);
	blkbegin = (uint32_t) (from & (~(mtd->erasesize-1)));
	realpage = (unsigned int)(blkbegin >> this->page_shift);

	blk_buf = (uint8_t *) NAND_malloc(numpages*(mtd->writesize + mtd->oobsize));
	if (unlikely(blk_buf == NULL)) {
		printk(KERN_ERR "%s: buffer allocation failed\n", __FUNCTION__);
		return -1;
	}

	memset(blk_buf, 0xff, numpages*(mtd->writesize + mtd->oobsize));

	if (unlikely(gdebug > 0)) {
		printk("---> %s: from = %08x, numpages = %d, realpage = %x\n",\
				__FUNCTION__, (uint32_t) from, numpages, realpage);
		printk("     Locking flash for read ... \n");
	}

	/* Read an entire block */
	nand_get_device(mtd, FL_READING);
	for (i = 0; i < numpages; i++) {
		ret = nand_read_page(mtd, blk_buf+pg_idx, blk_buf+oob_idx, realpage);
		if (ret < 0) {
			NAND_free(blk_buf);
			nand_release_device(mtd);
			return -1;
		}
		//printk("DEBUG -> Reading %d realpage = %x %x ret = %d oob = %x\n", i, realpage, *(blk_buf+pg_idx), ret, *(blk_buf + oob_idx));
		//print_oobbuf(blk_buf+oob_idx, mtd->oobsize);
		pg_idx += mtd->writesize + mtd->oobsize;
		oob_idx += mtd->oobsize + mtd->writesize;
		realpage++;
	}
	if (unlikely(gdebug > 0)) {
		printk("---> %s:  Read -> erase\n", __FUNCTION__);
	}
	this->state = FL_ERASING;

	/* Erase the block */
	instr = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
	if (instr == NULL) {
		printk(KERN_WARNING "kmalloc for erase_info failed\n");
		NAND_free(blk_buf);
		nand_release_device(mtd);
		return -ENOMEM;
	}
	memset(instr, 0, sizeof(struct erase_info));
	instr->mtd = mtd;
	instr->addr = blkbegin;
	instr->len = mtd->erasesize;
	if (unlikely(gdebug > 0)) {
		printk("DEBUG -> erasing %s, %x %d\n", __ll_sprintf(NandMsg, instr->addr), instr->len, this->state);
	}
	ret = nand_erase_nolock(mtd, instr, 0);
	if (ret) {
		NAND_free(blk_buf);
		kfree(instr);
		nand_release_device(mtd);
		printk(KERN_WARNING " %s Erase failed %d\n", __FUNCTION__, ret);
		return ret;
	}
	kfree(instr);

	/* Write the entire block */
	pg_idx = 0;
	oob_idx = mtd->writesize;
	realpage = (unsigned int)(blkbegin >> this->page_shift);
	if (unlikely(gdebug > 0)) {
		printk("---> %s: Erase -> write ... %d\n", __FUNCTION__, this->state);
	}
	oobinfo = this->ecclayout;
	this->state = FL_WRITING;
	for (i = 0; i < numpages; i++) {
		/* Avoid writing empty pages */
		count = 0;
		nonecccount = 0;
		oobptr = (uint8_t *) (blk_buf + oob_idx);
		oobptr32 = (uint32_t *) (blk_buf + oob_idx);
		for (j = 0; j < oobinfo->eccbytes; j++) {
			if (oobptr[oobinfo->eccpos[j]] == 0xff) { count++; }
		}
		for (k = 0; k < mtd->oobsize/4; k++) {
			if (oobptr32[k] == 0xffffffff) { nonecccount++; }
		}
		/* Skip this page if ECC is 0xff */
		if (count == j && nonecccount == k) {
			pg_idx += mtd->writesize + mtd->oobsize;
			oob_idx += mtd->oobsize + mtd->writesize;
			realpage++;
			continue;
		}
		/* Skip this page, but write the OOB */
		if (count == j && nonecccount != k) {
			ret = this->write_page_oob(mtd, blk_buf + oob_idx, realpage);
			if (ret) {
				NAND_free(blk_buf);
				nand_release_device(mtd);
				return ret;
			}
			pg_idx += mtd->writesize + mtd->oobsize;
			oob_idx += mtd->oobsize + mtd->writesize;
			realpage++;
			continue;
		}
		for (j = 0; j < oobinfo->eccbytes; j++) {
			oobptr[oobinfo->eccpos[j]] = 0xff;
		}
		ret = this->write_page(mtd, blk_buf+pg_idx, blk_buf+oob_idx, realpage);
		if (ret) {
			NAND_free(blk_buf);
			nand_release_device(mtd);
			return ret; 
		}
		pg_idx += mtd->writesize + mtd->oobsize;
		oob_idx += mtd->oobsize + mtd->writesize;
		realpage++;
	}
	nand_release_device(mtd);
	NAND_free(blk_buf);
	printk(KERN_INFO "%s: block refresh succes\n", __FUNCTION__);

	return 0;
}
#endif


/**
 * nand_do_read_ops - [Internal] Read data with ECC
 *
 * @mtd:	MTD device structure
 * @from:	offset to read from
 * @ops:		oob ops structure
 * @raw:		read raw data format when TRUE
 *
 * Internal function. Called with chip held.
 */
static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
			   

⌨️ 快捷键说明

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