精华内容
下载资源
问答
  • 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
    

    在这里插入图片描述

    展开全文
  • 一、MTD框架 MTD设备通常可分为四层 上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。 设备框架 二、MTD分区表的实现 在开机过程从console经常可以看到类似以下信息, 0x000000000000-...

    一、MTD框架

    MTD设备通常可分为四层

    上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。

    设备框架

    二、MTD分区表的实现


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

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

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

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


    1、内核中添加

    在内核中添加这是一个比较经常使用的方法,随便一本驱动移植的书上应该都有,主要就是在平台设备里面添加mtd_partition(目录例:arch\arm\mach-s3c24xx\mach-mini2440.c),添加类似下面的信息

    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)

    为了使kernel能够解析mtdparts信息,我们需要将内核中的Device Drivers -> Memory Technology Device (MTD) support ->Command line partition table parsing选项开启。u-boot下需要对MTD进行支持(只传个mtdparts字串,uboot不必须要mtd设备驱动代码吧),且所传输的mtd分区参数要符合格式要求。那怎样解析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参数的解析。

    mtdparts字串格式

    mtdparts=mtd-id:<size1>@<offset1>(<name1>),<size2>@<offset2>(<name2>)

    这有几个需要注意的地方:

    a、mtd-id 必须要跟你当前平台的flash的mtd-id一致,不然整个mtdparts会失效 怎样获取到当前平台的flash的mtd-id?在bootargs参数列表中,可以指定当前flash的mtd-id,指定 mtdids:nand0=gen_nand.1,前面的nand0则表示第一个flash

    b、size在设置的时候可以为实际的size(xxM,xxk,xx),也可以为'-'这表示剩余的所有空间。相关信息可以查看drivers/mtd/cmdlinepart.c中的注释找到相关描述。

    c、mtdparts里mtd_id的值为tq2440-0,那么kernel的平台代码中也必须有一个名为mtd_id的分区表,平台代码中的那张分区表可以为空,因为mtdparts中已经有了,就不会解析平台代码中设置的分区表,但是分区表的名字还是要匹配的。kernel中默认的分区表的名字是“Nand”。

    mtdparts=tq2440-0:1m@0(spl)ro,1m(u-boot)ro,3m(kernel)ro,-(rootfs)
    等价于
    mtdparts=tq2440-0:1m(spl)ro,1m(u-boot)ro,3m(kernel)ro,-(rootfs)

    U-boot环境变量有两个,他们分别是: bootcmd 和bootargs。

    为了实现mtdparts分区命令的支持需要在U-boot-2010.06/include/configs/xxxxxx.h中添加相关的宏定义:

    #define CONFIG_CMD_MTDPARTS
    #define CONFIG_MTD_DEVICE
    #define CONFIG_MTD_PARTITIONS
    
    //加入MTD分区信息:
    
    #define MTDIDS_DEFAULT     "nand0=atmel_nand"
    #define MTDPARTS_DEFAULT   "mtdparts=atmel_nand:15M@0(cramfs)," \
                               "15M(jffs2)," \
                               "30M(yaffs2)," \
                               "-(user)"

    记得执行U-Boot>mtdparts default


    3、dts传参

    在Linux3.14以后的linux版本中,加入一个新的知识DTS(Device tree),dts其实就是为了解决ARM Linux中的冗余代码,关于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>;
            };
        };
    

    参考链接:

    u-boot中添加mtdparts支持以及Linux的分区设置 - 摩斯电码 - 博客园

    Linux mtd system - 简书

    展开全文
  • Linux MTD下获取Nand 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子系统学习(一)

    1 Linux MTD基本概述

    1.1 专有名词描述

    • 1. MTD:Memory Technology Device,内存技术设备。
    • 2. JEDEC:Joint Electron Device Engineering Council,电子电器设备联合会。
    • 3. CFI:Common Flash Interface,通用Flash接口,Intel发起的一个Flash的接口标准。
    • 4. OOB: out of band,某些内存技术支持out-of-band数据——例如,NAND flash每512字节的块有16个字节的extra
      data,用于纠错或元数据。
    • 5. ECC: error correction,某些硬件不仅允许对flash的访问,也有ecc功能,所有flash器件都受位交换现象的困扰。在某些情况下,一个比特位会发生反转或被报告反转了,如果此位真的反转了,就要采用ECC算法。
    • 6. erasesize: 一个erase命令可以擦除的最小块的尺寸。
    • 7. buswidth:MTD设备的接口总线宽度。
    • 8.interleave:交错数,几块芯片平行连接成一块芯片,使buswidth变大。
    • 9. devicetype:芯片类型,x8、x16或者x32。
    • 10.NAND:一种Flash技术,参看NAND和NOR的比较。
    • 11.NOR:一种Flash技术,参看NAND和NOR的比较。

    1.2 MTD介绍

    MTD(memory technology device):内存技术设备,是linux用于描述ROM,NAND,NOR等设备的子系统的抽象,MTD设备可以按块读写也可以按字节读写,也就是说MTD设备既可以是块设备也可以是字符设备,块设备(mtdblackx)操作针对文件系统,字符设备(mtdx)操作主要针对格式化等操作的测试用。
    由于块设备的I/O性能与CPU相比很差,因此,块设备的数据流往往会引入文件系统的cache机制
    注意:MTD设备既非块设备也不是字符设备,但可以同时提供字符设备和块设备接口来操作。
    在这里插入图片描述
    如上图所示,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字符设备和块设备。

    2 Linux MTD相关数据结构

    2.1 mtd_info

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

    //源码:include/linux/mtd/mtd.h

    struct mtd_info {
    	u_char type;	//mtd类型,如:MTD_NORFLASH(See:mtd-abi.h)
    	uint32_t flags;// 标志位, MTD_WRITEABLE、MTD_NO_ERASE等(See mtd-abi.h)
    	uint64_t size;	 // Total size of the MTD(mtd设备的大小)
    
    	/* "Major" erase size for the device. Na茂ve users may take this
    	 * to be the only erase size available, or may use the more detailed
    	 * information below if they desire
    	 */
    	uint32_t erasesize;//擦除大小,即flash的块大小(mtd设备可能有多个erasesize)
    	/* Minimal writable flash unit size. In case of NOR flash it is 1 (even
    	 * though individual bits can be cleared), in case of NAND flash it is
    	 * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
    	 * it is of ECC block size, etc. It is illegal to have writesize = 0.
    	 * Any driver registering a struct mtd_info must ensure a writesize of
    	 * 1 or larger.
    	 */
    	uint32_t writesize;// 写大小, 对于norFlash是字节,对nandFlash为一页
    
    	/*
    	 * Size of the write buffer used by the MTD. MTD devices having a write
    	 * buffer can write multiple writesize chunks at a time. E.g. while
    	 * writing 4 * writesize bytes to a device with 2 * writesize bytes
    	 * buffer the MTD driver can (but doesn't have to) do 2 writesize
    	 * operations, but not 4. Currently, all NANDs have writebufsize
    	 * equivalent to writesize (NAND page size). Some NOR flashes do have
    	 * writebufsize greater than writesize.
    	 */
    	uint32_t writebufsize;
    
    	uint32_t oobsize;   // Amount of OOB data per block (e.g. 16)
    	uint32_t oobavail;  // Available OOB bytes per block
    
    	/*
    	 * If erasesize is a power of 2 then the shift is stored in
    	 * erasesize_shift otherwise erasesize_shift is zero. Ditto writesize.
    	 */
    	unsigned int erasesize_shift;	//默认为0,不重要
    	unsigned int writesize_shift;	//默认为0,不重要
    	/* Masks based on erasesize_shift and writesize_shift */
    	unsigned int erasesize_mask;	//默认为1,不重要
    	unsigned int writesize_mask;	//默认为1,不重要
    
    	/*
    	 * read ops return -EUCLEAN if max number of bitflips corrected on any
    	 * one region comprising an ecc step equals or exceeds this value.
    	 * Settable by driver, else defaults to ecc_strength.  User can override
    	 * in sysfs.  N.B. The meaning of the -EUCLEAN return code has changed;
    	 * see Documentation/ABI/testing/sysfs-class-mtd for more detail.
    	 */
    	unsigned int bitflip_threshold;
    
    	// Kernel-only stuff starts here.
    	const char *name;	//mtd设备名
    	int index;
    
    
    
        /* OOB layout description */
        //nand_ecclayout结构体指针, 表示的是ecc布局,可参考硬件手册的OOB中ecc布局
    	const struct mtd_ooblayout_ops *ooblayout;
    
    	/* NAND pairing scheme, only provided for MLC/TLC NANDs */
    	const struct mtd_pairing_scheme *pairing;
    
    	/* the ecc step size. */
    	unsigned int ecc_step_size;
    
    	/* max number of correctible bit errors per ecc step */
    	unsigned int ecc_strength;
    
    	/* Data for variable erase regions. If numeraseregions is zero,
    	 * it means that the whole device has erasesize as given above.
    	 */
    	int numeraseregions;//通常为1
    	struct mtd_erase_region_info *eraseregions;//可变擦除区域
    
    	/*
    	 * Do not call via these pointers, use corresponding mtd_*()
    	 * wrappers instead.
    	 */
    	/* flash擦除函数 */
    	int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
    	int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
    		       size_t *retlen, void **virt, resource_size_t *phys);
    	int (*_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);
    	/* 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);
    	int (*_panic_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, size_t len,
    				    size_t *retlen, struct otp_info *buf);
    	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, size_t len,
    				    size_t *retlen, struct otp_info *buf);
    	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 to,
    				     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);
    	/* 同步函数 */
    	void (*_sync) (struct mtd_info *mtd);
    	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 (*_is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
    
    	/* 坏块管理函数 */
    	int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs);
    	int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);	//检查坏块
    	int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);//标记坏块
    	int (*_max_bad_blocks) (struct mtd_info *mtd, loff_t ofs, size_t len);
    
    	/* 电源管理函数 */
    	int (*_suspend) (struct mtd_info *mtd);	//挂起函数
    	void (*_resume) (struct mtd_info *mtd);//恢复函数
    	void (*_reboot) (struct mtd_info *mtd);//重启函数
    	/*
    	 * If the driver is something smart, like UBI, it may need to maintain
    	 * its own reference counting. The below functions are only for driver.
    	 */
    	int (*_get_device) (struct mtd_info *mtd);
    	void (*_put_device) (struct mtd_info *mtd);
    
    	struct notifier_block reboot_notifier;  /* default mode before reboot */
    
    	/* ECC status information */
    	struct mtd_ecc_stats ecc_stats;//ECC状态
    	/* Subpage shift (NAND) */
    	int subpage_sft;
    
     	//私有数据, cfi接口flash指向map_info结构, 或指向自定义flash相关结构体
    	void *priv; 
    	struct module *owner;
    	struct device dev;
    	int usecount;
    	struct mtd_debug_info dbg;
    };
    

    2.2 mtd_part

    Linux内核使用mtd_part结构体表示分区,其中mtd_info结构体成员用于描述该分区,大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区的相应函数。

    //源码:drivers/mtd/mtdpart.c

    struct mtd_part {
    	struct mtd_info mtd;	//分区信息,大部分来自parent
    	struct mtd_info *parent;//分区的主分区
    	uint64_t offset;		//分区的偏移地址
    	struct list_head list;		//链接到mtd_partitions链表中
    };
    

    2.3 mtd_partition

    该结构体表示某一分区的分区信息,其将被添加到mtd_partitions链表中。
    //源码:include/linux/mtd/patitions.h

    struct mtd_partition {
    	const char *name;		/* identifier string */
    	const char *const *types;	/* names of parsers to use if any */
    	uint64_t size;			/* partition size */
    	uint64_t offset;		/* offset within the master MTD space */
    	uint32_t mask_flags;		/* master MTD flags to mask out for this partition */
    	struct device_node *of_node;
    };
    

    2.4 mao_info

    //源码:include/linux/mtd/map.h

    struct map_info {
    	const char *name;		//名称
    	unsigned long size;		//大小
    	resource_size_t phys;	//物理地址
    	#define NO_XIP (-1UL)
    	void __iomem *virt;	//虚拟地址,通常通过ioremap将物理地址映射得到的
    	void *cached;
    
    	int swap; /* this mapping's byte-swapping requirement */
    	int bankwidth; /* in octets. This isn't necessarily the width
    		       of actual bus cycles -- it's the repeat interval
    		      in bytes, before you are talking to the first chip again.
    		      */
        //读写函数
        #ifdef CONFIG_MTD_COMPLEX_MAPPINGS
        	map_word (*read)(struct map_info *, unsigned long);
        	void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
    	void (*write)(struct map_info *, const map_word, unsigned long);
    	void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
    
    	/* We can perhaps put in 'point' and 'unpoint' methods, if we really
    	   want to enable XIP for non-linear mappings. Not yet though. */
    #endif
    	/* It's possible for the map driver to use cached memory in its
    	   copy_from implementation (and _only_ with copy_from).  However,
    	   when the chip driver knows some flash area has changed contents,
    	   it will signal it to the map driver through this routine to let
    	   the map driver invalidate the corresponding cache as needed.
    	   If there is no cache to care about this can be set to NULL. */
    	void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
    
    	/* This will be called with 1 as parameter when the first map user
    	 * needs VPP, and called with 0 when the last user exits. The map
    	 * core maintains a reference counter, and assumes that VPP is a
    	 * global resource applying to all mapped flash chips on the system.
    	 */
    	void (*set_vpp)(struct map_info *, int);
    
    	unsigned long pfow_base;
    	unsigned long map_priv_1;	//驱动可用的私有数据
    	unsigned long map_priv_2;
    	struct device_node *device_node;
    	void *fldrv_priv;
    	struct mtd_chip_driver *fldrv;
    };
    

    2.5 nand_chip

    源码:include/linux/mtd/nand.h

    struct nand_chip {
    	void __iomem *IO_ADDR_R;	//读写8根io线的地址
    	void __iomem *IO_ADDR_W;
    
    	uint8_t (*read_byte)(struct mtd_info *mtd);	//读一个字节
    	u16 (*read_word)(struct mtd_info *mtd);	//读一个字
    
    	//将缓冲区内容写入芯片
    	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
    	//将芯片内容读取至缓冲区
    	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
    	//验证芯片写入缓冲区的数据
    	int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
    
    	//片选芯片
    	void (*select_chip)(struct mtd_info *mtd, int chip);
    	//检测是否有坏块
    	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
    	//坏块标记
    	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
    	//命令、地址、数据控制函数
    	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
    	int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
    			u8 *id_data);
    	//检查设备是否就绪
    	int (*dev_ready)(struct mtd_info *mtd);
    	//实现命令发送
    	void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
    			int page_addr); 
    	int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
    	//擦除命令处理
    	void (*erase_cmd)(struct mtd_info *mtd, int page);
    	//扫描坏块
    	int (*scan_bbt)(struct mtd_info *mtd);
    	int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
    			int status, int page);
    	//写一页
    	int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
    			const uint8_t *buf, int page, int cached, int raw);
    
    	int chip_delay;		//有板决定延迟时间
    	unsigned int options;
    	unsigned int bbt_options;
    
    	int page_shift;	//表示page的大小,如Nand的页大小为512byte,则page_shift为9
    	int phys_erase_shift;	//擦除块的大小
    
    /* 用位表示的bad block table的大小,通常一个bbt占用一个block,
    所 以bbt_erase_shift通常与phys_erase_shift相等 */
    	int bbt_erase_shift; 
    	int chip_shift;		//芯片容量
    	int numchips;		//芯片数量
    	uint64_t chipsize;	//芯片大小
    	int pagemask;
    	int pagebuf;
    	int subpagesize;
    	uint8_t cellinfo;
    	int badblockpos;
    	int badblockbits;
    
    	int onfi_version;
    	struct nand_onfi_params	onfi_params;
    
    	flstate_t state;
    
    	uint8_t *oob_poi;
    	struct nand_hw_control *controller;
    	struct nand_ecclayout *ecclayout;	//ECC布局
    
    	struct nand_ecc_ctrl ecc;			//ECC校验结构体,含有大量ECC校验的函数
    	struct nand_buffers *buffers;
    	struct nand_hw_control hwcontrol;
    
    	uint8_t *bbt;
    	struct nand_bbt_descr *bbt_td;
    	struct nand_bbt_descr *bbt_md;
    
    	struct nand_bbt_descr *badblock_pattern;
    
    	void *priv;
    };
    

    2.6 spi_nor

    用于表示一个spi-nor设备的相关信息。

    struct spi_nor {
    	struct mtd_info		mtd;	//nor mtd信息
    	struct mutex		lock;	
    	struct device		*dev;
    	u32			page_size;	//flash的页大小
    	u8			addr_width;	//地址宽度
    	u8			erase_opcode;	//flash擦除指令
    	u8			read_opcode;	//flash 读数据指令
    	u8			read_dummy;	//读操作时的dummy数据
    	u8			program_opcode;	//页操作指令
    	enum spi_nor_protocol	read_proto;//多线读写时的相关操作
    	enum spi_nor_protocol	write_proto;
    	enum spi_nor_protocol	reg_proto;
    	bool			sst_write_second;
    
    	//标志位,如:SNOR_F_USE_FSR(See:spi-nor.h,spi_nor_option_flags)
    	u32			flags;
    	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
    
    	//为读、写、擦除、lock、unlock的相关准备工作
    	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
    	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
    
    	//读nor内部寄存器
    	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
    	//写nor内部寄存器
    	int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
    
    	//读nor内部数据
    	ssize_t (*read)(struct spi_nor *nor, loff_t from,
    			size_t len, u_char *read_buf);
    	//往nor写入数据
     	ssize_t (*write)(struct spi_nor *nor, loff_t to,
    			size_t len, const u_char *write_buf);
    	//擦除flash数据
     	int (*erase)(struct spi_nor *nor, loff_t offs);
    
    	//锁住flash的部分区域
    	int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
    	int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
    	int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
    
    	void *priv;//私有数据
    };
    

    注:以上源码基于Linux-4.14.14分析。

    展开全文
  • linux mtd emmc

    2021-04-19 21:33:42
    mtd设备是nor flash或者nand flash上的分区。 EMMC上的分区类似于/dev/sda1这种

    mtd设备是nor flash或者nand flash上的分区。

    EMMC上的分区类似于/dev/sda1这种

    展开全文
  • linux MTD子系统框架

    2020-03-26 09:11:44
    1. MTD:Memory Technology Device,内存技术设备 2. MTD分块设备和字符设备. 在/dev/目录下,可以看到类似mtd× / mtdblock× 文件 3. 打开 “/proc/mtd” 文件即可解析出MTD分区信息,从这里可以知道MTD数目,...
  • Linux MTD是什么??

    2020-09-14 11:17:31
    MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。 如上图所示,MTD设备通常可分为四层,从上到下...
  • linux mtd设备使用

    千次阅读 2019-03-20 11:17:34
    mtd-physmap 问题 开机启动打印, jffs2: Write of 109 bytes at 0x0160f61c failed. returned -5, retlen 108 jffs2: Write of 109 bytes at 0x0160f68c failed. returned -5, retlen 108 jffs2: Write of ...
  • 本篇文章我们主要说明向mtd设备驱动模型的架构及相应的数据结构,我们从数据结构入手,即可以较好的理解mtd设备驱动模型的架构,以便我们能较好的理解mtd设备驱动模。 本篇主要包括如下几个部分: 一、mtd设备...
  • Linux MTD系统详解

    千次阅读 2017-02-21 16:26:08
    看到两篇很不错的写MTD的文章,做个记录,留着备用。原作者分别是lwj103862095和zgolee,以下是两位博主的博客链接。 lwj103862095:http://blog.csdn.net/lwj103862095/article/details/21545791 zgolee:...
  • Linux MTD架构下的nand flash驱动详解

    千次阅读 2019-04-23 17:45:12
    有了前面的基础(Nandflash详解:https://blog.csdn.net/Golden_Chen/article/details/89470673),我们就可以研究MTD下的nand驱动了,我这里用的是jz4780grus开发板,我将以下面几个部分做一个介绍...
  • 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系统剖析(转载+总结)

    万次阅读 2018-06-05 19:59:43
    MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。 如上图所示,MTD设备通常可分为四层,从上到下...
  • 该项目为MTD驱动程序和JFFS2文件系统提供了一组新功能和修补程序,旨在提高MTD和JFFS2性能并减少JFFS2 RAM的使用。 错误修复程序以特定内核的补丁程序形式提供。
  • Linux MTD系统剖析

    2016-03-03 21:58:32
    MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。 如上图所示,MTD设备通常可分为四层,从上到...
  • 从今天开始,我们进行linux mtd子系统的分析。mtd子系统即为内存技术设备子系统,主要包括nor flash、nand flash等闪存设备相关的子系统模块,而针对sd、tf等存储设备,则主要由mmc子系统模块进行管理并创建对应的块...
  • http://www.linux-mtd.infradead.org/faq/ubifs.html#L_empty_file 整理一下mtd和ubi的关系,出自其他博客: https://blog.csdn.net/faithsws/article/details/5381424 初识ubifs,相信大家都是从uibfs的操...
  • linux mtd详解

    2010-06-16 08:42:39
    好资料,理解后对NANDFLASH驱动很有好处
  • linux建立MTD分区

    2013-04-24 09:52:15
    学习linux下建立mtd分区必须的资料
  • 只读文件系统不能写的文件不能保存(掉电丢失),此代码是通过linux应用层直接掉用mtd子系统提供API对flash的分区进行读写、擦除,实现文件的保存。
  • 在上篇文章中,我们介绍了mtd层相关数据结构以及接口的关联,并简要说明了mtd层与vfs、文件系统层、闪存芯片驱动层的关联,本篇文章主要介绍mtd层相关的接口,这些接口用于实现这些数据结构的关联与解绑。...
  • Linux MTD子系统学习(二) 3 Linux MTD spi-nor驱动分析 3.1 spi-nor设备驱动框架 3.2 spi-nor设备注册 如果希望一个spi设备可以在linux系统下很好的工作,除了写驱动,还要向内核申明和注册这个spi设备。目前有两...
  • Linux MTD源代码情景分析,介绍的不错。
  •  YAFFS/YAFFS2自带NAND芯片的驱动,并且为嵌入式系统提供了直接访问文件系统的API,用户可以不使用Linux中的MTD与VFS,直接对文件系统操作。当然,YAFFS也可与MTD驱动程序配合使用。这方便了其跨平台移植。 ...
  • 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 驱动

    2009-04-24 02:09:54
    这是关于linuxmtd代码分析的文档
  • 参考代码 -linux linux_4.0/drivers/mtd mtd 设备类型 include/mtd/mtd-abi.h #define MTD_ABSENT 0 #define MTD_RAM 1 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,984
精华内容 7,193
关键字:

linuxmtd

linux 订阅