一、MTD系统架构

1.MTD设备体验

FLASH在嵌入式系统中是必不可少的,它是bootloader、linux内核和文件系统的最佳载体。

在Linux内核中引入了MTD子系统为NORFLASH和NAND FLASH设备提供统一的接口,从而使得FLASH驱动的设计大为简化。

  1. cat /proc/mtd

每个分区对应一个块设备

  1. ls -l /dev/mtd*
  2. crw-rw—- 1 0 0 90, 0 Jan 1 00:00 /dev/mtd0
  3. crw-rw—- 1 0 0 90, 1 Jan 1 00:00 /dev/mtd0ro
  4. crw-rw—- 1 0 0 90, 2 Jan 1 00:00 /dev/mtd1
  5. crw-rw—- 1 0 0 90, 3 Jan 1 00:00 /dev/mtd1ro
  6. crw-rw—- 1 0 0 90, 4 Jan 1 00:00 /dev/mtd2
  7. crw-rw—- 1 0 0 90, 5 Jan 1 00:00 /dev/mtd2ro
  8. brw-rw—- 1 0 0 31, 0 Jan 1 00:00 /dev/mtdblock0
  9. brw-rw—- 1 0 0 31, 1 Jan 1 00:00 /dev/mtdblock1
  10. brw-rw—- 1 0 0 31, 2 Jan 1 00:00 /dev/mtdblock2

2.块设备驱动系统架构

MTD系统架构和yaffs2使用、Nandflash驱动设计-编程之家

二、YAFFS2文件系统应用

1.MTD分区设置
配置linux内核支持mtd,找到mtd接口文件,设置空间大小。
2.Yaffs2文件系统制作
将rootfs格式化生成yaffs文件系统。

  1. /home/win/mkyaffs2image ./rootfs/ rootfs.img

3.Uboot参数设置

在uboot_tq2440includeconfigsTQ2440.h中有uboot的启动配置选项

  1. #define CONFIG_BZIP2
  2. #define CONFIG_LZO
  3. #define CONFIG_LZMA
  4. #define CONFIG_CMD_NAND_YAFFS
  5. #define CONFIG_BOOTARGS "console=ttySAC0 root=/dev/mtdblock3"
  6. #define CONFIG_BOOTCOMMAND "nand read 0x30000000 kernel;bootm 0x30000000"

4.下载烧写与启动

在uboot中用dnw下载

