×
单片机 > 单片机程序设计 > 详情

S3C6410使用---11uboot写yaffs2文件系统过程分析

发布时间:2020-09-01 发布时间:
|

一、介绍
Nand flash  K9GAG08U0D  (2G Byte)
在u-boot的shell里面执行如下命令: 把 rootfs.yaffs从SD卡的第一个分区读取出来,并写到nand flash中去.
SMDK6401> fatload mmc 0:1 50008000 rootfs.yaffs
SMDK6401> nand erase 600000  $(filesize)
SMDK6401> nand write.yaffs2 50008000 600000 $(filesize)
这儿分析一下最后一条命令:将数据写入到yaffs2分区的过程


二、 过程分析
1.1 u-boot/common/cmd_nand.c中

  1. int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])

  2. {

  3.     if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {

  4.         addr = (ulong)simple_strtoul(argv[2], NULL, 16);

  5.         read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */


  6.         if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)

  7.             return 1;


  8.         s = strchr(cmd, '.');

  9.          if (!read && s != NULL && + (!strcmp(s, ".yaffs2") || !strcmp(s, ".yaffs1"))) 

  10.          {

  11.             nand_write_options_t opts;

  12.              memset(&opts, 0, sizeof(opts));

  13.              opts.buffer = (u_char*) addr;              // addr=0x50008000内存

  14.              opts.length = size;                        // length是文件长度

  15.              opts.offset = off;                         // offset 是要写到nand flash的地址0x600000

  16.              opts.pad = 0;

  17.              opts.blockalign = 1;

  18.              opts.quiet = quiet;

  19.              opts.writeoob = 1;

  20.              opts.autoplace = 1;

  21.              ret = nand_write_opts(nand, &opts);

  22.          }

  23. }

argv[0]    argv[1]      argv[2]    argv[3]   argv[4]
nand     write.yaffs2   50008000   600000   $(filesize)
                         addr       off     size=0x420000

1.2 在文件driver/nand/nand_utils.c中

  1. int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)

  2. {

  3.     ulong mtdoffset = opts->offset;                // mtdoffset=nand_flash中的偏移0x600000

  4.     ulong erasesize_blockalign;

  5.     u_char *buffer = opts->buffer;                 // buffer=(u_char*)0x500080

  6.     imglen = opts->length;                         // imglen是rootfs.yaffs2这个文件的长度   

  7.     while (imglen && (mtdoffset size)) {


  8.         //下面这个 while判断要写入的块是不是坏块,如果是坏块继续查找直到找到一个好块

  9.         while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {

  10.             blockstart = mtdoffset & (~erasesize_blockalign+1);

  11.             offs = blockstart;

  12.             baderaseblock = 0;


  13.             do {

  14.                 int ret = meminfo->block_isbad(meminfo, offs);    //判断是不是块坏


  15.                 if (ret 

  16.                     printf("Bad block check failedn");

  17.                     goto restoreoob;

  18.                 }

  19.                 if (ret == 1) {                                    //ret=1是坏块

  20.                     baderaseblock = 1;                             //这个地方还要设个标志,直接do_something不就得了?

  21.                     if (!opts->quiet)

  22.                         printf("rBad block at 0x%lx "

  23.                          "in erase block from "

  24.                          "0x%x will be skippedn",

  25.                          (long) offs,

  26.                          blockstart);

  27.                 }


  28.                 if (baderaseblock) {

  29.                     mtdoffset = blockstart + erasesize_blockalign; //如果ret=1是坏块,要写入的起始位置指向下一个块

  30.                 }

  31.                 offs +=     erasesize_blockalign

  32.                     / opts->blockalign;

  33.             } while (offs 

  34.         }


  35.         readlen = meminfo->writesize;        

  36.         memcpy(data_buf, buffer, readlen);                      //初始时:buffer=(u_char*)0x50008000

  37.         buffer += readlen;                                      //meminfo->writesize= 4096


  38.         if (opts->writeoob) {            

  39.             memcpy(oob_buf, buffer, meminfo->oobsize);          //buffer=(data+oob)*n, oob紧跟data

  40.             buffer += meminfo->oobsize;                         //meminfo->oobsize = 128

  41.             oob_ops.mode = MTD_OOB_AUTO;    

  42.             oob_ops.len = meminfo->writesize;                   // 每一次写的大小为writesize=4k

  43.             oob_ops.ooboffs = 0;

  44.             oob_ops.ooblen = meminfo->oobsize;

  45.             oob_ops.oobbuf = (unsigned char *)&oob_buf;

  46.             oob_ops.datbuf = (unsigned char *)&data_buf;


  47.             result = meminfo->write_oob(meminfo, mtdoffset, &oob_ops);    //如果没有坏块的话: mtdoffset=nand_flash中的偏移0x600000

  48.             

  49.             imglen -= meminfo->oobsize;

  50.         }

  51.         imglen -= readlen;                                                // mtd->writesize=4096

  52.         mtdoffset += meminfo->writesize;                                  // mtdoffset指向下一个page,是page_align

  53.     }

  54. }

1.3 在driver/nand/nand_base.c中

  1. int nand_scan_tail(struct mtd_info *mtd)

  2. {

  3.     mtd->write_oob = nand_write_oob;                    //初始化

  4. }

  5. //初始化时,所以 meminfo->write_oob(meminfo, mtdoffset, &oob_ops),就是调用nand_write_oob

  6. static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)

  7. {

  8.     struct nand_chip *chip = mtd->priv;

  9.     nand_get_device(chip, mtd, FL_WRITING); 


  10.     if (!ops->datbuf)                                   //ops->databuf不为空,要调用下面那个

  11.         ret = nand_do_write_oob(mtd, to, ops);

  12.     else

  13.         ret = nand_do_write_ops(mtd, to, ops);         //调用这个,这就是nand flash写的过程,可参考下面的图

  14.     

  15. }

