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

全部博文(100)

文章存档

2017年(1)

2016年(16)

2015年(83)

我的朋友

分类: 嵌入式

2015-09-12 01:14:59

本文通过对三星smdkv210开发板的u-boot源码进行分析,了解u-boot烧写yaffs的方法,源码可以通过谷歌找到。

首先了解mtd的部分重要成员:
我的nand是2K,每512字节产生13字节的ecccode,所以ecc.steps = 2048 / 512=  4,
由chip->ecc.steps = mtd->writesize / chip->ecc.size;可知writesize表示页大小,ecc.size表示每次计算ecc的单元大小,这是由cpu决定的,比如s5pv210可以每读写512字节就生成ecc。erasesize肯定是块大小了。
先默认mtd->writesize = 2048,ecc.size = 512。oobsize = 64。erasesize = 128*2048。
mtd_oob_ops用来指示烧写内容的相关参数,注意mtd_oob_ops本身并没有操作函数。

点击(此处)折叠或打开

  1. struct nand_write_options {
  2.     u_char *buffer;        /* memory block containing image to write */
  3.     ulong length;        /* number of bytes to write */
  4.     ulong offset;        /* start address in NAND */
  5.     int quiet;        /* don't display progress messages */
  6.     int autoplace;        /* if true use auto oob layout */
  7.     int forcejffs2;        /* force jffs2 oob layout */
  8.     int forceyaffs;        /* force yaffs oob layout */
  9.     int noecc;        /* write without ecc */是否进行ECC?
  10.     int writeoob;        /* image contains oob data */指明所烧写的内容是否包含OOB
  11.     int pad;        /* pad to page size */指明填充至页大小(不写OOB)
  12.     int blockalign;        /* 1|2|4 set multiple of eraseblocks
  13.                  * to align to */
  14.     int flag; //hxs add
  15. };

