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

📄 pxa3xx_nand.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	 * consider it as a ecc error which will tell the caller the	 * read fail We have distinguish all the errors, but the	 * nand_read_ecc only check this function return value	 */	if (info->retcode != ERR_NONE)		return -1;	return 0;}static int __readid(struct pxa3xx_nand_info *info, uint32_t *id){	const struct pxa3xx_nand_flash *f = info->flash_info;	const struct pxa3xx_nand_cmdset *cmdset = f->cmdset;	uint32_t ndcr;	uint8_t  id_buff[8];	if (prepare_other_cmd(info, cmdset->read_id)) {		printk(KERN_ERR "failed to prepare command\n");		return -EINVAL;	}	/* Send command */	if (write_cmd(info))		goto fail_timeout;	/* Wait for CMDDM(command done successfully) */	if (wait_for_event(info, NDSR_RDDREQ))		goto fail_timeout;	__raw_readsl(info->mmio_base + NDDB, id_buff, 2);	*id = id_buff[0] | (id_buff[1] << 8);	return 0;fail_timeout:	ndcr = nand_readl(info, NDCR);	nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);	udelay(10);	return -ETIMEDOUT;}static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,				    const struct pxa3xx_nand_flash *f){	struct platform_device *pdev = info->pdev;	struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;	uint32_t ndcr = 0x00000FFF; /* disable all interrupts */	if (f->page_size != 2048 && f->page_size != 512)		return -EINVAL;	if (f->flash_width != 16 && f->flash_width != 8)		return -EINVAL;	/* calculate flash information */	info->oob_size = (f->page_size == 2048) ? 64 : 16;	info->read_id_bytes = (f->page_size == 2048) ? 4 : 2;	/* calculate addressing information */	info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;	if (f->num_blocks * f->page_per_block > 65536)		info->row_addr_cycles = 3;	else		info->row_addr_cycles = 2;	ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;	ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0;	ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;	ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;	ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;	ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;	ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes);	ndcr |= NDCR_SPARE_EN; /* enable spare by default */	info->reg_ndcr = ndcr;	pxa3xx_nand_set_timing(info, f->timing);	info->flash_info = f;	return 0;}static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info,				    const struct pxa3xx_nand_platform_data *pdata){	const struct pxa3xx_nand_flash *f;	uint32_t id = -1;	int i;	for (i = 0; i<pdata->num_flash; ++i) {		f = pdata->flash + i;		if (pxa3xx_nand_config_flash(info, f))			continue;		if (__readid(info, &id))			continue;		if (id == f->chip_id)			return 0;	}#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN	for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) {		f = builtin_flash_types[i];		if (pxa3xx_nand_config_flash(info, f))			continue;		if (__readid(info, &id))			continue;		if (id == f->chip_id)			return 0;	}#endif	dev_warn(&info->pdev->dev,		 "failed to detect configured nand flash; found %04x instead of\n",		 id);	return -ENODEV;}/* the maximum possible buffer size for large page with OOB data * is: 2048 + 64 = 2112 bytes, allocate a page here for both the * data buffer and the DMA descriptor */#define MAX_BUFF_SIZE	PAGE_SIZEstatic int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info){	struct platform_device *pdev = info->pdev;	int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);	if (use_dma == 0) {		info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);		if (info->data_buff == NULL)			return -ENOMEM;		return 0;	}	info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,				&info->data_buff_phys, GFP_KERNEL);	if (info->data_buff == NULL) {		dev_err(&pdev->dev, "failed to allocate dma buffer\n");		return -ENOMEM;	}	info->data_buff_size = MAX_BUFF_SIZE;	info->data_desc = (void *)info->data_buff + data_desc_offset;	info->data_desc_addr = info->data_buff_phys + data_desc_offset;	info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW,				pxa3xx_nand_data_dma_irq, info);	if (info->data_dma_ch < 0) {		dev_err(&pdev->dev, "failed to request data dma\n");		dma_free_coherent(&pdev->dev, info->data_buff_size,				info->data_buff, info->data_buff_phys);		return info->data_dma_ch;	}	return 0;}static struct nand_ecclayout hw_smallpage_ecclayout = {	.eccbytes = 6,	.eccpos = {8, 9, 10, 11, 12, 13 },	.oobfree = { {2, 6} }};static struct nand_ecclayout hw_largepage_ecclayout = {	.eccbytes = 24,	.eccpos = {		40, 41, 42, 43, 44, 45, 46, 47,		48, 49, 50, 51, 52, 53, 54, 55,		56, 57, 58, 59, 60, 61, 62, 63},	.oobfree = { {2, 38} }};static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,				 struct pxa3xx_nand_info *info){	const struct pxa3xx_nand_flash *f = info->flash_info;	struct nand_chip *this = &info->nand_chip;	this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0;	this->waitfunc		= pxa3xx_nand_waitfunc;	this->select_chip	= pxa3xx_nand_select_chip;	this->dev_ready		= pxa3xx_nand_dev_ready;	this->cmdfunc		= pxa3xx_nand_cmdfunc;	this->read_word		= pxa3xx_nand_read_word;	this->read_byte		= pxa3xx_nand_read_byte;	this->read_buf		= pxa3xx_nand_read_buf;	this->write_buf		= pxa3xx_nand_write_buf;	this->verify_buf	= pxa3xx_nand_verify_buf;	this->ecc.mode		= NAND_ECC_HW;	this->ecc.hwctl		= pxa3xx_nand_ecc_hwctl;	this->ecc.calculate	= pxa3xx_nand_ecc_calculate;	this->ecc.correct	= pxa3xx_nand_ecc_correct;	this->ecc.size		= f->page_size;	if (f->page_size == 2048)		this->ecc.layout = &hw_largepage_ecclayout;	else		this->ecc.layout = &hw_smallpage_ecclayout;	this->chip_delay = 25;}static int pxa3xx_nand_probe(struct platform_device *pdev){	struct pxa3xx_nand_platform_data *pdata;	struct pxa3xx_nand_info *info;	struct nand_chip *this;	struct mtd_info *mtd;	struct resource *r;	int ret = 0, irq;	pdata = pdev->dev.platform_data;	if (!pdata) {		dev_err(&pdev->dev, "no platform data defined\n");		return -ENODEV;	}	mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info),			GFP_KERNEL);	if (!mtd) {		dev_err(&pdev->dev, "failed to allocate memory\n");		return -ENOMEM;	}	info = (struct pxa3xx_nand_info *)(&mtd[1]);	info->pdev = pdev;	this = &info->nand_chip;	mtd->priv = info;	info->clk = clk_get(&pdev->dev, "NANDCLK");	if (IS_ERR(info->clk)) {		dev_err(&pdev->dev, "failed to get nand clock\n");		ret = PTR_ERR(info->clk);		goto fail_free_mtd;	}	clk_enable(info->clk);	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);	if (r == NULL) {		dev_err(&pdev->dev, "no resource defined for data DMA\n");		ret = -ENXIO;		goto fail_put_clk;	}	info->drcmr_dat = r->start;	r = platform_get_resource(pdev, IORESOURCE_DMA, 1);	if (r == NULL) {		dev_err(&pdev->dev, "no resource defined for command DMA\n");		ret = -ENXIO;		goto fail_put_clk;	}	info->drcmr_cmd = r->start;	irq = platform_get_irq(pdev, 0);	if (irq < 0) {		dev_err(&pdev->dev, "no IRQ resource defined\n");		ret = -ENXIO;		goto fail_put_clk;	}	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);	if (r == NULL) {		dev_err(&pdev->dev, "no IO memory resource defined\n");		ret = -ENODEV;		goto fail_put_clk;	}	r = request_mem_region(r->start, r->end - r->start + 1, pdev->name);	if (r == NULL) {		dev_err(&pdev->dev, "failed to request memory resource\n");		ret = -EBUSY;		goto fail_put_clk;	}	info->mmio_base = ioremap(r->start, r->end - r->start + 1);	if (info->mmio_base == NULL) {		dev_err(&pdev->dev, "ioremap() failed\n");		ret = -ENODEV;		goto fail_free_res;	}	ret = pxa3xx_nand_init_buff(info);	if (ret)		goto fail_free_io;	ret = request_irq(IRQ_NAND, pxa3xx_nand_irq, IRQF_DISABLED,				pdev->name, info);	if (ret < 0) {		dev_err(&pdev->dev, "failed to request IRQ\n");		goto fail_free_buf;	}	ret = pxa3xx_nand_detect_flash(info, pdata);	if (ret) {		dev_err(&pdev->dev, "failed to detect flash\n");		ret = -ENODEV;		goto fail_free_irq;	}	pxa3xx_nand_init_mtd(mtd, info);	platform_set_drvdata(pdev, mtd);	if (nand_scan(mtd, 1)) {		dev_err(&pdev->dev, "failed to scan nand\n");		ret = -ENXIO;		goto fail_free_irq;	}	return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);fail_free_irq:	free_irq(IRQ_NAND, info);fail_free_buf:	if (use_dma) {		pxa_free_dma(info->data_dma_ch);		dma_free_coherent(&pdev->dev, info->data_buff_size,			info->data_buff, info->data_buff_phys);	} else		kfree(info->data_buff);fail_free_io:	iounmap(info->mmio_base);fail_free_res:	release_mem_region(r->start, r->end - r->start + 1);fail_put_clk:	clk_disable(info->clk);	clk_put(info->clk);fail_free_mtd:	kfree(mtd);	return ret;}static int pxa3xx_nand_remove(struct platform_device *pdev){	struct mtd_info *mtd = platform_get_drvdata(pdev);	struct pxa3xx_nand_info *info = mtd->priv;	platform_set_drvdata(pdev, NULL);	del_mtd_device(mtd);	del_mtd_partitions(mtd);	free_irq(IRQ_NAND, info);	if (use_dma) {		pxa_free_dma(info->data_dma_ch);		dma_free_writecombine(&pdev->dev, info->data_buff_size,				info->data_buff, info->data_buff_phys);	} else		kfree(info->data_buff);	kfree(mtd);	return 0;}#ifdef CONFIG_PMstatic int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state){	struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);	struct pxa3xx_nand_info *info = mtd->priv;	if (info->state != STATE_READY) {		dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);		return -EAGAIN;	}	return 0;}static int pxa3xx_nand_resume(struct platform_device *pdev){	struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);	struct pxa3xx_nand_info *info = mtd->priv;	clk_enable(info->clk);	return pxa3xx_nand_config_flash(info, info->flash_info);}#else#define pxa3xx_nand_suspend	NULL#define pxa3xx_nand_resume	NULL#endifstatic struct platform_driver pxa3xx_nand_driver = {	.driver = {		.name	= "pxa3xx-nand",	},	.probe		= pxa3xx_nand_probe,	.remove		= pxa3xx_nand_remove,	.suspend	= pxa3xx_nand_suspend,	.resume		= pxa3xx_nand_resume,};static int __init pxa3xx_nand_init(void){	return platform_driver_register(&pxa3xx_nand_driver);}module_init(pxa3xx_nand_init);static void __exit pxa3xx_nand_exit(void){	platform_driver_unregister(&pxa3xx_nand_driver);}module_exit(pxa3xx_nand_exit);MODULE_LICENSE("GPL");MODULE_DESCRIPTION("PXA3xx NAND controller driver");

⌨️ 快捷键说明

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