Chinaunix首页 | 论坛 | 博客
  • 博客访问: 480063
  • 博文数量: 100
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 955
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-21 09:30
文章分类

全部博文(100)

文章存档

2017年(1)

2016年(16)

2015年(83)

我的朋友

分类: 嵌入式

2015-09-11 19:28:53

首先看几个全局变量,这些全局变量记录了nand设备的信息,并提供了驱动操作接口。
本文是基于s5pv210的uboot撰写的,mtd框架是通用的,其他cpu也类似。

typedef struct mtd_info nand_info_t;//记住,nand_info_t 就是mtd_info 结构体
int nand_curr_device = -1;
nand_info_t nand_info[CFG_MAX_NAND_DEVICE];//CFG_MAX_NAND_DEVICE配置为1
static struct nand_chip nand_chip[CFG_MAX_NAND_DEVICE];

看程序首先从入口看,无论是uboot还是linux内核,所有的设备(包括实际或抽象的)操作,必须注册该设备,也就是进行设备结构体初始化。
nand驱动的入口就是nand_init。
nand_init->
nand_init_chip->
board_nand_init(nand);//读nand id,初始化nand结构体 nand->ecc nand操作函数,如果是id = d5,默认8bitecc,如果没有匹配的nand id,默认1bitecc

    if (nand_scan(mtd, 1) == 0) {
    
                ret = nand_scan_ident(mtd, maxchips);
        if (!ret)
            ret = nand_scan_tail(mtd);
    
add_mtd_device,这一步很关键了,mtd->write怎么来的就看这里了。

s5pv210烧写uboot、logo、内核等分区使用8bitecc,只有烧写yaffs使用1bitecc(通过命令nand write.OEMyaffs)。

 重新缕一下初始化流程:
先初始化nand_chip再初始化mtd(即nand_info),其中nand_init_chipnand_chip挂在mtd->priv指针上, board_nand_init负责初始化nand_chip.ecc成员函数,nand_set_defaults(chip, busw);负责初始化mtd->priv(nand_chip)的剩余其他成员/函数,nand_scan_ident->nand_get_flash_type负责获取初始化部分mtd信息(大小、oobsize、writesize等),nand_scan_tail负责初始化mtd的第一层操作函数(write_oob等)和chip的write_page等函数

带oob的读写操作:
oob操作通常是mtd_write_oob调用mtd->_write_oob或mtd->_read_oob函数,该函数读写页数据同时读写OOB。
nand_scan_tail函数初始化对_write_oob函数指针进行初始化:
    mtd->write_oob = nand_write_oob;
nand_write_oob_>nand_do_write_oob
初始化完整路线是    nand_init->nand_init_chip -> nand_scan>nand_scan_tail



点击(此处)折叠或打开

  1. void nand_init(void)
  2. {
  3.     int i;
  4.     unsigned int size = 0;
  5.     for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
  6.         nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
  7.         size += nand_info[i].size;
  8.         if (nand_curr_device == -1)
  9.             nand_curr_device = i;
  10.     }
  11. #ifndef CONFIG_DIS_BOARD_INFO
  12.     printf("%d MB ", size / (1024 * 1024));

  13. #if defined(CFG_NAND_FLASH_BBT)
  14.     printf("(Flash Based BBT Enabled)");
  15. #endif

  16.     printf("\n");
  17. #endif /* CONFIG_DIS_BOARD_INFO */
  18. #ifdef CFG_NAND_SELECT_DEVICE
  19.     /*
  20.      * Select the chip in the board/cpu specific driver
  21.      */
  22.     board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
  23. #endif
  24. }

点击(此处)折叠或打开

  1. static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
  2.              ulong base_addr)
  3. {
  4.     mtd->priv = nand;

  5.     nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;
  6.     board_nand_init(nand);

  7.     if (nand_scan(mtd, 1) == 0) {
  8.         if (!mtd->name)
  9.             mtd->name = (char *)default_nand_name;

  10. #ifdef CONFIG_MTD_DEVICE
  11.         /*
  12.          * Add MTD device so that we can reference it later
  13.          * via the mtdcore infrastructure (e.g. ubi).
  14.          */
  15.         mtd->name = dev_name;
  16.         add_mtd_device(mtd);
  17. #endif
  18.     } else
  19.         mtd->name = NULL;

  20. }