点击(此处)折叠或打开

  1. 普通分区烧写:
  2.         s = strchr(cmd, '.');
  3.         if (s != NULL &&
  4.          (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) {
  5.             if (read) {
  6.                 /* read */
  7.                 nand_read_options_t opts;
  8.                 memset(&opts, 0, sizeof(opts));
  9.                 opts.buffer    = (u_char*) addr;
  10.                 opts.length    = size;
  11.                 opts.offset    = off;
  12.                 opts.quiet = quiet;
  13.                 ret = nand_read_opts(nand, &opts);
  14.             } else {
  15.                 /* write */
  16.                 nand_write_options_t opts;
  17.                 memset(&opts, 0, sizeof(opts));
  18.                 opts.buffer    = (u_char*) addr;
  19.                 opts.length    = size;
  20.                 opts.offset    = off;
  21.                 /* opts.forcejffs2 = 1; */
  22.                 opts.pad    = 1;
  23.                 opts.blockalign = 1;
  24.                 opts.quiet = quiet;
  25.                 opts.flag = flag; //HXS ADD
  26.                 ret = nand_write_opts(nand, &opts);
  27.             }

  28. tftp烧写yaffs分区:

  29. #ifdef CFG_NAND_YAFFS_WRITE
  30.         } else if (!read && s != NULL && + (!strcmp(s, ".yaffs") || !strcmp(s, ".yaffs1"))) {
  31.             nand_write_options_t opts;
  32.              memset(&opts, 0, sizeof(opts));
  33.              opts.buffer = (u_char*) addr;
  34.              opts.length = size;
  35.              opts.offset = off;
  36.              opts.pad = 0;
  37.              opts.blockalign = 1;
  38.              opts.quiet = quiet;
  39.              opts.writeoob = 1;
  40.              opts.autoplace = 1;

  41.             opts.flag = flag; //HXS ADD
  42.             /* jsgood */
  43.              /* if (s[6] == '1')
  44.                 opts.forceyaffs = 1; */

  45.              ret = nand_write_opts(nand, &opts);
  46. #endif

  47. sd卡烧写yaffs:
  48. #if (defined(CONFIG_TQ210_YAFFS) && defined(CONFIG_OEM_SDREAD))
  49.         } else if (/*!s || */!strcmp(s, ".OEMyaffs")) {
  50.             unsigned int Dir = 0;
  51.             DirFunRet FileDirFileRet = FindDirFile(argv[4]);
  52.             //printf("size:0x%x\n",FileDirFileRet.FileSize);
  53.             if (FileDirFileRet.FileSize == 0)
  54.             {
  55.                 return 1;
  56.             }
  57.             else
  58.             {
  59.                 Dir = FileDirFileRet.StartCluster;
  60.                 size = FileDirFileRet.FileSize;
  61.                 //if((size & (nand->oobsize+nand->writesize -1)) != 0){
  62.                 //    size = (size/(nand->oobsize+nand->writesize) + 1) * (nand->oobsize+nand->writesize);
  63.                 //}
  64.             //        printf ("cmd_sizeof(nand_info_t)= 0x%x\n",sizeof(nand_info_t));
  65.             //            printf ("sizof(loff_t)= 0x%x\n",sizeof(ulong));

  66.             //    printf("size:0x%x,&size=0x%x,addr:0x%x,\n",size,&size,addr);
  67.             }
  68.             nand_write_options_t opts;
  69.              memset(&opts, 0, sizeof(opts));
  70.              opts.buffer = (u_char*) addr;
  71.              opts.length = size;
  72.              opts.offset = off;
  73.              opts.pad = 0;
  74.              opts.blockalign = 1;
  75.              opts.quiet = quiet;
  76.              opts.writeoob = 1;
  77.              opts.autoplace = 1;

  78.             /* jsgood */
  79.              /* if (s[6] == '1')
  80.                 opts.forceyaffs = 1; */

  81.              ret = nand_OEM_write_opts(nand, &opts,Dir);


普通烧写时的nand_write_opts:

点击(此处)折叠或打开

  1. /**
  2.  * nand_write_opts: - write image to NAND flash with support for various options
  3.  *
  4.  * @param meminfo    NAND device to erase
  5.  * @param opts        write options (@see nand_write_options)
  6.  * @return        0 in case of success
  7.  *
  8.  * This code is ported from nandwrite.c from Linux mtd utils by
  9.  * Steven J. Hill and Thomas Gleixner.
  10.  */
  11.                  opts.pad    = 1;
  12.                 opts.blockalign = 1;
  13.                 opts.quiet = quiet;
  14.                 opts.flag = flag; //HXS ADD
  15. int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
  16. {
  17.     int imglen = 0;
  18.     int pagelen;
  19.     int baderaseblock;
  20.     int blockstart = -1;
  21.     loff_t offs;
  22.     int readlen;
  23.     int oobinfochanged = 0;
  24.     int percent_complete = -1;

  25.     /* org: struct nand_oobinfo old_oobinfo; */
  26.     struct nand_ecclayout old_oobinfo;
  27.     
  28.     ulong mtdoffset = opts->offset;
  29.     ulong erasesize_blockalign;
  30.     u_char *buffer = opts->buffer;
  31.     size_t written;
  32.     int result;

  33.     /* jsgood */
  34.     struct mtd_oob_ops oob_ops;

  35.     /* set erasesize to specified number of blocks - to match
  36.      * jffs2 (virtual) block size */
  37.     if (opts->blockalign == 0) {
  38.         erasesize_blockalign = meminfo->erasesize;
  39.     } else {
  40.         erasesize_blockalign = meminfo->erasesize * opts->blockalign;
  41.     }

  42.     /* read the current oob info */
  43.     /* org: memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo)); */
  44.     memcpy(&old_oobinfo, meminfo->ecclayout, sizeof(struct nand_ecclayout));

  45.     /* get image length */
  46.     imglen = opts->length;
  47.     pagelen = meminfo->writesize
  48.         + ((opts->writeoob != 0) ? meminfo->oobsize : 0);

  49.     /* check, if file is pagealigned */
  50.     if ((!opts->pad) && ((imglen % pagelen) != 0)) {
  51.         printf("Input block length is not page aligned\n");
  52.         goto restoreoob;
  53.     }

  54.     /* check, if length fits into device */
  55.     if (((imglen / pagelen) * meminfo->writesize)
  56.      > (meminfo->size - opts->offset)) {
  57.         printf("Image %d bytes, NAND page %d bytes, "
  58.          "OOB area %u bytes, device size %u bytes\n",
  59.          imglen, pagelen, meminfo->writesize, meminfo->size);
  60.         printf("Input block does not fit into device\n");
  61.         goto restoreoob;
  62.     }

  63.     if (!opts->quiet)
  64.         printf("\n");

  65.     /* get data from input and write to the device */
  66.     while (imglen && (mtdoffset < meminfo->size)) {

  67.         WATCHDOG_RESET ();

  68.         /*
  69.          * new eraseblock, check for bad block(s). Stay in the
  70.          * loop to be sure if the offset changes because of
  71.          * a bad block, that the next block that will be
  72.          * written to is also checked. Thus avoiding errors if
  73.          * the block(s) after the skipped block(s) is also bad
  74.          * (number of blocks depending on the blockalign
  75.          */
  76.         while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {
  77.             blockstart = mtdoffset & (~erasesize_blockalign+1);
  78.             offs = blockstart;
  79.             baderaseblock = 0;

  80.             /* check all the blocks in an erase block for
  81.              * bad blocks */
  82.             do {
  83.                 int ret = meminfo->block_isbad(meminfo, offs);

  84.                 if (ret < 0) {
  85.                     printf("Bad block check failed\n");
  86.                     goto restoreoob;
  87.                 }
  88.                 if (ret == 1) {
  89.                     baderaseblock = 1;
  90.                     if (!opts->quiet)
  91.                         printf("\rBad block at 0x%lx "
  92.                          "in erase block from "
  93.                          "0x%x will be skipped\n",
  94.                          (long) offs,
  95.                          blockstart);
  96.                 }

  97.                 if (baderaseblock) {
  98.                     mtdoffset = blockstart
  99.                         + erasesize_blockalign;
  100.                 }
  101.                 offs +=     erasesize_blockalign
  102.                     / opts->blockalign;
  103.             } while (offs < blockstart + erasesize_blockalign);
  104.         }

  105.         readlen = meminfo->writesize;
  106.         if (opts->pad && (imglen < readlen)) {
  107.             readlen = imglen;
  108.             memset(data_buf + readlen, 0xff,
  109.              meminfo->writesize - readlen);
  110.         }

  111.         /* read page data from input memory buffer */
  112.         memcpy(data_buf, buffer, readlen);
  113.         buffer += readlen;

  114.         /* This is yaffs2 writing if opts->writeoob == 1,
  115.          * and the other case is jffs2 writing in S3C NAND by jsgood.
  116.          */
  117.         if (opts->writeoob) {
  118.             /* read OOB data from input memory block, exit
  119.              * on failure */
  120.             memcpy(oob_buf, buffer, meminfo->oobsize);
  121.             buffer += meminfo->oobsize;

  122.             /* write OOB data first, as ecc will be placed
  123.              * in there*/
  124.             /* org: result = meminfo->write_oob(meminfo,
  125.                          mtdoffset,
  126.                          meminfo->oobsize,
  127.                          &written,
  128.                          (unsigned char *)
  129.                          &oob_buf); */
  130.             oob_ops.mode = MTD_OOB_AUTO;
  131.             oob_ops.len = meminfo->writesize;
  132.             oob_ops.ooboffs = 0;
  133.             oob_ops.ooblen = meminfo->oobsize;            
  134.             oob_ops.oobbuf = (unsigned char *)&oob_buf;
  135.             oob_ops.datbuf = (unsigned char *)&data_buf;

  136.             result = meminfo->write_oob(meminfo, mtdoffset, &oob_ops);

  137.             if (result != 0) {
  138.                 printf("\nMTD writeoob failure: %d\n",
  139.                  result);
  140.                 goto restoreoob;
  141.             }
  142.             imglen -= meminfo->oobsize;
  143.         } else {
  144.             /* write out the page data */
  145.             result = meminfo->write(meminfo,
  146.                         mtdoffset,
  147.                         meminfo->writesize,
  148.                         &written,
  149.                         (unsigned char *) &data_buf);

  150.             if (result != 0) {
  151.                 printf("writing NAND page at offset 0x%lx failed\n",
  152.                  mtdoffset);
  153.                 goto restoreoob;
  154.             }
  155.         }

  156.         imglen -= readlen;

  157.         if (!opts->quiet) {
  158.             unsigned long long n = (unsigned long long)
  159.                  (opts->length-imglen) * 100;
  160.             int percent;

  161.             do_div(n, opts->length);
  162.             percent = (int)n;

  163.             /* output progress message only at whole percent
  164.              * steps to reduce the number of messages printed
  165.              * on (slow) serial consoles
  166.              */
  167.             if (percent != percent_complete) {
  168.                 printf("\rWriting data at 0x%lx "
  169.                  "-- %3d%% complete.",
  170.                  mtdoffset, percent);
  171.                 percent_complete = percent;
  172.             }
  173.         }

  174.         mtdoffset += meminfo->writesize;
  175.     }

  176.     if (!opts->quiet)
  177.         printf("\n");

  178. restoreoob:
  179.     if (oobinfochanged) {
  180.         /* org: memcpy(&meminfo->oobinfo, &old_oobinfo,
  181.          sizeof(meminfo->oobinfo)); */
  182.         memcpy(meminfo->ecclayout, &old_oobinfo,
  183.          sizeof(struct nand_ecclayout));        
  184.     }

  185.     if (imglen > 0) {
  186.         printf("Data did not fit into device, due to bad blocks\n");
  187.         return -1;
  188.     }

  189.     /* return happy */
  190.     return 0;
  191. }
可见最终调用了meminfo->write来烧写数据:
/* write out the page data */
result = meminfo->write(meminfo,
mtdoffset,
meminfo->writesize,
&written,
(unsigned char *) &data_buf);

上一篇中我们已经分析过meminfo->write的调用过程,即mtd->write > nand_write > nand_do_write_ops > chip->write_page > s3c_nand_write_page_8bit(mtd, chip, buf);
而不管是tftp还是从sd卡烧写yaffs镜像时,都会标记opts.writeoob = 1; 因此会调用meminfo->write_oob(meminfo, mtdoffset, &oob_ops);
meminfo->write_oob就是nand_write_oob:

点击(此处)折叠或打开

  1. /**
  2.  * nand_write - [MTD Interface] NAND write with ECC
  3.  * @mtd:    MTD device structure
  4.  * @to:        offset to write to
  5.  * @len:    number of bytes to write
  6.  * @retlen:    pointer to variable to store the number of written bytes
  7.  * @buf:    the data to write
  8.  *
  9.  * NAND write with ECC
  10.  */
  11. static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
  12.              size_t *retlen, const uint8_t *buf)
  13. {
  14.     struct nand_chip *chip = mtd->priv;
  15.     int ret;

  16.     /* Do not allow reads past end of device */
  17.     if ((to + len) > mtd->size)
  18.         return -EINVAL;
  19.     if (!len)
  20.         return 0;

  21.     nand_get_device(chip, mtd, FL_WRITING);

  22.     chip->ops.len = len;
  23.     chip->ops.datbuf = (uint8_t *)buf;
  24.     chip->ops.oobbuf = NULL;

  25.     ret = nand_do_write_ops(mtd, to, &chip->ops);

  26.     *retlen = chip->ops.retlen;

  27.     nand_release_device(mtd);

  28.     return ret;
  29. }

  30. static int nand_write_oob(struct mtd_info *mtd, loff_t to,
  31.              struct mtd_oob_ops *ops)
  32. {
  33.     struct nand_chip *chip = mtd->priv;

  34.     /* org: int ret = -ENOTSUPP */
  35.     int ret = -524;

  36.     ops->retlen = 0;

  37.     /* Do not allow writes past end of device */
  38.     if (ops->datbuf && (to + ops->len) > mtd->size) {
  39.         DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
  40.          "Attempt read beyond end of device\n");
  41.         return -EINVAL;
  42.     }

  43.     nand_get_device(chip, mtd, FL_WRITING);

  44.     switch(ops->mode) {
  45.     case MTD_OOB_PLACE:
  46.     case MTD_OOB_AUTO:
  47.     case MTD_OOB_RAW:
  48.         break;

  49.     default:
  50.         goto out;
  51.     }

  52.     if (!ops->datbuf)
  53.         ret = nand_do_write_oob(mtd, to, ops);
  54.     else
  55.         ret = nand_do_write_ops(mtd, to, ops);

  56.  out:
  57.     nand_release_device(mtd);
  58.     return ret;
  59. }
