精华内容
下载资源
问答
  • linux mtd

    2019-12-20 17:33:08
    目录一、参考资料二、mtd-utils 工具1.使用 `cat /proc/mtd` 命令查看QSPI FLASH的分区信息2.使用 `mtd_debug info /dev/mtd0` 命令查看FLASH类型、分区大小、块大小3.使用 `flash_eraseall /dev/mtd1` 擦除选择的...

    一、参考资料

    转载自嵌入式文件系统简介(一) — Linux MTD设备文件系统

    在嵌入式系统中,与文件系统相关的存储设备包括硬盘、Flash存储器等。Flash存储器又分为Flash芯片设备(Raw Flash device,也叫MTD设备)和带Flash控制器的设备(Flash Translation Layer device, FTL设备),两者的关键区别是是否带有Flash控制器,这也直接决定了文件系统分为不同的两类。

    在这里插入图片描述

    其中MTD设备包括NOR Flash、NAND Flash等,FTL设备包括SD、eMMC、SSD、USB大容量存储设备等。如图所示JFFS2、YAFFS2、UBIF、LogFS支持MTD设备,FAT、EXT3/4、XFS和Btrfs支持 FTL设备和硬盘(HDD)。MTD设备对应的设备文件为/dev/mtd,FTL设备对应的设备文件可为/dev/mtdblock。
    在这里插入图片描述
    在这里插入图片描述

    二、mtd-utils 工具

    mtd-utils需要预先编译进linux_rootfs中,否则没有这些命令。

    1.使用 cat /proc/mtd 命令查看QSPI FLASH的分区信息

    root@zedboard:~# cat /proc/mtd
    dev:    size   erasesize  name
    mtd0: 00500000 00010000 "boot"
    mtd1: 00020000 00010000 "bootenv"
    mtd2: 00a80000 00010000 "kernel"
    mtd3: 01060000 00010000 "spare"
    

    2.使用 mtd_debug info /dev/mtd0 命令查看FLASH类型、分区大小、块大小

    root@zedboard:~# mtd_debug info /dev/mtd0
    mtd.type = MTD_NORFLASH
    mtd.flags = MTD_CAP_NORFLASH
    mtd.size = 5242880 (5M)
    mtd.erasesize = 65536 (64K)
    mtd.writesize = 1
    mtd.oobsize = 0
    regions = 0
    

    3.使用 flash_eraseall /dev/mtd1 擦除选择的某个mtd分区。

    root@zedboard:~# flash_eraseall /dev/mtd1
    flash_eraseall has been replaced by `flash_erase <mtddev> 0 0`; please use it
    Erasing 64 Kibyte @ 10000 -- 100 % complete
    

    4.使用 flashcp -v BOOT.BIN /dev/mtd0 更新linux系统固件

    更新U-BOOT。(对于ZYNQ,打包FSBL、BIT流、U-BOOT成BOOT.BIN,放在mtd0分区)

    root@zedboard:~# flashcp -v firmware/BOOT.BIN /dev/mtd0
    Erasing blocks: 7/7 (100%)
    Writing data: 395k/0k (100%)
    Verifying data: 395k/0k (100%)
    

    更新image.ub内核。

    root@zedboard:~# flashcp -v firmware/image.ub /dev/mtd2
    Erasing blocks: 1/58 (1%)random: crng init done
    Erasing blocks: 58/58 (100%)
    Writing data: 3674k/0k (100%))
    Verifying data: 3674k/0k (100%))
    

    更新jffs2根文件系统。

    root@zedboard:~# flashcp -v firmware/rootfs.jffs2 /dev/mtd3
    Erasing blocks: 104/104 (100%)
    Writing data: 6656k/0k (100%))
    Verifying data: 6656k/0k (100%))
    

    5.使用 mtd_debug read /dev/mtd0 0x0 0x20000 读取出FLASH中的数据,确认是否刷写成功

    root@zedboard_jffs2:~# mtd_debug read /dev/mtd0 0x0 0x20000 ~/test
    Copied 131072 bytes from address 0x00000000 in flash to /home/root/test
    

    在这里插入图片描述

    展开全文
  • linux mtd0信息,linux mtd

    2021-05-14 02:35:50
    Flash存储器又分为Flash芯片设备(Raw Flash device,也叫MTD设备)和带Flash控制器的设备(Flash Translation Layer device, FTL设备),两者的关键区别是是否带有Flash控制器,这也直接决定了文件系统分为不同的两类...

    一、参考资料

    在嵌入式系统中,与文件系统相关的存储设备包括硬盘、Flash存储器等。Flash存储器又分为Flash芯片设备(Raw Flash device,也叫MTD设备)和带Flash控制器的设备(Flash Translation Layer device, FTL设备),两者的关键区别是是否带有Flash控制器,这也直接决定了文件系统分为不同的两类。

    858a1ef8852e2809fb6f55091ee6fa73.png

    其中MTD设备包括NOR Flash、NAND Flash等,FTL设备包括SD、eMMC、SSD、USB大容量存储设备等。如图所示JFFS2、YAFFS2、UBIF、LogFS支持MTD设备,FAT、EXT3/4、XFS和Btrfs支持 FTL设备和硬盘(HDD)。MTD设备对应的设备文件为/dev/mtd,FTL设备对应的设备文件可为/dev/mtdblock。

    0fad4b023de06bc884735a1a097ef021.png

    二、mtd-utils 工具

    mtd-utils需要预先编译进linux_rootfs中,否则没有这些命令。

    1.使用 cat /proc/mtd 命令查看QSPI FLASH的分区信息

    [email protected]:~# cat /proc/mtd

    dev: size erasesize name

    mtd0: 00500000 00010000 "boot"

    mtd1: 00020000 00010000 "bootenv"

    mtd2: 00a80000 00010000 "kernel"

    mtd3: 01060000 00010000 "spare"

    2.使用 mtd_debug info /dev/mtd0 命令查看FLASH类型、分区大小、块大小

    [email protected]:~# mtd_debug info /dev/mtd0

    mtd.type = MTD_NORFLASH

    mtd.flags = MTD_CAP_NORFLASH

    mtd.size = 5242880 (5M)

    mtd.erasesize = 65536 (64K)

    mtd.writesize = 1

    mtd.oobsize = 0

    regions = 0

    3.使用 flash_eraseall /dev/mtd1 擦除选择的某个mtd分区。

    [email protected]:~# flash_eraseall /dev/mtd1

    flash_eraseall has been replaced by `flash_erase 0 0`; please use it

    Erasing 64 Kibyte @ 10000 -- 100 % complete

    4.使用 flashcp -v BOOT.BIN /dev/mtd0 更新linux系统固件

    更新U-BOOT。(对于ZYNQ,打包FSBL、BIT流、U-BOOT成BOOT.BIN,放在mtd0分区)

    [email protected]:~# flashcp -v firmware/BOOT.BIN /dev/mtd0

    Erasing blocks: 7/7 (100%)

    Writing data: 395k/0k (100%)

    Verifying data: 395k/0k (100%)

    更新image.ub内核。

    [email protected]:~# flashcp -v firmware/image.ub /dev/mtd2

    Erasing blocks: 1/58 (1%)random: crng init done

    Erasing blocks: 58/58 (100%)

    Writing data: 3674k/0k (100%))

    Verifying data: 3674k/0k (100%))

    更新jffs2根文件系统。

    [email protected]:~# flashcp -v firmware/rootfs.jffs2 /dev/mtd3

    Erasing blocks: 104/104 (100%)

    Writing data: 6656k/0k (100%))

    Verifying data: 6656k/0k (100%))

    5.使用 mtd_debug read /dev/mtd0 0x0 0x20000 读取出FLASH中的数据,确认是否刷写成功

    [email protected]_jffs2:~# mtd_debug read /dev/mtd0 0x0 0x20000 ~/test

    Copied 131072 bytes from address 0x00000000 in flash to /home/root/test

    a9fe87f9309308e4093c0fad34fba611.png

    展开全文
  • Linux MTD源代码分析

    2011-07-26 16:13:37
    Linux MTD源代码分析 Linux MTD源代码分析
  • 6-Linux mtd system

    千次阅读 2016-12-05 15:12:11
    Linux MTD system

    Linux mtd system

    MTD(Memory Technology Device),内存技术设备是Linux的存储设备中的一个子系统。其设计此系统的目的是,对于内存类的设备,提供一个抽象层,一个接口,使得对于硬件驱动设计者来说,只需要去提供最简单的底层硬件设备的读/写/擦除函数就可以了,数据对于上层使用者来说是如何表示的,可以不关心,因为MTD存储设备子系统都帮你做好了。

    MTD框架

    Linux的MTD设备位于drivers/mtd/下面,这边只对其目录结构进行大致的分析,如果想了解具体的细节可以查看crifan的博客,里面有很多连接和文章可供参考,分析的很透彻,MTD文件下的内容如下:

    这里写图片描述
    MTD设备通常可分为四层

    上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。
    这里写图片描述

    1.cmdlinepart.c

    当mtd分区表由u-boot通过cmd参数传输给linux时,linux内核可以不用对mtdparts进行注册添加,只需要将MTD中的command line partition选项开启即可。使用这种的方法u-boot下需要对MTD进行支持,且所传输的mtd分区参数要符合格式要求。

    2.devices文件夹

    当我们有一个spi flash设备时且要使用mtd进行管理,我们一般会将其放在devices文件夹下,如devices文件夹下面的m25p80.c就是一个典型的spi flash设备。

    3.chips/maps/nand/onenand文件夹

    nand flash 驱动在nand文件夹下;

    onenand flash 驱动在onenand文件夹下;

    nor flash比较杂,下面几个文件下都会有:

    • chips:cfi/jedec接口通用驱动
    • devices:nor flash底层驱动(spi flash)
    • maps:nor flash映射关系相关函数

    4.核心文件

    mtdchar.c : MTD字符设备接口相关实现,设备号31;

    mtdblock.c : MTD块设备接口相关实现,设备号90,;

    mtdcore.c: MTD原始设备接口相关实现;

    mtdpart.c : MTD分区接口相关实现。

    5.ubi

    ubifs文件的支持层,当使用ubifs文件系统时,需要将Device Drivers -> Memory Technology Device (MTD) support -> UBI -Unsorted block image 中的Enable UBI选中。

    将File systems -> Miscellaneous filesystems中的UBIFS file system support选中。

    MTD分区表的实现

    在开机过程从console经常可以看到类似以下信息,

    0x000000000000-0x000000100000 : "Bootloade"
    0x000000100000-0x000002000000 : "Kernel"
    0x000002000000-0x000003000000 : "User"
    0x000003000000-0x000008000000 : "File System"
    
    

    这就是MTD给我们一种最直观的表示形式,给我们展示了内存中各模块的分区结构,但这些分区是怎样实现的呢?分区表的实现方式有几种,下面进行分别说明:

    注:分区表实现的前提是MTD设备驱动已经成功了,否则连驱动都没成功就无分区可说了。

    1.内核中添加

    在内核中添加这是一个比较经常使用的方法,随便一本驱动移植的书上应该都有,主要就是在平台设备里面添加mtd_partition,添加类似下面的信息,这边就不过多描述

    struct mtd_partition s3c_nand_part[] = {
        {
            .name       = "Bootloader",
            .offset     = 0,
            .size       = (1 * SZ_1M),
            .mask_flags = MTD_CAP_NANDFLASH,
        },
        {
            .name       = "Kernel",
            .offset     = (1 * SZ_1M),
            .size       = (31 * SZ_1M) ,
            .mask_flags = MTD_CAP_NANDFLASH,
        },
        {
            .name       = "User",
            .offset     = (32 * SZ_1M),
            .size       = (16 * SZ_1M) ,
        },
        {
            .name       = "File System",
            .offset     = (48 * SZ_1M),
            .size       = (96 * SZ_1M),
        }
    };
    
    static struct s3c_nand_set s3c_nand_sets[] = {
        [0] = {
            .name       = "nand",
            .nr_chips   = 1,
            .nr_partitions  = ARRAY_SIZE(s3c_nand_part),
            .partitions = ok6410_nand_part,
        },
    };
    
    static struct s3c_platform_nand s3c_nand_info = {
        .tacls      = 25,
        .twrph0     = 55,
        .twrph1     = 40,
        .nr_sets    = ARRAY_SIZE(s3c_nand_sets),
        .sets       = ok6410_nand_sets,
    };
    
    static void __init s3c_machine_init(void)
    {
        s3c_nand_set_platdata(&s3c_nand_info); 
    }
    
    

    因为我们的MTD驱动已经完成了,当device和driver匹配后会调用驱动中的probe接口函数,我们需要在probe函数里面调用add_mtd_partitions(s3c_mtd, sets->partitions, sets->nr_partitions);实现分区表的添加。

    2.u-boot传参

    在u-boot下可以通过添加mtdparts信息到bootargs中,u-boot启动后会将bootargs中的信息传送给kernel,,kernel在启动的时候会解析bootargs中mtdparts的部分,这边举个例子:

    mtdparts=nand.0:1M(Bootloader)ro,31M(Kernel)ro,16M(User),96M(File System),更具体的mtdparts格式可以查阅下相关资料。

    为了使kernel能够解析mtdparts信息,我们需要将内核中的Device Drivers -> Memory Technology Device (MTD) support ->Command line partition table parsing选项开启,这在上面已经说过。

    在内核中添加分区表的时候,我们是在平台设备里面加入mtd_partition信息。这边通过u-boot传参则取消平台设备里面的partition信息,那我们需要怎样解析u-boot的传过来的mtdparts呢。

    u-boot传参过来后,cmdlinepart.c中会将这些参数解析好,存在里面LIST_HEAD(part_parsers)链表里面,然后我们在驱动的probe函数中,通过调用mtd_device_parse_register(mtd, probe_types,&ppdata, NULL, 0);函数。

    mtd_device_parse_register()函数位于drivers/mtd/mtdcore.c 中,内容如下:

    int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
                      struct mtd_part_parser_data *parser_data,
                      const struct mtd_partition *parts,
                      int nr_parts)
    {
        int err;
        struct mtd_partition *real_parts;
    
        err = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
        if (err <= 0 && nr_parts && parts) {
            real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
                         GFP_KERNEL);
            if (!real_parts)
                err = -ENOMEM;
            else
                err = nr_parts;
        }
    
        if (err > 0) {
            err = add_mtd_partitions(mtd, real_parts, err);
            kfree(real_parts);
        } else if (err == 0) {
            err = add_mtd_device(mtd);
            if (err == 1)
                err = -ENODEV;
        }
    
        return err;
    }
    
    

    可以看到该函数会先执行parse_mtd_partitions(mtd, types, &real_parts, parser_data);函数,后面还是通过add_mtd_partitions()函数来实现分区表的添加。

    parse_mtd_partitions()函数位于drivers/mtd/mtdpart.c中,内容如下:

    int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
                 struct mtd_partition **pparts,
                 struct mtd_part_parser_data *data)
    {
        struct mtd_part_parser *parser;
        int ret = 0;
    
        if (!types)
            types = default_mtd_part_types;
    
        for ( ; ret <= 0 && *types; types++) {
            parser = get_partition_parser(*types);
            if (!parser && !request_module("%s", *types))
                parser = get_partition_parser(*types);
            if (!parser)
                continue;
            ret = (*parser->parse_fn)(master, pparts, data);
            put_partition_parser(parser);
            if (ret > 0) {
                printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
                       ret, parser->name, master->name);
                break;
            }
        }
        return ret;
    }
    

    进入parse_mtd_partitions()函数会先判断types的类型,如果为空则给默认值,types的类型一般就两种,如下:

    static const char * const default_mtd_part_types[] = {
        "cmdlinepart",
        "ofpart",
        NULL
    };
    

    第一个"cmdlinepart"即u-boot传参的方式,第二个"ofpart"即下面要讲到的使用dts传参的方式,判断完类型后,就通过get_partition_parser去解析part_parsers链表里面的数据,这样就完成u-boot参数的解析。

    3.dts传参

    在Linux3.14以后的linux版本中,加入一个新的知识DTS(Device tree),dts其实就是为了解决ARM Linux中的冗余代码,在Linux2.6版本的arch/arm/plat.xxx和arch/arm/mach.xxx中充斥着大量的垃圾代码,采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码,关于dts可以自行查阅资料。

    dts传参的原理其实和u-boot一样,区别在于:u-boot的时候是通过cmdlinepart.c文件实现分区信息写入LIST_HEAD(part_parsers)链表,dts则是用过ofpart.c文件实现分区信息写入LIST_HEAD(part_parsers)链表,所以同样要把ofpart.c文件的宏打开,在调用mtd_device_parse_register(mtd, probe_types,&ppdata, NULL, 0);函数的时候types要设置成ofpart。

    如果去对比Linux2.6版本和Linux3.14版本,会发现drivers/mtd/ofpart.c和drivers/mtd/mtdpart.c文件有所不同,Linux3.8版本里面多了Device tree这一部分的内容,感兴趣的可以自己深究下。

    这边举个dts的例子:

     pinctrl-0 = <&s3c_nand_flash>;
        ranges = <0 0 0x000000000000 0x000008000000>;   /* CS0: NAND */
        nand@0,0 {
            partition@1 {
                label = "Bootloader";
                reg = <0x000000000000 0x000000100000>;
            };
            partition@2 {
                label = "Kernel";
                reg = <0x000000100000 0x000002000000>;
            };
            partition@3 {
                label = "User";
                reg = <0x000002000000 0x000003000000>;
            };
            partition@4 {
                label = "File System";
                reg = <0x000003000000 0x000008000000>;
            };
        };
    

    MTD分区表的三种实现方式这边做了简单介绍,具体还需自行深入研究实践,有误的地方还请指正修改。

    注:以上内容都是本人在学习过程积累的一些心得,难免会有参考到其他文章的一些知识,如有侵权,请及时通知我,我将及时删除或标注内容出处。文章只是起一个引导作用,详细的数据解析内容还请查看Linux相关教程,感谢您的查阅。

    展开全文
  • Linux MTD系统剖析

    2017-11-01 20:22:51
    Linux MTD系统剖析 MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。 如上图所示,MTD...

    Linux MTD系统剖析

    MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。


    如上图所示,MTD设备通常可分为四层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层、硬件驱动层。

    Flash硬件驱动层:Flash硬件驱动层负责对Flash硬件的读、写和擦除操作。MTD设备的Nand Flash芯片的驱动则drivers/mtd/nand/子目录下,Nor Flash芯片驱动位于drivers/mtd/chips/子目录下。

    MTD原始设备层:用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。其中mtdcore.c:  MTD原始设备接口相关实现,mtdpart.c :  MTD分区接口相关实现。

    MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)字符设备(设备号90)。其中mtdchar.c :  MTD字符设备接口相关实现,mtdblock.c : MTD块设备接口相关实现。

    设备节点:通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)MTD字符设备节点(主设备号为90)。通过访问此设备节点即可访问MTD字符设备和块设备 

    MTD数据结构:

    1.Linux内核使用mtd_info结构体表示MTD原始设备,这其中定义了大量关于MTD的数据和操作函数(后面将会看到),所有的mtd_info结构体存放在mtd_table结构体数据里。在/drivers/mtd/mtdcore.c里:

    struct mtd_info *mtd_table[MAX_MTD_DEVICES]; 
    2.Linux内核使用mtd_part结构体表示分区,其中mtd_info结构体成员用于描述该分区,大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区的相应函数。
    struct mtd_part {  
        struct mtd_info mtd;        /* 分区信息, 大部分由master决定 */  
        struct mtd_info *master;    /* 分区的主分区 */  
        uint64_t offset;            /* 分区的偏移地址 */  
        int index;                  /* 分区号 (Linux3.0后不存在该字段) */  
        struct list_head list;      /* 将mtd_part链成一个链表mtd_partitons */  
        int registered;  
    };
    mtd_info结构体主要成员,为了便于观察,将重要的数据放在前面,不大重要的编写在后面。

    struct mtd_info {  
        u_char type;         /* MTD类型,包括MTD_NORFLASH,MTD_NANDFLASH等(可参考mtd-abi.h) */  
        uint32_t flags;      /* MTD属性标志,MTD_WRITEABLE,MTD_NO_ERASE等(可参考mtd-abi.h) */  
        uint64_t size;       /* mtd设备的大小 */  
        uint32_t erasesize;  /* MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小 */  
        uint32_t writesize;  /* 写大小, 对于norFlash是字节,对nandFlash为一页 */  
        uint32_t oobsize;    /* OOB字节数 */  
        uint32_t oobavail;   /* 可用的OOB字节数 */  
        unsigned int erasesize_shift;   /* 默认为0,不重要 */  
        unsigned int writesize_shift;   /* 默认为0,不重要 */  
        unsigned int erasesize_mask;    /* 默认为1,不重要 */  
        unsigned int writesize_mask;    /* 默认为1,不重要 */  
        const char *name;               /* 名字,   不重要*/  
        int index;                      /* 索引号,不重要 */  
        int numeraseregions;            /* 通常为1 */  
        struct mtd_erase_region_info *eraseregions; /* 可变擦除区域 */  
          
        void *priv;     /* 设备私有数据指针,对于NandFlash来说指nand_chip结构体 */  
        struct module *owner;   /* 一般设置为THIS_MODULE */  
          
        /* 擦除函数 */  
        int (*erase) (struct mtd_info *mtd, struct erase_info *instr);  
      
        /* 读写flash函数 */  
        int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
        int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
      
        /* 带oob读写Flash函数 */  
        int (*read_oob) (struct mtd_info *mtd, loff_t from,  
                 struct mtd_oob_ops *ops);  
        int (*write_oob) (struct mtd_info *mtd, loff_t to,  
                 struct mtd_oob_ops *ops);  
      
        int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
        int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
        int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
        int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
        int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
        int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);  
      
        int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);  
        int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
        /* Sync */  
        void (*sync) (struct mtd_info *mtd);  
      
        /* Chip-supported device locking */  
        int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
        int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
      
        /* 电源管理函数 */  
        int (*suspend) (struct mtd_info *mtd);  
        void (*resume) (struct mtd_info *mtd);  
      
        /* 坏块管理函数 */  
        int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);  
        int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);  
      
        void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);  
        unsigned long (*get_unmapped_area) (struct mtd_info *mtd,  
                            unsigned long len,  
                            unsigned long offset,  
                            unsigned long flags);  
        struct backing_dev_info *backing_dev_info;  
        struct notifier_block reboot_notifier;  /* default mode before reboot */  
      
        /* ECC status information */  
        struct mtd_ecc_stats ecc_stats;  
        int subpage_sft;  
        struct device dev;  
        int usecount;  
        int (*get_device) (struct mtd_info *mtd);  
        void (*put_device) (struct mtd_info *mtd);  
    };  

    mtd_info结构体中的read()、write()、read_oob()、write_oob()、erase()是MTD设备驱动要实现的主要函数,幸运的是Linux大牛已经帮我们实现了一套适合大部分FLASH设备的mtd_info成员函数。

    如果MTD设备只有一个分区,那么使用下面两个函数注册和注销MTD设备。

    int add_mtd_device(struct mtd_info *mtd)  
    int del_mtd_device (struct mtd_info *mtd)  
    如果MTD设备存在其他分区,那么使用下面两个函数注册和注销MTD设备。

    int add_mtd_partitions(struct mtd_info *master,const struct mtd_partition *parts,int nbparts)  
    int del_mtd_partitions(struct mtd_info *master) 

    其中mtd_partition结构体表示分区的信息

    [cpp] view plain copy
    1. struct mtd_partition {  
    2.     char *name;             /* 分区名,如TQ2440_Board_uboot、TQ2440_Board_kernel、TQ2440_Board_yaffs2 */  
    3.     uint64_t size;          /* 分区大小 */  
    4.     uint64_t offset;        /* 分区偏移值 */  
    5.     uint32_t mask_flags;    /* 掩码标识,不重要 */  
    6.     struct nand_ecclayout *ecclayout;   /* OOB布局 */  
    7.     struct mtd_info **mtdp;     /* pointer to store the MTD object */  
    8. };  
    9. 其中nand_ecclayout结构体:  
    10. struct nand_ecclayout {  
    11.     __u32 eccbytes;     /* ECC字节数 */  
    12.     __u32 eccpos[64];   /* ECC校验码在OOB区域存放位置 */  
    13.     __u32 oobavail;       
    14.     /* 除了ECC校验码之外可用的OOB字节数 */  
    15.     struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];  
    16. };  
    关于nand_ecclayout结构体实例,更多可参考drivers/mtd/nand/nand_base.c下的nand_oob_8、nand_oob_16、nand_oob_64实例。
    MTD设备层:

    mtd字符设备接口:

    /drivers/mtd/mtdchar.c文件实现了MTD字符设备接口,通过它,可以直接访问Flash设备,与前面的字符驱动一样,通过file_operations结构体里面的open()、read()、write()、ioctl()可以读写Flash,通过一系列IOCTL 命令可以获取Flash 设备信息、擦除Flash、读写NAND 的OOB、获取OOB layout 及检查NAND 坏块等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL) 

    mtd块设备接口:

    /drivers/mtd/mtdblock.c文件实现了MTD块设备接口,主要原理是将Flash的erase block 中的数据在内存中建立映射,然后对其进行修改,最后擦除Flash 上的block,将内存中的映射块写入Flash 块。整个过程被称为read/modify/erase/rewrite 周期。 但是,这样做是不安全的,当下列操作序列发生时,read/modify/erase/poweroff,就会丢失这个block 块的数据。
    MTD硬件驱动层:

    Linux内核再MTD层下实现了通用的NAND驱动(/driver/mtd/nand/nand_base.c),因此芯片级的NAND驱动不再需要实现mtd_info结构体中的read()、write()、read_oob()、write_oob()等成员函数。

    MTD使用nand_chip来表示一个NAND FLASH芯片, 该结构体包含了关于Nand Flash的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制。

    [cpp] view plain copy
    1. struct nand_chip {  
    2.     void  __iomem   *IO_ADDR_R;     /* 读8位I/O线地址 */  
    3.     void  __iomem   *IO_ADDR_W;     /* 写8位I/O线地址 */  
    4.   
    5.     /* 从芯片中读一个字节 */  
    6.     uint8_t (*read_byte)(struct mtd_info *mtd);       
    7.     /* 从芯片中读一个字 */  
    8.     u16     (*read_word)(struct mtd_info *mtd);       
    9.     /* 将缓冲区内容写入芯片 */  
    10.     void    (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);      
    11.     /* 读芯片读取内容至缓冲区/ */  
    12.     void    (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);  
    13.     /* 验证芯片和写入缓冲区中的数据 */  
    14.     int     (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);  
    15.     /* 选中芯片 */  
    16.     void    (*select_chip)(struct mtd_info *mtd, int chip);  
    17.     /* 检测是否有坏块 */  
    18.     int     (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);  
    19.     /* 标记坏块 */  
    20.     int     (*block_markbad)(struct mtd_info *mtd, loff_t ofs);  
    21.     /* 命令、地址、数据控制函数 */  
    22.     void    (*cmd_ctrl)(struct mtd_info *mtd, int dat,unsigned int ctrl);  
    23.     /* 设备是否就绪 */  
    24.     int     (*dev_ready)(struct mtd_info *mtd);  
    25.     /* 实现命令发送 */  
    26.     void    (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);  
    27.     int     (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);  
    28.     /* 擦除命令的处理 */  
    29.     void    (*erase_cmd)(struct mtd_info *mtd, int page);  
    30.     /* 扫描坏块 */  
    31.     int     (*scan_bbt)(struct mtd_info *mtd);  
    32.     int     (*errstat)(struct mtd_info *mtd, struct nand_chip *thisint state, int status, int page);  
    33.     /* 写一页 */  
    34.     int     (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,  
    35.                       const uint8_t *buf, int page, int cached, int raw);  
    36.   
    37.     int     chip_delay;         /* 由板决定的延迟时间 */  
    38.     /* 与具体的NAND芯片相关的一些选项,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等 */  
    39.     unsigned int    options;      
    40.   
    41.     /* 用位表示的NAND芯片的page大小,如某片NAND芯片 
    42.      * 的一个page有512个字节,那么page_shift就是9  
    43.      */  
    44.     int      page_shift;  
    45.     /* 用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可 
    46.      * 擦除16K字节(通常就是一个block的大小),那么phys_erase_shift就是14 
    47.      */  
    48.     int      phys_erase_shift;  
    49.     /* 用位表示的bad block table的大小,通常一个bbt占用一个block, 
    50.      * 所以bbt_erase_shift通常与phys_erase_shift相等 
    51.      */  
    52.     int      bbt_erase_shift;  
    53.     /* 用位表示的NAND芯片的容量 */  
    54.     int      chip_shift;  
    55.     /* NADN FLASH芯片的数量 */  
    56.     int      numchips;  
    57.     /* NAND芯片的大小 */  
    58.     uint64_t chipsize;  
    59.     int      pagemask;  
    60.     int      pagebuf;  
    61.     int      subpagesize;  
    62.     uint8_t  cellinfo;  
    63.     int      badblockpos;  
    64.     nand_state_t    state;  
    65.     uint8_t     *oob_poi;  
    66.     struct nand_hw_control  *controller;  
    67.     struct nand_ecclayout   *ecclayout; /* ECC布局 */  
    68.       
    69.     struct nand_ecc_ctrl ecc;   /* ECC校验结构体,里面有大量的函数进行ECC校验 */  
    70.     struct nand_buffers *buffers;  
    71.     struct nand_hw_control hwcontrol;  
    72.     struct mtd_oob_ops ops;  
    73.     uint8_t     *bbt;  
    74.     struct nand_bbt_descr   *bbt_td;  
    75.     struct nand_bbt_descr   *bbt_md;  
    76.     struct nand_bbt_descr   *badblock_pattern;  
    77.     void        *priv;  
    78. };  
    最后,我们来用图表的形式来总结一下,MTD设备层、MTD原始设备层、FLASH硬件驱动层之间的联系。














    展开全文
  • Linux MTD子系统学习(四) 5 Linux mtd设备注册 5.1 mtd字符设备注册 5.1.1 init_mtd 源码:drivers/mtd/mtdcore.c static int __init init_mtd(void) { int ret; ret = class_register(&mtd_class); if ...
  • Linux MTD子系统学习(三)

    千次阅读 2019-06-22 09:55:41
    Linux MTD子系统学习(三) 4 Linux mtd分区的建立 4.1 mtd分区的建立方法 4.1.1 内核添加 在内核中添加分区表是就内核常用的方法,主要是在平台设备中添加mtd_parttion,如下: struct mtd_partition m25p80_part[]...
  • linux mtd源代码分析

    2008-10-09 15:23:51
    linux mtd源代码分析,FLASH
  • Linux MTD子系统学习(一)

    千次阅读 2019-06-22 09:33:55
    Linux MTD子系统学习(一) 1 Linux MTD基本概述 1.1 专有名词描述 1. MTD:Memory Technology Device,内存技术设备。 2. JEDEC:Joint Electron Device Engineering Council,电子电器设备联合会。 3. CFI:...
  • linux MTD源码学习报告.doc mtd源代码分析
  • Linux MTD源代码情景分析,介绍的不错。
  • 题图:gratisographyLinux mtd systemMTD(Memory Technology Device),内存技术设备是Linux的存储设备中的一个子系统。其设计此系统的目的是,对于内存类的设备,提供一个抽象层,一个接口,使得对于硬件驱动设计者来...
  • Linux MTD源代码分析 详细介绍linux MTD体系与具体实现,并结合源代码分析
  • Linux MTD子系统学习(二) 3 Linux MTD spi-nor驱动分析 3.1 spi-nor设备驱动框架 3.2 spi-nor设备注册 如果希望一个spi设备可以在linux系统下很好的工作,除了写驱动,还要向内核申明和注册这个spi设备。目前有两...
  • Linux MTD support for Spansion 65nm GL devices, This package contains patches to modify the Linux kernel and MTD utilities for 65nm GL-S devices.
  • linux mtd emmc

    2021-04-19 21:33:42
    mtd设备是nor flash或者nand flash上的分区。 EMMC上的分区类似于/dev/sda1这种
  • 从今天开始,我们进行linux mtd子系统的分析。mtd子系统即为内存技术设备子系统,主要包括nor flash、nand flash等闪存设备相关的子系统模块,而针对sd、tf等存储设备,则主要由mmc子系统模块进行管理并创建对应的块...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,709
精华内容 683
关键字:

linuxmtd

linux 订阅