点击(此处)折叠或打开

  1. int nand_scan(struct mtd_info *mtd, int maxchips)
  2. {
  3.     int ret;

  4. #if 0
  5.     /* Many callers got this wrong, so check for it for a while... */
  6.     if (!mtd->owner && caller_is_module()) {
  7.         printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
  8.         BUG();
  9.     }
  10. #endif

  11.     ret = nand_scan_ident(mtd, maxchips);
  12.     if (!ret)
  13.         ret = nand_scan_tail(mtd);
  14.     return ret;
  15. }
nand_scan_ident负责扫描nand设备的id。

点击(此处)折叠或打开

  1. /**
  2.  * nand_scan_ident - [NAND Interface] Scan for the NAND device
  3.  * @mtd:     MTD device structure
  4.  * @maxchips:     Number of chips to scan for
  5.  *
  6.  * This is the first phase of the normal nand_scan() function. It
  7.  * reads the flash ID and sets up MTD fields accordingly.
  8.  *
  9.  * The mtd->owner field must be set to the module of the caller.
  10.  */
  11. int nand_scan_ident(struct mtd_info *mtd, int maxchips)
  12. {
  13.     int i, busw, nand_maf_id;
  14.     struct nand_chip *chip = mtd->priv;
  15.     struct nand_flash_dev *type;

  16.     /* Get buswidth to select the correct functions */
  17.     busw = chip->options & NAND_BUSWIDTH_16;
  18.     /* Set the default functions */
  19.     nand_set_defaults(chip, busw);

  20.     /* Read the flash type */
  21.     type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);

  22.     if (!type) {
  23.         // printk (KERN_WARNING "No NAND device found!!!\n");
  24.         chip->select_chip(mtd, -1);
  25.         return 1;
  26.     }

  27.     /* Check for a chip array */
  28.     for (i = 1; i < maxchips; i++) {
  29.         chip->select_chip(mtd, i);
  30.         /* Send the command for reading device ID */
  31.         chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
  32.         /* Read manufacturer and device IDs */
  33.         if (nand_maf_id != chip->read_byte(mtd) ||
  34.          type->id != chip->read_byte(mtd))
  35.             break;
  36.     }
  37.     if (i > 1)
  38.         printk(KERN_INFO "%d NAND chips detected\n", i);

  39.     /* Store the number of chips and calc total size for mtd */
  40.     chip->numchips = i;
  41.     mtd->size = i * chip->chipsize;

  42.     return 0;
  43. }
nand_scan_tail用于检查mtd操作函数,如果之前在board_nand_init函数中没有初始化nand操作接口指针,则在会使用默认函数初始化nand操作指针。最后扫描坏块。