三、Nandflash驱动设计
s3c2410.c/s3c24xx_nand_probe:

  1. static int s3c24xx_nand_probe(struct platform_device *pdev,
  2.              enum s3c_cpu_type cpu_type)
  3. {
  4.     struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
  5.     struct s3c2410_nand_info *info;
  6.     struct s3c2410_nand_mtd *nmtd;
  7.     struct s3c2410_nand_set *sets;
  8.     struct resource *res;
  9.     int err = 0;
  10.     int size;
  11.     int nr_sets;
  12.     int setno;
  13.     pr_debug("s3c2410_nand_probe(%p)n", pdev);
  14.     info = kmalloc(sizeof(*info), GFP_KERNEL);
  15.     if (info == NULL) {
  16.         dev_err(&pdev>dev, "no memory for flash infon");
  17.         err = ENOMEM;
  18.         goto exit_error;
  19.     }
  20.     memset(info, 0, sizeof(*info));
  21.     platform_set_drvdata(pdev, info);
  22.     spin_lock_init(&info>controller.lock);
  23.     init_waitqueue_head(&info>controller.wq);
  24.     /* get the clock source and enable it */
  25.     info>clk = clk_get(&pdev>dev, "nand");                                  //获取时钟,并使能
  26.     if (IS_ERR(info>clk)) {
  27.         dev_err(&pdev>dev, "failed to get clockn");
  28.         err = ENOENT;
  29.         goto exit_error;
  30.     }
  31.     clk_enable(info>clk);
  32.     /* allocate and map the resource */
  33.     /* currently we assume we have the one resource */
  34.     res = pdev>resource;
  35.     size = res>end res>start + 1;
  36.     info>area = request_mem_region(res>start, size, pdev>name);                         //地址转换
  37.     if (info>area == NULL) {
  38.         dev_err(&pdev>dev, "cannot reserve register regionn");
  39.         err = ENOENT;
  40.         goto exit_error;
  41.     }
  42.     info>device = &pdev>dev;
  43.     info>platform = plat;
  44.     info>regs = ioremap(res>start, size);
  45.     info>cpu_type = cpu_type;
  46.     if (info>regs == NULL) {
  47.         dev_err(&pdev>dev, "cannot reserve register regionn");
  48.         err = EIO;
  49.         goto exit_error;
  50.     }
  51.     dev_dbg(&pdev>dev, "mapped registers at %pn", info>regs);
  52.     /* initialise the hardware */
  53.     err = s3c2410_nand_inithw(info);                                                        //初始化硬件
  54.     if (err != 0)
  55.         goto exit_error;
  56.     sets = (plat != NULL) ? plat>sets : NULL;
  57.     nr_sets = (plat != NULL) ? plat>nr_sets : 1;
  58.     info>mtd_count = nr_sets;
  59.     /* allocate our information */
  60.     size = nr_sets * sizeof(*info>mtds);
  61.     info>mtds = kmalloc(size, GFP_KERNEL);
  62.     if (info>mtds == NULL) {
  63.         dev_err(&pdev>dev, "failed to allocate mtd storagen");
  64.         err = ENOMEM;
  65.         goto exit_error;
  66.     }
  67.     memset(info>mtds, 0, size);
  68.     /* initialise all possible chips */
  69.     nmtd = info>mtds;
  70.     for (setno = 0; setno < nr_sets; setno++, nmtd++) {
  71.         pr_debug("initialising set %d (%p, info %p)n", setno, nmtd, info);
  72.         s3c2410_nand_init_chip(info, nmtd, sets);                                               //里面有校验nandflash
  73.         nmtd>scan_res = nand_scan_ident(&nmtd>mtd,                                            //搜索nandflash
  74.                          (sets) ? sets>nr_chips : 1);
  75.         if (nmtd>scan_res == 0) {
  76.             s3c2410_nand_update_chip(info, nmtd);
  77.             nand_scan_tail(&nmtd>mtd);
  78.             s3c2410_nand_add_partition(info, nmtd, sets);                                        //注册分区信息
  79.         }
  80.         if (sets != NULL)
  81.             sets++;
  82.     }
  83.     err = s3c2410_nand_cpufreq_register(info);
  84.     if (err < 0) {
  85.         dev_err(&pdev>dev, "failed to init cpufreq supportn");
  86.         goto exit_error;
  87.     }
  88.     if (allow_clk_stop(info)) {
  89.         dev_info(&pdev>dev, "clock idle support enabledn");
  90.         clk_disable(info>clk);
  91.     }
  92.     pr_debug("initialised okn");
  93.     return 0;
  94.  exit_error:
  95.     s3c2410_nand_remove(pdev);
  96.     if (err == 0)
  97.         err = EINVAL;
  98.     return err;
  99. }

MTD通用驱动部分nand_base.c(nand_read:

  1. static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
  2.          size_t *retlen, uint8_t *buf)
  3. {
  4.     struct nand_chip *chip = mtd>priv;
  5.     int ret;
  6.     /* Do not allow reads past end of device */
  7.     if ((from + len) > mtd>size)
  8.         return EINVAL;
  9.     if (!len)
  10.         return 0;
  11.     nand_get_device(chip, mtd, FL_READING);
  12.     chip>ops.len = len;
  13.     chip>ops.datbuf = buf;
  14.     chip>ops.oobbuf = NULL;
  15.     ret = nand_do_read_ops(mtd, from, &chip>ops);                                       //进行读操作的代码
  16.     *retlen = chip>ops.retlen;
  17.     nand_release_device(mtd);
  18.     return ret;
  19. }

