MTD 設備是象閃存芯片、小型閃存卡、記憶棒等之類的設備,它們在嵌入式設備中的使用正在不斷增長。
MTD 驅動程序是在 Linux 下專門為嵌入式環境開發的新的一類驅動程序。相對于常規塊設備驅動程序,使用 MTD 驅動程序的主要優點在于 MTD 驅動程序是專門為基于閃存的設備所設計的,所以它們通常有更好的支持、更好的管理和基于扇區的擦除和讀寫操作的更好的接口。Linux 下的 MTD 驅動程序接口被劃分為兩類模塊:用戶模塊和硬件模塊。
?
MTD 驅動程序設置?
為了訪問特定的閃存設備并將文件系統置于其上,需要將 MTD 子系統編譯到內核中。這包括選擇適當的 MTD 硬件和用戶模塊。當前,MTD 子系統支持為數眾多的閃存設備 ― 并且有越來越多的驅動程序正被添加進來以用于不同的閃存芯片。
?
有兩個流行的用戶模塊可啟用對閃存的訪問: MTD_CHAR 和 MTD_BLOCK 。?
MTD_CHAR 提供對閃存的原始字符訪問,而 MTD_BLOCK 將閃存設計為可以在上面創建文件系統的常規塊設備(象 IDE 磁盤)。與 MTD_CHAR 關聯的設備是 /dev/mtd0、mtd1、mtd2(等等),而與 MTD_BLOCK 關聯的設備是 /dev/mtdblock0、mtdblock1(等等)。由于 MTD_BLOCK 設備提供象塊設備那樣的模擬,通常更可取的是在這個模擬基礎上創建象 FTL 和 JFFS2 那樣的文件系統。
?
為了進行這個操作,可能需要創建分區表將閃存設備分拆到引導裝載程序節、內核節和文件系統節中。
Linux 中 MTD 子系統的主要目標是在系統的硬件驅動程序和上層,或用戶模塊之間提供通用接口。硬件驅動程序不需要知道象 JFFS2 和 FTL 那樣的用戶模塊使用的方法。所有它們真正需要提供的就是一組對底層閃存系統進行 read 、 write 和 erase 操作的簡單例程。
?
MTD 驅動程序是專門針對嵌入式Linux的一種驅動程序,相對于常規塊設備驅動程序(比如PC中的IDE硬盤)而言,MTD驅動程序能更好的支持和管理閃存設備,因為它本身就是專為閃存設備而設計的。MTD設備是指不同于傳統字符設備和塊設備的flash存儲設備,使得上層的文件系統像訪問傳統的字符或塊設備一樣訪問flash,為上層軟件系統提供一個同一的接口。
??? 具體地講,基于MTD的FLASH驅動,承上可以很好地支持cramfs,jffs2和yaffs等文件系統,啟下也能對FLASH的擦除,讀寫,FLASH壞塊以及損耗平衡進行很好的管理。所謂損耗平衡,是指對NAND的擦寫不能總是集中在某一個或某幾個block中,這是由NAND芯片有限的擦寫次數的特性決定的。
?
一、MTD?的概念和層次
MTD(memory technology device?存儲?技術設備?)?是用于訪問?memory?設備(?ROM?、?flash?)的?Linux?的子系統。?MTD?的主要目的是為了使新的?memory?設備的驅動更加簡單,為此它在硬件和上層之間提供了一個抽象的接口。?MTD?的所有源代碼在?/drivers/mtd?子目錄下?。[1]
傳統上,?UNIX?只認識塊設備和字符設備。字符設備是類似鍵盤或者鼠標的這類設備,你必須從它讀取當前數據,但是不可以定位也沒有大小。塊設備有固定的大小并且可以定位, 它們恰好組織成許多字節的塊,通常為?512字節。
閃存既不滿足塊設備描述也不滿足字符設備的描述。它們表現的類似塊設備,但又有所不同。比如,塊設備不區分寫和擦除操作。因此,一種符合閃存特性的特殊設備類型誕生了, 就是?MTD?設備。所以?MTD?既不是塊設備,也不是字符設備?。?[
These provide physical access(?物理訪問?)?to memory devices, and are not used directly - they are accessed through the user modules above(?他們是通過上層的用戶模塊來訪問的?)?.
On-board memory
Many PC chipsets(?芯片組?)?are incapable of correctly(?不能正確地?)?caching system memory above 64M or 512M. A driver exists which allows you to use this memory with the linux-mtd system.?(?有些?PC?芯片組不能正確緩存高于?64M?或者?512M?的系統內存,那么就可以通過?linux?的?mtd?來使用這些內存?)
PCMCIA devices
PCMCIA flash (not CompactFlash but real flash) cards are now supported by the pcmciamtd driver in CVS.?(PCMCIA?閃存卡?-??不是?CF?卡但是是真實的?flash)
Common Flash Interface (CFI) onboard NOR flash
This is a common solution and is well-tested and supported, most often using JFFS2 or cramfs file systems.
Onboard NAND flash
NAND flash is rapidly overtaking NOR flash due to its larger size and lower cost; JFFS2 support for NAND flash is approaching production quality.?(NAND?因其大容量和低成本正在飛速超越?NOR)
M-Systems' DiskOnChip 2000 and Millennium
The DiskOnChip 2000, Millennium and Millennium Plus devices should be fully supported, using their native NFTL and INFTL 'translation layers'. Support for JFFS2 on DiskOnChip 2000 and Millennium is also operational although lacking proper support for bad block handling.
CompactFlash?-?http://www.compactflash.org/
CompactFlash emulates an IDE disk, either through the PCMCIA-ATA standard, or by connecting directly to an IDE interface.
As such, it has no business being on this page, as to the best of my knowledge it doesn't have any alternative method of accessing the flash - you have to use the IDE emulation - I mention it here for completeness.
uboot 與系統內核中MTD分區的關系:
分區只是內核的概念,就是說A~B地址放內核,C~D地址放文件系統,(也就是規定哪個地址區間放內核或者文件系統)等等。
1:在內核MTD中可以定義分區A~B,C~D。。。。。。并予以絕對的地址賦值給每個分區。我們可以來看看在內核中是怎樣來對MTD進行分區的:arch/arm/plat-s3c24xx/common-smdk.c
static struct mtd_partition smdk_default_nand_part[] = {
?[0] = {
??.name?= "Boot",
??.size?= SZ_16K,
??.offset?= 0,
?},
?[1] = {
??.name?= "S3C2410 flash partition 1",
??.offset = 0,
??.size?= SZ_2M,
?},
?[2] = {
??.name?= "S3C2410 flash partition 2",
??.offset = SZ_4M,
??.size?= SZ_4M,
?},
?[3] = {
??.name?= "S3C2410 flash partition 3",
??.offset?= SZ_8M,
??.size?= SZ_2M,
?},
?[4] = {
??.name?= "S3C2410 flash partition 4",
??.offset = SZ_1M * 10,
??.size?= SZ_4M,
?},
......
?};
一般我們只需要分3-4個區,第一個為boot區,一個為boot參數區(傳遞給內核的參數),一個為內核區,一個為文件系統區。
而對于bootloader中只要能將內核下載到A~B區的A地址開始處就可以,C~D區的C起始地址下載文件系統。。。這些起始地址在MTD的分區信息中能找到。所以bootloader對分區的概念不重要,只要它能把內核燒到A位置,把文件系統燒到C位置。
所以,在bootloader對Flash進行操作時,哪塊區域放什么是以內核為主。
而為了方便操作,bootloader類似也引入分區的概念,如,可以使用“nand write 0x3000000 kernel 200000”命令將uImage燒到kernel分區,而不必寫那么長:nand write 3000000 A 200000,也就是用分區名來代替具體的地址。
這要對bootloader對內核重新分區:這需要重新設置一下bootloader環境參數,就可以同步更新內核分區信息
如:
setenv bootargs 'noinitrd console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2
???????????????????????????mtdparts=nand_flash:128k(u-boot)ro,64k(u-boot envs),3m(kernel),30m(root.jffs2),30m(root.yaffs)'
內核配置時選上Device Drivers? ---> Memory Technology Device (MTD) support? ---> Command line partition table parsing
在設置了mtdparts變量之后,就可以在nand read/write/erase命令中直接使用分區的名字而不必指定分區的偏移位置.而這需要內核MTD最好沒有規劃分區。
如果你是通過uboot的內核命令行給MTD層傳遞MTD分區信息,這種情況下,內核讀取到的分區信息始終和u-boot中的保持一致(推薦的做法)
如果你是把分區信息寫在內核源代碼MTD里定義好的方法,那最好保證它和u-boot中的保持一致,即同步修改uboot及內核的相關部分。
2:
內核通過bootargs找到文件系統,bootargs中的mtdblockx即代表分區,block1,2,3代表哪個分區。
事實上,bootargs中的"root=/dev/mtdblockx"只是告訴內核,root fs從第x個(x=0,1,2...)MTD分區掛載,mtdblock0對應第一個分區,mtdblock1對應第二個分區,以此類推.
3:分區方法
1) MTD層的分區
2) 通過U-boot傳遞給內核的命令行中的mtdparts=...
3) 其他可以讓內核知道分區信息的任何辦法,(內核默認的命令參數)
下面說到mtdparts,及它的用法:
mtdparts
mtdparts=fc000000.nor_flash:1920k(linux),128k(fdt),20M(ramdisk),4M(jffs2),38272k(user),256k(env),384k(uboot)
要想這個參數起作用,內核中的mtd驅動必須要支持,即內核配置時需要選上Device Drivers? ---> Memory Technology Device (MTD) support? ---> Command line partition table parsing
?
mtdparts的格式如下:
mtdparts=<mtddef>[;<mtddef]
<mtddef>? := <mtd-id>:<partdef>[,<partdef>]
?<partdef> := <size>[@offset][<name>][ro]
?<mtd-id>? := unique id used in mapping driver/device
<size>??? := standard linux memsize OR "-" to denote all remaining space
<name>?? ?:= (NAME)
因此你在使用的時候需要按照下面的格式來設置:
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中的注釋找到相關描述。