点击(此处)折叠或打开

  1. /**
     * nand_scan_tail - [NAND Interface] Scan for the NAND device
     * @mtd:        MTD device structure
     * @maxchips:        Number of chips to scan for
     *
     * This is the second phase of the normal nand_scan() function. It
     * fills out all the uninitialized function pointers with the defaults
     * and scans for a bad block table if appropriate.
     */
  2. int nand_scan_tail(struct mtd_info *mtd)
  3. {
  4.     int i;
  5.     struct nand_chip *chip = mtd->priv;

  6.     if (!(chip->options & NAND_OWN_BUFFERS))
  7.         chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
  8.     if (!chip->buffers)
  9.         return -ENOMEM;

  10.     /* Set the internal oob buffer location, just after the page data */
  11.     chip->oob_poi = chip->buffers->databuf + mtd->writesize;

  12.     /*
  13.      * If no default placement scheme is given, select an appropriate one
  14.      */
  15.     if (!chip->ecc.layout) {
  16.         switch (mtd->oobsize) {
  17.         case 8:
  18.             chip->ecc.layout = &nand_oob_8;
  19.             break;
  20.         case 16:
  21.             chip->ecc.layout = &nand_oob_16;
  22.             break;
  23.         case 64:
  24.             chip->ecc.layout = &nand_oob_64;
  25.             break;
  26.         case 128:
  27.             chip->ecc.layout = &nand_oob_128;
  28.             break;
  29.         case 218:
  30.             chip->ecc.layout = &nand_oob_218;
  31.             break;
  32.         default:
  33.             printk(KERN_WARNING "No oob scheme defined for "
  34.              "oobsize %d\n", mtd->oobsize);
  35.             BUG();
  36.         }
  37.     }

  38.     if (!chip->write_page)
  39.         chip->write_page = nand_write_page;

  40.     /*
  41.      * check ECC mode, default to software if 3byte/512byte hardware ECC is
  42.      * selected and we have 256 byte pagesize fallback to software ECC
  43.      */
  44.     if (!chip->ecc.read_page_raw)
  45.         chip->ecc.read_page_raw = nand_read_page_raw;
  46.     if (!chip->ecc.write_page_raw)
  47.         chip->ecc.write_page_raw = nand_write_page_raw;

  48.     switch (chip->ecc.mode) {
  49.     case NAND_ECC_HW:
  50.         /* Use standard hwecc read page function ? */
  51.         if (!chip->ecc.read_page)
  52.             chip->ecc.read_page = nand_read_page_hwecc;
  53.         if (!chip->ecc.write_page)
  54.             chip->ecc.write_page = nand_write_page_hwecc;
  55.         if (!chip->ecc.read_oob)
  56.             chip->ecc.read_oob = nand_read_oob_std;
  57.         if (!chip->ecc.write_oob)
  58.             chip->ecc.write_oob = nand_write_oob_std;

  59.     case NAND_ECC_HW_SYNDROME:
  60.         if (!chip->ecc.calculate || !chip->ecc.correct ||
  61.          !chip->ecc.hwctl) {
  62.             printk(KERN_WARNING "No ECC functions supplied, "
  63.              "Hardware ECC not possible\n");
  64.             BUG();
  65.         }
  66.         /* Use standard syndrome read/write page function ? */
  67.         if (!chip->ecc.read_page)
  68.             chip->ecc.read_page = nand_read_page_syndrome;
  69.         if (!chip->ecc.write_page)
  70.             chip->ecc.write_page = nand_write_page_syndrome;
  71.         if (!chip->ecc.read_oob)
  72.             chip->ecc.read_oob = nand_read_oob_syndrome;
  73.         if (!chip->ecc.write_oob)
  74.             chip->ecc.write_oob = nand_write_oob_syndrome;

  75.         if (mtd->writesize >= chip->ecc.size)
  76.             break;
  77.         printk(KERN_WARNING "%d byte HW ECC not possible on "
  78.          "%d byte page size, fallback to SW ECC\n",
  79.          chip->ecc.size, mtd->writesize);
  80.         chip->ecc.mode = NAND_ECC_SOFT;

  81.     case NAND_ECC_SOFT:
  82.         chip->ecc.calculate = nand_calculate_ecc;
  83.         chip->ecc.correct = nand_correct_data;
  84.         chip->ecc.read_page = nand_read_page_swecc;
  85.         chip->ecc.write_page = nand_write_page_swecc;
  86.         chip->ecc.read_oob = nand_read_oob_std;
  87.         chip->ecc.write_oob = nand_write_oob_std;
  88.         chip->ecc.size = 256;
  89.         chip->ecc.bytes = 3;
  90.         break;

  91.     case NAND_ECC_NONE:
  92.         printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
  93.          "This is not recommended !!\n");
  94.         chip->ecc.read_page = nand_read_page_raw;
  95.         chip->ecc.write_page = nand_write_page_raw;
  96.         chip->ecc.read_oob = nand_read_oob_std;
  97.         chip->ecc.write_oob = nand_write_oob_std;
  98.         chip->ecc.size = mtd->writesize;
  99.         chip->ecc.bytes = 0;
  100.         break;

  101.     default:
  102.         printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
  103.          chip->ecc.mode);
  104.         BUG();
  105.     }

  106.     /*
  107.      * The number of bytes available for a client to place data into
  108.      * the out of band area
  109.      */
  110.     chip->ecc.layout->oobavail = 0;
  111.     for (i = 0; chip->ecc.layout->oobfree[i].length; i++)
  112.         chip->ecc.layout->oobavail +=
  113.             chip->ecc.layout->oobfree[i].length;

  114.     /*
  115.      * Set the number of read / write steps for one page depending on ECC
  116.      * mode
  117.      */
  118.     chip->ecc.steps = mtd->writesize / chip->ecc.size;
  119.     if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
  120.         printk(KERN_WARNING "Invalid ecc parameters\n");
  121.         BUG();
  122.     }
  123.     chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;

  124.     /*
  125.      * Allow subpage writes up to ecc.steps. Not possible for MLC
  126.      * FLASH.
  127.      */
  128.     if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
  129.      !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
  130.         switch(chip->ecc.steps) {
  131.         case 2:
  132.             mtd->subpage_sft = 1;
  133.             break;
  134.         case 4:
  135.         case 8:
  136.             mtd->subpage_sft = 2;
  137.             break;
  138.         }
  139.     }
  140.     chip->subpagesize = mtd->writesize >> mtd->subpage_sft;

  141. /* XXX U-BOOT XXX */
  142. #if 0
  143.     /* Initialize state */
  144.     chip->state = FL_READY;
  145. #endif

  146.     /* De-select the device */
  147.     chip->select_chip(mtd, -1);

  148.     /* Invalidate the pagebuffer reference */
  149.     chip->pagebuf = -1;

  150.     /* Fill in remaining MTD driver data */
  151.     mtd->type = MTD_NANDFLASH;
  152.     mtd->flags = MTD_CAP_NANDFLASH;
  153.     mtd->ecctype = MTD_ECC_SW;
  154.     mtd->erase = nand_erase;
  155.     mtd->point = NULL;
  156.     mtd->unpoint = NULL;
  157.     mtd->read = nand_read;
  158.     mtd->write = nand_write;
  159.     mtd->read_oob = nand_read_oob;
  160.     mtd->write_oob = nand_write_oob;
  161.     mtd->sync = nand_sync;
  162.     mtd->lock = NULL;
  163.     mtd->unlock = NULL;
  164.     mtd->suspend = nand_suspend;
  165.     mtd->resume = nand_resume;
  166.     mtd->block_isbad = nand_block_isbad;
  167.     mtd->block_markbad = nand_block_markbad;

  168.     /* propagate ecc.layout to mtd_info */
  169.     mtd->ecclayout = chip->ecc.layout;

  170.     /* Check, if we should skip the bad block table scan */
  171.     if (chip->options & NAND_SKIP_BBTSCAN)
  172.         return 0;

  173.     /* Build bad block table */
  174.     return chip->scan_bbt(mtd);
  175. }

