what is MTD?

2010-7-20

what is MTD?

Description:

MTD(memory technology device内存技术设备)是用于访问memory设备(ROMflash)的Linux的子系统。MTD的主要目的是为了使新的memory设备的驱 动更加简单,为此它在硬件和上层之间提供了一个抽象的接口。MTD的所有源代码在/drivers/mtd子目录下。CFI接口的MTD设备分为四层(从 设备节点直到底层硬件驱动),这四层从上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。

  MTD原始设备描述

  所有组成MTD原始设备的Flash芯片必须是同类型(无论是interleave还是地址相 连),在描述MTD原始设备数据结构中采用同一结构描述组成Flash芯片。每个MTD原始设备有一个mtd_info结构,其中的priv指针指向一个 map_info结构,map_info结构中的fldrv_priv指向一个cfi_private结构,cfi_private结构的cfiq指针指 向一个cfi_ident结构,chips指针指向一个flchip结构的数组。其中mtd_infomap_infocfi_private结构用 于描述MTD原始设备,因为组成MTD原始设备的NORFlash相同,cfi_ident结构用于描述Flash芯片信息;而flchip结构用于描 述每个Flash芯片专有信息。

  根文件系统

  文件系统

  字符设备节点

  MTD字符设备

  MTD块设备

  MTD原始设备

  FLASH硬件驱动

  块设备节点

  一、Flash硬件驱动层:硬件驱动层负责在init时驱动Flash硬件,Linux MTD设备的NOR Flash芯片驱动遵循CFI接口标准,其驱动程序位于drivers/mtd/chips子目录下。NANDFlash的驱动程 序则位于/drivers/mtd/nand子目录下

  二、MTD原始设备:原始设备层有两部分组成,一部分是MTD原始设备的通用代码,另一部分是 各个特定的Flash的数据,例如分区。

  用于描述MTD原始设备的数据结构是mtd_info,这其中定义了大量的关于MTD的数据和 操作函数。mtd_tablemtdcore.c)则是所有MTD原始设备的列表,mtd_partmtd_part.c)是用于表示MTD原始设备 分区的结构,其中包含了mtd_info,因为每一个分区都是被看成一个MTD原始设备加在mtd_table中的,mtd_part.mtd_info 中的大部分数据都从该分区的主分区mtd_part->master中获得。

  在drivers/mtd/maps/子目录下存放的是特定的flash的数据,每一个文件都 描述了一块板子上的flash。其中调用add_mtd_device()del_mtd_device()建立/删除 mtd_info结构并将其加入/删除mtd_table(或者调用add_mtd_partition()del_mtd_partition()mtdpart.c)建立/删除mtd_part结构并将mtd_part.mtd_info加入/删除mtd_table 中)。

  三、MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号 31)和字符设备(设备号90)。MTD字符设备的定义在mtdchar.c中实现,通过注册一系列file operation函数(lseekopenclosereadwrite)。MTD块设备则是定义了一个描述MTD块设备的结构 mtdblk_dev,并声明了一个名为mtdblks的指针数组,这数组中的每一个mtdblk_devmtd_table中的每一个 mtd_info一一对应。

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

  五、根文件系统:在Bootloader中将JFFS(或JFFS2)的文件系统映像 jffs.image(或jffs2.img)烧到flash的某一个分区中,在/arch/arm/mach-your/arch.c文件的 your_fixup函数中将该分区作为根文件系统挂载。

  六、文件系统:内核启动后,通过mount 命令可以将flash中的其余分区作为文件系统挂载到mountpoint上。

  设备层和原始设备层的函数调用关系(红色部分需要我们实现):

  一个MTD原始设备可以通过mtd_part分割成数个MTD原始设备注册进 mtd_tablemtd_table中的每个MTD原始设备都可以被注册成一个MTD设备,其中字符设备的主设备号为90,次设备号为0246…(奇数次设备号为只读设备),块设备的主设备号为31,次设备号为0123…

  mtd_notifier mtd_notifier

  字符设备 mtd_fops 块设备 mtd_fops

  (mtdchar.c) (mtdblock.cmtdblks

  设备层

  register_mtd_user()

  get_mtd_device()

  unregister_mtd_user()

  put_mtd_device()

  erase_info

  mtd_notifiers

  mtd_table

  mtd_info

  mtd_part

  (mtdcore.c

  (mtdpart.c

  Your Flash

  (your-flash.c

  add_mtd_partitions()

  del_mtd_partitions()

  原始设备层 add_mtd_device()

  del_mtd_device()

  mtd_partition

  NORFlash芯片驱动与MTD原始设备

  所有的NORFlash的驱动(探测probe)程序都放在 drivers/mtd/chips下,一个MTD原始设备可以由一块或者数块相同的Flash芯片组成。假设由4devicetypex8Flash,每块大小为8Minterleave2,起始地址为0x01000000,地址相连,则构成一个MTD原始设备 (0x01000000-0x03000000),其中两块interleave成一个chip,其地址从0x010000000x02000000, 另两块interleave成一个chip,其地址从0x020000000x03000000

  请注意,所有组成一个MTD原始设备的Flash芯片必须是同类型的(无论是 interleave还是地址相连),在描述MTD原始设备的数据结构中也只是采用了同一个结构来描述组成它的Flash芯片。

  0x03000000

  0x02000000

  0x01000000

  每个MTD原始设备都有一个mtd_info 结构,其中的priv指针指向一个map_info结构,map_info结构中的fldrv_priv指向一个cfi_private结 构,cfi_private结构的cfiq指针指向一个cfi_ident结构,chips指针指向一个flchip结构的数组。其中mtd_infomap_infocfi_private结构用于描述MTD原始设备;因为组成MTD原始设备的NORFlash相同,cfi_ident结构用于描 述flash芯片的信息;而flchip结构用于描述每个Flash芯片的专有信息(比如说起始地址)

 

转载于:https://www.cnblogs.com/nickchan/archive/2012/07/21/3104398.html

<think>我们正在讨论嵌入式系统中MTD分区的配置查看。MTD(MemoryTechnologyDevice)是Linux内核中用于管理闪存设备的子系统,支持NORFlash、NANDFlash等。以下步骤将指导你如何查看和配置MTD分区。###一、查看MTD分区信息在Linux系统中,MTD分区信息可以通过以下方式查看:####1.使用`/proc/mtd`虚拟文件```bashcat/proc/mtd```输出示例:```dev:sizeerasesizenamemtd0:0004000000020000"bootloader"mtd1:0020000000020000"kernel"mtd2:0040000000020000"rootfs"```-**字段说明**:-`dev`:MTD设备编号(如`mtd0`)-`size`:分区大小(十六进制)-`erasesize`:擦除块大小-`name`:分区名称[^2]####2.使用`mtdinfo`工具(需安装`mtd-utils`)```bashmtdinfo/dev/mtd0```输出详细参数,包括分区类型(NOR/NAND)、可擦除块数量等。####3.通过`sysfs`接口查看```bashls/sys/class/mtd/```每个`mtdX`目录包含分区的详细信息(如`name`、`size`、`erasesize`)。---###二、配置MTD分区MTD分区通常在Linux内核或设备树中定义。以下是两种主流方法:####方法1:在内核源码中硬编码(不推荐)修改板级配置文件(如`arch/arm/mach-xxx/board-yyy.c`):```c#include<linux/mtd/partitions.h>staticstructmtd_partitionmy_flash_parts[]={{.name="bootloader",.offset=0,//起始偏移.size=0x40000,//256KB},{.name="kernel",.offset=MTDPART_OFS_APPEND,//接在前一分区之后.size=0x200000,//2MB},{.name="rootfs",.offset=MTDPART_OFS_APPEND,.size=MTDPART_SIZ_FULL,//剩余所有空间}};//注册到MTD设备staticstructflash_platform_datamy_flash_data={.parts=my_flash_parts,.nr_parts=ARRAY_SIZE(my_flash_parts),};```####方法2:使用设备树(DeviceTree,推荐)在设备树文件(`.dts`)中添加分区表:```dts&nand{#address-cells=<1>;#size-cells=<1>;partition@0{label="bootloader";reg=<0x00x00040000>;//起始0,大小256KB};partition@40000{label="kernel";reg=<0x000400000x00200000>;//起始256KB,大小2MB};partition@240000{label="rootfs";reg=<0x002400000x0dc00000>;//起始2.25MB,剩余空间};};```**编译并更新设备树**后,系统启动时会自动注册分区[^1][^3]。---###三、动态添加MTD分区(调试用)若需在运行时临时添加分区,可使用`add_mtd_partitions()`函数:```c#include<linux/mtd/partitions.h>staticstructmtd_partitiondyn_part={.name="temp",.size=0x100000,//1MB.offset=0x500000,//从5MB偏移开始};intret=add_mtd_partitions(master_device,&dyn_part,1);```>**警告**:动态分区在重启后失效,仅用于临时调试[^1]。---###四、MTD分区映射配置(针对NORFlash)若使用NORFlash,需在内核中配置物理映射:1.**启用CFI支持**:```kconfigDeviceDrivers→MemoryTechnologyDevice(MTD)support→<*>CFIFlashdeviceinphysicalmemorymap```2.**设置映射参数**(关键):-`Physicalstartaddress`:Flash物理基址(需Bootloader一致,如`0xff800000`)-`Physicallength`:映射空间大小(如`0x2000000`)-`Bankwidth`:数据位宽(如`2`表示16位)[^4]---###五、常见问题解决####问题1:分区未正确注册-**检查顺序**:1.确认设备树编译后已加载到内核2.通过`dmesg|grepmtd`查看内核日志3.若出现`failedtofindpartitions`,检查设备树语法或驱动兼容性[^3]####问题2:擦除/读写失败-**可能原因**:-分区偏移未对齐到擦除块边界-跨擦除块操作未分步执行-**解决方案**:调整`.offset`和`.size`为`erasesize`的整数倍。---###六、高级操作:合并多个MTD分区通过`mtdconcat`创建虚拟分区:```bash#将mtd0和mtd1合并为虚拟设备insmodmtdconcat.kodevices=mtd0,mtd1```新设备将出现在`/proc/mtd`中,名为`Virtual_concat`。§§相关问题§§1.如何通过设备树配置NANDFlash的坏块管理?2.MTDUBI文件系统的关系及转换步骤是什么?3.在Linux中如何对MTD分区进行读写编程?</think>以下是嵌入式系统中配置和查看MTD分区的详细步骤指南,结合Linux内核机制和实际操作: ### 一、查看MTD分区信息 #### 1. **通过/proc文件系统查看** ```bash cat /proc/mtd ``` 输出示例: ``` dev: size erasesize name mtd0: 00040000 00020000 "bootloader" mtd1: 00200000 00020000 "kernel" mtd2: 00400000 00020000 "rootfs" ``` - **字段说明**: - `dev`:MTD设备编号(如mtd0) - `size`:分区大小(十六进制) - `erasesize`:擦除块大小 - `name`:分区名称[^2] #### 2. **使用mtdinfo工具(需安装mtd-utils)** ```bash mtdinfo /dev/mtd0 ``` 输出详细参数,包括分区类型(NOR/NAND)、可擦除块数量等。 #### 3. **通过sysfs接口查看** ```bash ls /sys/class/mtd/ ``` 每个mtdX目录包含分区的详细信息(如name、size、erasesize)。 --- ### 二、配置MTD分区的方法 #### 方法1:设备树(Device Tree)配置(推荐) ```dts // 在设备树文件中定义 flash@0 { compatible = "jedec-flash"; reg = <0>; partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; partition@0 { label = "bootloader"; reg = <0x0 0x00040000>; // 起始0,大小256KB }; partition@40000 { label = "kernel"; reg = <0x00040000 0x00200000>; // 起始256KB,大小2MB }; partition@240000 { label = "rootfs"; reg = <0x00240000 0x0dc00000>; // 起始2.25MB,剩余空间 }; }; }; ``` **生效步骤**: 1. 修改设备树文件(.dts) 2. 编译设备树:`dtc -O dtb -o myboard.dtb myboard.dts` 3. 加载新设备树到内核 #### 方法2:内核代码硬编码(不推荐) ```c // 在板级初始化文件中 #include <linux/mtd/partitions.h> static struct mtd_partition my_parts[] = { { .name = "bootloader", .offset = 0, .size = 0x40000, // 256KB }, { .name = "kernel", .offset = MTDPART_OFS_APPEND, .size = 0x200000, // 2MB } }; // 注册到MTD核心 add_mtd_partitions(master_device, my_parts, ARRAY_SIZE(my_parts)); ``` #### 方法3:命令行传递参数(启动时) ```bash // 在U-Boot启动参数中添加 setenv bootargs "mtdparts=<mtd-id>:<size>@<offset>(<name>)" // 示例: setenv bootargs "mtdparts=spi0.0:256k(boot),2M(kernel),-(rootfs)" ``` --- ### 三、MTD分区映射配置(针对NOR Flash) 在Linux内核配置中: ```kconfig Device Drivers → Memory Technology Device (MTD) support → <*> CFI Flash device in physical memory map (0xff800000) Physical start address // Flash物理基址 (0x2000000) Physical length // 映射空间大小 (2) Bank width in octets // 位宽(2=16位) ``` **关键点**: - 物理地址需硬件设计一致 - 位宽必须匹配Flash芯片规格[^4] --- ### 四、内核处理MTD分区的流程 ```mermaid graph TB A[MTD驱动注册] --> B[parse_mtd_partitions] B --> C{解析成功?} C -->|Yes| D[注册解析到的分区] C -->|No| E[使用驱动定义的分区] D --> F[add_mtd_partitions] E --> F F --> G[创建/dev/mtdX设备节点] ``` 关键函数逻辑: ```c ret = parse_mtd_partitions(mtd, types, &parsed, parser_data); if (ret < 0 || !parsed.nr_parts) { // 使用驱动定义的分区 parsed.parts = driver_parts; parsed.nr_parts = driver_nr_parts; } add_mtd_partitions(mtd, parsed.parts, parsed.nr_parts); // 注册分区[^3] ``` --- ### 五、常见问题解决 #### 问题:分区未正确注册 **排查步骤**: 1. 检查`dmesg | grep mtd`输出 2. 确认设备树编译后已加载 3. 验证物理地址配置: ```bash cat /proc/iomem | grep -i flash ``` 4. 检查驱动兼容性: ```bash ls /sys/bus/platform/drivers/ | grep flash ``` #### 问题:擦除/读写失败 **可能原因**: - 分区偏移未对齐到擦除块边界 - 跨擦除块操作未分步执行 - Flash硬件写保护未解除 **解决方案**: ```bash flash_erase /dev/mtd0 0x0 1 // 从0地址擦除1个块 nandwrite -p /dev/mtd1 kernel.bin // 写入时自动处理坏块 ``` --- ### 六、高级操作:动态添加分区 ```c #include <linux/mtd/partitions.h> static struct mtd_partition dyn_part = { .name = "runtime_part", .size = 0x100000, // 1MB .offset = 0x500000, // 从5MB偏移开始 }; // 在模块初始化函数中 int add_dynamic_partition(void) { struct mtd_info *mtd = get_mtd_device(NULL, 0); return add_mtd_partitions(mtd, &dyn_part, 1); } ``` > **注意**:动态分区在重启后失效,需持久化请修改设备树[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值