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

📄 onenand_base.c

📁 项目源码察看工具---- MTD工具
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* Exit OTP access mode */	this->command(mtd, ONENAND_CMD_RESET, 0, 0);	this->wait(mtd, FL_RESETING);	return ret;}/** * onenand_otp_walk - [DEFAULT] Handle OTP operation * @param mtd		MTD device structure * @param from		The offset to read/write * @param len		number of bytes to read/write * @param retlen	pointer to variable to store the number of read bytes * @param buf		the databuffer to put/get data * @param action	do given action * @param mode		specify user and factory * * Handle OTP operation. */static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,			size_t *retlen, u_char *buf,			otp_op_t action, int mode){	struct onenand_chip *this = mtd->priv;	int otp_pages;	int density;	int ret = 0;	*retlen = 0;	density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;	if (density < ONENAND_DEVICE_DENSITY_512Mb)		otp_pages = 20;	else		otp_pages = 10;	if (mode == MTD_OTP_FACTORY) {		from += mtd->oobblock * otp_pages;		otp_pages = 64 - otp_pages;	}	/* Check User/Factory boundary */	if (((mtd->oobblock * otp_pages) - (from + len)) < 0)		return 0;	while (len > 0 && otp_pages > 0) {		if (!action) {	/* OTP Info functions */			struct otp_info *otpinfo;			len -= sizeof(struct otp_info);			if (len <= 0)				return -ENOSPC;			otpinfo = (struct otp_info *) buf;			otpinfo->start = from;			otpinfo->length = mtd->oobblock;			otpinfo->locked = 0;			from += mtd->oobblock;			buf += sizeof(struct otp_info);			*retlen += sizeof(struct otp_info);		} else {			size_t tmp_retlen;			int size = len;			ret = action(mtd, from, len, &tmp_retlen, buf);			buf += size;			len -= size;			*retlen += size;			if (ret < 0)				return ret;		}		otp_pages--;	}	return 0;}/** * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info * @param mtd		MTD device structure * @param buf		the databuffer to put/get data * @param len		number of bytes to read * * Read factory OTP info. */static int onenand_get_fact_prot_info(struct mtd_info *mtd,			struct otp_info *buf, size_t len){	size_t retlen;	int ret;	ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY);	return ret ? : retlen;}/** * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area * @param mtd		MTD device structure * @param from		The offset to read * @param len		number of bytes to read * @param retlen	pointer to variable to store the number of read bytes * @param buf		the databuffer to put/get data * * Read factory OTP area. */static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,			size_t len, size_t *retlen, u_char *buf){	return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY);}/** * onenand_get_user_prot_info - [MTD Interface] Read user OTP info * @param mtd		MTD device structure * @param buf		the databuffer to put/get data * @param len		number of bytes to read * * Read user OTP info. */static int onenand_get_user_prot_info(struct mtd_info *mtd,			struct otp_info *buf, size_t len){	size_t retlen;	int ret;	ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER);	return ret ? : retlen;}/** * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area * @param mtd		MTD device structure * @param from		The offset to read * @param len		number of bytes to read * @param retlen	pointer to variable to store the number of read bytes * @param buf		the databuffer to put/get data * * Read user OTP area. */static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from,			size_t len, size_t *retlen, u_char *buf){	return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER);}/** * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area * @param mtd		MTD device structure * @param from		The offset to write * @param len		number of bytes to write * @param retlen	pointer to variable to store the number of write bytes * @param buf		the databuffer to put/get data * * Write user OTP area. */static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,			size_t len, size_t *retlen, u_char *buf){	return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER);}/** * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area * @param mtd		MTD device structure * @param from		The offset to lock * @param len		number of bytes to unlock * * Write lock mark on spare area in page 0 in OTP block  */static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,			size_t len){	unsigned char oob_buf[64];	size_t retlen;	int ret;	memset(oob_buf, 0xff, mtd->oobsize);	/*	 * Note: OTP lock operation	 *       OTP block : 0xXXFC	 *       1st block : 0xXXF3 (If chip support)	 *       Both      : 0xXXF0 (If chip support)	 */	oob_buf[ONENAND_OTP_LOCK_OFFSET] = 0xFC;	/*	 * Write lock mark to 8th word of sector0 of page0 of the spare0.	 * We write 16 bytes spare area instead of 2 bytes.	 */	from = 0;	len = 16;	ret = onenand_otp_walk(mtd, from, len, &retlen, oob_buf, do_otp_lock, MTD_OTP_USER);	return ret ? : retlen;}#endif	/* CONFIG_MTD_ONENAND_OTP *//** * onenand_print_device_info - Print device ID * @param device        device ID * * Print device ID */static void onenand_print_device_info(int device){        int vcc, demuxed, ddp, density;        vcc = device & ONENAND_DEVICE_VCC_MASK;        demuxed = device & ONENAND_DEVICE_IS_DEMUX;        ddp = device & ONENAND_DEVICE_IS_DDP;        density = device >> ONENAND_DEVICE_DENSITY_SHIFT;        printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",                demuxed ? "" : "Muxed ",                ddp ? "(DDP)" : "",                (16 << density),                vcc ? "2.65/3.3" : "1.8",                device);}static const struct onenand_manufacturers onenand_manuf_ids[] = {        {ONENAND_MFR_SAMSUNG, "Samsung"},};/** * onenand_check_maf - Check manufacturer ID * @param manuf         manufacturer ID * * Check manufacturer ID */static int onenand_check_maf(int manuf){	int size = ARRAY_SIZE(onenand_manuf_ids);	char *name;        int i;        for (i = 0; i < size; i++)                if (manuf == onenand_manuf_ids[i].id)                        break;	if (i < size)		name = onenand_manuf_ids[i].name;	else		name = "Unknown";        printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);        return (i == size);}/** * onenand_probe - [OneNAND Interface] Probe the OneNAND device * @param mtd		MTD device structure * * OneNAND detection method: *   Compare the the values from command with ones from register */static int onenand_probe(struct mtd_info *mtd){	struct onenand_chip *this = mtd->priv;	int bram_maf_id, bram_dev_id, maf_id, dev_id;	int version_id;	int density;	/* Send the command for reading device ID from BootRAM */	this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);	/* Read manufacturer and device IDs from BootRAM */	bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);	bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);	/* Check manufacturer ID */	if (onenand_check_maf(bram_maf_id))		return -ENXIO;	/* Reset OneNAND to read default register values */	this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);	/* Read manufacturer and device IDs from Register */	maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);	dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);	/* Check OneNAND device */	if (maf_id != bram_maf_id || dev_id != bram_dev_id)		return -ENXIO;	/* Flash device information */	onenand_print_device_info(dev_id);	this->device_id = dev_id;	density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;	this->chipsize = (16 << density) << 20;	/* Set density mask. it is used for DDP */	this->density_mask = (1 << (density + 6));	/* OneNAND page size & block size */	/* The data buffer size is equal to page size */	mtd->oobblock = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);	mtd->oobsize = mtd->oobblock >> 5;	/* Pagers per block is always 64 in OneNAND */	mtd->erasesize = mtd->oobblock << 6;	this->erase_shift = ffs(mtd->erasesize) - 1;	this->page_shift = ffs(mtd->oobblock) - 1;	this->ppb_shift = (this->erase_shift - this->page_shift);	this->page_mask = (mtd->erasesize / mtd->oobblock) - 1;	/* REVIST: Multichip handling */	mtd->size = this->chipsize;	/* Version ID */	version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);	printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id);	/* Lock scheme */	if (density <= ONENAND_DEVICE_DENSITY_512Mb &&	    !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) {		printk(KERN_INFO "Lock scheme is Continues Lock\n");		this->options |= ONENAND_CONT_LOCK;	}	return 0;}/** * onenand_suspend - [MTD Interface] Suspend the OneNAND flash * @param mtd		MTD device structure */static int onenand_suspend(struct mtd_info *mtd){	return onenand_get_device(mtd, FL_PM_SUSPENDED);}/** * onenand_resume - [MTD Interface] Resume the OneNAND flash * @param mtd		MTD device structure */static void onenand_resume(struct mtd_info *mtd){	struct onenand_chip *this = mtd->priv;	if (this->state == FL_PM_SUSPENDED)		onenand_release_device(mtd);	else		printk(KERN_ERR "resume() called for the chip which is not"				"in suspended state\n");}/** * onenand_scan - [OneNAND Interface] Scan for the OneNAND device * @param mtd		MTD device structure * @param maxchips	Number of chips to scan for * * This fills out all the not initialized function pointers * with the defaults. * The flash ID is read and the mtd/chip structures are * filled with the appropriate values. */int onenand_scan(struct mtd_info *mtd, int maxchips){	struct onenand_chip *this = mtd->priv;	if (!this->read_word)		this->read_word = onenand_readw;	if (!this->write_word)		this->write_word = onenand_writew;	if (!this->command)		this->command = onenand_command;	if (!this->wait)		this->wait = onenand_wait;	if (!this->read_bufferram)		this->read_bufferram = onenand_read_bufferram;	if (!this->write_bufferram)		this->write_bufferram = onenand_write_bufferram;	if (!this->block_markbad)		this->block_markbad = onenand_default_block_markbad;	if (!this->scan_bbt)		this->scan_bbt = onenand_default_bbt;	if (onenand_probe(mtd))		return -ENXIO;	/* Set Sync. Burst Read after probing */	if (this->mmcontrol) {		printk(KERN_INFO "OneNAND Sync. Burst Read support\n");		this->read_bufferram = onenand_sync_read_bufferram;	}	/* Allocate buffers, if necessary */	if (!this->page_buf) {		size_t len;		len = mtd->oobblock + mtd->oobsize;		this->page_buf = kmalloc(len, GFP_KERNEL);		if (!this->page_buf) {			printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");			return -ENOMEM;		}		this->options |= ONENAND_PAGEBUF_ALLOC;	}	this->state = FL_READY;	init_waitqueue_head(&this->wq);	spin_lock_init(&this->chip_lock);	switch (mtd->oobsize) {	case 64:		this->autooob = &onenand_oob_64;		break;	case 32:		this->autooob = &onenand_oob_32;		break;	default:		printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n",			mtd->oobsize);		/* To prevent kernel oops */		this->autooob = &onenand_oob_32;		break;	}	memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));	/* Fill in remaining MTD driver data */	mtd->type = MTD_NANDFLASH;	mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;	mtd->ecctype = MTD_ECC_SW;	mtd->erase = onenand_erase;	mtd->point = NULL;	mtd->unpoint = NULL;	mtd->read = onenand_read;	mtd->write = onenand_write;	mtd->read_ecc = onenand_read_ecc;	mtd->write_ecc = onenand_write_ecc;	mtd->read_oob = onenand_read_oob;	mtd->write_oob = onenand_write_oob;#ifdef CONFIG_MTD_ONENAND_OTP	mtd->get_fact_prot_info = onenand_get_fact_prot_info;	mtd->read_fact_prot_reg = onenand_read_fact_prot_reg;	mtd->get_user_prot_info = onenand_get_user_prot_info;	mtd->read_user_prot_reg = onenand_read_user_prot_reg;	mtd->write_user_prot_reg = onenand_write_user_prot_reg;	mtd->lock_user_prot_reg = onenand_lock_user_prot_reg;#endif	mtd->readv = NULL;	mtd->readv_ecc = NULL;	mtd->writev = onenand_writev;	mtd->writev_ecc = onenand_writev_ecc;	mtd->sync = onenand_sync;	mtd->lock = NULL;	mtd->unlock = onenand_unlock;	mtd->suspend = onenand_suspend;	mtd->resume = onenand_resume;	mtd->block_isbad = onenand_block_isbad;	mtd->block_markbad = onenand_block_markbad;	mtd->owner = THIS_MODULE;	/* Unlock whole block */	mtd->unlock(mtd, 0x0, this->chipsize);	return this->scan_bbt(mtd);}/** * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device * @param mtd		MTD device structure */void onenand_release(struct mtd_info *mtd){	struct onenand_chip *this = mtd->priv;#ifdef CONFIG_MTD_PARTITIONS	/* Deregister partitions */	del_mtd_partitions (mtd);#endif	/* Deregister the device */	del_mtd_device (mtd);	/* Free bad block table memory, if allocated */	if (this->bbm)		kfree(this->bbm);	/* Buffer allocated by onenand_scan */	if (this->options & ONENAND_PAGEBUF_ALLOC)		kfree(this->page_buf);}EXPORT_SYMBOL_GPL(onenand_scan);EXPORT_SYMBOL_GPL(onenand_release);MODULE_LICENSE("GPL");MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");MODULE_DESCRIPTION("Generic OneNAND flash driver code");

⌨️ 快捷键说明

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