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. }


    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    如何理解python中的if __name__=='main'的作用
    如何在阿里云上部署war包到tomcat服务器
    如何在windows上部署war包到tomcat服务器
    解决:mysql5.7 timestamp默认值0000-00-00 00:00:00 报错
    python3中的unicode_escape
    python中的excel操作
    python的logging模块
    python中的SMTP发送邮件
    python中的字符串
    一道问题引出的python中可变数据类型与不可变数据类型
  • 原文地址:https://www.cnblogs.com/ch122633/p/7363296.html
Copyright © 2011-2022 走看看