uboot源码——mmc驱动分析
以下內(nèi)容源于朱有鵬《物聯(lián)網(wǎng)大講壇》課程的學(xué)習(xí),以及博客http://www.cnblogs.com/biaohc/p/6409197.html的學(xué)習(xí)整理,如有侵權(quán),請告知刪除。
一、uboot與linux驅(qū)動
1、uboot是裸機(jī)程序
- 狹義的驅(qū)動的概念:操作系統(tǒng)中用來具體操控硬件的那部分代碼叫驅(qū)動。
- 裸機(jī)中沒有驅(qū)動的概念,因?yàn)闆]有操作系統(tǒng)。
- 裸機(jī)程序是直接操控硬件的,而操作系統(tǒng)中則是通過驅(qū)動來操控硬件。兩者的本質(zhì)區(qū)別是分層。
2、uboot的虛擬地址對硬件操作的影響
(1)操作系統(tǒng)下,MMU是開啟的,即linux驅(qū)動使用的都是虛擬地址。純裸機(jī)程序不會開啟MMU,全部使用物理地址。
- 這是裸機(jī)下和驅(qū)動中操控硬件的一個重要區(qū)別。
(2)uboot早期也是純物理地址工作,但是現(xiàn)在的uboot開啟了MMU做了虛擬地址映射。
- 查uboot中的虛擬地址映射表,發(fā)現(xiàn)除了0x30000000-0x3FFFFFFF映射到了0xC0000000-0xCFFFFFFF之外,其余的虛擬地址空間全是原樣映射的。
- 我們驅(qū)動中主要是操控硬件寄存器,而S5PV210的SFR都在0xExxxxxx地址空間,因此驅(qū)動中不必考慮虛擬地址。
3、uboot移植了linux驅(qū)動
(1)linux的驅(qū)動是模塊化設(shè)計(jì)。
- linux驅(qū)動本身和linux內(nèi)核不是強(qiáng)耦合的,這是linux驅(qū)動可以被uboot移植的關(guān)鍵。
(2)uboot移植了linux驅(qū)動源代碼。
- uboot是從源代碼級別去移植linux驅(qū)動的,這就是linux系統(tǒng)的開源性。
(3)uboot中的硬件驅(qū)動比linux簡單。
- linux驅(qū)動本身有更復(fù)雜的框架,需要實(shí)現(xiàn)更多的附帶功能,而uboot本質(zhì)上只是個裸機(jī)程序,uboot移植linux驅(qū)動時只是借用了linux驅(qū)動的一部分而已。
二、iNand/SD驅(qū)動解析
1、MMC驅(qū)動的初始化,是在start_armboot函數(shù)中,調(diào)用的是mmc_initialize函數(shù)
下面看一下mmc_initialize函數(shù)
(1)函數(shù)位于uboot/drivers/mmc/mmc.c。
(2)此函數(shù)主要是初始化開發(fā)板上MMC系統(tǒng)。
- SoC里的MMC控制器初始化(MMC系統(tǒng)時鐘的初始化、SFR初始化);
- SoC里MMC相關(guān)的GPIO的初始化;
- SD卡/iNand芯片的初始化。
(3)mmc_devices,鏈表全局變量,用來記錄系統(tǒng)中所有已經(jīng)注冊的SD/iNand設(shè)備。
- 向系統(tǒng)中插入一個SD卡/iNand設(shè)備,則系統(tǒng)驅(qū)動就會向mmc_devices鏈表中插入一個數(shù)據(jù)結(jié)構(gòu)表示這個設(shè)備。
(4)struct mmc類型的結(jié)構(gòu)體指針
- 這個struct mmc類型的結(jié)構(gòu)體非常重要,我們說的驅(qū)動主要就是構(gòu)建這個結(jié)構(gòu)體;
- 在這個結(jié)構(gòu)體中構(gòu)建了一些列變量、函數(shù)指針等;
- 這些變量記錄了mmc的一些信息,函數(shù)指針?biāo)赶虻暮瘮?shù)是用來向sd卡中發(fā)送命令、或者發(fā)送數(shù)據(jù)、直接操作最底層的特殊功能寄存器
下面看一下cpu_mmc_init函數(shù)
(1)函數(shù)位于uboot/cpu/s5pc11x/cpu.c中,通過調(diào)用3個函數(shù)來完成。
(2)setup_hsmmc_clock,在uboot/cpu/s5pc11x/setup_hsmmc.c中,用來初始化SoC中MMC控制器中的時鐘部分的。
(3)setup_hsmmc_cfg_gpio,在uboot/cpu/s5pc11x/setup_hsmmc.c中,用來配置SoC中MMC控制器相關(guān)的GPIO的。
下面看一下setup_hsmmc_clock函數(shù),主要是選擇時鐘源、分頻
下面看一下setup_hsmmc_cfg_gpio函數(shù),主要是初始化相關(guān)的GPIO
下面看一下smdk_s3c_hsmmc_init函數(shù)
(1)函數(shù)位于:uboot/drivers/mmc/s3c_hsmmc.c中。
(2)函數(shù)內(nèi)部通過宏定義USE_MMCx來決定是否調(diào)用s3c_hsmmc_initialize來進(jìn)行具體的初始化操作。
下面看一下s3c_hsmmc_initialize函數(shù)
(1)函數(shù)位于:uboot/drivers/mmc/s3c_hsmmc.c中。
(2)定義并且實(shí)例化一個struct mmc類型的對象
- 即定義了一個指針,給指針分配內(nèi)存,然后填充它的各種成員,最后調(diào)用mmc_register函數(shù)來向驅(qū)動框架注冊這個mmc設(shè)備驅(qū)動。
(3)mmc_register功能是進(jìn)行mmc設(shè)備的注冊,注冊方法其實(shí)就是將當(dāng)前這個struct mmc使用鏈表連接到mmc_devices這個全局變量中去。
(4)在X210中定義了USE_MMC0和USE_MMC2
- 因此在我們的uboot初始化時,會調(diào)用2次s3c_hsmmc_initialize函數(shù),傳遞參數(shù)分別是0和2;
- 因此完成之后系統(tǒng)中會注冊上2個mmc設(shè)備,表示當(dāng)前系統(tǒng)中有2個mmc通道在工作。平常我們說的通道0和通道2?
(5)真正的操作寄存器的函數(shù)是s3c_hsmmc_send_command、s3c_hsmmc_set_ios、s3c_hsmmc_init;
- 發(fā)送命令、發(fā)送數(shù)據(jù)、初始化三個函數(shù);
- 這三個函數(shù)是最底層的、直接操作GPIO進(jìn)而特殊功能寄存器的函數(shù);
- 這三個函數(shù)以及一些變量被封裝在struct mmc結(jié)構(gòu)體中,因而操作系統(tǒng)對mmc設(shè)備進(jìn)行操作的時候,到封裝以后的這個結(jié)構(gòu)體中進(jìn)行操作即可;
(6)至此cpu_mmc_init函數(shù)分析完成。
下面看一下find_mmc_device函數(shù)
(1)函數(shù)位于uboot/drivers/mmc/mmc.c中。
(2)通過mmc設(shè)備編號來在系統(tǒng)中查找對應(yīng)的mmc設(shè)備(struct mmc的對象,根據(jù)上面分析系統(tǒng)中有2個,編號分別是0和2)。
- 通過遍歷mmc_devices鏈表,去依次尋找系統(tǒng)中注冊的mmc設(shè)備,然后對比其設(shè)備編號和我們當(dāng)前要查找的設(shè)備編號,如果相同則就找到了要找的設(shè)備。
- 找到了后調(diào)用mmc_init函數(shù)來初始化它。
下面看一下mmc_init函數(shù)
(1)函數(shù)位于:drivers/mmc/mmc.c中。
(2)分析猜測這個函數(shù)應(yīng)該要進(jìn)行mmc卡的初始化了(前面已經(jīng)進(jìn)行了SoC端控制器的初始化)
(3)函數(shù)的調(diào)用關(guān)系為:
mmc_init
mmc_go_idle
mmc_send_cmd
mmc_send_if_condmmc_send_cmd……
(4)分析可知,mmc_init函數(shù)通過依次向mmc卡發(fā)送命令碼(CMD0、CMD2那些)來初始化SD卡/iNand內(nèi)部的控制器,以達(dá)到初始化SD卡的目的。
- 調(diào)用struct mmc 中的函數(shù)進(jìn)行了一些時序操作
(5)send_cmd函數(shù)的細(xì)節(jié)找不到……
2、總結(jié)
(1)至此整個MMC系統(tǒng)初始化結(jié)束。
(2)整個MMC系統(tǒng)初始化分為2大部分
- SoC這一端的MMC控制器的初始化,SD卡這一端卡本身的初始化。
- 前一步主要是在cpu_mmc_init函數(shù)中完成,后一部分主要是在mmc_init函數(shù)中完成。
(3)初始化完成后,使用sd卡/iNand的操作方法和mmc_init函數(shù)中初始化SD卡的操作一樣的方式。讀寫sd卡時也是通過總線向SD卡發(fā)送命令、讀取/寫入數(shù)據(jù)來完成的。
(4)順著操作追下去,到了mmc_send_cmd函數(shù)處就斷了,真正的向SD卡發(fā)送命令的硬件操作的函數(shù)找不到。這就是學(xué)習(xí)驅(qū)動的麻煩之處。
(6)struct mmc結(jié)構(gòu)體是關(guān)鍵。
- 上述兩部分初始化之間用mmc結(jié)構(gòu)體來鏈接的;
- 初始化完了后對mmc卡的常規(guī)讀寫操作也是通過mmc結(jié)構(gòu)體來鏈接的。
三、關(guān)于驅(qū)動的理解
1、驅(qū)動的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)
(1)驅(qū)動的設(shè)計(jì)中有一個關(guān)鍵數(shù)據(jù)結(jié)構(gòu)。譬如MMC驅(qū)動的結(jié)構(gòu)體就是struct mmc。
- 這些結(jié)構(gòu)體中包含一些變量和一些函數(shù)指針,變量用來記錄驅(qū)動相關(guān)的一些屬性,函數(shù)指針用來記錄驅(qū)動相關(guān)的操作方法。
- 這些變量和函數(shù)指針加起來就構(gòu)成了驅(qū)動。驅(qū)動就被抽象為這個結(jié)構(gòu)體。
(2)一個驅(qū)動工作時主要分兩部分
- 驅(qū)動構(gòu)建(構(gòu)建一個struct mmc然后填充它);
- 驅(qū)動運(yùn)行時(調(diào)用這些函數(shù)指針指針的函數(shù)和變量);
2、分離思想
(1)分離思想,即在驅(qū)動中將操作方法和數(shù)據(jù)分開。
(2)操作方法就是函數(shù),數(shù)據(jù)就是變量。
- 所謂操作方法和數(shù)據(jù)分離的意思就是,在不同的地方來存儲和管理驅(qū)動的操作方法和變量,這樣的優(yōu)勢就是驅(qū)動便于移植。
3、分層思想
(1)分層思想,是指一個整個的驅(qū)動分為好多個層次。
- 簡單理解就是驅(qū)動分為很多個源文件,放在很多個文件夾中
- 譬如本課程講的mmc的驅(qū)動涉及到drivers/mmc下面的2個文件、cpu/s5pc11x下的好幾個文件。
(2)以mmc驅(qū)動為例來分析各個文件的作用
uboot/drivers/mmc/mmc.c
- 本文件是和MMC卡操作有關(guān)的方法,譬如MMC卡設(shè)置空閑狀態(tài)的、卡讀寫數(shù)據(jù)等。
- 本文件中并沒有具體的硬件操作函數(shù),操作最終指向的是struct mmc結(jié)構(gòu)體中的函數(shù)指針,這些函數(shù)指針是在驅(qū)動構(gòu)建的時候和真正硬件操作的函數(shù)掛接的(真正的硬件操作的函數(shù)在別的文件中)。
uboot/drivers/mmc/s3c_hsmmc.c:
- 本文件是SoC內(nèi)部MMC控制器的硬件操作的方法,譬如向SD卡發(fā)送命令的函數(shù)(s3c_hsmmc_send_command),譬如和SD卡讀寫數(shù)據(jù)的函數(shù)(s3c_hsmmc_set_ios)
- 這些函數(shù)是具體操作硬件的函數(shù),即mmc.c中需要的那些硬件操作函數(shù)。這些函數(shù)在mmc驅(qū)動初始化構(gòu)建時(s3c_hsmmc_initialize函數(shù)中)和struct mmc掛接起來。
由上分析可知
- mmc.c和s3c_hsmmc.c構(gòu)成了一個分層,mmc.c中調(diào)用了s3c_hsmmc.中的函數(shù),所以mmc.c在上層,s3c_hsmmc.c在下層。
- mmc.c中不涉及具體硬件的操作,s3c_hsmmc.c中不涉及驅(qū)動工程時的時序操作。
- 如果我們要把這一套mmc驅(qū)動移植到別的SoC上,那么mmc.c就不用動,修改s3c_hsmmc.c即可;
- 如果SoC沒變但是SD卡升級了,這時候只需要更換mmc.c,不需要更換s3c_hsmm。
總結(jié)
以上是生活随笔為你收集整理的uboot源码——mmc驱动分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: keras中文文档网址
- 下一篇: 方舟原始恐惧mod生物代码_方舟MOD