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

📄 nand_base.c

📁 飞思卡尔芯片imx27下的MTD模块的驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/** * 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;	DEBUG(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;		spin_lock_init(&chip->controller->lock);		init_waitqueue_head(&chip->controller->wq);	}}/* * 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;	/* Select the device */	chip->select_chip(mtd, 0);	/* 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);	/* 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 contains non relevant data ATM */		extid = 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; maf_idx++) {		if (nand_manuf_ids[maf_idx].id == *maf_id)			break;	}	/*	 * Check, if buswidth is correct. Hardware drivers should set	 * chip correct !	 */	if (busw != (chip->options & NAND_BUSWIDTH_16)) {		printk(KERN_INFO "NAND device: Manufacturer ID:"		       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,		       dev_id, nand_manuf_ids[maf_idx].name, mtd->name);		printk(KERN_WARNING "NAND bus width %d instead %d bit\n",		       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,		       busw ? 16 : 8);		return ERR_PTR(-EINVAL);	}	/* Calculate the address shift from the page size */	chip->page_shift = ffs(mtd->writesize) - 1;	/* Convert chipsize to number of pages per chip -1. */	chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;	chip->bbt_erase_shift = chip->phys_erase_shift =		ffs(mtd->erasesize) - 1;	chip->chip_shift = ffs(chip->chipsize) - 1;	/* Set the bad block position */	chip->badblockpos = mtd->writesize > 512 ?		NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;	/* Get chip options, preserve non chip based options */	chip->options &= ~NAND_CHIPOPTIONS_MSK;	chip->options |= type->options & NAND_CHIPOPTIONS_MSK;	/*	 * Set chip as a default. Board drivers can override it, if necessary	 */	chip->options |= NAND_NO_AUTOINCR;	/* Check if chip is a not a samsung device. Do not clear the	 * options for chips which are not having an extended id.	 */	if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;	/* Check for AND chips with 4 page planes */	if (chip->options & NAND_4PAGE_ARRAY)		chip->erase_cmd = multi_erase_cmd;	else		chip->erase_cmd = single_erase_cmd;	/* Do not replace user supplied command function ! */	if (mtd->writesize > 512 && chip->cmdfunc == nand_command)		chip->cmdfunc = nand_command_lp;	/*if boot from nor flash, and the card is 2k pagesize,then need enable this bit*/	if(mtd->writesize==NAND_PAGESIZE_2KB){		NFMS |= (1 << NFMS_BIT);		}	printk(KERN_INFO "NAND device: Manufacturer ID:"	       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,	       nand_manuf_ids[maf_idx].name, type->name);	return type;}/** * nand_scan_ident - [NAND Interface] Scan for the NAND device * @mtd:	     MTD device structure * @maxchips:	     Number of chips to scan for * * This is the first phase of the normal nand_scan() function. It * reads the flash ID and sets up MTD fields accordingly. * * The mtd->owner field must be set to the module of the caller. */int nand_scan_ident(struct mtd_info *mtd, int maxchips){	int i, busw, nand_maf_id;	struct nand_chip *chip = mtd->priv;	struct nand_flash_dev *type;	/* Get buswidth to select the correct functions */	busw = chip->options & NAND_BUSWIDTH_16;	/* Set the default functions */	nand_set_defaults(chip, busw);	/* Read the flash type */	type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);	if (IS_ERR(type)) {		printk(KERN_WARNING "No NAND device found!!!\n");		chip->select_chip(mtd, -1);		return PTR_ERR(type);	}	/* Check for a chip array */	for (i = 1; i < maxchips; i++) {		chip->select_chip(mtd, i);		/* Send the command for reading device ID */		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);		/* Read manufacturer and device IDs */		if (nand_maf_id != chip->read_byte(mtd) ||		    type->id != chip->read_byte(mtd))			break;	}	if (i > 1)		printk(KERN_INFO "%d NAND chips detected\n", i);	/* Store the number of chips and calc total size for mtd */	chip->numchips = i;	mtd->size = i * chip->chipsize;	return 0;}/** * nand_scan_tail - [NAND Interface] Scan for the NAND device * @mtd:	    MTD device structure * @maxchips:	    Number of chips to scan for * * This is the second phase of the normal nand_scan() function. It * fills out all the uninitialized function pointers with the defaults * and scans for a bad block table if appropriate. */int nand_scan_tail(struct mtd_info *mtd){	int i;	struct nand_chip *chip = mtd->priv;	if (!(chip->options & NAND_OWN_BUFFERS))		chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);	if (!chip->buffers)		return -ENOMEM;	/* Preset the internal oob write buffer */	memset(chip->buffers->oobwbuf, 0xff, mtd->oobsize);	/*	 * If no default placement scheme is given, select an appropriate one	 */	if (!chip->ecc.layout) {		switch (mtd->oobsize) {		case 8:			chip->ecc.layout = &nand_oob_8;			break;		case 16:			chip->ecc.layout = &nand_oob_16;			break;		case 64:			chip->ecc.layout = &nand_oob_64;			break;		default:			printk(KERN_WARNING "No oob scheme defined for "			       "oobsize %d\n", mtd->oobsize);			BUG();		}	}	if (!chip->write_page)		chip->write_page = nand_write_page;	/*	 * check ECC mode, default to software if 3byte/512byte hardware ECC is	 * selected and we have 256 byte pagesize fallback to software ECC	 */	if (!chip->ecc.read_page_raw)		chip->ecc.read_page_raw = nand_read_page_raw;	if (!chip->ecc.write_page_raw)		chip->ecc.write_page_raw = nand_write_page_raw;	switch (chip->ecc.mode) {	case NAND_ECC_HW:		/* Use standard hwecc read page function ? */		if (!chip->ecc.read_page)			chip->ecc.read_page = nand_read_page_hwecc;		if (!chip->ecc.write_page)			chip->ecc.write_page = nand_write_page_hwecc;		if (!chip->ecc.read_oob)			chip->ecc.read_oob = nand_read_oob_std;		if (!chip->ecc.write_oob)			chip->ecc.write_oob = nand_write_oob_std;	case NAND_ECC_HW_SYNDROME:		if (!chip->ecc.calculate || !chip->ecc.correct ||		    !chip->ecc.hwctl) {			printk(KERN_WARNING "No ECC functions supplied, "			       "Hardware ECC not possible\n");			BUG();		}		/* Use standard syndrome read/write page function ? */		if (!chip->ecc.read_page)			chip->ecc.read_page = nand_read_page_syndrome;		if (!chip->ecc.write_page)			chip->ecc.write_page = nand_write_page_syndrome;		if (!chip->ecc.read_oob)			chip->ecc.read_oob = nand_read_oob_syndrome;		if (!chip->ecc.write_oob)			chip->ecc.write_oob = nand_write_oob_syndrome;		if (mtd->writesize >= chip->ecc.size)			break;		printk(KERN_WARNING "%d byte HW ECC not possible on "		       "%d byte page size, fallback to SW ECC\n",		       chip->ecc.size, mtd->writesize);		chip->ecc.mode = NAND_ECC_SOFT;	case NAND_ECC_SOFT:		chip->ecc.calculate = nand_calculate_ecc;		chip->ecc.correct = nand_correct_data;		chip->ecc.read_page = nand_read_page_swecc;		chip->ecc.write_page = nand_write_page_swecc;		chip->ecc.read_oob = nand_read_oob_std;		chip->ecc.write_oob = nand_write_oob_std;		chip->ecc.size = 256;		chip->ecc.bytes = 3;		break;	case NAND_ECC_NONE:		printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "		       "This is not recommended !!\n");		chip->ecc.read_page = nand_read_page_raw;		chip->ecc.write_page = nand_write_page_raw;		chip->ecc.read_oob = nand_read_oob_std;		chip->ecc.write_oob = nand_write_oob_std;		chip->ecc.size = mtd->writesize;		chip->ecc.bytes = 0;		break;	default:		printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",		       chip->ecc.mode);		BUG();	}	/*	 * The number of bytes available for a client to place data into	 * the out of band area	 */	chip->ecc.layout->oobavail = 0;	for (i = 0; chip->ecc.layout->oobfree[i].length; i++)		chip->ecc.layout->oobavail +=			chip->ecc.layout->oobfree[i].length;	/*	 * Set the number of read / write steps for one page depending on ECC	 * mode	 */	chip->ecc.steps = mtd->writesize / chip->ecc.size;	if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {		printk(KERN_WARNING "Invalid ecc parameters\n");		BUG();	}	chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;	/* Initialize state */	chip->state = FL_READY;	/* De-select the device */	chip->select_chip(mtd, -1);	/* Invalidate the pagebuffer reference */	chip->pagebuf = -1;	/* Fill in remaining MTD driver data */	mtd->type = MTD_NANDFLASH;	mtd->flags = MTD_CAP_NANDFLASH;	mtd->ecctype = MTD_ECC_SW;	mtd->erase = nand_erase;	mtd->point = NULL;	mtd->unpoint = NULL;	mtd->read = nand_read;	mtd->write = nand_write;	mtd->read_oob = nand_read_oob;	mtd->write_oob = nand_write_oob;	mtd->sync = nand_sync;	mtd->lock = NULL;	mtd->unlock = NULL;	mtd->suspend = nand_suspend;	mtd->resume = nand_resume;	mtd->block_isbad = nand_block_isbad;	mtd->block_markbad = nand_block_markbad;	/* propagate ecc.layout to mtd_info */	mtd->ecclayout = chip->ecc.layout;	/* Check, if we should skip the bad block table scan */	if (chip->options & NAND_SKIP_BBTSCAN)		return 0;	/* Build bad block table */	return chip->scan_bbt(mtd);}/* module_text_address() isn't exported, and it's mostly a pointless   test if this is a module _anyway_ -- they'd have to try _really_ hard   to call us from in-kernel code if the core NAND support is modular. */#ifdef MODULE#define caller_is_module() (1)#else#define caller_is_module() \	module_text_address((unsigned long)__builtin_return_address(0))#endif/** * nand_scan - [NAND Interface] Scan for the NAND device * @mtd:	MTD device structure * @maxchips:	Number of chips to scan for * * This fills out all the uninitialized function pointers * with the defaults. * The flash ID is read and the mtd/

⌨️ 快捷键说明

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