uboot中nand flash代码分析(1)

来源:互联网 发布:mac系统截图 编辑:程序博客网 时间:2024/05/21 07:08

本文主要分析uboot中nand flash初始化部分的代码,主要是driver/mtd/nand/nand.c中的nand_init()函数。nand flash bbt建立部分的代码后面再分析。

(一)nand flash 相关的参数

#define CONFIG_CMD_NAND 1#define CONFIG_SYS_MAX_NAND_DEVICE 1#define CONFIG_SYS_NAND_BASE 0xB0000000#define CONFIG_SYS_NAND_ALE_ADDR (1 << 10)#define CONFIG_SYS_NAND_CLE_ADDR (1 << 12)#define CONFIG_SYS_NO_FLASH 1#define CONFIG_ENV_IS_IN_NAND 1#define CONFIG_ENV_OFFSET 0x40000#define CONFIG_ENV_OFFSET_REDUND 0x60000#define CONFIG_ENV_OVERWRITE 1#define NAND_MAX_CHIPS 1#define CONFIG_SYS_NAND_RB_BIT 18#define CONFIG_SYS_NAND_RB_PORT 0xC2104200
(二)初始化
初始化流程如下:
start_armboot
    -->nand_init                driver/mtd/nand/nand.c
        -->nand_init_chip       driver/mtd/nand/nand.c
            -->board_nand_init  (和具体开发板有关,board/xxx/yyy/nand.c)

            -->nand_scan         driver/mtd/nand/nand_base.c

一、start_armboot()和nand_init()

void start_armboot (void)  {      ...      #if defined(CONFIG_CMD_NAND)          puts ("NAND:  ")//注释1        nand_init(); /* go init the NAND */      #endif     ...  }  void nand_init(void)  {      int i;      unsigned int size = 0;      for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { //注释2        nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);//注释 3 4 5          size += nand_info[i].size / 1024;  //注释6        if (nand_curr_device == -1)  //注释7            nand_curr_device = i;      }      printf("%u MiB\n", size / 1024);//注释1} 

1.上述两行打印语句,会在串口上打印NAND: XXX MiB字样,如NAND: 128 MiB

2. CONFIG_SYS_MAX_NAND_DEVICE表示系统有几块nand设备,一般只有1块。

    该宏定义会影响下面数组的大小:

    nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];    static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];    static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE];

3.有两个主要的数据结构struct mtd_info和 struct nand_chip。里面存放着nand flash

  的sizeerasesizewritesizeoobsizeecc布局等属性,和操作nand flash所需

  的readwriteerase等函数。nand_chip中变量的含义的详细注释在

    Include/linux/mtd/nand.h中。初始化的目的就是初始化这两个数据结构。

4. Nand_infomtd_info同义,typedef struct mtd_info nand_info_t;

5. base_addressnand flash的基地址,和硬件有关。可以通过定义

    CONFIG_SYS_NAND_BASE_LIST或者 CONFIG_SYS_NAND_BASE

  来设置 base_address的值。

6.nand_info.size是整个MTD的大小(Total size of the MTD),单位是Byte

  当系统只有一个nand flash作为静态存储器时,该变量等于nand flash的总大小。

7.nand_curr_device表示正在使用的nand flash在数组nand_info[]中的位置。

   用户想要显示当前nand flash的信息时,可以在uboot命令行输入

#nand device

    Uboot就会调用nand_print_info(nand_curr_device);函数来显示当前nand flash的信息。

二、nand_init_chip()