烧写uboot、logo、内核等分区使用8bitecc,只有烧写yaffs使用1bitecc(tftp烧写通过nand write.yaffs,SD卡烧写通过命令nand write.OEMyaffs)。

点击(此处)折叠或打开

  1. static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
  2.              const uint8_t *buf, int page, int cached, int raw)
  3. {
  4.     int status;

  5.     chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);

  6. /* jsgood: org: #else block only */
  7. #if defined(CONFIG_NAND_BL1_8BIT_ECC) && \
  8.         (defined(CONFIG_S3C6430) || \
  9.          defined(CONFIG_S3C2450) || \
  10.          defined(CONFIG_S3C2416) || \
  11.          defined(CONFIG_S5PC100) || \
  12.          defined(CONFIG_S5PC110) || \
  13.          defined(CONFIG_S5PV210) || \
  14.          defined(CONFIG_S5P6440))
  15. #ifdef CONFIG_TQ210
  16.     if ((mtd->writesize == 512 && page < 512) || (mtd->writesize == 2048 && page < 256) ||
  17.         (mtd->writesize == 4096 && page < 128)) {
  18. #else
  19.     if (page < CFG_NAND_PAGES_IN_BLOCK) {
  20. #endif
  21.         memset(chip->oob_poi, 0xff, mtd->oobsize);
  22.         s3c_nand_write_page_8bit(mtd, chip, buf);//烧写bootloader
  23.     } else
  24. #elif defined(CONFIG_NAND_BL1_8BIT_ECC) && defined(CONFIG_S3C6410)
  25.     if (page < CFG_NAND_PAGES_IN_BLOCK) {
  26.         memset(chip->oob_poi, 0xff, mtd->oobsize);
  27.         s3c_nand_write_page_8bit_for_irom(mtd, chip, buf);
  28.     } else
  29. #endif
  30.     {
  31.         if (unlikely(raw))
  32.             chip->ecc.write_page_raw(mtd, chip, buf);
  33.         else
  34.             chip->ecc.write_page(mtd, chip, buf);//烧写其他分区使用1bitecc
  35.     }
实际上烧写u-boot是使用nand_block_write这个函数烧写的。

点击(此处)折叠或打开

  1. //nand_block_write is used to write u-boot
  2. int nand_block_write(struct mtd_info *mtd, loff_t to, size_t len,
  3.         size_t *retlen, const u_char * buf)
  4. {
  5.     struct nand_chip *this = mtd->priv;
  6.     int eraseshift = this->phys_erase_shift;
  7.     int blocks = len >> eraseshift;
  8.     int blocksize = (1 << eraseshift);
  9.     loff_t ofs;
  10.     size_t _retlen = 0;
  11.     int ret;
  12. #if (defined(CONFIG_S5PC110) || defined(CONFIG_S5PV210)) && defined(CONFIG_EVT1) && !defined(CONFIG_FUSED) && !defined(CONFIG_SECURE)
  13.     int i;
  14.     ulong checksum;
  15.     uint8_t *ptr;
  16. #endif

  17.     ofs = to;

  18.     if (ofs & (blocksize - 1)) {
  19.         printk(" ERROR: Starting address 0x%x is not a block start address\n",
  20.                 (unsigned int) ofs);
  21.         return 1;
  22.     }
  23.     if (len & (blocksize - 1)) {
  24.         printk(" ERROR: Length (0x%x) is not block aligned\n", (unsigned int) len);
  25.         return 1;
  26.     }
  27.     printk("Main area read (%d blocks):\n", blocks);

  28. #if (defined(CONFIG_S5PC110) || defined(CONFIG_S5PV210)) && defined(CONFIG_EVT1) && !defined(CONFIG_FUSED) && !defined(CONFIG_SECURE)
  29.     if (to == 0) {
  30.         ptr = buf + 16;
  31.         for(i = 16, checksum = 0; i < 8192; i++) {
  32.             checksum += *ptr;
  33.             ptr++;
  34.         }
  35.         *((volatile u32 *)(buf + 0x8)) = checksum;
  36.         printk("Checksum is calculated.\n");
  37.     }

  38. #endif
  39.     printk("Main area write (%d blocks):\n", blocks);
  40.     *retlen = 0;

  41.     while (blocks) {
  42.         ret = mtd->block_isbad(mtd, ofs);
  43.         if (ret) {
  44.             printk("Bad blocks %d at 0x%x is skipped\n",
  45.              (u32)(ofs >> eraseshift), (u32)ofs);
  46.             goto next;
  47.         }

  48.         ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
  49.         if (ret) {
  50.             printk("Write failed 0x%x, %d", (u32)ofs, ret);
  51.             goto next;
  52.         }

  53.         buf += blocksize;
  54.         blocks--;
  55.         *retlen += _retlen;
  56. next:
  57.         ofs += blocksize;
  58.     }

  59.     return 0;
  60. }
注意ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
为什么mtd->write就是8bitecc烧写?这就回头看当初注册mtd的代码了。
在nand_scan_tail函数最后有一句    mtd->write = nand_write;
nand_write调用nand_do_write_ops

点击(此处)折叠或打开

  1. /**
  2.  * nand_do_write_ops - [Internal] NAND write with ECC
  3.  * @mtd:    MTD device structure
  4.  * @to:        offset to write to
  5.  * @ops:    oob operations description structure
  6.  *
  7.  * NAND write with ECC
  8.  */
  9. static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
  10.              struct mtd_oob_ops *ops)
  11. {
  12.     int chipnr, realpage, page, blockmask, column;
  13.     struct nand_chip *chip = mtd->priv;
  14.     uint32_t writelen = ops->len;
  15.     uint8_t *oob = ops->oobbuf;
  16.     uint8_t *buf = ops->datbuf;
  17.     int ret, subpage;
  18. #if 0
  19.     /* jsgood */
  20.     int percent = 0;
  21.     int percent_complete = 0;
  22. #endif
  23.     ops->retlen = 0;
  24.     if (!writelen)
  25.         return 0;

  26.     /* reject writes, which are not page aligned */
  27.     if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
  28.         printk(KERN_NOTICE "nand_write: "
  29.          "Attempt to write not page aligned data\n");
  30.         return -EINVAL;
  31.     }

  32.     column = to & (mtd->writesize - 1);
  33.     subpage = column || (writelen & (mtd->writesize - 1));

  34.     if (subpage && oob)
  35.         return -EINVAL;

  36.     chipnr = (int)(to >> chip->chip_shift);
  37.     chip->select_chip(mtd, chipnr);

  38.     /* Check, if it is write protected */
  39.     if (nand_check_wp(mtd))
  40.         return -EIO;

  41.     realpage = (int)(to >> chip->page_shift);
  42.     page = realpage & chip->pagemask;
  43.     blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;

  44.     /* Invalidate the page cache, when we write to the cached page */
  45.     if (to <= (chip->pagebuf << chip->page_shift) &&
  46.      (chip->pagebuf << chip->page_shift) < (to + ops->len))
  47.         chip->pagebuf = -1;

  48.     /* If we're not given explicit OOB data, let it be 0xFF */
  49.     if (likely(!oob))
  50.         memset(chip->oob_poi, 0xff, mtd->oobsize);

  51.     while(1) {
  52.         int bytes = mtd->writesize;
  53.         int cached = writelen > bytes && page != blockmask;
  54.         uint8_t *wbuf = buf;

  55.         /* Partial page write ? */
  56.         if (unlikely(column || writelen < (mtd->writesize - 1))) {
  57.             cached = 0;
  58.             bytes = min_t(int, bytes - column, (int) writelen);
  59.             chip->pagebuf = -1;
  60.             memset(chip->buffers->databuf, 0xff, mtd->writesize);
  61.             memcpy(&chip->buffers->databuf[column], buf, bytes);
  62.             wbuf = chip->buffers->databuf;
  63.         }

  64.         if (unlikely(oob))
  65.             oob = nand_fill_oob(chip, oob, ops);

  66.         ret = chip->write_page(mtd, chip, wbuf, page, cached,
  67.                  (ops->mode == MTD_OOB_RAW));
  68.         if (ret)
  69.             break;

  70.         writelen -= bytes;
  71. #if 0
  72.         /* jsgood */
  73.         percent = ((ops->len - writelen) * 100) / ops->len;

  74.         if (percent != percent_complete) {
  75.             printf("\rWriting page at 0x%x -- %d%% complete.", page, percent);
  76.             percent_complete = percent;
  77.         }
  78. #endif
  79.         if (!writelen)
  80.             break;

  81.         column = 0;
  82.         buf += bytes;
  83.         realpage++;

  84.         page = realpage & chip->pagemask;
  85.         /* Check, if we cross a chip boundary */
  86.         if (!page) {
  87.             chipnr++;
  88.             chip->select_chip(mtd, -1);
  89.             chip->select_chip(mtd, chipnr);
  90.         }
  91.     }

  92. #if 0
  93.     /* jsgood */
  94.     printf("\n");
  95. #endif
  96.     ops->retlen = ops->len - writelen;
  97.     if (unlikely(oob))
  98.         ops->oobretlen = ops->ooblen;
  99.     return ret;
  100. }