nand_do_read_ops:

  1. /**
  2.  * nand_do_read_ops [Internal] Read data with ECC
  3.  *
  4.  * @mtd:    MTD device structure
  5.  * @from:    offset to read from
  6.  * @ops:    oob ops structure
  7.  *
  8.  * Internal function. Called with chip held.
  9.  */
  10. static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
  11.              struct mtd_oob_ops *ops)
  12. {
  13.     int chipnr, page, realpage, col, bytes, aligned;
  14.     struct nand_chip *chip = mtd>priv;
  15.     struct mtd_ecc_stats stats;
  16.     int blkcheck = (1 << (chip>phys_erase_shift chip>page_shift)) 1;
  17.     int sndcmd = 1;
  18.     int ret = 0;
  19.     uint32_t readlen = ops>len;
  20.     uint32_t oobreadlen = ops>ooblen;
  21.     uint8_t *bufpoi, *oob, *buf;
  22.     stats = mtd>ecc_stats;
  23.     chipnr = (int)(from >> chip>chip_shift);
  24.     chip>select_chip(mtd, chipnr);
  25.     realpage = (int)(from >> chip>page_shift);
  26.     page = realpage & chip>pagemask;
  27.     col = (int)(from & (mtd>writesize 1));
  28.     buf = ops>datbuf;
  29.     oob = ops>oobbuf;
  30.     while(1) {
  31.         bytes = min(mtd>writesize col, readlen);
  32.         aligned = (bytes == mtd>writesize);
  33.         /* Is the current page in the buffer ? */
  34.         if (realpage != chip>pagebuf || oob) {
  35.             bufpoi = aligned ? buf : chip>buffers>databuf;
  36.             if (likely(sndcmd)) {
  37.                 chip>cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);                                              //实际对应了nand_command_lp,cmd命令是0
  38.                 sndcmd = 0;
  39.             }
  40.         ………
  41. }

nand_command_lp:

  1. static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
  2.              int column, int page_addr)
  3. {
  4.     register struct nand_chip *chip = mtd>priv;
  5.     /* Emulate NAND_CMD_READOOB */
  6.     if (command == NAND_CMD_READOOB) {
  7.         column += mtd>writesize;
  8.         command = NAND_CMD_READ0;
  9.     }
  10.     /* Command latch cycle */
  11.     chip>cmd_ctrl(mtd, command & 0xff,
  12.          NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);                                   //cmd_ctrl来源于底层驱动,在s3c2410_nand_init_chip中赋值了。
  13.     …….
  14. }

s3c2410_nand_hwcontrol:

  1. /* s3c2410_nand_hwcontrol
  2.  *
  3.  * Issue command and address cycles to the chip
  4. */
  5. static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
  6.                  unsigned int ctrl)
  7. {
  8.     struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
  9.     if (cmd == NAND_CMD_NONE)
  10.         return;
  11.     if (ctrl & NAND_CLE)
  12.         writeb(cmd, info>regs + S3C2410_NFCMD);                                     //往NFCONT寄存器中写入cmd,cmd来自于nand_command,往上回溯为nand_read.其实就是发送了命令0x00
  13.     else
  14.         writeb(cmd, info>regs + S3C2410_NFADDR);
  15. }