static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,   ulong base_addr){int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;int __attribute__((unused)) i = 0; if (maxchips < 1)maxchips = 1;//建立两个重要数据结构之间的关系。mtd_info的priv指针指向nand_chipmtd->priv = nand;  nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;//设置读写地址//初始化与硬件相关的函数,如片选,cmd_ctrl等函数if (board_nand_init(nand) == 0) {//利用片选,cmd_ctrl等函数,读取nand flash的信息,并存放在mtd_info和nand_chip数据结构中。     if (nand_scan(mtd, maxchips) == 0) {          if (!mtd->name) //nand_scan会设置该变量,若没设置,就用默认值              mtd->name = (char *)default_nand_name;#ifndef CONFIG_RELOC_FIXUP_WORKS          else              mtd->name += gd->reloc_off;#endif #ifdef CONFIG_MTD_DEVICE   /*   * Add MTD device so that we can reference it later   * via the mtdcore infrastructure (e.g. ubi).   */     //若定义 CONFIG_MTD_DEVICE,则强制修改mtd->name为”nandx”  sprintf(dev_name[i], "nand%d", i);  mtd->name = dev_name[i++];  add_mtd_device(mtd);//在数组mtd_table中查找一个空闲位置,并占用之。#endif     } else     mtd->name = NULL;  } else {    mtd->name = NULL;    mtd->size = 0;  }}
三、board_nand_init()

    board_nand_init()函数主要初始化与硬件相关的函数,如片选,cmd_ctrl等函数。

    当我们移植uboot nand flash代码时,主要工作就是修改或者重写该函数。

   下面代码中的”yyy”,一般是指板子型号或者具体nand flash的型号。

int board_nand_init(struct nand_chip *nand){    nand->cmd_ctrl = yyy_nand_hwcontrol;// 注释1    nand->dev_ready = yyy_nand_readybusy;// 注释2    nand->select_chip = yyy_nand_select_chip;    nand->chip_delay = 100; // 注释3    nand->ecc.mode = NAND_ECC_SOFT;  // 注释4    nand->options = NAND_USE_FLASH_BBT | NAND_NO_READRDY;// 注释5}

1.当向nand flash发送命令或数据时,需要拉高CLE或者ALE,该动作

  就是由nand->cmd_ctrl函数来实现。

    本例中,yyy_nand_hwcontrol()源码大致如下:

static void yyy_nand_hwcontrol(struct mtd_info *mtd, int dat,unsigned int ctrl){    struct nand_chip *chip = mtd->priv;    void *IO_ADDR_W = chip->IO_ADDR_W;    if (ctrl & NAND_CLE) // flash的CLE引脚接在CPU的ADDR21引脚        IO_ADDR_W += CONFIG_SYS_NAND_CLE_ADDR;     if (ctrl & NAND_ALE) // flash的ALE引脚接在CPU的ADDR24引脚        IO_ADDR_W += CONFIG_SYS_NAND_ALE_ADDR;     if (dat != NAND_CMD_NONE) {        if (chip->options & NAND_BUSWIDTH_16)//flash数据线宽度是8 还是16            writew((unsigned short)dat, IO_ADDR_W);        else            writeb((unsigned char)dat, IO_ADDR_W);    }}

      如发送reset指令,需调用chip->cmd_ctrl(mtd,NAND_CMD_RESET, NAND_CLE);

      因为ctrl 等于NAND_CLE,所以NAND_CMD_RESET会发到

      (IO_ADDR_W + CONFIG_SYS_NAND_CLE_ADDR)地址上,即ADDR21会出现高电平,

   刚好满足发送命令时,CLE引脚是高电平的条件。

2.该函数可以为空,即不检测nand flashR/B引脚。而通过读取状态寄存器

  来判断flash是否空闲,或者不检测flash是否空闲,而仅仅等待一段时间。

3.等待时间,需要参考flash的数据手册,不能太小,否则会出错。

  有次设置太小,导致读取环境变量和内核时总是提示ecc错误。

4.计算ECC的方式,很重要

5.设置BBT存放方式,读操作时是否检测R/B状态等,很重要。

四、Nand_scan()

  Nand_scan()函数分为两部分。

int nand_scan(struct mtd_info *mtd, int maxchips){    int ret;    ret = nand_scan_ident(mtd, maxchips);    if (!ret)       ret = nand_scan_tail(mtd);    return ret;}


五、nand_scan_ident()

  首先将mtd_info和 nand_chip中还没初始化的函数,初始化为默认函数,

    然后读取flashID,获取flash的信息,并计算出flash的总容量,块大小等信息,

  并根据这些信息将mtd_info和 nand_chip设置为合适的值。

int nand_scan_ident(struct mtd_info *mtd, int maxchips){    int i, busw, nand_maf_id;    struct nand_chip *chip = mtd->priv;    struct nand_flash_dev *type;     /* Get buswidth to select the correct functions */    busw = chip->options & NAND_BUSWIDTH_16;//判断flash数据总线的宽度    /* Set the default functions */    nand_set_defaults(chip, busw);见六     /* Read the flash type */    type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);见七     if (IS_ERR(type)) {        chip->select_chip(mtd, -1);        return PTR_ERR(type);    }     /* 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) ||            type->id != chip->read_byte(mtd))            break;        }    /* Store the number of chips and calc total size for mtd */    chip->numchips = i;     mtd->size = i * chip->chipsize;    //只有一块nand flash时,i等于1,mtd总大小就等于flash的总容量。     return 0;}

六、nand_set_defaults()

    将nand_chip中还没初始化的函数初始化为默认值。

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 */    //仔细研究下nand_command,会有助于理解chip->chip_delay和chip->dev_ready函数的    //含义,如果是大页flash,nand_get_flash_type()会将chip->cmdfunc 修改为     //nand_command_lp()    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->verify_buf)        chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;    if (!chip->scan_bbt)        chip->scan_bbt = nand_default_bbt;     if (!chip->controller) {        chip->controller = &chip->hwcontrol;    }} 
七、nand_get_flash_type()

static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  struct nand_chip *chip,  int busw, int *maf_id){struct nand_flash_dev *type = NULL;int i, dev_id, maf_idx;int tmp_id, tmp_manf;/* Select the device */chip->select_chip(mtd, 0); /** Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)* after power-up*///调用nand_command(),reset flash。chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* Send the command for reading device ID */chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);//读取 flash ID/* Read manufacturer and device IDs */*maf_id = chip->read_byte(mtd);dev_id = chip->read_byte(mtd);/* Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a * possibly credible NAND flash to appear. If the two results do * not match, ignore the device completely. *///再次读取 flash IDchip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ tmp_manf = chip->read_byte(mtd);tmp_id = chip->read_byte(mtd); //比较两次所读的 flash ID是否一致if (tmp_manf != *maf_id || tmp_id != dev_id) {printk(KERN_INFO "%s: second ID read did not match "       "%02x,%02x against %02x,%02x\n", __func__,       *maf_id, dev_id, tmp_manf, tmp_id);return ERR_PTR(-ENODEV);} /*nand_flash_ids[]保存着uboot所支持的nand flash的*name,id,pagesize,chipsize,erasesize,options 等信息。*下面的for循环,从该数组中查找和自身ID相等的元素*//* Lookup the flash id */for (i = 0; nand_flash_ids[i].name != NULL; i++) {if (dev_id == nand_flash_ids[i].id) {type =  &nand_flash_ids[i];break;}} if (!type) {/* supress warning if there is no nand */if (*maf_id != 0x00 && *maf_id != 0xff &&    dev_id  != 0x00 && dev_id  != 0xff)printk(KERN_INFO "%s: unknown NAND device: ""Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",__func__, *maf_id, dev_id);return ERR_PTR(-ENODEV);}//找到了,如“ {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},”//设置mtd->name,该变量有可能被强制修改为nandx if (!mtd->name)mtd->name = type->name;//根据数组中的参数,设置flash的总容量,128Mchip->chipsize = (uint64_t)type->chipsize << 20;//若pagesize为0,表示需要继续读取ID,从ID中计算其他参数,而不是从 //nand_flash_ids[]中获取。/* Newer devices have all the information in additional id bytes */if (!type->pagesize) {int extid;/* The 3rd id byte holds MLC / multichip data */chip->cellinfo = chip->read_byte(mtd);/* The 4th id byte is the important one */// 4th id byte的含义见图一,本例用的nand flash是K9F1G08Q0A,读取到的是0x15,extid = chip->read_byte(mtd); /* Calc pagesize *///bit0,bit1为0,pagesize就是1024<<1=1024;为1,pagesize就是1024<<1=2048//writesize等于pagesize,因为每次写都是以页为单位。2048mtd->writesize = 1024 << (extid & 0x3);extid >>= 2;/* Calc oobsize *///writesize>>9算出几个512bytes,每512bytes对应8个还是16个oob区是由//(8 << (extid & 0x01))算得,两者相乘就得oob的总大小,16*4=64mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);extid >>= 2;/* Calc blocksize. Blocksize is multiples of 64KiB *///块大小或者擦除大小 64*1024*2=128KBmtd->erasesize = (64 * 1024) << (extid & 0x03);extid >>= 2;/* Get buswidth information *///总线宽度为8busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;} else {/* * Old devices have chip data hardcoded in the device id table */mtd->erasesize = type->erasesize;mtd->writesize = type->pagesize;mtd->oobsize = mtd->writesize / 32;busw = type->options & NAND_BUSWIDTH_16;} /* Try to identify manufacturer *///根据制造商ID,获取制造商名称,0xec对应Samsungfor (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {if (nand_manuf_ids[maf_idx].id == *maf_id)break;} /* * Check, if buswidth is correct. Hardware drivers should set * chip correct ! */if (busw != (chip->options & NAND_BUSWIDTH_16)) {printk(KERN_INFO "NAND device: Manufacturer ID:"       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,       dev_id, nand_manuf_ids[maf_idx].name, mtd->name);printk(KERN_WARNING "NAND bus width %d instead %d bit\n",       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,       busw ? 16 : 8);return ERR_PTR(-EINVAL);} /* Calculate the address shift from the page size *///给出一个地址,利用该变量可以直接得出 该地址是第几页。//如 realpage = (int)(address>> chip->page_shift);chip->page_shift = ffs(mtd->writesize) - 1;/* Convert chipsize to number of pages per chip -1. *///chip->pagemask是总页数减1,用来防止要读写的页号不超过总页数// page = realpage & chip->pagemask;chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; //给出一个地址,利用该变量可以直接得出 该地址是第几块。chip->bbt_erase_shift = chip->phys_erase_shift =ffs(mtd->erasesize) - 1; //给出一个地址,利用该变量可以直接得出 该地址是第几个flash设备。if (chip->chipsize & 0xffffffff)chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;elsechip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31; /* Set the bad block position *///坏块位置,后面讲到ECC时会用到chip->badblockpos = mtd->writesize > 512 ?NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; //设置chip->options/* Get chip options, preserve non chip based options */chip->options &= ~NAND_CHIPOPTIONS_MSK;chip->options |= type->options & NAND_CHIPOPTIONS_MSK; /* * Set chip as a default. Board drivers can override it, if necessary */chip->options |= NAND_NO_AUTOINCR; /* Check if chip is a not a samsung device. Do not clear the * options for chips which are not having an extended id. */if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; //修改默认的函数为合适的函数/* Check for AND chips with 4 page planes */if (chip->options & NAND_4PAGE_ARRAY)chip->erase_cmd = multi_erase_cmd;elsechip->erase_cmd = single_erase_cmd;//如果是大页flash,则修改chip->cmdfunc 为 nand_command_lp()/* Do not replace user supplied command function ! */if (mtd->writesize > 512 && chip->cmdfunc == nand_command)chip->cmdfunc = nand_command_lp; MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:"          " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,          nand_manuf_ids[maf_idx].name, type->name); return type;}

                                                                      

                                                                                                                                     图一

 七、nand_scan_tail()

      nand_scan_tail()继续初始化mtd_infonand_info数据结构,主要初始化和ECC有关的变量和函数。

int nand_scan_tail(struct mtd_info *mtd){int i;struct nand_chip *chip = mtd->priv; //分配buffers,用于临时存放从flash读取的数据,见nand_do_read_ops()函数if (!(chip->options & NAND_OWN_BUFFERS))chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);if (!chip->buffers)return -ENOMEM; //oob紧跟着数据存放/* 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) {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;//注释1break;case 128:chip->ecc.layout = &nand_oob_128;break;default:printk(KERN_WARNING "No oob scheme defined for "       "oobsize %d\n", mtd->oobsize);}}//初始化和ECC有关的函数if (!chip->write_page)chip->write_page = nand_write_page; /* * check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ 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) {printk(KERN_WARNING "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)) {printk(KERN_WARNING "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)break;printk(KERN_WARNING "%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;chip->ecc.size = 256;//每256bit 产生3bit的ECCchip->ecc.bytes = 3;break; case NAND_ECC_NONE:printk(KERN_WARNING "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;break; default:printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",       chip->ecc.mode);BUG();} /* * The number of bytes available for a client to place data into * the out of band area *///可用的oob大小,即nand_oob_64中所设置的>oobfree的总和,本例是38bitchip->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) {printk(KERN_WARNING "Invalid ecc parameters\n");BUG();}chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; /* * 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;}}//计算子页大小,即每次读flash时,最小需要读取的数据。为了检测数据是否有误,需//要至少读取一个单位的ECC对应的数据大小。chip->subpagesize = mtd->writesize >> mtd->subpage_sft; /* Initialize state */chip->state = FL_READY; /* De-select the device */chip->select_chip(mtd, -1); //该变量应该是表示chip->buffers中的数据是第几页的数据。//读flash之前,需要先判断所读的页的数据是否已在chip->buffers中,是则,直接从  //buffers中读取/* Invalidate the pagebuffer reference */chip->pagebuf = -1; //设置默认函数和变量/* Fill in remaining MTD driver data */mtd->type = MTD_NANDFLASH;mtd->flags = MTD_CAP_NANDFLASH;mtd->erase = nand_erase;mtd->point = NULL;mtd->unpoint = NULL;mtd->read = nand_read;mtd->write = 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; /* propagate ecc.layout to mtd_info */mtd->ecclayout = chip->ecc.layout; //如果定义NAND_SKIP_BBTSCAN,则设置BBT“已扫描过”。以后会跳过BBT扫描,/* Check, if we should skip the bad block table scan */if (chip->options & NAND_SKIP_BBTSCAN)chip->options |= NAND_BBT_SCANNED; return 0;} 


1.本例oobsize等于64,从下面结构可以看出oob区的结构

static struct nand_ecclayout nand_oob_64 = {    .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 = {       {.offset = 2,        .length = 38}}       };

   前两位有其他作用,从第2位开始,到第39位,一共38位是空闲的。从40位到63位共24位存放ECC数据,每256bytes对应3bytesECC,一页2048bytes,共24bytesECC

 




0 0
原创粉丝点击