最后调用了chip->write_page
nand_scan_tail函数中有一句:

点击(此处)折叠或打开

  1. if (!chip->write_page)
  2.     {
  3.         puts("chip->write_page = nand_write_page\n");//richard
  4.         chip->write_page = nand_write_page;}



点击(此处)折叠或打开

  1. static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
  2.              const uint8_t *buf, int page, int cached, int raw)
  3. {
  4.     int status;

  5.     chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);

  6. /* jsgood: org: #else block only */
  7. #if defined(CONFIG_NAND_BL1_8BIT_ECC) && \
  8.         (defined(CONFIG_S3C6430) || \
  9.          defined(CONFIG_S3C2450) || \
  10.          defined(CONFIG_S3C2416) || \
  11.          defined(CONFIG_S5PC100) || \
  12.          defined(CONFIG_S5PC110) || \
  13.          defined(CONFIG_S5PV210) || \
  14.          defined(CONFIG_S5P6440))
  15. #ifdef CONFIG_TQ210
  16.     if ((mtd->writesize == 512 && page < 512) || (mtd->writesize == 2048 && page < 256) ||
  17.         (mtd->writesize == 4096 && page < 128)) {
  18. #else
  19.     if (page < CFG_NAND_PAGES_IN_BLOCK) {
  20. #endif
  21.         memset(chip->oob_poi, 0xff, mtd->oobsize);
  22.         s3c_nand_write_page_8bit(mtd, chip, buf);
  23.     } else
  24. #elif defined(CONFIG_NAND_BL1_8BIT_ECC) && defined(CONFIG_S3C6410)
  25.     if (page < CFG_NAND_PAGES_IN_BLOCK) {
  26.         memset(chip->oob_poi, 0xff, mtd->oobsize);
  27.         s3c_nand_write_page_8bit_for_irom(mtd, chip, buf);
  28.     } else
  29. #endif
  30.     {
  31.         if (unlikely(raw))
  32.             chip->ecc.write_page_raw(mtd, chip, buf);
  33.         else
  34.             chip->ecc.write_page(mtd, chip, buf);
  35.     }

  36.     /*
  37.      * Cached progamming disabled for now, Not sure if its worth the
  38.      * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
  39.      */
  40.     cached = 0;

  41.     if (!cached || !(chip->options & NAND_CACHEPRG)) {

  42.         chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
  43.         status = chip->waitfunc(mtd, chip);
  44.         /*
  45.          * See if operation failed and additional status checks are
  46.          * available
  47.          */
  48.         if ((status & NAND_STATUS_FAIL) && (chip->errstat))
  49.             status = chip->errstat(mtd, chip, FL_WRITING, status,
  50.                      page);

  51.         if (status & NAND_STATUS_FAIL)
  52.             return -EIO;
  53.     } else {
  54.         chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
  55.         status = chip->waitfunc(mtd, chip);
  56.     }

  57. #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
  58.     /* Send command to read back the data */
  59.     chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);

  60.     if (chip->verify_buf(mtd, buf, mtd->writesize))
  61.         return -EIO;
  62. #endif
  63.     return 0;
  64. }
