FROM:https://blog.csdn.net/kivy_xian/article/details/53333831
請看原文,排版看得友善,轉載留作記錄,謝謝kivy_xian
1.Linux 總線模型
Linux下的任何驅動在核心中最終都抽象為bus, driver以及device三者間的互相作用。
總線是處理器和一個或多個裝置之間的通道,在裝置模型中,所有的裝置都通過總線相連接配接。總線将裝置和驅動綁定,在系統每注冊一個裝置的時候,會周遊該總線上的driver list,通過bus的math函數尋找與之比對的驅動;相反的,在系統每注冊一個驅動的時候,會便利該總線上的device 尋找與之比對的裝置,而比對由總線的match函數完成。一但比對,則會調用總線的probe函數。
在此模型下,如果存在實際總線當然很好,比如mmc總線,i2c總線和spi總線,相應的device和driver都可以直接注冊在總線上。但是總是有一些裝置和總線無關,為此,linux kernel引入了platform 虛拟總線,
Platform總線是一種虛拟的總線,相應的裝置則為platform_device,通過platform_driver_register;而驅動則為platform_driver,通過platform_driver_register 注冊。核心中該總線定義如下:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups= platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
platform_總線match采用名稱匹 配的方式,即driver和device兩者的name一樣則認為該device對應該driver,詳見下圖:
2.MMC 簡介
MMC
MMC全稱MultiMedia Card,由西門子公司和SanDisk公司1997年推出的多媒體記憶卡标準。MMC卡尺寸為32mm x24mm x 1.4mm,它将存貯單元和控制器一同做到了卡上,智能的控制器使得MMC保證相容性和靈活性。
MMC卡具有MMC和SPI兩種工作模式,MMC模式是預設工作模式,具有MMC的全部特性。而SPI模式則是MMC協定的一個子集,主要用于低速系統。
SD
SD卡全稱Secure DigitalMemory Card,由松下、東芝和SanDisk公司于1999年8月共同開發的新一代記憶卡标準,已完全相容MMC标準。SD卡比MMC卡多了一個進行資料著作權保護的暗号認證功能。
SD卡尺寸為32mm x 24mm x2.1mm,長寬和MMC卡一樣,隻是比MMC卡厚了0.7mm,以容納更大容量的存貯單元。SD卡與MMC卡保持向上相容,也就是說,MMC卡可以被新的設有SD卡插槽的裝置存取,但是SD卡卻不可以被設有MMC插槽的裝置存取。
SDIO
SDIO全稱Secure DigitalInput and Output Card,SDIO是在SD标準上定義了一種外設接口,它使用SD的I/O接口來連接配接外圍裝置,并通過SD上的I/O資料接口與這些外圍裝置傳輸資料。現在已經有很多手持裝置支援SDIO功能,而且許多SDIO外設也被開發出來,目前常見的SDIO外設有:WIFI Card、GPS Card、 Bluetooth Card等等。
eMMC
eMMC全稱Embedded MultiMediaCard,是MMC協會所制定的内嵌式存儲器标準規格,主要應用于智能手機和移動嵌入式産品等。eMMC是一種嵌入式非易失性存儲系統,由閃存和閃存控制器兩部分組成,它的一個明顯優勢是在封裝中內建了一個閃存控制器,它采用JEDEC标準BGA封裝,并采用統一閃存接口管理閃存。
eMMC結構由一個嵌入式存儲解決方案組成,帶有MMC接口、快閃儲存設備及主要制器,所有這些由一個小型BGA封裝。由于采用标準封裝,eMMC也很容易更新,并不用改變硬體結構。
eMMC的這種将Nand Flash晶片和控制晶片封裝在一起的設計概念,就是為了簡化産品記憶體儲器的使用,客戶隻需要采購eMMC晶片放進産品中,不需要處理其它複雜的Nand Flash相容性和管理問題,減少研發成本和研發周期。
3.MMC 子產品總線模型
mmc子系統涉及到三條總線,如下:
Host驅動相應的driver和device挂載在Linux核心内置的虛拟抽象總線platform_bus_type。兩者的比對采用名稱比對的方式,即driver和device兩者的name一樣則認為該device對應該driver,這裡是”rda,hsmmc”。
Card驅動相應的driver和device挂載在mmc自己建立的虛拟總線mmc_bus_type下,直接比對。
Sdio驅動相應的driver和device挂載在mmc自己建立的虛拟總線sdio_bus_type下,ID比對。
按照時間先後順序,mmc子產品中bus,device和driver的注冊順序如下:
3.1.host device
linux kernel 通過下圖所示流程,解析dts檔案mmc子產品相關配置,生成名為rda,hsmmc的platformdevice,挂在platform平台總線上。
2.2.mmc_bus, sdio_bus
mmc core初始化時,檔案core.c中的subsys_initcall(mmc_init), 調用mmc_register_bus和sdio_register_bus注冊mmc bus 和sdio bus,具體如圖下圖所示。
由上圖可以看出,任何挂在mmc總線上的device 和driver都會比對,而挂在sdio總線上的裝置和deriver需要通過id進行比對。
2.3.card driver
card目錄下,block.c中module_init(mmc_blk_init)調用mmc_register_driver函數建立mmcblk driver,并将之挂載到mmc_bus_type總線的driver list連結清單上。
注意:mmc core提供了mmc_test.c作為mmc driver的測試檔案。mmc_test.c中,module_init(mmc_test_init)函數中,調用mmc_register_driver函數建立了mmc_test driver,并且将之挂載在mmc_bus_type總線的driver list連結清單上。
mmc子產品如果需要使用mmc_test功能,需要把CONFIG_MMC_BLOKC宏關閉,然後把CONFIG_MMC_BLOCK=y。否則,card将會比對blockdreiver,不會再次比對mmc_test driver,具體見下圖。
2.4.host driver
host目錄下,rda_sgmmc.c檔案中,module_init(rda_mmc_init),把rda_mmc_init連結到相應的init字段中。在初始化時候,執行rda_mmc_init(),調用platform_driver_register注冊名為rda,hsmmc的host driver,此driver挂在platform虛拟總線上。
2.5. card device
在第四步中,hostdriver注冊成功後,platform總線會把此driver和1中注冊的host dev比對,然後執行host driver的probe 函數rda_mmc_probe。該函數中完成mmc_alloc_host申請mmc host 結構體,然後完成初始化,以及中斷等的申請等,最後調用mmc_add_host完成card 的探測,如果card存在,生成card device。
因為sd卡支援熱插拔,是以在probe階段,sd卡沒有插入的情況下,不會生成card device。而是在後期插入sd卡時候,産生中斷,中斷處理函數中調用mmc_detect_change函數探測sd card是否存在,完成初始化并且生成card device。具體見下圖。
從上圖中,我們并沒有看到card裝置的生成。這是因為我們通過detect work完成了sd,mmc,或sdio裝置的初始化,并且生成相應的block裝置,具體見下圖:
2.6. card driver執行
在第五步中,card device已經挂到mmc總線上,此時會比對到carddriver,自動執行driver 的probe函數。如果在3中,CONFIG_MMC_BLOCK=y,則會執行mmc_blk_probe,生成block裝置。如果CONFIG_MMC_BLOCK=n, CONFIG_MMC_TEST=y,則會自動執行mmc_test_probe。
綜上所述,裝置通過dts檔案把mmc host dev(platform裝置)挂在虛拟平台總線上,然後注冊sdio和mmc總線,緊接着注冊card driver,挂在mmc總線上。其後,在host目錄下,我們自己的driver中,調用platform_driver_register注冊platform平台驅動,即host driver。此時,platform會比對host dev 和driver,執行driver的probe函數,通過mmc_add_host注冊card
device,挂載到mmc總線上。最後,mmc總線會比對card dev 和driver,執行card driver的probe函數,生成block裝置或者mmc_test相關的屬性檔案。
4.MMC 協定實作
到此為止,mmc 的相關架構已經介紹清楚了。因為在架構明了的情況下,驅動已經很簡單了,是以後面僅僅會簡單介紹一下mmc驅動。
sd,sdio或者mmc的協定實作在哪裡呢?可以在圖5中看到,初始化就是在mmc_attach_sdio, mmc_attach_sd或者mmc_attach_mmc函數中。
1.初始化時候,首先發送cmd0使卡進入idle狀态;
2.接着發送cmd8,檢測卡是否SD2.0。SD1.1不支援cmd8,是以如果發送cmd8無回應,則卡為SD1.1,否則就是SD2.0;
3. mmc_attach_sdio發送cmd5讀取OCR 寄存器,判斷是否為sdio,如果是就綁定sdio總線;
4. mmc_attach_sd發送指令acmd55、cmd41,使卡進入工作狀态。如果通過,則認為是sd卡,綁定sd總線。mmc卡不支援acmd55,和cmd41,是以如果無回應,則認為卡是mmc卡;
5. mmc_attach_mmc中發送指令1,判斷是否為mmc卡,如果回應,則綁定mmc總線。如果cmd1無回應,則不是mmc卡。
具體實作和協定強相關,隻要對照協定來看,很簡單,就不再多述了。
ls kernel/drivers/mmc,可以看到如下三個目錄:
card core host
card目錄下主要是完成了上章中所述的mmc總線driver,也就是2.3所述的card driver,
core目錄主要是完成了上章中sdio bus和mmc bus注冊,card device的添加,host目錄就是具體的host driver的添加了。
在mmc driver中,需要做的很重要的一部就是實作mmc_host_ops,在probe函數中把其指派給mmc_host 結構體的ops變量,rda_sgmmc.c的mmc_host_ops實作如下:
static const struct mmc_host_ops rda_mmc_ops= {
.request = rda_mmc_request,
.get_ro = rda_mmc_get_ro,
.get_cd = rda_mmc_get_cd,
.set_ios = rda_mmc_set_ios,
.enable_sdio_irq =rda_mmc_enable_sdio_irq,
};
其中,request函數,主要實作指令發送,資料的讀寫;set_ios主要用來設定資料速度,mmc相位,power mode 和data bus width;get_cd用來檢測裝置是否存在;get_ro用來判斷mmc是否為read-only card;enable_sdio_irq是用來使能或者關閉sdio中斷。
mmc dev正常讀寫的時候調用流程是怎麼樣呢?怎麼和上面注冊的mmc_host_ops關聯起來呢?塊裝置的讀寫會被放入request_queue。見下圖:
其中,blk_fetch_request等涉及到block檔案的讀寫實作方式,這裡不再叙述,有興趣的話大家可以看看代碼。
由此,mmc card dev就和上面注冊的mmc_host_ops關聯起來了。
5.MMC test driver 使用
在第二章介紹card driver時候已經介紹到了mmc test driver了。如果要使用mmc_test function,可以按照如下步驟:
1.CONFIG_MMC_BLOCK=n,CONFIG_MMC_TEST=y。或者CONFIG_MMC_BLOCK=y, CONFIG_MMC_TEST=y。如果選用後一種配置,需要再系統起來後,在總線driver中手動bind和unbind,見後面;
2.CONFIG_DEBUG_FS=y,CONFIG_DEBUG_KERNEL=y,這兩項在我們項目的kernel的defconfig中已經配置,是以不需要進行改動;
3. mount -t debugfs none /sys/kernel/debug,這個我們的project中已經挂載了,不需要進行改動;
完成上面三項後,啟動系統,如果在步驟1中CONFIG_MMC_BLOCK=y,那麼需要先執行執行如下操作:
etau:/ # ls sys/bus/mmc/devices/
mmc0:aaaa
etau:/sys/bus/mmc/drivers # ls
mmc_test/ mmcblk/
etau:/sys/bus/mmc/drivers # cd mmcblk/
etau:/sys/bus/mmc/drivers/mmcblk # ls -al
total 0
drwxr-xr-x 2 root root 0 2000-01-01 01:27 .
drwxr-xr-x 4 root root 0 2000-01-01 01:27 ..
--w------- 1 root root 4096 2000-01-01 01:28bind
lrwxrwxrwx 1 root root 0 2000-01-01 01:28 mmc0:aaaa ->../../../../devices/soc0/20a50000.rda-mmc0/mmc_host/mmc0/mmc0:aaaa
--w------- 1 root root 4096 2000-01-01 01:28uevent
--w------- 1 root root 4096 2000-01-01 01:28unbind
etau:/sys/bus/mmc/drivers/mmcblk #echo –n mmc0:aaaa> unbind
etau:/sys/bus/mmc/drivers # cdmmc_test/
etau:/sys/bus/mmc/drivers/mmc_test # ls
bind uevent unbind
etau:/sys/bus/mmc/drivers/mmc_test #echo –n mmc0:aaaa> bind
完成上述操作後,完成了mmc0:aaaa和mmc_test driver的綁定。後續步驟完全一緻,如下:
etau:/sys/kernel/debug/mmc0/mmc0:aaaa# cat testlist
1: Basic write (no data verification)
2: Basic read (no data verification)
3: Basic write (with data verification)
4: Basic read (with data verification)
5: Multi-block write
6: Multi-block read
7: Power of two block writes
8: Power of two block reads
9: Weird sized block writes
10: Weird sized block reads
11: Badly aligned write
12: Badly aligned read
13: Badly aligned multi-block write
14: Badly aligned multi-block read
15: Correct xfer_size at write (start failure)
16: Correct xfer_size at read (start failure)
17: Correct xfer_size at write (midway failure)
18: Correct xfer_size at read (midway failure)
19: Highmem write
20: Highmem read
21: Multi-block highmem write
22: Multi-block highmem read
23: Best-case read performance
24: Best-case write performance
25: Best-case read performance into scattered pages
26: Best-case write performance from scatteredpages
27: Single read performance by transfer size
28: Single write performance by transfer size
29: Single trim performance by transfer size
30: Consecutive read performance by transfer size
31: Consecutive write performance by transfer size
32: Consecutive trim performance by transfer size
33: Random read performance by transfer size
34: Random write performance by transfer size
35: Large sequential read into scattered pages
36: Large sequential write from scattered pages
37: Write performance with blocking req 4k to 4MB
38: Write performance with non-blocking req 4k to 4MB
39: Read performance with blocking req 4k to 4MB
40: Read performance with non-blocking req 4k to 4MB
41: Write performance blocking req 1 to 512 sg elems
42: Write performance non-blocking req 1 to 512 sg elems
43: Read performance blocking req 1 to 512 sg elems
44: Read performance non-blocking req 1 to 512 sg elems
45: Reset test
然後執行etau:/sys/kernel/debug/mmc0/mmc0:aaaa# echo 1 > test可以看到測試結果:
[314034.644348] mmc0: Starting tests of cardmmc0:aaaa...
[314034.645080] mmc0: Test case 1. Basicwrite (no data verification)...
[314034.647583] mmc0: Result: OK
[314034.647827] mmc0: Tests completed.
至此,mmc子產品就告一段落了。
————————————————
版權聲明:本文為CSDN部落客「kivy_xian」的原創文章,遵循 CC 4.0 BY-SA 版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/kivy_xian/article/details/53333831