1.4 在driver/nand/nand_base.c中

  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, struct mtd_oob_ops *ops)

  10. {

  11.     int chipnr, realpage, page, blockmask, column;

  12.     struct nand_chip *chip = mtd->priv;

  13.     uint32_t writelen = ops->len;

  14.     uint8_t *oob = ops->oobbuf;

  15.     uint8_t *buf = ops->datbuf;

  16.     int ret, subpage;


  17.     ops->retlen = 0;


  18.     column = to & (mtd->writesize - 1);

  19.     subpage = column || (writelen & (mtd->writesize - 1));


  20.     if (subpage && oob)

  21.         return -EINVAL;


  22.     chipnr = (int)(to >> chip->chip_shift);

  23.     chip->select_chip(mtd, chipnr);                                            //写过程第1步,选中芯片


  24.     realpage = (int)(to >> chip->page_shift);

  25.     page = realpage & chip->pagemask;

  26.     blockmask = (1 page_shift)) - 1;


  27.     /* Invalidate the page cache, when we write to the cached page */

  28.     if (to <= (chip->pagebuf 

  29.             (chip->pagebuf 

  30.         chip->pagebuf = -1;


  31.     while(1) {

  32.         int bytes = mtd->writesize;

  33.         int cached = writelen > bytes && page != blockmask;

  34.         uint8_t *wbuf = buf;


  35.         if (unlikely(column || writelen writesize - 1))) {

  36.             cached = 0;

  37.             bytes = min_t(int, bytes - column, (int) writelen);

  38.             chip->pagebuf = -1;

  39.             memset(chip->buffers->databuf, 0xff, mtd->writesize);

  40.             memcpy(&chip->buffers->databuf[column], buf, bytes);

  41.             wbuf = chip->buffers->databuf;

  42.         }


  43.         if (unlikely(oob))

  44.             oob = nand_fill_oob(chip, oob, ops);


  45.         ret = chip->write_page(mtd, chip, wbuf, page, cached,  (ops->mode == MTD_OOB_RAW));

  46.         if (ret)

  47.             break;


  48.         writelen -= bytes;


  49.         if (!writelen)

  50.             break;


  51.         column = 0;

  52.         buf += bytes;

  53.         realpage++;


  54.         page = realpage & chip->pagemask;

  55.         /* Check, if we cross a chip boundary */

  56.         if (!page) {

  57.             chipnr++;

  58.             chip->select_chip(mtd, -1);

  59.             chip->select_chip(mtd, chipnr);

  60.         }

  61.     }


  62.     ops->retlen = ops->len - writelen;

  63.     if (unlikely(oob))

  64.         ops->oobretlen = ops->ooblen;

  65.     return ret;

  66. }

1.5 在driver/nand/nand_base.c中

  1. static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,    struct mtd_oob_ops *ops)

  2. {

  3.     size_t len = ops->ooblen;

  4.     int i=0;

  5.     switch(ops->mode) {

  6.         case MTD_OOB_AUTO:

  7.         {

  8.          struct nand_oobfree *free = chip->ecc.layout->oobfree;

  9.          uint32_t boffs = 0, woffs = ops->ooboffs;

  10.          size_t bytes = 0;

  11.          // free->length=22, len=128, woffs=0

  12.          for(; free->length && len; free++, len -= bytes) 

  13.          {    // bytes=22, boffs=2

  14.             bytes = min_t(size_t, len, free->length);

  15.             boffs = free->offset;

  16.             

  17.             memcpy(chip->oob_poi + boffs, oob, bytes);                       //将rootfs.yaffs2中紧跟main区的22个字节copy到oob_poi[2-24]处     

  18.             oob += bytes;                                                    //这块数据是yaffs2文件系统的信息

  19.          }

  20.          return oob;    

  21.         }

  22.      }       

  23.     return NULL;

  24. }