这样就明白了,chip->write_page使用8bitecc,chip->ecc.write_page使用1bitecc。
mtd->write也就是调用chip->write_page使用8bitecc烧写。
另外mtd->write_oob就是执行nand_write_oob->
    if (!ops->datbuf)
        ret = nand_do_write_oob(mtd, to, ops);
    else
        ret = nand_do_write_ops(mtd, to, ops);

点击(此处)折叠或打开

  1. static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
  2.              struct mtd_oob_ops *ops)
  3. {
  4.     int chipnr, realpage, page, blockmask, column;
  5.     struct nand_chip *chip = mtd->priv;
  6.     uint32_t writelen = ops->len;
  7.     uint8_t *oob = ops->oobbuf;
  8.     uint8_t *buf = ops->datbuf;
  9.     int ret, subpage;
  10. #if 0
  11.     /* jsgood */
  12.     int percent = 0;
  13.     int percent_complete = 0;
  14. #endif
  15.     ops->retlen = 0;
  16.     if (!writelen)
  17.         return 0;

  18.     /* reject writes, which are not page aligned */
  19.     if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
  20.         printk(KERN_NOTICE "nand_write: "
  21.          "Attempt to write not page aligned data\n");
  22.         return -EINVAL;
  23.     }

  24.     column = to & (mtd->writesize - 1);
  25.     subpage = column || (writelen & (mtd->writesize - 1));

  26.     if (subpage && oob)
  27.         return -EINVAL;

  28.     chipnr = (int)(to >> chip->chip_shift);
  29.     chip->select_chip(mtd, chipnr);

  30.     /* Check, if it is write protected */
  31.     if (nand_check_wp(mtd))
  32.         return -EIO;

  33.     realpage = (int)(to >> chip->page_shift);
  34.     page = realpage & chip->pagemask;
  35.     blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;

  36.     /* Invalidate the page cache, when we write to the cached page */
  37.     if (to <= (chip->pagebuf << chip->page_shift) &&
  38.      (chip->pagebuf << chip->page_shift) < (to + ops->len))
  39.         chip->pagebuf = -1;

  40.     /* If we're not given explicit OOB data, let it be 0xFF */
  41.     if (likely(!oob))
  42.         memset(chip->oob_poi, 0xff, mtd->oobsize);

  43.     while(1) {
  44.         int bytes = mtd->writesize;
  45.         int cached = writelen > bytes && page != blockmask;
  46.         uint8_t *wbuf = buf;

  47.         /* Partial page write ? */
  48.         if (unlikely(column || writelen < (mtd->writesize - 1))) {
  49.             cached = 0;
  50.             bytes = min_t(int, bytes - column, (int) writelen);
  51.             chip->pagebuf = -1;
  52.             memset(chip->buffers->databuf, 0xff, mtd->writesize);
  53.             memcpy(&chip->buffers->databuf[column], buf, bytes);
  54.             wbuf = chip->buffers->databuf;
  55.         }

  56.         if (unlikely(oob))
  57.             oob = nand_fill_oob(chip, oob, ops);

  58.         ret = chip->write_page(mtd, chip, wbuf, page, cached,
  59.                  (ops->mode == MTD_OOB_RAW));
  60.         if (ret)
  61.             break;

  62.         writelen -= bytes;
  63. #if 0
  64.         /* jsgood */
  65.         percent = ((ops->len - writelen) * 100) / ops->len;

  66.         if (percent != percent_complete) {
  67.             printf("\rWriting page at 0x%x -- %d%% complete.", page, percent);
  68.             percent_complete = percent;
  69.         }
  70. #endif
  71.         if (!writelen)
  72.             break;

  73.         column = 0;
  74.         buf += bytes;
  75.         realpage++;

  76.         page = realpage & chip->pagemask;
  77.         /* Check, if we cross a chip boundary */
  78.         if (!page) {
  79.             chipnr++;
  80.             chip->select_chip(mtd, -1);
  81.             chip->select_chip(mtd, chipnr);
  82.         }
  83.     }

  84. #if 0
  85.     /* jsgood */
  86.     printf("\n");
  87. #endif
  88.     ops->retlen = ops->len - writelen;
  89.     if (unlikely(oob))
  90.         ops->oobretlen = ops->ooblen;
  91.     return ret;
  92. }
总结:
烧写boot、内核采用8bitecc,流程:
mtd->write > nand_write > nand_do_write_ops > chip->write_page > chip->write_page > s3c_nand_write_page_8bit(mtd, chip, buf);
烧写yaffs镜像采用1bitecc,流程:
nand_OEM_write_opts(nand, &opts,Dir) > meminfo->write_oob >
nand_write_oob->
    if (!ops->datbuf)
        ret = nand_do_write_oob(mtd, to, ops);
    else
        ret = nand_do_write_ops(mtd, to, ops);
nand_do_write_ops  >  chip->write_page  > 

chip->write_page使用8bitecc,chip->ecc.write_page使用1bitecc。
mtd->write也就是调用chip->write_page使用8bitecc烧写。

烧写函数选择:
在源数据不包含OOB的情况下使用mtd->write即nand_write函数,在源数据含有OOB(yaffs镜像)的情况下使用write_oob即nand_write_oob函数
阅读(2552) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~