zoukankan      html  css  js  c++  java
  • MTD系统架构和yaffs2使用、Nandflash驱动设计

    一、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.块设备驱动系统架构


    二、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) ", pdev);

    14.     info = kmalloc(sizeof(*info), GFP_KERNEL);
    15.     if (info == NULL) {
    16.         dev_err(&pdev->dev, "no memory for flash info ");
    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 clock ");
    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 region ");
    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 region ");
    48.         err = -EIO;
    49.         goto exit_error;
    50.     }

    51.     dev_dbg(&pdev->dev, "mapped registers at %p ", 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 storage ");
    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) ", 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 support ");
    86.         goto exit_error;
    87.     }

    88.     if (allow_clk_stop(info)) {
    89.         dev_info(&pdev->dev, "clock idle support enabled ");
    90.         clk_disable(info->clk);
    91.     }

    92.     pr_debug("initialised ok ");
    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. }


    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    mojo 接口示例
    MojoliciousLite: 实时的web框架 概述
    接口返回json
    centos 6.7 perl 版本 This is perl 5, version 22 安装DBI DBD
    centos 6.7 perl 5.22 安装DBD 需要使用老的perl版本
    商业智能改变汽车行业
    商业智能改变汽车行业
    读MBA经历回顾(上)目的决定手段——北漂18年(48)
    perl 升级到5.20版本
    Group Commit of Binary Log
  • 原文地址:https://www.cnblogs.com/ch122633/p/7363296.html
Copyright © 2011-2022 走看看