📄 pxa3xx_nand.c
字号:
* 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 + -