📄 mxc_nd.c
字号:
break; case NAND_CMD_READ0: g_nandfc_info.colAddr = column; g_nandfc_info.bSpareOnly = false; useirq = false; break; case NAND_CMD_READOOB: g_nandfc_info.colAddr = column; g_nandfc_info.bSpareOnly = true; useirq = false; if (is2k_Pagesize) command = NAND_CMD_READ0; /* only READ0 is valid */ break; case NAND_CMD_SEQIN: if (column >= mtd->writesize) { if (is2k_Pagesize) { /** * 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. */ /* call itself to read a page */ mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr); } g_nandfc_info.colAddr = column - mtd->writesize; g_nandfc_info.bSpareOnly = true; /* Set program pointer to spare region */ if (!is2k_Pagesize) send_cmd(NAND_CMD_READOOB, false); } else { g_nandfc_info.bSpareOnly = false; g_nandfc_info.colAddr = column; /* Set program pointer to page start */ if (!is2k_Pagesize) send_cmd(NAND_CMD_READ0, false); } useirq = false; break; case NAND_CMD_PAGEPROG:#ifndef CONFIG_MTD_NAND_MXC_ECC_CORRECTION_OPTION2 if (Ecc_disabled) { /* Enable Ecc for page writes */ NFC_CONFIG1 |= NFC_ECC_EN; }#endif send_prog_page(0, g_nandfc_info.bSpareOnly); if (is2k_Pagesize) { /* data in 4 areas datas */ send_prog_page(1, g_nandfc_info.bSpareOnly); send_prog_page(2, g_nandfc_info.bSpareOnly); send_prog_page(3, g_nandfc_info.bSpareOnly); } break; case NAND_CMD_ERASE1: useirq = false; break; } /* * Write out the command to the device. */ send_cmd(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(0, page_addr == -1); if (is2k_Pagesize) send_addr(0, false); /* another col addr cycle for 2k page */ } /* * Write out page address, if necessary */ if (page_addr != -1) { send_addr((page_addr & 0xff), false); /* paddr_0 - p_addr_7 */ if (is2k_Pagesize) { /* One more address cycle for higher density devices */ if (mtd->size >= 0x10000000) { send_addr((page_addr >> 8) & 0xff, false); /* paddr_8 - paddr_15 */ send_addr((page_addr >> 16) & 0xff, true); } else send_addr((page_addr >> 8) & 0xff, true); /* paddr_8 - paddr_15 */ } else { /* One more address cycle for higher density devices */ if (mtd->size >= 0x4000000) { send_addr((page_addr >> 8) & 0xff, false); /* paddr_8 - paddr_15 */ send_addr((page_addr >> 16) & 0xff, true); } else send_addr((page_addr >> 8) & 0xff, true); /* paddr_8 - paddr_15 */ } } /* * Command post-processing step */ switch (command) { case NAND_CMD_RESET: break; case NAND_CMD_READOOB: case NAND_CMD_READ0: if (is2k_Pagesize) { /* send read confirm command */ send_cmd(NAND_CMD_READSTART, true); /* read for each AREA */ send_read_page(0, g_nandfc_info.bSpareOnly); send_read_page(1, g_nandfc_info.bSpareOnly); send_read_page(2, g_nandfc_info.bSpareOnly); send_read_page(3, g_nandfc_info.bSpareOnly); } else { send_read_page(0, g_nandfc_info.bSpareOnly); } break; case NAND_CMD_READID: send_read_id(); break; case NAND_CMD_PAGEPROG:#ifndef CONFIG_MTD_NAND_MXC_ECC_CORRECTION_OPTION2 if (Ecc_disabled) { /* Disble Ecc after page writes */ NFC_CONFIG1 &= ~(NFC_ECC_EN); }#endif break; case NAND_CMD_STATUS: break; case NAND_CMD_ERASE2: break; }}#ifdef CONFIG_MXC_NAND_LOW_LEVEL_ERASEstatic void mxc_low_erase(struct mtd_info *mtd){ struct nand_chip *this = mtd->priv; unsigned int page_addr, addr; u_char status; DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : mxc_low_erase:Erasing NAND\n"); for (addr = 0; addr < this->chipsize; addr += mtd->erasesize) { page_addr = addr / mtd->writesize; mxc_nand_command(mtd, NAND_CMD_ERASE1, -1, page_addr); mxc_nand_command(mtd, NAND_CMD_ERASE2, -1, -1); mxc_nand_command(mtd, NAND_CMD_STATUS, -1, -1); status = mxc_nand_read_byte(mtd); if (status & NAND_STATUS_FAIL) { printk(KERN_ERR "ERASE FAILED(block = %d,status = 0x%x)\n", addr / mtd->erasesize, status); } }}#endif/*! * This function is called during the driver binding process. * * @param pdev the device structure used to store device specific * information that is used by the suspend, resume and * remove functions * * @return The function always returns 0. */static int __init mxcnd_probe(struct platform_device *pdev){ struct nand_chip *this; struct mtd_info *mtd; struct flash_platform_data *flash = pdev->dev.platform_data; int nr_parts = 0; int err = 0; /* Allocate memory for MTD device structure and private data */ mxc_nand_data = kmalloc(sizeof(struct mxc_mtd_s), GFP_KERNEL); if (!mxc_nand_data) { printk(KERN_ERR "%s: failed to allocate mtd_info\n", __FUNCTION__); err = -ENOMEM; goto out; } memset(mxc_nand_data, 0, sizeof(struct mxc_mtd_s)); memset((char *)&g_nandfc_info, 0, sizeof(g_nandfc_info)); mxc_nand_data->dev = &pdev->dev; /* structures must be linked */ this = &mxc_nand_data->nand; mtd = &mxc_nand_data->mtd; mtd->priv = this; mtd->owner = THIS_MODULE; /* 50 us command delay time */ this->chip_delay = 5; this->priv = mxc_nand_data; 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; nfc_clk = clk_get(&pdev->dev, "nfc_clk"); clk_enable(nfc_clk); NFC_CONFIG1 |= NFC_INT_MSK; init_waitqueue_head(&irq_waitq); err = request_irq(INT_NANDFC, mxc_nfc_irq, 0, "mxc_nd", NULL); if (err) { goto out_1; } if (hardware_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; NFC_CONFIG1 |= NFC_ECC_EN; } else { this->ecc.mode = NAND_ECC_SOFT; } /* Reset NAND */ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* preset operation */ /* Unlock the internal RAM Buffer */ NFC_CONFIG = 0x2; /* Blocks to be unlocked */ NFC_UNLOCKSTART_BLKADDR = 0x0; NFC_UNLOCKEND_BLKADDR = 0x4000; /* Unlock Block Command for given address range */ NFC_WRPROT = 0x4; /* NAND bus width determines access funtions used by upper layer */ if (flash->width == 2) { this->options |= NAND_BUSWIDTH_16; this->ecc.layout = &nand_hw_eccoob_16; } else { this->options |= 0; } if ((NFMS >> NFMS_BIT) & 0x1) is2k_Pagesize = 1; else is2k_Pagesize = 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 out_1; } /* Register the partitions */#ifdef CONFIG_MTD_PARTITIONS nr_parts = parse_mtd_partitions(mtd, part_probes, &mxc_nand_data->parts, 0); if (nr_parts > 0) add_mtd_partitions(mtd, mxc_nand_data->parts, nr_parts); else if (flash->parts) add_mtd_partitions(mtd, flash->parts, flash->nr_parts); else#endif { pr_info("Registering %s as whole device\n", mtd->name); add_mtd_device(mtd); }#ifdef CONFIG_MXC_NAND_LOW_LEVEL_ERASE /* Erase all the blocks of a NAND */ mxc_low_erase(mtd);#endif platform_set_drvdata(pdev, mtd); return 0; out_1: kfree(mxc_nand_data); out: return err;} /*! * Dissociates the driver from the device. * * @param pdev the device structure used to give information on which * * @return The function always returns 0. */static int __exit mxcnd_remove(struct platform_device *pdev){ struct mtd_info *mtd = platform_get_drvdata(pdev); clk_put(nfc_clk); platform_set_drvdata(pdev, NULL); if (mxc_nand_data) { nand_release(mtd); free_irq(INT_NANDFC, NULL); kfree(mxc_nand_data); } return 0;}#ifdef CONFIG_PM/*! * This function is called to put the NAND in a low power state. Refer to the * document driver-model/driver.txt in the kernel source tree for more * information. * * @param pdev the device information structure * * @param state the power state the device is entering * * @return The function returns 0 on success and -1 on failure */static 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); return ret;}/*! * This function is called to bring the NAND back from a low power state. Refer * to the document driver-model/driver.txt in the kernel source tree for more * information. * * @param pdev the device information structure * * @return The function returns 0 on success and -1 on failure */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); if (info) { info->resume(info); } return ret;}#else/*! * \def mxcnd_resume * The PM is not defined. *//*! * The PM is not defined. */#define mxcnd_suspend NULL#define mxcnd_resume NULL#endif /* CONFIG_PM *//*! * This structure contains pointers to the power management callback functions. */static struct platform_driver mxcnd_driver = { .driver = { .name = "mxc_nand_flash", }, .probe = mxcnd_probe, .remove = __exit_p(mxcnd_remove), .suspend = mxcnd_suspend, .resume = mxcnd_resume,};/*! * Main initialization routine * @return 0 if successful; non-zero otherwise */static int __init mxc_nd_init(void){ /* Register the device driver structure. */ pr_info("MXC MTD nand Driver %s\n", DVR_VER); if (platform_driver_register(&mxcnd_driver) != 0) { printk(KERN_ERR "Driver register failed for mxcnd_driver\n"); return -ENODEV; } return 0;}/*! * Clean up routine */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 + -