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

📄 mxc_nand.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
			m = min(n, m) & ~3;			DEBUG(MTD_DEBUG_LEVEL3,			      "%s:%d: n = %d, m = %d, i = %d, col = %d\n",			      __func__,  __LINE__, n, m, i, col);			memcpy(p, &buf[i], m);			col += m;			i += m;			n -= m;		}	}	/* Update saved column address */	host->col_addr = col;}/* Read the data buffer from the NAND Flash. To read the data from NAND * Flash first the data output cycle is initiated by the NFC, which copies * the data to RAMbuffer. This data of length len is then copied to buffer buf. */static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len){	struct nand_chip *nand_chip = mtd->priv;	struct mxc_nand_host *host = nand_chip->priv;	int n, col, i = 0;	DEBUG(MTD_DEBUG_LEVEL3,	      "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len);	col = host->col_addr;	/* Adjust saved column address */	if (col < mtd->writesize && host->spare_only)		col += mtd->writesize;	n = mtd->writesize + mtd->oobsize - col;	n = min(len, n);	while (n) {		void __iomem *p;		if (col < mtd->writesize)			p = host->regs + MAIN_AREA0 + (col & ~3);		else			p = host->regs + SPARE_AREA0 -					mtd->writesize + (col & ~3);		if (((col | (int)&buf[i]) & 3) || n < 16) {			uint32_t data;			data = readl(p);			switch (col & 3) {			case 0:				if (n) {					buf[i++] = (uint8_t) (data);					n--;					col++;				}			case 1:				if (n) {					buf[i++] = (uint8_t) (data >> 8);					n--;					col++;				}			case 2:				if (n) {					buf[i++] = (uint8_t) (data >> 16);					n--;					col++;				}			case 3:				if (n) {					buf[i++] = (uint8_t) (data >> 24);					n--;					col++;				}			}		} else {			int m = mtd->writesize - col;			if (col >= mtd->writesize)				m += mtd->oobsize;			m = min(n, m) & ~3;			memcpy(&buf[i], p, m);			col += m;			i += m;			n -= m;		}	}	/* Update saved column address */	host->col_addr = col;}/* Used by the upper layer to verify the data in NAND Flash * with the data in the buf. */static int mxc_nand_verify_buf(struct mtd_info *mtd,				const u_char *buf, int len){	return -EFAULT;}/* This function is used by upper layer for select and * deselect of the NAND chip */static void mxc_nand_select_chip(struct mtd_info *mtd, int chip){	struct nand_chip *nand_chip = mtd->priv;	struct mxc_nand_host *host = nand_chip->priv;#ifdef CONFIG_MTD_NAND_MXC_FORCE_CE	if (chip > 0) {		DEBUG(MTD_DEBUG_LEVEL0,		      "ERROR:  Illegal chip select (chip = %d)\n", chip);		return;	}	if (chip == -1) {		writew(readw(host->regs + NFC_CONFIG1) & ~NFC_CE,				host->regs + NFC_CONFIG1);		return;	}	writew(readw(host->regs + NFC_CONFIG1) | NFC_CE,			host->regs + NFC_CONFIG1);#endif	switch (chip) {	case -1:		/* Disable the NFC clock */		if (host->clk_act) {			clk_disable(host->clk);			host->clk_act = 0;		}		break;	case 0:		/* Enable the NFC clock */		if (!host->clk_act) {			clk_enable(host->clk);			host->clk_act = 1;		}		break;	default:		break;	}}/* Used by the upper layer to write command to NAND Flash for * different operations to be carried out on NAND Flash */static void mxc_nand_command(struct mtd_info *mtd, unsigned command,				int column, int page_addr){	struct nand_chip *nand_chip = mtd->priv;	struct mxc_nand_host *host = nand_chip->priv;	int useirq = true;	DEBUG(MTD_DEBUG_LEVEL3,	      "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",	      command, column, page_addr);	/* Reset command state information */	host->status_request = false;	/* Command pre-processing step */	switch (command) {	case NAND_CMD_STATUS:		host->col_addr = 0;		host->status_request = true;		break;	case NAND_CMD_READ0:		host->col_addr = column;		host->spare_only = false;		useirq = false;		break;	case NAND_CMD_READOOB:		host->col_addr = column;		host->spare_only = true;		useirq = false;		if (host->pagesize_2k)			command = NAND_CMD_READ0; /* only READ0 is valid */		break;	case NAND_CMD_SEQIN:		if (column >= mtd->writesize) {			/*			 * FIXME: before send SEQIN command for write OOB,			 * We must read one page out.			 * For K9F1GXX has no READ1 command to set current HW			 * pointer to spare area, we must write the whole page			 * including OOB together.			 */			if (host->pagesize_2k)				/* call ourself to read a page */				mxc_nand_command(mtd, NAND_CMD_READ0, 0,						page_addr);			host->col_addr = column - mtd->writesize;			host->spare_only = true;			/* Set program pointer to spare region */			if (!host->pagesize_2k)				send_cmd(host, NAND_CMD_READOOB, false);		} else {			host->spare_only = false;			host->col_addr = column;			/* Set program pointer to page start */			if (!host->pagesize_2k)				send_cmd(host, NAND_CMD_READ0, false);		}		useirq = false;		break;	case NAND_CMD_PAGEPROG:		send_prog_page(host, 0, host->spare_only);		if (host->pagesize_2k) {			/* data in 4 areas datas */			send_prog_page(host, 1, host->spare_only);			send_prog_page(host, 2, host->spare_only);			send_prog_page(host, 3, host->spare_only);		}		break;	case NAND_CMD_ERASE1:		useirq = false;		break;	}	/* Write out the command to the device. */	send_cmd(host, command, useirq);	/* Write out column address, if necessary */	if (column != -1) {		/*		 * MXC NANDFC can only perform full page+spare or		 * spare-only read/write.  When the upper layers		 * layers perform a read/write buf operation,		 * we will used the saved column adress to index into		 * the full page.		 */		send_addr(host, 0, page_addr == -1);		if (host->pagesize_2k)			/* another col addr cycle for 2k page */			send_addr(host, 0, false);	}	/* Write out page address, if necessary */	if (page_addr != -1) {		/* paddr_0 - p_addr_7 */		send_addr(host, (page_addr & 0xff), false);		if (host->pagesize_2k) {			send_addr(host, (page_addr >> 8) & 0xFF, false);			if (mtd->size >= 0x40000000)				send_addr(host, (page_addr >> 16) & 0xff, true);		} else {			/* One more address cycle for higher density devices */			if (mtd->size >= 0x4000000) {				/* paddr_8 - paddr_15 */				send_addr(host, (page_addr >> 8) & 0xff, false);				send_addr(host, (page_addr >> 16) & 0xff, true);			} else				/* paddr_8 - paddr_15 */				send_addr(host, (page_addr >> 8) & 0xff, true);		}	}	/* Command post-processing step */	switch (command) {	case NAND_CMD_RESET:		break;	case NAND_CMD_READOOB:	case NAND_CMD_READ0:		if (host->pagesize_2k) {			/* send read confirm command */			send_cmd(host, NAND_CMD_READSTART, true);			/* read for each AREA */			send_read_page(host, 0, host->spare_only);			send_read_page(host, 1, host->spare_only);			send_read_page(host, 2, host->spare_only);			send_read_page(host, 3, host->spare_only);		} else			send_read_page(host, 0, host->spare_only);		break;	case NAND_CMD_READID:		send_read_id(host);		break;	case NAND_CMD_PAGEPROG:		break;	case NAND_CMD_STATUS:		break;	case NAND_CMD_ERASE2:		break;	}}static int __init mxcnd_probe(struct platform_device *pdev){	struct nand_chip *this;	struct mtd_info *mtd;	struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;	struct mxc_nand_host *host;	struct resource *res;	uint16_t tmp;	int err = 0, nr_parts = 0;	/* Allocate memory for MTD device structure and private data */	host = kzalloc(sizeof(struct mxc_nand_host), GFP_KERNEL);	if (!host)		return -ENOMEM;	host->dev = &pdev->dev;	/* structures must be linked */	this = &host->nand;	mtd = &host->mtd;	mtd->priv = this;	mtd->owner = THIS_MODULE;	/* 50 us command delay time */	this->chip_delay = 5;	this->priv = host;	this->dev_ready = mxc_nand_dev_ready;	this->cmdfunc = mxc_nand_command;	this->select_chip = mxc_nand_select_chip;	this->read_byte = mxc_nand_read_byte;	this->read_word = mxc_nand_read_word;	this->write_buf = mxc_nand_write_buf;	this->read_buf = mxc_nand_read_buf;	this->verify_buf = mxc_nand_verify_buf;	host->clk = clk_get(&pdev->dev, "nfc_clk");	if (IS_ERR(host->clk))		goto eclk;	clk_enable(host->clk);	host->clk_act = 1;	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	if (!res) {		err = -ENODEV;		goto eres;	}	host->regs = ioremap(res->start, res->end - res->start + 1);	if (!host->regs) {		err = -EIO;		goto eres;	}	tmp = readw(host->regs + NFC_CONFIG1);	tmp |= NFC_INT_MSK;	writew(tmp, host->regs + NFC_CONFIG1);	init_waitqueue_head(&host->irq_waitq);	host->irq = platform_get_irq(pdev, 0);	err = request_irq(host->irq, mxc_nfc_irq, 0, "mxc_nd", host);	if (err)		goto eirq;	if (pdata->hw_ecc) {		this->ecc.calculate = mxc_nand_calculate_ecc;		this->ecc.hwctl = mxc_nand_enable_hwecc;		this->ecc.correct = mxc_nand_correct_data;		this->ecc.mode = NAND_ECC_HW;		this->ecc.size = 512;		this->ecc.bytes = 3;		this->ecc.layout = &nand_hw_eccoob_8;		tmp = readw(host->regs + NFC_CONFIG1);		tmp |= NFC_ECC_EN;		writew(tmp, host->regs + NFC_CONFIG1);	} else {		this->ecc.size = 512;		this->ecc.bytes = 3;		this->ecc.layout = &nand_hw_eccoob_8;		this->ecc.mode = NAND_ECC_SOFT;		tmp = readw(host->regs + NFC_CONFIG1);		tmp &= ~NFC_ECC_EN;		writew(tmp, host->regs + NFC_CONFIG1);	}	/* Reset NAND */	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);	/* preset operation */	/* Unlock the internal RAM Buffer */	writew(0x2, host->regs + NFC_CONFIG);	/* Blocks to be unlocked */	writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR);	writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR);	/* Unlock Block Command for given address range */	writew(0x4, host->regs + NFC_WRPROT);	/* NAND bus width determines access funtions used by upper layer */	if (pdata->width == 2) {		this->options |= NAND_BUSWIDTH_16;		this->ecc.layout = &nand_hw_eccoob_16;	}	host->pagesize_2k = 0;	/* Scan to find existence of the device */	if (nand_scan(mtd, 1)) {		DEBUG(MTD_DEBUG_LEVEL0,		      "MXC_ND: Unable to find any NAND device.\n");		err = -ENXIO;		goto escan;	}	/* Register the partitions */#ifdef CONFIG_MTD_PARTITIONS	nr_parts =	    parse_mtd_partitions(mtd, part_probes, &host->parts, 0);	if (nr_parts > 0)		add_mtd_partitions(mtd, host->parts, nr_parts);	else#endif	{		pr_info("Registering %s as whole device\n", mtd->name);		add_mtd_device(mtd);	}	platform_set_drvdata(pdev, host);	return 0;escan:	free_irq(host->irq, NULL);eirq:	iounmap(host->regs);eres:	clk_put(host->clk);eclk:	kfree(host);	return err;}static int __devexit mxcnd_remove(struct platform_device *pdev){	struct mxc_nand_host *host = platform_get_drvdata(pdev);	clk_put(host->clk);	platform_set_drvdata(pdev, NULL);	nand_release(&host->mtd);	free_irq(host->irq, NULL);	iounmap(host->regs);	kfree(host);	return 0;}#ifdef CONFIG_PMstatic int mxcnd_suspend(struct platform_device *pdev, pm_message_t state){	struct mtd_info *info = platform_get_drvdata(pdev);	int ret = 0;	DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n");	if (info)		ret = info->suspend(info);	/* Disable the NFC clock */	clk_disable(nfc_clk);	/* FIXME */	return ret;}static int mxcnd_resume(struct platform_device *pdev){	struct mtd_info *info = platform_get_drvdata(pdev);	int ret = 0;	DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n");	/* Enable the NFC clock */	clk_enable(nfc_clk);	/* FIXME */	if (info)		info->resume(info);	return ret;}#else# define mxcnd_suspend   NULL# define mxcnd_resume    NULL#endif				/* CONFIG_PM */static struct platform_driver mxcnd_driver = {	.driver = {		   .name = DRIVER_NAME,		   },	.remove = __exit_p(mxcnd_remove),	.suspend = mxcnd_suspend,	.resume = mxcnd_resume,};static int __init mxc_nd_init(void){	/* Register the device driver structure. */	pr_info("MXC MTD nand Driver\n");	if (platform_driver_probe(&mxcnd_driver, mxcnd_probe) != 0) {		printk(KERN_ERR "Driver register failed for mxcnd_driver\n");		return -ENODEV;	}	return 0;}static void __exit mxc_nd_cleanup(void){	/* Unregister the device structure */	platform_driver_unregister(&mxcnd_driver);}module_init(mxc_nd_init);module_exit(mxc_nd_cleanup);MODULE_AUTHOR("Freescale Semiconductor, Inc.");MODULE_DESCRIPTION("MXC NAND MTD driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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