继续回到nand_command_lp:

  1.         ……………
  2.         if (column != 1 || page_addr != 1) {
  3.         int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
  4.         /* Serially input address */
  5.         if (column != 1) {
  6.             /* Adjust columns for 16 bit buswidth */
  7.             if (chip>options & NAND_BUSWIDTH_16)
  8.                 column >>= 1;
  9.             chip>cmd_ctrl(mtd, column, ctrl);                                   //紧接着发送列地址
  10.             ctrl &= ~NAND_CTRL_CHANGE;
  11.             chip>cmd_ctrl(mtd, column >> 8, ctrl);
  12.         }
  13.         if (page_addr != 1) {
  14.             chip>cmd_ctrl(mtd, page_addr, ctrl);                                //发送行地址
  15.             chip>cmd_ctrl(mtd, page_addr >> 8,
  16.                  NAND_NCE | NAND_ALE);
  17.             /* One more address cycle for devices > 128MiB */
  18.             if (chip>chipsize > (128 << 20))
  19.                 chip>cmd_ctrl(mtd, page_addr >> 16,
  20.                      NAND_NCE | NAND_ALE);
  21.         }
  22.     }
  23.     chip>cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
  24.     /*
  25.      * program and erase have their own busy handlers
  26.      * status, sequential in, and deplete1 need no delay
  27.      */
  28.     switch (command) {
  29.     case NAND_CMD_CACHEDPROG:
  30.     case NAND_CMD_PAGEPROG:
  31.     case NAND_CMD_ERASE1:
  32.     case NAND_CMD_ERASE2:
  33.     case NAND_CMD_SEQIN:
  34.     case NAND_CMD_RNDIN:
  35.     case NAND_CMD_STATUS:
  36.     case NAND_CMD_DEPLETE1:
  37.         return;
  38.         /*
  39.          * read error status commands require only a short delay
  40.          */
  41.     case NAND_CMD_STATUS_ERROR:
  42.     case NAND_CMD_STATUS_ERROR0:
  43.     case NAND_CMD_STATUS_ERROR1:
  44.     case NAND_CMD_STATUS_ERROR2:
  45.     case NAND_CMD_STATUS_ERROR3:
  46.         udelay(chip>chip_delay);
  47.         return;
  48.     case NAND_CMD_RESET:
  49.         if (chip>dev_ready)
  50.             break;
  51.         udelay(chip>chip_delay);
  52.         chip>cmd_ctrl(mtd, NAND_CMD_STATUS,
  53.              NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
  54.         chip>cmd_ctrl(mtd, NAND_CMD_NONE,
  55.              NAND_NCE | NAND_CTRL_CHANGE);
  56.         while (!(chip>read_byte(mtd) & NAND_STATUS_READY)) ;
  57.         return;
  58.     case NAND_CMD_RNDOUT:
  59.         /* No ready / busy check necessary */
  60.         chip>cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
  61.              NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
  62.         chip>cmd_ctrl(mtd, NAND_CMD_NONE,
  63.              NAND_NCE | NAND_CTRL_CHANGE);
  64.         return;
  65.     case NAND_CMD_READ0:
  66.         chip>cmd_ctrl(mtd, NAND_CMD_READSTART,                                                    //这里发送了0x30命令
  67.              NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
  68.         chip>cmd_ctrl(mtd, NAND_CMD_NONE,
  69.              NAND_NCE | NAND_CTRL_CHANGE);
  70.         /* This applies to read commands */
  71.     default:
  72.         /*
  73.          * If we don't have access to the busy pin, we apply the given
  74.          * command delay
  75.          */
  76.         if (!chip>dev_ready) {
  77.             udelay(chip>chip_delay);
  78.             return;
  79.         }
  80.     }
  81.     /* Apply this short delay always to ensure that we do wait tWB in
  82.      * any case on any machine. */
  83.     ndelay(100);
  84.     nand_wait_ready(mtd);                                                                          //wait等待
  85. }

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script> 阅读(38) | 评论(0) | 转发(0) |

0

上一篇:块设备驱动系统架构和简单设计

下一篇:I2C学习

相关热门文章

  • SHTML是什么_SSI有什么用…
  • 查看linux中某个端口(port)…
  • 卡尔曼滤波的原理说明…
  • shell中字符串操作
  • 关于java中的“错误:找不到或…

    给主人留下些什么吧!~~ 评论热议