注意opts->writeoob == 1时,会构建oob_ops结构体,接着从内存的源数据中分离出一页数据中的data和oob,赋给oob_ops,这个样oob_ops就包含了data和oob数据:
oob_ops.oobbuf = (unsigned char *)&oob_buf;
oob_ops.datbuf = (unsigned char *)&data_buf;
然后使用             meminfo->write_oob(meminfo, mtdoffset, &oob_ops);         烧写data和oob。

opts->writeoob == 0时,不会构建oob_ops结构体,直接使用
                            
result = meminfo->write(meminfo,mtdoffset,meminfo->writesize,&written,(unsigned char *) &data_buf);
来烧写数据。

nand_write和nand_write_oob 最后都会执行nand_do_write_ops函数,
如果nand_write_oob,会执行
if (unlikely(oob))
oob = nand_fill_oob(chip, oob, ops);
将源数据中的oob数据填入nand中的oobfree区域,然后执行write_page写入数据和ecc。
如果nand_write,不会填充OOB,而是直接执行chip->write_page(mtd, chip, wbuf, page, cached,     (ops->mode == MTD_OOB_RAW)); 烧写数据和ecc。

最后最重要的函数:

点击(此处)折叠或打开

  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 ((mtd->writesize == 512 && page < 512) || (mtd->writesize == 2048 && page < 256) ||
  8.         (mtd->writesize == 4096 && page < 128)) {

  9.         memset(chip->oob_poi, 0xff, mtd->oobsize);
  10.         s3c_nand_write_page_8bit(mtd, chip, buf);
  11.     } else
  12.     {
  13.         if (unlikely(raw))
  14.             chip->ecc.write_page_raw(mtd, chip, buf);
  15.         else
  16.             chip->ecc.write_page(mtd, chip, buf);
  17.     }

  18.     /*
  19.      * Cached progamming disabled for now, Not sure if its worth the
  20.      * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
  21.      */
  22.     cached = 0;

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

  24.         chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
  25.         status = chip->waitfunc(mtd, chip);
  26.         /*
  27.          * See if operation failed and additional status checks are
  28.          * available
  29.          */
  30.         if ((status & NAND_STATUS_FAIL) && (chip->errstat))
  31.             status = chip->errstat(mtd, chip, FL_WRITING, status,
  32.                      page);

  33.         if (status & NAND_STATUS_FAIL)
  34.             return -EIO;
  35.     } else {
  36.         chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
  37.         status = chip->waitfunc(mtd, chip);
  38.     }

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

  42.     if (chip->verify_buf(mtd, buf, mtd->writesize))
  43.         return -EIO;
  44. #endif
  45.     return 0;
  46. }
最关键的就是if ((mtd->writesize == 512 && page < 512) || (mtd->writesize == 2048 && page < 256) || 
(mtd->writesize == 4096 && page < 128)) {
这个判断条件,当写入的页地址未超过uboot分区时,采用8bitecc,若超过则采用1bitecc。
阅读(1438) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~