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

📄 nand_base.c

📁 uboot200903最新版本的通用uboot
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Invalidate the page cache, if we write to the cached page */	if (page == chip->pagebuf)		chip->pagebuf = -1;	memset(chip->oob_poi, 0xff, mtd->oobsize);	nand_fill_oob(chip, ops->oobbuf, ops);	status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);	memset(chip->oob_poi, 0xff, mtd->oobsize);	if (status)		return status;	ops->oobretlen = ops->ooblen;	return 0;}/** * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band * @mtd:	MTD device structure * @to:		offset to write to * @ops:	oob operation description structure */static int nand_write_oob(struct mtd_info *mtd, loff_t to,			  struct mtd_oob_ops *ops){	struct nand_chip *chip = mtd->priv;	int ret = -ENOTSUPP;	ops->retlen = 0;	/* Do not allow writes past end of device */	if (ops->datbuf && (to + ops->len) > mtd->size) {		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: "		          "Attempt read beyond end of device\n");		return -EINVAL;	}	nand_get_device(chip, mtd, FL_WRITING);	switch(ops->mode) {	case MTD_OOB_PLACE:	case MTD_OOB_AUTO:	case MTD_OOB_RAW:		break;	default:		goto out;	}	if (!ops->datbuf)		ret = nand_do_write_oob(mtd, to, ops);	else		ret = nand_do_write_ops(mtd, to, ops); out:	nand_release_device(mtd);	return ret;}/** * single_erease_cmd - [GENERIC] NAND standard block erase command function * @mtd:	MTD device structure * @page:	the page address of the block which will be erased * * Standard erase command for NAND chips */static void single_erase_cmd(struct mtd_info *mtd, int page){	struct nand_chip *chip = mtd->priv;	/* Send commands to erase a block */	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);}/** * multi_erease_cmd - [GENERIC] AND specific block erase command function * @mtd:	MTD device structure * @page:	the page address of the block which will be erased * * AND multi block erase command function * Erase 4 consecutive blocks */static void multi_erase_cmd(struct mtd_info *mtd, int page){	struct nand_chip *chip = mtd->priv;	/* Send commands to erase a block */	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);}/** * nand_erase - [MTD Interface] erase block(s) * @mtd:	MTD device structure * @instr:	erase instruction * * Erase one ore more blocks */static int nand_erase(struct mtd_info *mtd, struct erase_info *instr){	return nand_erase_nand(mtd, instr, 0);}#define BBT_PAGE_MASK	0xffffff3f/** * nand_erase_nand - [Internal] erase block(s) * @mtd:	MTD device structure * @instr:	erase instruction * @allowbbt:	allow erasing the bbt area * * Erase one ore more blocks */int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,		    int allowbbt){	int page, len, status, pages_per_block, ret, chipnr;	struct nand_chip *chip = mtd->priv;	int rewrite_bbt[CONFIG_SYS_NAND_MAX_CHIPS]={0};	unsigned int bbt_masked_page = 0xffffffff;	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",	          (unsigned int) instr->addr, (unsigned int) instr->len);	/* Start address must align on block boundary */	if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");		return -EINVAL;	}	/* Length must align on block boundary */	if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {		MTDDEBUG (MTD_DEBUG_LEVEL0,		          "nand_erase: Length not block aligned\n");		return -EINVAL;	}	/* Do not allow erase past end of device */	if ((instr->len + instr->addr) > mtd->size) {		MTDDEBUG (MTD_DEBUG_LEVEL0,		          "nand_erase: Erase past end of device\n");		return -EINVAL;	}	instr->fail_addr = 0xffffffff;	/* Grab the lock and see if the device is available */	nand_get_device(chip, mtd, FL_ERASING);	/* Shift to get first page */	page = (int)(instr->addr >> chip->page_shift);	chipnr = (int)(instr->addr >> chip->chip_shift);	/* Calculate pages in each block */	pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);	/* Select the NAND device */	chip->select_chip(mtd, chipnr);	/* Check, if it is write protected */	if (nand_check_wp(mtd)) {		MTDDEBUG (MTD_DEBUG_LEVEL0,		          "nand_erase: Device is write protected!!!\n");		instr->state = MTD_ERASE_FAILED;		goto erase_exit;	}	/*	 * If BBT requires refresh, set the BBT page mask to see if the BBT	 * should be rewritten. Otherwise the mask is set to 0xffffffff which	 * can not be matched. This is also done when the bbt is actually	 * erased to avoid recusrsive updates	 */	if (chip->options & BBT_AUTO_REFRESH && !allowbbt)		bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;	/* Loop through the pages */	len = instr->len;	instr->state = MTD_ERASING;	while (len) {		/*		 * heck if we have a bad block, we do not erase bad blocks !		 */		if (nand_block_checkbad(mtd, ((loff_t) page) <<					chip->page_shift, 0, allowbbt)) {			printk(KERN_WARNING "nand_erase: attempt to erase a "			       "bad block at page 0x%08x\n", page);			instr->state = MTD_ERASE_FAILED;			goto erase_exit;		}		/*		 * Invalidate the page cache, if we erase the block which		 * contains the current cached page		 */		if (page <= chip->pagebuf && chip->pagebuf <		    (page + pages_per_block))			chip->pagebuf = -1;		chip->erase_cmd(mtd, page & chip->pagemask);		status = chip->waitfunc(mtd, chip);		/*		 * See if operation failed and additional status checks are		 * available		 */		if ((status & NAND_STATUS_FAIL) && (chip->errstat))			status = chip->errstat(mtd, chip, FL_ERASING,					       status, page);		/* See if block erase succeeded */		if (status & NAND_STATUS_FAIL) {			MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: "			          "Failed erase, page 0x%08x\n", page);			instr->state = MTD_ERASE_FAILED;			instr->fail_addr = (page << chip->page_shift);			goto erase_exit;		}		/*		 * If BBT requires refresh, set the BBT rewrite flag to the		 * page being erased		 */		if (bbt_masked_page != 0xffffffff &&		    (page & BBT_PAGE_MASK) == bbt_masked_page)			    rewrite_bbt[chipnr] = (page << chip->page_shift);		/* Increment page address and decrement length */		len -= (1 << chip->phys_erase_shift);		page += pages_per_block;		/* Check, if we cross a chip boundary */		if (len && !(page & chip->pagemask)) {			chipnr++;			chip->select_chip(mtd, -1);			chip->select_chip(mtd, chipnr);			/*			 * If BBT requires refresh and BBT-PERCHIP, set the BBT			 * page mask to see if this BBT should be rewritten			 */			if (bbt_masked_page != 0xffffffff &&			    (chip->bbt_td->options & NAND_BBT_PERCHIP))				bbt_masked_page = chip->bbt_td->pages[chipnr] &					BBT_PAGE_MASK;		}	}	instr->state = MTD_ERASE_DONE; erase_exit:	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;	/* Deselect and wake up anyone waiting on the device */	nand_release_device(mtd);	/* Do call back function */	if (!ret)		mtd_erase_callback(instr);	/*	 * If BBT requires refresh and erase was successful, rewrite any	 * selected bad block tables	 */	if (bbt_masked_page == 0xffffffff || ret)		return ret;	for (chipnr = 0; chipnr < chip->numchips; chipnr++) {		if (!rewrite_bbt[chipnr])			continue;		/* update the BBT for chip */		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "		          "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],		          chip->bbt_td->pages[chipnr]);		nand_update_bbt(mtd, rewrite_bbt[chipnr]);	}	/* Return more or less happy */	return ret;}/** * nand_sync - [MTD Interface] sync * @mtd:	MTD device structure * * Sync is actually a wait for chip ready function */static void nand_sync(struct mtd_info *mtd){	struct nand_chip *chip = mtd->priv;	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");	/* Grab the lock and see if the device is available */	nand_get_device(chip, mtd, FL_SYNCING);	/* Release it and go back */	nand_release_device(mtd);}/** * nand_block_isbad - [MTD Interface] Check if block at offset is bad * @mtd:	MTD device structure * @offs:	offset relative to mtd start */static int nand_block_isbad(struct mtd_info *mtd, loff_t offs){	/* Check for invalid offset */	if (offs > mtd->size)		return -EINVAL;	return nand_block_checkbad(mtd, offs, 1, 0);}/** * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad * @mtd:	MTD device structure * @ofs:	offset relative to mtd start */static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs){	struct nand_chip *chip = mtd->priv;	int ret;	if ((ret = nand_block_isbad(mtd, ofs))) {		/* If it was bad already, return success and do nothing. */		if (ret > 0)			return 0;		return ret;	}	return chip->block_markbad(mtd, ofs);}/** * nand_suspend - [MTD Interface] Suspend the NAND flash * @mtd:	MTD device structure */static int nand_suspend(struct mtd_info *mtd){	struct nand_chip *chip = mtd->priv;	return nand_get_device(chip, mtd, FL_PM_SUSPENDED);}/** * nand_resume - [MTD Interface] Resume the NAND flash * @mtd:	MTD device structure */static void nand_resume(struct mtd_info *mtd){	struct nand_chip *chip = mtd->priv;	if (chip->state == FL_PM_SUSPENDED)		nand_release_device(mtd);	else		printk(KERN_ERR "nand_resume() called for a chip which is not "		       "in suspended state\n");}/* * Set default functions */static void nand_set_defaults(struct nand_chip *chip, int busw){	/* check for proper chip_delay setup, set 20us if not */	if (!chip->chip_delay)		chip->chip_delay = 20;	/* check, if a user supplied command function given */	if (chip->cmdfunc == NULL)		chip->cmdfunc = nand_command;	/* check, if a user supplied wait function given */	if (chip->waitfunc == NULL)		chip->waitfunc = nand_wait;	if (!chip->select_chip)		chip->select_chip = nand_select_chip;	if (!chip->read_byte)		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;	if (!chip->read_word)		chip->read_word = nand_read_word;	if (!chip->block_bad)		chip->block_bad = nand_block_bad;	if (!chip->block_markbad)		chip->block_markbad = nand_default_block_markbad;	if (!chip->write_buf)		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;	if (!chip->read_buf)		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;	if (!chip->verify_buf)		chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;	if (!chip->scan_bbt)		chip->scan_bbt = nand_default_bbt;	if (!chip->controller) {		chip->controller = &chip->hwcontrol;		/* XXX U-BOOT XXX */#if 0		spin_lock_init(&chip->controller->lock);		init_waitqueue_head(&chip->controller->wq);#endif	}}/* * Get the flash and manufacturer id and lookup if the type is supported */static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,						  struct nand_chip *chip,						  int busw, int *maf_id){	struct nand_flash_dev *type = NULL;	int i, dev_id, maf_idx;	int tmp_id, tmp_manf;	/* Select the device */	chip->select_chip(mtd, 0);	/*	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)	 * after power-up	 */	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);	/* Send the command for reading device ID */	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);	/* Read manufacturer and device IDs */	*maf_id = chip->read_byte(mtd);	dev_id = chip->read_byte(mtd);	/* Try again to make sure, as some systems the bus-hold or other	 * interface concerns can cause random data which looks like a	 * possibly credible NAND flash to appear. If the two results do	 * not match, ignore the device completely.	 */	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);	/* Read manufacturer and device IDs */	tmp_manf = chip->read_byte(mtd);	tmp_id = chip->read_byte(mtd);	if (tmp_manf != *maf_id || tmp_id != dev_id) {		printk(KERN_INFO "%s: second ID read did not match "		       "%02x,%02x against %02x,%02x\n", __func__,		       *maf_id, dev_id, tmp_manf, tmp_id);		return ERR_PTR(-ENODEV);	}	/* Lookup the flash id */	for (i = 0; nand_flash_ids[i].name != NULL; i++) {		if (dev_id == nand_flash_ids[i].id) {			type =  &nand_flash_ids[i];			break;		}	}	if (!type)		return ERR_PTR(-ENODEV);	if (!mtd->name)		mtd->name = type->name;	chip->chipsize = type->chipsize << 20;	/* Newer devices have all the information in additional id bytes */	if (!type->pagesize) {		int extid;		/* The 3rd id byte holds MLC / multichip data */		chip->cellinfo = chip->read_byte(mtd);		/* The 4th id byte is the important one */		extid = chip->read_byte(mtd);		/* Calc pagesize */		mtd->writesize = 1024 << (extid & 0x3);		extid >>= 2;		/* Calc oobsize */		mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);		extid >>= 2;		/* Calc blocksize. Blocksize is multiples of 64KiB */		mtd->erasesize = (64 * 1024) << (extid & 0x03);		extid >>= 2;		/* Get buswidth information */		busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;	} else {		/*		 * Old devices have chip data hardcoded in the device id table		 */		mtd->erasesize = type->erasesize;		mtd->writesize = type->pagesize;		mtd->oobsize = mtd->writesize / 32;		busw = type->options & NAND_BUSWIDTH_16;	}	/* Try to identify manufacturer */	for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; m

⌨️ 快捷键说明

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