1.6 在driver/nand/nand_base.c中
  1. nand_scan_tail
    {
        if (!chip->write_page)
            chip->write_page = nand_write_page;
    }

  2. static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,  const uint8_t *buf, int page, int cached, int raw)

  3. {


  4.     int status;


  5.     chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);                            //写过程第2-3步,发命令0x80,发地址


  6.     if (unlikely(raw))

  7.        chip->ecc.write_page_raw(mtd, chip, buf);

  8.     else    //exec       

  9.        chip->ecc.write_page(mtd, chip, buf);  

  10.    

  11.    cached = 0;

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

  13.         chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1,-1);                           //写过程第5步,写命令0x10

  14.         status = chip->waitfunc(mtd, chip);                                                          //写过程第6步,等侍结束

  15.         

  16.         if ((status & NAND_STATUS_FAIL) && (chip->errstat))

  17.             status = chip->errstat(mtd, chip, FL_WRITING, status,page);


  18.         if (status & NAND_STATUS_FAIL)

  19.             return -EIO;

  20.     } 

  21.     return 0;

  22. }

1.7 在cpu/s3c64xx/nand.c中

  1. board_nand_init()

  2. {

  3. #if defined(CONFIG_NAND_BL1_8BIT_ECC) && (defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430))

  4.     nand->ecc.write_page = s3c_nand_write_page_8bit;

  5.     nand->ecc.size = 512;

  6.     nand->ecc.bytes = 13;

  7.     nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;

  8. #endif

  9. }

  10. void s3c_nand_write_page_8bit(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf)

  11. {

  12.     int i, eccsize = 512;

  13.     int eccbytes = 13;

  14.     int eccsteps = mtd->writesize / eccsize;

  15.     uint8_t *ecc_calc = chip->buffers->ecccalc;

  16.     uint8_t *p = buf;

  17.                                                                                     //下面这个for代码,写的不明了,             

  18.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {                //意思是: 每512字节生成13字节的ECC,4K生成13*(4K/512)=104字节的ECC

  19.         s3c_nand_enable_hwecc_8bit(mtd, NAND_ECC_WRITE);                            //使能硬件ECC

  20.         chip->write_buf(mtd, p, eccsize);                                           //写过程第4步,写数据

  21.         s3c_nand_calculate_ecc_8bit(mtd, p, &ecc_calc[i]);                          //每写512字节到main区,就生成13字节的ECC,依次填充到ecc_calc[0-13*8=104]处

  22.     }


  23.     for (i = 0; i writesize / eccsize); i++)

  24.         chip->oob_poi[i+24] = ecc_calc[i];                                      //将硬件生成的ECC值填入oob的[24-128]处, ECC_size=8*13=104, (24+104=128)


  25.     chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);                 //写过程第4步,写OOB(OOB数据紧随main区数据写入的,单独写OOB是写不了的 )            

  26. }


1.8 在driver/nand/nand_base.c中

  1. static void nand_set_defaults(struct nand_chip *chip, int busw)

  2. {

  3.     if (!chip->write_buf)

  4.         chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;

  5. }

  6. static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)

  7. {

  8.     int i;

  9.     struct nand_chip *chip = mtd->priv;


  10.     for (i = 0; i 

  11.         writeb(buf[i], chip->IO_ADDR_W);

  12. }

1.9 上述写过程如下图所示:

1.10 OOB数据如下图所示



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
MSP430F5529 上手小例程2