转自http://blog.youkuaiyun.com/wang_zheng_kai/article/details/19037953
驱动中probe函数的分析
其中探测函数代码执行流程为:
在probe函数中主要是完成了NAND芯片级的初始化,主要有以下几个作用:
-分配nand_chip内存,根据目标板及NAND控制器初始化nand_chip中成员函数(若未初始化则使用nand_base.c中的默认函数),将mtd_info中的priv指向nand_chip(或板相关私有结构),设置ecc模式及处理函数
-以mtd_info为参数调用nand_scan_ident()和
nand_scan_tail()函数,探测NAND Flash并进行初始化。
nand_scan_ident()会读取nand芯片ID,并根据mtd->priv即nand_chip中成员初始化mtd_info
nand_scan_tail()进行了ECC的设置和剩下的MTD驱动函数的初始化。
-若有分区,则以mtd_info和mtd_partition为参数调用add_mtd_partitions()添加分区信息
nand_scan_ident()
首先初始化mtd_info中一个重要的指针priv,使这个指针指向nand_chip变量;
然后调用了同文件下的nand_set_defaults()和nand_get_flash_type(),nand_set_defaults()函数对struct nand_chip结构体的函数指针进行了赋值。在此函数中cmdfunc映射到了nand_command,nand_get_flash_type()读取了厂商和设备ID进行匹配,并对struct nand_chip结构体的变量进行初始化操作。
nand_scan_tail()
1、初始化oob区、ecc校验相关参数和函数指针。
2、初始化MTD驱动接口函数。
3、调用nand_bbt()创建坏块表。
probe程序代码分析如下:
- NAND驱动的代码分析(二)
- ----------probe程序的分析
- Joe
- static int jz4780_nand_probe(struct platform_device *pdev)
- {
- int ret = 0;
- int bank = 0;
- int i = 0, j = 0, k = 0, m = 0;
- int eccpos_start;
- struct nand_chip *chip;
- struct mtd_info *mtd;
- struct jz4780_nand *nand;
- struct jz4780_nand_platform_data *pdata;
- nand_flash_if_t *nand_if;
- 《1》
- /*
- * sanity check主要是获取平台设备信息设备的相关参数
- */
- pdata = dev_get_platdata(&pdev->dev);//获取平台设备的数据
- if (!pdata) {
- dev_err(&pdev->dev, "Failed to get platform_data.\n");
- return -ENXIO;
- }
- nand = kzalloc(sizeof(struct jz4780_nand), GFP_KERNEL);//为设备分配内存空间
- if (!nand) {
- dev_err(&pdev->dev,
- "Failed to allocate jz4780_nand.\n");
- return -ENOMEM;
- }
- nand->pdev = pdev;
- nand->pdata = pdata;
- platform_set_drvdata(pdev, nand);//将nand保存为平台总线的私有数据,将nand设备的数据信息传递到系统平台设备中去
- nand->num_nand_flash_if = pdata->num_nand_flash_if;//所用nand flash的片数
- nand->xfer_type = pdata->xfer_type;
- nand->ecc_type = pdata->ecc_type;
- 《2》
- /*
- * request GPEMC banks获取每一个bank的相关参数(busy,protect,timeout..)申请cs_gpio引脚
- */
- for (i = 0; i < nand->num_nand_flash_if; i++, j = i) {
- nand_if = &pdata->nand_flash_if_table[i];
- nand->nand_flash_if_table[i] = nand_if;
- bank = nand_if->bank;
- ret = gpemc_request_cs(&pdev->dev, &nand_if->cs, bank);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to request busy"
- " gpio irq for bank%d\n", bank);
- goto err_free_busy_irq;
- }
- }
- 《3》
- /*
- * request busy GPIO interrupt申请busy_gpio引脚
- */
- switch (nand->xfer_type) {
- case NAND_XFER_CPU_IRQ:
- case NAND_XFER_DMA_IRQ://中断方式读取数据
- for (i = 0; i < nand->num_nand_flash_if; i++, k = i) {
- nand_if = &pdata->nand_flash_if_table[i];
- if (nand_if->busy_gpio < 0)
- continue;
- ret = request_busy_irq(nand_if);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to request busy"
- " gpio irq for bank%d\n", bank);
- goto err_free_busy_irq;
- }
- }
- break;
- case NAND_XFER_CPU_POLL:
- case NAND_XFER_DMA_POLL://poll机制轮询读取数据(类似与底半部方式)
- for (i = 0; i < nand->num_nand_flash_if; i++, k = i) {
- nand_if = &pdata->nand_flash_if_table[i];
- if (nand_if->busy_gpio < 0)
- continue;
- ret = request_busy_poll(nand_if);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to request busy"
- " gpio irq for bank%d\n", bank);
- goto err_free_busy_irq;
- }
- }
- nand->busy_poll = 1;
- break;
- default:
- WARN(1, "Unsupport transfer type.\n");
- BUG();
- break;
- }
- 《4》
- /*
- * request WP GPIO//申请写保护引脚
- */
- for (i = 0; i < nand->num_nand_flash_if; i++, m = i) {
- nand_if = &pdata->nand_flash_if_table[i];
- if (nand_if->wp_gpio < 0)
- continue;
- if (!gpio_is_valid(nand_if->wp_gpio)) {
- dev_err(&pdev->dev,
- "Invalid wp GPIO:%d\n", nand_if->wp_gpio);
- ret = -EINVAL;
- goto err_free_wp_gpio;
- }
- bank = nand_if->bank;
- ret = gpio_request(nand_if->wp_gpio, label_wp_gpio[bank]);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to request wp GPIO:%d\n", nand_if->wp_gpio);
- goto err_free_wp_gpio;
- }
- gpio_direction_output(nand_if->wp_gpio, 0);//设定gipo为输出模式
- /* Write protect disabled by default */
- jz4780_nand_enable_wp(nand_if, 0); //disable 写保护
- }
- 《5》
- /*
- * NAND flash devices support list override
- */
- nand->nand_flash_table = pdata->nand_flash_table ?
- pdata->nand_flash_table : builtin_nand_flash_table;
- nand->num_nand_flash = pdata->nand_flash_table ?
- pdata->num_nand_flash :
- ARRAY_SIZE(builtin_nand_flash_table);
- /*
- * attach to MTD subsystem
- 链接MTD的子系统-----涉及到如何传输数据
- * struct nand_chip是一个与NAND芯片密切相关的结构体,主要包含三方面内 容:
- *指向一些操作NAND芯片的函数的指针;
- *表示NAND芯片特性的成员变量,主要有:
- *与ecc,oob和bbt (bad block table)相关的一些结构体,对于坏块及坏块管理
- */
- chip = &nand->chip;
- chip->chip_delay = MAX_RB_DELAY_US;
- chip->cmdfunc = jz4780_nand_command;
- chip->dev_ready = jz4780_nand_dev_is_ready;
- chip->select_chip = jz4780_nand_select_chip;
- chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
- chip->onfi_get_features = jz4780_nand_onfi_get_features;
- chip->onfi_set_features = jz4780_nand_onfi_set_features;
- switch (nand->xfer_type) {
- case NAND_XFER_DMA_IRQ:
- case NAND_XFER_DMA_POLL:
- /*
- * DMA transfer DMA方式传输数据
- */
- ret = jz4780_nand_request_dma(nand);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request DMA channel.\n");
- goto err_free_wp_gpio;
- }
- chip->read_buf = jz4780_nand_read_buf;//将芯片中的数据读到缓冲区中
- chip->write_buf = jz4780_nand_write_buf;//将缓冲区中的数据写入芯片
- nand->use_dma = 1;
- break;
- case NAND_XFER_CPU_IRQ:
- case NAND_XFER_CPU_POLL:
- /*
- * CPU transfer CPU方式传输数据
- */
- chip->read_buf = jz4780_nand_cpu_read_buf;
- chip->write_buf = jz4780_nand_cpu_write_buf;
- jz4780_nand_write_buf 和 jz4780_nand_read_buf:这是两个最基本的操作函数,其功能,就是往你的Nand Flash的控制器中的FIFO读写数据。一般情况下,是MTD上层的操作,比如要读取一页的数据,那么在发送完相关的读命令和等待时间之后,就会调用到你底层的read_buf,去Nand Flash的FIFO中,一点点把我们要的数据,读取出来,放到我们制定的内存的缓存中去。写操作也是类似,将我们内存中的数据,写到Nand Flash的FIFO中去。
- break;
- default:
- WARN(1, "Unsupport transfer type.\n");
- BUG();
- break;
- }
- mtd = &nand->mtd;//填充mtd_info结构体相关信息
- mtd->priv = chip;//把指向struct nand_chip结构体的指针赋给struct mtd_info的priv成员变量,
- //因为MTD Core中很多函数之间的调用都只传递struct mtd_info,它需要通过priv成员变量得到struct nand_chip。
- mtd->name = dev_name(&pdev->dev);
- mtd->owner = THIS_MODULE;
- /*
- * if you use u-boot BBT creation code,specifying
- * this flag will let the kernel fish out the BBT
- * from the NAND, and also skip the full NAND scan
- * that can take 1/2s or so. little things...
- */
- if (pdata->flash_bbt) {//当flashbbt=1的时候系统在启动的时候将跳过对bbt(bad block table)的扫描
- chip->bbt_options |= NAND_BBT_USE_FLASH;
- chip->options |= NAND_SKIP_BBTSCAN;
- }
- /*
- * nand_base handle subpage write by fill space
- * where are outside of the subpage with 0xff,
- * that make things totally wrong, so disable it.
- */
- chip->options |= NAND_NO_SUBPAGE_WRITE;
- /*
- * for relocation
- */
- nand->gpemc_enable_nand_flash = gpemc_enable_nand_flash;
- nand->nand_wait_ready = nand_wait_ready;
- nand->gpio_get_value = gpio_get_value;
- nand->wait_for_completion_timeout = wait_for_completion_timeout;
- nand->msecs_to_jiffies = msecs_to_jiffies;
- nand->printk = printk;
- nand->udelay = __udelay;
- nand->ndelay = __ndelay;
- 《6》
- /*
- * Detect NAND flash chips 侦测NAND flash chips
- */
- /* step1. relax bank timings to scan 定时扫描空闲的bank*/
- for (bank = 0; bank < nand->num_nand_flash_if; bank++) {
- nand_if = nand->nand_flash_if_table[bank];
- gpemc_relax_bank_timing(&nand_if->cs);
- }
- if (nand_scan_ident(mtd, nand->num_nand_flash_if,
- nand->nand_flash_table)) {
- ret = -ENXIO;
- dev_err(&pdev->dev, "Failed to detect NAND flash.\n");
- goto err_dma_release_channel;
- }
- /*
- * post configure bank timing by detected NAND device 通过侦测的NAND设备配置bank时序寄存器
- */
- /* step1. match NAND chip information */
- nand->curr_nand_flash_info = jz4780_nand_match_nand_chip_info(nand);
- if (!nand->curr_nand_flash_info) {
- ret = -ENODEV;
- goto err_dma_release_channel;
- }
- /*
- * step2. preinitialize NAND flash 预初始化NAND闪存
- */
- ret = jz4780_nand_pre_init(nand);
- if (ret) {
- dev_err(&nand->pdev->dev, "Failed to"
- " preinitialize NAND chip.\n");
- goto err_dma_release_channel;
- }
- /* step3. replace NAND command function with large page version */// 用对页面的操作命令函数替代NAND的功能命令函数
- if (mtd->writesize > 512)
- chip->cmdfunc = jz4780_nand_command_lp;
- /* step4. configure bank timings */ //配置BANK的时序
- switch (nand->curr_nand_flash_info->type) {
- case BANK_TYPE_NAND:
- for (bank = 0; bank < nand->num_nand_flash_if; bank++) {
- nand_if = nand->nand_flash_if_table[bank];
- gpemc_fill_timing_from_nand(&nand_if->cs,
- &nand->curr_nand_flash_info->
- nand_timing.common_nand_timing);//对bank时序进行赋值操作
- ret = gpemc_config_bank_timing(&nand_if->cs);//对bank时序寄存器进行配置
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to configure timings for bank%d\n"
- , nand_if->bank);
- goto err_dma_release_channel;
- }
- }
- break;
- case BANK_TYPE_TOGGLE:
- for (bank = 0; bank < nand->num_nand_flash_if; bank++) {
- nand_if = nand->nand_flash_if_table[bank];
- gpemc_fill_timing_from_toggle(&nand_if->cs,
- &nand->curr_nand_flash_info->
- nand_timing.toggle_nand_timing);
- ret = gpemc_config_bank_timing(&nand_if->cs);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to configure timings for bank%d\n"
- , nand_if->bank);
- goto err_dma_release_channel;
- }
- }
- break;
- default:
- WARN(1, "Unsupported NAND type.\n");
- BUG();
- break;
- }
- 《7》
- /*
- * initialize ECC control//初始化NAND ECC控制器
- */
- /* step1. configure ECC step */
- switch (nand->ecc_type) {
- case NAND_ECC_TYPE_SW: //软件实现ECC检测
- /*
- * valid ECC configuration ?
- */
- if (nand->curr_nand_flash_info->
- ecc_step.data_size % 8
- || nand->curr_nand_flash_info->
- ecc_step.ecc_bits % 8) {
- ret = -EINVAL;
- dev_err(&nand->pdev->dev, "Failed when configure ECC,"
- " ECC size, and ECC bits must be a multiple of 8.\n");//ECC的大小和ECC位大小必须是8位
- goto err_dma_release_channel;
- }
- chip->ecc.mode = NAND_ECC_SOFT_BCH;//ECC算法的模式为软件BCH模式
- chip->ecc.size =
- nand->curr_nand_flash_info->ecc_step.data_size;
- chip->ecc.bytes = (fls(88 * chip->ecc.size) *
- (nand->curr_nand_flash_info->ecc_step.ecc_bits) + 7) / 8;
- break;
- case NAND_ECC_TYPE_HW: //硬件实现ECC的检测,选取的算法同样是BCH
- nand->bch_req.dev = &nand->pdev->dev;
- nand->bch_req.complete = jz4780_nand_bch_req_complete;
- nand->bch_req.ecc_level =
- nand->curr_nand_flash_info->ecc_step.ecc_bits;
- nand->bch_req.blksz =
- nand->curr_nand_flash_info->ecc_step.data_size;
- nand->bch_req.errrept_data = kzalloc(MAX_ERRREPT_DATA_SIZE,
- GFP_KERNEL);
- if (!nand->bch_req.errrept_data) {
- dev_err(&pdev->dev,
- "Failed to allocate ECC errrept_data buffer\n");
- ret = -ENOMEM;
- goto err_dma_release_channel;
- }
- init_completion(&nand->bch_req_done);
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.calculate = jz4780_nand_ecc_calculate_bch;
- chip->ecc.correct = jz4780_nand_ecc_correct_bch;
- chip->ecc.hwctl = jz4780_nand_ecc_hwctl;
- chip->ecc.size =
- nand->curr_nand_flash_info->ecc_step.data_size;
- chip->ecc.bytes = bch_ecc_bits_to_bytes(
- nand->curr_nand_flash_info->ecc_step.ecc_bits);
- chip->ecc.strength = nand->bch_req.ecc_level;
- break;
- default :
- WARN(1, "Unsupported ECC type.\n");
- BUG();
- break;
- }
- /*
- /* step2. generate ECC layout *///产生出ECC的布局
- /*
- * eccbytes = eccsteps * eccbytes_prestep;//计算ECC的字节数
- */
- nand->ecclayout.eccbytes =
- mtd->writesize / chip->ecc.size * chip->ecc.bytes;
- //判断是否ECC字节数超出OOB的空间大小
- if (mtd->oobsize < (nand->ecclayout.eccbytes +
- chip->badblockpos + 2)) {
- WARN(1, "ECC codes are out of OOB area.\n");
- BUG();
- }
- /*
- * ECC codes are right aligned ECC码为右对齐
- * start position = oobsize - eccbytes 起始位置的计算
- */
- eccpos_start = mtd->oobsize - nand->ecclayout.eccbytes; //ECC码的起始位置
- for (bank = 0; bank < nand->ecclayout.eccbytes; bank++)
- nand->ecclayout.eccpos[bank] = eccpos_start + bank;
- nand->ecclayout.oobfree->offset = chip->badblockpos + 2;
- nand->ecclayout.oobfree->length =
- mtd->oobsize - (nand->ecclayout.eccbytes
- + chip->badblockpos + 2);
- chip->ecc.layout = &nand->ecclayout;
- 《8》
- /*
- * second phase NAND scan //第二阶段NAND扫描
- */
- if (nand_scan_tail(mtd)) {
- ret = -ENXIO;
- goto err_free_ecc;
- }
- #ifdef CONFIG_DEBUG_FS
- nand->debugfs_entry = jz4780_nand_debugfs_init(nand);
- if (IS_ERR(nand->debugfs_entry)) {
- dev_err(&pdev->dev, "Failed to register debugfs entry.\n");
- ret = PTR_ERR(nand->debugfs_entry);
- goto err_free_ecc;
- }
- #endif
- /*
- * relocate hot functions to TCSM
- */
- if (pdata->try_to_reloc_hot) {
- ret = jz4780_nand_reloc_hot_to_tcsm(nand);
- if (ret) {
- dev_err(&pdev->dev, "Failed to relocate hot functions.\n");
- goto err_debugfs_remove;
- }
- }
- 《9》
- /*
- * MTD register
- */
- ret = mtd_device_parse_register(mtd, NULL, NULL,
- pdata->part_table, pdata->num_part);
- if (ret) {
- dev_err(&pdev->dev, "Failed to add MTD device\n");
- goto err_unreloc_hot;
- }
- dev_info(&pdev->dev,
- "Successfully registered JZ4780 SoC NAND controller driver.\n");
- return 0;
- err_unreloc_hot:
- if (pdata->try_to_reloc_hot)
- jz4780_nand_unreloc_hot_from_tcsm(nand);
- err_debugfs_remove:
- #ifdef CONFIG_DEBUG_FS
- debugfs_remove_recursive(nand->debugfs_entry);
- #endif
- err_free_ecc:
- if (pdata->ecc_type == NAND_ECC_TYPE_HW)
- kfree(nand->bch_req.errrept_data);
- err_dma_release_channel:
- if (nand->xfer_type == NAND_XFER_DMA_IRQ ||
- nand->xfer_type == NAND_XFER_DMA_POLL)
- dma_release_channel(nand->dma_pipe_nand.chan);
- err_free_wp_gpio:
- for (bank = 0; bank < m; bank++) {
- nand_if = &pdata->nand_flash_if_table[bank];
- if (nand_if->wp_gpio < 0)
- continue;
- gpio_free(nand_if->wp_gpio);
- }
- err_free_busy_irq:
- for (bank = 0; bank < k; bank++) {
- nand_if = &pdata->nand_flash_if_table[bank];
- if (nand_if->busy_gpio < 0)
- continue;
- if (pdata->xfer_type == NAND_XFER_CPU_IRQ ||
- pdata->xfer_type ==NAND_XFER_DMA_IRQ)
- free_irq(nand_if->busy_irq, nand_if);
- gpio_free(nand_if->busy_gpio);
- }
- err_release_cs:
- for (bank = 0; bank < j; bank++) {
- nand_if = &pdata->nand_flash_if_table[bank];
- gpemc_release_cs(&nand_if->cs);
- }
- kfree(nand);
- return ret;
- }
nand_scan_ident()程序代码分析:
- <pre code_snippet_id="183770" snippet_file_name="blog_20140211_2_2449669" name="code" class="objc">int nand_scan_ident(struct mtd_info *mtd, int maxchips,struct nand_flash_dev *table)
- {
- int i, busw, nand_maf_id, nand_dev_id;
- struct nand_chip *chip = mtd->priv;
- // mtd->priv在probe函数中被初始化为数据结构nand_chip的变量nand_chip[i],所以这里的this指针指向的就是变量nand_chip[i]。
- struct nand_flash_dev *type;
- /* Get buswidth to select the correct functions */
- busw = chip->options & NAND_BUSWIDTH_16;
- //位宽设置,options bit1设置为0是busw为0,表示位宽为8。options会在该函数后续被初始化为nand_flash_ids[i].options。如果用户需要配置扩展功能只能在nand_flash_ids[i].options配置。
- /* Set the default functions */
- nand_set_defaults(chip, busw);
- //nand_set_defaults()函数对struct nand_chip结构体的函数指针进行了赋值。在此函数中cmdfunc映射到了nand_command,
- /* Set default functions */
- static void nand_set_defaults(struct nand_chip *chip, int busw)
- {
- /* check for proper chip_delay setup, set 20us if not */
- if (!chip->chip_delay)
- chip->chip_delay = 20
- /* check, if a user supplied command function given */
- if (chip->cmdfunc == NULL)
- chip->cmdfunc = nand_command;
- /* check, if a user supplied wait function given */
- if (chip->waitfunc == NULL)
- chip->waitfunc = nand_wait;
- if (!chip->select_chip)
- chip->select_chip = nand_select_chip;
- if (!chip->read_byte)
- chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
- if (!chip->read_word)
- chip->read_word = nand_read_word;
- if (!chip->block_bad)
- chip->block_bad = nand_block_bad;
- if (!chip->block_markbad)
- chip->block_markbad = nand_default_block_markbad;
- if (!chip->write_buf)
- chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
- if (!chip->read_buf)
- chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
- if (!chip->scan_bbt)
- chip->scan_bbt = nand_default_bbt;
- if (!chip->controller) {
- chip->controller = &chip->hwcontrol;
- spin_lock_init(&chip->controller->lock);
- init_waitqueue_head(&chip->controller->wq);
- }
- }
- /* Read the flash type */
- type = nand_get_flash_type(mtd, chip, busw,
- &nand_maf_id, &nand_dev_id, table);
- //nand_get_flash_type()读取了厂商和设备ID,并对struct nand_chip结构体的变量进行初始化操作
- if (IS_ERR(type)) {
- if (!(chip->options & NAND_SCAN_SILENT_NODEV))
- pr_warn("No NAND device found\n");
- chip->select_chip(mtd, -1);
- return PTR_ERR(type);
- }
- chip->select_chip(mtd, -1);
- /* Check for a chip array */
- for (i = 1; i < maxchips; i++) {
- chip->select_chip(mtd, i);
- /* See comment in nand_get_flash_type for reset */
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
- /* Send the command for reading device ID */
- chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
- /* Read manufacturer and device IDs */
- if (nand_maf_id != chip->read_byte(mtd) ||
- nand_dev_id != chip->read_byte(mtd)) {
- chip->select_chip(mtd, -1);
- break;
- }
- chip->select_chip(mtd, -1);
- }
- if (i > 1)
- pr_info("%d NAND chips detected\n", i);
- /* Store the number of chips and calc total size for mtd */
- chip->numchips = i;
- mtd->size = i * chip->chipsize;
- return 0;
- }
- EXPORT_SYMBOL(nand_scan_ident);
- </pre><br>
- <br>
- <pre></pre>
- <p></p>
- <pre></pre>
- <p></p>
- <pre code_snippet_id="183770" snippet_file_name="blog_20140211_3_8339013" name="code" class="objc"><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">nand_scan_tail()代码分析:</span></pre><pre code_snippet_id="183770" snippet_file_name="blog_20140211_4_5623798" name="code" class="objc">int nand_scan_tail(struct mtd_info *mtd)
- {
- int i;
- struct nand_chip *chip = mtd->priv;
- /* New bad blocks should be marked in OOB, flash-based BBT, or both */
- BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
- !(chip->bbt_options & NAND_BBT_USE_FLASH));
- if (!(chip->options & NAND_OWN_BUFFERS))
- chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
- if (!chip->buffers)
- return -ENOMEM;
- /* Set the internal oob buffer location, just after the page data */
- chip->oob_poi = chip->buffers->databuf + mtd->writesize;//设置缓存位置,仅仅需要在数据页后面就行
- * If no default placement scheme is given, select an appropriate one.如果没有预设的方案,就选择合适的一个
- */
- if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
- switch (mtd->oobsize) {
- case 8:
- chip->ecc.layout = &nand_oob_8;
- break;
- case 16:
- chip->ecc.layout = &nand_oob_16;
- break;
- case 64:
- chip->ecc.layout = &nand_oob_64;
- break;
- case 128:
- chip->ecc.layout = &nand_oob_128;
- break;
- default:
- pr_warn("No oob scheme defined for oobsize %d\n",
- mtd->oobsize);
- BUG();
- }
- }
- if (!chip->write_page)
- chip->write_page = nand_write_page;
- /* set for ONFI nand *///设置ONFI NAND的功能
- if (!chip->onfi_set_features)
- chip->onfi_set_features = nand_onfi_set_features;
- if (!chip->onfi_get_features)
- chip->onfi_get_features = nand_onfi_get_features;
- //对chip结构题的ecc相关的初始化
- /*
- * Check ECC mode, default to software if 3byte/512byte hardware ECC is
- * selected and we have 256 byte pagesize fallback to software ECC
- *///如果硬件检测选择的是3/512那么我们默认软件ECC模式,我们每页有256bytes为ECC备用
- // /*以下都是对chip赋值,对应nand_chip中的函数*/
- /*Nand_scan是在初始化nand的时候对nand进行的一步非常好重要的操作,
- *在nand_scan中会对我们所写的关于特定芯片的读写函数重载到nand_chip结构中去,
- *并会将mtd_info结构体中的函数用nand的函数来重载,实现了mtd到底层驱动的联系。
- *并且在nand_scan函数中会通过读取nand芯片的设备号和厂家号自动在芯片列表中寻找相应的型号和参数,并将其注册进去。*/
- switch (chip->ecc.mode) {
- case NAND_ECC_HW_OOB_FIRST:
- /* Similar to NAND_ECC_HW, but a separate read_page handle */
- if (!chip->ecc.calculate || !chip->ecc.correct ||
- !chip->ecc.hwctl) {
- pr_warn("No ECC functions supplied; "
- "hardware ECC not possible\n");
- BUG();
- }
- if (!chip->ecc.read_page)
- chip->ecc.read_page = nand_read_page_hwecc_oob_first;
- case NAND_ECC_HW:
- /* Use standard hwecc read page function? */
- if (!chip->ecc.read_page)
- chip->ecc.read_page = nand_read_page_hwecc;
- if (!chip->ecc.write_page)
- chip->ecc.write_page = nand_write_page_hwecc;
- if (!chip->ecc.read_page_raw)
- chip->ecc.read_page_raw = nand_read_page_raw;
- if (!chip->ecc.write_page_raw)
- chip->ecc.write_page_raw = nand_write_page_raw;
- if (!chip->ecc.read_oob)
- chip->ecc.read_oob = nand_read_oob_std;
- if (!chip->ecc.write_oob)
- chip->ecc.write_oob = nand_write_oob_std;
- case NAND_ECC_HW_SYNDROME:
- if ((!chip->ecc.calculate || !chip->ecc.correct ||
- !chip->ecc.hwctl) &&
- (!chip->ecc.read_page ||
- chip->ecc.read_page == nand_read_page_hwecc ||
- !chip->ecc.write_page ||
- chip->ecc.write_page == nand_write_page_hwecc)) {
- pr_warn("No ECC functions supplied; "
- "hardware ECC not possible\n");
- BUG();
- }
- /* Use standard syndrome read/write page function? */
- if (!chip->ecc.read_page)
- chip->ecc.read_page = nand_read_page_syndrome;
- if (!chip->ecc.write_page)
- chip->ecc.write_page = nand_write_page_syndrome;
- if (!chip->ecc.read_page_raw)
- chip->ecc.read_page_raw = nand_read_page_raw_syndrome;
- if (!chip->ecc.write_page_raw)
- chip->ecc.write_page_raw = nand_write_page_raw_syndrome;
- if (!chip->ecc.read_oob)
- chip->ecc.read_oob = nand_read_oob_syndrome;
- if (!chip->ecc.write_oob)
- chip->ecc.write_oob = nand_write_oob_syndrome;
- if (mtd->writesize >= chip->ecc.size) {
- if (!chip->ecc.strength) {
- pr_warn("Driver must set ecc.strength when using hardware ECC\n");
- BUG();
- }
- break;
- }
- pr_warn("%d byte HW ECC not possible on "
- "%d byte page size, fallback to SW ECC\n",
- chip->ecc.size, mtd->writesize);
- chip->ecc.mode = NAND_ECC_SOFT;
- case NAND_ECC_SOFT:
- chip->ecc.calculate = nand_calculate_ecc;
- chip->ecc.correct = nand_correct_data;
- chip->ecc.read_page = nand_read_page_swecc;
- chip->ecc.read_subpage = nand_read_subpage;
- chip->ecc.write_page = nand_write_page_swecc;
- chip->ecc.read_page_raw = nand_read_page_raw;
- chip->ecc.write_page_raw = nand_write_page_raw;
- chip->ecc.read_oob = nand_read_oob_std;
- chip->ecc.write_oob = nand_write_oob_std;
- if (!chip->ecc.size)
- chip->ecc.size = 256;
- chip->ecc.bytes = 3;
- chip->ecc.strength = 1;
- break;
- case NAND_ECC_SOFT_BCH:
- if (!mtd_nand_has_bch()) {
- pr_warn("CONFIG_MTD_ECC_BCH not enabled\n");
- BUG();
- }
- chip->ecc.calculate = nand_bch_calculate_ecc;
- chip->ecc.correct = nand_bch_correct_data;
- chip->ecc.read_page = nand_read_page_swecc;
- chip->ecc.read_subpage = nand_read_subpage;
- chip->ecc.write_page = nand_write_page_swecc;
- chip->ecc.read_page_raw = nand_read_page_raw;
- chip->ecc.write_page_raw = nand_write_page_raw;
- chip->ecc.read_oob = nand_read_oob_std;
- chip->ecc.write_oob = nand_write_oob_std;
- /*
- * Board driver should supply ecc.size and ecc.bytes values to
- * select how many bits are correctable; see nand_bch_init()
- * for details. Otherwise, default to 4 bits for large pag
- * devices.
- */
- if (!chip->ecc.size && (mtd->oobsize >= 64)) {
- chip->ecc.size = 512;
- chip->ecc.bytes = 7;
- }//初始化NAND BCH 纠错
- chip->ecc.priv = nand_bch_init(mtd,
- chip->ecc.size,
- chip->ecc.bytes,
- &chip->ecc.layout);//建立坏块表
- if (!chip->ecc.priv) {
- pr_warn("BCH ECC initialization failed!\n");
- BUG();
- }
- //Driver must set ecc.strength when using hardware ECC
- chip->ecc.strength =
- chip->ecc.bytes * 8 / fls(88 * chip->ecc.size);
- break;
- case NAND_ECC_NONE:
- pr_warn("NAND_ECC_NONE selected by board driver. "
- "This is not recommended!\n");
- chip->ecc.read_page = nand_read_page_raw;
- chip->ecc.write_page = nand_write_page_raw;
- chip->ecc.read_oob = nand_read_oob_std;
- chip->ecc.read_page_raw = nand_read_page_raw;
- chip->ecc.write_page_raw = nand_write_page_raw;
- chip->ecc.write_oob = nand_write_oob_std;
- chip->ecc.size = mtd->writesize;
- chip->ecc.bytes = 0;
- chip->ecc.strength = 0;
- break;
- default:
- pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode);
- BUG();
- }
- /* For many systems, the standard OOB write also works for raw */
- if (!chip->ecc.read_oob_raw)
- chip->ecc.read_oob_raw = chip->ecc.read_oob;
- if (!chip->ecc.write_oob_raw)
- chip->ecc.write_oob_raw = chip->ecc.write_oob;
- /*
- * The number of bytes available for a client to place data into
- * the out of band area.
- */
- chip->ecc.layout->oobavail = 0;
- for (i = 0; chip->ecc.layout->oobfree[i].length
- && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)
- chip->ecc.layout->oobavail +=
- chip->ecc.layout->oobfree[i].length;
- mtd->oobavail = chip->ecc.layout->oobavail;
- /*
- * Set the number of read / write steps for one page depending on ECC
- * mode.
- */
- chip->ecc.steps = mtd->writesize / chip->ecc.size;
- if (chip->ecc.steps * chip->ecc.size != mtd->writesize) {
- pr_warn("Invalid ECC parameters\n");
- BUG();
- }
- chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
- //subpage相关的初始化
- /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
- if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
- !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
- switch (chip->ecc.steps) {
- case 2:
- mtd->subpage_sft = 1;
- break;
- case 4:
- case 8:
- case 16:
- mtd->subpage_sft = 2;
- break;
- }
- }
- chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
- /* Initialize state */
- chip->state = FL_READY;
- /* Invalidate the pagebuffer reference */
- chip->pagebuf = -1;
- //本开发板用不到
- /* Large page NAND with SOFT_ECC should support subpage reads */
- if ((chip->ecc.mode == NAND_ECC_SOFT) && (chip->page_shift > 9))
- chip->options |= NAND_SUBPAGE_READ;
- //初始化剩余的mtd_info结构题
- /* Fill in remaining MTD driver data */
- mtd->type = MTD_NANDFLASH;
- mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
- MTD_CAP_NANDFLASH;
- mtd->_erase = nand_erase;
- mtd->_point = NULL;
- mtd->_unpoint = NULL;
- mtd->_read = nand_read;
- mtd->_write = nand_write;
- mtd->_panic_write = panic_nand_write;
- mtd->_read_oob = nand_read_oob;
- mtd->_write_oob = nand_write_oob;
- mtd->_sync = nand_sync;
- mtd->_lock = NULL;
- mtd->_unlock = NULL;
- mtd->_suspend = nand_suspend;
- mtd->_resume = nand_resume;
- mtd->_block_isbad = nand_block_isbad;
- mtd->_block_markbad = nand_block_markbad;
- mtd->writebufsize = mtd->writesize;
- //把chip中的ecc信息传递给mtd结构题,初始化mtd_info
- /* propagate ecc info to mtd_info */
- mtd->ecclayout = chip->ecc.layout;
- mtd->ecc_strength = chip->ecc.strength;
- /*
- * Initialize bitflip_threshold to its default prior scan_bbt() call.
- * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
- * properly set.
- */
- if (!mtd->bitflip_threshold)
- mtd->bitflip_threshold = mtd->ecc_strength;
- /* Check, if we should skip the bad block table scan */
- //判断是否跳过坏块表检测
- if (chip->options & NAND_SKIP_BBTSCAN)
- return 0;
- /* Build bad block table *///扫描并建立坏块表
- return chip->scan_bbt(mtd);
- }
- EXPORT_SYMBOL(nand_scan_tail);
- </pre><br>
- <pre></pre>
- <pre></pre>